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);
451 XmbTextExtents (mw->menu.font_set, newchars, j, &ri, &rl);
453 # else /* ! USE_XFONTSET */
454 XTextExtents (mw->menu.font, newchars, j, &drop, &drop, &drop, &xcs);
456 # endif /* USE_XFONTSET */
461 massage_resource_name (CONST char *in, char *out)
463 /* Turn a random string into something suitable for using as a resource.
466 "Kill Buffer" -> "killBuffer"
467 "Find File..." -> "findFile___"
468 "Search and Replace..." -> "searchAndReplace___"
469 "C++ Mode Commands" -> "cppModeCommands"
471 Valid characters in a resource NAME component are: a-zA-Z0-9_
474 #ifdef PRINT_XLWMENU_RESOURCE_CONVERSIONS
475 /* Compile with -DPRINT_XLWMENU_RESOURCE_CONVERSIONS to generate a
476 translation file for menu localizations. */
477 char *save_in = in, *save_out = out;
480 Boolean firstp = True;
483 char ch = massaged_resource_char[(unsigned char) *in++];
486 *out++ = firstp ? tolower (ch) : toupper (ch);
488 while ((ch = massaged_resource_char[(unsigned char) *in++]) != '\0')
490 if (!*(in-1)) /* Overshot the NULL byte? */
496 #ifdef PRINT_XLWMENU_RESOURCE_CONVERSIONS
497 printf ("! Emacs*XlwMenu.%s.labelString:\t%s\n", save_out, save_in);
498 printf ( "Emacs*XlwMenu.%s.labelString:\n", save_out);
505 { "labelString", "LabelString", XtRString, sizeof(String),
510 * This function looks through string searching for parameter
511 * inserts of the form:
513 * padding is space (' ') or dash ('-') characters meaning
514 * padding to the left or right of the inserted parameter.
515 * In essence all %1 strings are replaced by value in the return
516 * value (which the caller is expected to free).
517 * %% means insert one % (like printf).
518 * %1 means insert value.
519 * %-1 means insert value followed by one space. The latter is
520 * not inserted if value is a zero length string.
523 parameterize_string (CONST char *string, CONST char *value)
527 unsigned int done = 0;
532 result = XtMalloc(1);
540 for (ntimes = 1, result = (char *) string; (percent = strchr(result, '%'));
542 result = &percent[1];
544 result = XtMalloc ((ntimes * strlen(value)) + strlen(string) + 4);
547 while ((percent = strchr(string, '%')))
549 unsigned int left_pad;
550 unsigned int right_pad;
553 if (percent[1] == '%')
554 { /* it's a real % */
555 strncat (result, string, 1 + percent - string); /* incl % */
556 string = &percent[2]; /* after the second '%' */
557 continue; /* with the while() loop */
563 for (p = &percent[1]; /* test *p inside the loop */ ; p++)
574 { /* param and terminator */
575 strncat (result, string, percent - string);
576 if (value[0] != '\0')
579 for (i = 0; i < left_pad; i++)
580 strcat (result, " ");
581 strcat (result, value);
582 for (i = 0; i < right_pad; i++)
583 strcat (result, " ");
585 string = &p[1]; /* after the '1' */
586 done++; /* no need to do old way */
587 break; /* out of for() loop */
590 { /* bogus, copy the format as is */
591 /* out of for() loop */
592 strncat (result, string, 1 + p - string);
593 string = (*p ? &p[1] : p);
599 /* Copy the tail of the string */
600 strcat (result, string);
602 /* If we have not processed a % string, and we have a value, tail it. */
603 if (!done && value[0] != '\0')
605 strcat (result, " ");
606 strcat (result, value);
615 resource_widget_value (XlwMenuWidget mw, widget_value *val)
617 if (!val->toolkit_data)
619 char *resourced_name = NULL;
620 char *converted_name, *str;
621 XmString complete_name;
622 char massaged_name [1024];
624 if (mw->menu.lookup_labels)
626 /* Convert value style name into resource style name.
627 eg: "Free Willy" becomes "freeWilly" */
628 massage_resource_name (val->name, massaged_name);
630 /* If we have a value (parameter) see if we can find a "Named"
634 char named_name[1024];
635 sprintf (named_name, "%sNamed", massaged_name);
636 XtGetSubresources ((Widget) mw,
637 (XtPointer) &resourced_name,
638 named_name, named_name,
639 nameResource, 1, NULL, 0);
642 /* If nothing yet, try to load from the massaged name. */
645 XtGetSubresources ((Widget) mw,
646 (XtPointer) &resourced_name,
647 massaged_name, massaged_name,
648 nameResource, 1, NULL, 0);
650 } /* if (mw->menu.lookup_labels) */
652 /* Still nothing yet, use the name as the value. */
654 resourced_name = val->name;
656 /* Parameterize the string. */
657 converted_name = parameterize_string (resourced_name, val->value);
659 /* nuke newline characters to prevent menubar screwups */
660 for ( str = converted_name ; *str ; str++ )
662 if (str[0] == '\n') str[0] = ' ';
665 /* Improve OSF's bottom line. */
666 #if (XmVersion >= 1002)
667 complete_name = XmStringCreateLocalized (converted_name);
669 complete_name = XmStringCreateLtoR (converted_name,
670 XmSTRING_DEFAULT_CHARSET);
672 XtFree (converted_name);
674 val->toolkit_data = complete_name;
675 val->free_toolkit_data = True;
677 return (XmString) val->toolkit_data;
682 /* These two routines should be a seperate file..djw */
684 xlw_create_localized_string (Widget w,
695 XtGetSubresources (w,
705 return parameterize_string (string, arg);
709 xlw_create_localized_xmstring (Widget w,
714 char * string = xlw_create_localized_string (w, name, args, nargs);
715 XmString xm_string = XmStringCreateLtoR (string, XmSTRING_DEFAULT_CHARSET);
724 resource_widget_value (XlwMenuWidget mw, widget_value *val)
726 if (!val->toolkit_data)
728 char *resourced_name = NULL;
730 char massaged_name [1024];
732 if (mw->menu.lookup_labels)
734 massage_resource_name (val->name, massaged_name);
736 XtGetSubresources ((Widget) mw,
737 (XtPointer) &resourced_name,
738 massaged_name, massaged_name,
739 nameResource, 1, NULL, 0);
742 resourced_name = val->name;
744 complete_name = parameterize_string (resourced_name, val->value);
746 val->toolkit_data = complete_name;
747 /* nuke newline characters to prevent menubar screwups */
748 for ( ; *complete_name ; complete_name++ )
750 if (complete_name[0] == '\n')
751 complete_name[0] = ' ';
753 val->free_toolkit_data = True;
755 return (char *) val->toolkit_data;
760 /* Code for drawing strings. */
762 string_draw (XlwMenuWidget mw,
774 XmStringDraw (XtDisplay (mw), window,
778 1000, /* ???? width */
779 XmALIGNMENT_BEGINNING,
780 0, /* ???? layout_direction */
784 XmbDrawString (XtDisplay (mw), window, mw->menu.font_set, gc,
785 x, y + mw->menu.font_ascent, string, strlen (string));
787 XDrawString (XtDisplay (mw), window, gc,
788 x, y + mw->menu.font_ascent, string, strlen (string));
789 # endif /* USE_XFONTSET */
806 Dimension width, height;
814 newstring = XmStringLtoRCreate (&string[start], XmFONTLIST_DEFAULT_TAG);
816 XtDisplay (mw), window,
820 1000, /* ???? width */
821 XmALIGNMENT_BEGINNING,
822 0, /* ???? layout_direction */
825 XmStringExtent (mw->menu.font_list, newstring, &width, &height);
826 XmStringFree (newstring);
836 XtDisplay (mw), window, mw->menu.font_set, gc,
837 x, y + mw->menu.font_ascent, &string[start], end - start);
839 mw->menu.font_set, &string[start], end - start, &ri, &rl);
848 XtDisplay (mw), window, gc,
849 x, y + mw->menu.font_ascent, &string[start], end - start);
851 mw->menu.font, &string[start], end - start,
852 &drop, &drop, &drop, &xcs);
859 string_draw_u (XlwMenuWidget mw,
874 XmStringGetLtoR (string, XmFONTLIST_DEFAULT_TAG, &chars);
878 for (i=0;chars[i];++i) {
879 if (chars[i]=='%'&&chars[i+1]=='_') {
882 x += string_draw_range (mw, window, x, y, gc, chars, s, i);
883 w = string_draw_range (mw, window, x, y, gc, chars, i+2, i+3);
885 /* underline next character */
886 XDrawLine (XtDisplay (mw), window, gc, x - 1,
887 y + mw->menu.font_ascent + 1,
888 x + w - 1, y + mw->menu.font_ascent + 1 );
894 x += string_draw_range (mw, window, x, y, gc, chars, s, i);
901 binding_draw (XlwMenuWidget mw, Window w, int x, int y, GC gc, char *value)
904 XmString xm_value = XmStringCreateLtoR(value, XmSTRING_DEFAULT_CHARSET);
905 string_draw (mw, w, x, y, gc, xm_value);
906 XmStringFree (xm_value);
908 string_draw (mw, w, x, y, gc, value);
912 /* Low level code for drawing 3-D edges. */
914 shadow_rectangle_draw (Display *dpy,
921 unsigned int thickness)
930 points [1].x = x + width;
932 points [2].x = x + width - thickness;
933 points [2].y = y + thickness;
935 points [3].y = y + thickness;
936 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
938 points [0].y = y + thickness;
940 points [1].y = y + height;
941 points [2].x = x + thickness;
942 points [2].y = y + height - thickness;
943 points [3].x = x + thickness;
944 points [3].y = y + thickness;
945 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
946 points [0].x = x + width;
948 points [1].x = x + width - thickness;
949 points [1].y = y + thickness;
950 points [2].x = x + width - thickness;
951 points [2].y = y + height - thickness;
952 points [3].x = x + width;
953 points [3].y = y + height - thickness;
954 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin);
956 points [0].y = y + height;
957 points [1].x = x + width;
958 points [1].y = y + height;
959 points [2].x = x + width;
960 points [2].y = y + height - thickness;
961 points [3].x = x + thickness;
962 points [3].y = y + height - thickness;
963 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin);
966 typedef enum e_shadow_type
968 /* these are Motif compliant */
974 SHADOW_ETCHED_OUT_DASH,
975 SHADOW_ETCHED_IN_DASH,
978 SHADOW_SINGLE_DASHED_LINE,
979 SHADOW_DOUBLE_DASHED_LINE,
981 /* these are all non-Motif */
982 SHADOW_DOUBLE_ETCHED_OUT,
983 SHADOW_DOUBLE_ETCHED_IN,
984 SHADOW_DOUBLE_ETCHED_OUT_DASH,
985 SHADOW_DOUBLE_ETCHED_IN_DASH
989 shadow_draw (XlwMenuWidget mw,
996 Display *dpy = XtDisplay (mw);
999 int thickness = mw->menu.shadow_thickness;
1003 Boolean etched = False;
1007 case SHADOW_BACKGROUND:
1008 top_gc = bottom_gc = mw->menu.background_gc;
1010 case SHADOW_ETCHED_IN:
1011 top_gc = mw->menu.shadow_bottom_gc;
1012 bottom_gc = mw->menu.shadow_top_gc;
1015 case SHADOW_ETCHED_OUT:
1016 top_gc = mw->menu.shadow_top_gc;
1017 bottom_gc = mw->menu.shadow_bottom_gc;
1021 top_gc = mw->menu.shadow_bottom_gc;
1022 bottom_gc = mw->menu.shadow_top_gc;
1026 top_gc = mw->menu.shadow_top_gc;
1027 bottom_gc = mw->menu.shadow_bottom_gc;
1033 unsigned int half = thickness/2;
1034 shadow_rectangle_draw (dpy,
1039 width - half, height - half,
1041 shadow_rectangle_draw (dpy,
1046 width - half , height - half,
1051 shadow_rectangle_draw (dpy,
1062 arrow_decoration_draw (XlwMenuWidget mw,
1068 Display *dpy = XtDisplay (mw);
1072 int thickness = mw->menu.shadow_thickness;
1075 int length = (int)((double)width * 0.87);
1076 int thick_med = (int)((double)thickness * 1.73);
1079 half_width = width/2 + 1;
1081 half_width = width/2;
1083 select_gc = mw->menu.background_gc;
1087 top_gc = mw->menu.shadow_bottom_gc;
1088 bottom_gc = mw->menu.shadow_top_gc;
1092 top_gc = mw->menu.shadow_top_gc;
1093 bottom_gc = mw->menu.shadow_bottom_gc;
1096 /* Fill internal area. We do this first so that the borders have a
1098 points [0].x = x + thickness;
1099 points [0].y = y + thickness;
1100 points [1].x = x + length - thickness;
1101 points [1].y = y + half_width;
1102 points [2].x = x + length - thickness;
1103 points [2].y = y + half_width + thickness;
1104 points [3].x = x + thickness;
1105 points [3].y = y + width - thickness;
1118 points [1].x = x + thickness;
1119 points [1].y = y + thick_med;
1120 points [2].x = x + thickness;
1121 points [2].y = y + width - thick_med;
1123 points [3].y = y + width;
1125 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
1129 points [0].y = y + width;
1130 points [1].x = x + length;
1131 points [1].y = y + half_width;
1132 points [2].x = x + length - (thickness + thickness);
1133 points [2].y = y + half_width;
1134 points [3].x = x + thickness;
1135 points [3].y = y + width - thick_med;
1137 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin);
1142 points [1].x = x + length;
1143 points [1].y = y + half_width;
1144 points [2].x = x + length - (thickness + thickness);
1145 points [2].y = y + half_width;
1146 points [3].x = x + thickness;
1147 points [3].y = y + thick_med;
1149 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
1153 toggle_decoration_draw (XlwMenuWidget mw,
1159 Display *dpy = XtDisplay (mw);
1160 int thickness = mw->menu.shadow_thickness;
1162 GC select_gc = mw->menu.select_gc;
1169 /* Fill internal area. */
1171 XFillRectangle (dpy,
1176 width - (2*thickness),
1177 width - (2*thickness));
1179 shadow_draw (mw, window, x, y, width, width, type);
1183 radio_decoration_draw (XlwMenuWidget mw,
1189 Display *dpy = XtDisplay (mw);
1192 GC select_gc = mw->menu.select_gc;
1193 int thickness = mw->menu.shadow_thickness;
1203 half_width = width/2;
1207 top_gc = mw->menu.shadow_bottom_gc;
1208 bottom_gc = mw->menu.shadow_top_gc;
1212 top_gc = mw->menu.shadow_top_gc;
1213 bottom_gc = mw->menu.shadow_bottom_gc;
1217 /* Draw the bottom first, just in case the regions overlap.
1218 The top should cast the longer shadow. */
1219 points [0].x = x; /* left corner */
1220 points [0].y = y + half_width;
1221 points [1].x = x + half_width; /* bottom corner */
1222 points [1].y = y + width;
1223 points [2].x = x + half_width; /* bottom inside corner */
1224 points [2].y = y + width - thickness;
1225 points [3].x = x + thickness; /* left inside corner */
1226 points [3].y = y + half_width;
1228 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin);
1230 points [0].x = x + half_width; /* bottom corner */
1231 points [0].y = y + width;
1232 points [1].x = x + width; /* right corner */
1233 points [1].y = y + half_width;
1234 points [2].x = x + width - thickness; /* right inside corner */
1235 points [2].y = y + half_width;
1236 points [3].x = x + half_width; /* bottom inside corner */
1237 points [3].y = y + width - thickness;
1239 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin);
1241 points [0].x = x; /* left corner */
1242 points [0].y = y + half_width;
1243 points [1].x = x + half_width; /* top corner */
1245 points [2].x = x + half_width; /* top inside corner */
1246 points [2].y = y + thickness;
1247 points [3].x = x + thickness; /* left inside corner */
1248 points [3].y = y + half_width;
1250 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
1252 points [0].x = x + half_width; /* top corner */
1254 points [1].x = x + width; /* right corner */
1255 points [1].y = y + half_width;
1256 points [2].x = x + width - thickness; /* right inside corner */
1257 points [2].y = y + half_width;
1258 points [3].x = x + half_width; /* top inside corner */
1259 points [3].y = y + thickness;
1261 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin);
1263 /* Draw the bottom first, just in case the regions overlap.
1264 The top should cast the longer shadow. */
1266 points [npoints].x = x; /* left corner */
1267 points [npoints++].y = y + half_width;
1268 points [npoints].x = x + half_width; /* bottom corner */
1269 points [npoints++].y = y + width;
1270 points [npoints].x = x + width; /* right corner */
1271 points [npoints++].y = y + half_width;
1272 points [npoints].x = x + width - thickness; /* right inside corner */
1273 points [npoints++].y = y + half_width;
1274 points [npoints].x = x + half_width; /* bottom inside corner */
1275 points [npoints++].y = y + width - thickness;
1276 points [npoints].x = x + thickness; /* left inside corner */
1277 points [npoints++].y = y + half_width;
1279 XFillPolygon (dpy, window, bottom_gc,
1280 points, npoints, Nonconvex, CoordModeOrigin);
1284 points [npoints].x = x; /* left corner */
1285 points [npoints++].y = y + half_width;
1286 points [npoints].x = x + half_width; /* top corner */
1287 points [npoints++].y = y;
1288 points [npoints].x = x + width; /* right corner */
1289 points [npoints++].y = y + half_width;
1290 points [npoints].x = x + width - thickness; /* right inside corner */
1291 points [npoints++].y = y + half_width;
1292 points [npoints].x = x + half_width; /* top inside corner */
1293 points [npoints++].y = y + thickness;
1294 points [npoints].x = x + thickness; /* left inside corner */
1295 points [npoints++].y = y + half_width;
1297 XFillPolygon (dpy, window, top_gc, points, npoints, Nonconvex,
1302 /* Fill internal area. */
1305 points [0].x = x + thickness;
1306 points [0].y = y + half_width;
1307 points [1].x = x + half_width;
1308 points [1].y = y + thickness;
1309 points [2].x = x + width - thickness;
1310 points [2].y = y + half_width;
1311 points [3].x = x + half_width;
1312 points [3].y = y + width - thickness;
1324 separator_decoration_draw (XlwMenuWidget mw,
1331 Display *dpy = XtDisplay (mw);
1334 unsigned int offset = 0;
1335 unsigned int num_separators = 1;
1336 unsigned int top_line_thickness = 0;
1337 unsigned int bottom_line_thickness = 0;
1338 Boolean dashed = False;
1342 case SHADOW_NO_LINE: /* nothing to do */
1344 case SHADOW_DOUBLE_LINE:
1346 case SHADOW_SINGLE_LINE:
1347 top_gc = bottom_gc = mw->menu.foreground_gc;
1348 top_line_thickness = 1;
1350 case SHADOW_DOUBLE_DASHED_LINE:
1352 case SHADOW_SINGLE_DASHED_LINE:
1353 top_gc = bottom_gc = mw->menu.foreground_gc;
1354 top_line_thickness = 1;
1357 case SHADOW_DOUBLE_ETCHED_OUT_DASH:
1359 case SHADOW_ETCHED_OUT_DASH:
1360 top_gc = mw->menu.shadow_top_gc;
1361 bottom_gc = mw->menu.shadow_bottom_gc;
1362 top_line_thickness = mw->menu.shadow_thickness/2;
1363 bottom_line_thickness = mw->menu.shadow_thickness - top_line_thickness;
1366 case SHADOW_DOUBLE_ETCHED_IN_DASH:
1368 case SHADOW_ETCHED_IN_DASH:
1369 top_gc = mw->menu.shadow_bottom_gc;
1370 bottom_gc = mw->menu.shadow_top_gc;
1371 top_line_thickness = mw->menu.shadow_thickness/2;
1372 bottom_line_thickness = mw->menu.shadow_thickness - top_line_thickness;
1375 case SHADOW_DOUBLE_ETCHED_OUT:
1377 case SHADOW_ETCHED_OUT:
1378 top_gc = mw->menu.shadow_top_gc;
1379 bottom_gc = mw->menu.shadow_bottom_gc;
1380 top_line_thickness = mw->menu.shadow_thickness/2;
1381 bottom_line_thickness = mw->menu.shadow_thickness - top_line_thickness;
1383 case SHADOW_DOUBLE_ETCHED_IN:
1385 case SHADOW_ETCHED_IN:
1387 top_gc = mw->menu.shadow_bottom_gc;
1388 bottom_gc = mw->menu.shadow_top_gc;
1389 top_line_thickness = mw->menu.shadow_thickness/2;
1390 bottom_line_thickness = mw->menu.shadow_thickness - top_line_thickness;
1397 values.line_style = LineOnOffDash;
1398 if (top_line_thickness > 0)
1399 XChangeGC (dpy, top_gc, GCLineStyle, &values);
1400 if (bottom_line_thickness > 0 && bottom_gc != top_gc)
1401 XChangeGC (dpy, bottom_gc, GCLineStyle, &values);
1404 while (num_separators--)
1407 for (i = 0; i < top_line_thickness; i++)
1408 XDrawLine (dpy, window, top_gc, x, y + i, x + width, y + i);
1410 for (i = 0; i < bottom_line_thickness; i++)
1411 XDrawLine (dpy, window, bottom_gc,
1412 x, y + top_line_thickness + offset + i,
1413 x + width, y + top_line_thickness + offset + i);
1414 y += (top_line_thickness + offset + bottom_line_thickness + 1);
1420 values.line_style = LineSolid;
1421 if (top_line_thickness > 0)
1422 XChangeGC (dpy, top_gc, GCLineStyle, &values);
1423 if (bottom_line_thickness > 0 && bottom_gc != top_gc)
1424 XChangeGC (dpy, bottom_gc, GCLineStyle, &values);
1428 #define SLOPPY_TYPES 0 /* 0=off, 1=error check, 2=easy to please */
1430 #if SLOPPY_TYPES < 2
1432 static char *wv_types[] =
1446 print_widget_value (widget_value *wv, int just_one, int depth)
1450 for (i = 0; i < depth; i++)
1455 printf ("%s(null widget value pointer)\n", d);
1458 printf ("%stype: %s\n", d, wv_types [wv->type]);
1460 printf ("%sname: %s\n", d, (wv->name ? wv->name : "(null)"));
1462 if (wv->name) printf ("%sname: %s\n", d, wv->name);
1464 if (wv->value) printf ("%svalue: %s\n", d, wv->value);
1465 if (wv->key) printf ("%skey: %s\n", d, wv->key);
1466 printf ("%senabled: %d\n", d, wv->enabled);
1469 printf ("\n%scontents: \n", d);
1470 print_widget_value (wv->contents, 0, depth + 5);
1472 if (!just_one && wv->next)
1475 print_widget_value (wv->next, 0, depth);
1481 all_dashes_p (char *s)
1484 if (!s || s[0] == '\0')
1486 for (p = s; *p == '-'; p++);
1488 if (*p == '!' || *p == '\0')
1494 static widget_value_type
1495 menu_item_type (widget_value *val)
1497 if (val->type != UNSPECIFIED_TYPE)
1502 if (all_dashes_p (val->name))
1503 return SEPARATOR_TYPE;
1504 else if (val->name && val->name[0] == '\0') /* push right */
1505 return PUSHRIGHT_TYPE;
1506 else if (val->contents) /* cascade */
1507 return CASCADE_TYPE;
1508 else if (val->call_data) /* push button */
1519 label_button_size (XlwMenuWidget mw,
1522 unsigned int *toggle_width,
1523 unsigned int *label_width,
1524 unsigned int *bindings_width,
1525 unsigned int *height)
1527 *height = (mw->menu.font_ascent + mw->menu.font_descent +
1528 2 * mw->menu.vertical_margin +
1529 2 * mw->menu.shadow_thickness);
1530 /* no left column decoration */
1531 *toggle_width = mw->menu.horizontal_margin + mw->menu.shadow_thickness;;
1533 *label_width = string_width_u (mw, resource_widget_value (mw, val));
1534 *bindings_width = mw->menu.horizontal_margin + mw->menu.shadow_thickness;
1538 label_button_draw (XlwMenuWidget mw,
1541 Boolean highlighted,
1545 unsigned int height,
1546 unsigned int label_offset,
1547 unsigned int binding_tab)
1549 int y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin;
1553 label_offset = mw->menu.shadow_thickness + mw->menu.horizontal_margin;
1555 if (highlighted && (in_menubar || val->contents))
1556 gc = mw->menu.highlight_gc;
1557 else if (in_menubar || val->contents)
1558 gc = mw->menu.foreground_gc;
1560 gc = mw->menu.title_gc;
1562 /* Draw the label string. */
1565 x + label_offset, y + y_offset,
1567 resource_widget_value (mw, val));
1571 push_button_size (XlwMenuWidget mw,
1574 unsigned int *toggle_width,
1575 unsigned int *label_width,
1576 unsigned int *bindings_width,
1577 unsigned int *height)
1580 label_button_size (mw, val, in_menubar,
1581 toggle_width, label_width, bindings_width,
1584 /* key bindings to display? */
1585 if (!in_menubar && val->key)
1589 XmString key = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
1590 w = string_width (mw, key);
1593 char *key = val->key;
1594 w = string_width (mw, key);
1596 *bindings_width += w + mw->menu.column_spacing;
1601 push_button_draw (XlwMenuWidget mw,
1604 Boolean highlighted,
1608 unsigned int height,
1609 unsigned int label_offset,
1610 unsigned int binding_offset)
1612 int y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin;
1615 Boolean menu_pb = in_menubar && (menu_item_type (val) == BUTTON_TYPE);
1617 /* Draw the label string. */
1619 label_offset = mw->menu.shadow_thickness + mw->menu.horizontal_margin;
1624 gc = mw->menu.highlight_gc;
1626 gc = mw->menu.inactive_gc;
1631 gc = mw->menu.button_gc;
1633 gc = mw->menu.inactive_button_gc;
1638 gc = mw->menu.foreground_gc;
1640 gc = mw->menu.inactive_gc;
1645 x + label_offset, y + y_offset,
1647 resource_widget_value (mw, val));
1649 /* Draw the keybindings */
1652 if (!binding_offset)
1654 unsigned int s_width =
1655 string_width (mw, resource_widget_value (mw, val));
1656 binding_offset = label_offset + s_width + mw->menu.shadow_thickness;
1658 binding_draw (mw, window,
1659 x + binding_offset + mw->menu.column_spacing,
1660 y + y_offset, gc, val->key);
1663 /* Draw the shadow */
1669 type = (val->selected ? SHADOW_ETCHED_OUT : SHADOW_ETCHED_IN);
1676 type = SHADOW_BACKGROUND;
1679 shadow_draw (mw, window, x, y, width, height, type);
1683 arrow_decoration_height (XlwMenuWidget mw)
1685 int result = (mw->menu.font_ascent + mw->menu.font_descent) / 2;
1687 result += 2 * mw->menu.shadow_thickness;
1689 if (result > (mw->menu.font_ascent + mw->menu.font_descent))
1690 result = mw->menu.font_ascent + mw->menu.font_descent;
1696 cascade_button_size (XlwMenuWidget mw,
1699 unsigned int *toggle_width,
1700 unsigned int *label_width,
1701 unsigned int *arrow_width,
1702 unsigned int *height)
1705 label_button_size (mw, val, in_menubar,
1706 toggle_width, label_width, arrow_width,
1708 /* we have a pull aside arrow */
1711 *arrow_width += arrow_decoration_height (mw) + mw->menu.column_spacing;
1716 cascade_button_draw (XlwMenuWidget mw,
1719 Boolean highlighted,
1723 unsigned int height,
1724 unsigned int label_offset,
1725 unsigned int binding_offset)
1729 /* Draw the label string. */
1730 label_button_draw (mw, val, in_menubar, highlighted,
1731 window, x, y, width, height, label_offset,
1734 /* Draw the pull aside arrow */
1735 if (!in_menubar && val->contents)
1738 unsigned int arrow_height = arrow_decoration_height (mw);
1740 y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin +
1741 (mw->menu.font_ascent+mw->menu.font_descent - arrow_height)/2;
1743 if (!binding_offset)
1745 unsigned int s_width =
1746 string_width (mw, resource_widget_value (mw, val));
1749 label_offset = mw->menu.shadow_thickness +
1750 mw->menu.horizontal_margin;
1752 binding_offset = label_offset + s_width + mw->menu.shadow_thickness;
1755 arrow_decoration_draw (mw,
1757 x + binding_offset + mw->menu.column_spacing,
1763 /* Draw the shadow */
1767 type = SHADOW_BACKGROUND;
1769 shadow_draw (mw, window, x, y, width, height, type);
1773 toggle_decoration_height (XlwMenuWidget mw)
1776 if (mw->menu.indicator_size > 0)
1777 rv = mw->menu.indicator_size;
1779 rv = mw->menu.font_ascent;
1781 if (rv > (mw->menu.font_ascent + mw->menu.font_descent))
1782 rv = mw->menu.font_ascent + mw->menu.font_descent;
1784 /* radio button can't be smaller than its border or a filling
1785 error will occur. */
1786 if (rv < 2 * mw->menu.shadow_thickness)
1787 rv = 2 * mw->menu.shadow_thickness;
1793 toggle_button_size (XlwMenuWidget mw,
1796 unsigned int *toggle_width,
1797 unsigned int *label_width,
1798 unsigned int *bindings_width,
1799 unsigned int *height)
1802 push_button_size (mw, val, in_menubar,
1803 toggle_width, label_width, bindings_width,
1805 /* we have a toggle */
1806 *toggle_width += toggle_decoration_height (mw) + mw->menu.column_spacing;
1810 toggle_button_draw (XlwMenuWidget mw,
1813 Boolean highlighted,
1817 unsigned int height,
1818 unsigned int label_tab,
1819 unsigned int binding_tab)
1823 unsigned int t_height = toggle_decoration_height (mw);
1825 /* Draw a toggle. */
1826 x_offset = mw->menu.shadow_thickness + mw->menu.horizontal_margin;
1827 y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin;
1828 y_offset += (mw->menu.font_ascent + mw->menu.font_descent - t_height)/2;
1830 toggle_decoration_draw (mw, window, x + x_offset, y + y_offset,
1831 t_height, val->selected);
1833 /* Draw the pushbutton parts. */
1834 push_button_draw (mw, val, in_menubar, highlighted, window, x, y, width,
1835 height, label_tab, binding_tab);
1839 radio_decoration_height (XlwMenuWidget mw)
1841 return toggle_decoration_height (mw);
1845 radio_button_draw (XlwMenuWidget mw,
1848 Boolean highlighted,
1852 unsigned int height,
1853 unsigned int label_tab,
1854 unsigned int binding_tab)
1858 unsigned int r_height = radio_decoration_height (mw);
1860 /* Draw a toggle. */
1861 x_offset = mw->menu.shadow_thickness + mw->menu.horizontal_margin;
1862 y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin;
1863 y_offset += (mw->menu.font_ascent + mw->menu.font_descent - r_height)/2;
1865 radio_decoration_draw (mw, window, x + x_offset, y + y_offset, r_height,
1868 /* Draw the pushbutton parts. */
1869 push_button_draw (mw, val, in_menubar, highlighted, window, x, y, width,
1870 height, label_tab, binding_tab);
1873 static struct _shadow_names
1880 { "singleLine", SHADOW_SINGLE_LINE },
1881 { "doubleLine", SHADOW_DOUBLE_LINE },
1882 { "singleDashedLine", SHADOW_SINGLE_DASHED_LINE },
1883 { "doubleDashedLine", SHADOW_DOUBLE_DASHED_LINE },
1884 { "noLine", SHADOW_NO_LINE },
1885 { "shadowEtchedIn", SHADOW_ETCHED_IN },
1886 { "shadowEtchedOut", SHADOW_ETCHED_OUT },
1887 { "shadowEtchedInDash", SHADOW_ETCHED_IN_DASH },
1888 { "shadowEtchedOutDash", SHADOW_ETCHED_OUT_DASH },
1890 { "shadowDoubleEtchedIn", SHADOW_DOUBLE_ETCHED_IN },
1891 { "shadowDoubleEtchedOut", SHADOW_DOUBLE_ETCHED_OUT },
1892 { "shadowDoubleEtchedInDash", SHADOW_DOUBLE_ETCHED_IN_DASH },
1893 { "shadowDoubleEtchedOutDash", SHADOW_DOUBLE_ETCHED_OUT_DASH }
1897 separator_type (char *name)
1902 for (i = 0; i < (int) (XtNumber (shadow_names)); i++ )
1904 if (strcmp (name, shadow_names[i].name) == 0)
1905 return shadow_names[i].type;
1908 return SHADOW_BACKGROUND;
1912 separator_decoration_height (XlwMenuWidget mw, widget_value *val)
1915 switch (separator_type (val->value))
1917 case SHADOW_NO_LINE:
1918 case SHADOW_SINGLE_LINE:
1919 case SHADOW_SINGLE_DASHED_LINE:
1921 case SHADOW_DOUBLE_LINE:
1922 case SHADOW_DOUBLE_DASHED_LINE:
1924 case SHADOW_DOUBLE_ETCHED_OUT:
1925 case SHADOW_DOUBLE_ETCHED_IN:
1926 case SHADOW_DOUBLE_ETCHED_OUT_DASH:
1927 case SHADOW_DOUBLE_ETCHED_IN_DASH:
1928 return (1 + 2 * mw->menu.shadow_thickness);
1929 case SHADOW_ETCHED_OUT:
1930 case SHADOW_ETCHED_IN:
1932 return mw->menu.shadow_thickness;
1937 separator_size (XlwMenuWidget mw,
1940 unsigned int *toggle_width,
1941 unsigned int *label_width,
1942 unsigned int *rest_width,
1943 unsigned int *height)
1945 *height = separator_decoration_height (mw, val);
1947 *toggle_width = *rest_width = 0;
1951 separator_draw (XlwMenuWidget mw,
1954 Boolean highlighted,
1958 unsigned int height,
1959 unsigned int label_tab,
1960 unsigned int binding_tab)
1962 unsigned int sep_width;
1969 separator_decoration_draw (mw,
1975 separator_type(val->value));
1979 pushright_size (XlwMenuWidget mw,
1982 unsigned int *toggle_width,
1983 unsigned int *label_width,
1984 unsigned int *rest_width,
1985 unsigned int *height)
1987 *height = *label_width = *toggle_width = *rest_width = 0;
1991 size_menu_item (XlwMenuWidget mw,
1994 unsigned int *toggle_width,
1995 unsigned int *label_width,
1996 unsigned int *rest_width,
1997 unsigned int *height)
1999 void (*function_ptr) (XlwMenuWidget _mw,
2001 Boolean _in_menubar,
2002 unsigned int *_toggle_width,
2003 unsigned int *_label_width,
2004 unsigned int *_rest_width,
2005 unsigned int *_height);
2007 switch (menu_item_type (val))
2011 function_ptr = toggle_button_size;
2013 case SEPARATOR_TYPE:
2014 function_ptr = separator_size;
2016 case INCREMENTAL_TYPE:
2018 function_ptr = cascade_button_size;
2021 function_ptr = push_button_size;
2023 case PUSHRIGHT_TYPE:
2024 function_ptr = pushright_size;
2028 function_ptr = label_button_size;
2032 (*function_ptr) (mw,
2042 display_menu_item (XlwMenuWidget mw,
2046 Boolean highlighted,
2048 Boolean just_compute)
2051 int x = where->x /* + mw->menu.shadow_thickness */ ;
2052 int y = where->y /* + mw->menu.shadow_thickness */ ;
2053 unsigned int toggle_width;
2054 unsigned int label_width;
2055 unsigned int binding_width;
2057 unsigned int height;
2058 unsigned int label_tab;
2059 unsigned int binding_tab;
2060 void (*function_ptr) (XlwMenuWidget _mw,
2062 Boolean _in_menubar,
2063 Boolean _highlighted,
2066 unsigned int _width,
2067 unsigned int _height,
2068 unsigned int _label_tab,
2069 unsigned int _binding_tab);
2071 size_menu_item (mw, val, horizontal,
2072 &toggle_width, &label_width, &binding_width, &height);
2076 width = toggle_width + label_width + binding_width;
2077 height = ws->height - 2 * mw->menu.shadow_thickness;
2081 width = ws->width - 2 * mw->menu.shadow_thickness;
2082 toggle_width = ws->toggle_width;
2083 label_width = ws->label_width;
2092 label_tab = toggle_width;
2093 binding_tab = toggle_width + label_width;
2095 switch (menu_item_type (val))
2098 function_ptr = toggle_button_draw;
2101 function_ptr = radio_button_draw;
2103 case SEPARATOR_TYPE:
2104 function_ptr = separator_draw;
2106 case INCREMENTAL_TYPE:
2108 function_ptr = cascade_button_draw;
2111 function_ptr = push_button_draw;
2114 function_ptr = label_button_draw;
2116 default: /* do no drawing */
2120 (*function_ptr) (mw,
2132 size_menu (XlwMenuWidget mw, int level)
2134 unsigned int toggle_width;
2135 unsigned int label_width;
2136 unsigned int rest_width;
2137 unsigned int height;
2138 unsigned int max_toggle_width = 0;
2139 unsigned int max_label_width = 0;
2140 unsigned int max_rest_width = 0;
2141 unsigned int max_height = 0;
2142 int horizontal_p = mw->menu.horizontal && (level == 0);
2146 if (level >= mw->menu.old_depth)
2149 ws = &mw->menu.windows [level];
2151 for (val = mw->menu.old_stack [level]->contents; val; val = val->next)
2162 max_label_width += toggle_width + label_width + rest_width;
2163 if (height > max_height)
2164 max_height = height;
2168 if (max_toggle_width < toggle_width)
2169 max_toggle_width = toggle_width;
2170 if (max_label_width < label_width)
2171 max_label_width = label_width;
2172 if (max_rest_width < rest_width)
2173 max_rest_width = rest_width;
2174 max_height += height;
2178 ws->height = max_height;
2179 ws->width = max_label_width + max_rest_width + max_toggle_width;
2180 ws->toggle_width = max_toggle_width;
2181 ws->label_width = max_label_width;
2183 ws->width += 2 * mw->menu.shadow_thickness;
2184 ws->height += 2 * mw->menu.shadow_thickness;
2188 display_menu (XlwMenuWidget mw, int level, Boolean just_compute_p,
2189 XPoint *highlighted_pos, XPoint *hit, widget_value **hit_return,
2190 widget_value *this, widget_value *that)
2193 widget_value *following_item;
2196 int horizontal_p = mw->menu.horizontal && (level == 0);
2198 int just_compute_this_one_p;
2200 if (level >= mw->menu.old_depth)
2203 if (level < mw->menu.old_depth - 1)
2204 following_item = mw->menu.old_stack [level + 1];
2207 if (lw_menu_accelerate
2208 && level == mw->menu.old_depth - 1
2209 && mw->menu.old_stack [level]->type == CASCADE_TYPE)
2210 just_compute_p = True;
2211 following_item = NULL;
2214 #if SLOPPY_TYPES == 1
2215 puts("===================================================================");
2216 print_widget_value (following_item, 1, 0);
2222 where.x = mw->menu.shadow_thickness;
2223 where.y = mw->menu.shadow_thickness;
2225 ws = &mw->menu.windows [level];
2226 for (val = mw->menu.old_stack [level]->contents; val; val = val->next)
2230 highlighted_p = (val == following_item);
2231 /* If this is the partition (the dummy item which says that menus
2232 after this should be flushright) then figure out how big the
2233 following items are. This means we walk down the tail of the
2234 list twice, but that's no big deal - it's short.
2236 if (horizontal_p && (menu_item_type (val) == PUSHRIGHT_TYPE))
2239 XPoint flushright_size;
2241 flushright_size.x = 0;
2242 flushright_size.y = 0;
2243 for (rest = val; rest; rest = rest->next)
2244 display_menu_item (mw, rest, ws, &flushright_size,
2245 highlighted_p, horizontal_p, True);
2246 new_x = ws->width - (flushright_size.x + mw->menu.shadow_thickness);
2247 if (new_x > where.x)
2249 /* We know what we need; don't draw this item. */
2253 if (highlighted_p && highlighted_pos)
2256 highlighted_pos->x = where.x;
2258 highlighted_pos->y = where.y;
2261 just_compute_this_one_p =
2262 just_compute_p || ((this || that) && val != this && val != that);
2266 display_menu_item (mw, val, ws, &where, highlighted_p, horizontal_p,
2267 just_compute_this_one_p);
2269 if (highlighted_p && highlighted_pos)
2272 highlighted_pos->y = ws->height;
2274 highlighted_pos->x = ws->width;
2277 if (hit && !*hit_return)
2279 if (horizontal_p && hit->x > start.x && hit->x <= where.x)
2281 else if (!horizontal_p && hit->y > start.y && hit->y <= where.y)
2286 where.y = mw->menu.shadow_thickness;
2288 where.x = mw->menu.shadow_thickness;
2291 /* Draw slab edges around menu */
2292 if (!just_compute_p)
2293 shadow_draw(mw, ws->window, 0, 0, ws->width, ws->height, SHADOW_OUT);
2298 set_new_state (XlwMenuWidget mw, widget_value *val, int level)
2302 mw->menu.new_depth = 0;
2303 for (i = 0; i < level; i++)
2304 push_new_stack (mw, mw->menu.old_stack [i]);
2306 push_new_stack (mw, val);
2310 make_windows_if_needed (XlwMenuWidget mw, int n)
2314 XSetWindowAttributes xswa;
2319 window_state *windows;
2322 if (mw->menu.windows_length >= n)
2325 root = RootWindowOfScreen (XtScreen(mw));
2326 /* grab the visual and depth from the nearest shell ancestor */
2327 visual = CopyFromParent;
2328 depth = CopyFromParent;
2330 while (visual == CopyFromParent && p)
2334 visual = ((ShellWidget)p)->shell.visual;
2335 depth = p->core.depth;
2340 xswa.save_under = True;
2341 xswa.override_redirect = True;
2342 xswa.background_pixel = mw->core.background_pixel;
2343 xswa.border_pixel = mw->core.border_pixel;
2344 xswa.event_mask = (ExposureMask | ButtonMotionMask
2345 | ButtonReleaseMask | ButtonPressMask);
2346 xswa.cursor = mw->menu.cursor_shape;
2347 xswa.colormap = mw->core.colormap;
2348 mask = CWSaveUnder | CWOverrideRedirect | CWBackPixel | CWBorderPixel
2349 | CWEventMask | CWCursor | CWColormap;
2351 if (mw->menu.use_backing_store)
2353 xswa.backing_store = Always;
2354 mask |= CWBackingStore;
2357 if (!mw->menu.windows)
2360 (window_state *) XtMalloc (n * sizeof (window_state));
2366 (window_state *) XtRealloc ((char *) mw->menu.windows,
2367 n * sizeof (window_state));
2368 start_at = mw->menu.windows_length;
2370 mw->menu.windows_length = n;
2372 windows = mw->menu.windows;
2374 for (i = start_at; i < n; i++)
2378 windows [i].width = 1;
2379 windows [i].height = 1;
2380 windows [i].window =
2381 XCreateWindow (XtDisplay (mw),
2384 0, depth, CopyFromParent, visual, mask, &xswa);
2388 /* Make the window fit in the screen */
2390 fit_to_screen (XlwMenuWidget mw, window_state *ws, window_state *previous_ws,
2391 Boolean horizontal_p)
2393 int screen_width = WidthOfScreen (XtScreen (mw));
2394 int screen_height = HeightOfScreen (XtScreen (mw));
2398 else if ((int) (ws->x + ws->width) > screen_width)
2401 ws->x = previous_ws->x - ws->width;
2404 ws->x = screen_width - ws->width;
2406 /* This check is to make sure we cut off the right side
2407 instead of the left side if the menu is wider than the
2415 else if ((int) (ws->y + ws->height) > screen_height)
2419 /* A pulldown must either be entirely above or below the menubar.
2420 If we're here, the pulldown doesn't fit below the menubar, so
2421 let's determine if it will fit above the menubar.
2422 Only put it above if there is more room above than below.
2423 Note shadow_thickness offset to allow for slab surround.
2425 if (ws->y > (screen_height / 2))
2426 ws->y = previous_ws->y - ws->height + mw->menu.shadow_thickness;
2430 ws->y = screen_height - ws->height;
2431 /* if it's taller than the screen, display the topmost part
2432 that will fit, beginning at the top of the screen. */
2439 /* Updates old_stack from new_stack and redisplays. */
2441 remap_menubar (XlwMenuWidget mw)
2445 XPoint selection_position;
2446 int old_depth = mw->menu.old_depth;
2447 int new_depth = mw->menu.new_depth;
2448 widget_value **old_stack;
2449 widget_value **new_stack;
2450 window_state *windows;
2451 widget_value *old_selection;
2452 widget_value *new_selection;
2454 /* Check that enough windows and old_stack are ready. */
2455 make_windows_if_needed (mw, new_depth);
2456 make_old_stack_space (mw, new_depth);
2457 windows = mw->menu.windows;
2458 old_stack = mw->menu.old_stack;
2459 new_stack = mw->menu.new_stack;
2461 /* compute the last identical different entry */
2462 for (i = 1; i < old_depth && i < new_depth; i++)
2463 if (old_stack [i] != new_stack [i])
2467 if (lw_menu_accelerate
2469 && last_same == old_depth - 1
2470 && old_stack [last_same]->contents)
2473 /* Memorize the previously selected item to be able to refresh it */
2474 old_selection = last_same + 1 < old_depth ? old_stack [last_same + 1] : NULL;
2475 new_selection = last_same + 1 < new_depth ? new_stack [last_same + 1] : NULL;
2477 /* updates old_state from new_state. It has to be done now because
2478 display_menu (called below) uses the old_stack to know what to display. */
2479 for (i = last_same + 1; i < new_depth; i++)
2480 old_stack [i] = new_stack [i];
2482 mw->menu.old_depth = new_depth;
2484 /* refresh the last seletion */
2485 selection_position.x = 0;
2486 selection_position.y = 0;
2487 display_menu (mw, last_same, new_selection == old_selection,
2488 &selection_position, NULL, NULL, old_selection, new_selection);
2490 /* Now popup the new menus */
2491 for (i = last_same + 1; i < new_depth && new_stack [i]->contents; i++)
2493 window_state *previous_ws = &windows [i - 1];
2494 window_state *ws = &windows [i];
2496 if (lw_menu_accelerate && i == new_depth - 1)
2499 ws->x = previous_ws->x + selection_position.x;
2500 ws->y = previous_ws->y + selection_position.y;
2502 /* take into account the slab around the new menu */
2503 ws->y -= mw->menu.shadow_thickness;
2506 widget_value *val = mw->menu.old_stack [i];
2507 if (val->contents->type == INCREMENTAL_TYPE)
2509 /* okay, we're now doing a lisp callback to incrementally generate
2510 more of the menu. */
2511 XtCallCallbackList ((Widget)mw,
2513 (XtPointer)val->contents);
2519 fit_to_screen (mw, ws, previous_ws, mw->menu.horizontal && i == 1);
2521 XClearWindow (XtDisplay (mw), ws->window);
2522 XMoveResizeWindow (XtDisplay (mw), ws->window, ws->x, ws->y,
2523 ws->width, ws->height);
2524 XMapRaised (XtDisplay (mw), ws->window);
2525 display_menu (mw, i, False, &selection_position, NULL, NULL, NULL, NULL);
2528 /* unmap the menus that popped down */
2530 last_same = new_depth;
2531 if (lw_menu_accelerate
2533 && new_stack [last_same - 1]->contents)
2536 for (i = last_same - 1; i < old_depth; i++)
2537 if (i >= last_same || !new_stack [i]->contents)
2538 XUnmapWindow (XtDisplay (mw), windows [i].window);
2542 motion_event_is_in_menu (XlwMenuWidget mw, XMotionEvent *ev, int level,
2543 XPoint *relative_pos)
2545 window_state *ws = &mw->menu.windows [level];
2546 int x = level == 0 ? ws->x : ws->x + mw->menu.shadow_thickness;
2547 int y = level == 0 ? ws->y : ws->y + mw->menu.shadow_thickness;
2548 relative_pos->x = ev->x_root - x;
2549 relative_pos->y = ev->y_root - y;
2550 return (x < ev->x_root && ev->x_root < (int) (x + ws->width) &&
2551 y < ev->y_root && ev->y_root < (int) (y + ws->height));
2555 map_event_to_widget_value (XlwMenuWidget mw, XMotionEvent *ev,
2556 widget_value **val_ptr, int *level,
2557 Boolean *inside_menu)
2560 XPoint relative_pos;
2564 *inside_menu = False;
2566 /* Find the window */
2568 for (i = mw->menu.old_depth - 1; i >= 0; i--)
2570 for (i = 0; i <= mw->menu.old_depth - 1; i++)
2573 ws = &mw->menu.windows [i];
2574 if (ws && motion_event_is_in_menu (mw, ev, i, &relative_pos))
2576 *inside_menu = True; /* special logic for menubar below... */
2577 if ((ev->type == ButtonPress) ||
2580 display_menu (mw, i, True, NULL, &relative_pos,
2581 val_ptr, NULL, NULL);
2585 *inside_menu = True;
2588 else if (mw->menu.horizontal || i == 0)
2590 /* if we're clicking on empty part of the menubar, then
2591 unpost the stay-up menu */
2592 *inside_menu = False;
2602 make_drawing_gcs (XlwMenuWidget mw)
2605 unsigned long flags = (GCFont | GCForeground | GCBackground);
2608 xgcv.font = default_font_of_font_list (mw->menu.font_list)->fid;
2610 xgcv.font = mw->menu.font->fid;
2613 xgcv.foreground = mw->core.background_pixel;
2614 xgcv.background = mw->menu.foreground;
2615 mw->menu.background_gc = XtGetGC ((Widget) mw, flags, &xgcv);
2617 xgcv.foreground = mw->menu.foreground;
2618 xgcv.background = mw->core.background_pixel;
2619 mw->menu.foreground_gc = XtGetGC ((Widget) mw, flags, &xgcv);
2621 if (mw->menu.select_color != (Pixel)-1)
2623 xgcv.foreground = mw->menu.select_color;
2627 Display *dpy = XtDisplay(mw);
2628 if (CellsOfScreen(DefaultScreenOfDisplay(dpy)) <= 2)
2630 xgcv.foreground = mw->menu.foreground;
2635 Colormap cmap = mw->core.colormap;
2636 xcolor.pixel = mw->core.background_pixel;
2637 XQueryColor (dpy, cmap, &xcolor);
2638 xcolor.red = (xcolor.red * 17) / 20;
2639 xcolor.green = (xcolor.green * 17) / 20;
2640 xcolor.blue = (xcolor.blue * 17) / 20;
2641 if (allocate_nearest_color (dpy, cmap, &xcolor))
2642 xgcv.foreground = xcolor.pixel;
2645 xgcv.background = mw->core.background_pixel;
2646 mw->menu.select_gc = XtGetGC ((Widget)mw, flags, &xgcv);
2648 xgcv.foreground = mw->menu.foreground;
2649 xgcv.background = mw->core.background_pixel;
2650 xgcv.fill_style = FillStippled;
2651 xgcv.stipple = mw->menu.gray_pixmap;
2652 mw->menu.inactive_gc = XtGetGC ((Widget)mw,
2653 (flags | GCFillStyle | GCStipple),
2656 xgcv.foreground = mw->menu.highlight_foreground;
2657 xgcv.background = mw->core.background_pixel;
2658 mw->menu.highlight_gc = XtGetGC ((Widget)mw, flags, &xgcv);
2660 xgcv.foreground = mw->menu.title_foreground;
2661 xgcv.background = mw->core.background_pixel;
2662 mw->menu.title_gc = XtGetGC ((Widget)mw, flags, &xgcv);
2664 xgcv.foreground = mw->menu.button_foreground;
2665 xgcv.background = mw->core.background_pixel;
2666 mw->menu.button_gc = XtGetGC ((Widget)mw, flags, &xgcv);
2668 xgcv.fill_style = FillStippled;
2669 xgcv.stipple = mw->menu.gray_pixmap;
2670 mw->menu.inactive_button_gc = XtGetGC ((Widget)mw,
2671 (flags | GCFillStyle | GCStipple),
2676 release_drawing_gcs (XlwMenuWidget mw)
2678 XtReleaseGC ((Widget) mw, mw->menu.foreground_gc);
2679 XtReleaseGC ((Widget) mw, mw->menu.button_gc);
2680 XtReleaseGC ((Widget) mw, mw->menu.highlight_gc);
2681 XtReleaseGC ((Widget) mw, mw->menu.title_gc);
2682 XtReleaseGC ((Widget) mw, mw->menu.inactive_gc);
2683 XtReleaseGC ((Widget) mw, mw->menu.inactive_button_gc);
2684 XtReleaseGC ((Widget) mw, mw->menu.background_gc);
2685 XtReleaseGC ((Widget) mw, mw->menu.select_gc);
2686 /* let's get some segvs if we try to use these... */
2687 mw->menu.foreground_gc = (GC) -1;
2688 mw->menu.button_gc = (GC) -1;
2689 mw->menu.highlight_gc = (GC) -1;
2690 mw->menu.title_gc = (GC) -1;
2691 mw->menu.inactive_gc = (GC) -1;
2692 mw->menu.inactive_button_gc = (GC) -1;
2693 mw->menu.background_gc = (GC) -1;
2694 mw->menu.select_gc = (GC) -1;
2697 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
2698 ? ((unsigned long) (x)) : ((unsigned long) (y)))
2701 make_shadow_gcs (XlwMenuWidget mw)
2704 unsigned long pm = 0;
2705 Display *dpy = XtDisplay ((Widget) mw);
2706 Colormap cmap = mw->core.colormap;
2708 int top_frobbed = 0, bottom_frobbed = 0;
2710 if (mw->menu.top_shadow_color == (Pixel) (-1))
2711 mw->menu.top_shadow_color = mw->core.background_pixel;
2712 if (mw->menu.bottom_shadow_color == (Pixel) (-1))
2713 mw->menu.bottom_shadow_color = mw->menu.foreground;
2715 if (mw->menu.top_shadow_color == mw->core.background_pixel ||
2716 mw->menu.top_shadow_color == mw->menu.foreground)
2718 topc.pixel = mw->core.background_pixel;
2719 XQueryColor (dpy, cmap, &topc);
2720 /* don't overflow/wrap! */
2721 topc.red = MINL (65535, topc.red * 1.2);
2722 topc.green = MINL (65535, topc.green * 1.2);
2723 topc.blue = MINL (65535, topc.blue * 1.2);
2724 if (allocate_nearest_color (dpy, cmap, &topc))
2726 if (topc.pixel == mw->core.background_pixel)
2728 XFreeColors( dpy, cmap, &topc.pixel, 1, 0);
2729 topc.red = MINL (65535, topc.red + 0x8000);
2730 topc.green = MINL (65535, topc.green + 0x8000);
2731 topc.blue = MINL (65535, topc.blue + 0x8000);
2732 if (allocate_nearest_color (dpy, cmap, &topc))
2734 mw->menu.top_shadow_color = topc.pixel;
2739 mw->menu.top_shadow_color = topc.pixel;
2745 if (mw->menu.bottom_shadow_color == mw->menu.foreground ||
2746 mw->menu.bottom_shadow_color == mw->core.background_pixel)
2748 botc.pixel = mw->core.background_pixel;
2749 XQueryColor (dpy, cmap, &botc);
2750 botc.red = (botc.red * 3) / 5;
2751 botc.green = (botc.green * 3) / 5;
2752 botc.blue = (botc.blue * 3) / 5;
2753 if (allocate_nearest_color (dpy, cmap, &botc))
2755 if (botc.pixel == mw->core.background_pixel)
2757 XFreeColors (dpy, cmap, &botc.pixel, 1, 0);
2758 botc.red = MINL (65535, botc.red + 0x4000);
2759 botc.green = MINL (65535, botc.green + 0x4000);
2760 botc.blue = MINL (65535, botc.blue + 0x4000);
2761 if (allocate_nearest_color (dpy, cmap, &botc))
2763 mw->menu.bottom_shadow_color = botc.pixel;
2768 mw->menu.bottom_shadow_color = botc.pixel;
2775 if (top_frobbed && bottom_frobbed)
2777 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3));
2778 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3));
2779 if (bot_avg > top_avg)
2781 Pixel tmp = mw->menu.top_shadow_color;
2782 mw->menu.top_shadow_color = mw->menu.bottom_shadow_color;
2783 mw->menu.bottom_shadow_color = tmp;
2785 else if (topc.pixel == botc.pixel)
2787 if (botc.pixel == mw->menu.foreground)
2788 mw->menu.top_shadow_color = mw->core.background_pixel;
2790 mw->menu.bottom_shadow_color = mw->menu.foreground;
2794 if (!mw->menu.top_shadow_pixmap &&
2795 mw->menu.top_shadow_color == mw->core.background_pixel)
2797 mw->menu.top_shadow_pixmap = mw->menu.gray_pixmap;
2798 mw->menu.top_shadow_color = mw->menu.foreground;
2800 if (!mw->menu.bottom_shadow_pixmap &&
2801 mw->menu.bottom_shadow_color == mw->core.background_pixel)
2803 mw->menu.bottom_shadow_pixmap = mw->menu.gray_pixmap;
2804 mw->menu.bottom_shadow_color = mw->menu.foreground;
2807 xgcv.fill_style = FillOpaqueStippled;
2808 xgcv.foreground = mw->menu.top_shadow_color;
2809 xgcv.background = mw->core.background_pixel;
2810 /* xgcv.stipple = mw->menu.top_shadow_pixmap; gtb */
2812 if (mw->menu.top_shadow_pixmap &&
2813 mw->menu.top_shadow_pixmap != XmUNSPECIFIED_PIXMAP)
2814 xgcv.stipple = mw->menu.top_shadow_pixmap;
2818 xgcv.stipple = mw->menu.top_shadow_pixmap;
2819 #endif /* NEED_MOTIF */
2820 pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
2821 mw->menu.shadow_top_gc =
2822 XtGetGC((Widget)mw, GCForeground|GCBackground|pm, &xgcv);
2824 xgcv.foreground = mw->menu.bottom_shadow_color;
2825 /* xgcv.stipple = mw->menu.bottom_shadow_pixmap; gtb */
2827 if (mw->menu.top_shadow_pixmap &&
2828 mw->menu.top_shadow_pixmap != XmUNSPECIFIED_PIXMAP)
2829 xgcv.stipple = mw->menu.bottom_shadow_pixmap;
2833 xgcv.stipple = mw->menu.bottom_shadow_pixmap;
2834 #endif /* NEED_MOTIF */
2835 pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0);
2836 mw->menu.shadow_bottom_gc =
2837 XtGetGC ((Widget)mw, GCForeground|GCBackground|pm, &xgcv);
2842 release_shadow_gcs (XlwMenuWidget mw)
2844 XtReleaseGC ((Widget) mw, mw->menu.shadow_top_gc);
2845 XtReleaseGC ((Widget) mw, mw->menu.shadow_bottom_gc);
2850 extract_font_extents (XlwMenuWidget mw)
2853 /* Find the maximal ascent/descent of the fonts in the font list
2854 so that all menu items can be the same height... */
2855 mw->menu.font_ascent = 0;
2856 mw->menu.font_descent = 0;
2859 XmFontContext context;
2860 #if (XmVersion >= 1002)
2861 XmFontListEntry fontentry;
2863 XmStringCharSet charset;
2867 if (! XmFontListInitFontContext (&context, mw->menu.font_list))
2869 #if (XmVersion >= 1002)
2870 /* There is a BUG in the 1.2 version of XmFontListGetNextFont() (or more
2871 specifically, in _XmGetFirstFont()) that can cause a null pointer to be
2872 passed to XFontsOfFontSet. Use XmFontListNextEntry(), which is the
2873 newer equivalent, instead. Also, it supports font sets, and the
2874 older function doesn't. */
2875 while ((fontentry = XmFontListNextEntry (context)))
2879 XtPointer one_of_them = XmFontListEntryGetFont (fontentry, &rettype);
2880 if (rettype == XmFONT_IS_FONTSET)
2882 XFontSet fontset = (XFontSet) one_of_them;
2883 XFontStruct **fontstruct_list;
2884 char **fontname_list;
2885 int fontcount = XFontsOfFontSet (fontset, &fontstruct_list,
2887 while (--fontcount >= 0)
2889 font = fontstruct_list[fontcount];
2890 if (font->ascent > (int) mw->menu.font_ascent)
2891 mw->menu.font_ascent = font->ascent;
2892 if (font->descent > (int) mw->menu.font_descent)
2893 mw->menu.font_descent = font->descent;
2896 else /* XmFONT_IS_FONT */
2898 font = (XFontStruct *) one_of_them;
2899 if (font->ascent > (int) mw->menu.font_ascent)
2900 mw->menu.font_ascent = font->ascent;
2901 if (font->descent > (int) mw->menu.font_descent)
2902 mw->menu.font_descent = font->descent;
2905 #else /* motif 1.1 */
2906 while (XmFontListGetNextFont (context, &charset, &font))
2908 if (font->ascent > (int) mw->menu.font_ascent)
2909 mw->menu.font_ascent = font->ascent;
2910 if (font->descent > (int) mw->menu.font_descent)
2911 mw->menu.font_descent = font->descent;
2914 #endif /* Motif version */
2915 XmFontListFreeFontContext (context);
2917 #else /* Not Motif */
2918 # ifdef USE_XFONTSET
2919 XFontStruct **fontstruct_list;
2920 char **fontname_list;
2922 int fontcount = XFontsOfFontSet(mw->menu.font_set, &fontstruct_list,
2924 mw->menu.font_ascent = 0;
2925 mw->menu.font_descent = 0;
2926 # if 0 /* nasty, personal debug, Kazz */
2927 fprintf(stderr, "fontSet count is %d\n", fontcount);
2929 while (--fontcount >= 0) {
2930 font = fontstruct_list[fontcount];
2931 if (font->ascent > (int) mw->menu.font_ascent)
2932 mw->menu.font_ascent = font->ascent;
2933 if (font->descent > (int) mw->menu.font_descent)
2934 mw->menu.font_descent = font->descent;
2936 # else /* ! USE_XFONTSET */
2937 mw->menu.font_ascent = mw->menu.font->ascent;
2938 mw->menu.font_descent = mw->menu.font->descent;
2940 #endif /* NEED_MOTIF */
2944 static XFontStruct *
2945 default_font_of_font_list (XmFontList font_list)
2947 XFontStruct *font = 0;
2949 /* Xm/Label.c does this: */
2950 _XmFontListGetDefaultFont (font_list, &font);
2953 XmFontContext context;
2954 #if (XmVersion >= 1002)
2955 XmFontListEntry fontentry;
2957 XtPointer one_of_them;
2959 XmStringCharSet charset;
2962 if (! XmFontListInitFontContext (&context, font_list))
2964 #if (XmVersion >= 1002)
2965 /* There is a BUG in the 1.2 version of XmFontListGetNextFont() (or more
2966 specifically, in _XmGetFirstFont()) that can cause a null pointer to be
2967 passed to XFontsOfFontSet. Use XmFontListNextEntry(), which is the
2968 newer equivalent, instead. */
2969 fontentry = XmFontListNextEntry (context);
2970 one_of_them = XmFontListEntryGetFont (fontentry, &rettype);
2971 if (rettype == XmFONT_IS_FONTSET)
2973 XFontSet fontset = (XFontSet) one_of_them;
2974 XFontStruct **fontstruct_list;
2975 char **fontname_list;
2976 (void) XFontsOfFontSet (fontset, &fontstruct_list, &fontname_list);
2977 font = fontstruct_list[0];
2979 else /* XmFONT_IS_FONT */
2981 font = (XFontStruct *) one_of_them;
2984 if (! XmFontListGetNextFont (context, &charset, &font))
2988 XmFontListFreeFontContext (context);
2992 if (! font) abort ();
2995 #endif /* NEED_MOTIF */
2998 XlwMenuInitialize (Widget request, Widget new, ArgList args,
3001 /* Get the GCs and the widget size */
3002 XlwMenuWidget mw = (XlwMenuWidget)new;
3004 XSetWindowAttributes xswa;
3007 Window window = RootWindowOfScreen (DefaultScreenOfDisplay (XtDisplay (mw)));
3008 Display *display = XtDisplay (mw);
3010 /* mw->menu.cursor = XCreateFontCursor (display, mw->menu.cursor_shape); */
3011 mw->menu.cursor = mw->menu.cursor_shape;
3013 mw->menu.gray_pixmap =
3014 XCreatePixmapFromBitmapData (display, window, (char *) gray_bits,
3015 gray_width, gray_height, 1, 0, 1);
3018 /* The menu.font_list slot came from the *fontList resource (Motif standard.)
3019 The menu.font_list_2 slot came from the *font resource, for backward
3020 compatibility with older versions of this code, and consistency with the
3021 rest of emacs. If both font and fontList are specified, we use font.
3022 If only one is specified, we use that. If neither are specified, we
3023 use the "fallback" value. What a kludge!!!
3025 Note that this has the bug that a more general wildcard like "*fontList:"
3026 will override a more specific resource like "Emacs*menubar.font:". But
3027 I can't think of a way around that.
3029 if (mw->menu.font_list) /* if *fontList is specified, use that */
3031 else if (mw->menu.font_list_2) /* else if *font is specified, use that */
3032 mw->menu.font_list = mw->menu.font_list_2;
3033 else /* otherwise use default */
3034 mw->menu.font_list = mw->menu.fallback_font_list;
3037 make_drawing_gcs (mw);
3038 make_shadow_gcs (mw);
3039 extract_font_extents (mw);
3041 xswa.background_pixel = mw->core.background_pixel;
3042 xswa.border_pixel = mw->core.border_pixel;
3043 mask = CWBackPixel | CWBorderPixel;
3045 mw->menu.popped_up = False;
3046 mw->menu.pointer_grabbed = False;
3047 mw->menu.next_release_must_exit = False;
3049 mw->menu.old_depth = 1;
3050 mw->menu.old_stack = XtNew (widget_value*);
3051 mw->menu.old_stack_length = 1;
3052 mw->menu.old_stack [0] = mw->menu.contents;
3054 mw->menu.new_depth = 0;
3055 mw->menu.new_stack = 0;
3056 mw->menu.new_stack_length = 0;
3057 push_new_stack (mw, mw->menu.contents);
3059 mw->menu.windows = XtNew (window_state);
3060 mw->menu.windows_length = 1;
3061 mw->menu.windows [0].x = 0;
3062 mw->menu.windows [0].y = 0;
3063 mw->menu.windows [0].width = 0;
3064 mw->menu.windows [0].height = 0;
3067 mw->core.width = mw->menu.windows [0].width;
3068 mw->core.height = mw->menu.windows [0].height;
3072 XlwMenuClassInitialize (void)
3074 initialize_massaged_resource_char();
3078 XlwMenuRealize (Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
3080 XlwMenuWidget mw = (XlwMenuWidget)w;
3081 XSetWindowAttributes xswa;
3084 (*xlwMenuWidgetClass->core_class.superclass->core_class.realize)
3085 (w, valueMask, attributes);
3087 xswa.save_under = True;
3088 xswa.cursor = mw->menu.cursor_shape;
3089 mask = CWSaveUnder | CWCursor;
3090 if (mw->menu.use_backing_store)
3092 xswa.backing_store = Always;
3093 mask |= CWBackingStore;
3095 XChangeWindowAttributes (XtDisplay (w), XtWindow (w), mask, &xswa);
3097 mw->menu.windows [0].window = XtWindow (w);
3098 mw->menu.windows [0].x = w->core.x;
3099 mw->menu.windows [0].y = w->core.y;
3100 mw->menu.windows [0].width = w->core.width;
3101 mw->menu.windows [0].height = w->core.height;
3104 /* Only the toplevel menubar/popup is a widget so it's the only one that
3105 receives expose events through Xt. So we repaint all the other panes
3106 when receiving an Expose event. */
3108 XlwMenuRedisplay (Widget w, XEvent *ev, Region region)
3110 XlwMenuWidget mw = (XlwMenuWidget)w;
3113 if (mw->core.being_destroyed) return;
3115 for (i = 0; i < mw->menu.old_depth; i++)
3116 display_menu (mw, i, False, NULL, NULL, NULL, NULL, NULL);
3117 set_new_state (mw, NULL, mw->menu.old_depth); /* #### - ??? */
3118 remap_menubar (mw); /* #### - do these two lines do anything? */
3122 XlwMenuDestroy (Widget w)
3125 XlwMenuWidget mw = (XlwMenuWidget) w;
3127 if (mw->menu.pointer_grabbed)
3129 XtUngrabPointer (w, CurrentTime);
3130 mw->menu.pointer_grabbed = False;
3133 release_drawing_gcs (mw);
3134 release_shadow_gcs (mw);
3136 /* this doesn't come from the resource db but is created explicitly
3137 so we must free it ourselves. */
3138 XFreePixmap (XtDisplay (mw), mw->menu.gray_pixmap);
3139 mw->menu.gray_pixmap = (Pixmap) -1;
3141 /* Don't free mw->menu.contents because that comes from our creator.
3142 The `*_stack' elements are just pointers into `contents' so leave
3143 that alone too. But free the stacks themselves. */
3144 if (mw->menu.old_stack) XtFree ((char *) mw->menu.old_stack);
3145 if (mw->menu.new_stack) XtFree ((char *) mw->menu.new_stack);
3147 /* Remember, you can't free anything that came from the resource
3148 database. This includes:
3150 mw->menu.top_shadow_pixmap
3151 mw->menu.bottom_shadow_pixmap
3154 Also the color cells of top_shadow_color, bottom_shadow_color,
3155 foreground, and button_foreground will never be freed until this
3156 client exits. Nice, eh?
3159 /* start from 1 because the one in slot 0 is w->core.window */
3160 for (i = 1; i < mw->menu.windows_length; i++)
3161 XDestroyWindow (XtDisplay (mw), mw->menu.windows [i].window);
3162 if (mw->menu.windows)
3163 XtFree ((char *) mw->menu.windows);
3167 XlwMenuSetValues (Widget current, Widget request, Widget new, ArgList args,
3170 XlwMenuWidget oldmw = (XlwMenuWidget)current;
3171 XlwMenuWidget newmw = (XlwMenuWidget)new;
3172 Boolean redisplay = False;
3175 if (newmw->menu.contents
3176 && newmw->menu.contents->contents
3177 && newmw->menu.contents->contents->change >= VISIBLE_CHANGE)
3180 if (newmw->core.background_pixel != oldmw->core.background_pixel
3181 || newmw->menu.foreground != oldmw->menu.foreground
3182 /* For the XEditResource protocol, which may want to change the font. */
3184 || newmw->menu.font_list != oldmw->menu.font_list
3185 || newmw->menu.font_list_2 != oldmw->menu.font_list_2
3186 || newmw->menu.fallback_font_list != oldmw->menu.fallback_font_list
3188 || newmw->menu.font != oldmw->menu.font
3192 release_drawing_gcs (newmw);
3193 make_drawing_gcs (newmw);
3196 for (i = 0; i < oldmw->menu.windows_length; i++)
3198 XSetWindowBackground (XtDisplay (oldmw),
3199 oldmw->menu.windows [i].window,
3200 newmw->core.background_pixel);
3201 /* clear windows and generate expose events */
3202 XClearArea (XtDisplay (oldmw), oldmw->menu.windows[i].window,
3211 XlwMenuResize (Widget w)
3213 XlwMenuWidget mw = (XlwMenuWidget)w;
3215 mw->menu.windows [0].width = mw->core.width;
3216 mw->menu.windows [0].height = mw->core.height;
3219 \f/* Action procedures */
3221 handle_single_motion_event (XlwMenuWidget mw, XMotionEvent *ev,
3228 if (!map_event_to_widget_value (mw, ev, &val, &level, &stay_up))
3230 /* we wind up here when: (a) the event is in the menubar, (b) the
3231 event isn't in the menubar or any of the panes, (c) the event is on
3232 a disabled menu item */
3233 pop_new_stack_if_no_contents (mw);
3234 if (select_p && !stay_up) {
3235 /* pop down all menus and exit */
3236 mw->menu.next_release_must_exit = True;
3237 set_new_state(mw, (val = NULL), 1);
3242 /* we wind up here when: (a) the event pops up a pull_right menu,
3243 (b) a menu item that is not disabled is highlighted */
3244 if (select_p && mw->menu.bounce_down
3245 && close_to_reference_time((Widget)mw,
3246 mw->menu.menu_bounce_time,
3249 /* motion can cause more than one event. Don't bounce right back
3250 up if we've just bounced down. */
3253 else if (select_p && mw->menu.bounce_down &&
3254 mw->menu.last_selected_val &&
3255 (mw->menu.last_selected_val == val))
3257 val = NULL; /* assigned to mw->last_selected_val below */
3258 mw->menu.menu_bounce_time = ev->time;
3259 /* popdown last menu if we're selecting the same menu item as we did
3260 last time and the XlwMenu.bounceDown resource is set, if the
3261 item is on the menubar itself, then exit. */
3262 if (level == (mw->menu.popped_up ? 0 : 1))
3263 mw->menu.next_release_must_exit = True;
3266 mw->menu.menu_bounce_time = 0;
3267 set_new_state (mw, val, level);
3269 mw->menu.last_selected_val = val;
3272 /* Sync with the display. Makes it feel better on X terms. */
3273 XFlush (XtDisplay (mw));
3277 handle_motion_event (XlwMenuWidget mw, XMotionEvent *ev,
3282 unsigned int state = ev->state;
3283 XMotionEvent *event= ev, dummy;
3285 /* allow motion events to be generated again */
3286 dummy.window = ev->window;
3288 && XQueryPointer (XtDisplay (mw), dummy.window,
3289 &dummy.root, &dummy.subwindow,
3290 &dummy.x_root, &dummy.y_root,
3293 && dummy.state == state
3294 && (dummy.x_root != x || dummy.y_root != y))
3296 /* don't handle the event twice or that breaks bounce_down. --Stig */
3297 dummy.type = ev->type;
3301 lw_menu_accelerate = False;
3302 handle_single_motion_event (mw, event, select_p);
3305 Time x_focus_timestamp_really_sucks_fix_me_better;
3308 Start (Widget w, XEvent *ev, String *params, Cardinal *num_params)
3310 XlwMenuWidget mw = (XlwMenuWidget)w;
3312 lw_menubar_widget = w;
3314 lw_menu_active = True;
3316 if (!mw->menu.pointer_grabbed)
3318 mw->menu.menu_post_time = ev->xbutton.time;
3319 mw->menu.menu_bounce_time = 0;
3320 mw->menu.next_release_must_exit = True;
3321 mw->menu.last_selected_val = NULL;
3322 x_focus_timestamp_really_sucks_fix_me_better =
3323 ((XButtonPressedEvent*)ev)->time;
3324 XtCallCallbackList ((Widget)mw, mw->menu.open, NULL);
3326 /* notes the absolute position of the menubar window */
3327 mw->menu.windows [0].x = ev->xmotion.x_root - ev->xmotion.x;
3328 mw->menu.windows [0].y = ev->xmotion.y_root - ev->xmotion.y;
3330 XtGrabPointer ((Widget)mw, False,
3331 (ButtonMotionMask | ButtonReleaseMask | ButtonPressMask),
3332 GrabModeAsync, GrabModeAsync,
3333 None, mw->menu.cursor_shape,
3334 ((XButtonPressedEvent*)ev)->time);
3335 mw->menu.pointer_grabbed = True;
3338 /* handles the down like a move, slots are mostly compatible */
3339 handle_motion_event (mw, &ev->xmotion, True);
3343 Drag (Widget w, XEvent *ev, String *params, Cardinal *num_params)
3345 XlwMenuWidget mw = (XlwMenuWidget)w;
3346 handle_motion_event (mw, &ev->xmotion, False);
3350 Select (Widget w, XEvent *ev, String *params, Cardinal *num_params)
3352 XlwMenuWidget mw = (XlwMenuWidget)w;
3353 widget_value *selected_item = mw->menu.old_stack [mw->menu.old_depth - 1];
3355 lw_menu_accelerate = False;
3357 /* If user releases the button quickly, without selecting anything,
3358 after the initial down-click that brought the menu up,
3360 if ((selected_item == 0 || selected_item->call_data == 0)
3361 && (!mw->menu.next_release_must_exit
3362 || close_to_reference_time(w, mw->menu.menu_post_time, ev)))
3364 mw->menu.next_release_must_exit = False;
3368 /* pop down everything */
3369 mw->menu.new_depth = 1;
3372 /* Destroy() only gets called for popup menus. Menubar widgets aren't
3373 destroyed when their menu panes get nuked. */
3374 if (mw->menu.pointer_grabbed)
3376 XtUngrabPointer ((Widget)w, ev->xmotion.time);
3377 mw->menu.pointer_grabbed = False;
3380 if (mw->menu.popped_up)
3382 mw->menu.popped_up = False;
3383 XtPopdown (XtParent (mw));
3386 lw_menu_active = False;
3388 x_focus_timestamp_really_sucks_fix_me_better =
3389 ((XButtonPressedEvent*)ev)->time;
3392 XtCallCallbackList ((Widget) mw, mw->menu.select, (XtPointer) selected_item);
3395 \f/* Action procedures for keyboard accelerators */
3399 xlw_set_menu (Widget w, widget_value *val)
3401 lw_menubar_widget = w;
3402 set_new_state ((XlwMenuWidget)w, val, 1);
3405 /* prepare the menu structure via the call-backs */
3407 xlw_map_menu (Time t)
3409 XlwMenuWidget mw = (XlwMenuWidget)lw_menubar_widget;
3411 lw_menu_accelerate = True;
3413 if (!mw->menu.pointer_grabbed)
3415 XWindowAttributes ret;
3418 unsigned int num_waste;
3420 lw_menu_active = True;
3422 mw->menu.menu_post_time = t;
3423 mw->menu.menu_bounce_time = 0;
3425 mw->menu.next_release_must_exit = True;
3426 mw->menu.last_selected_val = NULL;
3428 XtCallCallbackList ((Widget)mw, mw->menu.open, NULL);
3430 /* do this for keyboards too! */
3431 /* notes the absolute position of the menubar window */
3433 mw->menu.windows [0].x = ev->xmotion.x_root - ev->xmotion.x;
3434 mw->menu.windows [0].y = ev->xmotion.y_root - ev->xmotion.y;
3437 /* get the geometry of the menubar */
3439 /* there has to be a better way than this. */
3441 mw->menu.windows [0].x = 0;
3442 mw->menu.windows [0].y = 0;
3444 parent = XtWindow (lw_menubar_widget);
3447 XGetWindowAttributes (XtDisplay (lw_menubar_widget), parent, &ret);
3448 mw->menu.windows [0].x += ret.x;
3449 mw->menu.windows [0].y += ret.y;
3452 XQueryTree (XtDisplay (lw_menubar_widget), parent, &root, &parent, &waste,
3459 while (parent != root);
3461 XtGrabPointer ((Widget)mw, False,
3462 (ButtonMotionMask | ButtonReleaseMask | ButtonPressMask),
3463 GrabModeAsync, GrabModeAsync,
3464 None, mw->menu.cursor_shape, t);
3465 mw->menu.pointer_grabbed = True;
3469 /* display the stupid menu already */
3471 xlw_display_menu (Time t)
3473 XlwMenuWidget mw = (XlwMenuWidget)lw_menubar_widget;
3475 lw_menu_accelerate = True;
3479 /* Sync with the display. Makes it feel better on X terms. */
3480 XFlush (XtDisplay (mw));
3483 /* push a sub menu */
3485 xlw_push_menu (widget_value *val)
3487 push_new_stack ((XlwMenuWidget)lw_menubar_widget, val);
3490 /* pop a sub menu */
3494 if (((XlwMenuWidget)lw_menubar_widget)->menu.new_depth > 0)
3495 ((XlwMenuWidget)lw_menubar_widget)->menu.new_depth --;
3502 xlw_kill_menus (widget_value *val)
3504 XlwMenuWidget mw = (XlwMenuWidget)lw_menubar_widget;
3506 lw_menu_accelerate = False;
3508 mw->menu.new_depth = 1;
3511 if (mw->menu.pointer_grabbed)
3513 XtUngrabPointer (lw_menubar_widget, CurrentTime);
3514 mw->menu.pointer_grabbed = False;
3517 lw_menu_active = False;
3518 XtCallCallbackList (lw_menubar_widget, mw->menu.select, (XtPointer)val);
3521 /* set the menu item */
3523 xlw_set_item (widget_value *val)
3525 if (((XlwMenuWidget)lw_menubar_widget)->menu.new_depth > 0)
3526 ((XlwMenuWidget) lw_menubar_widget)->menu.new_depth --;
3527 push_new_stack ((XlwMenuWidget) lw_menubar_widget, val);
3530 /* get either the current entry or a list of all entries in the current submenu */
3532 xlw_get_entries (int allp)
3534 XlwMenuWidget mw = (XlwMenuWidget)lw_menubar_widget;
3537 if (mw->menu.new_depth >= 2)
3538 return mw->menu.new_stack [mw->menu.new_depth - 2]->contents;
3540 return mw->menu.new_stack[0];
3543 if (mw->menu.new_depth >= 1)
3544 return mw->menu.new_stack [mw->menu.new_depth - 1];
3550 xlw_menu_level (void)
3552 return ((XlwMenuWidget)lw_menubar_widget)->menu.new_depth;
3556 /* Special code to pop-up a menu */
3558 xlw_pop_up_menu (XlwMenuWidget mw, XButtonPressedEvent *event)
3560 int x = event->x_root;
3561 int y = event->y_root;
3564 int borderwidth = mw->menu.shadow_thickness;
3565 Screen* screen = XtScreen (mw);
3567 mw->menu.menu_post_time = event->time;
3568 mw->menu.menu_bounce_time = 0;
3569 mw->menu.next_release_must_exit = True;
3570 mw->menu.last_selected_val = NULL;
3572 XtCallCallbackList ((Widget) mw, mw->menu.open, NULL);
3576 w = mw->menu.windows [0].width;
3577 h = mw->menu.windows [0].height;
3582 if (x < borderwidth)
3585 if (x > WidthOfScreen (screen) - w - 2 * borderwidth)
3586 x = WidthOfScreen (screen) - w - 2 * borderwidth;
3588 if (y < borderwidth)
3591 if (y > HeightOfScreen (screen) - h - 2 * borderwidth)
3592 y = HeightOfScreen (screen) - h - 2 * borderwidth;
3594 mw->menu.popped_up = True;
3595 XtConfigureWidget (XtParent (mw), x, y, w, h,
3596 XtParent (mw)->core.border_width);
3597 XtPopup (XtParent (mw), XtGrabExclusive);
3598 display_menu (mw, 0, False, NULL, NULL, NULL, NULL, NULL);
3599 if (!mw->menu.pointer_grabbed)
3601 XtGrabPointer ((Widget)mw, False,
3602 (ButtonMotionMask | ButtonReleaseMask | ButtonPressMask),
3603 GrabModeAsync, GrabModeAsync,
3604 None, mw->menu.cursor_shape, event->time);
3605 mw->menu.pointer_grabbed = True;
3608 mw->menu.windows [0].x = x + borderwidth;
3609 mw->menu.windows [0].y = y + borderwidth;
3611 handle_motion_event (mw, (XMotionEvent *) event, True);
3617 * This is a horrible function which should not be needed.
3618 * use it to put the resize method back the way the XlwMenu
3619 * class initializer put it. Motif screws with this when
3620 * the XlwMenu class gets instantiated.
3623 xlw_unmunge_class_resize (Widget w)
3625 if (w->core.widget_class->core_class.resize != XlwMenuResize)
3626 w->core.widget_class->core_class.resize = XlwMenuResize;