Mercurial > emacs
comparison src/xmenu.c @ 88155:d7ddb3e565de
sync with trunk
author | Henrik Enberg <henrik.enberg@telia.com> |
---|---|
date | Mon, 16 Jan 2006 00:03:54 +0000 |
parents | 05ebf4266798 |
children |
comparison
equal
deleted
inserted
replaced
88154:8ce476d3ba36 | 88155:d7ddb3e565de |
---|---|
1 /* X Communication module for terminals which understand the X protocol. | 1 /* X Communication module for terminals which understand the X protocol. |
2 Copyright (C) 1986, 88, 93, 94, 96, 99, 2000, 2001 | 2 Copyright (C) 1986, 1988, 1993, 1994, 1996, 1999, 2000, 2001, 2002, 2003, |
3 Free Software Foundation, Inc. | 3 2004, 2005 Free Software Foundation, Inc. |
4 | 4 |
5 This file is part of GNU Emacs. | 5 This file is part of GNU Emacs. |
6 | 6 |
7 GNU Emacs is free software; you can redistribute it and/or modify | 7 GNU Emacs is free software; you can redistribute it and/or modify |
8 it under the terms of the GNU General Public License as published by | 8 it under the terms of the GNU General Public License as published by |
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 GNU General Public License for more details. | 15 GNU General Public License for more details. |
16 | 16 |
17 You should have received a copy of the GNU General Public License | 17 You should have received a copy of the GNU General Public License |
18 along with GNU Emacs; see the file COPYING. If not, write to | 18 along with GNU Emacs; see the file COPYING. If not, write to |
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
20 Boston, MA 02111-1307, USA. */ | 20 Boston, MA 02110-1301, USA. */ |
21 | 21 |
22 /* X pop-up deck-of-cards menu facility for GNU Emacs. | 22 /* X pop-up deck-of-cards menu facility for GNU Emacs. |
23 * | 23 * |
24 * Written by Jon Arnold and Roman Budzianowski | 24 * Written by Jon Arnold and Roman Budzianowski |
25 * Mods and rewrite by Robert Krawitz | 25 * Mods and rewrite by Robert Krawitz |
31 | 31 |
32 /* Rewritten for clarity and GC protection by rms in Feb 94. */ | 32 /* Rewritten for clarity and GC protection by rms in Feb 94. */ |
33 | 33 |
34 #include <config.h> | 34 #include <config.h> |
35 | 35 |
36 #if 0 /* Why was this included? And without syssignal.h? */ | |
36 /* On 4.3 this loses if it comes after xterm.h. */ | 37 /* On 4.3 this loses if it comes after xterm.h. */ |
37 #include <signal.h> | 38 #include <signal.h> |
39 #endif | |
38 | 40 |
39 #include <stdio.h> | 41 #include <stdio.h> |
40 | 42 |
41 #include "lisp.h" | 43 #include "lisp.h" |
42 #include "termhooks.h" | 44 #include "termhooks.h" |
46 #include "window.h" | 48 #include "window.h" |
47 #include "blockinput.h" | 49 #include "blockinput.h" |
48 #include "buffer.h" | 50 #include "buffer.h" |
49 #include "charset.h" | 51 #include "charset.h" |
50 #include "coding.h" | 52 #include "coding.h" |
53 #include "sysselect.h" | |
51 | 54 |
52 #ifdef MSDOS | 55 #ifdef MSDOS |
53 #include "msdos.h" | 56 #include "msdos.h" |
54 #endif | 57 #endif |
55 | 58 |
66 #endif | 69 #endif |
67 | 70 |
68 #include "dispextern.h" | 71 #include "dispextern.h" |
69 | 72 |
70 #ifdef HAVE_X_WINDOWS | 73 #ifdef HAVE_X_WINDOWS |
74 /* Defining HAVE_MULTILINGUAL_MENU would mean that the toolkit menu | |
75 code accepts the Emacs internal encoding. */ | |
71 #undef HAVE_MULTILINGUAL_MENU | 76 #undef HAVE_MULTILINGUAL_MENU |
72 #ifdef USE_X_TOOLKIT | 77 #ifdef USE_X_TOOLKIT |
73 #include "widget.h" | 78 #include "widget.h" |
74 #include <X11/Xlib.h> | 79 #include <X11/Xlib.h> |
75 #include <X11/IntrinsicP.h> | 80 #include <X11/IntrinsicP.h> |
95 Lisp_Object Vmenu_updating_frame; | 100 Lisp_Object Vmenu_updating_frame; |
96 | 101 |
97 Lisp_Object Qdebug_on_next_call; | 102 Lisp_Object Qdebug_on_next_call; |
98 | 103 |
99 extern Lisp_Object Qmenu_bar; | 104 extern Lisp_Object Qmenu_bar; |
100 extern Lisp_Object Qmouse_click, Qevent_kind; | |
101 | 105 |
102 extern Lisp_Object QCtoggle, QCradio; | 106 extern Lisp_Object QCtoggle, QCradio; |
103 | 107 |
104 extern Lisp_Object Voverriding_local_map; | 108 extern Lisp_Object Voverriding_local_map; |
105 extern Lisp_Object Voverriding_local_map_menu_flag; | 109 extern Lisp_Object Voverriding_local_map_menu_flag; |
107 extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map; | 111 extern Lisp_Object Qoverriding_local_map, Qoverriding_terminal_local_map; |
108 | 112 |
109 extern Lisp_Object Qmenu_bar_update_hook; | 113 extern Lisp_Object Qmenu_bar_update_hook; |
110 | 114 |
111 #ifdef USE_X_TOOLKIT | 115 #ifdef USE_X_TOOLKIT |
112 extern void set_frame_menubar (); | 116 extern void set_frame_menubar P_ ((FRAME_PTR, int, int)); |
113 extern XtAppContext Xt_app_con; | 117 extern XtAppContext Xt_app_con; |
114 | 118 |
115 static Lisp_Object xdialog_show (); | 119 static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object, |
116 static void popup_get_selection (); | 120 char **)); |
121 static void popup_get_selection P_ ((XEvent *, struct x_display_info *, | |
122 LWLIB_ID, int)); | |
117 | 123 |
118 /* Define HAVE_BOXES if menus can handle radio and toggle buttons. */ | 124 /* Define HAVE_BOXES if menus can handle radio and toggle buttons. */ |
119 | 125 |
120 #define HAVE_BOXES 1 | 126 #define HAVE_BOXES 1 |
121 #endif /* USE_X_TOOLKIT */ | 127 #endif /* USE_X_TOOLKIT */ |
122 | 128 |
123 #ifdef USE_GTK | 129 #ifdef USE_GTK |
124 #include "gtkutil.h" | 130 #include "gtkutil.h" |
125 #define HAVE_BOXES 1 | 131 #define HAVE_BOXES 1 |
126 extern void set_frame_menubar (); | 132 extern void set_frame_menubar P_ ((FRAME_PTR, int, int)); |
127 static Lisp_Object xdialog_show (); | 133 static Lisp_Object xdialog_show P_ ((FRAME_PTR, int, Lisp_Object, Lisp_Object, |
134 char **)); | |
135 #endif | |
136 | |
137 /* This is how to deal with multibyte text if HAVE_MULTILINGUAL_MENU | |
138 isn't defined. The use of HAVE_MULTILINGUAL_MENU could probably be | |
139 confined to an extended version of this with sections of code below | |
140 using it unconditionally. */ | |
141 #ifdef USE_GTK | |
142 /* gtk just uses utf-8. */ | |
143 # define ENCODE_MENU_STRING(str) ENCODE_UTF_8 (str) | |
144 #elif defined HAVE_X_I18N | |
145 # define ENCODE_MENU_STRING(str) ENCODE_SYSTEM (str) | |
146 #else | |
147 # define ENCODE_MENU_STRING(str) string_make_unibyte (str) | |
128 #endif | 148 #endif |
129 | 149 |
130 static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object, | 150 static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object, |
131 Lisp_Object, Lisp_Object, Lisp_Object, | 151 Lisp_Object, Lisp_Object, Lisp_Object, |
132 Lisp_Object, Lisp_Object)); | 152 Lisp_Object, Lisp_Object)); |
134 static Lisp_Object xmenu_show P_ ((struct frame *, int, int, int, int, | 154 static Lisp_Object xmenu_show P_ ((struct frame *, int, int, int, int, |
135 Lisp_Object, char **)); | 155 Lisp_Object, char **)); |
136 static void keymap_panes P_ ((Lisp_Object *, int, int)); | 156 static void keymap_panes P_ ((Lisp_Object *, int, int)); |
137 static void single_keymap_panes P_ ((Lisp_Object, Lisp_Object, Lisp_Object, | 157 static void single_keymap_panes P_ ((Lisp_Object, Lisp_Object, Lisp_Object, |
138 int, int)); | 158 int, int)); |
139 static void single_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object *, | |
140 int, int, int *)); | |
141 static void list_of_panes P_ ((Lisp_Object)); | 159 static void list_of_panes P_ ((Lisp_Object)); |
142 static void list_of_items P_ ((Lisp_Object)); | 160 static void list_of_items P_ ((Lisp_Object)); |
143 | 161 |
144 extern EMACS_TIME timer_check P_ ((int)); | |
145 | 162 |
146 /* This holds a Lisp vector that holds the results of decoding | 163 /* This holds a Lisp vector that holds the results of decoding |
147 the keymaps or alist-of-alists that specify a menu. | 164 the keymaps or alist-of-alists that specify a menu. |
148 | 165 |
149 It describes the panes and items within the panes. | 166 It describes the panes and items within the panes. |
270 { | 287 { |
271 } | 288 } |
272 | 289 |
273 static Lisp_Object | 290 static Lisp_Object |
274 unuse_menu_items (dummy) | 291 unuse_menu_items (dummy) |
275 int dummy; | 292 Lisp_Object dummy; |
276 { | 293 { |
277 return menu_items_inuse = Qnil; | 294 return menu_items_inuse = Qnil; |
278 } | 295 } |
279 | 296 |
280 /* Call when finished using the data for the current menu | 297 /* Call when finished using the data for the current menu |
408 Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10); | 425 Fkeymap_prompt (keymaps[mapno]), Qnil, notreal, 10); |
409 | 426 |
410 finish_menu_items (); | 427 finish_menu_items (); |
411 } | 428 } |
412 | 429 |
430 /* Args passed between single_keymap_panes and single_menu_item. */ | |
431 struct skp | |
432 { | |
433 Lisp_Object pending_maps; | |
434 int maxdepth, notreal; | |
435 int notbuttons; | |
436 }; | |
437 | |
438 static void single_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object, | |
439 void *)); | |
440 | |
413 /* This is a recursive subroutine of keymap_panes. | 441 /* This is a recursive subroutine of keymap_panes. |
414 It handles one keymap, KEYMAP. | 442 It handles one keymap, KEYMAP. |
415 The other arguments are passed along | 443 The other arguments are passed along |
416 or point to local variables of the previous function. | 444 or point to local variables of the previous function. |
417 If NOTREAL is nonzero, only check for equivalent key bindings, don't | 445 If NOTREAL is nonzero, only check for equivalent key bindings, don't |
425 Lisp_Object pane_name; | 453 Lisp_Object pane_name; |
426 Lisp_Object prefix; | 454 Lisp_Object prefix; |
427 int notreal; | 455 int notreal; |
428 int maxdepth; | 456 int maxdepth; |
429 { | 457 { |
430 Lisp_Object pending_maps = Qnil; | 458 struct skp skp; |
431 Lisp_Object tail, item; | 459 struct gcpro gcpro1; |
432 struct gcpro gcpro1, gcpro2; | 460 |
433 int notbuttons = 0; | 461 skp.pending_maps = Qnil; |
462 skp.maxdepth = maxdepth; | |
463 skp.notreal = notreal; | |
464 skp.notbuttons = 0; | |
434 | 465 |
435 if (maxdepth <= 0) | 466 if (maxdepth <= 0) |
436 return; | 467 return; |
437 | 468 |
438 push_menu_pane (pane_name, prefix); | 469 push_menu_pane (pane_name, prefix); |
440 #ifndef HAVE_BOXES | 471 #ifndef HAVE_BOXES |
441 /* Remember index for first item in this pane so we can go back and | 472 /* Remember index for first item in this pane so we can go back and |
442 add a prefix when (if) we see the first button. After that, notbuttons | 473 add a prefix when (if) we see the first button. After that, notbuttons |
443 is set to 0, to mark that we have seen a button and all non button | 474 is set to 0, to mark that we have seen a button and all non button |
444 items need a prefix. */ | 475 items need a prefix. */ |
445 notbuttons = menu_items_used; | 476 skp.notbuttons = menu_items_used; |
446 #endif | 477 #endif |
447 | 478 |
448 for (tail = keymap; CONSP (tail); tail = XCDR (tail)) | 479 GCPRO1 (skp.pending_maps); |
449 { | 480 map_keymap (keymap, single_menu_item, Qnil, &skp, 1); |
450 GCPRO2 (keymap, pending_maps); | 481 UNGCPRO; |
451 /* Look at each key binding, and if it is a menu item add it | |
452 to this menu. */ | |
453 item = XCAR (tail); | |
454 if (CONSP (item)) | |
455 single_menu_item (XCAR (item), XCDR (item), | |
456 &pending_maps, notreal, maxdepth, ¬buttons); | |
457 else if (VECTORP (item)) | |
458 { | |
459 /* Loop over the char values represented in the vector. */ | |
460 int len = XVECTOR (item)->size; | |
461 int c; | |
462 for (c = 0; c < len; c++) | |
463 { | |
464 Lisp_Object character; | |
465 XSETFASTINT (character, c); | |
466 single_menu_item (character, XVECTOR (item)->contents[c], | |
467 &pending_maps, notreal, maxdepth, ¬buttons); | |
468 } | |
469 } | |
470 UNGCPRO; | |
471 } | |
472 | 482 |
473 /* Process now any submenus which want to be panes at this level. */ | 483 /* Process now any submenus which want to be panes at this level. */ |
474 while (!NILP (pending_maps)) | 484 while (CONSP (skp.pending_maps)) |
475 { | 485 { |
476 Lisp_Object elt, eltcdr, string; | 486 Lisp_Object elt, eltcdr, string; |
477 elt = Fcar (pending_maps); | 487 elt = XCAR (skp.pending_maps); |
478 eltcdr = XCDR (elt); | 488 eltcdr = XCDR (elt); |
479 string = XCAR (eltcdr); | 489 string = XCAR (eltcdr); |
480 /* We no longer discard the @ from the beginning of the string here. | 490 /* We no longer discard the @ from the beginning of the string here. |
481 Instead, we do this in xmenu_show. */ | 491 Instead, we do this in xmenu_show. */ |
482 single_keymap_panes (Fcar (elt), string, | 492 single_keymap_panes (Fcar (elt), string, |
483 XCDR (eltcdr), notreal, maxdepth - 1); | 493 XCDR (eltcdr), notreal, maxdepth - 1); |
484 pending_maps = Fcdr (pending_maps); | 494 skp.pending_maps = XCDR (skp.pending_maps); |
485 } | 495 } |
486 } | 496 } |
487 | 497 |
488 /* This is a subroutine of single_keymap_panes that handles one | 498 /* This is a subroutine of single_keymap_panes that handles one |
489 keymap entry. | 499 keymap entry. |
490 KEY is a key in a keymap and ITEM is its binding. | 500 KEY is a key in a keymap and ITEM is its binding. |
491 PENDING_MAPS_PTR points to a list of keymaps waiting to be made into | 501 SKP->PENDING_MAPS_PTR is a list of keymaps waiting to be made into |
492 separate panes. | 502 separate panes. |
493 If NOTREAL is nonzero, only check for equivalent key bindings, don't | 503 If SKP->NOTREAL is nonzero, only check for equivalent key bindings, don't |
494 evaluate expressions in menu items and don't make any menu. | 504 evaluate expressions in menu items and don't make any menu. |
495 If we encounter submenus deeper than MAXDEPTH levels, ignore them. | 505 If we encounter submenus deeper than SKP->MAXDEPTH levels, ignore them. |
496 NOTBUTTONS_PTR is only used when simulating toggle boxes and radio | 506 SKP->NOTBUTTONS is only used when simulating toggle boxes and radio |
497 buttons. It points to variable notbuttons in single_keymap_panes, | 507 buttons. It keeps track of if we have seen a button in this menu or |
498 which keeps track of if we have seen a button in this menu or not. */ | 508 not. */ |
499 | 509 |
500 static void | 510 static void |
501 single_menu_item (key, item, pending_maps_ptr, notreal, maxdepth, | 511 single_menu_item (key, item, dummy, skp_v) |
502 notbuttons_ptr) | 512 Lisp_Object key, item, dummy; |
503 Lisp_Object key, item; | 513 void *skp_v; |
504 Lisp_Object *pending_maps_ptr; | |
505 int maxdepth, notreal; | |
506 int *notbuttons_ptr; | |
507 { | 514 { |
508 Lisp_Object map, item_string, enabled; | 515 Lisp_Object map, item_string, enabled; |
509 struct gcpro gcpro1, gcpro2; | 516 struct gcpro gcpro1, gcpro2; |
510 int res; | 517 int res; |
518 struct skp *skp = skp_v; | |
511 | 519 |
512 /* Parse the menu item and leave the result in item_properties. */ | 520 /* Parse the menu item and leave the result in item_properties. */ |
513 GCPRO2 (key, item); | 521 GCPRO2 (key, item); |
514 res = parse_menu_item (item, notreal, 0); | 522 res = parse_menu_item (item, skp->notreal, 0); |
515 UNGCPRO; | 523 UNGCPRO; |
516 if (!res) | 524 if (!res) |
517 return; /* Not a menu item. */ | 525 return; /* Not a menu item. */ |
518 | 526 |
519 map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP]; | 527 map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP]; |
520 | 528 |
521 if (notreal) | 529 if (skp->notreal) |
522 { | 530 { |
523 /* We don't want to make a menu, just traverse the keymaps to | 531 /* We don't want to make a menu, just traverse the keymaps to |
524 precompute equivalent key bindings. */ | 532 precompute equivalent key bindings. */ |
525 if (!NILP (map)) | 533 if (!NILP (map)) |
526 single_keymap_panes (map, Qnil, key, 1, maxdepth - 1); | 534 single_keymap_panes (map, Qnil, key, 1, skp->maxdepth - 1); |
527 return; | 535 return; |
528 } | 536 } |
529 | 537 |
530 enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE]; | 538 enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE]; |
531 item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME]; | 539 item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME]; |
532 | 540 |
533 if (!NILP (map) && SREF (item_string, 0) == '@') | 541 if (!NILP (map) && SREF (item_string, 0) == '@') |
534 { | 542 { |
535 if (!NILP (enabled)) | 543 if (!NILP (enabled)) |
536 /* An enabled separate pane. Remember this to handle it later. */ | 544 /* An enabled separate pane. Remember this to handle it later. */ |
537 *pending_maps_ptr = Fcons (Fcons (map, Fcons (item_string, key)), | 545 skp->pending_maps = Fcons (Fcons (map, Fcons (item_string, key)), |
538 *pending_maps_ptr); | 546 skp->pending_maps); |
539 return; | 547 return; |
540 } | 548 } |
541 | 549 |
542 #ifndef HAVE_BOXES | 550 #ifndef HAVE_BOXES |
543 /* Simulate radio buttons and toggle boxes by putting a prefix in | 551 /* Simulate radio buttons and toggle boxes by putting a prefix in |
548 if (!NILP (type)) | 556 if (!NILP (type)) |
549 { | 557 { |
550 Lisp_Object selected | 558 Lisp_Object selected |
551 = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED]; | 559 = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED]; |
552 | 560 |
553 if (*notbuttons_ptr) | 561 if (skp->notbuttons) |
554 /* The first button. Line up previous items in this menu. */ | 562 /* The first button. Line up previous items in this menu. */ |
555 { | 563 { |
556 int index = *notbuttons_ptr; /* Index for first item this menu. */ | 564 int index = skp->notbuttons; /* Index for first item this menu. */ |
557 int submenu = 0; | 565 int submenu = 0; |
558 Lisp_Object tem; | 566 Lisp_Object tem; |
559 while (index < menu_items_used) | 567 while (index < menu_items_used) |
560 { | 568 { |
561 tem | 569 tem |
581 XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME] | 589 XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME] |
582 = concat2 (build_string (" "), tem); | 590 = concat2 (build_string (" "), tem); |
583 index += MENU_ITEMS_ITEM_LENGTH; | 591 index += MENU_ITEMS_ITEM_LENGTH; |
584 } | 592 } |
585 } | 593 } |
586 *notbuttons_ptr = 0; | 594 skp->notbuttons = 0; |
587 } | 595 } |
588 | 596 |
589 /* Calculate prefix, if any, for this item. */ | 597 /* Calculate prefix, if any, for this item. */ |
590 if (EQ (type, QCtoggle)) | 598 if (EQ (type, QCtoggle)) |
591 prefix = build_string (NILP (selected) ? "[ ] " : "[X] "); | 599 prefix = build_string (NILP (selected) ? "[ ] " : "[X] "); |
592 else if (EQ (type, QCradio)) | 600 else if (EQ (type, QCradio)) |
593 prefix = build_string (NILP (selected) ? "( ) " : "(*) "); | 601 prefix = build_string (NILP (selected) ? "( ) " : "(*) "); |
594 } | 602 } |
595 /* Not a button. If we have earlier buttons, then we need a prefix. */ | 603 /* Not a button. If we have earlier buttons, then we need a prefix. */ |
596 else if (!*notbuttons_ptr && SREF (item_string, 0) != '\0' | 604 else if (!skp->notbuttons && SREF (item_string, 0) != '\0' |
597 && SREF (item_string, 0) != '-') | 605 && SREF (item_string, 0) != '-') |
598 prefix = build_string (" "); | 606 prefix = build_string (" "); |
599 | 607 |
600 if (!NILP (prefix)) | 608 if (!NILP (prefix)) |
601 item_string = concat2 (prefix, item_string); | 609 item_string = concat2 (prefix, item_string); |
602 } | 610 } |
603 #endif /* not HAVE_BOXES */ | 611 #endif /* not HAVE_BOXES */ |
604 | 612 |
605 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) | 613 #if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) |
606 if (!NILP(map)) | 614 if (!NILP (map)) |
607 /* Indicate visually that this is a submenu. */ | 615 /* Indicate visually that this is a submenu. */ |
608 item_string = concat2 (item_string, build_string (" >")); | 616 item_string = concat2 (item_string, build_string (" >")); |
609 #endif | 617 #endif |
610 | 618 |
611 push_menu_item (item_string, enabled, key, | 619 push_menu_item (item_string, enabled, key, |
618 #if defined (USE_X_TOOLKIT) || defined (USE_GTK) | 626 #if defined (USE_X_TOOLKIT) || defined (USE_GTK) |
619 /* Display a submenu using the toolkit. */ | 627 /* Display a submenu using the toolkit. */ |
620 if (! (NILP (map) || NILP (enabled))) | 628 if (! (NILP (map) || NILP (enabled))) |
621 { | 629 { |
622 push_submenu_start (); | 630 push_submenu_start (); |
623 single_keymap_panes (map, Qnil, key, 0, maxdepth - 1); | 631 single_keymap_panes (map, Qnil, key, 0, skp->maxdepth - 1); |
624 push_submenu_end (); | 632 push_submenu_end (); |
625 } | 633 } |
626 #endif | 634 #endif |
627 } | 635 } |
628 | 636 |
636 { | 644 { |
637 Lisp_Object tail; | 645 Lisp_Object tail; |
638 | 646 |
639 init_menu_items (); | 647 init_menu_items (); |
640 | 648 |
641 for (tail = menu; !NILP (tail); tail = Fcdr (tail)) | 649 for (tail = menu; CONSP (tail); tail = XCDR (tail)) |
642 { | 650 { |
643 Lisp_Object elt, pane_name, pane_data; | 651 Lisp_Object elt, pane_name, pane_data; |
644 elt = Fcar (tail); | 652 elt = XCAR (tail); |
645 pane_name = Fcar (elt); | 653 pane_name = Fcar (elt); |
646 CHECK_STRING (pane_name); | 654 CHECK_STRING (pane_name); |
647 push_menu_pane (pane_name, Qnil); | 655 push_menu_pane (ENCODE_MENU_STRING (pane_name), Qnil); |
648 pane_data = Fcdr (elt); | 656 pane_data = Fcdr (elt); |
649 CHECK_CONS (pane_data); | 657 CHECK_CONS (pane_data); |
650 list_of_items (pane_data); | 658 list_of_items (pane_data); |
651 } | 659 } |
652 | 660 |
659 list_of_items (pane) | 667 list_of_items (pane) |
660 Lisp_Object pane; | 668 Lisp_Object pane; |
661 { | 669 { |
662 Lisp_Object tail, item, item1; | 670 Lisp_Object tail, item, item1; |
663 | 671 |
664 for (tail = pane; !NILP (tail); tail = Fcdr (tail)) | 672 for (tail = pane; CONSP (tail); tail = XCDR (tail)) |
665 { | 673 { |
666 item = Fcar (tail); | 674 item = XCAR (tail); |
667 if (STRINGP (item)) | 675 if (STRINGP (item)) |
668 push_menu_item (item, Qnil, Qnil, Qt, Qnil, Qnil, Qnil, Qnil); | 676 push_menu_item (ENCODE_MENU_STRING (item), Qnil, Qnil, Qt, |
669 else if (NILP (item)) | 677 Qnil, Qnil, Qnil, Qnil); |
678 else if (CONSP (item)) | |
679 { | |
680 item1 = XCAR (item); | |
681 CHECK_STRING (item1); | |
682 push_menu_item (ENCODE_MENU_STRING (item1), Qt, XCDR (item), | |
683 Qt, Qnil, Qnil, Qnil, Qnil); | |
684 } | |
685 else | |
670 push_left_right_boundary (); | 686 push_left_right_boundary (); |
671 else | 687 |
672 { | |
673 CHECK_CONS (item); | |
674 item1 = Fcar (item); | |
675 CHECK_STRING (item1); | |
676 push_menu_item (item1, Qt, Fcdr (item), Qt, Qnil, Qnil, Qnil, Qnil); | |
677 } | |
678 } | 688 } |
679 } | 689 } |
680 | 690 |
681 #ifdef HAVE_X_WINDOWS | 691 #ifdef HAVE_X_WINDOWS |
682 /* Return the mouse position in *X and *Y. The coordinates are window | 692 /* Return the mouse position in *X and *Y. The coordinates are window |
685 be used for X, as it returns window relative coordinates | 695 be used for X, as it returns window relative coordinates |
686 for the window where the mouse is in. This could be the menu bar, | 696 for the window where the mouse is in. This could be the menu bar, |
687 the scroll bar or the edit window. Fx_popup_menu needs to be | 697 the scroll bar or the edit window. Fx_popup_menu needs to be |
688 sure it is the edit window. */ | 698 sure it is the edit window. */ |
689 static void | 699 static void |
690 mouse_position_for_popup(f, x, y) | 700 mouse_position_for_popup (f, x, y) |
691 FRAME_PTR f; | 701 FRAME_PTR f; |
692 int *x; | 702 int *x; |
693 int *y; | 703 int *y; |
694 { | 704 { |
695 Window root, dummy_window; | 705 Window root, dummy_window; |
718 | 728 |
719 UNBLOCK_INPUT; | 729 UNBLOCK_INPUT; |
720 | 730 |
721 /* xmenu_show expects window coordinates, not root window | 731 /* xmenu_show expects window coordinates, not root window |
722 coordinates. Translate. */ | 732 coordinates. Translate. */ |
723 *x -= f->output_data.x->left_pos | 733 *x -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); |
724 + FRAME_OUTER_TO_INNER_DIFF_X (f); | 734 *y -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); |
725 *y -= f->output_data.x->top_pos | |
726 + FRAME_OUTER_TO_INNER_DIFF_Y (f); | |
727 } | 735 } |
728 | 736 |
729 #endif /* HAVE_X_WINDOWS */ | 737 #endif /* HAVE_X_WINDOWS */ |
730 | 738 |
731 DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0, | 739 DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0, |
732 doc: /* Pop up a deck-of-cards menu and return user's selection. | 740 doc: /* Pop up a deck-of-cards menu and return user's selection. |
733 POSITION is a position specification. This is either a mouse button event | 741 POSITION is a position specification. This is either a mouse button event |
734 or a list ((XOFFSET YOFFSET) WINDOW) | 742 or a list ((XOFFSET YOFFSET) WINDOW) |
735 where XOFFSET and YOFFSET are positions in pixels from the top left | 743 where XOFFSET and YOFFSET are positions in pixels from the top left |
736 corner of WINDOW's frame. (WINDOW may be a frame object instead of a window.) | 744 corner of WINDOW. (WINDOW may be a window or a frame object.) |
737 This controls the position of the center of the first line | 745 This controls the position of the top left of the menu as a whole. |
738 in the first pane of the menu, not the top left of the menu as a whole. | |
739 If POSITION is t, it means to use the current mouse position. | 746 If POSITION is t, it means to use the current mouse position. |
740 | 747 |
741 MENU is a specifier for a menu. For the simplest case, MENU is a keymap. | 748 MENU is a specifier for a menu. For the simplest case, MENU is a keymap. |
742 The menu items come from key bindings that have a menu string as well as | 749 The menu items come from key bindings that have a menu string as well as |
743 a definition; actually, the "definition" in such a key binding looks like | 750 a definition; actually, the "definition" in such a key binding looks like |
747 If REAL-DEFINITION is nil, that puts a nonselectable string in the menu. | 754 If REAL-DEFINITION is nil, that puts a nonselectable string in the menu. |
748 Otherwise, REAL-DEFINITION should be a valid key binding definition. | 755 Otherwise, REAL-DEFINITION should be a valid key binding definition. |
749 | 756 |
750 You can also use a list of keymaps as MENU. | 757 You can also use a list of keymaps as MENU. |
751 Then each keymap makes a separate pane. | 758 Then each keymap makes a separate pane. |
752 When MENU is a keymap or a list of keymaps, the return value | 759 |
753 is a list of events. | 760 When MENU is a keymap or a list of keymaps, the return value is the |
761 list of events corresponding to the user's choice. Note that | |
762 `x-popup-menu' does not actually execute the command bound to that | |
763 sequence of events. | |
754 | 764 |
755 Alternatively, you can specify a menu of multiple panes | 765 Alternatively, you can specify a menu of multiple panes |
756 with a list of the form (TITLE PANE1 PANE2...), | 766 with a list of the form (TITLE PANE1 PANE2...), |
757 where each pane is a list of form (TITLE ITEM1 ITEM2...). | 767 where each pane is a list of form (TITLE ITEM1 ITEM2...). |
758 Each ITEM is normally a cons cell (STRING . VALUE); | 768 Each ITEM is normally a cons cell (STRING . VALUE); |
759 but a string can appear as an item--that makes a nonselectable line | 769 but a string can appear as an item--that makes a nonselectable line |
760 in the menu. | 770 in the menu. |
761 With this form of menu, the return value is VALUE from the chosen item. | 771 With this form of menu, the return value is VALUE from the chosen item. |
762 | 772 |
763 If POSITION is nil, don't display the menu at all, just precalculate the | 773 If POSITION is nil, don't display the menu at all, just precalculate the |
764 cached information about equivalent key sequences. */) | 774 cached information about equivalent key sequences. |
775 | |
776 If the user gets rid of the menu without making a valid choice, for | |
777 instance by clicking the mouse away from a valid choice or by typing | |
778 keyboard input, then this normally results in a quit and | |
779 `x-popup-menu' does not return. But if POSITION is a mouse button | |
780 event (indicating that the user invoked the menu with the mouse) then | |
781 no quit occurs and `x-popup-menu' returns nil. */) | |
765 (position, menu) | 782 (position, menu) |
766 Lisp_Object position, menu; | 783 Lisp_Object position, menu; |
767 { | 784 { |
768 Lisp_Object keymap, tem; | 785 Lisp_Object keymap, tem; |
769 int xpos = 0, ypos = 0; | 786 int xpos = 0, ypos = 0; |
770 Lisp_Object title; | 787 Lisp_Object title; |
771 char *error_name; | 788 char *error_name = NULL; |
772 Lisp_Object selection; | 789 Lisp_Object selection; |
773 FRAME_PTR f = NULL; | 790 FRAME_PTR f = NULL; |
774 Lisp_Object x, y, window; | 791 Lisp_Object x, y, window; |
775 int keymaps = 0; | 792 int keymaps = 0; |
776 int for_click = 0; | 793 int for_click = 0; |
794 { | 811 { |
795 tem = Fcar (position); | 812 tem = Fcar (position); |
796 if (CONSP (tem)) | 813 if (CONSP (tem)) |
797 { | 814 { |
798 window = Fcar (Fcdr (position)); | 815 window = Fcar (Fcdr (position)); |
799 x = Fcar (tem); | 816 x = XCAR (tem); |
800 y = Fcar (Fcdr (tem)); | 817 y = Fcar (XCDR (tem)); |
801 } | 818 } |
802 else | 819 else |
803 { | 820 { |
804 for_click = 1; | 821 for_click = 1; |
805 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */ | 822 tem = Fcar (Fcdr (position)); /* EVENT_START (position) */ |
870 else if (WINDOWP (window)) | 887 else if (WINDOWP (window)) |
871 { | 888 { |
872 CHECK_LIVE_WINDOW (window); | 889 CHECK_LIVE_WINDOW (window); |
873 f = XFRAME (WINDOW_FRAME (XWINDOW (window))); | 890 f = XFRAME (WINDOW_FRAME (XWINDOW (window))); |
874 | 891 |
875 xpos = (FONT_WIDTH (FRAME_FONT (f)) | 892 xpos = WINDOW_LEFT_EDGE_X (XWINDOW (window)); |
876 * XFASTINT (XWINDOW (window)->left)); | 893 ypos = WINDOW_TOP_EDGE_Y (XWINDOW (window)); |
877 ypos = (FRAME_LINE_HEIGHT (f) | |
878 * XFASTINT (XWINDOW (window)->top)); | |
879 } | 894 } |
880 else | 895 else |
881 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME, | 896 /* ??? Not really clean; should be CHECK_WINDOW_OR_FRAME, |
882 but I don't want to make one now. */ | 897 but I don't want to make one now. */ |
883 CHECK_WINDOW (window); | 898 CHECK_WINDOW (window); |
884 | 899 |
885 xpos += XINT (x); | 900 xpos += XINT (x); |
886 ypos += XINT (y); | 901 ypos += XINT (y); |
887 } | 902 |
888 Vmenu_updating_frame = Qnil; | 903 XSETFRAME (Vmenu_updating_frame, f); |
904 } | |
905 else | |
906 Vmenu_updating_frame = Qnil; | |
889 #endif /* HAVE_MENUS */ | 907 #endif /* HAVE_MENUS */ |
890 | 908 |
891 record_unwind_protect (unuse_menu_items, Qnil); | 909 record_unwind_protect (unuse_menu_items, Qnil); |
892 title = Qnil; | 910 title = Qnil; |
893 GCPRO1 (title); | 911 GCPRO1 (title); |
925 | 943 |
926 title = Qnil; | 944 title = Qnil; |
927 | 945 |
928 /* The first keymap that has a prompt string | 946 /* The first keymap that has a prompt string |
929 supplies the menu title. */ | 947 supplies the menu title. */ |
930 for (tem = menu, i = 0; CONSP (tem); tem = Fcdr (tem)) | 948 for (tem = menu, i = 0; CONSP (tem); tem = XCDR (tem)) |
931 { | 949 { |
932 Lisp_Object prompt; | 950 Lisp_Object prompt; |
933 | 951 |
934 maps[i++] = keymap = get_keymap (Fcar (tem), 1, 0); | 952 maps[i++] = keymap = get_keymap (XCAR (tem), 1, 0); |
935 | 953 |
936 prompt = Fkeymap_prompt (keymap); | 954 prompt = Fkeymap_prompt (keymap); |
937 if (NILP (title) && !NILP (prompt)) | 955 if (NILP (title) && !NILP (prompt)) |
938 title = prompt; | 956 title = prompt; |
939 } | 957 } |
984 return selection; | 1002 return selection; |
985 } | 1003 } |
986 | 1004 |
987 #ifdef HAVE_MENUS | 1005 #ifdef HAVE_MENUS |
988 | 1006 |
989 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 2, 0, | 1007 DEFUN ("x-popup-dialog", Fx_popup_dialog, Sx_popup_dialog, 2, 3, 0, |
990 doc: /* Pop up a dialog box and return user's selection. | 1008 doc: /* Pop up a dialog box and return user's selection. |
991 POSITION specifies which frame to use. | 1009 POSITION specifies which frame to use. |
992 This is normally a mouse button event or a window or frame. | 1010 This is normally a mouse button event or a window or frame. |
993 If POSITION is t, it means to use the frame the mouse is on. | 1011 If POSITION is t, it means to use the frame the mouse is on. |
994 The dialog box appears in the middle of the specified frame. | 1012 The dialog box appears in the middle of the specified frame. |
995 | 1013 |
996 CONTENTS specifies the alternatives to display in the dialog box. | 1014 CONTENTS specifies the alternatives to display in the dialog box. |
997 It is a list of the form (TITLE ITEM1 ITEM2...). | 1015 It is a list of the form (DIALOG ITEM1 ITEM2...). |
998 Each ITEM is a cons cell (STRING . VALUE). | 1016 Each ITEM is a cons cell (STRING . VALUE). |
999 The return value is VALUE from the chosen item. | 1017 The return value is VALUE from the chosen item. |
1000 | 1018 |
1001 An ITEM may also be just a string--that makes a nonselectable item. | 1019 An ITEM may also be just a string--that makes a nonselectable item. |
1002 An ITEM may also be nil--that means to put all preceding items | 1020 An ITEM may also be nil--that means to put all preceding items |
1003 on the left of the dialog box and all following items on the right. | 1021 on the left of the dialog box and all following items on the right. |
1004 \(By default, approximately half appear on each side.) */) | 1022 \(By default, approximately half appear on each side.) |
1005 (position, contents) | 1023 |
1006 Lisp_Object position, contents; | 1024 If HEADER is non-nil, the frame title for the box is "Information", |
1025 otherwise it is "Question". | |
1026 | |
1027 If the user gets rid of the dialog box without making a valid choice, | |
1028 for instance using the window manager, then this produces a quit and | |
1029 `x-popup-dialog' does not return. */) | |
1030 (position, contents, header) | |
1031 Lisp_Object position, contents, header; | |
1007 { | 1032 { |
1008 FRAME_PTR f = NULL; | 1033 FRAME_PTR f = NULL; |
1009 Lisp_Object window; | 1034 Lisp_Object window; |
1010 | 1035 |
1011 check_x (); | 1036 check_x (); |
1086 /* Decode the dialog items from what was specified. */ | 1111 /* Decode the dialog items from what was specified. */ |
1087 title = Fcar (contents); | 1112 title = Fcar (contents); |
1088 CHECK_STRING (title); | 1113 CHECK_STRING (title); |
1089 record_unwind_protect (unuse_menu_items, Qnil); | 1114 record_unwind_protect (unuse_menu_items, Qnil); |
1090 | 1115 |
1116 if (NILP (Fcar (Fcdr (contents)))) | |
1117 /* No buttons specified, add an "Ok" button so users can pop down | |
1118 the dialog. Also, the lesstif/motif version crashes if there are | |
1119 no buttons. */ | |
1120 contents = Fcons (title, Fcons (Fcons (build_string ("Ok"), Qt), Qnil)); | |
1121 | |
1091 list_of_panes (Fcons (contents, Qnil)); | 1122 list_of_panes (Fcons (contents, Qnil)); |
1092 | 1123 |
1093 /* Display them in a dialog box. */ | 1124 /* Display them in a dialog box. */ |
1094 BLOCK_INPUT; | 1125 BLOCK_INPUT; |
1095 selection = xdialog_show (f, 0, title, &error_name); | 1126 selection = xdialog_show (f, 0, title, header, &error_name); |
1096 UNBLOCK_INPUT; | 1127 UNBLOCK_INPUT; |
1097 | 1128 |
1098 unbind_to (specpdl_count, Qnil); | 1129 unbind_to (specpdl_count, Qnil); |
1099 discard_menu_items (); | 1130 discard_menu_items (); |
1100 | 1131 |
1101 if (error_name) error (error_name); | 1132 if (error_name) error (error_name); |
1102 return selection; | 1133 return selection; |
1103 } | 1134 } |
1104 #endif | 1135 #endif |
1105 } | 1136 } |
1137 | |
1138 | |
1139 #ifndef MSDOS | |
1140 | |
1141 /* Set menu_items_inuse so no other popup menu or dialog is created. */ | |
1142 | |
1143 void | |
1144 x_menu_set_in_use (in_use) | |
1145 int in_use; | |
1146 { | |
1147 menu_items_inuse = in_use ? Qt : Qnil; | |
1148 popup_activated_flag = in_use; | |
1149 } | |
1150 | |
1151 /* Wait for an X event to arrive or for a timer to expire. */ | |
1152 | |
1153 void | |
1154 x_menu_wait_for_event (void *data) | |
1155 { | |
1156 extern EMACS_TIME timer_check P_ ((int)); | |
1157 | |
1158 /* Another way to do this is to register a timer callback, that can be | |
1159 done in GTK and Xt. But we have to do it like this when using only X | |
1160 anyway, and with callbacks we would have three variants for timer handling | |
1161 instead of the small ifdefs below. */ | |
1162 | |
1163 while ( | |
1164 #ifdef USE_X_TOOLKIT | |
1165 ! XtAppPending (Xt_app_con) | |
1166 #elif defined USE_GTK | |
1167 ! gtk_events_pending () | |
1168 #else | |
1169 ! XPending ((Display*) data) | |
1170 #endif | |
1171 ) | |
1172 { | |
1173 EMACS_TIME next_time = timer_check (1); | |
1174 long secs = EMACS_SECS (next_time); | |
1175 long usecs = EMACS_USECS (next_time); | |
1176 SELECT_TYPE read_fds; | |
1177 struct x_display_info *dpyinfo; | |
1178 int n = 0; | |
1179 | |
1180 FD_ZERO (&read_fds); | |
1181 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) | |
1182 { | |
1183 int fd = ConnectionNumber (dpyinfo->display); | |
1184 FD_SET (fd, &read_fds); | |
1185 if (fd > n) n = fd; | |
1186 } | |
1187 | |
1188 if (secs < 0 || (secs == 0 && usecs == 0)) | |
1189 { | |
1190 /* Sometimes timer_check returns -1 (no timers) even if there are | |
1191 timers. So do a timeout anyway. */ | |
1192 EMACS_SET_SECS (next_time, 1); | |
1193 EMACS_SET_USECS (next_time, 0); | |
1194 } | |
1195 | |
1196 select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, &next_time); | |
1197 } | |
1198 } | |
1199 #endif /* ! MSDOS */ | |
1200 | |
1106 | 1201 |
1107 #if defined (USE_X_TOOLKIT) || defined (USE_GTK) | 1202 #if defined (USE_X_TOOLKIT) || defined (USE_GTK) |
1203 | |
1204 #ifdef USE_X_TOOLKIT | |
1108 | 1205 |
1109 /* Loop in Xt until the menu pulldown or dialog popup has been | 1206 /* Loop in Xt until the menu pulldown or dialog popup has been |
1110 popped down (deactivated). This is used for x-popup-menu | 1207 popped down (deactivated). This is used for x-popup-menu |
1111 and x-popup-dialog; it is not used for the menu bar. | 1208 and x-popup-dialog; it is not used for the menu bar. |
1112 | 1209 |
1113 If DO_TIMERS is nonzero, run timers. | |
1114 | |
1115 NOTE: All calls to popup_get_selection should be protected | 1210 NOTE: All calls to popup_get_selection should be protected |
1116 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */ | 1211 with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */ |
1117 | 1212 |
1118 #ifdef USE_X_TOOLKIT | |
1119 static void | 1213 static void |
1120 popup_get_selection (initial_event, dpyinfo, id, do_timers) | 1214 popup_get_selection (initial_event, dpyinfo, id, do_timers) |
1121 XEvent *initial_event; | 1215 XEvent *initial_event; |
1122 struct x_display_info *dpyinfo; | 1216 struct x_display_info *dpyinfo; |
1123 LWLIB_ID id; | 1217 LWLIB_ID id; |
1125 { | 1219 { |
1126 XEvent event; | 1220 XEvent event; |
1127 | 1221 |
1128 while (popup_activated_flag) | 1222 while (popup_activated_flag) |
1129 { | 1223 { |
1130 /* If we have no events to run, consider timers. */ | |
1131 if (do_timers && !XtAppPending (Xt_app_con)) | |
1132 timer_check (1); | |
1133 | |
1134 if (initial_event) | 1224 if (initial_event) |
1135 { | 1225 { |
1136 event = *initial_event; | 1226 event = *initial_event; |
1137 initial_event = 0; | 1227 initial_event = 0; |
1138 } | 1228 } |
1139 else | 1229 else |
1140 XtAppNextEvent (Xt_app_con, &event); | 1230 { |
1231 if (do_timers) x_menu_wait_for_event (0); | |
1232 XtAppNextEvent (Xt_app_con, &event); | |
1233 } | |
1141 | 1234 |
1142 /* Make sure we don't consider buttons grabbed after menu goes. | 1235 /* Make sure we don't consider buttons grabbed after menu goes. |
1143 And make sure to deactivate for any ButtonRelease, | 1236 And make sure to deactivate for any ButtonRelease, |
1144 even if XtDispatchEvent doesn't do that. */ | 1237 even if XtDispatchEvent doesn't do that. */ |
1145 if (event.type == ButtonRelease | 1238 if (event.type == ButtonRelease |
1155 key is pressed and the button is released. So reset key state | 1248 key is pressed and the button is released. So reset key state |
1156 so Motif thinks this is the case. */ | 1249 so Motif thinks this is the case. */ |
1157 event.xbutton.state = 0; | 1250 event.xbutton.state = 0; |
1158 #endif | 1251 #endif |
1159 } | 1252 } |
1160 /* If the user presses a key, deactivate the menu. | 1253 /* Pop down on C-g and Escape. */ |
1161 The user is likely to do that if we get wedged. | |
1162 This is mostly for Lucid, Motif pops down the menu on ESC. */ | |
1163 else if (event.type == KeyPress | 1254 else if (event.type == KeyPress |
1164 && dpyinfo->display == event.xbutton.display) | 1255 && dpyinfo->display == event.xbutton.display) |
1165 { | 1256 { |
1166 KeySym keysym = XLookupKeysym (&event.xkey, 0); | 1257 KeySym keysym = XLookupKeysym (&event.xkey, 0); |
1167 if (!IsModifierKey (keysym)) | 1258 |
1259 if ((keysym == XK_g && (event.xkey.state & ControlMask) != 0) | |
1260 || keysym == XK_Escape) /* Any escape, ignore modifiers. */ | |
1168 popup_activated_flag = 0; | 1261 popup_activated_flag = 0; |
1169 } | 1262 } |
1170 | 1263 |
1171 x_dispatch_event (&event, event.xany.display); | 1264 x_dispatch_event (&event, event.xany.display); |
1172 } | 1265 } |
1175 #endif /* USE_X_TOOLKIT */ | 1268 #endif /* USE_X_TOOLKIT */ |
1176 | 1269 |
1177 #ifdef USE_GTK | 1270 #ifdef USE_GTK |
1178 /* Loop util popup_activated_flag is set to zero in a callback. | 1271 /* Loop util popup_activated_flag is set to zero in a callback. |
1179 Used for popup menus and dialogs. */ | 1272 Used for popup menus and dialogs. */ |
1273 | |
1180 static void | 1274 static void |
1181 popup_widget_loop () | 1275 popup_widget_loop (do_timers, widget) |
1276 int do_timers; | |
1277 GtkWidget *widget; | |
1182 { | 1278 { |
1183 ++popup_activated_flag; | 1279 ++popup_activated_flag; |
1184 | 1280 |
1185 /* Process events in the Gtk event loop until done. */ | 1281 /* Process events in the Gtk event loop until done. */ |
1186 while (popup_activated_flag) | 1282 while (popup_activated_flag) |
1187 { | 1283 { |
1284 if (do_timers) x_menu_wait_for_event (0); | |
1188 gtk_main_iteration (); | 1285 gtk_main_iteration (); |
1189 } | 1286 } |
1190 } | 1287 } |
1191 #endif | 1288 #endif |
1192 | 1289 |
1210 { | 1307 { |
1211 if (!f->output_data.x->saved_menu_event->type) | 1308 if (!f->output_data.x->saved_menu_event->type) |
1212 return; | 1309 return; |
1213 | 1310 |
1214 #ifdef USE_GTK | 1311 #ifdef USE_GTK |
1215 if (! xg_win_to_widget (f->output_data.x->saved_menu_event->xany.window)) | 1312 if (! xg_win_to_widget (FRAME_X_DISPLAY (f), |
1313 f->output_data.x->saved_menu_event->xany.window)) | |
1216 return; | 1314 return; |
1217 #endif | 1315 #endif |
1218 | 1316 |
1219 set_frame_menubar (f, 0, 1); | 1317 set_frame_menubar (f, 0, 1); |
1220 BLOCK_INPUT; | 1318 BLOCK_INPUT; |
1296 XSETFRAME (frame, f); | 1394 XSETFRAME (frame, f); |
1297 kbd_buffer_store_help_event (frame, help); | 1395 kbd_buffer_store_help_event (frame, help); |
1298 } | 1396 } |
1299 else | 1397 else |
1300 { | 1398 { |
1399 #if 0 /* This code doesn't do anything useful. ++kfs */ | |
1301 /* WIDGET is the popup menu. It's parent is the frame's | 1400 /* WIDGET is the popup menu. It's parent is the frame's |
1302 widget. See which frame that is. */ | 1401 widget. See which frame that is. */ |
1303 xt_or_gtk_widget frame_widget = XtParent (widget); | 1402 xt_or_gtk_widget frame_widget = XtParent (widget); |
1304 Lisp_Object tail; | 1403 Lisp_Object tail; |
1305 | 1404 |
1309 if (GC_FRAMEP (frame) | 1408 if (GC_FRAMEP (frame) |
1310 && (f = XFRAME (frame), | 1409 && (f = XFRAME (frame), |
1311 FRAME_X_P (f) && f->output_data.x->widget == frame_widget)) | 1410 FRAME_X_P (f) && f->output_data.x->widget == frame_widget)) |
1312 break; | 1411 break; |
1313 } | 1412 } |
1314 | 1413 #endif |
1315 show_help_echo (help, Qnil, Qnil, Qnil, 1); | 1414 show_help_echo (help, Qnil, Qnil, Qnil, 1); |
1316 } | 1415 } |
1317 } | 1416 } |
1318 | 1417 |
1319 /* Callback called when menu items are highlighted/unhighlighted | 1418 /* Callback called when menu items are highlighted/unhighlighted |
1365 #endif | 1464 #endif |
1366 | 1465 |
1367 /* Find the menu selection and store it in the keyboard buffer. | 1466 /* Find the menu selection and store it in the keyboard buffer. |
1368 F is the frame the menu is on. | 1467 F is the frame the menu is on. |
1369 MENU_BAR_ITEMS_USED is the length of VECTOR. | 1468 MENU_BAR_ITEMS_USED is the length of VECTOR. |
1370 VECTOR is an array of menu events for the whole menu. | 1469 VECTOR is an array of menu events for the whole menu. */ |
1371 */ | 1470 |
1372 void | 1471 static void |
1373 find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data) | 1472 find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data) |
1374 FRAME_PTR f; | 1473 FRAME_PTR f; |
1375 int menu_bar_items_used; | 1474 int menu_bar_items_used; |
1376 Lisp_Object vector; | 1475 Lisp_Object vector; |
1377 void *client_data; | 1476 void *client_data; |
1412 if ((int) (EMACS_INT) client_data == i) | 1511 if ((int) (EMACS_INT) client_data == i) |
1413 { | 1512 { |
1414 int j; | 1513 int j; |
1415 struct input_event buf; | 1514 struct input_event buf; |
1416 Lisp_Object frame; | 1515 Lisp_Object frame; |
1516 EVENT_INIT (buf); | |
1417 | 1517 |
1418 XSETFRAME (frame, f); | 1518 XSETFRAME (frame, f); |
1419 buf.kind = MENU_BAR_EVENT; | 1519 buf.kind = MENU_BAR_EVENT; |
1420 buf.frame_or_window = frame; | 1520 buf.frame_or_window = frame; |
1421 buf.arg = frame; | 1521 buf.arg = frame; |
1472 if (xg_crazy_callback_abort) | 1572 if (xg_crazy_callback_abort) |
1473 return; | 1573 return; |
1474 | 1574 |
1475 if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f) | 1575 if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f) |
1476 return; | 1576 return; |
1577 | |
1578 /* For a group of radio buttons, GTK calls the selection callback first | |
1579 for the item that was active before the selection and then for the one that | |
1580 is active after the selection. For C-h k this means we get the help on | |
1581 the deselected item and then the selected item is executed. Prevent that | |
1582 by ignoring the non-active item. */ | |
1583 if (GTK_IS_RADIO_MENU_ITEM (widget) | |
1584 && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) | |
1585 return; | |
1586 | |
1587 /* When a menu is popped down, X generates a focus event (i.e. focus | |
1588 goes back to the frame below the menu). Since GTK buffers events, | |
1589 we force it out here before the menu selection event. Otherwise | |
1590 sit-for will exit at once if the focus event follows the menu selection | |
1591 event. */ | |
1592 | |
1593 BLOCK_INPUT; | |
1594 while (gtk_events_pending ()) | |
1595 gtk_main_iteration (); | |
1596 UNBLOCK_INPUT; | |
1477 | 1597 |
1478 find_and_call_menu_selection (cb_data->cl_data->f, | 1598 find_and_call_menu_selection (cb_data->cl_data->f, |
1479 cb_data->cl_data->menu_bar_items_used, | 1599 cb_data->cl_data->menu_bar_items_used, |
1480 cb_data->cl_data->menu_bar_vector, | 1600 cb_data->cl_data->menu_bar_vector, |
1481 cb_data->call_data); | 1601 cb_data->call_data); |
1658 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; | 1778 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; |
1659 | 1779 |
1660 #ifndef HAVE_MULTILINGUAL_MENU | 1780 #ifndef HAVE_MULTILINGUAL_MENU |
1661 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) | 1781 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) |
1662 { | 1782 { |
1663 pane_name = ENCODE_SYSTEM (pane_name); | 1783 pane_name = ENCODE_MENU_STRING (pane_name); |
1664 AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name; | 1784 AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name; |
1665 } | 1785 } |
1666 #endif | 1786 #endif |
1667 pane_string = (NILP (pane_name) | 1787 pane_string = (NILP (pane_name) |
1668 ? "" : (char *) SDATA (pane_name)); | 1788 ? "" : (char *) SDATA (pane_name)); |
1679 wv = xmalloc_widget_value (); | 1799 wv = xmalloc_widget_value (); |
1680 if (save_wv) | 1800 if (save_wv) |
1681 save_wv->next = wv; | 1801 save_wv->next = wv; |
1682 else | 1802 else |
1683 first_wv->contents = wv; | 1803 first_wv->contents = wv; |
1684 wv->name = pane_string; | 1804 wv->lname = pane_name; |
1685 /* Ignore the @ that means "separate pane". | 1805 /* Set value to 1 so update_submenu_strings can handle '@' */ |
1686 This is a kludge, but this isn't worth more time. */ | 1806 wv->value = (char *)1; |
1687 if (!NILP (prefix) && wv->name[0] == '@') | |
1688 wv->name++; | |
1689 wv->value = 0; | |
1690 wv->enabled = 1; | 1807 wv->enabled = 1; |
1691 wv->button_type = BUTTON_TYPE_NONE; | 1808 wv->button_type = BUTTON_TYPE_NONE; |
1692 wv->help = Qnil; | 1809 wv->help = Qnil; |
1693 } | 1810 } |
1694 save_wv = wv; | 1811 save_wv = wv; |
1710 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP); | 1827 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP); |
1711 | 1828 |
1712 #ifndef HAVE_MULTILINGUAL_MENU | 1829 #ifndef HAVE_MULTILINGUAL_MENU |
1713 if (STRING_MULTIBYTE (item_name)) | 1830 if (STRING_MULTIBYTE (item_name)) |
1714 { | 1831 { |
1715 item_name = ENCODE_SYSTEM (item_name); | 1832 item_name = ENCODE_MENU_STRING (item_name); |
1716 AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name; | 1833 AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name; |
1717 } | 1834 } |
1718 | 1835 |
1719 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) | 1836 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) |
1720 { | 1837 { |
1721 descrip = ENCODE_SYSTEM (descrip); | 1838 descrip = ENCODE_MENU_STRING (descrip); |
1722 AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip; | 1839 AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip; |
1723 } | 1840 } |
1724 #endif /* not HAVE_MULTILINGUAL_MENU */ | 1841 #endif /* not HAVE_MULTILINGUAL_MENU */ |
1725 | 1842 |
1726 wv = xmalloc_widget_value (); | 1843 wv = xmalloc_widget_value (); |
1727 if (prev_wv) | 1844 if (prev_wv) |
1728 prev_wv->next = wv; | 1845 prev_wv->next = wv; |
1729 else | 1846 else |
1730 save_wv->contents = wv; | 1847 save_wv->contents = wv; |
1731 | 1848 |
1732 wv->name = (char *) SDATA (item_name); | 1849 wv->lname = item_name; |
1733 if (!NILP (descrip)) | 1850 if (!NILP (descrip)) |
1734 wv->key = (char *) SDATA (descrip); | 1851 wv->lkey = descrip; |
1735 wv->value = 0; | 1852 wv->value = 0; |
1736 /* The EMACS_INT cast avoids a warning. There's no problem | 1853 /* The EMACS_INT cast avoids a warning. There's no problem |
1737 as long as pointers have enough bits to hold small integers. */ | 1854 as long as pointers have enough bits to hold small integers. */ |
1738 wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0); | 1855 wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0); |
1739 wv->enabled = !NILP (enable); | 1856 wv->enabled = !NILP (enable); |
1768 return wv; | 1885 return wv; |
1769 } | 1886 } |
1770 | 1887 |
1771 return first_wv; | 1888 return first_wv; |
1772 } | 1889 } |
1890 | |
1891 /* Walk through the widget_value tree starting at FIRST_WV and update | |
1892 the char * pointers from the corresponding lisp values. | |
1893 We do this after building the whole tree, since GC may happen while the | |
1894 tree is constructed, and small strings are relocated. So we must wait | |
1895 until no GC can happen before storing pointers into lisp values. */ | |
1896 static void | |
1897 update_submenu_strings (first_wv) | |
1898 widget_value *first_wv; | |
1899 { | |
1900 widget_value *wv; | |
1901 | |
1902 for (wv = first_wv; wv; wv = wv->next) | |
1903 { | |
1904 if (STRINGP (wv->lname)) | |
1905 { | |
1906 wv->name = (char *) SDATA (wv->lname); | |
1907 | |
1908 /* Ignore the @ that means "separate pane". | |
1909 This is a kludge, but this isn't worth more time. */ | |
1910 if (wv->value == (char *)1) | |
1911 { | |
1912 if (wv->name[0] == '@') | |
1913 wv->name++; | |
1914 wv->value = 0; | |
1915 } | |
1916 } | |
1917 | |
1918 if (STRINGP (wv->lkey)) | |
1919 wv->key = (char *) SDATA (wv->lkey); | |
1920 | |
1921 if (wv->contents) | |
1922 update_submenu_strings (wv->contents); | |
1923 } | |
1924 } | |
1925 | |
1773 | 1926 |
1774 /* Recompute all the widgets of frame F, when the menu bar has been | 1927 /* Recompute all the widgets of frame F, when the menu bar has been |
1775 changed. Value is non-zero if widgets were updated. */ | 1928 changed. Value is non-zero if widgets were updated. */ |
1776 | 1929 |
1777 static int | 1930 static int |
1788 return 0; | 1941 return 0; |
1789 | 1942 |
1790 BLOCK_INPUT; | 1943 BLOCK_INPUT; |
1791 /* Save the size of the frame because the pane widget doesn't accept | 1944 /* Save the size of the frame because the pane widget doesn't accept |
1792 to resize itself. So force it. */ | 1945 to resize itself. So force it. */ |
1793 columns = f->width; | 1946 columns = FRAME_COLS (f); |
1794 rows = f->height; | 1947 rows = FRAME_LINES (f); |
1795 | 1948 |
1796 /* Do the voodoo which means "I'm changing lots of things, don't try | 1949 /* Do the voodoo which means "I'm changing lots of things, don't try |
1797 to refigure sizes until I'm done." */ | 1950 to refigure sizes until I'm done." */ |
1798 lw_refigure_widget (x->column_widget, False); | 1951 lw_refigure_widget (x->column_widget, False); |
1799 | 1952 |
1833 #ifdef USE_X_TOOLKIT | 1986 #ifdef USE_X_TOOLKIT |
1834 LWLIB_ID id; | 1987 LWLIB_ID id; |
1835 #endif | 1988 #endif |
1836 Lisp_Object items; | 1989 Lisp_Object items; |
1837 widget_value *wv, *first_wv, *prev_wv = 0; | 1990 widget_value *wv, *first_wv, *prev_wv = 0; |
1838 int i, last_i; | 1991 int i, last_i = 0; |
1839 int *submenu_start, *submenu_end; | 1992 int *submenu_start, *submenu_end; |
1840 int *submenu_top_level_items, *submenu_n_panes; | 1993 int *submenu_top_level_items, *submenu_n_panes; |
1841 | 1994 |
1842 | 1995 |
1843 XSETFRAME (Vmenu_updating_frame, f); | 1996 XSETFRAME (Vmenu_updating_frame, f); |
1857 { | 2010 { |
1858 deep_p = 1; | 2011 deep_p = 1; |
1859 f->output_data.x->saved_menu_event = (XEvent*)xmalloc (sizeof (XEvent)); | 2012 f->output_data.x->saved_menu_event = (XEvent*)xmalloc (sizeof (XEvent)); |
1860 f->output_data.x->saved_menu_event->type = 0; | 2013 f->output_data.x->saved_menu_event->type = 0; |
1861 } | 2014 } |
2015 | |
2016 #ifdef USE_GTK | |
2017 /* If we have detached menus, we must update deep so detached menus | |
2018 also gets updated. */ | |
2019 deep_p = deep_p || xg_have_tear_offs (); | |
2020 #endif | |
1862 | 2021 |
1863 if (deep_p) | 2022 if (deep_p) |
1864 { | 2023 { |
1865 /* Make a widget-value tree representing the entire menu trees. */ | 2024 /* Make a widget-value tree representing the entire menu trees. */ |
1866 | 2025 |
1881 specbind (Qinhibit_quit, Qt); | 2040 specbind (Qinhibit_quit, Qt); |
1882 /* Don't let the debugger step into this code | 2041 /* Don't let the debugger step into this code |
1883 because it is not reentrant. */ | 2042 because it is not reentrant. */ |
1884 specbind (Qdebug_on_next_call, Qnil); | 2043 specbind (Qdebug_on_next_call, Qnil); |
1885 | 2044 |
1886 record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil)); | 2045 record_unwind_save_match_data (); |
1887 record_unwind_protect (unuse_menu_items, Qnil); | 2046 record_unwind_protect (unuse_menu_items, Qnil); |
1888 if (NILP (Voverriding_local_map_menu_flag)) | 2047 if (NILP (Voverriding_local_map_menu_flag)) |
1889 { | 2048 { |
1890 specbind (Qoverriding_terminal_local_map, Qnil); | 2049 specbind (Qoverriding_terminal_local_map, Qnil); |
1891 specbind (Qoverriding_local_map, Qnil); | 2050 specbind (Qoverriding_local_map, Qnil); |
1994 for (i = 0; i < XVECTOR (items)->size; i += 4) | 2153 for (i = 0; i < XVECTOR (items)->size; i += 4) |
1995 { | 2154 { |
1996 Lisp_Object string; | 2155 Lisp_Object string; |
1997 string = XVECTOR (items)->contents[i + 1]; | 2156 string = XVECTOR (items)->contents[i + 1]; |
1998 if (NILP (string)) | 2157 if (NILP (string)) |
1999 break; | 2158 break; |
2000 wv->name = (char *) SDATA (string); | 2159 wv->name = (char *) SDATA (string); |
2001 wv = wv->next; | 2160 update_submenu_strings (wv->contents); |
2161 wv = wv->next; | |
2002 } | 2162 } |
2003 | 2163 |
2004 f->menu_bar_vector = menu_items; | 2164 f->menu_bar_vector = menu_items; |
2005 f->menu_bar_items_used = menu_items_used; | 2165 f->menu_bar_items_used = menu_items_used; |
2006 discard_menu_items (); | 2166 discard_menu_items (); |
2058 | 2218 |
2059 #ifdef USE_GTK | 2219 #ifdef USE_GTK |
2060 xg_crazy_callback_abort = 1; | 2220 xg_crazy_callback_abort = 1; |
2061 if (menubar_widget) | 2221 if (menubar_widget) |
2062 { | 2222 { |
2063 /* The third arg is DEEP_P, which says to consider the entire | 2223 /* The fourth arg is DEEP_P, which says to consider the entire |
2064 menu trees we supply, rather than just the menu bar item names. */ | 2224 menu trees we supply, rather than just the menu bar item names. */ |
2065 xg_modify_menubar_widgets (menubar_widget, | 2225 xg_modify_menubar_widgets (menubar_widget, |
2066 f, | 2226 f, |
2067 first_wv, | 2227 first_wv, |
2068 deep_p, | 2228 deep_p, |
2097 /* Re-enable the edit widget to resize. */ | 2257 /* Re-enable the edit widget to resize. */ |
2098 lw_allow_resizing (f->output_data.x->widget, True); | 2258 lw_allow_resizing (f->output_data.x->widget, True); |
2099 } | 2259 } |
2100 else | 2260 else |
2101 { | 2261 { |
2262 char menuOverride[] = "Ctrl<KeyPress>g: MenuGadgetEscape()"; | |
2263 XtTranslations override = XtParseTranslationTable (menuOverride); | |
2264 | |
2102 menubar_widget = lw_create_widget ("menubar", "menubar", id, first_wv, | 2265 menubar_widget = lw_create_widget ("menubar", "menubar", id, first_wv, |
2103 f->output_data.x->column_widget, | 2266 f->output_data.x->column_widget, |
2104 0, | 2267 0, |
2105 popup_activate_callback, | 2268 popup_activate_callback, |
2106 menubar_selection_callback, | 2269 menubar_selection_callback, |
2107 popup_deactivate_callback, | 2270 popup_deactivate_callback, |
2108 menu_highlight_callback); | 2271 menu_highlight_callback); |
2109 f->output_data.x->menubar_widget = menubar_widget; | 2272 f->output_data.x->menubar_widget = menubar_widget; |
2273 | |
2274 /* Make menu pop down on C-g. */ | |
2275 XtOverrideTranslations (menubar_widget, override); | |
2110 } | 2276 } |
2111 | 2277 |
2112 { | 2278 { |
2113 int menubar_size | 2279 int menubar_size |
2114 = (f->output_data.x->menubar_widget | 2280 = (f->output_data.x->menubar_widget |
2266 { | 2432 { |
2267 struct next_popup_x_y* data = (struct next_popup_x_y*)user_data; | 2433 struct next_popup_x_y* data = (struct next_popup_x_y*)user_data; |
2268 GtkRequisition req; | 2434 GtkRequisition req; |
2269 int disp_width = FRAME_X_DISPLAY_INFO (data->f)->width; | 2435 int disp_width = FRAME_X_DISPLAY_INFO (data->f)->width; |
2270 int disp_height = FRAME_X_DISPLAY_INFO (data->f)->height; | 2436 int disp_height = FRAME_X_DISPLAY_INFO (data->f)->height; |
2271 | 2437 |
2272 *x = data->x; | 2438 *x = data->x; |
2273 *y = data->y; | 2439 *y = data->y; |
2274 | 2440 |
2275 /* Check if there is room for the menu. If not, adjust x/y so that | 2441 /* Check if there is room for the menu. If not, adjust x/y so that |
2276 the menu is fully visible. */ | 2442 the menu is fully visible. */ |
2288 { | 2454 { |
2289 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data; | 2455 xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data; |
2290 | 2456 |
2291 if (xg_crazy_callback_abort) return; | 2457 if (xg_crazy_callback_abort) return; |
2292 if (cb_data) menu_item_selection = (Lisp_Object *) cb_data->call_data; | 2458 if (cb_data) menu_item_selection = (Lisp_Object *) cb_data->call_data; |
2459 } | |
2460 | |
2461 static Lisp_Object | |
2462 pop_down_menu (arg) | |
2463 Lisp_Object arg; | |
2464 { | |
2465 struct Lisp_Save_Value *p = XSAVE_VALUE (arg); | |
2466 | |
2467 popup_activated_flag = 0; | |
2468 BLOCK_INPUT; | |
2469 gtk_widget_destroy (GTK_WIDGET (p->pointer)); | |
2470 UNBLOCK_INPUT; | |
2471 return Qnil; | |
2293 } | 2472 } |
2294 | 2473 |
2295 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the | 2474 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the |
2296 menu pops down. | 2475 menu pops down. |
2297 menu_item_selection will be set to the selection. */ | 2476 menu_item_selection will be set to the selection. */ |
2305 { | 2484 { |
2306 int i; | 2485 int i; |
2307 GtkWidget *menu; | 2486 GtkWidget *menu; |
2308 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */ | 2487 GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */ |
2309 struct next_popup_x_y popup_x_y; | 2488 struct next_popup_x_y popup_x_y; |
2489 int specpdl_count = SPECPDL_INDEX (); | |
2310 | 2490 |
2311 xg_crazy_callback_abort = 1; | 2491 xg_crazy_callback_abort = 1; |
2312 menu = xg_create_widget ("popup", first_wv->name, f, first_wv, | 2492 menu = xg_create_widget ("popup", first_wv->name, f, first_wv, |
2313 G_CALLBACK (popup_selection_callback), | 2493 G_CALLBACK (popup_selection_callback), |
2314 G_CALLBACK (popup_deactivate_callback), | 2494 G_CALLBACK (popup_deactivate_callback), |
2315 G_CALLBACK (menu_highlight_callback)); | 2495 G_CALLBACK (menu_highlight_callback)); |
2316 xg_crazy_callback_abort = 0; | 2496 xg_crazy_callback_abort = 0; |
2317 | 2497 |
2318 for (i = 0; i < 5; i++) | |
2319 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i)) | |
2320 break; | |
2321 | |
2322 if (! for_click) | 2498 if (! for_click) |
2323 { | 2499 { |
2324 /* Not invoked by a click. pop up at x/y. */ | 2500 /* Not invoked by a click. pop up at x/y. */ |
2325 pos_func = menu_position_func; | 2501 pos_func = menu_position_func; |
2326 | 2502 |
2327 /* Adjust coordinates to be root-window-relative. */ | 2503 /* Adjust coordinates to be root-window-relative. */ |
2328 x += f->output_data.x->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); | 2504 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); |
2329 y += f->output_data.x->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); | 2505 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); |
2330 | 2506 |
2331 popup_x_y.x = x; | 2507 popup_x_y.x = x; |
2332 popup_x_y.y = y; | 2508 popup_x_y.y = y; |
2333 popup_x_y.f = f; | 2509 popup_x_y.f = f; |
2510 | |
2511 i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */ | |
2512 } | |
2513 else | |
2514 { | |
2515 for (i = 0; i < 5; i++) | |
2516 if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i)) | |
2517 break; | |
2334 } | 2518 } |
2335 | 2519 |
2336 /* Display the menu. */ | 2520 /* Display the menu. */ |
2337 gtk_widget_show_all (menu); | 2521 gtk_widget_show_all (menu); |
2338 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i, 0); | 2522 gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i, 0); |
2339 | 2523 |
2340 xg_did_tearoff = 0; | 2524 record_unwind_protect (pop_down_menu, make_save_value (menu, 0)); |
2341 /* Set this to one. popup_widget_loop increases it by one, so it becomes | 2525 |
2342 two. show_help_echo uses this to detect popup menus. */ | 2526 if (GTK_WIDGET_MAPPED (menu)) |
2343 popup_activated_flag = 1; | 2527 { |
2344 /* Process events that apply to the menu. */ | 2528 /* Set this to one. popup_widget_loop increases it by one, so it becomes |
2345 popup_widget_loop (); | 2529 two. show_help_echo uses this to detect popup menus. */ |
2346 | 2530 popup_activated_flag = 1; |
2347 if (xg_did_tearoff) | 2531 /* Process events that apply to the menu. */ |
2348 xg_keep_popup (menu, xg_did_tearoff); | 2532 popup_widget_loop (1, menu); |
2349 else | 2533 } |
2350 gtk_widget_destroy (menu); | 2534 |
2535 unbind_to (specpdl_count, Qnil); | |
2351 | 2536 |
2352 /* Must reset this manually because the button release event is not passed | 2537 /* Must reset this manually because the button release event is not passed |
2353 to Emacs event loop. */ | 2538 to Emacs event loop. */ |
2354 FRAME_X_DISPLAY_INFO (f)->grabbed = 0; | 2539 FRAME_X_DISPLAY_INFO (f)->grabbed = 0; |
2355 } | 2540 } |
2371 Widget widget; | 2556 Widget widget; |
2372 LWLIB_ID id; | 2557 LWLIB_ID id; |
2373 XtPointer client_data; | 2558 XtPointer client_data; |
2374 { | 2559 { |
2375 menu_item_selection = (Lisp_Object *) client_data; | 2560 menu_item_selection = (Lisp_Object *) client_data; |
2561 } | |
2562 | |
2563 /* ARG is the LWLIB ID of the dialog box, represented | |
2564 as a Lisp object as (HIGHPART . LOWPART). */ | |
2565 | |
2566 static Lisp_Object | |
2567 pop_down_menu (arg) | |
2568 Lisp_Object arg; | |
2569 { | |
2570 LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID) | |
2571 | XINT (XCDR (arg))); | |
2572 | |
2573 BLOCK_INPUT; | |
2574 lw_destroy_all_widgets (id); | |
2575 UNBLOCK_INPUT; | |
2576 popup_activated_flag = 0; | |
2577 | |
2578 return Qnil; | |
2376 } | 2579 } |
2377 | 2580 |
2378 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the | 2581 /* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the |
2379 menu pops down. | 2582 menu pops down. |
2380 menu_item_selection will be set to the selection. */ | 2583 menu_item_selection will be set to the selection. */ |
2390 Arg av[2]; | 2593 Arg av[2]; |
2391 int ac = 0; | 2594 int ac = 0; |
2392 XButtonPressedEvent dummy; | 2595 XButtonPressedEvent dummy; |
2393 LWLIB_ID menu_id; | 2596 LWLIB_ID menu_id; |
2394 Widget menu; | 2597 Widget menu; |
2395 Window child; | |
2396 | 2598 |
2397 menu_id = widget_id_tick++; | 2599 menu_id = widget_id_tick++; |
2398 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv, | 2600 menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv, |
2399 f->output_data.x->widget, 1, 0, | 2601 f->output_data.x->widget, 1, 0, |
2400 popup_selection_callback, | 2602 popup_selection_callback, |
2411 dummy.subwindow = dummy.root; | 2613 dummy.subwindow = dummy.root; |
2412 dummy.x = x; | 2614 dummy.x = x; |
2413 dummy.y = y; | 2615 dummy.y = y; |
2414 | 2616 |
2415 /* Adjust coordinates to be root-window-relative. */ | 2617 /* Adjust coordinates to be root-window-relative. */ |
2416 x += f->output_data.x->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); | 2618 x += f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); |
2417 y += f->output_data.x->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); | 2619 y += f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); |
2418 | 2620 |
2419 dummy.x_root = x; | 2621 dummy.x_root = x; |
2420 dummy.y_root = y; | 2622 dummy.y_root = y; |
2421 | 2623 |
2422 dummy.state = 0; | 2624 dummy.state = 0; |
2431 | 2633 |
2432 /* Display the menu. */ | 2634 /* Display the menu. */ |
2433 lw_popup_menu (menu, (XEvent *) &dummy); | 2635 lw_popup_menu (menu, (XEvent *) &dummy); |
2434 popup_activated_flag = 1; | 2636 popup_activated_flag = 1; |
2435 | 2637 |
2436 /* Process events that apply to the menu. */ | 2638 { |
2437 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 0); | 2639 int fact = 4 * sizeof (LWLIB_ID); |
2438 | 2640 int specpdl_count = SPECPDL_INDEX (); |
2439 /* fp turned off the following statement and wrote a comment | 2641 record_unwind_protect (pop_down_menu, |
2440 that it is unnecessary--that the menu has already disappeared. | 2642 Fcons (make_number (menu_id >> (fact)), |
2441 Nowadays the menu disappears ok, all right, but | 2643 make_number (menu_id & ~(-1 << (fact))))); |
2442 we need to delete the widgets or multiple ones will pile up. */ | 2644 |
2443 lw_destroy_all_widgets (menu_id); | 2645 /* Process events that apply to the menu. */ |
2646 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 1); | |
2647 | |
2648 unbind_to (specpdl_count, Qnil); | |
2649 } | |
2444 } | 2650 } |
2445 | 2651 |
2446 #endif /* not USE_GTK */ | 2652 #endif /* not USE_GTK */ |
2447 | 2653 |
2448 static Lisp_Object | 2654 static Lisp_Object |
2520 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); | 2726 prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); |
2521 | 2727 |
2522 #ifndef HAVE_MULTILINGUAL_MENU | 2728 #ifndef HAVE_MULTILINGUAL_MENU |
2523 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) | 2729 if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) |
2524 { | 2730 { |
2525 pane_name = ENCODE_SYSTEM (pane_name); | 2731 pane_name = ENCODE_MENU_STRING (pane_name); |
2526 AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name; | 2732 AREF (menu_items, i + MENU_ITEMS_PANE_NAME) = pane_name; |
2527 } | 2733 } |
2528 #endif | 2734 #endif |
2529 pane_string = (NILP (pane_name) | 2735 pane_string = (NILP (pane_name) |
2530 ? "" : (char *) SDATA (pane_name)); | 2736 ? "" : (char *) SDATA (pane_name)); |
2574 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP); | 2780 help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP); |
2575 | 2781 |
2576 #ifndef HAVE_MULTILINGUAL_MENU | 2782 #ifndef HAVE_MULTILINGUAL_MENU |
2577 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name)) | 2783 if (STRINGP (item_name) && STRING_MULTIBYTE (item_name)) |
2578 { | 2784 { |
2579 item_name = ENCODE_SYSTEM (item_name); | 2785 item_name = ENCODE_MENU_STRING (item_name); |
2580 AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name; | 2786 AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name; |
2581 } | 2787 } |
2582 | 2788 |
2583 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) | 2789 if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) |
2584 { | 2790 { |
2585 descrip = ENCODE_SYSTEM (descrip); | 2791 descrip = ENCODE_MENU_STRING (descrip); |
2586 AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip; | 2792 AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip; |
2587 } | 2793 } |
2588 #endif /* not HAVE_MULTILINGUAL_MENU */ | 2794 #endif /* not HAVE_MULTILINGUAL_MENU */ |
2589 | 2795 |
2590 wv = xmalloc_widget_value (); | 2796 wv = xmalloc_widget_value (); |
2640 wv_sep1->next = wv_sep2; | 2846 wv_sep1->next = wv_sep2; |
2641 wv_sep1->help = Qnil; | 2847 wv_sep1->help = Qnil; |
2642 | 2848 |
2643 #ifndef HAVE_MULTILINGUAL_MENU | 2849 #ifndef HAVE_MULTILINGUAL_MENU |
2644 if (STRING_MULTIBYTE (title)) | 2850 if (STRING_MULTIBYTE (title)) |
2645 title = ENCODE_SYSTEM (title); | 2851 title = ENCODE_MENU_STRING (title); |
2646 #endif | 2852 #endif |
2647 | 2853 |
2648 wv_title->name = (char *) SDATA (title); | 2854 wv_title->name = (char *) SDATA (title); |
2649 wv_title->enabled = TRUE; | 2855 wv_title->enabled = TRUE; |
2650 wv_title->button_type = BUTTON_TYPE_NONE; | 2856 wv_title->button_type = BUTTON_TYPE_NONE; |
2714 } | 2920 } |
2715 i += MENU_ITEMS_ITEM_LENGTH; | 2921 i += MENU_ITEMS_ITEM_LENGTH; |
2716 } | 2922 } |
2717 } | 2923 } |
2718 } | 2924 } |
2925 else if (!for_click) | |
2926 /* Make "Cancel" equivalent to C-g. */ | |
2927 Fsignal (Qquit, Qnil); | |
2719 | 2928 |
2720 return Qnil; | 2929 return Qnil; |
2721 } | 2930 } |
2722 | 2931 |
2723 #ifdef USE_GTK | 2932 #ifdef USE_GTK |
2749 G_CALLBACK (popup_deactivate_callback), | 2958 G_CALLBACK (popup_deactivate_callback), |
2750 0); | 2959 0); |
2751 | 2960 |
2752 if (menu) | 2961 if (menu) |
2753 { | 2962 { |
2963 int specpdl_count = SPECPDL_INDEX (); | |
2964 record_unwind_protect (pop_down_menu, make_save_value (menu, 0)); | |
2965 | |
2754 /* Display the menu. */ | 2966 /* Display the menu. */ |
2755 gtk_widget_show_all (menu); | 2967 gtk_widget_show_all (menu); |
2756 | 2968 |
2757 /* Process events that apply to the menu. */ | 2969 /* Process events that apply to the menu. */ |
2758 popup_widget_loop (); | 2970 popup_widget_loop (1, menu); |
2759 | 2971 |
2760 gtk_widget_destroy (menu); | 2972 unbind_to (specpdl_count, Qnil); |
2761 } | 2973 } |
2762 } | 2974 } |
2763 | 2975 |
2764 #else /* not USE_GTK */ | 2976 #else /* not USE_GTK */ |
2765 static void | 2977 static void |
2775 | 2987 |
2776 BLOCK_INPUT; | 2988 BLOCK_INPUT; |
2777 lw_destroy_all_widgets (id); | 2989 lw_destroy_all_widgets (id); |
2778 UNBLOCK_INPUT; | 2990 UNBLOCK_INPUT; |
2779 popup_activated_flag = 0; | 2991 popup_activated_flag = 0; |
2780 } | |
2781 | |
2782 | |
2783 /* ARG is the LWLIB ID of the dialog box, represented | |
2784 as a Lisp object as (HIGHPART . LOWPART). */ | |
2785 | |
2786 Lisp_Object | |
2787 xdialog_show_unwind (arg) | |
2788 Lisp_Object arg; | |
2789 { | |
2790 LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID) | |
2791 | XINT (XCDR (arg))); | |
2792 BLOCK_INPUT; | |
2793 lw_destroy_all_widgets (id); | |
2794 UNBLOCK_INPUT; | |
2795 popup_activated_flag = 0; | |
2796 return Qnil; | |
2797 } | 2992 } |
2798 | 2993 |
2799 | 2994 |
2800 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the | 2995 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the |
2801 dialog pops down. | 2996 dialog pops down. |
2822 { | 3017 { |
2823 int count = SPECPDL_INDEX (); | 3018 int count = SPECPDL_INDEX (); |
2824 int fact = 4 * sizeof (LWLIB_ID); | 3019 int fact = 4 * sizeof (LWLIB_ID); |
2825 | 3020 |
2826 /* xdialog_show_unwind is responsible for popping the dialog box down. */ | 3021 /* xdialog_show_unwind is responsible for popping the dialog box down. */ |
2827 record_unwind_protect (xdialog_show_unwind, | 3022 record_unwind_protect (pop_down_menu, |
2828 Fcons (make_number (dialog_id >> (fact)), | 3023 Fcons (make_number (dialog_id >> (fact)), |
2829 make_number (dialog_id & ~(-1 << (fact))))); | 3024 make_number (dialog_id & ~(-1 << (fact))))); |
2830 | 3025 |
2831 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id, 1); | 3026 popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), |
3027 dialog_id, 1); | |
2832 | 3028 |
2833 unbind_to (count, Qnil); | 3029 unbind_to (count, Qnil); |
2834 } | 3030 } |
2835 } | 3031 } |
2836 | 3032 |
2839 static char * button_names [] = { | 3035 static char * button_names [] = { |
2840 "button1", "button2", "button3", "button4", "button5", | 3036 "button1", "button2", "button3", "button4", "button5", |
2841 "button6", "button7", "button8", "button9", "button10" }; | 3037 "button6", "button7", "button8", "button9", "button10" }; |
2842 | 3038 |
2843 static Lisp_Object | 3039 static Lisp_Object |
2844 xdialog_show (f, keymaps, title, error) | 3040 xdialog_show (f, keymaps, title, header, error_name) |
2845 FRAME_PTR f; | 3041 FRAME_PTR f; |
2846 int keymaps; | 3042 int keymaps; |
2847 Lisp_Object title; | 3043 Lisp_Object title, header; |
2848 char **error; | 3044 char **error_name; |
2849 { | 3045 { |
2850 int i, nb_buttons=0; | 3046 int i, nb_buttons=0; |
2851 char dialog_name[6]; | 3047 char dialog_name[6]; |
2852 | 3048 |
2853 widget_value *wv, *first_wv = 0, *prev_wv = 0; | 3049 widget_value *wv, *first_wv = 0, *prev_wv = 0; |
2855 /* Number of elements seen so far, before boundary. */ | 3051 /* Number of elements seen so far, before boundary. */ |
2856 int left_count = 0; | 3052 int left_count = 0; |
2857 /* 1 means we've seen the boundary between left-hand elts and right-hand. */ | 3053 /* 1 means we've seen the boundary between left-hand elts and right-hand. */ |
2858 int boundary_seen = 0; | 3054 int boundary_seen = 0; |
2859 | 3055 |
2860 *error = NULL; | 3056 *error_name = NULL; |
2861 | 3057 |
2862 if (menu_items_n_panes > 1) | 3058 if (menu_items_n_panes > 1) |
2863 { | 3059 { |
2864 *error = "Multiple panes in dialog box"; | 3060 *error_name = "Multiple panes in dialog box"; |
2865 return Qnil; | 3061 return Qnil; |
2866 } | 3062 } |
2867 | 3063 |
2868 /* Create a tree of widget_value objects | 3064 /* Create a tree of widget_value objects |
2869 representing the text label and buttons. */ | 3065 representing the text label and buttons. */ |
2896 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY]; | 3092 = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY]; |
2897 | 3093 |
2898 if (NILP (item_name)) | 3094 if (NILP (item_name)) |
2899 { | 3095 { |
2900 free_menubar_widget_value_tree (first_wv); | 3096 free_menubar_widget_value_tree (first_wv); |
2901 *error = "Submenu in dialog items"; | 3097 *error_name = "Submenu in dialog items"; |
2902 return Qnil; | 3098 return Qnil; |
2903 } | 3099 } |
2904 if (EQ (item_name, Qquote)) | 3100 if (EQ (item_name, Qquote)) |
2905 { | 3101 { |
2906 /* This is the boundary between left-side elts | 3102 /* This is the boundary between left-side elts |
2910 continue; | 3106 continue; |
2911 } | 3107 } |
2912 if (nb_buttons >= 9) | 3108 if (nb_buttons >= 9) |
2913 { | 3109 { |
2914 free_menubar_widget_value_tree (first_wv); | 3110 free_menubar_widget_value_tree (first_wv); |
2915 *error = "Too many dialog items"; | 3111 *error_name = "Too many dialog items"; |
2916 return Qnil; | 3112 return Qnil; |
2917 } | 3113 } |
2918 | 3114 |
2919 wv = xmalloc_widget_value (); | 3115 wv = xmalloc_widget_value (); |
2920 prev_wv->next = wv; | 3116 prev_wv->next = wv; |
2940 left_count = nb_buttons - nb_buttons / 2; | 3136 left_count = nb_buttons - nb_buttons / 2; |
2941 | 3137 |
2942 wv = xmalloc_widget_value (); | 3138 wv = xmalloc_widget_value (); |
2943 wv->name = dialog_name; | 3139 wv->name = dialog_name; |
2944 wv->help = Qnil; | 3140 wv->help = Qnil; |
3141 | |
3142 /* Frame title: 'Q' = Question, 'I' = Information. | |
3143 Can also have 'E' = Error if, one day, we want | |
3144 a popup for errors. */ | |
3145 if (NILP(header)) | |
3146 dialog_name[0] = 'Q'; | |
3147 else | |
3148 dialog_name[0] = 'I'; | |
3149 | |
2945 /* Dialog boxes use a really stupid name encoding | 3150 /* Dialog boxes use a really stupid name encoding |
2946 which specifies how many buttons to use | 3151 which specifies how many buttons to use |
2947 and how many buttons are on the right. | 3152 and how many buttons are on the right. */ |
2948 The Q means something also. */ | |
2949 dialog_name[0] = 'Q'; | |
2950 dialog_name[1] = '0' + nb_buttons; | 3153 dialog_name[1] = '0' + nb_buttons; |
2951 dialog_name[2] = 'B'; | 3154 dialog_name[2] = 'B'; |
2952 dialog_name[3] = 'R'; | 3155 dialog_name[3] = 'R'; |
2953 /* Number of buttons to put on the right. */ | 3156 /* Number of buttons to put on the right. */ |
2954 dialog_name[4] = '0' + nb_buttons - left_count; | 3157 dialog_name[4] = '0' + nb_buttons - left_count; |
3006 } | 3209 } |
3007 i += MENU_ITEMS_ITEM_LENGTH; | 3210 i += MENU_ITEMS_ITEM_LENGTH; |
3008 } | 3211 } |
3009 } | 3212 } |
3010 } | 3213 } |
3214 else | |
3215 /* Make "Cancel" equivalent to C-g. */ | |
3216 Fsignal (Qquit, Qnil); | |
3011 | 3217 |
3012 return Qnil; | 3218 return Qnil; |
3013 } | 3219 } |
3014 | 3220 |
3015 #else /* not USE_X_TOOLKIT && not USE_GTK */ | 3221 #else /* not USE_X_TOOLKIT && not USE_GTK */ |
3054 Fcons (make_number (pane), Qnil))); | 3260 Fcons (make_number (pane), Qnil))); |
3055 show_help_echo (help_string ? build_string (help_string) : Qnil, | 3261 show_help_echo (help_string ? build_string (help_string) : Qnil, |
3056 Qnil, menu_object, make_number (item), 1); | 3262 Qnil, menu_object, make_number (item), 1); |
3057 } | 3263 } |
3058 | 3264 |
3265 static Lisp_Object | |
3266 pop_down_menu (arg) | |
3267 Lisp_Object arg; | |
3268 { | |
3269 struct Lisp_Save_Value *p1 = XSAVE_VALUE (Fcar (arg)); | |
3270 struct Lisp_Save_Value *p2 = XSAVE_VALUE (Fcdr (arg)); | |
3271 | |
3272 FRAME_PTR f = p1->pointer; | |
3273 XMenu *menu = p2->pointer; | |
3274 | |
3275 BLOCK_INPUT; | |
3276 #ifndef MSDOS | |
3277 XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime); | |
3278 XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime); | |
3279 #endif | |
3280 XMenuDestroy (FRAME_X_DISPLAY (f), menu); | |
3281 | |
3282 #ifdef HAVE_X_WINDOWS | |
3283 /* Assume the mouse has moved out of the X window. | |
3284 If it has actually moved in, we will get an EnterNotify. */ | |
3285 x_mouse_leave (FRAME_X_DISPLAY_INFO (f)); | |
3286 | |
3287 /* State that no mouse buttons are now held. | |
3288 (The oldXMenu code doesn't track this info for us.) | |
3289 That is not necessarily true, but the fiction leads to reasonable | |
3290 results, and it is a pain to ask which are actually held now. */ | |
3291 FRAME_X_DISPLAY_INFO (f)->grabbed = 0; | |
3292 | |
3293 #endif /* HAVE_X_WINDOWS */ | |
3294 | |
3295 UNBLOCK_INPUT; | |
3296 | |
3297 return Qnil; | |
3298 } | |
3299 | |
3059 | 3300 |
3060 static Lisp_Object | 3301 static Lisp_Object |
3061 xmenu_show (f, x, y, for_click, keymaps, title, error) | 3302 xmenu_show (f, x, y, for_click, keymaps, title, error) |
3062 FRAME_PTR f; | 3303 FRAME_PTR f; |
3063 int x, y; | 3304 int x, y; |
3071 int pane, selidx, lpane, status; | 3312 int pane, selidx, lpane, status; |
3072 Lisp_Object entry, pane_prefix; | 3313 Lisp_Object entry, pane_prefix; |
3073 char *datap; | 3314 char *datap; |
3074 int ulx, uly, width, height; | 3315 int ulx, uly, width, height; |
3075 int dispwidth, dispheight; | 3316 int dispwidth, dispheight; |
3076 int i, j; | 3317 int i, j, lines, maxlines; |
3077 int maxwidth; | 3318 int maxwidth; |
3078 int dummy_int; | 3319 int dummy_int; |
3079 unsigned int dummy_uint; | 3320 unsigned int dummy_uint; |
3321 int specpdl_count = SPECPDL_INDEX (); | |
3080 | 3322 |
3081 *error = 0; | 3323 *error = 0; |
3082 if (menu_items_n_panes == 0) | 3324 if (menu_items_n_panes == 0) |
3083 return Qnil; | 3325 return Qnil; |
3084 | 3326 |
3099 { | 3341 { |
3100 *error = "Can't create menu"; | 3342 *error = "Can't create menu"; |
3101 return Qnil; | 3343 return Qnil; |
3102 } | 3344 } |
3103 | 3345 |
3346 /* Don't GC while we prepare and show the menu, | |
3347 because we give the oldxmenu library pointers to the | |
3348 contents of strings. */ | |
3349 inhibit_garbage_collection (); | |
3350 | |
3104 #ifdef HAVE_X_WINDOWS | 3351 #ifdef HAVE_X_WINDOWS |
3105 /* Adjust coordinates to relative to the outer (window manager) window. */ | 3352 /* Adjust coordinates to relative to the outer (window manager) window. */ |
3106 { | 3353 x += FRAME_OUTER_TO_INNER_DIFF_X (f); |
3107 Window child; | 3354 y += FRAME_OUTER_TO_INNER_DIFF_Y (f); |
3108 int win_x = 0, win_y = 0; | |
3109 | |
3110 /* Find the position of the outside upper-left corner of | |
3111 the inner window, with respect to the outer window. */ | |
3112 if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window) | |
3113 { | |
3114 BLOCK_INPUT; | |
3115 XTranslateCoordinates (FRAME_X_DISPLAY (f), | |
3116 | |
3117 /* From-window, to-window. */ | |
3118 f->output_data.x->window_desc, | |
3119 f->output_data.x->parent_desc, | |
3120 | |
3121 /* From-position, to-position. */ | |
3122 0, 0, &win_x, &win_y, | |
3123 | |
3124 /* Child of window. */ | |
3125 &child); | |
3126 UNBLOCK_INPUT; | |
3127 x += win_x; | |
3128 y += win_y; | |
3129 } | |
3130 } | |
3131 #endif /* HAVE_X_WINDOWS */ | 3355 #endif /* HAVE_X_WINDOWS */ |
3132 | 3356 |
3133 /* Adjust coordinates to be root-window-relative. */ | 3357 /* Adjust coordinates to be root-window-relative. */ |
3134 x += f->output_data.x->left_pos; | 3358 x += f->left_pos; |
3135 y += f->output_data.x->top_pos; | 3359 y += f->top_pos; |
3136 | 3360 |
3137 /* Create all the necessary panes and their items. */ | 3361 /* Create all the necessary panes and their items. */ |
3138 i = 0; | 3362 maxlines = lines = i = 0; |
3139 while (i < menu_items_used) | 3363 while (i < menu_items_used) |
3140 { | 3364 { |
3141 if (EQ (XVECTOR (menu_items)->contents[i], Qt)) | 3365 if (EQ (XVECTOR (menu_items)->contents[i], Qt)) |
3142 { | 3366 { |
3143 /* Create a new pane. */ | 3367 /* Create a new pane. */ |
3144 Lisp_Object pane_name, prefix; | 3368 Lisp_Object pane_name, prefix; |
3145 char *pane_string; | 3369 char *pane_string; |
3146 | 3370 |
3371 maxlines = max (maxlines, lines); | |
3372 lines = 0; | |
3147 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME]; | 3373 pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME]; |
3148 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; | 3374 prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; |
3149 pane_string = (NILP (pane_name) | 3375 pane_string = (NILP (pane_name) |
3150 ? "" : (char *) SDATA (pane_name)); | 3376 ? "" : (char *) SDATA (pane_name)); |
3151 if (keymaps && !NILP (prefix)) | 3377 if (keymaps && !NILP (prefix)) |
3234 XMenuDestroy (FRAME_X_DISPLAY (f), menu); | 3460 XMenuDestroy (FRAME_X_DISPLAY (f), menu); |
3235 *error = "Can't add selection to menu"; | 3461 *error = "Can't add selection to menu"; |
3236 return Qnil; | 3462 return Qnil; |
3237 } | 3463 } |
3238 i += MENU_ITEMS_ITEM_LENGTH; | 3464 i += MENU_ITEMS_ITEM_LENGTH; |
3465 lines++; | |
3239 } | 3466 } |
3240 } | 3467 } |
3468 | |
3469 maxlines = max (maxlines, lines); | |
3241 | 3470 |
3242 /* All set and ready to fly. */ | 3471 /* All set and ready to fly. */ |
3243 XMenuRecompute (FRAME_X_DISPLAY (f), menu); | 3472 XMenuRecompute (FRAME_X_DISPLAY (f), menu); |
3244 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f)); | 3473 dispwidth = DisplayWidth (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f)); |
3245 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f)); | 3474 dispheight = DisplayHeight (FRAME_X_DISPLAY (f), FRAME_X_SCREEN_NUMBER (f)); |
3260 uly = dispheight - height; | 3489 uly = dispheight - height; |
3261 } | 3490 } |
3262 if (ulx < 0) x -= ulx; | 3491 if (ulx < 0) x -= ulx; |
3263 if (uly < 0) y -= uly; | 3492 if (uly < 0) y -= uly; |
3264 | 3493 |
3494 if (! for_click) | |
3495 { | |
3496 /* If position was not given by a mouse click, adjust so upper left | |
3497 corner of the menu as a whole ends up at given coordinates. This | |
3498 is what x-popup-menu says in its documentation. */ | |
3499 x += width/2; | |
3500 y += 1.5*height/(maxlines+2); | |
3501 } | |
3502 | |
3265 XMenuSetAEQ (menu, TRUE); | 3503 XMenuSetAEQ (menu, TRUE); |
3266 XMenuSetFreeze (menu, TRUE); | 3504 XMenuSetFreeze (menu, TRUE); |
3267 pane = selidx = 0; | 3505 pane = selidx = 0; |
3506 | |
3507 #ifndef MSDOS | |
3508 XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f)); | |
3509 #endif | |
3510 | |
3511 record_unwind_protect (pop_down_menu, | |
3512 Fcons (make_save_value (f, 0), | |
3513 make_save_value (menu, 0))); | |
3268 | 3514 |
3269 /* Help display under X won't work because XMenuActivate contains | 3515 /* Help display under X won't work because XMenuActivate contains |
3270 a loop that doesn't give Emacs a chance to process it. */ | 3516 a loop that doesn't give Emacs a chance to process it. */ |
3271 menu_help_frame = f; | 3517 menu_help_frame = f; |
3272 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx, | 3518 status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx, |
3273 x, y, ButtonReleaseMask, &datap, | 3519 x, y, ButtonReleaseMask, &datap, |
3274 menu_help_callback); | 3520 menu_help_callback); |
3275 | |
3276 | |
3277 #ifdef HAVE_X_WINDOWS | |
3278 /* Assume the mouse has moved out of the X window. | |
3279 If it has actually moved in, we will get an EnterNotify. */ | |
3280 x_mouse_leave (FRAME_X_DISPLAY_INFO (f)); | |
3281 #endif | |
3282 | 3521 |
3283 switch (status) | 3522 switch (status) |
3284 { | 3523 { |
3285 case XM_SUCCESS: | 3524 case XM_SUCCESS: |
3286 #ifdef XDEBUG | 3525 #ifdef XDEBUG |
3323 break; | 3562 break; |
3324 | 3563 |
3325 case XM_FAILURE: | 3564 case XM_FAILURE: |
3326 *error = "Can't activate menu"; | 3565 *error = "Can't activate menu"; |
3327 case XM_IA_SELECT: | 3566 case XM_IA_SELECT: |
3328 case XM_NO_SELECT: | |
3329 entry = Qnil; | 3567 entry = Qnil; |
3330 break; | 3568 break; |
3331 } | 3569 case XM_NO_SELECT: |
3332 XMenuDestroy (FRAME_X_DISPLAY (f), menu); | 3570 /* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means |
3333 | 3571 the menu was invoked with a mouse event as POSITION). */ |
3334 #ifdef HAVE_X_WINDOWS | 3572 if (! for_click) |
3335 /* State that no mouse buttons are now held. | 3573 Fsignal (Qquit, Qnil); |
3336 (The oldXMenu code doesn't track this info for us.) | 3574 entry = Qnil; |
3337 That is not necessarily true, but the fiction leads to reasonable | 3575 break; |
3338 results, and it is a pain to ask which are actually held now. */ | 3576 } |
3339 FRAME_X_DISPLAY_INFO (f)->grabbed = 0; | 3577 |
3340 #endif | 3578 unbind_to (specpdl_count, Qnil); |
3341 | 3579 |
3342 return entry; | 3580 return entry; |
3343 } | 3581 } |
3344 | 3582 |
3345 #endif /* not USE_X_TOOLKIT */ | 3583 #endif /* not USE_X_TOOLKIT */ |
3369 defsubr (&Sx_popup_menu); | 3607 defsubr (&Sx_popup_menu); |
3370 #ifdef HAVE_MENUS | 3608 #ifdef HAVE_MENUS |
3371 defsubr (&Sx_popup_dialog); | 3609 defsubr (&Sx_popup_dialog); |
3372 #endif | 3610 #endif |
3373 } | 3611 } |
3612 | |
3613 /* arch-tag: 92ea573c-398e-496e-ac73-2436f7d63242 | |
3614 (do not change this comment) */ |