81 |
#endif /* USE_LUCID */ |
#endif /* USE_LUCID */ |
82 |
#include "../lwlib/lwlib.h" |
#include "../lwlib/lwlib.h" |
83 |
#else /* not USE_X_TOOLKIT */ |
#else /* not USE_X_TOOLKIT */ |
84 |
|
#ifndef USE_GTK |
85 |
#include "../oldXMenu/XMenu.h" |
#include "../oldXMenu/XMenu.h" |
86 |
|
#endif |
87 |
#endif /* not USE_X_TOOLKIT */ |
#endif /* not USE_X_TOOLKIT */ |
88 |
#endif /* HAVE_X_WINDOWS */ |
#endif /* HAVE_X_WINDOWS */ |
89 |
|
|
110 |
|
|
111 |
#ifdef USE_X_TOOLKIT |
#ifdef USE_X_TOOLKIT |
112 |
extern void set_frame_menubar (); |
extern void set_frame_menubar (); |
|
extern void process_expose_from_menu (); |
|
113 |
extern XtAppContext Xt_app_con; |
extern XtAppContext Xt_app_con; |
114 |
|
|
115 |
static Lisp_Object xdialog_show (); |
static Lisp_Object xdialog_show (); |
116 |
void popup_get_selection (); |
static void popup_get_selection (); |
117 |
|
|
118 |
/* Define HAVE_BOXES if menus can handle radio and toggle buttons. */ |
/* Define HAVE_BOXES if menus can handle radio and toggle buttons. */ |
119 |
|
|
120 |
#define HAVE_BOXES 1 |
#define HAVE_BOXES 1 |
121 |
|
#endif /* USE_X_TOOLKIT */ |
122 |
|
|
123 |
|
#ifdef USE_GTK |
124 |
|
#include "gtkutil.h" |
125 |
|
#define HAVE_BOXES 1 |
126 |
|
extern void set_frame_menubar (); |
127 |
|
static Lisp_Object xdialog_show (); |
128 |
#endif |
#endif |
129 |
|
|
130 |
static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object, |
static void push_menu_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object, |
140 |
int, int, int *)); |
int, int, int *)); |
141 |
static void list_of_panes P_ ((Lisp_Object)); |
static void list_of_panes P_ ((Lisp_Object)); |
142 |
static void list_of_items P_ ((Lisp_Object)); |
static void list_of_items P_ ((Lisp_Object)); |
143 |
|
|
144 |
|
extern EMACS_TIME timer_check P_ ((int)); |
145 |
|
|
146 |
/* This holds a Lisp vector that holds the results of decoding |
/* This holds a Lisp vector that holds the results of decoding |
147 |
the keymaps or alist-of-alists that specify a menu. |
the keymaps or alist-of-alists that specify a menu. |
184 |
|
|
185 |
static Lisp_Object menu_items; |
static Lisp_Object menu_items; |
186 |
|
|
187 |
|
/* If non-nil, means that the global vars defined here are already in use. |
188 |
|
Used to detect cases where we try to re-enter this non-reentrant code. */ |
189 |
|
static Lisp_Object menu_items_inuse; |
190 |
|
|
191 |
/* Number of slots currently allocated in menu_items. */ |
/* Number of slots currently allocated in menu_items. */ |
192 |
static int menu_items_allocated; |
static int menu_items_allocated; |
193 |
|
|
203 |
|
|
204 |
/* Flag which when set indicates a dialog or menu has been posted by |
/* Flag which when set indicates a dialog or menu has been posted by |
205 |
Xt on behalf of one of the widget sets. */ |
Xt on behalf of one of the widget sets. */ |
206 |
int popup_activated_flag; |
static int popup_activated_flag; |
207 |
|
|
208 |
static int next_menubar_widget_id; |
static int next_menubar_widget_id; |
209 |
|
|
255 |
menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil); |
menu_items = Fmake_vector (make_number (menu_items_allocated), Qnil); |
256 |
} |
} |
257 |
|
|
258 |
|
if (!NILP (menu_items_inuse)) |
259 |
|
error ("Trying to use a menu from within a menu-entry"); |
260 |
|
menu_items_inuse = Qt; |
261 |
menu_items_used = 0; |
menu_items_used = 0; |
262 |
menu_items_n_panes = 0; |
menu_items_n_panes = 0; |
263 |
menu_items_submenu_depth = 0; |
menu_items_submenu_depth = 0; |
270 |
{ |
{ |
271 |
} |
} |
272 |
|
|
273 |
|
static Lisp_Object |
274 |
|
unuse_menu_items (dummy) |
275 |
|
int dummy; |
276 |
|
{ |
277 |
|
return menu_items_inuse = Qnil; |
278 |
|
} |
279 |
|
|
280 |
/* Call when finished using the data for the current menu |
/* Call when finished using the data for the current menu |
281 |
in menu_items. */ |
in menu_items. */ |
282 |
|
|
290 |
menu_items = Qnil; |
menu_items = Qnil; |
291 |
menu_items_allocated = 0; |
menu_items_allocated = 0; |
292 |
} |
} |
293 |
|
xassert (NILP (menu_items_inuse)); |
294 |
} |
} |
295 |
|
|
296 |
/* Make the menu_items vector twice as large. */ |
/* Make the menu_items vector twice as large. */ |
487 |
|
|
488 |
/* This is a subroutine of single_keymap_panes that handles one |
/* This is a subroutine of single_keymap_panes that handles one |
489 |
keymap entry. |
keymap entry. |
490 |
KEY is a key in a keymap and ITEM is its binding. |
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 |
PENDING_MAPS_PTR points to a list of keymaps waiting to be made into |
492 |
separate panes. |
separate panes. |
493 |
If NOTREAL is nonzero, only check for equivalent key bindings, don't |
If NOTREAL is nonzero, only check for equivalent key bindings, don't |
508 |
Lisp_Object map, item_string, enabled; |
Lisp_Object map, item_string, enabled; |
509 |
struct gcpro gcpro1, gcpro2; |
struct gcpro gcpro1, gcpro2; |
510 |
int res; |
int res; |
511 |
|
|
512 |
/* Parse the menu item and leave the result in item_properties. */ |
/* Parse the menu item and leave the result in item_properties. */ |
513 |
GCPRO2 (key, item); |
GCPRO2 (key, item); |
514 |
res = parse_menu_item (item, notreal, 0); |
res = parse_menu_item (item, notreal, 0); |
517 |
return; /* Not a menu item. */ |
return; /* Not a menu item. */ |
518 |
|
|
519 |
map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP]; |
map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP]; |
520 |
|
|
521 |
if (notreal) |
if (notreal) |
522 |
{ |
{ |
523 |
/* We don't want to make a menu, just traverse the keymaps to |
/* We don't want to make a menu, just traverse the keymaps to |
528 |
} |
} |
529 |
|
|
530 |
enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE]; |
enabled = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE]; |
531 |
item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME]; |
item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME]; |
532 |
|
|
533 |
if (!NILP (map) && XSTRING (item_string)->data[0] == '@') |
if (!NILP (map) && SREF (item_string, 0) == '@') |
534 |
{ |
{ |
535 |
if (!NILP (enabled)) |
if (!NILP (enabled)) |
536 |
/* An enabled separate pane. Remember this to handle it later. */ |
/* An enabled separate pane. Remember this to handle it later. */ |
576 |
index++; /* Skip a left, right divider. */ |
index++; /* Skip a left, right divider. */ |
577 |
else |
else |
578 |
{ |
{ |
579 |
if (!submenu && XSTRING (tem)->data[0] != '\0' |
if (!submenu && SREF (tem, 0) != '\0' |
580 |
&& XSTRING (tem)->data[0] != '-') |
&& SREF (tem, 0) != '-') |
581 |
XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME] |
XVECTOR (menu_items)->contents[index + MENU_ITEMS_ITEM_NAME] |
582 |
= concat2 (build_string (" "), tem); |
= concat2 (build_string (" "), tem); |
583 |
index += MENU_ITEMS_ITEM_LENGTH; |
index += MENU_ITEMS_ITEM_LENGTH; |
593 |
prefix = build_string (NILP (selected) ? "( ) " : "(*) "); |
prefix = build_string (NILP (selected) ? "( ) " : "(*) "); |
594 |
} |
} |
595 |
/* Not a button. If we have earlier buttons, then we need a prefix. */ |
/* Not a button. If we have earlier buttons, then we need a prefix. */ |
596 |
else if (!*notbuttons_ptr && XSTRING (item_string)->data[0] != '\0' |
else if (!*notbuttons_ptr && SREF (item_string, 0) != '\0' |
597 |
&& XSTRING (item_string)->data[0] != '-') |
&& SREF (item_string, 0) != '-') |
598 |
prefix = build_string (" "); |
prefix = build_string (" "); |
599 |
|
|
600 |
if (!NILP (prefix)) |
if (!NILP (prefix)) |
601 |
item_string = concat2 (prefix, item_string); |
item_string = concat2 (prefix, item_string); |
602 |
} |
} |
603 |
#endif /* not HAVE_BOXES */ |
#endif /* not HAVE_BOXES */ |
604 |
|
|
605 |
#ifndef USE_X_TOOLKIT |
#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) |
606 |
if (!NILP(map)) |
if (!NILP(map)) |
607 |
/* Indicate visually that this is a submenu. */ |
/* Indicate visually that this is a submenu. */ |
608 |
item_string = concat2 (item_string, build_string (" >")); |
item_string = concat2 (item_string, build_string (" >")); |
615 |
XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED], |
XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED], |
616 |
XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]); |
XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]); |
617 |
|
|
618 |
#ifdef USE_X_TOOLKIT |
#if defined (USE_X_TOOLKIT) || defined (USE_GTK) |
619 |
/* Display a submenu using the toolkit. */ |
/* Display a submenu using the toolkit. */ |
620 |
if (! (NILP (map) || NILP (enabled))) |
if (! (NILP (map) || NILP (enabled))) |
621 |
{ |
{ |
678 |
} |
} |
679 |
} |
} |
680 |
|
|
681 |
|
#ifdef HAVE_X_WINDOWS |
682 |
|
/* Return the mouse position in *X and *Y. The coordinates are window |
683 |
|
relative for the edit window in frame F. |
684 |
|
This is for Fx_popup_menu. The mouse_position_hook can not |
685 |
|
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, |
687 |
|
the scroll bar or the edit window. Fx_popup_menu needs to be |
688 |
|
sure it is the edit window. */ |
689 |
|
static void |
690 |
|
mouse_position_for_popup(f, x, y) |
691 |
|
FRAME_PTR f; |
692 |
|
int *x; |
693 |
|
int *y; |
694 |
|
{ |
695 |
|
Window root, dummy_window; |
696 |
|
int dummy; |
697 |
|
|
698 |
|
BLOCK_INPUT; |
699 |
|
|
700 |
|
XQueryPointer (FRAME_X_DISPLAY (f), |
701 |
|
DefaultRootWindow (FRAME_X_DISPLAY (f)), |
702 |
|
|
703 |
|
/* The root window which contains the pointer. */ |
704 |
|
&root, |
705 |
|
|
706 |
|
/* Window pointer is on, not used */ |
707 |
|
&dummy_window, |
708 |
|
|
709 |
|
/* The position on that root window. */ |
710 |
|
x, y, |
711 |
|
|
712 |
|
/* x/y in dummy_window coordinates, not used. */ |
713 |
|
&dummy, &dummy, |
714 |
|
|
715 |
|
/* Modifier keys and pointer buttons, about which |
716 |
|
we don't care. */ |
717 |
|
(unsigned int *) &dummy); |
718 |
|
|
719 |
|
UNBLOCK_INPUT; |
720 |
|
|
721 |
|
/* xmenu_show expects window coordinates, not root window |
722 |
|
coordinates. Translate. */ |
723 |
|
*x -= f->output_data.x->left_pos |
724 |
|
+ FRAME_OUTER_TO_INNER_DIFF_X (f); |
725 |
|
*y -= f->output_data.x->top_pos |
726 |
|
+ FRAME_OUTER_TO_INNER_DIFF_Y (f); |
727 |
|
} |
728 |
|
|
729 |
|
#endif /* HAVE_X_WINDOWS */ |
730 |
|
|
731 |
DEFUN ("x-popup-menu", Fx_popup_menu, Sx_popup_menu, 2, 2, 0, |
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. |
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 |
POSITION is a position specification. This is either a mouse button event |
774 |
Lisp_Object x, y, window; |
Lisp_Object x, y, window; |
775 |
int keymaps = 0; |
int keymaps = 0; |
776 |
int for_click = 0; |
int for_click = 0; |
777 |
|
int specpdl_count = SPECPDL_INDEX (); |
778 |
struct gcpro gcpro1; |
struct gcpro gcpro1; |
779 |
|
|
780 |
#ifdef HAVE_MENUS |
#ifdef HAVE_MENUS |
781 |
if (! NILP (position)) |
if (! NILP (position)) |
782 |
{ |
{ |
783 |
|
int get_current_pos_p = 0; |
784 |
check_x (); |
check_x (); |
785 |
|
|
786 |
/* Decode the first argument: find the window and the coordinates. */ |
/* Decode the first argument: find the window and the coordinates. */ |
788 |
|| (CONSP (position) && (EQ (XCAR (position), Qmenu_bar) |
|| (CONSP (position) && (EQ (XCAR (position), Qmenu_bar) |
789 |
|| EQ (XCAR (position), Qtool_bar)))) |
|| EQ (XCAR (position), Qtool_bar)))) |
790 |
{ |
{ |
791 |
/* Use the mouse's current position. */ |
get_current_pos_p = 1; |
792 |
FRAME_PTR new_f = SELECTED_FRAME (); |
} |
|
Lisp_Object bar_window; |
|
|
enum scroll_bar_part part; |
|
|
unsigned long time; |
|
|
|
|
|
if (mouse_position_hook) |
|
|
(*mouse_position_hook) (&new_f, 1, &bar_window, |
|
|
&part, &x, &y, &time); |
|
|
if (new_f != 0) |
|
|
XSETFRAME (window, new_f); |
|
|
else |
|
|
{ |
|
|
window = selected_window; |
|
|
XSETFASTINT (x, 0); |
|
|
XSETFASTINT (y, 0); |
|
|
} |
|
|
} |
|
793 |
else |
else |
794 |
{ |
{ |
795 |
tem = Fcar (position); |
tem = Fcar (position); |
808 |
x = Fcar (tem); |
x = Fcar (tem); |
809 |
y = Fcdr (tem); |
y = Fcdr (tem); |
810 |
} |
} |
811 |
|
|
812 |
|
/* If a click happens in an external tool bar or a detached |
813 |
|
tool bar, x and y is NIL. In that case, use the current |
814 |
|
mouse position. This happens for the help button in the |
815 |
|
tool bar. Ideally popup-menu should pass NIL to |
816 |
|
this function, but it doesn't. */ |
817 |
|
if (NILP (x) && NILP (y)) |
818 |
|
get_current_pos_p = 1; |
819 |
|
} |
820 |
|
|
821 |
|
if (get_current_pos_p) |
822 |
|
{ |
823 |
|
/* Use the mouse's current position. */ |
824 |
|
FRAME_PTR new_f = SELECTED_FRAME (); |
825 |
|
#ifdef HAVE_X_WINDOWS |
826 |
|
/* Can't use mouse_position_hook for X since it returns |
827 |
|
coordinates relative to the window the mouse is in, |
828 |
|
we need coordinates relative to the edit widget always. */ |
829 |
|
if (new_f != 0) |
830 |
|
{ |
831 |
|
int cur_x, cur_y; |
832 |
|
|
833 |
|
mouse_position_for_popup (new_f, &cur_x, &cur_y); |
834 |
|
/* cur_x/y may be negative, so use make_number. */ |
835 |
|
x = make_number (cur_x); |
836 |
|
y = make_number (cur_y); |
837 |
|
} |
838 |
|
|
839 |
|
#else /* not HAVE_X_WINDOWS */ |
840 |
|
Lisp_Object bar_window; |
841 |
|
enum scroll_bar_part part; |
842 |
|
unsigned long time; |
843 |
|
|
844 |
|
if (mouse_position_hook) |
845 |
|
(*mouse_position_hook) (&new_f, 1, &bar_window, |
846 |
|
&part, &x, &y, &time); |
847 |
|
#endif /* not HAVE_X_WINDOWS */ |
848 |
|
|
849 |
|
if (new_f != 0) |
850 |
|
XSETFRAME (window, new_f); |
851 |
|
else |
852 |
|
{ |
853 |
|
window = selected_window; |
854 |
|
XSETFASTINT (x, 0); |
855 |
|
XSETFASTINT (y, 0); |
856 |
|
} |
857 |
} |
} |
858 |
|
|
859 |
CHECK_NUMBER (x); |
CHECK_NUMBER (x); |
884 |
|
|
885 |
xpos += XINT (x); |
xpos += XINT (x); |
886 |
ypos += XINT (y); |
ypos += XINT (y); |
|
|
|
|
XSETFRAME (Vmenu_updating_frame, f); |
|
887 |
} |
} |
888 |
Vmenu_updating_frame = Qnil; |
Vmenu_updating_frame = Qnil; |
889 |
#endif /* HAVE_MENUS */ |
#endif /* HAVE_MENUS */ |
890 |
|
|
891 |
|
record_unwind_protect (unuse_menu_items, Qnil); |
892 |
title = Qnil; |
title = Qnil; |
893 |
GCPRO1 (title); |
GCPRO1 (title); |
894 |
|
|
957 |
|
|
958 |
keymaps = 0; |
keymaps = 0; |
959 |
} |
} |
960 |
|
|
961 |
|
unbind_to (specpdl_count, Qnil); |
962 |
|
|
963 |
if (NILP (position)) |
if (NILP (position)) |
964 |
{ |
{ |
965 |
discard_menu_items (); |
discard_menu_items (); |
1063 |
but I don't want to make one now. */ |
but I don't want to make one now. */ |
1064 |
CHECK_WINDOW (window); |
CHECK_WINDOW (window); |
1065 |
|
|
1066 |
#ifndef USE_X_TOOLKIT |
#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) |
1067 |
/* Display a menu with these alternatives |
/* Display a menu with these alternatives |
1068 |
in the middle of frame F. */ |
in the middle of frame F. */ |
1069 |
{ |
{ |
1081 |
Lisp_Object title; |
Lisp_Object title; |
1082 |
char *error_name; |
char *error_name; |
1083 |
Lisp_Object selection; |
Lisp_Object selection; |
1084 |
|
int specpdl_count = SPECPDL_INDEX (); |
1085 |
|
|
1086 |
/* Decode the dialog items from what was specified. */ |
/* Decode the dialog items from what was specified. */ |
1087 |
title = Fcar (contents); |
title = Fcar (contents); |
1088 |
CHECK_STRING (title); |
CHECK_STRING (title); |
1089 |
|
record_unwind_protect (unuse_menu_items, Qnil); |
1090 |
|
|
1091 |
list_of_panes (Fcons (contents, Qnil)); |
list_of_panes (Fcons (contents, Qnil)); |
1092 |
|
|
1095 |
selection = xdialog_show (f, 0, title, &error_name); |
selection = xdialog_show (f, 0, title, &error_name); |
1096 |
UNBLOCK_INPUT; |
UNBLOCK_INPUT; |
1097 |
|
|
1098 |
|
unbind_to (specpdl_count, Qnil); |
1099 |
discard_menu_items (); |
discard_menu_items (); |
1100 |
|
|
1101 |
if (error_name) error (error_name); |
if (error_name) error (error_name); |
1104 |
#endif |
#endif |
1105 |
} |
} |
1106 |
|
|
1107 |
#ifdef USE_X_TOOLKIT |
#if defined (USE_X_TOOLKIT) || defined (USE_GTK) |
1108 |
|
|
1109 |
/* Loop in Xt until the menu pulldown or dialog popup has been |
/* Loop in Xt until the menu pulldown or dialog popup has been |
1110 |
popped down (deactivated). This is used for x-popup-menu |
popped down (deactivated). This is used for x-popup-menu |
1111 |
and x-popup-dialog; it is not used for the menu bar any more. |
and x-popup-dialog; it is not used for the menu bar. |
1112 |
|
|
1113 |
|
If DO_TIMERS is nonzero, run timers. |
1114 |
|
|
1115 |
NOTE: All calls to popup_get_selection should be protected |
NOTE: All calls to popup_get_selection should be protected |
1116 |
with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */ |
with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */ |
1117 |
|
|
1118 |
void |
#ifdef USE_X_TOOLKIT |
1119 |
popup_get_selection (initial_event, dpyinfo, id) |
static void |
1120 |
|
popup_get_selection (initial_event, dpyinfo, id, do_timers) |
1121 |
XEvent *initial_event; |
XEvent *initial_event; |
1122 |
struct x_display_info *dpyinfo; |
struct x_display_info *dpyinfo; |
1123 |
LWLIB_ID id; |
LWLIB_ID id; |
1124 |
|
int do_timers; |
1125 |
{ |
{ |
1126 |
XEvent event; |
XEvent event; |
1127 |
|
|
1128 |
/* Define a queue to save up for later unreading |
while (popup_activated_flag) |
1129 |
all X events that don't pertain to the menu. */ |
{ |
1130 |
struct event_queue |
/* If we have no events to run, consider timers. */ |
1131 |
{ |
if (do_timers && !XtAppPending (Xt_app_con)) |
1132 |
XEvent event; |
timer_check (1); |
|
struct event_queue *next; |
|
|
}; |
|
|
|
|
|
struct event_queue *queue = NULL; |
|
|
struct event_queue *queue_tmp; |
|
1133 |
|
|
1134 |
if (initial_event) |
if (initial_event) |
1135 |
event = *initial_event; |
{ |
1136 |
else |
event = *initial_event; |
1137 |
XtAppNextEvent (Xt_app_con, &event); |
initial_event = 0; |
1138 |
|
} |
1139 |
|
else |
1140 |
|
XtAppNextEvent (Xt_app_con, &event); |
1141 |
|
|
|
while (1) |
|
|
{ |
|
|
/* Handle expose events for editor frames right away. */ |
|
|
if (event.type == Expose) |
|
|
process_expose_from_menu (event); |
|
1142 |
/* Make sure we don't consider buttons grabbed after menu goes. |
/* Make sure we don't consider buttons grabbed after menu goes. |
1143 |
And make sure to deactivate for any ButtonRelease, |
And make sure to deactivate for any ButtonRelease, |
1144 |
even if XtDispatchEvent doesn't do that. */ |
even if XtDispatchEvent doesn't do that. */ |
1145 |
else if (event.type == ButtonRelease |
if (event.type == ButtonRelease |
1146 |
&& dpyinfo->display == event.xbutton.display) |
&& dpyinfo->display == event.xbutton.display) |
1147 |
{ |
{ |
1148 |
dpyinfo->grabbed &= ~(1 << event.xbutton.button); |
dpyinfo->grabbed &= ~(1 << event.xbutton.button); |
1149 |
popup_activated_flag = 0; |
#ifdef USE_MOTIF /* Pretending that the event came from a |
1150 |
#ifdef USE_MOTIF /* Pretending that the event came from a |
Btn1Down seems the only way to convince Motif to |
1151 |
Btn1Down seems the only way to convince Motif to |
activate its callbacks; setting the XmNmenuPost |
1152 |
activate its callbacks; setting the XmNmenuPost |
isn't working. --marcus@sysc.pdx.edu. */ |
1153 |
isn't working. --marcus@sysc.pdx.edu. */ |
event.xbutton.button = 1; |
1154 |
event.xbutton.button = 1; |
/* Motif only pops down menus when no Ctrl, Alt or Mod |
1155 |
|
key is pressed and the button is released. So reset key state |
1156 |
|
so Motif thinks this is the case. */ |
1157 |
|
event.xbutton.state = 0; |
1158 |
#endif |
#endif |
1159 |
} |
} |
1160 |
/* If the user presses a key, deactivate the menu. |
/* If the user presses a key, deactivate the menu. |
1161 |
The user is likely to do that if we get wedged. */ |
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 |
else if (event.type == KeyPress |
|
&& dpyinfo->display == event.xbutton.display) |
|
|
{ |
|
|
KeySym keysym = XLookupKeysym (&event.xkey, 0); |
|
|
if (!IsModifierKey (keysym)) |
|
|
{ |
|
|
popup_activated_flag = 0; |
|
|
break; |
|
|
} |
|
|
} |
|
|
/* Button presses outside the menu also pop it down. */ |
|
|
else if (event.type == ButtonPress |
|
|
&& event.xany.display == dpyinfo->display |
|
|
&& x_any_window_to_frame (dpyinfo, event.xany.window)) |
|
|
{ |
|
|
popup_activated_flag = 0; |
|
|
break; |
|
|
} |
|
|
|
|
|
/* Queue all events not for this popup, |
|
|
except for Expose, which we've already handled, and ButtonRelease. |
|
|
Note that the X window is associated with the frame if this |
|
|
is a menu bar popup, but not if it's a dialog box. So we use |
|
|
x_non_menubar_window_to_frame, not x_any_window_to_frame. */ |
|
|
if (event.type != Expose |
|
|
&& !(event.type == ButtonRelease |
|
1164 |
&& dpyinfo->display == event.xbutton.display) |
&& dpyinfo->display == event.xbutton.display) |
1165 |
&& (event.xany.display != dpyinfo->display |
{ |
1166 |
|| x_non_menubar_window_to_frame (dpyinfo, event.xany.window))) |
KeySym keysym = XLookupKeysym (&event.xkey, 0); |
1167 |
{ |
if (!IsModifierKey (keysym)) |
1168 |
queue_tmp = (struct event_queue *) xmalloc (sizeof *queue_tmp); |
popup_activated_flag = 0; |
1169 |
queue_tmp->event = event; |
} |
1170 |
queue_tmp->next = queue; |
|
1171 |
queue = queue_tmp; |
x_dispatch_event (&event, event.xany.display); |
1172 |
} |
} |
1173 |
else |
} |
1174 |
XtDispatchEvent (&event); |
|
1175 |
|
#endif /* USE_X_TOOLKIT */ |
1176 |
|
|
1177 |
|
#ifdef USE_GTK |
1178 |
|
/* Loop util popup_activated_flag is set to zero in a callback. |
1179 |
|
Used for popup menus and dialogs. */ |
1180 |
|
static void |
1181 |
|
popup_widget_loop () |
1182 |
|
{ |
1183 |
|
++popup_activated_flag; |
1184 |
|
|
1185 |
if (!popup_activated ()) |
/* Process events in the Gtk event loop until done. */ |
1186 |
break; |
while (popup_activated_flag) |
1187 |
XtAppNextEvent (Xt_app_con, &event); |
{ |
1188 |
} |
gtk_main_iteration (); |
|
|
|
|
/* Unread any events that we got but did not handle. */ |
|
|
while (queue != NULL) |
|
|
{ |
|
|
queue_tmp = queue; |
|
|
XPutBackEvent (queue_tmp->event.xany.display, &queue_tmp->event); |
|
|
queue = queue_tmp->next; |
|
|
xfree ((char *)queue_tmp); |
|
|
/* Cause these events to get read as soon as we UNBLOCK_INPUT. */ |
|
|
interrupt_input_pending = 1; |
|
1189 |
} |
} |
1190 |
} |
} |
1191 |
|
#endif |
1192 |
|
|
1193 |
/* Activate the menu bar of frame F. |
/* Activate the menu bar of frame F. |
1194 |
This is called from keyboard.c when it gets the |
This is called from keyboard.c when it gets the |
1195 |
menu_bar_activate_event out of the Emacs event queue. |
MENU_BAR_ACTIVATE_EVENT out of the Emacs event queue. |
1196 |
|
|
1197 |
To activate the menu bar, we use the X button-press event |
To activate the menu bar, we use the X button-press event |
1198 |
that was saved in saved_menu_event. |
that was saved in saved_menu_event. |
1203 |
The reason for saving the button event until here, instead of |
The reason for saving the button event until here, instead of |
1204 |
passing it to the toolkit right away, is that we can safely |
passing it to the toolkit right away, is that we can safely |
1205 |
execute Lisp code. */ |
execute Lisp code. */ |
1206 |
|
|
1207 |
void |
void |
1208 |
x_activate_menubar (f) |
x_activate_menubar (f) |
1209 |
FRAME_PTR f; |
FRAME_PTR f; |
1211 |
if (!f->output_data.x->saved_menu_event->type) |
if (!f->output_data.x->saved_menu_event->type) |
1212 |
return; |
return; |
1213 |
|
|
1214 |
|
#ifdef USE_GTK |
1215 |
|
if (! xg_win_to_widget (f->output_data.x->saved_menu_event->xany.window)) |
1216 |
|
return; |
1217 |
|
#endif |
1218 |
|
|
1219 |
set_frame_menubar (f, 0, 1); |
set_frame_menubar (f, 0, 1); |
1220 |
BLOCK_INPUT; |
BLOCK_INPUT; |
1221 |
XtDispatchEvent ((XEvent *) f->output_data.x->saved_menu_event); |
#ifdef USE_GTK |
1222 |
|
XPutBackEvent (f->output_data.x->display_info->display, |
1223 |
|
f->output_data.x->saved_menu_event); |
1224 |
|
popup_activated_flag = 1; |
1225 |
|
#else |
1226 |
|
XtDispatchEvent (f->output_data.x->saved_menu_event); |
1227 |
|
#endif |
1228 |
UNBLOCK_INPUT; |
UNBLOCK_INPUT; |
1229 |
#ifdef USE_MOTIF |
#ifdef USE_MOTIF |
1230 |
if (f->output_data.x->saved_menu_event->type == ButtonRelease) |
if (f->output_data.x->saved_menu_event->type == ButtonRelease) |
1231 |
pending_menu_activation = 1; |
pending_menu_activation = 1; |
1232 |
#endif |
#endif |
1233 |
|
|
1234 |
/* Ignore this if we get it a second time. */ |
/* Ignore this if we get it a second time. */ |
1235 |
f->output_data.x->saved_menu_event->type = 0; |
f->output_data.x->saved_menu_event->type = 0; |
1236 |
} |
} |
1246 |
/* This callback is invoked when the user selects a menubar cascade |
/* This callback is invoked when the user selects a menubar cascade |
1247 |
pushbutton, but before the pulldown menu is posted. */ |
pushbutton, but before the pulldown menu is posted. */ |
1248 |
|
|
1249 |
|
#ifndef USE_GTK |
1250 |
static void |
static void |
1251 |
popup_activate_callback (widget, id, client_data) |
popup_activate_callback (widget, id, client_data) |
1252 |
Widget widget; |
Widget widget; |
1255 |
{ |
{ |
1256 |
popup_activated_flag = 1; |
popup_activated_flag = 1; |
1257 |
} |
} |
1258 |
|
#endif |
1259 |
|
|
1260 |
/* This callback is invoked when a dialog or menu is finished being |
/* This callback is invoked when a dialog or menu is finished being |
1261 |
used and has been unposted. */ |
used and has been unposted. */ |
1262 |
|
|
1263 |
|
#ifdef USE_GTK |
1264 |
|
static void |
1265 |
|
popup_deactivate_callback (widget, client_data) |
1266 |
|
GtkWidget *widget; |
1267 |
|
gpointer client_data; |
1268 |
|
{ |
1269 |
|
popup_activated_flag = 0; |
1270 |
|
} |
1271 |
|
#else |
1272 |
static void |
static void |
1273 |
popup_deactivate_callback (widget, id, client_data) |
popup_deactivate_callback (widget, id, client_data) |
1274 |
Widget widget; |
Widget widget; |
1277 |
{ |
{ |
1278 |
popup_activated_flag = 0; |
popup_activated_flag = 0; |
1279 |
} |
} |
1280 |
|
#endif |
1281 |
|
|
|
/* Lwlib callback called when menu items are highlighted/unhighlighted |
|
|
while moving the mouse over them. WIDGET is the menu bar or menu |
|
|
popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to |
|
|
the widget_value structure for the menu item, or null in case of |
|
|
unhighlighting. */ |
|
1282 |
|
|
1283 |
void |
/* Function that finds the frame for WIDGET and shows the HELP text |
1284 |
menu_highlight_callback (widget, id, call_data) |
for that widget. |
1285 |
Widget widget; |
F is the frame if known, or NULL if not known. */ |
1286 |
LWLIB_ID id; |
static void |
1287 |
void *call_data; |
show_help_event (f, widget, help) |
1288 |
|
FRAME_PTR f; |
1289 |
|
xt_or_gtk_widget widget; |
1290 |
|
Lisp_Object help; |
1291 |
{ |
{ |
1292 |
widget_value *wv = (widget_value *) call_data; |
Lisp_Object frame; |
|
struct frame *f; |
|
|
Lisp_Object frame, help; |
|
1293 |
|
|
|
help = wv ? wv->help : Qnil; |
|
|
|
|
|
/* Determine the frame for the help event. */ |
|
|
f = menubar_id_to_frame (id); |
|
1294 |
if (f) |
if (f) |
1295 |
{ |
{ |
1296 |
XSETFRAME (frame, f); |
XSETFRAME (frame, f); |
1298 |
} |
} |
1299 |
else |
else |
1300 |
{ |
{ |
1301 |
/* WIDGET is the popup menu. It's parent is the frame's |
/* WIDGET is the popup menu. It's parent is the frame's |
1302 |
widget. See which frame that is. */ |
widget. See which frame that is. */ |
1303 |
Widget frame_widget = XtParent (widget); |
xt_or_gtk_widget frame_widget = XtParent (widget); |
1304 |
Lisp_Object tail; |
Lisp_Object tail; |
1305 |
|
|
1306 |
for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail)) |
for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail)) |
1316 |
} |
} |
1317 |
} |
} |
1318 |
|
|
1319 |
/* This callback is called from the menu bar pulldown menu |
/* Callback called when menu items are highlighted/unhighlighted |
1320 |
when the user makes a selection. |
while moving the mouse over them. WIDGET is the menu bar or menu |
1321 |
Figure out what the user chose |
popup widget. ID is its LWLIB_ID. CALL_DATA contains a pointer to |
1322 |
and put the appropriate events into the keyboard buffer. */ |
the data structure for the menu item, or null in case of |
1323 |
|
unhighlighting. */ |
1324 |
|
|
1325 |
static void |
#ifdef USE_GTK |
1326 |
menubar_selection_callback (widget, id, client_data) |
void |
1327 |
|
menu_highlight_callback (widget, call_data) |
1328 |
|
GtkWidget *widget; |
1329 |
|
gpointer call_data; |
1330 |
|
{ |
1331 |
|
xg_menu_item_cb_data *cb_data; |
1332 |
|
Lisp_Object help; |
1333 |
|
|
1334 |
|
cb_data = (xg_menu_item_cb_data*) g_object_get_data (G_OBJECT (widget), |
1335 |
|
XG_ITEM_DATA); |
1336 |
|
if (! cb_data) return; |
1337 |
|
|
1338 |
|
help = call_data ? cb_data->help : Qnil; |
1339 |
|
|
1340 |
|
/* If popup_activated_flag is greater than 1 we are in a popup menu. |
1341 |
|
Don't show help for them, they won't appear before the |
1342 |
|
popup is popped down. */ |
1343 |
|
if (popup_activated_flag <= 1) |
1344 |
|
show_help_event (cb_data->cl_data->f, widget, help); |
1345 |
|
} |
1346 |
|
#else |
1347 |
|
void |
1348 |
|
menu_highlight_callback (widget, id, call_data) |
1349 |
Widget widget; |
Widget widget; |
1350 |
LWLIB_ID id; |
LWLIB_ID id; |
1351 |
XtPointer client_data; |
void *call_data; |
1352 |
|
{ |
1353 |
|
struct frame *f; |
1354 |
|
Lisp_Object help; |
1355 |
|
|
1356 |
|
widget_value *wv = (widget_value *) call_data; |
1357 |
|
|
1358 |
|
help = wv ? wv->help : Qnil; |
1359 |
|
|
1360 |
|
/* Determine the frame for the help event. */ |
1361 |
|
f = menubar_id_to_frame (id); |
1362 |
|
|
1363 |
|
show_help_event (f, widget, help); |
1364 |
|
} |
1365 |
|
#endif |
1366 |
|
|
1367 |
|
/* Find the menu selection and store it in the keyboard buffer. |
1368 |
|
F is the frame the menu is on. |
1369 |
|
MENU_BAR_ITEMS_USED is the length of VECTOR. |
1370 |
|
VECTOR is an array of menu events for the whole menu. |
1371 |
|
*/ |
1372 |
|
void |
1373 |
|
find_and_call_menu_selection (f, menu_bar_items_used, vector, client_data) |
1374 |
|
FRAME_PTR f; |
1375 |
|
int menu_bar_items_used; |
1376 |
|
Lisp_Object vector; |
1377 |
|
void *client_data; |
1378 |
{ |
{ |
1379 |
Lisp_Object prefix, entry; |
Lisp_Object prefix, entry; |
|
FRAME_PTR f = menubar_id_to_frame (id); |
|
|
Lisp_Object vector; |
|
1380 |
Lisp_Object *subprefix_stack; |
Lisp_Object *subprefix_stack; |
1381 |
int submenu_depth = 0; |
int submenu_depth = 0; |
1382 |
int i; |
int i; |
1383 |
|
|
|
if (!f) |
|
|
return; |
|
1384 |
entry = Qnil; |
entry = Qnil; |
1385 |
subprefix_stack = (Lisp_Object *) alloca (f->menu_bar_items_used * sizeof (Lisp_Object)); |
subprefix_stack = (Lisp_Object *) alloca (menu_bar_items_used * sizeof (Lisp_Object)); |
|
vector = f->menu_bar_vector; |
|
1386 |
prefix = Qnil; |
prefix = Qnil; |
1387 |
i = 0; |
i = 0; |
1388 |
while (i < f->menu_bar_items_used) |
|
1389 |
|
while (i < menu_bar_items_used) |
1390 |
{ |
{ |
1391 |
if (EQ (XVECTOR (vector)->contents[i], Qnil)) |
if (EQ (XVECTOR (vector)->contents[i], Qnil)) |
1392 |
{ |
{ |
1450 |
} |
} |
1451 |
} |
} |
1452 |
|
|
1453 |
|
|
1454 |
|
#ifdef USE_GTK |
1455 |
|
/* Gtk calls callbacks just because we tell it what item should be |
1456 |
|
selected in a radio group. If this variable is set to a non-zero |
1457 |
|
value, we are creating menus and don't want callbacks right now. |
1458 |
|
*/ |
1459 |
|
static int xg_crazy_callback_abort; |
1460 |
|
|
1461 |
|
/* This callback is called from the menu bar pulldown menu |
1462 |
|
when the user makes a selection. |
1463 |
|
Figure out what the user chose |
1464 |
|
and put the appropriate events into the keyboard buffer. */ |
1465 |
|
static void |
1466 |
|
menubar_selection_callback (widget, client_data) |
1467 |
|
GtkWidget *widget; |
1468 |
|
gpointer client_data; |
1469 |
|
{ |
1470 |
|
xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data; |
1471 |
|
|
1472 |
|
if (xg_crazy_callback_abort) |
1473 |
|
return; |
1474 |
|
|
1475 |
|
if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f) |
1476 |
|
return; |
1477 |
|
|
1478 |
|
find_and_call_menu_selection (cb_data->cl_data->f, |
1479 |
|
cb_data->cl_data->menu_bar_items_used, |
1480 |
|
cb_data->cl_data->menu_bar_vector, |
1481 |
|
cb_data->call_data); |
1482 |
|
} |
1483 |
|
|
1484 |
|
#else /* not USE_GTK */ |
1485 |
|
|
1486 |
|
/* This callback is called from the menu bar pulldown menu |
1487 |
|
when the user makes a selection. |
1488 |
|
Figure out what the user chose |
1489 |
|
and put the appropriate events into the keyboard buffer. */ |
1490 |
|
static void |
1491 |
|
menubar_selection_callback (widget, id, client_data) |
1492 |
|
Widget widget; |
1493 |
|
LWLIB_ID id; |
1494 |
|
XtPointer client_data; |
1495 |
|
{ |
1496 |
|
FRAME_PTR f; |
1497 |
|
|
1498 |
|
f = menubar_id_to_frame (id); |
1499 |
|
if (!f) |
1500 |
|
return; |
1501 |
|
find_and_call_menu_selection (f, f->menu_bar_items_used, |
1502 |
|
f->menu_bar_vector, client_data); |
1503 |
|
} |
1504 |
|
#endif /* not USE_GTK */ |
1505 |
|
|
1506 |
/* Allocate a widget_value, blocking input. */ |
/* Allocate a widget_value, blocking input. */ |
1507 |
|
|
1508 |
widget_value * |
widget_value * |
1545 |
UNBLOCK_INPUT; |
UNBLOCK_INPUT; |
1546 |
} |
} |
1547 |
|
|
1548 |
/* Return a tree of widget_value structures for a menu bar item |
/* Set up data in menu_items for a menu bar item |
1549 |
whose event type is ITEM_KEY (with string ITEM_NAME) |
whose event type is ITEM_KEY (with string ITEM_NAME) |
1550 |
and whose contents come from the list of keymaps MAPS. */ |
and whose contents come from the list of keymaps MAPS. */ |
1551 |
|
|
1552 |
static widget_value * |
static int |
1553 |
single_submenu (item_key, item_name, maps) |
parse_single_submenu (item_key, item_name, maps) |
1554 |
Lisp_Object item_key, item_name, maps; |
Lisp_Object item_key, item_name, maps; |
1555 |
{ |
{ |
|
widget_value *wv, *prev_wv, *save_wv, *first_wv; |
|
|
int i; |
|
|
int submenu_depth = 0; |
|
1556 |
Lisp_Object length; |
Lisp_Object length; |
1557 |
int len; |
int len; |
1558 |
Lisp_Object *mapvec; |
Lisp_Object *mapvec; |
1559 |
widget_value **submenu_stack; |
int i; |
|
int previous_items = menu_items_used; |
|
1560 |
int top_level_items = 0; |
int top_level_items = 0; |
1561 |
|
|
1562 |
length = Flength (maps); |
length = Flength (maps); |
1570 |
maps = Fcdr (maps); |
maps = Fcdr (maps); |
1571 |
} |
} |
1572 |
|
|
|
menu_items_n_panes = 0; |
|
|
|
|
1573 |
/* Loop over the given keymaps, making a pane for each map. |
/* Loop over the given keymaps, making a pane for each map. |
1574 |
But don't make a pane that is empty--ignore that map instead. */ |
But don't make a pane that is empty--ignore that map instead. */ |
1575 |
for (i = 0; i < len; i++) |
for (i = 0; i < len; i++) |
1576 |
{ |
{ |
1577 |
if (SYMBOLP (mapvec[i]) |
if (!KEYMAPP (mapvec[i])) |
|
|| (CONSP (mapvec[i]) && !KEYMAPP (mapvec[i]))) |
|
1578 |
{ |
{ |
1579 |
/* Here we have a command at top level in the menu bar |
/* Here we have a command at top level in the menu bar |
1580 |
as opposed to a submenu. */ |
as opposed to a submenu. */ |
1584 |
Qnil, Qnil, Qnil, Qnil); |
Qnil, Qnil, Qnil, Qnil); |
1585 |
} |
} |
1586 |
else |
else |
1587 |
single_keymap_panes (mapvec[i], item_name, item_key, 0, 10); |
{ |
1588 |
|
Lisp_Object prompt; |
1589 |
|
prompt = Fkeymap_prompt (mapvec[i]); |
1590 |
|
single_keymap_panes (mapvec[i], |
1591 |
|
!NILP (prompt) ? prompt : item_name, |
1592 |
|
item_key, 0, 10); |
1593 |
|
} |
1594 |
} |
} |
1595 |
|
|
1596 |
/* Create a tree of widget_value objects |
return top_level_items; |
1597 |
representing the panes and their items. */ |
} |
1598 |
|
|
1599 |
|
/* Create a tree of widget_value objects |
1600 |
|
representing the panes and items |
1601 |
|
in menu_items starting at index START, up to index END. */ |
1602 |
|
|
1603 |
|
static widget_value * |
1604 |
|
digest_single_submenu (start, end, top_level_items) |
1605 |
|
int start, end, top_level_items; |
1606 |
|
{ |
1607 |
|
widget_value *wv, *prev_wv, *save_wv, *first_wv; |
1608 |
|
int i; |
1609 |
|
int submenu_depth = 0; |
1610 |
|
widget_value **submenu_stack; |
1611 |
|
|
1612 |
submenu_stack |
submenu_stack |
1613 |
= (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); |
= (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); |
1620 |
first_wv = wv; |
first_wv = wv; |
1621 |
save_wv = 0; |
save_wv = 0; |
1622 |
prev_wv = 0; |
prev_wv = 0; |
1623 |
|
|
1624 |
/* Loop over all panes and items made during this call |
/* Loop over all panes and items made by the preceding call |
1625 |
and construct a tree of widget_value objects. |
to parse_single_submenu and construct a tree of widget_value objects. |
1626 |
Ignore the panes and items made by previous calls to |
Ignore the panes and items used by previous calls to |
1627 |
single_submenu, even though those are also in menu_items. */ |
digest_single_submenu, even though those are also in menu_items. */ |
1628 |
i = previous_items; |
i = start; |
1629 |
while (i < menu_items_used) |
while (i < end) |
1630 |
{ |
{ |
1631 |
if (EQ (XVECTOR (menu_items)->contents[i], Qnil)) |
if (EQ (XVECTOR (menu_items)->contents[i], Qnil)) |
1632 |
{ |
{ |
1653 |
/* Create a new pane. */ |
/* Create a new pane. */ |
1654 |
Lisp_Object pane_name, prefix; |
Lisp_Object pane_name, prefix; |
1655 |
char *pane_string; |
char *pane_string; |
1656 |
|
|
1657 |
pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME]; |
pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME]; |
1658 |
prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; |
prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; |
1659 |
|
|
1660 |
#ifndef HAVE_MULTILINGUAL_MENU |
#ifndef HAVE_MULTILINGUAL_MENU |
1661 |
if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) |
if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) |
1662 |
{ |
{ |
1665 |
} |
} |
1666 |
#endif |
#endif |
1667 |
pane_string = (NILP (pane_name) |
pane_string = (NILP (pane_name) |
1668 |
? "" : (char *) XSTRING (pane_name)->data); |
? "" : (char *) SDATA (pane_name)); |
1669 |
/* If there is just one top-level pane, put all its items directly |
/* If there is just one top-level pane, put all its items directly |
1670 |
under the top-level menu. */ |
under the top-level menu. */ |
1671 |
if (menu_items_n_panes == 1) |
if (menu_items_n_panes == 1) |
1700 |
/* Create a new item within current pane. */ |
/* Create a new item within current pane. */ |
1701 |
Lisp_Object item_name, enable, descrip, def, type, selected; |
Lisp_Object item_name, enable, descrip, def, type, selected; |
1702 |
Lisp_Object help; |
Lisp_Object help; |
1703 |
|
|
1704 |
item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME); |
item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME); |
1705 |
enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE); |
enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE); |
1706 |
descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY); |
descrip = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY); |
1715 |
item_name = ENCODE_SYSTEM (item_name); |
item_name = ENCODE_SYSTEM (item_name); |
1716 |
AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name; |
AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name; |
1717 |
} |
} |
1718 |
|
|
1719 |
if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) |
if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) |
1720 |
{ |
{ |
1721 |
descrip = ENCODE_SYSTEM (descrip); |
descrip = ENCODE_SYSTEM (descrip); |
1724 |
#endif /* not HAVE_MULTILINGUAL_MENU */ |
#endif /* not HAVE_MULTILINGUAL_MENU */ |
1725 |
|
|
1726 |
wv = xmalloc_widget_value (); |
wv = xmalloc_widget_value (); |
1727 |
if (prev_wv) |
if (prev_wv) |
1728 |
prev_wv->next = wv; |
prev_wv->next = wv; |
1729 |
else |
else |
1730 |
save_wv->contents = wv; |
save_wv->contents = wv; |
1731 |
|
|
1732 |
wv->name = (char *) XSTRING (item_name)->data; |
wv->name = (char *) SDATA (item_name); |
1733 |
if (!NILP (descrip)) |
if (!NILP (descrip)) |
1734 |
wv->key = (char *) XSTRING (descrip)->data; |
wv->key = (char *) SDATA (descrip); |
1735 |
wv->value = 0; |
wv->value = 0; |
1736 |
/* The EMACS_INT cast avoids a warning. There's no problem |
/* The EMACS_INT cast avoids a warning. There's no problem |
1737 |
as long as pointers have enough bits to hold small integers. */ |
as long as pointers have enough bits to hold small integers. */ |
1738 |
wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0); |
wv->call_data = (!NILP (def) ? (void *) (EMACS_INT) i : 0); |
1739 |
wv->enabled = !NILP (enable); |
wv->enabled = !NILP (enable); |
1740 |
|
|
1741 |
if (NILP (type)) |
if (NILP (type)) |
1742 |
wv->button_type = BUTTON_TYPE_NONE; |
wv->button_type = BUTTON_TYPE_NONE; |
1743 |
else if (EQ (type, QCradio)) |
else if (EQ (type, QCradio)) |
1770 |
|
|
1771 |
return first_wv; |
return first_wv; |
1772 |
} |
} |
|
|
|
|
|
|
1773 |
|
|
1774 |
/* Recompute all the widgets of frame F, when the menu bar has been |
/* Recompute all the widgets of frame F, when the menu bar has been |
1775 |
changed. Value is non-zero if widgets were updated. */ |
changed. Value is non-zero if widgets were updated. */ |
1778 |
update_frame_menubar (f) |
update_frame_menubar (f) |
1779 |
FRAME_PTR f; |
FRAME_PTR f; |
1780 |
{ |
{ |
1781 |
|
#ifdef USE_GTK |
1782 |
|
return xg_update_frame_menubar (f); |
1783 |
|
#else |
1784 |
struct x_output *x = f->output_data.x; |
struct x_output *x = f->output_data.x; |
1785 |
int columns, rows; |
int columns, rows; |
1786 |
|
|
1787 |
if (!x->menubar_widget || XtIsManaged (x->menubar_widget)) |
if (!x->menubar_widget || XtIsManaged (x->menubar_widget)) |
1788 |
return 0; |
return 0; |
1789 |
|
|
1815 |
/* Force the pane widget to resize itself with the right values. */ |
/* Force the pane widget to resize itself with the right values. */ |
1816 |
EmacsFrameSetCharSize (x->edit_widget, columns, rows); |
EmacsFrameSetCharSize (x->edit_widget, columns, rows); |
1817 |
UNBLOCK_INPUT; |
UNBLOCK_INPUT; |
1818 |
|
#endif |
1819 |
return 1; |
return 1; |
1820 |
} |
} |
1821 |
|
|
1829 |
int first_time; |
int first_time; |
1830 |
int deep_p; |
int deep_p; |
1831 |
{ |
{ |
1832 |
Widget menubar_widget = f->output_data.x->menubar_widget; |
xt_or_gtk_widget menubar_widget = f->output_data.x->menubar_widget; |
1833 |
|
#ifdef USE_X_TOOLKIT |
1834 |
|
LWLIB_ID id; |
1835 |
|
#endif |
1836 |
Lisp_Object items; |
Lisp_Object items; |
1837 |
widget_value *wv, *first_wv, *prev_wv = 0; |
widget_value *wv, *first_wv, *prev_wv = 0; |
1838 |
int i; |
int i, last_i; |
1839 |
|
int *submenu_start, *submenu_end; |
1840 |
|
int *submenu_top_level_items, *submenu_n_panes; |
1841 |
|
|
|
LWLIB_ID id; |
|
1842 |
|
|
1843 |
XSETFRAME (Vmenu_updating_frame, f); |
XSETFRAME (Vmenu_updating_frame, f); |
1844 |
|
|
1845 |
|
#ifdef USE_X_TOOLKIT |
1846 |
if (f->output_data.x->id == 0) |
if (f->output_data.x->id == 0) |
1847 |
f->output_data.x->id = next_menubar_widget_id++; |
f->output_data.x->id = next_menubar_widget_id++; |
1848 |
id = f->output_data.x->id; |
id = f->output_data.x->id; |
1849 |
|
#endif |
1850 |
|
|
1851 |
if (! menubar_widget) |
if (! menubar_widget) |
1852 |
deep_p = 1; |
deep_p = 1; |
1860 |
f->output_data.x->saved_menu_event->type = 0; |
f->output_data.x->saved_menu_event->type = 0; |
1861 |
} |
} |
1862 |
|
|
|
wv = xmalloc_widget_value (); |
|
|
wv->name = "menubar"; |
|
|
wv->value = 0; |
|
|
wv->enabled = 1; |
|
|
wv->button_type = BUTTON_TYPE_NONE; |
|
|
wv->help = Qnil; |
|
|
first_wv = wv; |
|
|
|
|
1863 |
if (deep_p) |
if (deep_p) |
1864 |
{ |
{ |
1865 |
/* Make a widget-value tree representing the entire menu trees. */ |
/* Make a widget-value tree representing the entire menu trees. */ |
1866 |
|
|
1867 |
struct buffer *prev = current_buffer; |
struct buffer *prev = current_buffer; |
1868 |
Lisp_Object buffer; |
Lisp_Object buffer; |
1869 |
int specpdl_count = specpdl_ptr - specpdl; |
int specpdl_count = SPECPDL_INDEX (); |
1870 |
int previous_menu_items_used = f->menu_bar_items_used; |
int previous_menu_items_used = f->menu_bar_items_used; |
1871 |
Lisp_Object *previous_items |
Lisp_Object *previous_items |
1872 |
= (Lisp_Object *) alloca (previous_menu_items_used |
= (Lisp_Object *) alloca (previous_menu_items_used |
1884 |
specbind (Qdebug_on_next_call, Qnil); |
specbind (Qdebug_on_next_call, Qnil); |
1885 |
|
|
1886 |
record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil)); |
record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil)); |
1887 |
|
record_unwind_protect (unuse_menu_items, Qnil); |
1888 |
if (NILP (Voverriding_local_map_menu_flag)) |
if (NILP (Voverriding_local_map_menu_flag)) |
1889 |
{ |
{ |
1890 |
specbind (Qoverriding_terminal_local_map, Qnil); |
specbind (Qoverriding_terminal_local_map, Qnil); |
1895 |
|
|
1896 |
/* Run the Lucid hook. */ |
/* Run the Lucid hook. */ |
1897 |
safe_run_hooks (Qactivate_menubar_hook); |
safe_run_hooks (Qactivate_menubar_hook); |
1898 |
|
|
1899 |
/* If it has changed current-menubar from previous value, |
/* If it has changed current-menubar from previous value, |
1900 |
really recompute the menubar from the value. */ |
really recompute the menubar from the value. */ |
1901 |
if (! NILP (Vlucid_menu_bar_dirty_flag)) |
if (! NILP (Vlucid_menu_bar_dirty_flag)) |
1905 |
|
|
1906 |
items = FRAME_MENU_BAR_ITEMS (f); |
items = FRAME_MENU_BAR_ITEMS (f); |
1907 |
|
|
|
inhibit_garbage_collection (); |
|
|
|
|
1908 |
/* Save the frame's previous menu bar contents data. */ |
/* Save the frame's previous menu bar contents data. */ |
1909 |
if (previous_menu_items_used) |
if (previous_menu_items_used) |
1910 |
bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items, |
bcopy (XVECTOR (f->menu_bar_vector)->contents, previous_items, |
1911 |
previous_menu_items_used * sizeof (Lisp_Object)); |
previous_menu_items_used * sizeof (Lisp_Object)); |
1912 |
|
|
1913 |
/* Fill in the current menu bar contents. */ |
/* Fill in menu_items with the current menu bar contents. |
1914 |
|
This can evaluate Lisp code. */ |
1915 |
menu_items = f->menu_bar_vector; |
menu_items = f->menu_bar_vector; |
1916 |
menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0; |
menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0; |
1917 |
|
submenu_start = (int *) alloca (XVECTOR (items)->size * sizeof (int *)); |
1918 |
|
submenu_end = (int *) alloca (XVECTOR (items)->size * sizeof (int *)); |
1919 |
|
submenu_n_panes = (int *) alloca (XVECTOR (items)->size * sizeof (int)); |
1920 |
|
submenu_top_level_items |
1921 |
|
= (int *) alloca (XVECTOR (items)->size * sizeof (int *)); |
1922 |
init_menu_items (); |
init_menu_items (); |
1923 |
for (i = 0; i < XVECTOR (items)->size; i += 4) |
for (i = 0; i < XVECTOR (items)->size; i += 4) |
1924 |
{ |
{ |
1925 |
Lisp_Object key, string, maps; |
Lisp_Object key, string, maps; |
1926 |
|
|
1927 |
|
last_i = i; |
1928 |
|
|
1929 |
key = XVECTOR (items)->contents[i]; |
key = XVECTOR (items)->contents[i]; |
1930 |
string = XVECTOR (items)->contents[i + 1]; |
string = XVECTOR (items)->contents[i + 1]; |
1931 |
maps = XVECTOR (items)->contents[i + 2]; |
maps = XVECTOR (items)->contents[i + 2]; |
1932 |
if (NILP (string)) |
if (NILP (string)) |
1933 |
break; |
break; |
1934 |
|
|
1935 |
wv = single_submenu (key, string, maps); |
submenu_start[i] = menu_items_used; |
1936 |
if (prev_wv) |
|
1937 |
|
menu_items_n_panes = 0; |
1938 |
|
submenu_top_level_items[i] |
1939 |
|
= parse_single_submenu (key, string, maps); |
1940 |
|
submenu_n_panes[i] = menu_items_n_panes; |
1941 |
|
|
1942 |
|
submenu_end[i] = menu_items_used; |
1943 |
|
} |
1944 |
|
|
1945 |
|
finish_menu_items (); |
1946 |
|
|
1947 |
|
/* Convert menu_items into widget_value trees |
1948 |
|
to display the menu. This cannot evaluate Lisp code. */ |
1949 |
|
|
1950 |
|
wv = xmalloc_widget_value (); |
1951 |
|
wv->name = "menubar"; |
1952 |
|
wv->value = 0; |
1953 |
|
wv->enabled = 1; |
1954 |
|
wv->button_type = BUTTON_TYPE_NONE; |
1955 |
|
wv->help = Qnil; |
1956 |
|
first_wv = wv; |
1957 |
|
|
1958 |
|
for (i = 0; i < last_i; i += 4) |
1959 |
|
{ |
1960 |
|
menu_items_n_panes = submenu_n_panes[i]; |
1961 |
|
wv = digest_single_submenu (submenu_start[i], submenu_end[i], |
1962 |
|
submenu_top_level_items[i]); |
1963 |
|
if (prev_wv) |
1964 |
prev_wv->next = wv; |
prev_wv->next = wv; |
1965 |
else |
else |
1966 |
first_wv->contents = wv; |
first_wv->contents = wv; |
1970 |
prev_wv = wv; |
prev_wv = wv; |
1971 |
} |
} |
1972 |
|
|
|
finish_menu_items (); |
|
|
|
|
1973 |
set_buffer_internal_1 (prev); |
set_buffer_internal_1 (prev); |
1974 |
unbind_to (specpdl_count, Qnil); |
unbind_to (specpdl_count, Qnil); |
1975 |
|
|
1983 |
if (i == menu_items_used && i == previous_menu_items_used && i != 0) |
if (i == menu_items_used && i == previous_menu_items_used && i != 0) |
1984 |
{ |
{ |
1985 |
free_menubar_widget_value_tree (first_wv); |
free_menubar_widget_value_tree (first_wv); |
1986 |
menu_items = Qnil; |
discard_menu_items (); |
1987 |
|
|
1988 |
return; |
return; |
1989 |
} |
} |
1997 |
string = XVECTOR (items)->contents[i + 1]; |
string = XVECTOR (items)->contents[i + 1]; |
1998 |
if (NILP (string)) |
if (NILP (string)) |
1999 |
break; |
break; |
2000 |
wv->name = (char *) XSTRING (string)->data; |
wv->name = (char *) SDATA (string); |
2001 |
wv = wv->next; |
wv = wv->next; |
2002 |
} |
} |
2003 |
|
|
2004 |
f->menu_bar_vector = menu_items; |
f->menu_bar_vector = menu_items; |
2005 |
f->menu_bar_items_used = menu_items_used; |
f->menu_bar_items_used = menu_items_used; |
2006 |
menu_items = Qnil; |
discard_menu_items (); |
2007 |
} |
} |
2008 |
else |
else |
2009 |
{ |
{ |
2010 |
/* Make a widget-value tree containing |
/* Make a widget-value tree containing |
2011 |
just the top level menu bar strings. */ |
just the top level menu bar strings. */ |
2012 |
|
|
2013 |
|
wv = xmalloc_widget_value (); |
2014 |
|
wv->name = "menubar"; |
2015 |
|
wv->value = 0; |
2016 |
|
wv->enabled = 1; |
2017 |
|
wv->button_type = BUTTON_TYPE_NONE; |
2018 |
|
wv->help = Qnil; |
2019 |
|
first_wv = wv; |
2020 |
|
|
2021 |
items = FRAME_MENU_BAR_ITEMS (f); |
items = FRAME_MENU_BAR_ITEMS (f); |
2022 |
for (i = 0; i < XVECTOR (items)->size; i += 4) |
for (i = 0; i < XVECTOR (items)->size; i += 4) |
2023 |
{ |
{ |
2028 |
break; |
break; |
2029 |
|
|
2030 |
wv = xmalloc_widget_value (); |
wv = xmalloc_widget_value (); |
2031 |
wv->name = (char *) XSTRING (string)->data; |
wv->name = (char *) SDATA (string); |
2032 |
wv->value = 0; |
wv->value = 0; |
2033 |
wv->enabled = 1; |
wv->enabled = 1; |
2034 |
wv->button_type = BUTTON_TYPE_NONE; |
wv->button_type = BUTTON_TYPE_NONE; |
2039 |
This value just has to be different from small integers. */ |
This value just has to be different from small integers. */ |
2040 |
wv->call_data = (void *) (EMACS_INT) (-1); |
wv->call_data = (void *) (EMACS_INT) (-1); |
2041 |
|
|
2042 |
if (prev_wv) |
if (prev_wv) |
2043 |
prev_wv->next = wv; |
prev_wv->next = wv; |
2044 |
else |
else |
2045 |
first_wv->contents = wv; |
first_wv->contents = wv; |
2056 |
|
|
2057 |
BLOCK_INPUT; |
BLOCK_INPUT; |
2058 |
|
|
2059 |
|
#ifdef USE_GTK |
2060 |
|
xg_crazy_callback_abort = 1; |
2061 |
|
if (menubar_widget) |
2062 |
|
{ |
2063 |
|
/* The third arg is DEEP_P, which says to consider the entire |
2064 |
|
menu trees we supply, rather than just the menu bar item names. */ |
2065 |
|
xg_modify_menubar_widgets (menubar_widget, |
2066 |
|
f, |
2067 |
|
first_wv, |
2068 |
|
deep_p, |
2069 |
|
G_CALLBACK (menubar_selection_callback), |
2070 |
|
G_CALLBACK (popup_deactivate_callback), |
2071 |
|
G_CALLBACK (menu_highlight_callback)); |
2072 |
|
} |
2073 |
|
else |
2074 |
|
{ |
2075 |
|
GtkWidget *wvbox = f->output_data.x->vbox_widget; |
2076 |
|
|
2077 |
|
menubar_widget |
2078 |
|
= xg_create_widget ("menubar", "menubar", f, first_wv, |
2079 |
|
G_CALLBACK (menubar_selection_callback), |
2080 |
|
G_CALLBACK (popup_deactivate_callback), |
2081 |
|
G_CALLBACK (menu_highlight_callback)); |
2082 |
|
|
2083 |
|
f->output_data.x->menubar_widget = menubar_widget; |
2084 |
|
} |
2085 |
|
|
2086 |
|
|
2087 |
|
#else /* not USE_GTK */ |
2088 |
if (menubar_widget) |
if (menubar_widget) |
2089 |
{ |
{ |
2090 |
/* Disable resizing (done for Motif!) */ |
/* Disable resizing (done for Motif!) */ |
2099 |
} |
} |
2100 |
else |
else |
2101 |
{ |
{ |
2102 |
menubar_widget = lw_create_widget ("menubar", "menubar", id, first_wv, |
menubar_widget = lw_create_widget ("menubar", "menubar", id, first_wv, |
2103 |
f->output_data.x->column_widget, |
f->output_data.x->column_widget, |
2104 |
0, |
0, |
2105 |
popup_activate_callback, |
popup_activate_callback, |
2110 |
} |
} |
2111 |
|
|
2112 |
{ |
{ |
2113 |
int menubar_size |
int menubar_size |
2114 |
= (f->output_data.x->menubar_widget |
= (f->output_data.x->menubar_widget |
2115 |
? (f->output_data.x->menubar_widget->core.height |
? (f->output_data.x->menubar_widget->core.height |
2116 |
+ f->output_data.x->menubar_widget->core.border_width) |
+ f->output_data.x->menubar_widget->core.border_width) |
2131 |
|
|
2132 |
f->output_data.x->menubar_height = menubar_size; |
f->output_data.x->menubar_height = menubar_size; |
2133 |
} |
} |
2134 |
|
#endif /* not USE_GTK */ |
2135 |
|
|
2136 |
free_menubar_widget_value_tree (first_wv); |
free_menubar_widget_value_tree (first_wv); |
2137 |
update_frame_menubar (f); |
update_frame_menubar (f); |
2138 |
|
|
2139 |
|
#ifdef USE_GTK |
2140 |
|
xg_crazy_callback_abort = 0; |
2141 |
|
#endif |
2142 |
|
|
2143 |
UNBLOCK_INPUT; |
UNBLOCK_INPUT; |
2144 |
} |
} |
2145 |
|
|
2160 |
|
|
2161 |
|
|
2162 |
/* Get rid of the menu bar of frame F, and free its storage. |
/* Get rid of the menu bar of frame F, and free its storage. |
2163 |
This is used when deleting a frame, and when turning off the menu bar. */ |
This is used when deleting a frame, and when turning off the menu bar. |
2164 |
|
For GTK this function is in gtkutil.c. */ |
2165 |
|
|
2166 |
|
#ifndef USE_GTK |
2167 |
void |
void |
2168 |
free_frame_menubar (f) |
free_frame_menubar (f) |
2169 |
FRAME_PTR f; |
FRAME_PTR f; |
2173 |
menubar_widget = f->output_data.x->menubar_widget; |
menubar_widget = f->output_data.x->menubar_widget; |
2174 |
|
|
2175 |
f->output_data.x->menubar_height = 0; |
f->output_data.x->menubar_height = 0; |
2176 |
|
|
2177 |
if (menubar_widget) |
if (menubar_widget) |
2178 |
{ |
{ |
2179 |
#ifdef USE_MOTIF |
#ifdef USE_MOTIF |
2187 |
is switched off, which fixes the shell position. */ |
is switched off, which fixes the shell position. */ |
2188 |
Position x0, y0, x1, y1; |
Position x0, y0, x1, y1; |
2189 |
#endif |
#endif |
2190 |
|
|
2191 |
BLOCK_INPUT; |
BLOCK_INPUT; |
2192 |
|
|
2193 |
#ifdef USE_MOTIF |
#ifdef USE_MOTIF |
2194 |
if (f->output_data.x->widget) |
if (f->output_data.x->widget) |
2195 |
XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL); |
XtVaGetValues (f->output_data.x->widget, XtNx, &x0, XtNy, &y0, NULL); |
2196 |
#endif |
#endif |
2197 |
|
|
2198 |
lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id); |
lw_destroy_all_widgets ((LWLIB_ID) f->output_data.x->id); |
2199 |
f->output_data.x->menubar_widget = NULL; |
f->output_data.x->menubar_widget = NULL; |
2200 |
|
|
2206 |
XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL); |
XtVaSetValues (f->output_data.x->widget, XtNx, x0, XtNy, y0, NULL); |
2207 |
} |
} |
2208 |
#endif |
#endif |
2209 |
|
|
2210 |
UNBLOCK_INPUT; |
UNBLOCK_INPUT; |
2211 |
} |
} |
2212 |
} |
} |
2213 |
|
#endif /* not USE_GTK */ |
2214 |
|
|
2215 |
#endif /* USE_X_TOOLKIT */ |
#endif /* USE_X_TOOLKIT || USE_GTK */ |
2216 |
|
|
2217 |
/* xmenu_show actually displays a menu using the panes and items in menu_items |
/* xmenu_show actually displays a menu using the panes and items in menu_items |
2218 |
and returns the value selected from it. |
and returns the value selected from it. |
2230 |
ERROR is a place to store an error message string in case of failure. |
ERROR is a place to store an error message string in case of failure. |
2231 |
(We return nil on failure, but the value doesn't actually matter.) */ |
(We return nil on failure, but the value doesn't actually matter.) */ |
2232 |
|
|
2233 |
#ifdef USE_X_TOOLKIT |
#if defined (USE_X_TOOLKIT) || defined (USE_GTK) |
2234 |
|
|
2235 |
|
/* The item selected in the popup menu. */ |
2236 |
|
static Lisp_Object *volatile menu_item_selection; |
2237 |
|
|
2238 |
|
#ifdef USE_GTK |
2239 |
|
|
2240 |
|
/* Used when position a popup menu. See menu_position_func and |
2241 |
|
create_and_show_popup_menu below. */ |
2242 |
|
struct next_popup_x_y |
2243 |
|
{ |
2244 |
|
FRAME_PTR f; |
2245 |
|
int x; |
2246 |
|
int y; |
2247 |
|
}; |
2248 |
|
|
2249 |
|
/* The menu position function to use if we are not putting a popup |
2250 |
|
menu where the pointer is. |
2251 |
|
MENU is the menu to pop up. |
2252 |
|
X and Y shall on exit contain x/y where the menu shall pop up. |
2253 |
|
PUSH_IN is not documented in the GTK manual. |
2254 |
|
USER_DATA is any data passed in when calling gtk_menu_popup. |
2255 |
|
Here it points to a struct next_popup_x_y where the coordinates |
2256 |
|
to store in *X and *Y are as well as the frame for the popup. |
2257 |
|
|
2258 |
|
Here only X and Y are used. */ |
2259 |
|
static void |
2260 |
|
menu_position_func (menu, x, y, push_in, user_data) |
2261 |
|
GtkMenu *menu; |
2262 |
|
gint *x; |
2263 |
|
gint *y; |
2264 |
|
gboolean *push_in; |
2265 |
|
gpointer user_data; |
2266 |
|
{ |
2267 |
|
struct next_popup_x_y* data = (struct next_popup_x_y*)user_data; |
2268 |
|
GtkRequisition req; |
2269 |
|
int disp_width = FRAME_X_DISPLAY_INFO (data->f)->width; |
2270 |
|
int disp_height = FRAME_X_DISPLAY_INFO (data->f)->height; |
2271 |
|
|
2272 |
|
*x = data->x; |
2273 |
|
*y = data->y; |
2274 |
|
|
2275 |
|
/* Check if there is room for the menu. If not, adjust x/y so that |
2276 |
|
the menu is fully visible. */ |
2277 |
|
gtk_widget_size_request (GTK_WIDGET (menu), &req); |
2278 |
|
if (data->x + req.width > disp_width) |
2279 |
|
*x -= data->x + req.width - disp_width; |
2280 |
|
if (data->y + req.height > disp_height) |
2281 |
|
*y -= data->y + req.height - disp_height; |
2282 |
|
} |
2283 |
|
|
2284 |
|
static void |
2285 |
|
popup_selection_callback (widget, client_data) |
2286 |
|
GtkWidget *widget; |
2287 |
|
gpointer client_data; |
2288 |
|
{ |
2289 |
|
xg_menu_item_cb_data *cb_data = (xg_menu_item_cb_data*) client_data; |
2290 |
|
|
2291 |
|
if (xg_crazy_callback_abort) return; |
2292 |
|
if (cb_data) menu_item_selection = (Lisp_Object *) cb_data->call_data; |
2293 |
|
} |
2294 |
|
|
2295 |
|
/* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the |
2296 |
|
menu pops down. |
2297 |
|
menu_item_selection will be set to the selection. */ |
2298 |
|
static void |
2299 |
|
create_and_show_popup_menu (f, first_wv, x, y, for_click) |
2300 |
|
FRAME_PTR f; |
2301 |
|
widget_value *first_wv; |
2302 |
|
int x; |
2303 |
|
int y; |
2304 |
|
int for_click; |
2305 |
|
{ |
2306 |
|
int i; |
2307 |
|
GtkWidget *menu; |
2308 |
|
GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */ |
2309 |
|
struct next_popup_x_y popup_x_y; |
2310 |
|
|
2311 |
|
xg_crazy_callback_abort = 1; |
2312 |
|
menu = xg_create_widget ("popup", first_wv->name, f, first_wv, |
2313 |
|
G_CALLBACK (popup_selection_callback), |
2314 |
|
G_CALLBACK (popup_deactivate_callback), |
2315 |
|
G_CALLBACK (menu_highlight_callback)); |
2316 |
|
xg_crazy_callback_abort = 0; |
2317 |
|
|
2318 |
|
for (i = 0; i < 5; i++) |
2319 |
|
if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i)) |
2320 |
|
break; |
2321 |
|
|
2322 |
|
if (! for_click) |
2323 |
|
{ |
2324 |
|
/* Not invoked by a click. pop up at x/y. */ |
2325 |
|
pos_func = menu_position_func; |
2326 |
|
|
2327 |
|
/* Adjust coordinates to be root-window-relative. */ |
2328 |
|
x += f->output_data.x->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); |
2329 |
|
y += f->output_data.x->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); |
2330 |
|
|
2331 |
|
popup_x_y.x = x; |
2332 |
|
popup_x_y.y = y; |
2333 |
|
popup_x_y.f = f; |
2334 |
|
} |
2335 |
|
|
2336 |
|
/* Display the menu. */ |
2337 |
|
gtk_widget_show_all (menu); |
2338 |
|
gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i, 0); |
2339 |
|
|
2340 |
|
xg_did_tearoff = 0; |
2341 |
|
/* Set this to one. popup_widget_loop increases it by one, so it becomes |
2342 |
|
two. show_help_echo uses this to detect popup menus. */ |
2343 |
|
popup_activated_flag = 1; |
2344 |
|
/* Process events that apply to the menu. */ |
2345 |
|
popup_widget_loop (); |
2346 |
|
|
2347 |
|
if (xg_did_tearoff) |
2348 |
|
xg_keep_popup (menu, xg_did_tearoff); |
2349 |
|
else |
2350 |
|
gtk_widget_destroy (menu); |
2351 |
|
|
2352 |
|
/* Must reset this manually because the button release event is not passed |
2353 |
|
to Emacs event loop. */ |
2354 |
|
FRAME_X_DISPLAY_INFO (f)->grabbed = 0; |
2355 |
|
} |
2356 |
|
|
2357 |
|
#else /* not USE_GTK */ |
2358 |
|
|
2359 |
/* We need a unique id for each widget handled by the Lucid Widget |
/* We need a unique id for each widget handled by the Lucid Widget |
2360 |
library. |
library. |
2366 |
next_menubar_widget_id. */ |
next_menubar_widget_id. */ |
2367 |
LWLIB_ID widget_id_tick; |
LWLIB_ID widget_id_tick; |
2368 |
|
|
|
static Lisp_Object *volatile menu_item_selection; |
|
|
|
|
2369 |
static void |
static void |
2370 |
popup_selection_callback (widget, id, client_data) |
popup_selection_callback (widget, id, client_data) |
2371 |
Widget widget; |
Widget widget; |
2375 |
menu_item_selection = (Lisp_Object *) client_data; |
menu_item_selection = (Lisp_Object *) client_data; |
2376 |
} |
} |
2377 |
|
|
2378 |
|
/* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the |
2379 |
|
menu pops down. |
2380 |
|
menu_item_selection will be set to the selection. */ |
2381 |
|
static void |
2382 |
|
create_and_show_popup_menu (f, first_wv, x, y, for_click) |
2383 |
|
FRAME_PTR f; |
2384 |
|
widget_value *first_wv; |
2385 |
|
int x; |
2386 |
|
int y; |
2387 |
|
int for_click; |
2388 |
|
{ |
2389 |
|
int i; |
2390 |
|
Arg av[2]; |
2391 |
|
int ac = 0; |
2392 |
|
XButtonPressedEvent dummy; |
2393 |
|
LWLIB_ID menu_id; |
2394 |
|
Widget menu; |
2395 |
|
Window child; |
2396 |
|
|
2397 |
|
menu_id = widget_id_tick++; |
2398 |
|
menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv, |
2399 |
|
f->output_data.x->widget, 1, 0, |
2400 |
|
popup_selection_callback, |
2401 |
|
popup_deactivate_callback, |
2402 |
|
menu_highlight_callback); |
2403 |
|
|
2404 |
|
dummy.type = ButtonPress; |
2405 |
|
dummy.serial = 0; |
2406 |
|
dummy.send_event = 0; |
2407 |
|
dummy.display = FRAME_X_DISPLAY (f); |
2408 |
|
dummy.time = CurrentTime; |
2409 |
|
dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window; |
2410 |
|
dummy.window = dummy.root; |
2411 |
|
dummy.subwindow = dummy.root; |
2412 |
|
dummy.x = x; |
2413 |
|
dummy.y = y; |
2414 |
|
|
2415 |
|
/* Adjust coordinates to be root-window-relative. */ |
2416 |
|
x += f->output_data.x->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); |
2417 |
|
y += f->output_data.x->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); |
2418 |
|
|
2419 |
|
dummy.x_root = x; |
2420 |
|
dummy.y_root = y; |
2421 |
|
|
2422 |
|
dummy.state = 0; |
2423 |
|
dummy.button = 0; |
2424 |
|
for (i = 0; i < 5; i++) |
2425 |
|
if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i)) |
2426 |
|
dummy.button = i; |
2427 |
|
|
2428 |
|
/* Don't allow any geometry request from the user. */ |
2429 |
|
XtSetArg (av[ac], XtNgeometry, 0); ac++; |
2430 |
|
XtSetValues (menu, av, ac); |
2431 |
|
|
2432 |
|
/* Display the menu. */ |
2433 |
|
lw_popup_menu (menu, (XEvent *) &dummy); |
2434 |
|
popup_activated_flag = 1; |
2435 |
|
|
2436 |
|
/* Process events that apply to the menu. */ |
2437 |
|
popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 0); |
2438 |
|
|
2439 |
|
/* fp turned off the following statement and wrote a comment |
2440 |
|
that it is unnecessary--that the menu has already disappeared. |
2441 |
|
Nowadays the menu disappears ok, all right, but |
2442 |
|
we need to delete the widgets or multiple ones will pile up. */ |
2443 |
|
lw_destroy_all_widgets (menu_id); |
2444 |
|
} |
2445 |
|
|
2446 |
|
#endif /* not USE_GTK */ |
2447 |
|
|
2448 |
static Lisp_Object |
static Lisp_Object |
2449 |
xmenu_show (f, x, y, for_click, keymaps, title, error) |
xmenu_show (f, x, y, for_click, keymaps, title, error) |
2450 |
FRAME_PTR f; |
FRAME_PTR f; |
2456 |
char **error; |
char **error; |
2457 |
{ |
{ |
2458 |
int i; |
int i; |
|
LWLIB_ID menu_id; |
|
|
Widget menu; |
|
|
Arg av[2]; |
|
|
int ac = 0; |
|
2459 |
widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; |
widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; |
2460 |
widget_value **submenu_stack |
widget_value **submenu_stack |
2461 |
= (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); |
= (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); |
2462 |
Lisp_Object *subprefix_stack |
Lisp_Object *subprefix_stack |
2463 |
= (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object)); |
= (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object)); |
2464 |
int submenu_depth = 0; |
int submenu_depth = 0; |
|
XButtonPressedEvent dummy; |
|
2465 |
|
|
2466 |
int first_pane; |
int first_pane; |
2467 |
|
|
2483 |
wv->help =Qnil; |
wv->help =Qnil; |
2484 |
first_wv = wv; |
first_wv = wv; |
2485 |
first_pane = 1; |
first_pane = 1; |
2486 |
|
|
2487 |
/* Loop over all panes and items, filling in the tree. */ |
/* Loop over all panes and items, filling in the tree. */ |
2488 |
i = 0; |
i = 0; |
2489 |
while (i < menu_items_used) |
while (i < menu_items_used) |
2515 |
/* Create a new pane. */ |
/* Create a new pane. */ |
2516 |
Lisp_Object pane_name, prefix; |
Lisp_Object pane_name, prefix; |
2517 |
char *pane_string; |
char *pane_string; |
2518 |
|
|
2519 |
pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME); |
pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME); |
2520 |
prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); |
prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); |
2521 |
|
|
2522 |
#ifndef HAVE_MULTILINGUAL_MENU |
#ifndef HAVE_MULTILINGUAL_MENU |
2523 |
if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) |
if (STRINGP (pane_name) && STRING_MULTIBYTE (pane_name)) |
2524 |
{ |
{ |
2527 |
} |
} |
2528 |
#endif |
#endif |
2529 |
pane_string = (NILP (pane_name) |
pane_string = (NILP (pane_name) |
2530 |
? "" : (char *) XSTRING (pane_name)->data); |
? "" : (char *) SDATA (pane_name)); |
2531 |
/* If there is just one top-level pane, put all its items directly |
/* If there is just one top-level pane, put all its items directly |
2532 |
under the top-level menu. */ |
under the top-level menu. */ |
2533 |
if (menu_items_n_panes == 1) |
if (menu_items_n_panes == 1) |
2579 |
item_name = ENCODE_SYSTEM (item_name); |
item_name = ENCODE_SYSTEM (item_name); |
2580 |
AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name; |
AREF (menu_items, i + MENU_ITEMS_ITEM_NAME) = item_name; |
2581 |
} |
} |
2582 |
|
|
2583 |
if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) |
if (STRINGP (descrip) && STRING_MULTIBYTE (descrip)) |
2584 |
{ |
{ |
2585 |
descrip = ENCODE_SYSTEM (descrip); |
descrip = ENCODE_SYSTEM (descrip); |
2586 |
AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip; |
AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY) = descrip; |
2587 |
} |
} |
2588 |
#endif /* not HAVE_MULTILINGUAL_MENU */ |
#endif /* not HAVE_MULTILINGUAL_MENU */ |
2589 |
|
|
2590 |
wv = xmalloc_widget_value (); |
wv = xmalloc_widget_value (); |
2591 |
if (prev_wv) |
if (prev_wv) |
2592 |
prev_wv->next = wv; |
prev_wv->next = wv; |
2593 |
else |
else |
2594 |
save_wv->contents = wv; |
save_wv->contents = wv; |
2595 |
wv->name = (char *) XSTRING (item_name)->data; |
wv->name = (char *) SDATA (item_name); |
2596 |
if (!NILP (descrip)) |
if (!NILP (descrip)) |
2597 |
wv->key = (char *) XSTRING (descrip)->data; |
wv->key = (char *) SDATA (descrip); |
2598 |
wv->value = 0; |
wv->value = 0; |
2599 |
/* If this item has a null value, |
/* If this item has a null value, |
2600 |
make the call_data null so that it won't display a box |
make the call_data null so that it won't display a box |
2644 |
if (STRING_MULTIBYTE (title)) |
if (STRING_MULTIBYTE (title)) |
2645 |
title = ENCODE_SYSTEM (title); |
title = ENCODE_SYSTEM (title); |
2646 |
#endif |
#endif |
2647 |
|
|
2648 |
wv_title->name = (char *) XSTRING (title)->data; |
wv_title->name = (char *) SDATA (title); |
2649 |
wv_title->enabled = TRUE; |
wv_title->enabled = TRUE; |
2650 |
wv_title->button_type = BUTTON_TYPE_NONE; |
wv_title->button_type = BUTTON_TYPE_NONE; |
2651 |
wv_title->next = wv_sep1; |
wv_title->next = wv_sep1; |
2653 |
first_wv->contents = wv_title; |
first_wv->contents = wv_title; |
2654 |
} |
} |
2655 |
|
|
|
/* Actually create the menu. */ |
|
|
menu_id = widget_id_tick++; |
|
|
menu = lw_create_widget ("popup", first_wv->name, menu_id, first_wv, |
|
|
f->output_data.x->widget, 1, 0, |
|
|
popup_selection_callback, |
|
|
popup_deactivate_callback, |
|
|
menu_highlight_callback); |
|
|
|
|
|
/* Adjust coordinates to relative to the outer (window manager) window. */ |
|
|
{ |
|
|
Window child; |
|
|
int win_x = 0, win_y = 0; |
|
|
|
|
|
/* Find the position of the outside upper-left corner of |
|
|
the inner window, with respect to the outer window. */ |
|
|
if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window) |
|
|
{ |
|
|
BLOCK_INPUT; |
|
|
XTranslateCoordinates (FRAME_X_DISPLAY (f), |
|
|
|
|
|
/* From-window, to-window. */ |
|
|
f->output_data.x->window_desc, |
|
|
f->output_data.x->parent_desc, |
|
|
|
|
|
/* From-position, to-position. */ |
|
|
0, 0, &win_x, &win_y, |
|
|
|
|
|
/* Child of window. */ |
|
|
&child); |
|
|
UNBLOCK_INPUT; |
|
|
x += win_x; |
|
|
y += win_y; |
|
|
} |
|
|
} |
|
|
|
|
|
/* Adjust coordinates to be root-window-relative. */ |
|
|
x += f->output_data.x->left_pos; |
|
|
y += f->output_data.x->top_pos; |
|
|
|
|
|
dummy.type = ButtonPress; |
|
|
dummy.serial = 0; |
|
|
dummy.send_event = 0; |
|
|
dummy.display = FRAME_X_DISPLAY (f); |
|
|
dummy.time = CurrentTime; |
|
|
dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window; |
|
|
dummy.window = dummy.root; |
|
|
dummy.subwindow = dummy.root; |
|
|
dummy.x_root = x; |
|
|
dummy.y_root = y; |
|
|
dummy.x = x; |
|
|
dummy.y = y; |
|
|
dummy.state = (FRAME_X_DISPLAY_INFO (f)->grabbed >> 1) * Button1Mask; |
|
|
dummy.button = 0; |
|
|
for (i = 0; i < 5; i++) |
|
|
if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i)) |
|
|
dummy.button = i; |
|
|
|
|
|
/* Don't allow any geometry request from the user. */ |
|
|
XtSetArg (av[ac], XtNgeometry, 0); ac++; |
|
|
XtSetValues (menu, av, ac); |
|
|
|
|
|
/* Free the widget_value objects we used to specify the contents. */ |
|
|
free_menubar_widget_value_tree (first_wv); |
|
|
|
|
2656 |
/* No selection has been chosen yet. */ |
/* No selection has been chosen yet. */ |
2657 |
menu_item_selection = 0; |
menu_item_selection = 0; |
2658 |
|
|
2659 |
/* Display the menu. */ |
/* Actually create and show the menu until popped down. */ |
2660 |
lw_popup_menu (menu, (XEvent *) &dummy); |
create_and_show_popup_menu (f, first_wv, x, y, for_click); |
|
popup_activated_flag = 1; |
|
2661 |
|
|
2662 |
/* Process events that apply to the menu. */ |
/* Free the widget_value objects we used to specify the contents. */ |
2663 |
popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id); |
free_menubar_widget_value_tree (first_wv); |
|
|
|
|
/* fp turned off the following statement and wrote a comment |
|
|
that it is unnecessary--that the menu has already disappeared. |
|
|
Nowadays the menu disappears ok, all right, but |
|
|
we need to delete the widgets or multiple ones will pile up. */ |
|
|
lw_destroy_all_widgets (menu_id); |
|
2664 |
|
|
2665 |
/* Find the selected item, and its pane, to return |
/* Find the selected item, and its pane, to return |
2666 |
the proper value. */ |
the proper value. */ |
2720 |
return Qnil; |
return Qnil; |
2721 |
} |
} |
2722 |
|
|
2723 |
|
#ifdef USE_GTK |
2724 |
|
static void |
2725 |
|
dialog_selection_callback (widget, client_data) |
2726 |
|
GtkWidget *widget; |
2727 |
|
gpointer client_data; |
2728 |
|
{ |
2729 |
|
/* The EMACS_INT cast avoids a warning. There's no problem |
2730 |
|
as long as pointers have enough bits to hold small integers. */ |
2731 |
|
if ((int) (EMACS_INT) client_data != -1) |
2732 |
|
menu_item_selection = (Lisp_Object *) client_data; |
2733 |
|
|
2734 |
|
popup_activated_flag = 0; |
2735 |
|
} |
2736 |
|
|
2737 |
|
/* Pop up the dialog for frame F defined by FIRST_WV and loop until the |
2738 |
|
dialog pops down. |
2739 |
|
menu_item_selection will be set to the selection. */ |
2740 |
|
static void |
2741 |
|
create_and_show_dialog (f, first_wv) |
2742 |
|
FRAME_PTR f; |
2743 |
|
widget_value *first_wv; |
2744 |
|
{ |
2745 |
|
GtkWidget *menu; |
2746 |
|
|
2747 |
|
menu = xg_create_widget ("dialog", first_wv->name, f, first_wv, |
2748 |
|
G_CALLBACK (dialog_selection_callback), |
2749 |
|
G_CALLBACK (popup_deactivate_callback), |
2750 |
|
0); |
2751 |
|
|
2752 |
|
if (menu) |
2753 |
|
{ |
2754 |
|
/* Display the menu. */ |
2755 |
|
gtk_widget_show_all (menu); |
2756 |
|
|
2757 |
|
/* Process events that apply to the menu. */ |
2758 |
|
popup_widget_loop (); |
2759 |
|
|
2760 |
|
gtk_widget_destroy (menu); |
2761 |
|
} |
2762 |
|
} |
2763 |
|
|
2764 |
|
#else /* not USE_GTK */ |
2765 |
static void |
static void |
2766 |
dialog_selection_callback (widget, id, client_data) |
dialog_selection_callback (widget, id, client_data) |
2767 |
Widget widget; |
Widget widget; |
2772 |
as long as pointers have enough bits to hold small integers. */ |
as long as pointers have enough bits to hold small integers. */ |
2773 |
if ((int) (EMACS_INT) client_data != -1) |
if ((int) (EMACS_INT) client_data != -1) |
2774 |
menu_item_selection = (Lisp_Object *) client_data; |
menu_item_selection = (Lisp_Object *) client_data; |
2775 |
|
|
2776 |
BLOCK_INPUT; |
BLOCK_INPUT; |
2777 |
lw_destroy_all_widgets (id); |
lw_destroy_all_widgets (id); |
2778 |
UNBLOCK_INPUT; |
UNBLOCK_INPUT; |
2779 |
popup_activated_flag = 0; |
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 |
|
} |
2798 |
|
|
2799 |
|
|
2800 |
|
/* Pop up the dialog for frame F defined by FIRST_WV and loop until the |
2801 |
|
dialog pops down. |
2802 |
|
menu_item_selection will be set to the selection. */ |
2803 |
|
static void |
2804 |
|
create_and_show_dialog (f, first_wv) |
2805 |
|
FRAME_PTR f; |
2806 |
|
widget_value *first_wv; |
2807 |
|
{ |
2808 |
|
LWLIB_ID dialog_id; |
2809 |
|
|
2810 |
|
dialog_id = widget_id_tick++; |
2811 |
|
lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv, |
2812 |
|
f->output_data.x->widget, 1, 0, |
2813 |
|
dialog_selection_callback, 0, 0); |
2814 |
|
lw_modify_all_widgets (dialog_id, first_wv->contents, True); |
2815 |
|
|
2816 |
|
/* Display the dialog box. */ |
2817 |
|
lw_pop_up_all_widgets (dialog_id); |
2818 |
|
popup_activated_flag = 1; |
2819 |
|
|
2820 |
|
/* Process events that apply to the dialog box. |
2821 |
|
Also handle timers. */ |
2822 |
|
{ |
2823 |
|
int count = SPECPDL_INDEX (); |
2824 |
|
int fact = 4 * sizeof (LWLIB_ID); |
2825 |
|
|
2826 |
|
/* xdialog_show_unwind is responsible for popping the dialog box down. */ |
2827 |
|
record_unwind_protect (xdialog_show_unwind, |
2828 |
|
Fcons (make_number (dialog_id >> (fact)), |
2829 |
|
make_number (dialog_id & ~(-1 << (fact))))); |
2830 |
|
|
2831 |
|
popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id, 1); |
2832 |
|
|
2833 |
|
unbind_to (count, Qnil); |
2834 |
|
} |
2835 |
|
} |
2836 |
|
|
2837 |
|
#endif /* not USE_GTK */ |
2838 |
|
|
2839 |
static char * button_names [] = { |
static char * button_names [] = { |
2840 |
"button1", "button2", "button3", "button4", "button5", |
"button1", "button2", "button3", "button4", "button5", |
2841 |
"button6", "button7", "button8", "button9", "button10" }; |
"button6", "button7", "button8", "button9", "button10" }; |
2848 |
char **error; |
char **error; |
2849 |
{ |
{ |
2850 |
int i, nb_buttons=0; |
int i, nb_buttons=0; |
|
LWLIB_ID dialog_id; |
|
|
Widget menu; |
|
2851 |
char dialog_name[6]; |
char dialog_name[6]; |
2852 |
|
|
2853 |
widget_value *wv, *first_wv = 0, *prev_wv = 0; |
widget_value *wv, *first_wv = 0, *prev_wv = 0; |
2873 |
pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME]; |
pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME]; |
2874 |
prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX]; |
prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX]; |
2875 |
pane_string = (NILP (pane_name) |
pane_string = (NILP (pane_name) |
2876 |
? "" : (char *) XSTRING (pane_name)->data); |
? "" : (char *) SDATA (pane_name)); |
2877 |
prev_wv = xmalloc_widget_value (); |
prev_wv = xmalloc_widget_value (); |
2878 |
prev_wv->value = pane_string; |
prev_wv->value = pane_string; |
2879 |
if (keymaps && !NILP (prefix)) |
if (keymaps && !NILP (prefix)) |
2882 |
prev_wv->name = "message"; |
prev_wv->name = "message"; |
2883 |
prev_wv->help = Qnil; |
prev_wv->help = Qnil; |
2884 |
first_wv = prev_wv; |
first_wv = prev_wv; |
2885 |
|
|
2886 |
/* Loop over all panes and items, filling in the tree. */ |
/* Loop over all panes and items, filling in the tree. */ |
2887 |
i = MENU_ITEMS_PANE_LENGTH; |
i = MENU_ITEMS_PANE_LENGTH; |
2888 |
while (i < menu_items_used) |
while (i < menu_items_used) |
2889 |
{ |
{ |
2890 |
|
|
2891 |
/* Create a new item within current pane. */ |
/* Create a new item within current pane. */ |
2892 |
Lisp_Object item_name, enable, descrip; |
Lisp_Object item_name, enable, descrip; |
2893 |
item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME]; |
item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME]; |
2894 |
enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE]; |
enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE]; |
2895 |
descrip |
descrip |
2896 |
= XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY]; |
= XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY]; |
2897 |
|
|
2898 |
if (NILP (item_name)) |
if (NILP (item_name)) |
2899 |
{ |
{ |
2900 |
free_menubar_widget_value_tree (first_wv); |
free_menubar_widget_value_tree (first_wv); |
2920 |
prev_wv->next = wv; |
prev_wv->next = wv; |
2921 |
wv->name = (char *) button_names[nb_buttons]; |
wv->name = (char *) button_names[nb_buttons]; |
2922 |
if (!NILP (descrip)) |
if (!NILP (descrip)) |
2923 |
wv->key = (char *) XSTRING (descrip)->data; |
wv->key = (char *) SDATA (descrip); |
2924 |
wv->value = (char *) XSTRING (item_name)->data; |
wv->value = (char *) SDATA (item_name); |
2925 |
wv->call_data = (void *) &XVECTOR (menu_items)->contents[i]; |
wv->call_data = (void *) &XVECTOR (menu_items)->contents[i]; |
2926 |
wv->enabled = !NILP (enable); |
wv->enabled = !NILP (enable); |
2927 |
wv->help = Qnil; |
wv->help = Qnil; |
2957 |
first_wv = wv; |
first_wv = wv; |
2958 |
} |
} |
2959 |
|
|
|
/* Actually create the dialog. */ |
|
|
dialog_id = widget_id_tick++; |
|
|
menu = lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv, |
|
|
f->output_data.x->widget, 1, 0, |
|
|
dialog_selection_callback, 0, 0); |
|
|
lw_modify_all_widgets (dialog_id, first_wv->contents, True); |
|
|
/* Free the widget_value objects we used to specify the contents. */ |
|
|
free_menubar_widget_value_tree (first_wv); |
|
|
|
|
2960 |
/* No selection has been chosen yet. */ |
/* No selection has been chosen yet. */ |
2961 |
menu_item_selection = 0; |
menu_item_selection = 0; |
2962 |
|
|
2963 |
/* Display the menu. */ |
/* Actually create and show the dialog. */ |
2964 |
lw_pop_up_all_widgets (dialog_id); |
create_and_show_dialog (f, first_wv); |
|
popup_activated_flag = 1; |
|
2965 |
|
|
2966 |
/* Process events that apply to the menu. */ |
/* Free the widget_value objects we used to specify the contents. */ |
2967 |
popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), dialog_id); |
free_menubar_widget_value_tree (first_wv); |
|
|
|
|
lw_destroy_all_widgets (dialog_id); |
|
2968 |
|
|
2969 |
/* Find the selected item, and its pane, to return |
/* Find the selected item, and its pane, to return |
2970 |
the proper value. */ |
the proper value. */ |
3012 |
return Qnil; |
return Qnil; |
3013 |
} |
} |
3014 |
|
|
3015 |
#else /* not USE_X_TOOLKIT */ |
#else /* not USE_X_TOOLKIT && not USE_GTK */ |
3016 |
|
|
3017 |
/* The frame of the last activated non-toolkit menu bar. |
/* The frame of the last activated non-toolkit menu bar. |
3018 |
Used to generate menu help events. */ |
Used to generate menu help events. */ |
3024 |
|
|
3025 |
PANE is the pane number, and ITEM is the menu item number in |
PANE is the pane number, and ITEM is the menu item number in |
3026 |
the menu (currently not used). |
the menu (currently not used). |
3027 |
|
|
3028 |
This cannot be done with generating a HELP_EVENT because |
This cannot be done with generating a HELP_EVENT because |
3029 |
XMenuActivate contains a loop that doesn't let Emacs process |
XMenuActivate contains a loop that doesn't let Emacs process |
3030 |
keyboard events. */ |
keyboard events. */ |
3038 |
Lisp_Object *first_item; |
Lisp_Object *first_item; |
3039 |
Lisp_Object pane_name; |
Lisp_Object pane_name; |
3040 |
Lisp_Object menu_object; |
Lisp_Object menu_object; |
3041 |
|
|
3042 |
first_item = XVECTOR (menu_items)->contents; |
first_item = XVECTOR (menu_items)->contents; |
3043 |
if (EQ (first_item[0], Qt)) |
if (EQ (first_item[0], Qt)) |
3044 |
pane_name = first_item[MENU_ITEMS_PANE_NAME]; |
pane_name = first_item[MENU_ITEMS_PANE_NAME]; |
3047 |
pane_name = empty_string; |
pane_name = empty_string; |
3048 |
else |
else |
3049 |
pane_name = first_item[MENU_ITEMS_ITEM_NAME]; |
pane_name = first_item[MENU_ITEMS_ITEM_NAME]; |
3050 |
|
|
3051 |
/* (menu-item MENU-NAME PANE-NUMBER) */ |
/* (menu-item MENU-NAME PANE-NUMBER) */ |
3052 |
menu_object = Fcons (Qmenu_item, |
menu_object = Fcons (Qmenu_item, |
3053 |
Fcons (pane_name, |
Fcons (pane_name, |
3055 |
show_help_echo (help_string ? build_string (help_string) : Qnil, |
show_help_echo (help_string ? build_string (help_string) : Qnil, |
3056 |
Qnil, menu_object, make_number (item), 1); |
Qnil, menu_object, make_number (item), 1); |
3057 |
} |
} |
3058 |
|
|
3059 |
|
|
3060 |
static Lisp_Object |
static Lisp_Object |
3061 |
xmenu_show (f, x, y, for_click, keymaps, title, error) |
xmenu_show (f, x, y, for_click, keymaps, title, error) |
3066 |
Lisp_Object title; |
Lisp_Object title; |
3067 |
char **error; |
char **error; |
3068 |
{ |
{ |
3069 |
Window root; |
Window root; |
3070 |
XMenu *menu; |
XMenu *menu; |
3071 |
int pane, selidx, lpane, status; |
int pane, selidx, lpane, status; |
3072 |
Lisp_Object entry, pane_prefix; |
Lisp_Object entry, pane_prefix; |
3133 |
/* Adjust coordinates to be root-window-relative. */ |
/* Adjust coordinates to be root-window-relative. */ |
3134 |
x += f->output_data.x->left_pos; |
x += f->output_data.x->left_pos; |
3135 |
y += f->output_data.x->top_pos; |
y += f->output_data.x->top_pos; |
3136 |
|
|
3137 |
/* Create all the necessary panes and their items. */ |
/* Create all the necessary panes and their items. */ |
3138 |
i = 0; |
i = 0; |
3139 |
while (i < menu_items_used) |
while (i < menu_items_used) |
3147 |
pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME]; |
pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME]; |
3148 |
prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; |
prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; |
3149 |
pane_string = (NILP (pane_name) |
pane_string = (NILP (pane_name) |
3150 |
? "" : (char *) XSTRING (pane_name)->data); |
? "" : (char *) SDATA (pane_name)); |
3151 |
if (keymaps && !NILP (prefix)) |
if (keymaps && !NILP (prefix)) |
3152 |
pane_string++; |
pane_string++; |
3153 |
|
|
3174 |
j++; |
j++; |
3175 |
continue; |
continue; |
3176 |
} |
} |
3177 |
width = STRING_BYTES (XSTRING (item)); |
width = SBYTES (item); |
3178 |
if (width > maxwidth) |
if (width > maxwidth) |
3179 |
maxwidth = width; |
maxwidth = width; |
3180 |
|
|
3197 |
descrip |
descrip |
3198 |
= XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY]; |
= XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY]; |
3199 |
help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP]; |
help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP]; |
3200 |
help_string = STRINGP (help) ? XSTRING (help)->data : NULL; |
help_string = STRINGP (help) ? SDATA (help) : NULL; |
3201 |
|
|
3202 |
if (!NILP (descrip)) |
if (!NILP (descrip)) |
3203 |
{ |
{ |
3204 |
int gap = maxwidth - STRING_BYTES (XSTRING (item_name)); |
int gap = maxwidth - SBYTES (item_name); |
3205 |
#ifdef C_ALLOCA |
#ifdef C_ALLOCA |
3206 |
Lisp_Object spacer; |
Lisp_Object spacer; |
3207 |
spacer = Fmake_string (make_number (gap), make_number (' ')); |
spacer = Fmake_string (make_number (gap), make_number (' ')); |
3208 |
item_name = concat2 (item_name, spacer); |
item_name = concat2 (item_name, spacer); |
3209 |
item_name = concat2 (item_name, descrip); |
item_name = concat2 (item_name, descrip); |
3210 |
item_data = XSTRING (item_name)->data; |
item_data = SDATA (item_name); |
3211 |
#else |
#else |
3212 |
/* if alloca is fast, use that to make the space, |
/* if alloca is fast, use that to make the space, |
3213 |
to reduce gc needs. */ |
to reduce gc needs. */ |
3214 |
item_data |
item_data |
3215 |
= (unsigned char *) alloca (maxwidth |
= (unsigned char *) alloca (maxwidth |
3216 |
+ STRING_BYTES (XSTRING (descrip)) + 1); |
+ SBYTES (descrip) + 1); |
3217 |
bcopy (XSTRING (item_name)->data, item_data, |
bcopy (SDATA (item_name), item_data, |
3218 |
STRING_BYTES (XSTRING (item_name))); |
SBYTES (item_name)); |
3219 |
for (j = XSTRING (item_name)->size; j < maxwidth; j++) |
for (j = SCHARS (item_name); j < maxwidth; j++) |
3220 |
item_data[j] = ' '; |
item_data[j] = ' '; |
3221 |
bcopy (XSTRING (descrip)->data, item_data + j, |
bcopy (SDATA (descrip), item_data + j, |
3222 |
STRING_BYTES (XSTRING (descrip))); |
SBYTES (descrip)); |
3223 |
item_data[j + STRING_BYTES (XSTRING (descrip))] = 0; |
item_data[j + SBYTES (descrip)] = 0; |
3224 |
#endif |
#endif |
3225 |
} |
} |
3226 |
else |
else |
3227 |
item_data = XSTRING (item_name)->data; |
item_data = SDATA (item_name); |
3228 |
|
|
3229 |
if (XMenuAddSelection (FRAME_X_DISPLAY (f), |
if (XMenuAddSelection (FRAME_X_DISPLAY (f), |
3230 |
menu, lpane, 0, item_data, |
menu, lpane, 0, item_data, |
3351 |
{ |
{ |
3352 |
staticpro (&menu_items); |
staticpro (&menu_items); |
3353 |
menu_items = Qnil; |
menu_items = Qnil; |
3354 |
|
menu_items_inuse = Qnil; |
3355 |
|
|
3356 |
Qdebug_on_next_call = intern ("debug-on-next-call"); |
Qdebug_on_next_call = intern ("debug-on-next-call"); |
3357 |
staticpro (&Qdebug_on_next_call); |
staticpro (&Qdebug_on_next_call); |
3362 |
Vmenu_updating_frame = Qnil; |
Vmenu_updating_frame = Qnil; |
3363 |
|
|
3364 |
#ifdef USE_X_TOOLKIT |
#ifdef USE_X_TOOLKIT |
3365 |
widget_id_tick = (1<<16); |
widget_id_tick = (1<<16); |
3366 |
next_menubar_widget_id = 1; |
next_menubar_widget_id = 1; |
3367 |
#endif |
#endif |
3368 |
|
|