comparison lwlib/xlwmenu.c @ 8860:8e5ef22c9438

*** empty log message ***
author Paul Reilly <pmr@pajato.com>
date Sat, 17 Sep 1994 12:53:30 +0000
parents f84dac6453db
children a5e3635a9544
comparison
equal deleted inserted replaced
8859:678a41575de0 8860:8e5ef22c9438
17 along with GNU Emacs; see the file COPYING. If not, write to 17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ 18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19 19
20 /* Created by devin@lucid.com */ 20 /* Created by devin@lucid.com */
21 21
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <stdio.h> 22 #include <stdio.h>
26 23
27 #include <sys/types.h> 24 #include <sys/types.h>
28 #include <X11/Xos.h> 25 #include <X11/Xos.h>
29 #include <X11/IntrinsicP.h> 26 #include <X11/IntrinsicP.h>
30 #include <X11/StringDefs.h> 27 #include <X11/StringDefs.h>
31 #include <X11/cursorfont.h> 28 #include <X11/cursorfont.h>
32 #include <X11/bitmaps/gray> 29 #include <X11/bitmaps/gray>
33 #include "xlwmenuP.h" 30 #include "xlwmenuP.h"
34 #include <string.h> 31
32 static int pointer_grabbed;
33 static XEvent menu_post_event;
35 34
36 static char 35 static char
37 xlwMenuTranslations [] = 36 xlwMenuTranslations [] =
38 "<BtnDown>: start()\n\ 37 "<BtnDown>: start()\n\
39 <BtnMotion>: drag()\n\ 38 <Motion>: drag()\n\
40 <BtnUp>: select()\n\ 39 <BtnUp>: select()\n\
41 "; 40 ";
42 41
43 #define offset(field) XtOffset(XlwMenuWidget, field) 42 #define offset(field) XtOffset(XlwMenuWidget, field)
44 static XtResource 43 static XtResource
57 {XtNverticalSpacing, XtCMargin, XtRDimension, sizeof(Dimension), 56 {XtNverticalSpacing, XtCMargin, XtRDimension, sizeof(Dimension),
58 offset(menu.vertical_spacing), XtRImmediate, (XtPointer)1}, 57 offset(menu.vertical_spacing), XtRImmediate, (XtPointer)1},
59 {XtNarrowSpacing, XtCMargin, XtRDimension, sizeof(Dimension), 58 {XtNarrowSpacing, XtCMargin, XtRDimension, sizeof(Dimension),
60 offset(menu.arrow_spacing), XtRImmediate, (XtPointer)10}, 59 offset(menu.arrow_spacing), XtRImmediate, (XtPointer)10},
61 60
62 {XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension, 61 {XmNshadowThickness, XmCShadowThickness, XtRDimension,
63 sizeof (Dimension), offset (menu.shadow_thickness), 62 sizeof (Dimension), offset (menu.shadow_thickness),
64 XtRImmediate, (XtPointer) 2}, 63 XtRImmediate, (XtPointer) 2},
65 {XmNtopShadowColor, XmCTopShadowColor, XtRPixel, sizeof (Pixel), 64 {XmNtopShadowColor, XmCTopShadowColor, XtRPixel, sizeof (Pixel),
66 offset (menu.top_shadow_color), XtRImmediate, (XtPointer)-1}, 65 offset (menu.top_shadow_color), XtRImmediate, (XtPointer)-1},
67 {XmNbottomShadowColor, XmCBottomShadowColor, XtRPixel, sizeof (Pixel), 66 {XmNbottomShadowColor, XmCBottomShadowColor, XtRPixel, sizeof (Pixel),
147 }, 146 },
148 }; 147 };
149 148
150 WidgetClass xlwMenuWidgetClass = (WidgetClass) &xlwMenuClassRec; 149 WidgetClass xlwMenuWidgetClass = (WidgetClass) &xlwMenuClassRec;
151 150
151 int submenu_destroyed;
152
153 static int next_release_must_exit;
154
152 /* Utilities */ 155 /* Utilities */
153 static void 156 static void
154 push_new_stack (XlwMenuWidget mw, widget_value* val) 157 push_new_stack (mw, val)
158 XlwMenuWidget mw;
159 widget_value* val;
155 { 160 {
156 if (!mw->menu.new_stack) 161 if (!mw->menu.new_stack)
157 { 162 {
158 mw->menu.new_stack_length = 10; 163 mw->menu.new_stack_length = 10;
159 mw->menu.new_stack = 164 mw->menu.new_stack =
169 } 174 }
170 mw->menu.new_stack [mw->menu.new_depth++] = val; 175 mw->menu.new_stack [mw->menu.new_depth++] = val;
171 } 176 }
172 177
173 static void 178 static void
174 pop_new_stack_if_no_contents (XlwMenuWidget mw) 179 pop_new_stack_if_no_contents (mw)
180 XlwMenuWidget mw;
175 { 181 {
176 if (mw->menu.new_depth) 182 if (mw->menu.new_depth)
177 { 183 {
178 if (!mw->menu.new_stack [mw->menu.new_depth - 1]->contents) 184 if (!mw->menu.new_stack [mw->menu.new_depth - 1]->contents)
179 mw->menu.new_depth -= 1; 185 mw->menu.new_depth -= 1;
180 } 186 }
181 } 187 }
182 188
183 static void 189 static void
184 make_old_stack_space (XlwMenuWidget mw, int n) 190 make_old_stack_space (mw, n)
191 XlwMenuWidget mw;
192 int n;
185 { 193 {
186 if (!mw->menu.old_stack) 194 if (!mw->menu.old_stack)
187 { 195 {
188 mw->menu.old_stack_length = 10; 196 mw->menu.old_stack_length = 10;
189 mw->menu.old_stack = 197 mw->menu.old_stack =
199 } 207 }
200 } 208 }
201 209
202 /* Size code */ 210 /* Size code */
203 static Boolean 211 static Boolean
204 all_dashes_p (char* s) 212 all_dashes_p (s)
213 char *s;
205 { 214 {
206 char* p; 215 char* p;
207 for (p = s; *p == '-'; p++); 216 for (p = s; *p == '-'; p++);
208 return !*p; 217 return !*p;
209 } 218 }
210 219
211 static int 220 int
212 string_width (XlwMenuWidget mw, char* s) 221 string_width (mw, s)
222 XlwMenuWidget mw;
223 char *s;
213 { 224 {
214 XCharStruct xcs; 225 XCharStruct xcs;
215 int drop; 226 int drop;
216 227
217 XTextExtents (mw->menu.font, s, strlen (s), &drop, &drop, &drop, &xcs); 228 XTextExtents (mw->menu.font, s, strlen (s), &drop, &drop, &drop, &xcs);
218 return xcs.width; 229 return xcs.width;
219 } 230 }
220 231
221 static int 232 static int
222 arrow_width (XlwMenuWidget mw) 233 arrow_width (mw)
234 XlwMenuWidget mw;
223 { 235 {
224 return mw->menu.font->ascent / 2 | 1; 236 return mw->menu.font->ascent / 2 | 1;
225 } 237 }
226 238
227 static XtResource 239 static XtResource
230 {"labelString", "LabelString", XtRString, sizeof(String), 242 {"labelString", "LabelString", XtRString, sizeof(String),
231 0, XtRImmediate, 0}, 243 0, XtRImmediate, 0},
232 }; 244 };
233 245
234 static char* 246 static char*
235 resource_widget_value (XlwMenuWidget mw, widget_value* val) 247 resource_widget_value (mw, val)
248 XlwMenuWidget mw;
249 widget_value *val;
236 { 250 {
237 if (!val->toolkit_data) 251 if (!val->toolkit_data)
238 { 252 {
239 char* resourced_name = NULL; 253 char* resourced_name = NULL;
240 char* complete_name; 254 char* complete_name;
266 return (char*)val->toolkit_data; 280 return (char*)val->toolkit_data;
267 } 281 }
268 282
269 /* Returns the sizes of an item */ 283 /* Returns the sizes of an item */
270 static void 284 static void
271 size_menu_item (XlwMenuWidget mw, widget_value* val, int horizontal_p, 285 size_menu_item (mw, val, horizontal_p, label_width, rest_width, height)
272 int* label_width, int* rest_width, int* height) 286 XlwMenuWidget mw;
287 widget_value* val;
288 int horizontal_p;
289 int* label_width;
290 int* rest_width;
291 int* height;
273 { 292 {
274 if (all_dashes_p (val->name)) 293 if (all_dashes_p (val->name))
275 { 294 {
276 *height = 2; 295 *height = 2;
277 *label_width = 1; 296 *label_width = 1;
298 } 317 }
299 } 318 }
300 } 319 }
301 320
302 static void 321 static void
303 size_menu (XlwMenuWidget mw, int level) 322 size_menu (mw, level)
323 XlwMenuWidget mw;
324 int level;
304 { 325 {
305 int label_width = 0; 326 int label_width = 0;
306 int rest_width = 0; 327 int rest_width = 0;
307 int max_rest_width = 0; 328 int max_rest_width = 0;
308 int height = 0; 329 int height = 0;
348 } 369 }
349 370
350 371
351 /* Display code */ 372 /* Display code */
352 static void 373 static void
353 draw_arrow (XlwMenuWidget mw, Window window, GC gc, int x, int y, int width) 374 draw_arrow (mw, window, gc, x, y, width)
375 XlwMenuWidget mw;
376 Window window;
377 GC gc;
378 int x;
379 int y;
380 int width;
354 { 381 {
355 XPoint points [3]; 382 XPoint points [3];
356 points [0].x = x; 383 points [0].x = x;
357 points [0].y = y + mw->menu.font->ascent; 384 points [0].y = y + mw->menu.font->ascent;
358 points [1].x = x; 385 points [1].x = x;
363 XFillPolygon (XtDisplay (mw), window, gc, points, 3, Convex, 390 XFillPolygon (XtDisplay (mw), window, gc, points, 3, Convex,
364 CoordModeOrigin); 391 CoordModeOrigin);
365 } 392 }
366 393
367 static void 394 static void
368 draw_shadow_rectangle (XlwMenuWidget mw, Window window, 395 draw_shadow_rectangle (mw, window, x, y, width, height, erase_p)
369 int x, int y, int width, int height, int erase_p) 396 XlwMenuWidget mw;
397 Window window;
398 int x;
399 int y;
400 int width;
401 int height;
402 int erase_p;
370 { 403 {
371 Display *dpy = XtDisplay (mw); 404 Display *dpy = XtDisplay (mw);
372 GC top_gc = !erase_p ? mw->menu.shadow_top_gc : mw->menu.background_gc; 405 GC top_gc = !erase_p ? mw->menu.shadow_top_gc : mw->menu.background_gc;
373 GC bottom_gc = !erase_p ? mw->menu.shadow_bottom_gc : mw->menu.background_gc; 406 GC bottom_gc = !erase_p ? mw->menu.shadow_bottom_gc : mw->menu.background_gc;
374 int thickness = mw->menu.shadow_thickness; 407 int thickness = mw->menu.shadow_thickness;
414 447
415 /* Display the menu item and increment where.x and where.y to show how large 448 /* Display the menu item and increment where.x and where.y to show how large
416 ** the menu item was. 449 ** the menu item was.
417 */ 450 */
418 static void 451 static void
419 display_menu_item (XlwMenuWidget mw, widget_value* val, window_state* ws, 452 display_menu_item (mw, val, ws, where, highlighted_p, horizontal_p, just_compute_p)
420 XPoint* where, Boolean highlighted_p, Boolean horizontal_p, 453 XlwMenuWidget mw;
421 Boolean just_compute_p) 454 widget_value* val;
455 window_state* ws;
456 XPoint* where;
457 Boolean highlighted_p;
458 Boolean horizontal_p;
459 Boolean just_compute_p;
422 { 460 {
423 GC deco_gc; 461 GC deco_gc;
424 GC text_gc; 462 GC text_gc;
425 int font_ascent = mw->menu.font->ascent; 463 int font_ascent = mw->menu.font->ascent;
426 int font_descent = mw->menu.font->descent; 464 int font_descent = mw->menu.font->descent;
488 { 526 {
489 if (val->contents) 527 if (val->contents)
490 { 528 {
491 int a_w = arrow_width (mw); 529 int a_w = arrow_width (mw);
492 draw_arrow (mw, ws->window, deco_gc, 530 draw_arrow (mw, ws->window, deco_gc,
493 x + label_width + mw->menu.arrow_spacing, 531 x + width - arrow_width (mw)
532 - mw->menu.horizontal_spacing
533 - mw->menu.shadow_thickness,
494 y + v_spacing + shadow, a_w); 534 y + v_spacing + shadow, a_w);
495 } 535 }
496 else if (val->key) 536 else if (val->key)
497 { 537 {
498 XDrawString (XtDisplay (mw), ws->window, text_gc, 538 XDrawString (XtDisplay (mw), ws->window, text_gc,
507 #if 1 547 #if 1
508 XDrawRectangle (XtDisplay (mw), ws->window, deco_gc, 548 XDrawRectangle (XtDisplay (mw), ws->window, deco_gc,
509 x + shadow, y + shadow, 549 x + shadow, y + shadow,
510 label_width + h_spacing - 1, 550 label_width + h_spacing - 1,
511 font_ascent + font_descent + 2 * v_spacing - 1); 551 font_ascent + font_descent + 2 * v_spacing - 1);
552 draw_shadow_rectangle (mw, ws->window, x, y, width, height,
553 False);
512 #else 554 #else
513 highlighted_p = True; 555 highlighted_p = True;
514 #endif 556 #endif
515 } 557 }
558 else
559 {
560 XDrawRectangle (XtDisplay (mw), ws->window,
561 mw->menu.background_gc,
562 x + shadow, y + shadow,
563 label_width + h_spacing - 1,
564 font_ascent + font_descent + 2 * v_spacing - 1);
565 draw_shadow_rectangle (mw, ws->window, x, y, width, height,
566 True);
567 }
516 568
517 if (highlighted_p) 569 if (highlighted_p)
518 draw_shadow_rectangle (mw, ws->window, x, y, width, height, False); 570 draw_shadow_rectangle (mw, ws->window, x, y, width, height, False);
519 } 571 }
520 } 572 }
522 where->x += width; 574 where->x += width;
523 where->y += height; 575 where->y += height;
524 } 576 }
525 577
526 static void 578 static void
527 display_menu (XlwMenuWidget mw, int level, Boolean just_compute_p, 579 display_menu (mw, level, just_compute_p, highlighted_pos, hit, hit_return,
528 XPoint* highlighted_pos, XPoint* hit, widget_value** hit_return, 580 this, that)
529 widget_value* this, widget_value* that) 581 XlwMenuWidget mw;
582 int level;
583 Boolean just_compute_p;
584 XPoint* highlighted_pos;
585 XPoint* hit;
586 widget_value** hit_return;
587 widget_value* this;
588 widget_value* that;
530 { 589 {
531 widget_value* val; 590 widget_value* val;
532 widget_value* following_item; 591 widget_value* following_item;
533 window_state* ws; 592 window_state* ws;
534 XPoint where; 593 XPoint where;
592 draw_shadow_rectangle (mw, ws->window, 0, 0, ws->width, ws->height, False); 651 draw_shadow_rectangle (mw, ws->window, 0, 0, ws->width, ws->height, False);
593 } 652 }
594 653
595 /* Motion code */ 654 /* Motion code */
596 static void 655 static void
597 set_new_state (XlwMenuWidget mw, widget_value* val, int level) 656 set_new_state (mw, val, level)
657 XlwMenuWidget mw;
658 widget_value* val;
659 int level;
598 { 660 {
599 int i; 661 int i;
600 662
601 mw->menu.new_depth = 0; 663 mw->menu.new_depth = 0;
602 for (i = 0; i < level; i++) 664 for (i = 0; i < level; i++)
603 push_new_stack (mw, mw->menu.old_stack [i]); 665 push_new_stack (mw, mw->menu.old_stack [i]);
604 push_new_stack (mw, val); 666 push_new_stack (mw, val);
605 } 667 }
606 668
607 static void 669 static void
608 make_windows_if_needed (XlwMenuWidget mw, int n) 670 make_windows_if_needed (mw, n)
671 XlwMenuWidget mw;
672 int n;
609 { 673 {
610 int i; 674 int i;
611 int start_at; 675 int start_at;
612 XSetWindowAttributes xswa; 676 XSetWindowAttributes xswa;
613 int mask; 677 int mask;
620 xswa.save_under = True; 684 xswa.save_under = True;
621 xswa.override_redirect = True; 685 xswa.override_redirect = True;
622 xswa.background_pixel = mw->core.background_pixel; 686 xswa.background_pixel = mw->core.background_pixel;
623 xswa.border_pixel = mw->core.border_pixel; 687 xswa.border_pixel = mw->core.border_pixel;
624 xswa.event_mask = 688 xswa.event_mask =
625 ExposureMask | ButtonMotionMask | PointerMotionHintMask 689 ExposureMask | PointerMotionMask | PointerMotionHintMask
626 | ButtonReleaseMask | ButtonPressMask; 690 | ButtonReleaseMask | ButtonPressMask;
627 xswa.cursor = mw->menu.cursor_shape; 691 xswa.cursor = mw->menu.cursor_shape;
628 mask = CWSaveUnder | CWOverrideRedirect | CWBackPixel | CWBorderPixel 692 mask = CWSaveUnder | CWOverrideRedirect | CWBackPixel | CWBorderPixel
629 | CWEventMask | CWCursor; 693 | CWEventMask | CWCursor;
630 694
657 } 721 }
658 } 722 }
659 723
660 /* Make the window fit in the screen */ 724 /* Make the window fit in the screen */
661 static void 725 static void
662 fit_to_screen (XlwMenuWidget mw, window_state* ws, window_state* previous_ws, 726 fit_to_screen (mw, ws, previous_ws, horizontal_p)
663 Boolean horizontal_p) 727 XlwMenuWidget mw;
728 window_state* ws;
729 window_state* previous_ws;
730 Boolean horizontal_p;
664 { 731 {
665 int screen_width = WidthOfScreen (XtScreen (mw)); 732 int screen_width = WidthOfScreen (XtScreen (mw));
666 int screen_height = HeightOfScreen (XtScreen (mw)); 733 int screen_height = HeightOfScreen (XtScreen (mw));
667 734
668 if (ws->x < 0) 735 if (ws->x < 0)
685 } 752 }
686 } 753 }
687 754
688 /* Updates old_stack from new_stack and redisplays. */ 755 /* Updates old_stack from new_stack and redisplays. */
689 static void 756 static void
690 remap_menubar (XlwMenuWidget mw) 757 remap_menubar (mw)
758 XlwMenuWidget mw;
691 { 759 {
692 int i; 760 int i;
693 int last_same; 761 int last_same;
694 XPoint selection_position; 762 XPoint selection_position;
695 int old_depth = mw->menu.old_depth; 763 int old_depth = mw->menu.old_depth;
762 if (i >= new_depth || !new_stack [i]->contents) 830 if (i >= new_depth || !new_stack [i]->contents)
763 XUnmapWindow (XtDisplay (mw), windows [i].window); 831 XUnmapWindow (XtDisplay (mw), windows [i].window);
764 } 832 }
765 833
766 static Boolean 834 static Boolean
767 motion_event_is_in_menu (XlwMenuWidget mw, XMotionEvent* ev, int level, 835 motion_event_is_in_menu (mw, ev, level, relative_pos)
768 XPoint* relative_pos) 836 XlwMenuWidget mw;
837 XMotionEvent* ev;
838 int level;
839 XPoint* relative_pos;
769 { 840 {
770 window_state* ws = &mw->menu.windows [level]; 841 window_state* ws = &mw->menu.windows [level];
771 int x = level == 0 ? ws->x : ws->x + mw->menu.shadow_thickness; 842 int x = level == 0 ? ws->x : ws->x + mw->menu.shadow_thickness;
772 int y = level == 0 ? ws->y : ws->y + mw->menu.shadow_thickness; 843 int y = level == 0 ? ws->y : ws->y + mw->menu.shadow_thickness;
773 relative_pos->x = ev->x_root - x; 844 relative_pos->x = ev->x_root - x;
775 return (x < ev->x_root && ev->x_root < x + ws->width 846 return (x < ev->x_root && ev->x_root < x + ws->width
776 && y < ev->y_root && ev->y_root < y + ws->height); 847 && y < ev->y_root && ev->y_root < y + ws->height);
777 } 848 }
778 849
779 static Boolean 850 static Boolean
780 map_event_to_widget_value (XlwMenuWidget mw, XMotionEvent* ev, 851 map_event_to_widget_value (mw, ev, val, level)
781 widget_value** val, int* level) 852 XlwMenuWidget mw;
853 XMotionEvent* ev;
854 widget_value** val;
855 int* level;
782 { 856 {
783 int i; 857 int i;
784 XPoint relative_pos; 858 XPoint relative_pos;
785 window_state* ws; 859 window_state* ws;
786 860
804 return False; 878 return False;
805 } 879 }
806 880
807 /* Procedures */ 881 /* Procedures */
808 static void 882 static void
809 make_drawing_gcs (XlwMenuWidget mw) 883 make_drawing_gcs (mw)
884 XlwMenuWidget mw;
810 { 885 {
811 XGCValues xgcv; 886 XGCValues xgcv;
812 887
813 xgcv.font = mw->menu.font->fid; 888 xgcv.font = mw->menu.font->fid;
814 xgcv.foreground = mw->menu.foreground; 889 xgcv.foreground = mw->menu.foreground;
849 GCFont | GCForeground | GCBackground, 924 GCFont | GCForeground | GCBackground,
850 &xgcv); 925 &xgcv);
851 } 926 }
852 927
853 static void 928 static void
854 release_drawing_gcs (XlwMenuWidget mw) 929 release_drawing_gcs (mw)
930 XlwMenuWidget mw;
855 { 931 {
856 XtReleaseGC ((Widget) mw, mw->menu.foreground_gc); 932 XtReleaseGC ((Widget) mw, mw->menu.foreground_gc);
857 XtReleaseGC ((Widget) mw, mw->menu.button_gc); 933 XtReleaseGC ((Widget) mw, mw->menu.button_gc);
858 XtReleaseGC ((Widget) mw, mw->menu.inactive_gc); 934 XtReleaseGC ((Widget) mw, mw->menu.inactive_gc);
859 XtReleaseGC ((Widget) mw, mw->menu.inactive_button_gc); 935 XtReleaseGC ((Widget) mw, mw->menu.inactive_button_gc);
868 944
869 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \ 945 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
870 ? ((unsigned long) (x)) : ((unsigned long) (y))) 946 ? ((unsigned long) (x)) : ((unsigned long) (y)))
871 947
872 static void 948 static void
873 make_shadow_gcs (XlwMenuWidget mw) 949 make_shadow_gcs (mw)
950 XlwMenuWidget mw;
874 { 951 {
875 XGCValues xgcv; 952 XGCValues xgcv;
876 unsigned long pm = 0; 953 unsigned long pm = 0;
877 Display *dpy = XtDisplay ((Widget) mw); 954 Display *dpy = XtDisplay ((Widget) mw);
878 Colormap cmap = DefaultColormapOfScreen (XtScreen ((Widget) mw)); 955 Colormap cmap = DefaultColormapOfScreen (XtScreen ((Widget) mw));
958 mw->menu.shadow_bottom_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv); 1035 mw->menu.shadow_bottom_gc = XtGetGC ((Widget)mw, GCForeground | pm, &xgcv);
959 } 1036 }
960 1037
961 1038
962 static void 1039 static void
963 release_shadow_gcs (XlwMenuWidget mw) 1040 release_shadow_gcs (mw)
1041 XlwMenuWidget mw;
964 { 1042 {
965 XtReleaseGC ((Widget) mw, mw->menu.shadow_top_gc); 1043 XtReleaseGC ((Widget) mw, mw->menu.shadow_top_gc);
966 XtReleaseGC ((Widget) mw, mw->menu.shadow_bottom_gc); 1044 XtReleaseGC ((Widget) mw, mw->menu.shadow_bottom_gc);
967 } 1045 }
968 1046
969 static void 1047 static void
970 XlwMenuInitialize (Widget request, Widget new, ArgList args, 1048 XlwMenuInitialize (request, new, args, num_args)
971 Cardinal *num_args) 1049 Widget request;
1050 Widget new;
1051 ArgList args;
1052 Cardinal *num_args;
972 { 1053 {
973 /* Get the GCs and the widget size */ 1054 /* Get the GCs and the widget size */
974 XlwMenuWidget mw = (XlwMenuWidget)new; 1055 XlwMenuWidget mw = (XlwMenuWidget)new;
975 1056
976 XSetWindowAttributes xswa; 1057 XSetWindowAttributes xswa;
977 int mask; 1058 int mask;
978 1059
979 Window window = RootWindowOfScreen (DefaultScreenOfDisplay (XtDisplay (mw))); 1060 Window window = RootWindowOfScreen (DefaultScreenOfDisplay (XtDisplay (mw)));
980 Display* display = XtDisplay (mw); 1061 Display* display = XtDisplay (mw);
981 1062
1063 #if 0
1064 widget_value *tem = (widget_value *) XtMalloc (sizeof (widget_value));
1065
1066 /* _XtCreate is freeing the object that was passed to us,
1067 so make a copy that we will actually keep. */
1068 lwlib_bcopy (mw->menu.contents, tem, sizeof (widget_value));
1069 mw->menu.contents = tem;
1070 #endif
1071
982 /* mw->menu.cursor = XCreateFontCursor (display, mw->menu.cursor_shape); */ 1072 /* mw->menu.cursor = XCreateFontCursor (display, mw->menu.cursor_shape); */
983 mw->menu.cursor = mw->menu.cursor_shape; 1073 mw->menu.cursor = mw->menu.cursor_shape;
984 1074
985 mw->menu.gray_pixmap = XCreatePixmapFromBitmapData (display, window, 1075 mw->menu.gray_pixmap = XCreatePixmapFromBitmapData (display, window,
986 gray_bits, gray_width, 1076 gray_bits, gray_width,
1021 XlwMenuClassInitialize () 1111 XlwMenuClassInitialize ()
1022 { 1112 {
1023 } 1113 }
1024 1114
1025 static void 1115 static void
1026 XlwMenuRealize (Widget w, Mask *valueMask, XSetWindowAttributes *attributes) 1116 XlwMenuRealize (w, valueMask, attributes)
1117 Widget w;
1118 Mask *valueMask;
1119 XSetWindowAttributes *attributes;
1027 { 1120 {
1028 XlwMenuWidget mw = (XlwMenuWidget)w; 1121 XlwMenuWidget mw = (XlwMenuWidget)w;
1029 XSetWindowAttributes xswa; 1122 XSetWindowAttributes xswa;
1030 int mask; 1123 int mask;
1031 1124
1046 1139
1047 /* Only the toplevel menubar/popup is a widget so it's the only one that 1140 /* Only the toplevel menubar/popup is a widget so it's the only one that
1048 receives expose events through Xt. So we repaint all the other panes 1141 receives expose events through Xt. So we repaint all the other panes
1049 when receiving an Expose event. */ 1142 when receiving an Expose event. */
1050 static void 1143 static void
1051 XlwMenuRedisplay (Widget w, XEvent* ev, Region region) 1144 XlwMenuRedisplay (w, ev, region)
1145 Widget w;
1146 XEvent* ev;
1147 Region region;
1052 { 1148 {
1053 XlwMenuWidget mw = (XlwMenuWidget)w; 1149 XlwMenuWidget mw = (XlwMenuWidget)w;
1054 int i; 1150 int i;
1055 1151
1152 /* If we have a depth beyond 1, it's because a submenu was displayed.
1153 If the submenu has been destroyed, set the depth back to 1. */
1154 if (submenu_destroyed)
1155 {
1156 mw->menu.old_depth = 1;
1157 submenu_destroyed = 0;
1158 }
1159
1056 for (i = 0; i < mw->menu.old_depth; i++) 1160 for (i = 0; i < mw->menu.old_depth; i++)
1057 display_menu (mw, i, False, NULL, NULL, NULL, NULL, NULL); 1161 display_menu (mw, i, False, NULL, NULL, NULL, NULL, NULL);
1058 } 1162 }
1059 1163
1060 static void 1164 static void
1061 XlwMenuDestroy (Widget w) 1165 XlwMenuDestroy (w)
1166 Widget w;
1062 { 1167 {
1063 int i; 1168 int i;
1064 XlwMenuWidget mw = (XlwMenuWidget) w; 1169 XlwMenuWidget mw = (XlwMenuWidget) w;
1170
1171 if (pointer_grabbed)
1172 XtUngrabPointer ((Widget)w, CurrentTime);
1173 pointer_grabbed = 0;
1174
1175 submenu_destroyed = 1;
1065 1176
1066 release_drawing_gcs (mw); 1177 release_drawing_gcs (mw);
1067 release_shadow_gcs (mw); 1178 release_shadow_gcs (mw);
1068 1179
1069 /* this doesn't come from the resource db but is created explicitly 1180 /* this doesn't come from the resource db but is created explicitly
1070 so we must free it ourselves. */ 1181 so we must free it ourselves. */
1071 XFreePixmap (XtDisplay (mw), mw->menu.gray_pixmap); 1182 XFreePixmap (XtDisplay (mw), mw->menu.gray_pixmap);
1072 mw->menu.gray_pixmap = (Pixmap) -1; 1183 mw->menu.gray_pixmap = (Pixmap) -1;
1184
1185 #if 0
1186 /* Do free mw->menu.contents because nowadays we copy it
1187 during initialization. */
1188 XtFree (mw->menu.contents);
1189 #endif
1073 1190
1074 /* Don't free mw->menu.contents because that comes from our creator. 1191 /* Don't free mw->menu.contents because that comes from our creator.
1075 The `*_stack' elements are just pointers into `contents' so leave 1192 The `*_stack' elements are just pointers into `contents' so leave
1076 that alone too. But free the stacks themselves. */ 1193 that alone too. But free the stacks themselves. */
1077 if (mw->menu.old_stack) XtFree ((char *) mw->menu.old_stack); 1194 if (mw->menu.old_stack) XtFree ((char *) mw->menu.old_stack);
1094 if (mw->menu.windows) 1211 if (mw->menu.windows)
1095 XtFree ((char *) mw->menu.windows); 1212 XtFree ((char *) mw->menu.windows);
1096 } 1213 }
1097 1214
1098 static Boolean 1215 static Boolean
1099 XlwMenuSetValues (Widget current, Widget request, Widget new) 1216 XlwMenuSetValues (current, request, new)
1217 Widget current;
1218 Widget request;
1219 Widget new;
1100 { 1220 {
1101 XlwMenuWidget oldmw = (XlwMenuWidget)current; 1221 XlwMenuWidget oldmw = (XlwMenuWidget)current;
1102 XlwMenuWidget newmw = (XlwMenuWidget)new; 1222 XlwMenuWidget newmw = (XlwMenuWidget)new;
1103 Boolean redisplay = False; 1223 Boolean redisplay = False;
1104 int i; 1224 int i;
1107 && newmw->menu.contents->contents 1227 && newmw->menu.contents->contents
1108 && newmw->menu.contents->contents->change >= VISIBLE_CHANGE) 1228 && newmw->menu.contents->contents->change >= VISIBLE_CHANGE)
1109 redisplay = True; 1229 redisplay = True;
1110 1230
1111 if (newmw->core.background_pixel != oldmw->core.background_pixel 1231 if (newmw->core.background_pixel != oldmw->core.background_pixel
1112 || newmw->menu.foreground != oldmw->menu.foreground) 1232 || newmw->menu.foreground != oldmw->menu.foreground
1233 || newmw->menu.font != oldmw->menu.font)
1113 { 1234 {
1114 release_drawing_gcs (newmw); 1235 release_drawing_gcs (newmw);
1115 make_drawing_gcs (newmw); 1236 make_drawing_gcs (newmw);
1116 redisplay = True; 1237 redisplay = True;
1117 1238
1128 1249
1129 return redisplay; 1250 return redisplay;
1130 } 1251 }
1131 1252
1132 static void 1253 static void
1133 XlwMenuResize (Widget w) 1254 XlwMenuResize (w)
1255 Widget w;
1134 { 1256 {
1135 XlwMenuWidget mw = (XlwMenuWidget)w; 1257 XlwMenuWidget mw = (XlwMenuWidget)w;
1136 1258
1137 mw->menu.windows [0].width = mw->core.width; 1259 if (mw->menu.popped_up)
1138 mw->menu.windows [0].height = mw->core.height; 1260 {
1261 /* Don't allow the popup menu to resize itself. */
1262 mw->core.width = mw->menu.windows [0].width;
1263 mw->core.height = mw->menu.windows [0].height;
1264 mw->core.parent->core.width = mw->core.width ;
1265 mw->core.parent->core.height = mw->core.height ;
1266 }
1267 else
1268 {
1269 mw->menu.windows [0].width = mw->core.width;
1270 mw->menu.windows [0].height = mw->core.height;
1271 }
1139 } 1272 }
1140 1273
1141 /* Action procedures */ 1274 /* Action procedures */
1142 static void 1275 static void
1143 handle_single_motion_event (XlwMenuWidget mw, XMotionEvent* ev) 1276 handle_single_motion_event (mw, ev)
1277 XlwMenuWidget mw;
1278 XMotionEvent* ev;
1144 { 1279 {
1145 widget_value* val; 1280 widget_value* val;
1146 int level; 1281 int level;
1147 1282
1148 if (!map_event_to_widget_value (mw, ev, &val, &level)) 1283 if (!map_event_to_widget_value (mw, ev, &val, &level))
1149 pop_new_stack_if_no_contents (mw); 1284 pop_new_stack_if_no_contents (mw);
1150 else 1285 else
1151 set_new_state (mw, val, level); 1286 set_new_state (mw, val, level);
1152 remap_menubar (mw); 1287 remap_menubar (mw);
1153 1288
1289 #if 0
1154 /* Sync with the display. Makes it feel better on X terms. */ 1290 /* Sync with the display. Makes it feel better on X terms. */
1155 XSync (XtDisplay (mw), False); 1291 XSync (XtDisplay (mw), False);
1156 } 1292 #endif
1157 1293 }
1158 static void 1294
1159 handle_motion_event (XlwMenuWidget mw, XMotionEvent* ev) 1295 static void
1296 handle_motion_event (mw, ev)
1297 XlwMenuWidget mw;
1298 XMotionEvent* ev;
1160 { 1299 {
1161 int x = ev->x_root; 1300 int x = ev->x_root;
1162 int y = ev->y_root; 1301 int y = ev->y_root;
1163 int state = ev->state; 1302 int state = ev->state;
1164 1303
1175 && (ev->x_root != x || ev->y_root != y)) 1314 && (ev->x_root != x || ev->y_root != y))
1176 handle_single_motion_event (mw, ev); 1315 handle_single_motion_event (mw, ev);
1177 } 1316 }
1178 1317
1179 static void 1318 static void
1180 Start (Widget w, XEvent *ev, String *params, Cardinal *num_params) 1319 Start (w, ev, params, num_params)
1320 Widget w;
1321 XEvent *ev;
1322 String *params;
1323 Cardinal *num_params;
1181 { 1324 {
1182 XlwMenuWidget mw = (XlwMenuWidget)w; 1325 XlwMenuWidget mw = (XlwMenuWidget)w;
1183 1326
1327 if (!mw->menu.popped_up)
1328 {
1329 menu_post_event = *ev;
1330 pop_up_menu (mw, ev);
1331 }
1332 else
1333 /* If we push a button while the menu is posted semipermanently,
1334 releasing the button should always pop the menu down. */
1335 next_release_must_exit = 1;
1336
1337 #if 0
1184 XtCallCallbackList ((Widget)mw, mw->menu.open, NULL); 1338 XtCallCallbackList ((Widget)mw, mw->menu.open, NULL);
1185 1339
1186 /* notes the absolute position of the menubar window */ 1340 /* notes the absolute position of the menubar window */
1187 mw->menu.windows [0].x = ev->xmotion.x_root - ev->xmotion.x; 1341 mw->menu.windows [0].x = ev->xmotion.x_root - ev->xmotion.x;
1188 mw->menu.windows [0].y = ev->xmotion.y_root - ev->xmotion.y; 1342 mw->menu.windows [0].y = ev->xmotion.y_root - ev->xmotion.y;
1189 1343
1190 /* handles the down like a move, slots are compatible */ 1344 /* handles the down like a move, slots are compatible */
1191 handle_motion_event (mw, &ev->xmotion); 1345 handle_motion_event (mw, &ev->xmotion);
1346 #endif
1347
1192 } 1348 }
1193 1349
1194 static void 1350 static void
1195 Drag (Widget w, XEvent *ev, String *params, Cardinal *num_params) 1351 Drag (w, ev, params, num_params)
1352 Widget w;
1353 XEvent *ev;
1354 String *params;
1355 Cardinal *num_params;
1196 { 1356 {
1197 XlwMenuWidget mw = (XlwMenuWidget)w; 1357 XlwMenuWidget mw = (XlwMenuWidget)w;
1198 handle_motion_event (mw, &ev->xmotion); 1358 handle_motion_event (mw, &ev->xmotion);
1199 } 1359 }
1200 1360
1201 static void 1361 static void
1202 Select (Widget w, XEvent *ev, String *params, Cardinal *num_params) 1362 Select (w, ev, params, num_params)
1363 Widget w;
1364 XEvent *ev;
1365 String *params;
1366 Cardinal *num_params;
1203 { 1367 {
1204 XlwMenuWidget mw = (XlwMenuWidget)w; 1368 XlwMenuWidget mw = (XlwMenuWidget)w;
1205 widget_value* selected_item = mw->menu.old_stack [mw->menu.old_depth - 1]; 1369 widget_value* selected_item = mw->menu.old_stack [mw->menu.old_depth - 1];
1206 1370
1207 /* pop down everything */ 1371 /* If user releases the button quickly, without selecting anything,
1372 after the initial down-click that brought the menu up,
1373 do nothing. */
1374 if ((selected_item == 0
1375 || ((widget_value *) selected_item)->call_data == 0)
1376 && !next_release_must_exit
1377 && (ev->xbutton.time - menu_post_event.xbutton.time
1378 < XtGetMultiClickTime (XtDisplay (w))))
1379 return;
1380
1381 /* pop down everything. */
1208 mw->menu.new_depth = 1; 1382 mw->menu.new_depth = 1;
1209 remap_menubar (mw); 1383 remap_menubar (mw);
1210 1384
1211 if (mw->menu.popped_up) 1385 if (mw->menu.popped_up)
1212 { 1386 {
1221 } 1395 }
1222 1396
1223 1397
1224 /* Special code to pop-up a menu */ 1398 /* Special code to pop-up a menu */
1225 void 1399 void
1226 pop_up_menu (XlwMenuWidget mw, XButtonPressedEvent* event) 1400 pop_up_menu (mw, event)
1401 XlwMenuWidget mw;
1402 XButtonPressedEvent* event;
1227 { 1403 {
1228 int x = event->x_root; 1404 int x = event->x_root;
1229 int y = event->y_root; 1405 int y = event->y_root;
1230 int w; 1406 int w;
1231 int h; 1407 int h;
1232 int borderwidth = mw->menu.shadow_thickness; 1408 int borderwidth = mw->menu.shadow_thickness;
1233 Screen* screen = XtScreen (mw); 1409 Screen* screen = XtScreen (mw);
1410
1411 next_release_must_exit = 0;
1234 1412
1235 XtCallCallbackList ((Widget)mw, mw->menu.open, NULL); 1413 XtCallCallbackList ((Widget)mw, mw->menu.open, NULL);
1236 1414
1237 size_menu (mw, 0); 1415 size_menu (mw, 0);
1238 1416
1253 mw->menu.popped_up = True; 1431 mw->menu.popped_up = True;
1254 XtConfigureWidget (XtParent (mw), x, y, w, h, 1432 XtConfigureWidget (XtParent (mw), x, y, w, h,
1255 XtParent (mw)->core.border_width); 1433 XtParent (mw)->core.border_width);
1256 XtPopup (XtParent (mw), XtGrabExclusive); 1434 XtPopup (XtParent (mw), XtGrabExclusive);
1257 display_menu (mw, 0, False, NULL, NULL, NULL, NULL, NULL); 1435 display_menu (mw, 0, False, NULL, NULL, NULL, NULL, NULL);
1436 #ifdef emacs
1437 x_catch_errors ();
1438 #endif
1258 XtGrabPointer ((Widget)mw, False, 1439 XtGrabPointer ((Widget)mw, False,
1259 (ButtonMotionMask | PointerMotionHintMask | ButtonReleaseMask 1440 (PointerMotionMask | PointerMotionHintMask | ButtonReleaseMask
1260 | ButtonPressMask), 1441 | ButtonPressMask),
1261 GrabModeAsync, GrabModeAsync, None, mw->menu.cursor_shape, 1442 GrabModeAsync, GrabModeAsync, None, mw->menu.cursor_shape,
1262 event->time); 1443 event->time);
1444 pointer_grabbed = 1;
1445 #ifdef emacs
1446 if (x_had_errors_p ())
1447 {
1448 pointer_grabbed = 0;
1449 XtUngrabPointer ((Widget)mw, event->time);
1450 }
1451 x_uncatch_errors ();
1452 #endif
1263 1453
1264 mw->menu.windows [0].x = x + borderwidth; 1454 mw->menu.windows [0].x = x + borderwidth;
1265 mw->menu.windows [0].y = y + borderwidth; 1455 mw->menu.windows [0].y = y + borderwidth;
1266 1456
1267 handle_motion_event (mw, (XMotionEvent*)event); 1457 handle_motion_event (mw, (XMotionEvent*)event);