1 /* Implements a lightweight menubar widget.
2 Copyright (C) 1992, 1993, 1994 Lucid, Inc.
3 Copyright (C) 1995 Tinker Systems and INS Engineering Corp.
5 This file is part of the Lucid Widget Library.
7 The Lucid Widget Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 The Lucid Widget Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
22 /* Created by devin@lucid.com */
29 #include <sys/types.h>
35 #include <X11/IntrinsicP.h>
36 #include <X11/ShellP.h>
37 #include <X11/StringDefs.h>
38 #include <X11/cursorfont.h>
39 #include <X11/bitmaps/gray>
43 #if XmVersion < 1002 /* 1.1 or ancient */
44 #undef XmFONTLIST_DEFAULT_TAG
45 #define XmFONTLIST_DEFAULT_TAG XmSTRING_DEFAULT_CHARSET
46 #endif /* XmVersion < 1.2 */
50 #ifdef USE_DEBUG_MALLOC
54 /* simple, naieve integer maximum */
56 #define max(a,b) ((a)>(b)?(a):(b))
60 xlwMenuTranslations [] =
61 "<BtnDown>: start()\n\
62 <BtnMotion>: drag()\n\
66 extern Widget lw_menubar_widget;
68 #define offset(field) XtOffset(XlwMenuWidget, field)
73 /* There are three font list resources, so that we can accept either of
74 the resources *fontList: or *font:, and so that we can tell the
75 difference between them being specified, and being defaulted to a
76 font from the XtRString specified here. */
77 {XmNfontList, XmCFontList, XmRFontList, sizeof(XmFontList),
78 offset(menu.font_list), XtRImmediate, (XtPointer)0},
79 {XtNfont, XtCFont, XmRFontList, sizeof(XmFontList),
80 offset(menu.font_list_2),XtRImmediate, (XtPointer)0},
81 {XmNfontList, XmCFontList, XmRFontList, sizeof(XmFontList),
82 offset(menu.fallback_font_list),
83 /* We must use an iso8859-1 font here, or people without $LANG set lose.
84 It's fair to assume that those who do have $LANG set also have the
85 *fontList resource set, or at least know how to deal with this. */
86 XtRString, "-*-helvetica-bold-r-*-*-*-120-*-*-*-*-iso8859-1"},
88 {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
89 offset(menu.font), XtRString, "XtDefaultFont"},
91 {XtNfontSet, XtCFontSet, XtRFontSet, sizeof(XFontSet),
92 offset(menu.font_set), XtRString, "XtDefaultFontSet"},
95 {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
96 offset(menu.foreground), XtRString, "XtDefaultForeground"},
97 {XtNbuttonForeground, XtCButtonForeground, XtRPixel, sizeof(Pixel),
98 offset(menu.button_foreground), XtRString, "XtDefaultForeground"},
99 {XtNhighlightForeground, XtCHighlightForeground, XtRPixel, sizeof(Pixel),
100 offset(menu.highlight_foreground), XtRString, "XtDefaultForeground"},
101 {XtNtitleForeground, XtCTitleForeground, XtRPixel, sizeof(Pixel),
102 offset(menu.title_foreground), XtRString, "XtDefaultForeground"},
103 {XtNmargin, XtCMargin, XtRDimension, sizeof(Dimension),
104 offset(menu.margin), XtRImmediate, (XtPointer)2},
105 {XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension, sizeof(Dimension),
106 offset(menu.horizontal_margin), XtRImmediate, (XtPointer)2},
107 {XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension, sizeof(Dimension),
108 offset(menu.vertical_margin), XtRImmediate, (XtPointer)1},
109 {XmNspacing, XmCSpacing, XmRHorizontalDimension, sizeof(Dimension),
110 offset(menu.column_spacing), XtRImmediate, (XtPointer)4},
111 {XmNindicatorSize, XmCIndicatorSize, XtRDimension, sizeof(Dimension),
112 offset(menu.indicator_size), XtRImmediate, (XtPointer)0},
114 {XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension,
115 sizeof (Dimension), offset (menu.shadow_thickness),
116 XtRImmediate, (XtPointer) 2},
118 {XmNshadowThickness, XmCShadowThickness, XtRDimension,
119 sizeof (Dimension), offset (menu.shadow_thickness),
120 XtRImmediate, (XtPointer) 2},
122 {XmNselectColor, XmCSelectColor, XtRPixel, sizeof (Pixel),
123 offset (menu.select_color), XtRImmediate, (XtPointer)-1},
124 {XmNtopShadowColor, XmCTopShadowColor, XtRPixel, sizeof (Pixel),
125 offset (menu.top_shadow_color), XtRImmediate, (XtPointer)-1},
126 {XmNbottomShadowColor, XmCBottomShadowColor, XtRPixel, sizeof (Pixel),
127 offset (menu.bottom_shadow_color), XtRImmediate, (XtPointer)-1},
128 {XmNtopShadowPixmap, XmCTopShadowPixmap, XtRPixmap, sizeof (Pixmap),
129 offset (menu.top_shadow_pixmap), XtRImmediate, (XtPointer)None},
130 {XmNbottomShadowPixmap, XmCBottomShadowPixmap, XtRPixmap, sizeof (Pixmap),
131 offset (menu.bottom_shadow_pixmap), XtRImmediate, (XtPointer)None},
133 {XtNopen, XtCCallback, XtRCallback, sizeof(XtPointer),
134 offset(menu.open), XtRCallback, (XtPointer)NULL},
135 {XtNselect, XtCCallback, XtRCallback, sizeof(XtPointer),
136 offset(menu.select), XtRCallback, (XtPointer)NULL},
137 {XtNmenu, XtCMenu, XtRPointer, sizeof(XtPointer),
138 offset(menu.contents), XtRImmediate, (XtPointer)NULL},
139 {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
140 offset(menu.cursor_shape), XtRString, (XtPointer) "right_ptr"},
141 {XtNhorizontal, XtCHorizontal, XtRInt, sizeof(int),
142 offset(menu.horizontal), XtRImmediate, (XtPointer)True},
143 {XtNuseBackingStore, XtCUseBackingStore, XtRBoolean, sizeof (Boolean),
144 offset (menu.use_backing_store), XtRImmediate, (XtPointer)False},
145 {XtNbounceDown, XtCBounceDown, XtRBoolean, sizeof (Boolean),
146 offset (menu.bounce_down), XtRImmediate, (XtPointer)True},
147 {XtNresourceLabels, XtCResourceLabels, XtRBoolean, sizeof (Boolean),
148 offset (menu.lookup_labels), XtRImmediate, (XtPointer)False},
152 static Boolean XlwMenuSetValues (Widget current, Widget request, Widget new,
153 ArgList args, Cardinal *num_args);
154 static void XlwMenuRealize (Widget w, Mask *valueMask,
155 XSetWindowAttributes *attributes);
156 static void XlwMenuRedisplay (Widget w, XEvent *ev, Region region);
157 static void XlwMenuResize (Widget w);
158 static void XlwMenuInitialize (Widget request, Widget new, ArgList args,
160 static void XlwMenuDestroy (Widget w);
161 static void XlwMenuClassInitialize (void);
162 static void Start (Widget w, XEvent *ev, String *params, Cardinal *num_params);
163 static void Drag (Widget w, XEvent *ev, String *params, Cardinal *num_params);
164 static void Select(Widget w, XEvent *ev, String *params, Cardinal *num_params);
167 static XFontStruct *default_font_of_font_list (XmFontList);
171 xlwMenuActionsList [] =
178 #define SuperClass ((CoreWidgetClass)&coreClassRec)
180 XlwMenuClassRec xlwMenuClassRec =
182 { /* CoreClass fields initialization */
183 (WidgetClass) SuperClass, /* superclass */
184 "XlwMenu", /* class_name */
185 sizeof(XlwMenuRec), /* size */
186 XlwMenuClassInitialize, /* class_initialize */
187 NULL, /* class_part_initialize */
188 FALSE, /* class_inited */
189 XlwMenuInitialize, /* initialize */
190 NULL, /* initialize_hook */
191 XlwMenuRealize, /* realize */
192 xlwMenuActionsList, /* actions */
193 XtNumber(xlwMenuActionsList), /* num_actions */
194 xlwMenuResources, /* resources */
195 XtNumber(xlwMenuResources), /* resource_count */
196 NULLQUARK, /* xrm_class */
197 TRUE, /* compress_motion */
198 TRUE, /* compress_exposure */
199 TRUE, /* compress_enterleave */
200 FALSE, /* visible_interest */
201 XlwMenuDestroy, /* destroy */
202 XlwMenuResize, /* resize */
203 XlwMenuRedisplay, /* expose */
204 XlwMenuSetValues, /* set_values */
205 NULL, /* set_values_hook */
206 XtInheritSetValuesAlmost, /* set_values_almost */
207 NULL, /* get_values_hook */
208 NULL, /* #### - should this be set for grabs? accept_focus */
209 XtVersion, /* version */
210 NULL, /* callback_private */
211 xlwMenuTranslations, /* tm_table */
212 XtInheritQueryGeometry, /* query_geometry */
213 XtInheritDisplayAccelerator, /* display_accelerator */
215 }, /* XlwMenuClass fields initialization */
221 WidgetClass xlwMenuWidgetClass = (WidgetClass) &xlwMenuClassRec;
223 extern int lw_menu_accelerate;
226 #if 0 /* Apparently not used anywhere */
229 safe_strdup (char *s)
233 result = (char *) malloc (strlen (s) + 1);
242 /* Replacement for XAllocColor() that tries to return the nearest
243 available color if the colormap is full. From FSF Emacs. */
246 allocate_nearest_color (Display *display, Colormap screen_colormap,
249 int status = XAllocColor (display, screen_colormap, color_def);
254 /* If we got to this point, the colormap is full, so we're
255 going to try to get the next closest color.
256 The algorithm used is a least-squares matching, which is
257 what X uses for closest color matching with StaticColor visuals. */
260 unsigned long nearest_delta = ULONG_MAX;
262 int no_cells = XDisplayCells (display, XDefaultScreen (display));
263 /* Don't use alloca here because lwlib doesn't have the
264 necessary configuration information that src does. */
265 XColor *cells = (XColor *) malloc (sizeof (XColor) * no_cells);
267 for (x = 0; x < no_cells; x++)
270 XQueryColors (display, screen_colormap, cells, no_cells);
272 for (nearest = 0, x = 0; x < no_cells; x++)
274 long dred = (color_def->red >> 8) - (cells[x].red >> 8);
275 long dgreen = (color_def->green >> 8) - (cells[x].green >> 8);
276 long dblue = (color_def->blue >> 8) - (cells[x].blue >> 8);
277 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
279 if (delta < nearest_delta)
282 nearest_delta = delta;
285 color_def->red = cells[nearest].red;
286 color_def->green = cells[nearest].green;
287 color_def->blue = cells[nearest].blue;
289 return XAllocColor (display, screen_colormap, color_def);
294 push_new_stack (XlwMenuWidget mw, widget_value *val)
296 if (!mw->menu.new_stack)
298 mw->menu.new_stack_length = 10;
300 (widget_value**)XtCalloc (mw->menu.new_stack_length,
301 sizeof (widget_value*));
303 else if (mw->menu.new_depth == mw->menu.new_stack_length)
305 mw->menu.new_stack_length *= 2;
307 (widget_value**)XtRealloc ((char *)mw->menu.new_stack,
308 mw->menu.new_stack_length *
309 sizeof (widget_value*));
311 mw->menu.new_stack [mw->menu.new_depth++] = val;
315 pop_new_stack_if_no_contents (XlwMenuWidget mw)
317 if (mw->menu.new_depth &&
318 !mw->menu.new_stack [mw->menu.new_depth - 1]->contents)
319 mw->menu.new_depth -= 1;
323 make_old_stack_space (XlwMenuWidget mw, int n)
325 if (!mw->menu.old_stack)
327 mw->menu.old_stack_length = max (10, n);
329 (widget_value**)XtCalloc (mw->menu.old_stack_length,
330 sizeof (widget_value*));
332 else if (mw->menu.old_stack_length < n)
334 while (mw->menu.old_stack_length < n)
335 mw->menu.old_stack_length *= 2;
338 (widget_value**)XtRealloc ((char *)mw->menu.old_stack,
339 mw->menu.old_stack_length *
340 sizeof (widget_value*));
345 close_to_reference_time (Widget w, Time reference_time, XEvent *ev)
349 (ev->xbutton.time - reference_time < XtGetMultiClickTime (XtDisplay (w)));
354 string_width (XlwMenuWidget mw,
363 Dimension width, height;
364 XmStringExtent (mw->menu.font_list, s, &width, &height);
369 XmbTextExtents (mw->menu.font_set, s, strlen (s), &ri, &rl);
374 XTextExtents (mw->menu.font, s, strlen (s), &drop, &drop, &drop, &xcs);
376 # endif /* USE_XFONTSET */
380 static char massaged_resource_char[256];
383 initialize_massaged_resource_char (void)
386 for (j = 0; j < (int) sizeof (massaged_resource_char); j++)
388 if ((j >= 'a' && j <= 'z') ||
389 (j >= 'A' && j <= 'Z') ||
390 (j >= '0' && j <= '9') ||
393 massaged_resource_char[j] = (char) j;
395 massaged_resource_char ['_'] = '_';
396 massaged_resource_char ['+'] = 'P'; /* Convert C++ to cPP */
397 massaged_resource_char ['.'] = '_'; /* Convert Buffers... to buffers___ */
401 string_width_u (XlwMenuWidget mw,
410 Dimension width, height;
415 # else /* ! USE_XFONTSET */
426 if (!XmStringGetLtoR (string, XmFONTLIST_DEFAULT_TAG, &chars))
433 charslength = strlen (chars);
434 newchars = (char *) alloca (charslength + 1);
436 for (i = j = 0; chars[i] && (j < charslength); i++)
437 if (chars[i]=='%'&&chars[i+1]=='_')
440 newchars[j++] = chars[i];
444 newstring = XmStringLtoRCreate (newchars, XmFONTLIST_DEFAULT_TAG);
445 XmStringExtent (mw->menu.font_list, newstring, &width, &height);
446 XmStringFree (newstring);
450 XmbTextExtents (mw->menu.font_set, newchars, j, &ri, &rl);
452 # else /* ! USE_XFONTSET */
453 XTextExtents (mw->menu.font, newchars, j, &drop, &drop, &drop, &xcs);
455 # endif /* USE_XFONTSET */
460 massage_resource_name (CONST char *in, char *out)
462 /* Turn a random string into something suitable for using as a resource.
465 "Kill Buffer" -> "killBuffer"
466 "Find File..." -> "findFile___"
467 "Search and Replace..." -> "searchAndReplace___"
468 "C++ Mode Commands" -> "cppModeCommands"
470 Valid characters in a resource NAME component are: a-zA-Z0-9_
473 #ifdef PRINT_XLWMENU_RESOURCE_CONVERSIONS
474 /* Compile with -DPRINT_XLWMENU_RESOURCE_CONVERSIONS to generate a
475 translation file for menu localizations. */
476 char *save_in = in, *save_out = out;
479 Boolean firstp = True;
482 char ch = massaged_resource_char[(unsigned char) *in++];
485 *out++ = firstp ? tolower (ch) : toupper (ch);
487 while ((ch = massaged_resource_char[(unsigned char) *in++]) != '\0')
489 if (!*(in-1)) /* Overshot the NULL byte? */
495 #ifdef PRINT_XLWMENU_RESOURCE_CONVERSIONS
496 printf ("! Emacs*XlwMenu.%s.labelString:\t%s\n", save_out, save_in);
497 printf ( "Emacs*XlwMenu.%s.labelString:\n", save_out);
504 { "labelString", "LabelString", XtRString, sizeof(String),
509 * This function looks through string searching for parameter
510 * inserts of the form:
512 * padding is space (' ') or dash ('-') characters meaning
513 * padding to the left or right of the inserted parameter.
514 * In essence all %1 strings are replaced by value in the return
515 * value (which the caller is expected to free).
516 * %% means insert one % (like printf).
517 * %1 means insert value.
518 * %-1 means insert value followed by one space. The latter is
519 * not inserted if value is a zero length string.
522 parameterize_string (CONST char *string, CONST char *value)
526 unsigned int done = 0;
531 result = XtMalloc(1);
539 for (ntimes = 1, result = (char *) string; (percent = strchr(result, '%'));
541 result = &percent[1];
543 result = XtMalloc ((ntimes * strlen(value)) + strlen(string) + 4);
546 while ((percent = strchr(string, '%')))
548 unsigned int left_pad;
549 unsigned int right_pad;
552 if (percent[1] == '%')
553 { /* it's a real % */
554 strncat (result, string, 1 + percent - string); /* incl % */
555 string = &percent[2]; /* after the second '%' */
556 continue; /* with the while() loop */
562 for (p = &percent[1]; /* test *p inside the loop */ ; p++)
573 { /* param and terminator */
574 strncat (result, string, percent - string);
575 if (value[0] != '\0')
578 for (i = 0; i < left_pad; i++)
579 strcat (result, " ");
580 strcat (result, value);
581 for (i = 0; i < right_pad; i++)
582 strcat (result, " ");
584 string = &p[1]; /* after the '1' */
585 done++; /* no need to do old way */
586 break; /* out of for() loop */
589 { /* bogus, copy the format as is */
590 /* out of for() loop */
591 strncat (result, string, 1 + p - string);
592 string = (*p ? &p[1] : p);
598 /* Copy the tail of the string */
599 strcat (result, string);
601 /* If we have not processed a % string, and we have a value, tail it. */
602 if (!done && value[0] != '\0')
604 strcat (result, " ");
605 strcat (result, value);
614 resource_widget_value (XlwMenuWidget mw, widget_value *val)
616 if (!val->toolkit_data)
618 char *resourced_name = NULL;
619 char *converted_name, *str;
620 XmString complete_name;
621 char massaged_name [1024];
623 if (mw->menu.lookup_labels)
625 /* Convert value style name into resource style name.
626 eg: "Free Willy" becomes "freeWilly" */
627 massage_resource_name (val->name, massaged_name);
629 /* If we have a value (parameter) see if we can find a "Named"
633 char named_name[1024];
634 sprintf (named_name, "%sNamed", massaged_name);
635 XtGetSubresources ((Widget) mw,
636 (XtPointer) &resourced_name,
637 named_name, named_name,
638 nameResource, 1, NULL, 0);
641 /* If nothing yet, try to load from the massaged name. */
644 XtGetSubresources ((Widget) mw,
645 (XtPointer) &resourced_name,
646 massaged_name, massaged_name,
647 nameResource, 1, NULL, 0);
649 } /* if (mw->menu.lookup_labels) */
651 /* Still nothing yet, use the name as the value. */
653 resourced_name = val->name;
655 /* Parameterize the string. */
656 converted_name = parameterize_string (resourced_name, val->value);
658 /* nuke newline characters to prevent menubar screwups */
659 for ( str = converted_name ; *str ; str++ )
661 if (str[0] == '\n') str[0] = ' ';
664 /* Improve OSF's bottom line. */
665 #if (XmVersion >= 1002)
666 complete_name = XmStringCreateLocalized (converted_name);
668 complete_name = XmStringCreateLtoR (converted_name,
669 XmSTRING_DEFAULT_CHARSET);
671 XtFree (converted_name);
673 val->toolkit_data = complete_name;
674 val->free_toolkit_data = True;
676 return (XmString) val->toolkit_data;
681 /* These two routines should be a seperate file..djw */
683 xlw_create_localized_string (Widget w,
694 XtGetSubresources (w,
704 return parameterize_string (string, arg);
708 xlw_create_localized_xmstring (Widget w,
713 char * string = xlw_create_localized_string (w, name, args, nargs);
714 XmString xm_string = XmStringCreateLtoR (string, XmSTRING_DEFAULT_CHARSET);
723 resource_widget_value (XlwMenuWidget mw, widget_value *val)
725 if (!val->toolkit_data)
727 char *resourced_name = NULL;
729 char massaged_name [1024];
731 if (mw->menu.lookup_labels)
733 massage_resource_name (val->name, massaged_name);
735 XtGetSubresources ((Widget) mw,
736 (XtPointer) &resourced_name,
737 massaged_name, massaged_name,
738 nameResource, 1, NULL, 0);
741 resourced_name = val->name;
743 complete_name = parameterize_string (resourced_name, val->value);
745 val->toolkit_data = complete_name;
746 /* nuke newline characters to prevent menubar screwups */
747 for ( ; *complete_name ; complete_name++ )
749 if (complete_name[0] == '\n')
750 complete_name[0] = ' ';
752 val->free_toolkit_data = True;
754 return (char *) val->toolkit_data;
759 /* Code for drawing strings. */
761 string_draw (XlwMenuWidget mw,
773 XmStringDraw (XtDisplay (mw), window,
777 1000, /* ???? width */
778 XmALIGNMENT_BEGINNING,
779 0, /* ???? layout_direction */
783 XmbDrawString (XtDisplay (mw), window, mw->menu.font_set, gc,
784 x, y + mw->menu.font_ascent, string, strlen (string));
786 XDrawString (XtDisplay (mw), window, gc,
787 x, y + mw->menu.font_ascent, string, strlen (string));
788 # endif /* USE_XFONTSET */
805 Dimension width, height;
813 newstring = XmStringLtoRCreate (&string[start], XmFONTLIST_DEFAULT_TAG);
815 XtDisplay (mw), window,
819 1000, /* ???? width */
820 XmALIGNMENT_BEGINNING,
821 0, /* ???? layout_direction */
824 XmStringExtent (mw->menu.font_list, newstring, &width, &height);
825 XmStringFree (newstring);
835 XtDisplay (mw), window, mw->menu.font_set, gc,
836 x, y + mw->menu.font_ascent, &string[start], end - start);
838 mw->menu.font_set, &string[start], end - start, &ri, &rl);
847 XtDisplay (mw), window, gc,
848 x, y + mw->menu.font_ascent, &string[start], end - start);
850 mw->menu.font, &string[start], end - start,
851 &drop, &drop, &drop, &xcs);
858 string_draw_u (XlwMenuWidget mw,
873 XmStringGetLtoR (string, XmFONTLIST_DEFAULT_TAG, &chars);
877 for (i=0;chars[i];++i) {
878 if (chars[i]=='%'&&chars[i+1]=='_') {
881 x += string_draw_range (mw, window, x, y, gc, chars, s, i);
882 w = string_draw_range (mw, window, x, y, gc, chars, i+2, i+3);
884 /* underline next character */
885 XDrawLine (XtDisplay (mw), window, gc, x - 1,
886 y + mw->menu.font_ascent + 1,
887 x + w - 1, y + mw->menu.font_ascent + 1 );
893 x += string_draw_range (mw, window, x, y, gc, chars, s, i);
897 binding_draw (XlwMenuWidget mw, Window w, int x, int y, GC gc, char *value)
900 XmString xm_value = XmStringCreateLtoR(value, XmSTRING_DEFAULT_CHARSET);
901 string_draw (mw, w, x, y, gc, xm_value);
902 XmStringFree (xm_value);
904 string_draw (mw, w, x, y, gc, value);
908 /* Low level code for drawing 3-D edges. */
910 shadow_rectangle_draw (Display *dpy,
917 unsigned int thickness)
926 points [1].x = x + width;
928 points [2].x = x + width - thickness;
929 points [2].y = y + thickness;
931 points [3].y = y + thickness;
932 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
934 points [0].y = y + thickness;
936 points [1].y = y + height;
937 points [2].x = x + thickness;
938 points [2].y = y + height - thickness;
939 points [3].x = x + thickness;
940 points [3].y = y + thickness;
941 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
942 points [0].x = x + width;
944 points [1].x = x + width - thickness;
945 points [1].y = y + thickness;
946 points [2].x = x + width - thickness;
947 points [2].y = y + height - thickness;
948 points [3].x = x + width;
949 points [3].y = y + height - thickness;
950 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin);
952 points [0].y = y + height;
953 points [1].x = x + width;
954 points [1].y = y + height;
955 points [2].x = x + width;
956 points [2].y = y + height - thickness;
957 points [3].x = x + thickness;
958 points [3].y = y + height - thickness;
959 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin);
962 typedef enum e_shadow_type
964 /* these are Motif compliant */
970 SHADOW_ETCHED_OUT_DASH,
971 SHADOW_ETCHED_IN_DASH,
974 SHADOW_SINGLE_DASHED_LINE,
975 SHADOW_DOUBLE_DASHED_LINE,
977 /* these are all non-Motif */
978 SHADOW_DOUBLE_ETCHED_OUT,
979 SHADOW_DOUBLE_ETCHED_IN,
980 SHADOW_DOUBLE_ETCHED_OUT_DASH,
981 SHADOW_DOUBLE_ETCHED_IN_DASH
985 shadow_draw (XlwMenuWidget mw,
992 Display *dpy = XtDisplay (mw);
995 int thickness = mw->menu.shadow_thickness;
999 Boolean etched = False;
1003 case SHADOW_BACKGROUND:
1004 top_gc = bottom_gc = mw->menu.background_gc;
1006 case SHADOW_ETCHED_IN:
1007 top_gc = mw->menu.shadow_bottom_gc;
1008 bottom_gc = mw->menu.shadow_top_gc;
1011 case SHADOW_ETCHED_OUT:
1012 top_gc = mw->menu.shadow_top_gc;
1013 bottom_gc = mw->menu.shadow_bottom_gc;
1017 top_gc = mw->menu.shadow_bottom_gc;
1018 bottom_gc = mw->menu.shadow_top_gc;
1022 top_gc = mw->menu.shadow_top_gc;
1023 bottom_gc = mw->menu.shadow_bottom_gc;
1029 unsigned int half = thickness/2;
1030 shadow_rectangle_draw (dpy,
1035 width - half, height - half,
1037 shadow_rectangle_draw (dpy,
1042 width - half , height - half,
1047 shadow_rectangle_draw (dpy,
1058 arrow_decoration_draw (XlwMenuWidget mw,
1064 Display *dpy = XtDisplay (mw);
1068 int thickness = mw->menu.shadow_thickness;
1071 int length = (int)((double)width * 0.87);
1072 int thick_med = (int)((double)thickness * 1.73);
1075 half_width = width/2 + 1;
1077 half_width = width/2;
1079 select_gc = mw->menu.background_gc;
1083 top_gc = mw->menu.shadow_bottom_gc;
1084 bottom_gc = mw->menu.shadow_top_gc;
1088 top_gc = mw->menu.shadow_top_gc;
1089 bottom_gc = mw->menu.shadow_bottom_gc;
1092 /* Fill internal area. We do this first so that the borders have a
1094 points [0].x = x + thickness;
1095 points [0].y = y + thickness;
1096 points [1].x = x + length - thickness;
1097 points [1].y = y + half_width;
1098 points [2].x = x + length - thickness;
1099 points [2].y = y + half_width + thickness;
1100 points [3].x = x + thickness;
1101 points [3].y = y + width - thickness;
1114 points [1].x = x + thickness;
1115 points [1].y = y + thick_med;
1116 points [2].x = x + thickness;
1117 points [2].y = y + width - thick_med;
1119 points [3].y = y + width;
1121 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
1125 points [0].y = y + width;
1126 points [1].x = x + length;
1127 points [1].y = y + half_width;
1128 points [2].x = x + length - (thickness + thickness);
1129 points [2].y = y + half_width;
1130 points [3].x = x + thickness;
1131 points [3].y = y + width - thick_med;
1133 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin);
1138 points [1].x = x + length;
1139 points [1].y = y + half_width;
1140 points [2].x = x + length - (thickness + thickness);
1141 points [2].y = y + half_width;
1142 points [3].x = x + thickness;
1143 points [3].y = y + thick_med;
1145 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
1149 toggle_decoration_draw (XlwMenuWidget mw,
1155 Display *dpy = XtDisplay (mw);
1156 int thickness = mw->menu.shadow_thickness;
1158 GC select_gc = mw->menu.select_gc;
1165 /* Fill internal area. */
1167 XFillRectangle (dpy,
1172 width - (2*thickness),
1173 width - (2*thickness));
1175 shadow_draw (mw, window, x, y, width, width, type);
1179 radio_decoration_draw (XlwMenuWidget mw,
1185 Display *dpy = XtDisplay (mw);
1188 GC select_gc = mw->menu.select_gc;
1189 int thickness = mw->menu.shadow_thickness;
1199 half_width = width/2;
1203 top_gc = mw->menu.shadow_bottom_gc;
1204 bottom_gc = mw->menu.shadow_top_gc;
1208 top_gc = mw->menu.shadow_top_gc;
1209 bottom_gc = mw->menu.shadow_bottom_gc;
1213 /* Draw the bottom first, just in case the regions overlap.
1214 The top should cast the longer shadow. */
1215 points [0].x = x; /* left corner */
1216 points [0].y = y + half_width;
1217 points [1].x = x + half_width; /* bottom corner */
1218 points [1].y = y + width;
1219 points [2].x = x + half_width; /* bottom inside corner */
1220 points [2].y = y + width - thickness;
1221 points [3].x = x + thickness; /* left inside corner */
1222 points [3].y = y + half_width;
1224 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin);
1226 points [0].x = x + half_width; /* bottom corner */
1227 points [0].y = y + width;
1228 points [1].x = x + width; /* right corner */
1229 points [1].y = y + half_width;
1230 points [2].x = x + width - thickness; /* right inside corner */
1231 points [2].y = y + half_width;
1232 points [3].x = x + half_width; /* bottom inside corner */
1233 points [3].y = y + width - thickness;
1235 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin);
1237 points [0].x = x; /* left corner */
1238 points [0].y = y + half_width;
1239 points [1].x = x + half_width; /* top corner */
1241 points [2].x = x + half_width; /* top inside corner */
1242 points [2].y = y + thickness;
1243 points [3].x = x + thickness; /* left inside corner */
1244 points [3].y = y + half_width;
1246 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
1248 points [0].x = x + half_width; /* top corner */
1250 points [1].x = x + width; /* right corner */
1251 points [1].y = y + half_width;
1252 points [2].x = x + width - thickness; /* right inside corner */
1253 points [2].y = y + half_width;
1254 points [3].x = x + half_width; /* top inside corner */
1255 points [3].y = y + thickness;
1257 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
1259 /* Draw the bottom first, just in case the regions overlap.
1260 The top should cast the longer shadow. */
1262 points [npoints].x = x; /* left corner */
1263 points [npoints++].y = y + half_width;
1264 points [npoints].x = x + half_width; /* bottom corner */
1265 points [npoints++].y = y + width;
1266 points [npoints].x = x + width; /* right corner */
1267 points [npoints++].y = y + half_width;
1268 points [npoints].x = x + width - thickness; /* right inside corner */
1269 points [npoints++].y = y + half_width;
1270 points [npoints].x = x + half_width; /* bottom inside corner */
1271 points [npoints++].y = y + width - thickness;
1272 points [npoints].x = x + thickness; /* left inside corner */
1273 points [npoints++].y = y + half_width;
1275 XFillPolygon (dpy, window, bottom_gc,
1276 points, npoints, Nonconvex, CoordModeOrigin);
1280 points [npoints].x = x; /* left corner */
1281 points [npoints++].y = y + half_width;
1282 points [npoints].x = x + half_width; /* top corner */
1283 points [npoints++].y = y;
1284 points [npoints].x = x + width; /* right corner */
1285 points [npoints++].y = y + half_width;
1286 points [npoints].x = x + width - thickness; /* right inside corner */
1287 points [npoints++].y = y + half_width;
1288 points [npoints].x = x + half_width; /* top inside corner */
1289 points [npoints++].y = y + thickness;
1290 points [npoints].x = x + thickness; /* left inside corner */
1291 points [npoints++].y = y + half_width;
1293 XFillPolygon (dpy, window, top_gc, points, npoints, Nonconvex,
1298 /* Fill internal area. */
1301 points [0].x = x + thickness;
1302 points [0].y = y + half_width;
1303 points [1].x = x + half_width;
1304 points [1].y = y + thickness;
1305 points [2].x = x + width - thickness;
1306 points [2].y = y + half_width;
1307 points [3].x = x + half_width;
1308 points [3].y = y + width - thickness;
1320 separator_decoration_draw (XlwMenuWidget mw,
1327 Display *dpy = XtDisplay (mw);
1330 unsigned int offset = 0;
1331 unsigned int num_separators = 1;
1332 unsigned int top_line_thickness = 0;
1333 unsigned int bottom_line_thickness = 0;
1334 Boolean dashed = False;
1338 case SHADOW_NO_LINE: /* nothing to do */
1340 case SHADOW_DOUBLE_LINE:
1342 case SHADOW_SINGLE_LINE:
1343 top_gc = bottom_gc = mw->menu.foreground_gc;
1344 top_line_thickness = 1;
1346 case SHADOW_DOUBLE_DASHED_LINE:
1348 case SHADOW_SINGLE_DASHED_LINE:
1349 top_gc = bottom_gc = mw->menu.foreground_gc;
1350 top_line_thickness = 1;
1353 case SHADOW_DOUBLE_ETCHED_OUT_DASH:
1355 case SHADOW_ETCHED_OUT_DASH:
1356 top_gc = mw->menu.shadow_top_gc;
1357 bottom_gc = mw->menu.shadow_bottom_gc;
1358 top_line_thickness = mw->menu.shadow_thickness/2;
1359 bottom_line_thickness = mw->menu.shadow_thickness - top_line_thickness;
1362 case SHADOW_DOUBLE_ETCHED_IN_DASH:
1364 case SHADOW_ETCHED_IN_DASH:
1365 top_gc = mw->menu.shadow_bottom_gc;
1366 bottom_gc = mw->menu.shadow_top_gc;
1367 top_line_thickness = mw->menu.shadow_thickness/2;
1368 bottom_line_thickness = mw->menu.shadow_thickness - top_line_thickness;
1371 case SHADOW_DOUBLE_ETCHED_OUT:
1373 case SHADOW_ETCHED_OUT:
1374 top_gc = mw->menu.shadow_top_gc;
1375 bottom_gc = mw->menu.shadow_bottom_gc;
1376 top_line_thickness = mw->menu.shadow_thickness/2;
1377 bottom_line_thickness = mw->menu.shadow_thickness - top_line_thickness;
1379 case SHADOW_DOUBLE_ETCHED_IN:
1381 case SHADOW_ETCHED_IN:
1383 top_gc = mw->menu.shadow_bottom_gc;
1384 bottom_gc = mw->menu.shadow_top_gc;
1385 top_line_thickness = mw->menu.shadow_thickness/2;
1386 bottom_line_thickness = mw->menu.shadow_thickness - top_line_thickness;
1393 values.line_style = LineOnOffDash;
1394 if (top_line_thickness > 0)
1395 XChangeGC (dpy, top_gc, GCLineStyle, &values);
1396 if (bottom_line_thickness > 0 && bottom_gc != top_gc)
1397 XChangeGC (dpy, bottom_gc, GCLineStyle, &values);
1400 while (num_separators--)
1403 for (i = 0; i < top_line_thickness; i++)
1404 XDrawLine (dpy, window, top_gc, x, y + i, x + width, y + i);
1406 for (i = 0; i < bottom_line_thickness; i++)
1407 XDrawLine (dpy, window, bottom_gc,
1408 x, y + top_line_thickness + offset + i,
1409 x + width, y + top_line_thickness + offset + i);
1410 y += (top_line_thickness + offset + bottom_line_thickness + 1);
1416 values.line_style = LineSolid;
1417 if (top_line_thickness > 0)
1418 XChangeGC (dpy, top_gc, GCLineStyle, &values);
1419 if (bottom_line_thickness > 0 && bottom_gc != top_gc)
1420 XChangeGC (dpy, bottom_gc, GCLineStyle, &values);
1424 #define SLOPPY_TYPES 0 /* 0=off, 1=error check, 2=easy to please */
1426 #if SLOPPY_TYPES < 2
1428 static char *wv_types[] =
1442 print_widget_value (widget_value *wv, int just_one, int depth)
1446 for (i = 0; i < depth; i++)
1451 printf ("%s(null widget value pointer)\n", d);
1454 printf ("%stype: %s\n", d, wv_types [wv->type]);
1456 printf ("%sname: %s\n", d, (wv->name ? wv->name : "(null)"));
1458 if (wv->name) printf ("%sname: %s\n", d, wv->name);
1460 if (wv->value) printf ("%svalue: %s\n", d, wv->value);
1461 if (wv->key) printf ("%skey: %s\n", d, wv->key);
1462 printf ("%senabled: %d\n", d, wv->enabled);
1465 printf ("\n%scontents: \n", d);
1466 print_widget_value (wv->contents, 0, depth + 5);
1468 if (!just_one && wv->next)
1471 print_widget_value (wv->next, 0, depth);
1477 all_dashes_p (char *s)
1480 if (!s || s[0] == '\0')
1482 for (p = s; *p == '-'; p++);
1484 if (*p == '!' || *p == '\0')
1490 static widget_value_type
1491 menu_item_type (widget_value *val)
1493 if (val->type != UNSPECIFIED_TYPE)
1498 if (all_dashes_p (val->name))
1499 return SEPARATOR_TYPE;
1500 else if (val->name && val->name[0] == '\0') /* push right */
1501 return PUSHRIGHT_TYPE;
1502 else if (val->contents) /* cascade */
1503 return CASCADE_TYPE;
1504 else if (val->call_data) /* push button */
1515 label_button_size (XlwMenuWidget mw,
1518 unsigned int *toggle_width,
1519 unsigned int *label_width,
1520 unsigned int *bindings_width,
1521 unsigned int *height)
1523 *height = (mw->menu.font_ascent + mw->menu.font_descent +
1524 2 * mw->menu.vertical_margin +
1525 2 * mw->menu.shadow_thickness);
1526 /* no left column decoration */
1527 *toggle_width = mw->menu.horizontal_margin + mw->menu.shadow_thickness;;
1529 *label_width = string_width_u (mw, resource_widget_value (mw, val));
1530 *bindings_width = mw->menu.horizontal_margin + mw->menu.shadow_thickness;
1534 label_button_draw (XlwMenuWidget mw,
1537 Boolean highlighted,
1541 unsigned int height,
1542 unsigned int label_offset,
1543 unsigned int binding_tab)
1545 int y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin;
1549 label_offset = mw->menu.shadow_thickness + mw->menu.horizontal_margin;
1551 if (highlighted && (in_menubar || val->contents))
1552 gc = mw->menu.highlight_gc;
1553 else if (in_menubar || val->contents)
1554 gc = mw->menu.foreground_gc;
1556 gc = mw->menu.title_gc;
1558 /* Draw the label string. */
1561 x + label_offset, y + y_offset,
1563 resource_widget_value (mw, val));
1567 push_button_size (XlwMenuWidget mw,
1570 unsigned int *toggle_width,
1571 unsigned int *label_width,
1572 unsigned int *bindings_width,
1573 unsigned int *height)
1576 label_button_size (mw, val, in_menubar,
1577 toggle_width, label_width, bindings_width,
1580 /* key bindings to display? */
1581 if (!in_menubar && val->key)
1585 XmString key = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
1586 w = string_width (mw, key);
1589 char *key = val->key;
1590 w = string_width (mw, key);
1592 *bindings_width += w + mw->menu.column_spacing;
1597 push_button_draw (XlwMenuWidget mw,
1600 Boolean highlighted,
1604 unsigned int height,
1605 unsigned int label_offset,
1606 unsigned int binding_offset)
1608 int y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin;
1611 Boolean menu_pb = in_menubar && (menu_item_type (val) == BUTTON_TYPE);
1613 /* Draw the label string. */
1615 label_offset = mw->menu.shadow_thickness + mw->menu.horizontal_margin;
1620 gc = mw->menu.highlight_gc;
1622 gc = mw->menu.inactive_gc;
1627 gc = mw->menu.button_gc;
1629 gc = mw->menu.inactive_button_gc;
1634 gc = mw->menu.foreground_gc;
1636 gc = mw->menu.inactive_gc;
1641 x + label_offset, y + y_offset,
1643 resource_widget_value (mw, val));
1645 /* Draw the keybindings */
1648 if (!binding_offset)
1650 unsigned int s_width =
1651 string_width (mw, resource_widget_value (mw, val));
1652 binding_offset = label_offset + s_width + mw->menu.shadow_thickness;
1654 binding_draw (mw, window,
1655 x + binding_offset + mw->menu.column_spacing,
1656 y + y_offset, gc, val->key);
1659 /* Draw the shadow */
1665 type = (val->selected ? SHADOW_ETCHED_OUT : SHADOW_ETCHED_IN);
1672 type = SHADOW_BACKGROUND;
1675 shadow_draw (mw, window, x, y, width, height, type);
1679 arrow_decoration_height (XlwMenuWidget mw)
1681 int result = (mw->menu.font_ascent + mw->menu.font_descent) / 2;
1683 result += 2 * mw->menu.shadow_thickness;
1685 if (result > (mw->menu.font_ascent + mw->menu.font_descent))
1686 result = mw->menu.font_ascent + mw->menu.font_descent;
1692 cascade_button_size (XlwMenuWidget mw,
1695 unsigned int *toggle_width,
1696 unsigned int *label_width,
1697 unsigned int *arrow_width,
1698 unsigned int *height)
1701 label_button_size (mw, val, in_menubar,
1702 toggle_width, label_width, arrow_width,
1704 /* we have a pull aside arrow */
1707 *arrow_width += arrow_decoration_height (mw) + mw->menu.column_spacing;
1712 cascade_button_draw (XlwMenuWidget mw,
1715 Boolean highlighted,
1719 unsigned int height,
1720 unsigned int label_offset,
1721 unsigned int binding_offset)
1725 /* Draw the label string. */
1726 label_button_draw (mw, val, in_menubar, highlighted,
1727 window, x, y, width, height, label_offset,
1730 /* Draw the pull aside arrow */
1731 if (!in_menubar && val->contents)
1734 unsigned int arrow_height = arrow_decoration_height (mw);
1736 y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin +
1737 (mw->menu.font_ascent+mw->menu.font_descent - arrow_height)/2;
1739 if (!binding_offset)
1741 unsigned int s_width =
1742 string_width (mw, resource_widget_value (mw, val));
1745 label_offset = mw->menu.shadow_thickness +
1746 mw->menu.horizontal_margin;
1748 binding_offset = label_offset + s_width + mw->menu.shadow_thickness;
1751 arrow_decoration_draw (mw,
1753 x + binding_offset + mw->menu.column_spacing,
1759 /* Draw the shadow */
1763 type = SHADOW_BACKGROUND;
1765 shadow_draw (mw, window, x, y, width, height, type);
1769 toggle_decoration_height (XlwMenuWidget mw)
1772 if (mw->menu.indicator_size > 0)
1773 rv = mw->menu.indicator_size;
1775 rv = mw->menu.font_ascent;
1777 if (rv > (mw->menu.font_ascent + mw->menu.font_descent))
1778 rv = mw->menu.font_ascent + mw->menu.font_descent;
1780 /* radio button can't be smaller than its border or a filling
1781 error will occur. */
1782 if (rv < 2 * mw->menu.shadow_thickness)
1783 rv = 2 * mw->menu.shadow_thickness;
1789 toggle_button_size (XlwMenuWidget mw,
1792 unsigned int *toggle_width,
1793 unsigned int *label_width,
1794 unsigned int *bindings_width,
1795 unsigned int *height)
1798 push_button_size (mw, val, in_menubar,
1799 toggle_width, label_width, bindings_width,
1801 /* we have a toggle */
1802 *toggle_width += toggle_decoration_height (mw) + mw->menu.column_spacing;
1806 toggle_button_draw (XlwMenuWidget mw,
1809 Boolean highlighted,
1813 unsigned int height,
1814 unsigned int label_tab,
1815 unsigned int binding_tab)
1819 unsigned int t_height = toggle_decoration_height (mw);
1821 /* Draw a toggle. */
1822 x_offset = mw->menu.shadow_thickness + mw->menu.horizontal_margin;
1823 y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin;
1824 y_offset += (mw->menu.font_ascent + mw->menu.font_descent - t_height)/2;
1826 toggle_decoration_draw (mw, window, x + x_offset, y + y_offset,
1827 t_height, val->selected);
1829 /* Draw the pushbutton parts. */
1830 push_button_draw (mw, val, in_menubar, highlighted, window, x, y, width,
1831 height, label_tab, binding_tab);
1835 radio_decoration_height (XlwMenuWidget mw)
1837 return toggle_decoration_height (mw);
1841 radio_button_draw (XlwMenuWidget mw,
1844 Boolean highlighted,
1848 unsigned int height,
1849 unsigned int label_tab,
1850 unsigned int binding_tab)
1854 unsigned int r_height = radio_decoration_height (mw);
1856 /* Draw a toggle. */
1857 x_offset = mw->menu.shadow_thickness + mw->menu.horizontal_margin;
1858 y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin;
1859 y_offset += (mw->menu.font_ascent + mw->menu.font_descent - r_height)/2;
1861 radio_decoration_draw (mw, window, x + x_offset, y + y_offset, r_height,
1864 /* Draw the pushbutton parts. */
1865 push_button_draw (mw, val, in_menubar, highlighted, window, x, y, width,
1866 height, label_tab, binding_tab);
1869 static struct _shadow_names
1876 { "singleLine", SHADOW_SINGLE_LINE },
1877 { "doubleLine", SHADOW_DOUBLE_LINE },
1878 { "singleDashedLine", SHADOW_SINGLE_DASHED_LINE },
1879 { "doubleDashedLine", SHADOW_DOUBLE_DASHED_LINE },
1880 { "noLine", SHADOW_NO_LINE },
1881 { "shadowEtchedIn", SHADOW_ETCHED_IN },
1882 { "shadowEtchedOut", SHADOW_ETCHED_OUT },
1883 { "shadowEtchedInDash", SHADOW_ETCHED_IN_DASH },
1884 { "shadowEtchedOutDash", SHADOW_ETCHED_OUT_DASH },
1886 { "shadowDoubleEtchedIn", SHADOW_DOUBLE_ETCHED_IN },
1887 { "shadowDoubleEtchedOut", SHADOW_DOUBLE_ETCHED_OUT },
1888 { "shadowDoubleEtchedInDash", SHADOW_DOUBLE_ETCHED_IN_DASH },
1889 { "shadowDoubleEtchedOutDash", SHADOW_DOUBLE_ETCHED_OUT_DASH }
1893 separator_type (char *name)
1898 for (i = 0; i < (int) (XtNumber (shadow_names)); i++ )
1900 if (strcmp (name, shadow_names[i].name) == 0)
1901 return shadow_names[i].type;
1904 return SHADOW_BACKGROUND;
1908 separator_decoration_height (XlwMenuWidget mw, widget_value *val)
1911 switch (separator_type (val->value))
1913 case SHADOW_NO_LINE:
1914 case SHADOW_SINGLE_LINE:
1915 case SHADOW_SINGLE_DASHED_LINE:
1917 case SHADOW_DOUBLE_LINE:
1918 case SHADOW_DOUBLE_DASHED_LINE:
1920 case SHADOW_DOUBLE_ETCHED_OUT:
1921 case SHADOW_DOUBLE_ETCHED_IN:
1922 case SHADOW_DOUBLE_ETCHED_OUT_DASH:
1923 case SHADOW_DOUBLE_ETCHED_IN_DASH:
1924 return (1 + 2 * mw->menu.shadow_thickness);
1925 case SHADOW_ETCHED_OUT:
1926 case SHADOW_ETCHED_IN:
1928 return mw->menu.shadow_thickness;
1933 separator_size (XlwMenuWidget mw,
1936 unsigned int *toggle_width,
1937 unsigned int *label_width,
1938 unsigned int *rest_width,
1939 unsigned int *height)
1941 *height = separator_decoration_height (mw, val);
1943 *toggle_width = *rest_width = 0;
1947 separator_draw (XlwMenuWidget mw,
1950 Boolean highlighted,
1954 unsigned int height,
1955 unsigned int label_tab,
1956 unsigned int binding_tab)
1958 unsigned int sep_width;
1965 separator_decoration_draw (mw,
1971 separator_type(val->value));
1975 pushright_size (XlwMenuWidget mw,
1978 unsigned int *toggle_width,
1979 unsigned int *label_width,
1980 unsigned int *rest_width,
1981 unsigned int *height)
1983 *height = *label_width = *toggle_width = *rest_width = 0;
1987 size_menu_item (XlwMenuWidget mw,
1990 unsigned int *toggle_width,
1991 unsigned int *label_width,
1992 unsigned int *rest_width,
1993 unsigned int *height)
1995 void (*function_ptr) (XlwMenuWidget _mw,
1997 Boolean _in_menubar,
1998 unsigned int *_toggle_width,
1999 unsigned int *_label_width,
2000 unsigned int *_rest_width,
2001 unsigned int *_height);
2003 switch (menu_item_type (val))
2007 function_ptr = toggle_button_size;
2009 case SEPARATOR_TYPE:
2010 function_ptr = separator_size;
2012 case INCREMENTAL_TYPE:
2014 function_ptr = cascade_button_size;
2017 function_ptr = push_button_size;
2019 case PUSHRIGHT_TYPE:
2020 function_ptr = pushright_size;
2024 function_ptr = label_button_size;
2028 (*function_ptr) (mw,
2038 display_menu_item (XlwMenuWidget mw,
2042 Boolean highlighted,
2044 Boolean just_compute)
2047 int x = where->x /* + mw->menu.shadow_thickness */ ;
2048 int y = where->y /* + mw->menu.shadow_thickness */ ;
2049 unsigned int toggle_width;
2050 unsigned int label_width;
2051 unsigned int binding_width;
2053 unsigned int height;
2054 unsigned int label_tab;
2055 unsigned int binding_tab;
2056 void (*function_ptr) (XlwMenuWidget _mw,
2058 Boolean _in_menubar,
2059 Boolean _highlighted,
2062 unsigned int _width,
2063 unsigned int _height,
2064 unsigned int _label_tab,
2065 unsigned int _binding_tab);
2067 size_menu_item (mw, val, horizontal,
2068 &toggle_width, &label_width, &binding_width, &height);
2072 width = toggle_width + label_width + binding_width;
2073 height = ws->height - 2 * mw->menu.shadow_thickness;
2077 width = ws->width - 2 * mw->menu.shadow_thickness;
2078 toggle_width = ws->toggle_width;
2079 label_width = ws->label_width;
2088 label_tab = toggle_width;
2089 binding_tab = toggle_width + label_width;
2091 switch (menu_item_type (val))
2094 function_ptr = toggle_button_draw;
2097 function_ptr = radio_button_draw;
2099 case SEPARATOR_TYPE:
2100 function_ptr = separator_draw;
2102 case INCREMENTAL_TYPE:
2104 function_ptr = cascade_button_draw;
2107 function_ptr = push_button_draw;
2110 function_ptr = label_button_draw;
2112 default: /* do no drawing */
2116 (*function_ptr) (mw,
2128 size_menu (XlwMenuWidget mw, int level)
2130 unsigned int toggle_width;
2131 unsigned int label_width;
2132 unsigned int rest_width;
2133 unsigned int height;
2134 unsigned int max_toggle_width = 0;
2135 unsigned int max_label_width = 0;
2136 unsigned int max_rest_width = 0;
2137 unsigned int max_height = 0;
2138 int horizontal_p = mw->menu.horizontal && (level == 0);
2142 if (level >= mw->menu.old_depth)
2145 ws = &mw->menu.windows [level];
2147 for (val = mw->menu.old_stack [level]->contents; val; val = val->next)
2158 max_label_width += toggle_width + label_width + rest_width;
2159 if (height > max_height)
2160 max_height = height;
2164 if (max_toggle_width < toggle_width)
2165 max_toggle_width = toggle_width;
2166 if (max_label_width < label_width)
2167 max_label_width = label_width;
2168 if (max_rest_width < rest_width)
2169 max_rest_width = rest_width;
2170 max_height += height;
2174 ws->height = max_height;
2175 ws->width = max_label_width + max_rest_width + max_toggle_width;
2176 ws->toggle_width = max_toggle_width;
2177 ws->label_width = max_label_width;
2179 ws->width += 2 * mw->menu.shadow_thickness;
2180 ws->height += 2 * mw->menu.shadow_thickness;
2184 display_menu (XlwMenuWidget mw, int level, Boolean just_compute_p,
2185 XPoint *highlighted_pos, XPoint *hit, widget_value **hit_return,
2186 widget_value *this, widget_value *that)
2189 widget_value *following_item;
2192 int horizontal_p = mw->menu.horizontal && (level == 0);
2194 int just_compute_this_one_p;
2196 if (level >= mw->menu.old_depth)
2199 if (level < mw->menu.old_depth - 1)
2200 following_item = mw->menu.old_stack [level + 1];
2203 if (lw_menu_accelerate
2204 && level == mw->menu.old_depth - 1
2205 && mw->menu.old_stack [level]->type == CASCADE_TYPE)
2206 just_compute_p = True;
2207 following_item = NULL;
2210 #if SLOPPY_TYPES == 1
2211 puts("===================================================================");
2212 print_widget_value (following_item, 1, 0);
2218 where.x = mw->menu.shadow_thickness;
2219 where.y = mw->menu.shadow_thickness;
2221 ws = &mw->menu.windows [level];
2222 for (val = mw->menu.old_stack [level]->contents; val; val = val->next)
2226 highlighted_p = (val == following_item);
2227 /* If this is the partition (the dummy item which says that menus
2228 after this should be flushright) then figure out how big the
2229 following items are. This means we walk down the tail of the
2230 list twice, but that's no big deal - it's short.
2232 if (horizontal_p && (menu_item_type (val) == PUSHRIGHT_TYPE))
2235 XPoint flushright_size;
2237 flushright_size.x = 0;
2238 flushright_size.y = 0;
2239 for (rest = val; rest; rest = rest->next)
2240 display_menu_item (mw, rest, ws, &flushright_size,
2241 highlighted_p, horizontal_p, True);
2242 new_x = ws->width - (flushright_size.x + mw->menu.shadow_thickness);
2243 if (new_x > where.x)
2245 /* We know what we need; don't draw this item. */
2249 if (highlighted_p && highlighted_pos)
2252 highlighted_pos->x = where.x;
2254 highlighted_pos->y = where.y;
2257 just_compute_this_one_p =
2258 just_compute_p || ((this || that) && val != this && val != that);
2262 display_menu_item (mw, val, ws, &where, highlighted_p, horizontal_p,
2263 just_compute_this_one_p);
2265 if (highlighted_p && highlighted_pos)
2268 highlighted_pos->y = ws->height;
2270 highlighted_pos->x = ws->width;
2273 if (hit && !*hit_return)
2275 if (horizontal_p && hit->x > start.x && hit->x <= where.x)
2277 else if (!horizontal_p && hit->y > start.y && hit->y <= where.y)
2282 where.y = mw->menu.shadow_thickness;
2284 where.x = mw->menu.shadow_thickness;
2287 /* Draw slab edges around menu */
2288 if (!just_compute_p)
2289 shadow_draw(mw, ws->window, 0, 0, ws->width, ws->height, SHADOW_OUT);
2294 set_new_state (XlwMenuWidget mw, widget_value *val, int level)
2298 mw->menu.new_depth = 0;
2299 for (i = 0; i < level; i++)
2300 push_new_stack (mw, mw->menu.old_stack [i]);
2302 push_new_stack (mw, val);
2306 make_windows_if_needed (XlwMenuWidget mw, int n)
2310 XSetWindowAttributes xswa;
2315 window_state *windows;
2318 if (mw->menu.windows_length >= n)
2321 root = RootWindowOfScreen (XtScreen(mw));
2322 /* grab the visual and depth from the nearest shell ancestor */
2323 visual = CopyFromParent;
2324 depth = CopyFromParent;
2326 while (visual == CopyFromParent && p)
2330 visual = ((ShellWidget)p)->shell.visual;
2331 depth = p->core.depth;
2336 xswa.save_under = True;
2337 xswa.override_redirect = True;
2338 xswa.background_pixel = mw->core.background_pixel;
2339 xswa.border_pixel = mw->core.border_pixel;
2340 xswa.event_mask = (ExposureMask | ButtonMotionMask
2341 | ButtonReleaseMask | ButtonPressMask);
2342 xswa.cursor = mw->menu.cursor_shape;
2343 xswa.colormap = mw->core.colormap;
2344 mask = CWSaveUnder | CWOverrideRedirect | CWBackPixel | CWBorderPixel
2345 | CWEventMask | CWCursor | CWColormap;
2347 if (mw->menu.use_backing_store)
2349 xswa.backing_store = Always;
2350 mask |= CWBackingStore;
2353 if (!mw->menu.windows)
2356 (window_state *) XtMalloc (n * sizeof (window_state));
2362 (window_state *) XtRealloc ((char *) mw->menu.windows,
2363 n * sizeof (window_state));
2364 start_at = mw->menu.windows_length;
2366 mw->menu.windows_length = n;
2368 windows = mw->menu.windows;
2370 for (i = start_at; i < n; i++)
2374 windows [i].width = 1;
2375 windows [i].height = 1;
2376 windows [i].window =
2377 XCreateWindow (XtDisplay (mw),
2380 0, depth, CopyFromParent, visual, mask, &xswa);
2384 /* Make the window fit in the screen */
2386 fit_to_screen (XlwMenuWidget mw, window_state *ws, window_state *previous_ws,
2387 Boolean horizontal_p)
2389 int screen_width = WidthOfScreen (XtScreen (mw));
2390 int screen_height = HeightOfScreen (XtScreen (mw));
2394 else if ((int) (ws->x + ws->width) > screen_width)
2397 ws->x = previous_ws->x - ws->width;
2400 ws->x = screen_width - ws->width;
2402 /* This check is to make sure we cut off the right side
2403 instead of the left side if the menu is wider than the
2411 else if ((int) (ws->y + ws->height) > screen_height)
2415 /* A pulldown must either be entirely above or below the menubar.
2416 If we're here, the pulldown doesn't fit below the menubar, so
2417 let's determine if it will fit above the menubar.
2418 Only put it above if there is more room above than below.
2419 Note shadow_thickness offset to allow for slab surround.
2421 if (ws->y > (screen_height / 2))
2422 ws->y = previous_ws->y - ws->height + mw->menu.shadow_thickness;
2426 ws->y = screen_height - ws->height;
2427 /* if it's taller than the screen, display the topmost part
2428 that will fit, beginning at the top of the screen. */
2435 /* Updates old_stack from new_stack and redisplays. */
2437 remap_menubar (XlwMenuWidget mw)
2441 XPoint selection_position;
2442 int old_depth = mw->menu.old_depth;
2443 int new_depth = mw->menu.new_depth;
2444 widget_value **old_stack;
2445 widget_value **new_stack;
2446 window_state *windows;
2447 widget_value *old_selection;
2448 widget_value *new_selection;
2450 /* Check that enough windows and old_stack are ready. */
2451 make_windows_if_needed (mw, new_depth);
2452 make_old_stack_space (mw, new_depth);
2453 windows = mw->menu.windows;
2454 old_stack = mw->menu.old_stack;
2455 new_stack = mw->menu.new_stack;
2457 /* compute the last identical different entry */
2458 for (i = 1; i < old_depth && i < new_depth; i++)
2459 if (old_stack [i] != new_stack [i])
2463 if (lw_menu_accelerate
2465 && last_same == old_depth - 1
2466 && old_stack [last_same]->contents)
2469 /* Memorize the previously selected item to be able to refresh it */
2470 old_selection = last_same + 1 < old_depth ? old_stack [last_same + 1] : NULL;
2471 new_selection = last_same + 1 < new_depth ? new_stack [last_same + 1] : NULL;
2473 /* updates old_state from new_state. It has to be done now because
2474 display_menu (called below) uses the old_stack to know what to display. */
2475 for (i = last_same + 1; i < new_depth; i++)
2476 old_stack [i] = new_stack [i];
2478 mw->menu.old_depth = new_depth;
2480 /* refresh the last seletion */
2481 selection_position.x = 0;
2482 selection_position.y = 0;
2483 display_menu (mw, last_same, new_selection == old_selection,
2484 &selection_position, NULL, NULL, old_selection, new_selection);
2486 /* Now popup the new menus */
2487 for (i = last_same + 1; i < new_depth && new_stack [i]->contents; i++)
2489 window_state *previous_ws = &windows [i - 1];
2490 window_state *ws = &windows [i];
2492 if (lw_menu_accelerate && i == new_depth - 1)
2495 ws->x = previous_ws->x + selection_position.x;
2496 ws->y = previous_ws->y + selection_position.y;
2498 /* take into account the slab around the new menu */
2499 ws->y -= mw->menu.shadow_thickness;
2502 widget_value *val = mw->menu.old_stack [i];
2503 if (val->contents->type == INCREMENTAL_TYPE)
2505 /* okay, we're now doing a lisp callback to incrementally generate
2506 more of the menu. */
2507 XtCallCallbackList ((Widget)mw,
2509 (XtPointer)val->contents);
2515 fit_to_screen (mw, ws, previous_ws, mw->menu.horizontal && i == 1);
2517 XClearWindow (XtDisplay (mw), ws->window);
2518 XMoveResizeWindow (XtDisplay (mw), ws->window, ws->x, ws->y,
2519 ws->width, ws->height);
2520 XMapRaised (XtDisplay (mw), ws->window);
2521 display_menu (mw, i, False, &selection_position, NULL, NULL, NULL, NULL);
2524 /* unmap the menus that popped down */
2526 last_same = new_depth;
2527 if (lw_menu_accelerate
2529 && new_stack [last_same - 1]->contents)
2532 for (i = last_same - 1; i < old_depth; i++)
2533 if (i >= last_same || !new_stack [i]->contents)
2534 XUnmapWindow (XtDisplay (mw), windows [i].window);
2538 motion_event_is_in_menu (XlwMenuWidget mw, XMotionEvent *ev, int level,
2539 XPoint *relative_pos)
2541 window_state *ws = &mw->menu.windows [level];
2542 int x = level == 0 ? ws->x : ws->x + mw->menu.shadow_thickness;
2543 int y = level == 0 ? ws->y : ws->y + mw->menu.shadow_thickness;
2544 relative_pos->x = ev->x_root - x;
2545 relative_pos->y = ev->y_root - y;
2546 return (x < ev->x_root && ev->x_root < (int) (x + ws->width) &&
2547 y < ev->y_root && ev->y_root < (int) (y + ws->height));
2551 map_event_to_widget_value (XlwMenuWidget mw, XMotionEvent *ev,
2552 widget_value **val_ptr, int *level,
2553 Boolean *inside_menu)
2556 XPoint relative_pos;
2560 *inside_menu = False;
2562 /* Find the window */
2564 for (i = mw->menu.old_depth - 1; i >= 0; i--)
2566 for (i = 0; i <= mw->menu.old_depth - 1; i++)
2569 ws = &mw->menu.windows [i];
2570 if (ws && motion_event_is_in_menu (mw, ev, i, &relative_pos))
2572 *inside_menu = True; /* special logic for menubar below... */
2573 if ((ev->type == ButtonPress) ||
2576 display_menu (mw, i, True, NULL, &relative_pos,
2577 val_ptr, NULL, NULL);
2581 *inside_menu = True;
2584 else if (mw->menu.horizontal || i == 0)
2586 /* if we're clicking on empty part of the menubar, then
2587 unpost the stay-up menu */
2588 *inside_menu = False;
2598 make_drawing_gcs (XlwMenuWidget mw)
2601 unsigned long flags = (GCFont | GCForeground | GCBackground);
2604 xgcv.font = default_font_of_font_list (mw->menu.font_list)->fid;
2606 xgcv.font = mw->menu.font->fid;
2609 xgcv.foreground = mw->core.background_pixel;
2610 xgcv.background = mw->menu.foreground;
2611 mw->menu.background_gc = XtGetGC ((Widget) mw, flags, &xgcv);
2613 xgcv.foreground = mw->menu.foreground;
2614 xgcv.background = mw->core.background_pixel;
2615 mw->menu.foreground_gc = XtGetGC ((Widget) mw, flags, &xgcv);
2617 if (mw->menu.select_color != (Pixel)-1)
2619 xgcv.foreground = mw->menu.select_color;
2623 Display *dpy = XtDisplay(mw);
2624 if (CellsOfScreen(DefaultScreenOfDisplay(dpy)) <= 2)
2626 xgcv.foreground = mw->menu.foreground;
2631 Colormap cmap = mw->core.colormap;
2632 xcolor.pixel = mw->core.background_pixel;
2633 XQueryColor (dpy, cmap, &xcolor);
2634 xcolor.red = (xcolor.red * 17) / 20;
2635 xcolor.green = (xcolor.green * 17) / 20;
2636 xcolor.blue = (xcolor.blue * 17) / 20;
2637 if (allocate_nearest_color (dpy, cmap, &xcolor))
2638 xgcv.foreground = xcolor.pixel;
2641 xgcv.background = mw->core.background_pixel;
2642 mw->menu.select_gc = XtGetGC ((Widget)mw, flags, &xgcv);
2644 xgcv.foreground = mw->menu.foreground;
2645 xgcv.background = mw->core.background_pixel;
2646 xgcv.fill_style = FillStippled;
2647 xgcv.stipple = mw->menu.gray_pixmap;
2648 mw->menu.inactive_gc = XtGetGC ((Widget)mw,
2649 (flags | GCFillStyle | GCStipple),
2652 xgcv.foreground = mw->menu.highlight_foreground;
2653 xgcv.background = mw->core.background_pixel;
2654 mw->menu.highlight_gc = XtGetGC ((Widget)mw, flags, &xgcv);
2656 xgcv.foreground = mw->menu.title_foreground;
2657 xgcv.background = mw->core.background_pixel;
2658 mw->menu.title_gc = XtGetGC ((Widget)mw, flags, &xgcv);
2660 xgcv.foreground = mw->menu.button_foreground;
2661 xgcv.background = mw->core.background_pixel;
2662 mw->menu.button_gc = XtGetGC ((Widget)mw, flags, &xgcv);
2664 xgcv.fill_style = FillStippled;
2665 xgcv.stipple = mw->menu.gray_pixmap;
2666 mw->menu.inactive_button_gc = XtGetGC ((Widget)mw,
2667 (flags | GCFillStyle | GCStipple),
2672 release_drawing_gcs (XlwMenuWidget mw)
2674 XtReleaseGC ((Widget) mw, mw->menu.foreground_gc);
2675 XtReleaseGC ((Widget) mw, mw->menu.button_gc);
2676 XtReleaseGC ((Widget) mw, mw->menu.highlight_gc);
2677 XtReleaseGC ((Widget) mw, mw->menu.title_gc);
2678 XtReleaseGC ((Widget) mw, mw->menu.inactive_gc);
2679 XtReleaseGC ((Widget) mw, mw->menu.inactive_button_gc);
2680 XtReleaseGC ((Widget) mw, mw->menu.background_gc);
2681 XtReleaseGC ((Widget) mw, mw->menu.select_gc);
2682 /* let's get some segvs if we try to use these... */
2683 mw->menu.foreground_gc = (GC) -1;
2684 mw->menu.button_gc = (GC) -1;
2685 mw->menu.highlight_gc = (GC) -1;
2686 mw->menu.title_gc = (GC) -1;
2687 mw->menu.inactive_gc = (GC) -1;
2688 mw->menu.inactive_button_gc = (GC) -1;
2689 mw->menu.background_gc = (GC) -1;
2690 mw->menu.select_gc = (GC) -1;
2693 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
2694 ? ((unsigned long) (x)) : ((unsigned long) (y)))
2697 make_shadow_gcs (XlwMenuWidget mw)
2700 unsigned long pm = 0;
2701 Display *dpy = XtDisplay ((Widget) mw);
2702 Colormap cmap = mw->core.colormap;
2704 int top_frobbed = 0, bottom_frobbed = 0;
2706 if (mw->menu.top_shadow_color == (Pixel) (-1))
2707 mw->menu.top_shadow_color = mw->core.background_pixel;
2708 if (mw->menu.bottom_shadow_color == (Pixel) (-1))
2709 mw->menu.bottom_shadow_color = mw->menu.foreground;
2711 if (mw->menu.top_shadow_color == mw->core.background_pixel ||
2712 mw->menu.top_shadow_color == mw->menu.foreground)
2714 topc.pixel = mw->core.background_pixel;
2715 XQueryColor (dpy, cmap, &topc);
2716 /* don't overflow/wrap! */
2717 topc.red = MINL (65535, topc.red * 1.2);
2718 topc.green = MINL (65535, topc.green * 1.2);
2719 topc.blue = MINL (65535, topc.blue * 1.2);
2720 if (allocate_nearest_color (dpy, cmap, &topc))
2722 if (topc.pixel == mw->core.background_pixel)
2724 XFreeColors( dpy, cmap, &topc.pixel, 1, 0);
2725 topc.red = MINL (65535, topc.red + 0x8000);
2726 topc.green = MINL (65535, topc.green + 0x8000);
2727 topc.blue = MINL (65535, topc.blue + 0x8000);
2728 if (allocate_nearest_color (dpy, cmap, &topc))
2730 mw->menu.top_shadow_color = topc.pixel;
2735 mw->menu.top_shadow_color = topc.pixel;
2741 if (mw->menu.bottom_shadow_color == mw->menu.foreground ||
2742 mw->menu.bottom_shadow_color == mw->core.background_pixel)
2744 botc.pixel = mw->core.background_pixel;
2745 XQueryColor (dpy, cmap, &botc);
2746 botc.red = (botc.red * 3) / 5;
2747 botc.green = (botc.green * 3) / 5;
2748 botc.blue = (botc.blue * 3) / 5;
2749 if (allocate_nearest_color (dpy, cmap, &botc))
2751 if (botc.pixel == mw->core.background_pixel)
2753 XFreeColors (dpy, cmap, &botc.pixel, 1, 0);
2754 botc.red = MINL (65535, botc.red + 0x4000);
2755 botc.green = MINL (65535, botc.green + 0x4000);
2756 botc.blue = MINL (65535, botc.blue + 0x4000);
2757 if (allocate_nearest_color (dpy, cmap, &botc))
2759 mw->menu.bottom_shadow_color = botc.pixel;
2764 mw->menu.bottom_shadow_color = botc.pixel;
2771 if (top_frobbed && bottom_frobbed)
2773 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
2774 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
2775 if (bot_avg > top_avg)
2777 Pixel tmp = mw->menu.top_shadow_color;
2778 mw->menu.top_shadow_color = mw->menu.bottom_shadow_color;
2779 mw->menu.bottom_shadow_color = tmp;
2781 else if (topc.pixel == botc.pixel)
2783 if (botc.pixel == mw->menu.foreground)
2784 mw->menu.top_shadow_color = mw->core.background_pixel;
2786 mw->menu.bottom_shadow_color = mw->menu.foreground;
2790 if (!mw->menu.top_shadow_pixmap &&
2791 mw->menu.top_shadow_color == mw->core.background_pixel)
2793 mw->menu.top_shadow_pixmap = mw->menu.gray_pixmap;
2794 mw->menu.top_shadow_color = mw->menu.foreground;
2796 if (!mw->menu.bottom_shadow_pixmap &&
2797 mw->menu.bottom_shadow_color == mw->core.background_pixel)
2799 mw->menu.bottom_shadow_pixmap = mw->menu.gray_pixmap;
2800 mw->menu.bottom_shadow_color = mw->menu.foreground;
2803 xgcv.fill_style = FillOpaqueStippled;
2804 xgcv.foreground = mw->menu.top_shadow_color;
2805 xgcv.background = mw->core.background_pixel;
2806 xgcv.stipple = mw->menu.top_shadow_pixmap;
2807 pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
2808 mw->menu.shadow_top_gc =
2809 XtGetGC((Widget)mw, GCForeground|GCBackground|pm, &xgcv);
2811 xgcv.foreground = mw->menu.bottom_shadow_color;
2812 xgcv.stipple = mw->menu.bottom_shadow_pixmap;
2813 pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
2814 mw->menu.shadow_bottom_gc =
2815 XtGetGC ((Widget)mw, GCForeground|GCBackground|pm, &xgcv);
2820 release_shadow_gcs (XlwMenuWidget mw)
2822 XtReleaseGC ((Widget) mw, mw->menu.shadow_top_gc);
2823 XtReleaseGC ((Widget) mw, mw->menu.shadow_bottom_gc);
2828 extract_font_extents (XlwMenuWidget mw)
2831 /* Find the maximal ascent/descent of the fonts in the font list
2832 so that all menu items can be the same height... */
2833 mw->menu.font_ascent = 0;
2834 mw->menu.font_descent = 0;
2837 XmFontContext context;
2838 #if (XmVersion >= 1002)
2839 XmFontListEntry fontentry;
2841 XmStringCharSet charset;
2845 if (! XmFontListInitFontContext (&context, mw->menu.font_list))
2847 #if (XmVersion >= 1002)
2848 /* There is a BUG in the 1.2 version of XmFontListGetNextFont() (or more
2849 specifically, in _XmGetFirstFont()) that can cause a null pointer to be
2850 passed to XFontsOfFontSet. Use XmFontListNextEntry(), which is the
2851 newer equivalent, instead. Also, it supports font sets, and the
2852 older function doesn't. */
2853 while ((fontentry = XmFontListNextEntry (context)))
2857 XtPointer one_of_them = XmFontListEntryGetFont (fontentry, &rettype);
2858 if (rettype == XmFONT_IS_FONTSET)
2860 XFontSet fontset = (XFontSet) one_of_them;
2861 XFontStruct **fontstruct_list;
2862 char **fontname_list;
2863 int fontcount = XFontsOfFontSet (fontset, &fontstruct_list,
2865 while (--fontcount >= 0)
2867 font = fontstruct_list[fontcount];
2868 if (font->ascent > (int) mw->menu.font_ascent)
2869 mw->menu.font_ascent = font->ascent;
2870 if (font->descent > (int) mw->menu.font_descent)
2871 mw->menu.font_descent = font->descent;
2874 else /* XmFONT_IS_FONT */
2876 font = (XFontStruct *) one_of_them;
2877 if (font->ascent > (int) mw->menu.font_ascent)
2878 mw->menu.font_ascent = font->ascent;
2879 if (font->descent > (int) mw->menu.font_descent)
2880 mw->menu.font_descent = font->descent;
2883 #else /* motif 1.1 */
2884 while (XmFontListGetNextFont (context, &charset, &font))
2886 if (font->ascent > (int) mw->menu.font_ascent)
2887 mw->menu.font_ascent = font->ascent;
2888 if (font->descent > (int) mw->menu.font_descent)
2889 mw->menu.font_descent = font->descent;
2892 #endif /* Motif version */
2893 XmFontListFreeFontContext (context);
2895 #else /* Not Motif */
2896 # ifdef USE_XFONTSET
2897 XFontStruct **fontstruct_list;
2898 char **fontname_list;
2900 int fontcount = XFontsOfFontSet(mw->menu.font_set, &fontstruct_list,
2902 mw->menu.font_ascent = 0;
2903 mw->menu.font_descent = 0;
2904 # if 0 /* nasty, personal debug, Kazz */
2905 fprintf(stderr, "fontSet count is %d\n", fontcount);
2907 while (--fontcount >= 0) {
2908 font = fontstruct_list[fontcount];
2909 if (font->ascent > (int) mw->menu.font_ascent)
2910 mw->menu.font_ascent = font->ascent;
2911 if (font->descent > (int) mw->menu.font_descent)
2912 mw->menu.font_descent = font->descent;
2914 # else /* ! USE_XFONTSET */
2915 mw->menu.font_ascent = mw->menu.font->ascent;
2916 mw->menu.font_descent = mw->menu.font->descent;
2918 #endif /* NEED_MOTIF */
2922 static XFontStruct *
2923 default_font_of_font_list (XmFontList font_list)
2925 XFontStruct *font = 0;
2927 /* Xm/Label.c does this: */
2928 _XmFontListGetDefaultFont (font_list, &font);
2931 XmFontContext context;
2932 #if (XmVersion >= 1002)
2933 XmFontListEntry fontentry;
2935 XtPointer one_of_them;
2937 XmStringCharSet charset;
2940 if (! XmFontListInitFontContext (&context, font_list))
2942 #if (XmVersion >= 1002)
2943 /* There is a BUG in the 1.2 version of XmFontListGetNextFont() (or more
2944 specifically, in _XmGetFirstFont()) that can cause a null pointer to be
2945 passed to XFontsOfFontSet. Use XmFontListNextEntry(), which is the
2946 newer equivalent, instead. */
2947 fontentry = XmFontListNextEntry (context);
2948 one_of_them = XmFontListEntryGetFont (fontentry, &rettype);
2949 if (rettype == XmFONT_IS_FONTSET)
2951 XFontSet fontset = (XFontSet) one_of_them;
2952 XFontStruct **fontstruct_list;
2953 char **fontname_list;
2954 (void) XFontsOfFontSet (fontset, &fontstruct_list, &fontname_list);
2955 font = fontstruct_list[0];
2957 else /* XmFONT_IS_FONT */
2959 font = (XFontStruct *) one_of_them;
2962 if (! XmFontListGetNextFont (context, &charset, &font))
2966 XmFontListFreeFontContext (context);
2970 if (! font) abort ();
2973 #endif /* NEED_MOTIF */
2976 XlwMenuInitialize (Widget request, Widget new, ArgList args,
2979 /* Get the GCs and the widget size */
2980 XlwMenuWidget mw = (XlwMenuWidget)new;
2982 XSetWindowAttributes xswa;
2985 Window window = RootWindowOfScreen (DefaultScreenOfDisplay (XtDisplay (mw)));
2986 Display *display = XtDisplay (mw);
2988 /* mw->menu.cursor = XCreateFontCursor (display, mw->menu.cursor_shape); */
2989 mw->menu.cursor = mw->menu.cursor_shape;
2991 mw->menu.gray_pixmap =
2992 XCreatePixmapFromBitmapData (display, window, (char *) gray_bits,
2993 gray_width, gray_height, 1, 0, 1);
2996 /* The menu.font_list slot came from the *fontList resource (Motif standard.)
2997 The menu.font_list_2 slot came from the *font resource, for backward
2998 compatibility with older versions of this code, and consistency with the
2999 rest of emacs. If both font and fontList are specified, we use font.
3000 If only one is specified, we use that. If neither are specified, we
3001 use the "fallback" value. What a kludge!!!
3003 Note that this has the bug that a more general wildcard like "*fontList:"
3004 will override a more specific resource like "Emacs*menubar.font:". But
3005 I can't think of a way around that.
3007 if (mw->menu.font_list) /* if *fontList is specified, use that */
3009 else if (mw->menu.font_list_2) /* else if *font is specified, use that */
3010 mw->menu.font_list = mw->menu.font_list_2;
3011 else /* otherwise use default */
3012 mw->menu.font_list = mw->menu.fallback_font_list;
3015 make_drawing_gcs (mw);
3016 make_shadow_gcs (mw);
3017 extract_font_extents (mw);
3019 xswa.background_pixel = mw->core.background_pixel;
3020 xswa.border_pixel = mw->core.border_pixel;
3021 mask = CWBackPixel | CWBorderPixel;
3023 mw->menu.popped_up = False;
3024 mw->menu.pointer_grabbed = False;
3025 mw->menu.next_release_must_exit = False;
3027 mw->menu.old_depth = 1;
3028 mw->menu.old_stack = XtNew (widget_value*);
3029 mw->menu.old_stack_length = 1;
3030 mw->menu.old_stack [0] = mw->menu.contents;
3032 mw->menu.new_depth = 0;
3033 mw->menu.new_stack = 0;
3034 mw->menu.new_stack_length = 0;
3035 push_new_stack (mw, mw->menu.contents);
3037 mw->menu.windows = XtNew (window_state);
3038 mw->menu.windows_length = 1;
3039 mw->menu.windows [0].x = 0;
3040 mw->menu.windows [0].y = 0;
3041 mw->menu.windows [0].width = 0;
3042 mw->menu.windows [0].height = 0;
3045 mw->core.width = mw->menu.windows [0].width;
3046 mw->core.height = mw->menu.windows [0].height;
3050 XlwMenuClassInitialize (void)
3052 initialize_massaged_resource_char();
3056 XlwMenuRealize (Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
3058 XlwMenuWidget mw = (XlwMenuWidget)w;
3059 XSetWindowAttributes xswa;
3062 (*xlwMenuWidgetClass->core_class.superclass->core_class.realize)
3063 (w, valueMask, attributes);
3065 xswa.save_under = True;
3066 xswa.cursor = mw->menu.cursor_shape;
3067 mask = CWSaveUnder | CWCursor;
3068 if (mw->menu.use_backing_store)
3070 xswa.backing_store = Always;
3071 mask |= CWBackingStore;
3073 XChangeWindowAttributes (XtDisplay (w), XtWindow (w), mask, &xswa);
3075 mw->menu.windows [0].window = XtWindow (w);
3076 mw->menu.windows [0].x = w->core.x;
3077 mw->menu.windows [0].y = w->core.y;
3078 mw->menu.windows [0].width = w->core.width;
3079 mw->menu.windows [0].height = w->core.height;
3082 /* Only the toplevel menubar/popup is a widget so it's the only one that
3083 receives expose events through Xt. So we repaint all the other panes
3084 when receiving an Expose event. */
3086 XlwMenuRedisplay (Widget w, XEvent *ev, Region region)
3088 XlwMenuWidget mw = (XlwMenuWidget)w;
3091 if (mw->core.being_destroyed) return;
3093 for (i = 0; i < mw->menu.old_depth; i++)
3094 display_menu (mw, i, False, NULL, NULL, NULL, NULL, NULL);
3095 set_new_state (mw, NULL, mw->menu.old_depth); /* #### - ??? */
3096 remap_menubar (mw); /* #### - do these two lines do anything? */
3100 XlwMenuDestroy (Widget w)
3103 XlwMenuWidget mw = (XlwMenuWidget) w;
3105 if (mw->menu.pointer_grabbed)
3107 XtUngrabPointer (w, CurrentTime);
3108 mw->menu.pointer_grabbed = False;
3111 release_drawing_gcs (mw);
3112 release_shadow_gcs (mw);
3114 /* this doesn't come from the resource db but is created explicitly
3115 so we must free it ourselves. */
3116 XFreePixmap (XtDisplay (mw), mw->menu.gray_pixmap);
3117 mw->menu.gray_pixmap = (Pixmap) -1;
3119 /* Don't free mw->menu.contents because that comes from our creator.
3120 The `*_stack' elements are just pointers into `contents' so leave
3121 that alone too. But free the stacks themselves. */
3122 if (mw->menu.old_stack) XtFree ((char *) mw->menu.old_stack);
3123 if (mw->menu.new_stack) XtFree ((char *) mw->menu.new_stack);
3125 /* Remember, you can't free anything that came from the resource
3126 database. This includes:
3128 mw->menu.top_shadow_pixmap
3129 mw->menu.bottom_shadow_pixmap
3132 Also the color cells of top_shadow_color, bottom_shadow_color,
3133 foreground, and button_foreground will never be freed until this
3134 client exits. Nice, eh?
3137 /* start from 1 because the one in slot 0 is w->core.window */
3138 for (i = 1; i < mw->menu.windows_length; i++)
3139 XDestroyWindow (XtDisplay (mw), mw->menu.windows [i].window);
3140 if (mw->menu.windows)
3141 XtFree ((char *) mw->menu.windows);
3145 XlwMenuSetValues (Widget current, Widget request, Widget new, ArgList args,
3148 XlwMenuWidget oldmw = (XlwMenuWidget)current;
3149 XlwMenuWidget newmw = (XlwMenuWidget)new;
3150 Boolean redisplay = False;
3153 if (newmw->menu.contents
3154 && newmw->menu.contents->contents
3155 && newmw->menu.contents->contents->change >= VISIBLE_CHANGE)
3158 if (newmw->core.background_pixel != oldmw->core.background_pixel
3159 || newmw->menu.foreground != oldmw->menu.foreground
3160 /* For the XEditResource protocol, which may want to change the font. */
3162 || newmw->menu.font_list != oldmw->menu.font_list
3163 || newmw->menu.font_list_2 != oldmw->menu.font_list_2
3164 || newmw->menu.fallback_font_list != oldmw->menu.fallback_font_list
3166 || newmw->menu.font != oldmw->menu.font
3170 release_drawing_gcs (newmw);
3171 make_drawing_gcs (newmw);
3174 for (i = 0; i < oldmw->menu.windows_length; i++)
3176 XSetWindowBackground (XtDisplay (oldmw),
3177 oldmw->menu.windows [i].window,
3178 newmw->core.background_pixel);
3179 /* clear windows and generate expose events */
3180 XClearArea (XtDisplay (oldmw), oldmw->menu.windows[i].window,
3189 XlwMenuResize (Widget w)
3191 XlwMenuWidget mw = (XlwMenuWidget)w;
3193 mw->menu.windows [0].width = mw->core.width;
3194 mw->menu.windows [0].height = mw->core.height;
3197 \f/* Action procedures */
3199 handle_single_motion_event (XlwMenuWidget mw, XMotionEvent *ev,
3206 if (!map_event_to_widget_value (mw, ev, &val, &level, &stay_up))
3208 /* we wind up here when: (a) the event is in the menubar, (b) the
3209 event isn't in the menubar or any of the panes, (c) the event is on
3210 a disabled menu item */
3211 pop_new_stack_if_no_contents (mw);
3212 if (select_p && !stay_up) {
3213 /* pop down all menus and exit */
3214 mw->menu.next_release_must_exit = True;
3215 set_new_state(mw, (val = NULL), 1);
3220 /* we wind up here when: (a) the event pops up a pull_right menu,
3221 (b) a menu item that is not disabled is highlighted */
3222 if (select_p && mw->menu.bounce_down
3223 && close_to_reference_time((Widget)mw,
3224 mw->menu.menu_bounce_time,
3227 /* motion can cause more than one event. Don't bounce right back
3228 up if we've just bounced down. */
3231 else if (select_p && mw->menu.bounce_down &&
3232 mw->menu.last_selected_val &&
3233 (mw->menu.last_selected_val == val))
3235 val = NULL; /* assigned to mw->last_selected_val below */
3236 mw->menu.menu_bounce_time = ev->time;
3237 /* popdown last menu if we're selecting the same menu item as we did
3238 last time and the XlwMenu.bounceDown resource is set, if the
3239 item is on the menubar itself, then exit. */
3240 if (level == (mw->menu.popped_up ? 0 : 1))
3241 mw->menu.next_release_must_exit = True;
3244 mw->menu.menu_bounce_time = 0;
3245 set_new_state (mw, val, level);
3247 mw->menu.last_selected_val = val;
3250 /* Sync with the display. Makes it feel better on X terms. */
3251 XFlush (XtDisplay (mw));
3255 handle_motion_event (XlwMenuWidget mw, XMotionEvent *ev,
3260 unsigned int state = ev->state;
3261 XMotionEvent *event= ev, dummy;
3263 /* allow motion events to be generated again */
3264 dummy.window = ev->window;
3266 && XQueryPointer (XtDisplay (mw), dummy.window,
3267 &dummy.root, &dummy.subwindow,
3268 &dummy.x_root, &dummy.y_root,
3271 && dummy.state == state
3272 && (dummy.x_root != x || dummy.y_root != y))
3274 /* don't handle the event twice or that breaks bounce_down. --Stig */
3275 dummy.type = ev->type;
3279 lw_menu_accelerate = False;
3280 handle_single_motion_event (mw, event, select_p);
3283 Time x_focus_timestamp_really_sucks_fix_me_better;
3286 Start (Widget w, XEvent *ev, String *params, Cardinal *num_params)
3288 XlwMenuWidget mw = (XlwMenuWidget)w;
3290 lw_menubar_widget = w;
3292 lw_menu_active = True;
3294 if (!mw->menu.pointer_grabbed)
3296 mw->menu.menu_post_time = ev->xbutton.time;
3297 mw->menu.menu_bounce_time = 0;
3298 mw->menu.next_release_must_exit = True;
3299 mw->menu.last_selected_val = NULL;
3300 x_focus_timestamp_really_sucks_fix_me_better =
3301 ((XButtonPressedEvent*)ev)->time;
3302 XtCallCallbackList ((Widget)mw, mw->menu.open, NULL);
3304 /* notes the absolute position of the menubar window */
3305 mw->menu.windows [0].x = ev->xmotion.x_root - ev->xmotion.x;
3306 mw->menu.windows [0].y = ev->xmotion.y_root - ev->xmotion.y;
3308 XtGrabPointer ((Widget)mw, False,
3309 (ButtonMotionMask | ButtonReleaseMask | ButtonPressMask),
3310 GrabModeAsync, GrabModeAsync,
3311 None, mw->menu.cursor_shape,
3312 ((XButtonPressedEvent*)ev)->time);
3313 mw->menu.pointer_grabbed = True;
3316 /* handles the down like a move, slots are mostly compatible */
3317 handle_motion_event (mw, &ev->xmotion, True);
3321 Drag (Widget w, XEvent *ev, String *params, Cardinal *num_params)
3323 XlwMenuWidget mw = (XlwMenuWidget)w;
3324 handle_motion_event (mw, &ev->xmotion, False);
3328 Select (Widget w, XEvent *ev, String *params, Cardinal *num_params)
3330 XlwMenuWidget mw = (XlwMenuWidget)w;
3331 widget_value *selected_item = mw->menu.old_stack [mw->menu.old_depth - 1];
3333 lw_menu_accelerate = False;
3335 /* If user releases the button quickly, without selecting anything,
3336 after the initial down-click that brought the menu up,
3338 if ((selected_item == 0 || selected_item->call_data == 0)
3339 && (!mw->menu.next_release_must_exit
3340 || close_to_reference_time(w, mw->menu.menu_post_time, ev)))
3342 mw->menu.next_release_must_exit = False;
3346 /* pop down everything */
3347 mw->menu.new_depth = 1;
3350 /* Destroy() only gets called for popup menus. Menubar widgets aren't
3351 destroyed when their menu panes get nuked. */
3352 if (mw->menu.pointer_grabbed)
3354 XtUngrabPointer ((Widget)w, ev->xmotion.time);
3355 mw->menu.pointer_grabbed = False;
3358 if (mw->menu.popped_up)
3360 mw->menu.popped_up = False;
3361 XtPopdown (XtParent (mw));
3364 lw_menu_active = False;
3366 x_focus_timestamp_really_sucks_fix_me_better =
3367 ((XButtonPressedEvent*)ev)->time;
3370 XtCallCallbackList ((Widget) mw, mw->menu.select, (XtPointer) selected_item);
3373 \f/* Action procedures for keyboard accelerators */
3377 xlw_set_menu (Widget w, widget_value *val)
3379 lw_menubar_widget = w;
3380 set_new_state ((XlwMenuWidget)w, val, 1);
3383 /* prepare the menu structure via the call-backs */
3385 xlw_map_menu (Time t)
3387 XlwMenuWidget mw = (XlwMenuWidget)lw_menubar_widget;
3389 lw_menu_accelerate = True;
3391 if (!mw->menu.pointer_grabbed)
3393 XWindowAttributes ret;
3396 unsigned int num_waste;
3398 lw_menu_active = True;
3400 mw->menu.menu_post_time = t;
3401 mw->menu.menu_bounce_time = 0;
3403 mw->menu.next_release_must_exit = True;
3404 mw->menu.last_selected_val = NULL;
3406 XtCallCallbackList ((Widget)mw, mw->menu.open, NULL);
3408 /* do this for keyboards too! */
3409 /* notes the absolute position of the menubar window */
3411 mw->menu.windows [0].x = ev->xmotion.x_root - ev->xmotion.x;
3412 mw->menu.windows [0].y = ev->xmotion.y_root - ev->xmotion.y;
3415 /* get the geometry of the menubar */
3417 /* there has to be a better way than this. */
3419 mw->menu.windows [0].x = 0;
3420 mw->menu.windows [0].y = 0;
3422 parent = XtWindow (lw_menubar_widget);
3425 XGetWindowAttributes (XtDisplay (lw_menubar_widget), parent, &ret);
3426 mw->menu.windows [0].x += ret.x;
3427 mw->menu.windows [0].y += ret.y;
3430 XQueryTree (XtDisplay (lw_menubar_widget), parent, &root, &parent, &waste,
3437 while (parent != root);
3439 XtGrabPointer ((Widget)mw, False,
3440 (ButtonMotionMask | ButtonReleaseMask | ButtonPressMask),
3441 GrabModeAsync, GrabModeAsync,
3442 None, mw->menu.cursor_shape, t);
3443 mw->menu.pointer_grabbed = True;
3447 /* display the stupid menu already */
3449 xlw_display_menu (Time t)
3451 XlwMenuWidget mw = (XlwMenuWidget)lw_menubar_widget;
3453 lw_menu_accelerate = True;
3457 /* Sync with the display. Makes it feel better on X terms. */
3458 XFlush (XtDisplay (mw));
3461 /* push a sub menu */
3463 xlw_push_menu (widget_value *val)
3465 push_new_stack ((XlwMenuWidget)lw_menubar_widget, val);
3468 /* pop a sub menu */
3472 if (((XlwMenuWidget)lw_menubar_widget)->menu.new_depth > 0)
3473 ((XlwMenuWidget)lw_menubar_widget)->menu.new_depth --;
3480 xlw_kill_menus (widget_value *val)
3482 XlwMenuWidget mw = (XlwMenuWidget)lw_menubar_widget;
3484 lw_menu_accelerate = False;
3486 mw->menu.new_depth = 1;
3489 if (mw->menu.pointer_grabbed)
3491 XtUngrabPointer (lw_menubar_widget, CurrentTime);
3492 mw->menu.pointer_grabbed = False;
3495 lw_menu_active = False;
3496 XtCallCallbackList (lw_menubar_widget, mw->menu.select, (XtPointer)val);
3499 /* set the menu item */
3501 xlw_set_item (widget_value *val)
3503 if (((XlwMenuWidget)lw_menubar_widget)->menu.new_depth > 0)
3504 ((XlwMenuWidget) lw_menubar_widget)->menu.new_depth --;
3505 push_new_stack ((XlwMenuWidget) lw_menubar_widget, val);
3508 /* get either the current entry or a list of all entries in the current submenu */
3510 xlw_get_entries (int allp)
3512 XlwMenuWidget mw = (XlwMenuWidget)lw_menubar_widget;
3515 if (mw->menu.new_depth >= 2)
3516 return mw->menu.new_stack [mw->menu.new_depth - 2]->contents;
3518 return mw->menu.new_stack[0];
3521 if (mw->menu.new_depth >= 1)
3522 return mw->menu.new_stack [mw->menu.new_depth - 1];
3528 xlw_menu_level (void)
3530 return ((XlwMenuWidget)lw_menubar_widget)->menu.new_depth;
3534 /* Special code to pop-up a menu */
3536 xlw_pop_up_menu (XlwMenuWidget mw, XButtonPressedEvent *event)
3538 int x = event->x_root;
3539 int y = event->y_root;
3542 int borderwidth = mw->menu.shadow_thickness;
3543 Screen* screen = XtScreen (mw);
3545 mw->menu.menu_post_time = event->time;
3546 mw->menu.menu_bounce_time = 0;
3547 mw->menu.next_release_must_exit = True;
3548 mw->menu.last_selected_val = NULL;
3550 XtCallCallbackList ((Widget) mw, mw->menu.open, NULL);
3554 w = mw->menu.windows [0].width;
3555 h = mw->menu.windows [0].height;
3560 if (x < borderwidth)
3563 if (x > WidthOfScreen (screen) - w - 2 * borderwidth)
3564 x = WidthOfScreen (screen) - w - 2 * borderwidth;
3566 if (y < borderwidth)
3569 if (y > HeightOfScreen (screen) - h - 2 * borderwidth)
3570 y = HeightOfScreen (screen) - h - 2 * borderwidth;
3572 mw->menu.popped_up = True;
3573 XtConfigureWidget (XtParent (mw), x, y, w, h,
3574 XtParent (mw)->core.border_width);
3575 XtPopup (XtParent (mw), XtGrabExclusive);
3576 display_menu (mw, 0, False, NULL, NULL, NULL, NULL, NULL);
3577 if (!mw->menu.pointer_grabbed)
3579 XtGrabPointer ((Widget)mw, False,
3580 (ButtonMotionMask | ButtonReleaseMask | ButtonPressMask),
3581 GrabModeAsync, GrabModeAsync,
3582 None, mw->menu.cursor_shape, event->time);
3583 mw->menu.pointer_grabbed = True;
3586 mw->menu.windows [0].x = x + borderwidth;
3587 mw->menu.windows [0].y = y + borderwidth;
3589 handle_motion_event (mw, (XMotionEvent *) event, True);
3595 * This is a horrible function which should not be needed.
3596 * use it to put the resize method back the way the XlwMenu
3597 * class initializer put it. Motif screws with this when
3598 * the XlwMenu class gets instantiated.
3601 xlw_unmunge_class_resize (Widget w)
3603 if (w->core.widget_class->core_class.resize != XlwMenuResize)
3604 w->core.widget_class->core_class.resize = XlwMenuResize;