diff options
| author | Jan Djärv | 2003-01-08 20:06:05 +0000 |
|---|---|---|
| committer | Jan Djärv | 2003-01-08 20:06:05 +0000 |
| commit | 8b806a8574f8e3a292a36e73dd144b46fb4d07d2 (patch) | |
| tree | 7a2aa5a4bca5130f66e32f52aff1ee7af4b2a754 /src | |
| parent | 00e3ab56664fbf759daa5a98e31976e90a8fca8e (diff) | |
| download | emacs-8b806a8574f8e3a292a36e73dd144b46fb4d07d2.tar.gz emacs-8b806a8574f8e3a292a36e73dd144b46fb4d07d2.zip | |
(Fx_popup_menu): If popping up at mouse position,
call XQueryPointer to get coordinates.
(popup_get_selection): Do not set popup_activated_flag to zero,
let popup_deactivate_callback do that. Needed for Motif.
Call x_dispatch_event instead of XtDispatchEvent.
(xmenu_show): Calculate root coordinate from frame top/left position.
Diffstat (limited to 'src')
| -rw-r--r-- | src/xmenu.c | 240 |
1 files changed, 88 insertions, 152 deletions
diff --git a/src/xmenu.c b/src/xmenu.c index 4724b2e7ff4..d4c09edfa5d 100644 --- a/src/xmenu.c +++ b/src/xmenu.c | |||
| @@ -108,7 +108,6 @@ extern Lisp_Object Qmenu_bar_update_hook; | |||
| 108 | 108 | ||
| 109 | #ifdef USE_X_TOOLKIT | 109 | #ifdef USE_X_TOOLKIT |
| 110 | extern void set_frame_menubar (); | 110 | extern void set_frame_menubar (); |
| 111 | extern void process_expose_from_menu (); | ||
| 112 | extern XtAppContext Xt_app_con; | 111 | extern XtAppContext Xt_app_con; |
| 113 | 112 | ||
| 114 | static Lisp_Object xdialog_show (); | 113 | static Lisp_Object xdialog_show (); |
| @@ -731,21 +730,44 @@ cached information about equivalent key sequences. */) | |||
| 731 | { | 730 | { |
| 732 | /* Use the mouse's current position. */ | 731 | /* Use the mouse's current position. */ |
| 733 | FRAME_PTR new_f = SELECTED_FRAME (); | 732 | FRAME_PTR new_f = SELECTED_FRAME (); |
| 734 | Lisp_Object bar_window; | 733 | Window root, dummy_window; |
| 735 | enum scroll_bar_part part; | 734 | int cur_x, cur_y, dummy; |
| 736 | unsigned long time; | 735 | |
| 737 | 736 | BLOCK_INPUT; | |
| 738 | if (mouse_position_hook) | 737 | |
| 739 | (*mouse_position_hook) (&new_f, 1, &bar_window, | 738 | XQueryPointer (FRAME_X_DISPLAY (new_f), |
| 740 | &part, &x, &y, &time); | 739 | DefaultRootWindow (FRAME_X_DISPLAY (new_f)), |
| 741 | if (new_f != 0) | 740 | |
| 742 | XSETFRAME (window, new_f); | 741 | /* The root window which contains the pointer. */ |
| 743 | else | 742 | &root, |
| 744 | { | 743 | |
| 745 | window = selected_window; | 744 | /* Window pointer is on, not used */ |
| 746 | XSETFASTINT (x, 0); | 745 | &dummy_window, |
| 747 | XSETFASTINT (y, 0); | 746 | |
| 748 | } | 747 | /* The position on that root window. */ |
| 748 | &cur_x, &cur_y, | ||
| 749 | |||
| 750 | /* x/y in dummy_window coordinates, not used. */ | ||
| 751 | &dummy, &dummy, | ||
| 752 | |||
| 753 | /* Modifier keys and pointer buttons, about which | ||
| 754 | we don't care. */ | ||
| 755 | (unsigned int *) &dummy); | ||
| 756 | |||
| 757 | UNBLOCK_INPUT; | ||
| 758 | |||
| 759 | /* xmenu_show expects window coordinates, not root window | ||
| 760 | coordinates. Translate. */ | ||
| 761 | cur_x -= new_f->output_data.x->left_pos | ||
| 762 | + FRAME_OUTER_TO_INNER_DIFF_X (new_f); | ||
| 763 | cur_y -= new_f->output_data.x->top_pos | ||
| 764 | + FRAME_OUTER_TO_INNER_DIFF_Y (new_f); | ||
| 765 | |||
| 766 | /* cur_x/y may be negative, so use make_number. */ | ||
| 767 | x = make_number (cur_x); | ||
| 768 | y = make_number (cur_y); | ||
| 769 | |||
| 770 | XSETFRAME (window, new_f); | ||
| 749 | } | 771 | } |
| 750 | else | 772 | else |
| 751 | { | 773 | { |
| @@ -1017,21 +1039,6 @@ on the left of the dialog box and all following items on the right. | |||
| 1017 | 1039 | ||
| 1018 | #ifdef USE_X_TOOLKIT | 1040 | #ifdef USE_X_TOOLKIT |
| 1019 | 1041 | ||
| 1020 | /* Define a queue to save up for later unreading | ||
| 1021 | all X events that don't pertain to the menu. */ | ||
| 1022 | struct event_queue | ||
| 1023 | { | ||
| 1024 | XEvent event; | ||
| 1025 | struct event_queue *next; | ||
| 1026 | }; | ||
| 1027 | |||
| 1028 | /* It is ok that this queue is a static variable, | ||
| 1029 | because init_menu_items won't allow the menu mechanism | ||
| 1030 | to be entered recursively. */ | ||
| 1031 | static struct event_queue *popup_get_selection_queue; | ||
| 1032 | |||
| 1033 | static Lisp_Object popup_get_selection_unwind (); | ||
| 1034 | |||
| 1035 | /* Loop in Xt until the menu pulldown or dialog popup has been | 1042 | /* Loop in Xt until the menu pulldown or dialog popup has been |
| 1036 | popped down (deactivated). This is used for x-popup-menu | 1043 | popped down (deactivated). This is used for x-popup-menu |
| 1037 | and x-popup-dialog; it is not used for the menu bar. | 1044 | and x-popup-dialog; it is not used for the menu bar. |
| @@ -1049,107 +1056,51 @@ popup_get_selection (initial_event, dpyinfo, id, do_timers) | |||
| 1049 | int do_timers; | 1056 | int do_timers; |
| 1050 | { | 1057 | { |
| 1051 | XEvent event; | 1058 | XEvent event; |
| 1052 | struct event_queue *queue_tmp; | ||
| 1053 | int count = SPECPDL_INDEX (); | ||
| 1054 | |||
| 1055 | popup_get_selection_queue = NULL; | ||
| 1056 | 1059 | ||
| 1057 | record_unwind_protect (popup_get_selection_unwind, Qnil); | 1060 | while (popup_activated_flag) |
| 1061 | { | ||
| 1062 | /* If we have no events to run, consider timers. */ | ||
| 1063 | if (do_timers && !XtAppPending (Xt_app_con)) | ||
| 1064 | timer_check (1); | ||
| 1058 | 1065 | ||
| 1059 | if (initial_event) | 1066 | if (initial_event) |
| 1060 | event = *initial_event; | 1067 | { |
| 1061 | else | 1068 | event = *initial_event; |
| 1062 | XtAppNextEvent (Xt_app_con, &event); | 1069 | initial_event = 0; |
| 1070 | } | ||
| 1071 | else | ||
| 1072 | XtAppNextEvent (Xt_app_con, &event); | ||
| 1063 | 1073 | ||
| 1064 | while (1) | ||
| 1065 | { | ||
| 1066 | /* Handle expose events for editor frames right away. */ | ||
| 1067 | if (event.type == Expose) | ||
| 1068 | process_expose_from_menu (event); | ||
| 1069 | /* Make sure we don't consider buttons grabbed after menu goes. | 1074 | /* Make sure we don't consider buttons grabbed after menu goes. |
| 1070 | And make sure to deactivate for any ButtonRelease, | 1075 | And make sure to deactivate for any ButtonRelease, |
| 1071 | even if XtDispatchEvent doesn't do that. */ | 1076 | even if XtDispatchEvent doesn't do that. */ |
| 1072 | else if (event.type == ButtonRelease | 1077 | if (event.type == ButtonRelease |
| 1073 | && dpyinfo->display == event.xbutton.display) | 1078 | && dpyinfo->display == event.xbutton.display) |
| 1074 | { | 1079 | { |
| 1075 | dpyinfo->grabbed &= ~(1 << event.xbutton.button); | 1080 | dpyinfo->grabbed &= ~(1 << event.xbutton.button); |
| 1076 | popup_activated_flag = 0; | ||
| 1077 | #ifdef USE_MOTIF /* Pretending that the event came from a | 1081 | #ifdef USE_MOTIF /* Pretending that the event came from a |
| 1078 | Btn1Down seems the only way to convince Motif to | 1082 | Btn1Down seems the only way to convince Motif to |
| 1079 | activate its callbacks; setting the XmNmenuPost | 1083 | activate its callbacks; setting the XmNmenuPost |
| 1080 | isn't working. --marcus@sysc.pdx.edu. */ | 1084 | isn't working. --marcus@sysc.pdx.edu. */ |
| 1081 | event.xbutton.button = 1; | 1085 | event.xbutton.button = 1; |
| 1086 | /* Motif only pops down menus when no Ctrl, Alt or Mod | ||
| 1087 | key is pressed and the button is released. So reset key state | ||
| 1088 | so Motif thinks this is the case. */ | ||
| 1089 | event.xbutton.state = 0; | ||
| 1082 | #endif | 1090 | #endif |
| 1083 | } | 1091 | } |
| 1084 | /* If the user presses a key, deactivate the menu. | 1092 | /* If the user presses a key, deactivate the menu. |
| 1085 | The user is likely to do that if we get wedged. */ | 1093 | The user is likely to do that if we get wedged. |
| 1094 | This is mostly for Lucid, Motif pops down the menu on ESC. */ | ||
| 1086 | else if (event.type == KeyPress | 1095 | else if (event.type == KeyPress |
| 1087 | && dpyinfo->display == event.xbutton.display) | ||
| 1088 | { | ||
| 1089 | KeySym keysym = XLookupKeysym (&event.xkey, 0); | ||
| 1090 | if (!IsModifierKey (keysym)) | ||
| 1091 | { | ||
| 1092 | popup_activated_flag = 0; | ||
| 1093 | break; | ||
| 1094 | } | ||
| 1095 | } | ||
| 1096 | /* Button presses outside the menu also pop it down. */ | ||
| 1097 | else if (event.type == ButtonPress | ||
| 1098 | && event.xany.display == dpyinfo->display | ||
| 1099 | && x_any_window_to_frame (dpyinfo, event.xany.window)) | ||
| 1100 | { | ||
| 1101 | popup_activated_flag = 0; | ||
| 1102 | break; | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | /* Queue all events not for this popup, | ||
| 1106 | except for Expose, which we've already handled, and ButtonRelease. | ||
| 1107 | Note that the X window is associated with the frame if this | ||
| 1108 | is a menu bar popup, but not if it's a dialog box. So we use | ||
| 1109 | x_non_menubar_window_to_frame, not x_any_window_to_frame. */ | ||
| 1110 | if (event.type != Expose | ||
| 1111 | && !(event.type == ButtonRelease | ||
| 1112 | && dpyinfo->display == event.xbutton.display) | 1096 | && dpyinfo->display == event.xbutton.display) |
| 1113 | && (event.xany.display != dpyinfo->display | 1097 | { |
| 1114 | || x_non_menubar_window_to_frame (dpyinfo, event.xany.window))) | 1098 | KeySym keysym = XLookupKeysym (&event.xkey, 0); |
| 1115 | { | 1099 | if (!IsModifierKey (keysym)) |
| 1116 | queue_tmp = (struct event_queue *) xmalloc (sizeof *queue_tmp); | 1100 | popup_activated_flag = 0; |
| 1117 | queue_tmp->event = event; | 1101 | } |
| 1118 | queue_tmp->next = popup_get_selection_queue; | 1102 | |
| 1119 | popup_get_selection_queue = queue_tmp; | 1103 | x_dispatch_event (&event, event.xany.display); |
| 1120 | } | ||
| 1121 | else | ||
| 1122 | XtDispatchEvent (&event); | ||
| 1123 | |||
| 1124 | /* If the event deactivated the menu, we are finished. */ | ||
| 1125 | if (!popup_activated_flag) | ||
| 1126 | break; | ||
| 1127 | |||
| 1128 | /* If we have no events to run, consider timers. */ | ||
| 1129 | if (do_timers && !XtAppPending (Xt_app_con)) | ||
| 1130 | timer_check (1); | ||
| 1131 | |||
| 1132 | XtAppNextEvent (Xt_app_con, &event); | ||
| 1133 | } | ||
| 1134 | |||
| 1135 | unbind_to (count, Qnil); | ||
| 1136 | } | ||
| 1137 | |||
| 1138 | /* Unread any events that popup_get_selection read but did not handle. */ | ||
| 1139 | |||
| 1140 | static Lisp_Object | ||
| 1141 | popup_get_selection_unwind (ignore) | ||
| 1142 | Lisp_Object ignore; | ||
| 1143 | { | ||
| 1144 | while (popup_get_selection_queue != NULL) | ||
| 1145 | { | ||
| 1146 | struct event_queue *queue_tmp; | ||
| 1147 | queue_tmp = popup_get_selection_queue; | ||
| 1148 | XPutBackEvent (queue_tmp->event.xany.display, &queue_tmp->event); | ||
| 1149 | popup_get_selection_queue = queue_tmp->next; | ||
| 1150 | xfree ((char *)queue_tmp); | ||
| 1151 | /* Cause these events to get read as soon as we UNBLOCK_INPUT. */ | ||
| 1152 | interrupt_input_pending = 1; | ||
| 1153 | } | 1104 | } |
| 1154 | } | 1105 | } |
| 1155 | 1106 | ||
| @@ -1630,7 +1581,7 @@ update_frame_menubar (f) | |||
| 1630 | { | 1581 | { |
| 1631 | struct x_output *x = f->output_data.x; | 1582 | struct x_output *x = f->output_data.x; |
| 1632 | int columns, rows; | 1583 | int columns, rows; |
| 1633 | 1584 | ||
| 1634 | if (!x->menubar_widget || XtIsManaged (x->menubar_widget)) | 1585 | if (!x->menubar_widget || XtIsManaged (x->menubar_widget)) |
| 1635 | return 0; | 1586 | return 0; |
| 1636 | 1587 | ||
| @@ -2278,38 +2229,18 @@ xmenu_show (f, x, y, for_click, keymaps, title, error) | |||
| 2278 | popup_selection_callback, | 2229 | popup_selection_callback, |
| 2279 | popup_deactivate_callback, | 2230 | popup_deactivate_callback, |
| 2280 | menu_highlight_callback); | 2231 | menu_highlight_callback); |
| 2281 | 2232 | ||
| 2282 | /* Adjust coordinates to relative to the outer (window manager) window. */ | 2233 | /* See if whe positions are up to date. Temporary code to be removed |
| 2234 | when we are sure positions are always up to date. */ | ||
| 2283 | { | 2235 | { |
| 2284 | Window child; | 2236 | int real_x, real_y; |
| 2285 | int win_x = 0, win_y = 0; | 2237 | x_real_positions (f, &real_x, &real_y); |
| 2286 | 2238 | ||
| 2287 | /* Find the position of the outside upper-left corner of | 2239 | if (real_x != f->output_data.x->left_pos || |
| 2288 | the inner window, with respect to the outer window. */ | 2240 | real_y != f->output_data.x->top_pos) |
| 2289 | if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window) | 2241 | abort (); |
| 2290 | { | ||
| 2291 | BLOCK_INPUT; | ||
| 2292 | XTranslateCoordinates (FRAME_X_DISPLAY (f), | ||
| 2293 | |||
| 2294 | /* From-window, to-window. */ | ||
| 2295 | f->output_data.x->window_desc, | ||
| 2296 | f->output_data.x->parent_desc, | ||
| 2297 | |||
| 2298 | /* From-position, to-position. */ | ||
| 2299 | 0, 0, &win_x, &win_y, | ||
| 2300 | |||
| 2301 | /* Child of window. */ | ||
| 2302 | &child); | ||
| 2303 | UNBLOCK_INPUT; | ||
| 2304 | x += win_x; | ||
| 2305 | y += win_y; | ||
| 2306 | } | ||
| 2307 | } | 2242 | } |
| 2308 | 2243 | ||
| 2309 | /* Adjust coordinates to be root-window-relative. */ | ||
| 2310 | x += f->output_data.x->left_pos; | ||
| 2311 | y += f->output_data.x->top_pos; | ||
| 2312 | |||
| 2313 | dummy.type = ButtonPress; | 2244 | dummy.type = ButtonPress; |
| 2314 | dummy.serial = 0; | 2245 | dummy.serial = 0; |
| 2315 | dummy.send_event = 0; | 2246 | dummy.send_event = 0; |
| @@ -2318,11 +2249,16 @@ xmenu_show (f, x, y, for_click, keymaps, title, error) | |||
| 2318 | dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window; | 2249 | dummy.root = FRAME_X_DISPLAY_INFO (f)->root_window; |
| 2319 | dummy.window = dummy.root; | 2250 | dummy.window = dummy.root; |
| 2320 | dummy.subwindow = dummy.root; | 2251 | dummy.subwindow = dummy.root; |
| 2321 | dummy.x_root = x; | ||
| 2322 | dummy.y_root = y; | ||
| 2323 | dummy.x = x; | 2252 | dummy.x = x; |
| 2324 | dummy.y = y; | 2253 | dummy.y = y; |
| 2325 | dummy.state = (FRAME_X_DISPLAY_INFO (f)->grabbed >> 1) * Button1Mask; | 2254 | |
| 2255 | /* Adjust coordinates to be root-window-relative. */ | ||
| 2256 | x += f->output_data.x->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); | ||
| 2257 | y += f->output_data.x->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); | ||
| 2258 | |||
| 2259 | dummy.x_root = x; | ||
| 2260 | dummy.y_root = y; | ||
| 2261 | dummy.state = 0; | ||
| 2326 | dummy.button = 0; | 2262 | dummy.button = 0; |
| 2327 | for (i = 0; i < 5; i++) | 2263 | for (i = 0; i < 5; i++) |
| 2328 | if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i)) | 2264 | if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i)) |