48 |
#include "buffer.h" |
#include "buffer.h" |
49 |
#include "charset.h" |
#include "charset.h" |
50 |
#include "coding.h" |
#include "coding.h" |
51 |
|
#include "sysselect.h" |
52 |
|
|
53 |
#ifdef MSDOS |
#ifdef MSDOS |
54 |
#include "msdos.h" |
#include "msdos.h" |
158 |
static void list_of_panes P_ ((Lisp_Object)); |
static void list_of_panes P_ ((Lisp_Object)); |
159 |
static void list_of_items P_ ((Lisp_Object)); |
static void list_of_items P_ ((Lisp_Object)); |
160 |
|
|
|
extern EMACS_TIME timer_check P_ ((int)); |
|
|
|
|
161 |
|
|
162 |
/* This holds a Lisp vector that holds the results of decoding |
/* This holds a Lisp vector that holds the results of decoding |
163 |
the keymaps or alist-of-alists that specify a menu. |
the keymaps or alist-of-alists that specify a menu. |
288 |
|
|
289 |
static Lisp_Object |
static Lisp_Object |
290 |
unuse_menu_items (dummy) |
unuse_menu_items (dummy) |
291 |
int dummy; |
Lisp_Object dummy; |
292 |
{ |
{ |
293 |
return menu_items_inuse = Qnil; |
return menu_items_inuse = Qnil; |
294 |
} |
} |
524 |
return; /* Not a menu item. */ |
return; /* Not a menu item. */ |
525 |
|
|
526 |
map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP]; |
map = XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP]; |
527 |
|
|
528 |
if (skp->notreal) |
if (skp->notreal) |
529 |
{ |
{ |
530 |
/* 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 |
1098 |
the dialog. Also, the lesstif/motif version crashes if there are |
the dialog. Also, the lesstif/motif version crashes if there are |
1099 |
no buttons. */ |
no buttons. */ |
1100 |
contents = Fcons (title, Fcons (Fcons (build_string ("Ok"), Qt), Qnil)); |
contents = Fcons (title, Fcons (Fcons (build_string ("Ok"), Qt), Qnil)); |
1101 |
|
|
1102 |
list_of_panes (Fcons (contents, Qnil)); |
list_of_panes (Fcons (contents, Qnil)); |
1103 |
|
|
1104 |
/* Display them in a dialog box. */ |
/* Display them in a dialog box. */ |
1114 |
} |
} |
1115 |
#endif |
#endif |
1116 |
} |
} |
1117 |
|
|
1118 |
|
|
1119 |
|
#ifndef MSDOS |
1120 |
|
|
1121 |
|
/* Set menu_items_inuse so no other popup menu or dialog is created. */ |
1122 |
|
|
1123 |
|
void |
1124 |
|
x_menu_set_in_use (in_use) |
1125 |
|
int in_use; |
1126 |
|
{ |
1127 |
|
menu_items_inuse = in_use ? Qt : Qnil; |
1128 |
|
popup_activated_flag = in_use; |
1129 |
|
} |
1130 |
|
|
1131 |
|
/* Wait for an X event to arrive or for a timer to expire. */ |
1132 |
|
|
1133 |
|
void |
1134 |
|
x_menu_wait_for_event (void *data) |
1135 |
|
{ |
1136 |
|
extern EMACS_TIME timer_check P_ ((int)); |
1137 |
|
|
1138 |
|
/* Another way to do this is to register a timer callback, that can be |
1139 |
|
done in GTK and Xt. But we have to do it like this when using only X |
1140 |
|
anyway, and with callbacks we would have three variants for timer handling |
1141 |
|
instead of the small ifdefs below. */ |
1142 |
|
|
1143 |
|
while ( |
1144 |
|
#ifdef USE_X_TOOLKIT |
1145 |
|
! XtAppPending (Xt_app_con) |
1146 |
|
#elif defined USE_GTK |
1147 |
|
! gtk_events_pending () |
1148 |
|
#else |
1149 |
|
! XPending ((Display*) data) |
1150 |
|
#endif |
1151 |
|
) |
1152 |
|
{ |
1153 |
|
EMACS_TIME next_time = timer_check (1); |
1154 |
|
long secs = EMACS_SECS (next_time); |
1155 |
|
long usecs = EMACS_USECS (next_time); |
1156 |
|
SELECT_TYPE read_fds; |
1157 |
|
struct x_display_info *dpyinfo; |
1158 |
|
int n = 0; |
1159 |
|
|
1160 |
|
FD_ZERO (&read_fds); |
1161 |
|
for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) |
1162 |
|
{ |
1163 |
|
int fd = ConnectionNumber (dpyinfo->display); |
1164 |
|
FD_SET (fd, &read_fds); |
1165 |
|
if (fd > n) n = fd; |
1166 |
|
} |
1167 |
|
|
1168 |
|
if (secs < 0 || (secs == 0 && usecs == 0)) |
1169 |
|
{ |
1170 |
|
/* Sometimes timer_check returns -1 (no timers) even if there are |
1171 |
|
timers. So do a timeout anyway. */ |
1172 |
|
EMACS_SET_SECS (next_time, 1); |
1173 |
|
EMACS_SET_USECS (next_time, 0); |
1174 |
|
} |
1175 |
|
|
1176 |
|
select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, &next_time); |
1177 |
|
} |
1178 |
|
} |
1179 |
|
#endif /* ! MSDOS */ |
1180 |
|
|
1181 |
|
|
1182 |
#if defined (USE_X_TOOLKIT) || defined (USE_GTK) |
#if defined (USE_X_TOOLKIT) || defined (USE_GTK) |
1183 |
|
|
1184 |
|
#ifdef USE_X_TOOLKIT |
1185 |
|
|
1186 |
/* Loop in Xt until the menu pulldown or dialog popup has been |
/* Loop in Xt until the menu pulldown or dialog popup has been |
1187 |
popped down (deactivated). This is used for x-popup-menu |
popped down (deactivated). This is used for x-popup-menu |
1188 |
and x-popup-dialog; it is not used for the menu bar. |
and x-popup-dialog; it is not used for the menu bar. |
1192 |
NOTE: All calls to popup_get_selection should be protected |
NOTE: All calls to popup_get_selection should be protected |
1193 |
with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */ |
with BLOCK_INPUT, UNBLOCK_INPUT wrappers. */ |
1194 |
|
|
|
#ifdef USE_X_TOOLKIT |
|
1195 |
static void |
static void |
1196 |
popup_get_selection (initial_event, dpyinfo, id, do_timers, down_on_keypress) |
popup_get_selection (initial_event, dpyinfo, id, do_timers, down_on_keypress) |
1197 |
XEvent *initial_event; |
XEvent *initial_event; |
1204 |
|
|
1205 |
while (popup_activated_flag) |
while (popup_activated_flag) |
1206 |
{ |
{ |
|
/* If we have no events to run, consider timers. */ |
|
|
if (do_timers && !XtAppPending (Xt_app_con)) |
|
|
timer_check (1); |
|
|
|
|
1207 |
if (initial_event) |
if (initial_event) |
1208 |
{ |
{ |
1209 |
event = *initial_event; |
event = *initial_event; |
1210 |
initial_event = 0; |
initial_event = 0; |
1211 |
} |
} |
1212 |
else |
else |
1213 |
XtAppNextEvent (Xt_app_con, &event); |
{ |
1214 |
|
if (do_timers) x_menu_wait_for_event (0); |
1215 |
|
XtAppNextEvent (Xt_app_con, &event); |
1216 |
|
} |
1217 |
|
|
1218 |
/* Make sure we don't consider buttons grabbed after menu goes. |
/* Make sure we don't consider buttons grabbed after menu goes. |
1219 |
And make sure to deactivate for any ButtonRelease, |
And make sure to deactivate for any ButtonRelease, |
1258 |
#ifdef USE_GTK |
#ifdef USE_GTK |
1259 |
/* Loop util popup_activated_flag is set to zero in a callback. |
/* Loop util popup_activated_flag is set to zero in a callback. |
1260 |
Used for popup menus and dialogs. */ |
Used for popup menus and dialogs. */ |
1261 |
|
|
1262 |
static void |
static void |
1263 |
popup_widget_loop () |
popup_widget_loop (do_timers, widget) |
1264 |
|
int do_timers; |
1265 |
|
GtkWidget *widget; |
1266 |
{ |
{ |
1267 |
++popup_activated_flag; |
++popup_activated_flag; |
1268 |
|
|
1269 |
/* Process events in the Gtk event loop until done. */ |
/* Process events in the Gtk event loop until done. */ |
1270 |
while (popup_activated_flag) |
while (popup_activated_flag) |
1271 |
{ |
{ |
1272 |
|
if (do_timers) x_menu_wait_for_event (0); |
1273 |
gtk_main_iteration (); |
gtk_main_iteration (); |
1274 |
} |
} |
1275 |
} |
} |
2396 |
GtkRequisition req; |
GtkRequisition req; |
2397 |
int disp_width = FRAME_X_DISPLAY_INFO (data->f)->width; |
int disp_width = FRAME_X_DISPLAY_INFO (data->f)->width; |
2398 |
int disp_height = FRAME_X_DISPLAY_INFO (data->f)->height; |
int disp_height = FRAME_X_DISPLAY_INFO (data->f)->height; |
2399 |
|
|
2400 |
*x = data->x; |
*x = data->x; |
2401 |
*y = data->y; |
*y = data->y; |
2402 |
|
|
2420 |
if (cb_data) menu_item_selection = (Lisp_Object *) cb_data->call_data; |
if (cb_data) menu_item_selection = (Lisp_Object *) cb_data->call_data; |
2421 |
} |
} |
2422 |
|
|
2423 |
|
static Lisp_Object |
2424 |
|
pop_down_menu (arg) |
2425 |
|
Lisp_Object arg; |
2426 |
|
{ |
2427 |
|
struct Lisp_Save_Value *p = XSAVE_VALUE (arg); |
2428 |
|
|
2429 |
|
popup_activated_flag = 0; |
2430 |
|
BLOCK_INPUT; |
2431 |
|
gtk_widget_destroy (GTK_WIDGET (p->pointer)); |
2432 |
|
UNBLOCK_INPUT; |
2433 |
|
return Qnil; |
2434 |
|
} |
2435 |
|
|
2436 |
/* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the |
/* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the |
2437 |
menu pops down. |
menu pops down. |
2438 |
menu_item_selection will be set to the selection. */ |
menu_item_selection will be set to the selection. */ |
2448 |
GtkWidget *menu; |
GtkWidget *menu; |
2449 |
GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */ |
GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */ |
2450 |
struct next_popup_x_y popup_x_y; |
struct next_popup_x_y popup_x_y; |
2451 |
|
int specpdl_count = SPECPDL_INDEX (); |
2452 |
|
|
2453 |
xg_crazy_callback_abort = 1; |
xg_crazy_callback_abort = 1; |
2454 |
menu = xg_create_widget ("popup", first_wv->name, f, first_wv, |
menu = xg_create_widget ("popup", first_wv->name, f, first_wv, |
2479 |
gtk_widget_show_all (menu); |
gtk_widget_show_all (menu); |
2480 |
gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i, 0); |
gtk_menu_popup (GTK_MENU (menu), 0, 0, pos_func, &popup_x_y, i, 0); |
2481 |
|
|
2482 |
|
record_unwind_protect (pop_down_menu, make_save_value (menu, 0)); |
2483 |
|
|
2484 |
/* Set this to one. popup_widget_loop increases it by one, so it becomes |
/* Set this to one. popup_widget_loop increases it by one, so it becomes |
2485 |
two. show_help_echo uses this to detect popup menus. */ |
two. show_help_echo uses this to detect popup menus. */ |
2486 |
popup_activated_flag = 1; |
popup_activated_flag = 1; |
2487 |
/* Process events that apply to the menu. */ |
/* Process events that apply to the menu. */ |
2488 |
popup_widget_loop (); |
popup_widget_loop (1, menu); |
2489 |
|
|
2490 |
gtk_widget_destroy (menu); |
unbind_to (specpdl_count, Qnil); |
2491 |
|
|
2492 |
/* Must reset this manually because the button release event is not passed |
/* Must reset this manually because the button release event is not passed |
2493 |
to Emacs event loop. */ |
to Emacs event loop. */ |
2515 |
menu_item_selection = (Lisp_Object *) client_data; |
menu_item_selection = (Lisp_Object *) client_data; |
2516 |
} |
} |
2517 |
|
|
2518 |
|
/* ARG is the LWLIB ID of the dialog box, represented |
2519 |
|
as a Lisp object as (HIGHPART . LOWPART). */ |
2520 |
|
|
2521 |
|
static Lisp_Object |
2522 |
|
pop_down_menu (arg) |
2523 |
|
Lisp_Object arg; |
2524 |
|
{ |
2525 |
|
LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID) |
2526 |
|
| XINT (XCDR (arg))); |
2527 |
|
|
2528 |
|
BLOCK_INPUT; |
2529 |
|
lw_destroy_all_widgets (id); |
2530 |
|
UNBLOCK_INPUT; |
2531 |
|
popup_activated_flag = 0; |
2532 |
|
|
2533 |
|
return Qnil; |
2534 |
|
} |
2535 |
|
|
2536 |
/* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the |
/* Pop up the menu for frame F defined by FIRST_WV at X/Y and loop until the |
2537 |
menu pops down. |
menu pops down. |
2538 |
menu_item_selection will be set to the selection. */ |
menu_item_selection will be set to the selection. */ |
2589 |
/* Display the menu. */ |
/* Display the menu. */ |
2590 |
lw_popup_menu (menu, (XEvent *) &dummy); |
lw_popup_menu (menu, (XEvent *) &dummy); |
2591 |
popup_activated_flag = 1; |
popup_activated_flag = 1; |
2592 |
|
|
2593 |
|
{ |
2594 |
|
int fact = 4 * sizeof (LWLIB_ID); |
2595 |
|
int specpdl_count = SPECPDL_INDEX (); |
2596 |
|
record_unwind_protect (pop_down_menu, |
2597 |
|
Fcons (make_number (menu_id >> (fact)), |
2598 |
|
make_number (menu_id & ~(-1 << (fact))))); |
2599 |
|
|
2600 |
/* Process events that apply to the menu. */ |
/* Process events that apply to the menu. */ |
2601 |
popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 0, 0); |
popup_get_selection ((XEvent *) 0, FRAME_X_DISPLAY_INFO (f), menu_id, 1, 0); |
2602 |
|
|
2603 |
/* fp turned off the following statement and wrote a comment |
unbind_to (specpdl_count, Qnil); |
2604 |
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); |
|
2605 |
} |
} |
2606 |
|
|
2607 |
#endif /* not USE_GTK */ |
#endif /* not USE_GTK */ |
2912 |
|
|
2913 |
if (menu) |
if (menu) |
2914 |
{ |
{ |
2915 |
|
int specpdl_count = SPECPDL_INDEX (); |
2916 |
|
record_unwind_protect (pop_down_menu, make_save_value (menu, 0)); |
2917 |
|
|
2918 |
/* Display the menu. */ |
/* Display the menu. */ |
2919 |
gtk_widget_show_all (menu); |
gtk_widget_show_all (menu); |
2920 |
|
|
2921 |
/* Process events that apply to the menu. */ |
/* Process events that apply to the menu. */ |
2922 |
popup_widget_loop (); |
popup_widget_loop (1, menu); |
2923 |
|
|
2924 |
gtk_widget_destroy (menu); |
unbind_to (specpdl_count, Qnil); |
2925 |
} |
} |
2926 |
} |
} |
2927 |
|
|
2944 |
} |
} |
2945 |
|
|
2946 |
|
|
|
/* ARG is the LWLIB ID of the dialog box, represented |
|
|
as a Lisp object as (HIGHPART . LOWPART). */ |
|
|
|
|
|
Lisp_Object |
|
|
xdialog_show_unwind (arg) |
|
|
Lisp_Object arg; |
|
|
{ |
|
|
LWLIB_ID id = (XINT (XCAR (arg)) << 4 * sizeof (LWLIB_ID) |
|
|
| XINT (XCDR (arg))); |
|
|
BLOCK_INPUT; |
|
|
lw_destroy_all_widgets (id); |
|
|
UNBLOCK_INPUT; |
|
|
popup_activated_flag = 0; |
|
|
return Qnil; |
|
|
} |
|
|
|
|
|
|
|
2947 |
/* Pop up the dialog for frame F defined by FIRST_WV and loop until the |
/* Pop up the dialog for frame F defined by FIRST_WV and loop until the |
2948 |
dialog pops down. |
dialog pops down. |
2949 |
menu_item_selection will be set to the selection. */ |
menu_item_selection will be set to the selection. */ |
2971 |
int fact = 4 * sizeof (LWLIB_ID); |
int fact = 4 * sizeof (LWLIB_ID); |
2972 |
|
|
2973 |
/* xdialog_show_unwind is responsible for popping the dialog box down. */ |
/* xdialog_show_unwind is responsible for popping the dialog box down. */ |
2974 |
record_unwind_protect (xdialog_show_unwind, |
record_unwind_protect (pop_down_menu, |
2975 |
Fcons (make_number (dialog_id >> (fact)), |
Fcons (make_number (dialog_id >> (fact)), |
2976 |
make_number (dialog_id & ~(-1 << (fact))))); |
make_number (dialog_id & ~(-1 << (fact))))); |
2977 |
|
|
3204 |
Qnil, menu_object, make_number (item), 1); |
Qnil, menu_object, make_number (item), 1); |
3205 |
} |
} |
3206 |
|
|
3207 |
|
static Lisp_Object |
3208 |
|
pop_down_menu (arg) |
3209 |
|
Lisp_Object arg; |
3210 |
|
{ |
3211 |
|
struct Lisp_Save_Value *p1 = XSAVE_VALUE (Fcar (arg)); |
3212 |
|
struct Lisp_Save_Value *p2 = XSAVE_VALUE (Fcdr (arg)); |
3213 |
|
|
3214 |
|
FRAME_PTR f = p1->pointer; |
3215 |
|
XMenu *menu = p2->pointer; |
3216 |
|
|
3217 |
|
BLOCK_INPUT; |
3218 |
|
#ifndef MSDOS |
3219 |
|
XUngrabPointer (FRAME_X_DISPLAY (f), CurrentTime); |
3220 |
|
XUngrabKeyboard (FRAME_X_DISPLAY (f), CurrentTime); |
3221 |
|
#endif |
3222 |
|
XMenuDestroy (FRAME_X_DISPLAY (f), menu); |
3223 |
|
|
3224 |
|
#ifdef HAVE_X_WINDOWS |
3225 |
|
/* Assume the mouse has moved out of the X window. |
3226 |
|
If it has actually moved in, we will get an EnterNotify. */ |
3227 |
|
x_mouse_leave (FRAME_X_DISPLAY_INFO (f)); |
3228 |
|
|
3229 |
|
/* State that no mouse buttons are now held. |
3230 |
|
(The oldXMenu code doesn't track this info for us.) |
3231 |
|
That is not necessarily true, but the fiction leads to reasonable |
3232 |
|
results, and it is a pain to ask which are actually held now. */ |
3233 |
|
FRAME_X_DISPLAY_INFO (f)->grabbed = 0; |
3234 |
|
|
3235 |
|
#endif /* HAVE_X_WINDOWS */ |
3236 |
|
|
3237 |
|
UNBLOCK_INPUT; |
3238 |
|
|
3239 |
|
return Qnil; |
3240 |
|
} |
3241 |
|
|
3242 |
|
|
3243 |
static Lisp_Object |
static Lisp_Object |
3244 |
xmenu_show (f, x, y, for_click, keymaps, title, error) |
xmenu_show (f, x, y, for_click, keymaps, title, error) |
3260 |
int maxwidth; |
int maxwidth; |
3261 |
int dummy_int; |
int dummy_int; |
3262 |
unsigned int dummy_uint; |
unsigned int dummy_uint; |
3263 |
|
int specpdl_count = SPECPDL_INDEX (); |
3264 |
|
|
3265 |
*error = 0; |
*error = 0; |
3266 |
if (menu_items_n_panes == 0) |
if (menu_items_n_panes == 0) |
3450 |
XMenuSetFreeze (menu, TRUE); |
XMenuSetFreeze (menu, TRUE); |
3451 |
pane = selidx = 0; |
pane = selidx = 0; |
3452 |
|
|
3453 |
|
#ifndef MSDOS |
3454 |
|
XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f)); |
3455 |
|
#endif |
3456 |
|
|
3457 |
|
record_unwind_protect (pop_down_menu, |
3458 |
|
Fcons (make_save_value (f, 0), |
3459 |
|
make_save_value (menu, 0))); |
3460 |
|
|
3461 |
/* Help display under X won't work because XMenuActivate contains |
/* Help display under X won't work because XMenuActivate contains |
3462 |
a loop that doesn't give Emacs a chance to process it. */ |
a loop that doesn't give Emacs a chance to process it. */ |
3463 |
menu_help_frame = f; |
menu_help_frame = f; |
3464 |
status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx, |
status = XMenuActivate (FRAME_X_DISPLAY (f), menu, &pane, &selidx, |
3465 |
x, y, ButtonReleaseMask, &datap, |
x, y, ButtonReleaseMask, &datap, |
3466 |
menu_help_callback); |
menu_help_callback); |
|
|
|
|
|
|
|
#ifdef HAVE_X_WINDOWS |
|
|
/* Assume the mouse has moved out of the X window. |
|
|
If it has actually moved in, we will get an EnterNotify. */ |
|
|
x_mouse_leave (FRAME_X_DISPLAY_INFO (f)); |
|
|
#endif |
|
3467 |
|
|
3468 |
switch (status) |
switch (status) |
3469 |
{ |
{ |
3514 |
entry = Qnil; |
entry = Qnil; |
3515 |
break; |
break; |
3516 |
} |
} |
|
XMenuDestroy (FRAME_X_DISPLAY (f), menu); |
|
3517 |
|
|
3518 |
#ifdef HAVE_X_WINDOWS |
unbind_to (specpdl_count, Qnil); |
|
/* State that no mouse buttons are now held. |
|
|
(The oldXMenu code doesn't track this info for us.) |
|
|
That is not necessarily true, but the fiction leads to reasonable |
|
|
results, and it is a pain to ask which are actually held now. */ |
|
|
FRAME_X_DISPLAY_INFO (f)->grabbed = 0; |
|
|
#endif |
|
3519 |
|
|
3520 |
return entry; |
return entry; |
3521 |
} |
} |