X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/cd3520a41df21d80a9d894c58af2daba23c8dd24..cb1caeaf2ba26df05e8f9bcd4aa63203cef781fb:/src/xmenu.c diff --git a/src/xmenu.c b/src/xmenu.c index fc629b3510..5a6390449c 100644 --- a/src/xmenu.c +++ b/src/xmenu.c @@ -1,6 +1,6 @@ /* X Communication module for terminals which understand the X protocol. -Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2011 +Copyright (C) 1986, 1988, 1993-1994, 1996, 1999-2012 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -47,6 +47,7 @@ along with GNU Emacs. If not, see . */ #include "termhooks.h" #include "window.h" #include "blockinput.h" +#include "character.h" #include "buffer.h" #include "charset.h" #include "coding.h" @@ -102,6 +103,9 @@ along with GNU Emacs. If not, see . */ #ifdef USE_GTK #include "gtkutil.h" +#ifdef HAVE_GTK3 +#include "xgselect.h" +#endif #endif #include "menu.h" @@ -315,7 +319,7 @@ for instance using the window manager, then this produces a quit and Lisp_Object title; const char *error_name; Lisp_Object selection; - int specpdl_count = SPECPDL_INDEX (); + ptrdiff_t specpdl_count = SPECPDL_INDEX (); /* Decode the dialog items from what was specified. */ title = Fcar (contents); @@ -388,8 +392,6 @@ x_menu_wait_for_event (void *data) ) { EMACS_TIME next_time = timer_check (), *ntp; - long secs = EMACS_SECS (next_time); - long usecs = EMACS_USECS (next_time); SELECT_TYPE read_fds; struct x_display_info *dpyinfo; int n = 0; @@ -403,12 +405,19 @@ x_menu_wait_for_event (void *data) XFlush (dpyinfo->display); } - if (secs < 0 && usecs < 0) + if (! EMACS_TIME_VALID_P (next_time)) ntp = 0; else ntp = &next_time; - select (n + 1, &read_fds, (SELECT_TYPE *)0, (SELECT_TYPE *)0, ntp); +#ifdef HAVE_GTK3 + /* Gtk3 have arrows on menus when they don't fit. When the + pointer is over an arrow, a timeout scrolls it a bit. Use + xg_select so that timeout gets triggered. */ + xg_select (n + 1, &read_fds, NULL, NULL, ntp, NULL); +#else + pselect (n + 1, &read_fds, NULL, NULL, ntp, NULL); +#endif } } #endif /* ! MSDOS */ @@ -740,10 +749,13 @@ menu_highlight_callback (GtkWidget *widget, gpointer call_data) help = call_data ? cb_data->help : Qnil; /* If popup_activated_flag is greater than 1 we are in a popup menu. - Don't show help for them, they won't appear before the - popup is popped down. */ - if (popup_activated_flag <= 1) - show_help_event (cb_data->cl_data->f, widget, help); + Don't pass the frame to show_help_event for those. + Passing frame creates an Emacs event. As we are looping in + popup_widget_loop, it won't be handled. Passing NULL shows the tip + directly without using an Emacs event. This is what the Lucid code + does below. */ + show_help_event (popup_activated_flag <= 1 ? cb_data->cl_data->f : NULL, + widget, help); } #else static void @@ -949,7 +961,7 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p) else if (!f->output_data.x->saved_menu_event && !deep_p) { deep_p = 1; - f->output_data.x->saved_menu_event = (XEvent*)xmalloc (sizeof (XEvent)); + f->output_data.x->saved_menu_event = xmalloc (sizeof (XEvent)); f->output_data.x->saved_menu_event->type = 0; } @@ -965,11 +977,10 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p) struct buffer *prev = current_buffer; Lisp_Object buffer; - int specpdl_count = SPECPDL_INDEX (); + ptrdiff_t specpdl_count = SPECPDL_INDEX (); int previous_menu_items_used = f->menu_bar_items_used; Lisp_Object *previous_items - = (Lisp_Object *) alloca (previous_menu_items_used - * sizeof (Lisp_Object)); + = alloca (previous_menu_items_used * sizeof *previous_items); int subitems; /* If we are making a new widget, its contents are empty, @@ -1016,18 +1027,19 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p) menu_items = f->menu_bar_vector; menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0; subitems = ASIZE (items) / 4; - submenu_start = (int *) alloca ((subitems + 1) * sizeof (int)); - submenu_end = (int *) alloca (subitems * sizeof (int)); - submenu_n_panes = (int *) alloca (subitems * sizeof (int)); - submenu_top_level_items = (int *) alloca (subitems * sizeof (int)); + submenu_start = alloca ((subitems + 1) * sizeof *submenu_start); + submenu_end = alloca (subitems * sizeof *submenu_end); + submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes); + submenu_top_level_items = alloca (subitems + * sizeof *submenu_top_level_items); init_menu_items (); for (i = 0; i < subitems; i++) { Lisp_Object key, string, maps; - key = XVECTOR (items)->contents[4 * i]; - string = XVECTOR (items)->contents[4 * i + 1]; - maps = XVECTOR (items)->contents[4 * i + 2]; + key = AREF (items, 4 * i); + string = AREF (items, 4 * i + 1); + maps = AREF (items, 4 * i + 2); if (NILP (string)) break; @@ -1078,7 +1090,7 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p) /* Compare the new menu items with the ones computed last time. */ for (i = 0; i < previous_menu_items_used; i++) if (menu_items_used == i - || (!EQ (previous_items[i], XVECTOR (menu_items)->contents[i]))) + || (!EQ (previous_items[i], AREF (menu_items, i)))) break; if (i == menu_items_used && i == previous_menu_items_used && i != 0) { @@ -1103,7 +1115,7 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p) for (i = 0; i < ASIZE (items); i += 4) { Lisp_Object string; - string = XVECTOR (items)->contents[i + 1]; + string = AREF (items, i + 1); if (NILP (string)) break; wv->name = SSDATA (string); @@ -1130,7 +1142,7 @@ set_frame_menubar (FRAME_PTR f, int first_time, int deep_p) { Lisp_Object string; - string = XVECTOR (items)->contents[i + 1]; + string = AREF (items, i + 1); if (NILP (string)) break; @@ -1301,7 +1313,7 @@ free_frame_menubar (FRAME_PTR f) #ifdef USE_MOTIF /* Removing the menu bar magically changes the shell widget's x and y position of (0, 0) which, when the menu bar is turned - on again, leads to pull-down menuss appearing in strange + on again, leads to pull-down menus appearing in strange positions near the upper-left corner of the display. This happens only with some window managers like twm and ctwm, but not with other like Motif's mwm or kwm, because the @@ -1431,7 +1443,14 @@ create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv, int x, int y, GtkWidget *menu; GtkMenuPositionFunc pos_func = 0; /* Pop up at pointer. */ struct next_popup_x_y popup_x_y; - int specpdl_count = SPECPDL_INDEX (); + ptrdiff_t specpdl_count = SPECPDL_INDEX (); + int use_pos_func = ! for_click; + +#ifdef HAVE_GTK3 + /* Always use position function for Gtk3. Otherwise menus may become + too small to show anything. */ + use_pos_func = 1; +#endif if (! FRAME_X_P (f)) abort (); @@ -1443,7 +1462,7 @@ create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv, int x, int y, G_CALLBACK (menu_highlight_callback)); xg_crazy_callback_abort = 0; - if (! for_click) + if (use_pos_func) { /* Not invoked by a click. pop up at x/y. */ pos_func = menu_position_func; @@ -1458,7 +1477,8 @@ create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv, int x, int y, i = 0; /* gtk_menu_popup needs this to be 0 for a non-button popup. */ } - else + + if (for_click) { for (i = 0; i < 5; i++) if (FRAME_X_DISPLAY_INFO (f)->grabbed & (1 << i)) @@ -1587,7 +1607,7 @@ create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv, { int fact = 4 * sizeof (LWLIB_ID); - int specpdl_count = SPECPDL_INDEX (); + ptrdiff_t specpdl_count = SPECPDL_INDEX (); record_unwind_protect (pop_down_menu, Fcons (make_number (menu_id >> (fact)), make_number (menu_id & ~(-1 << (fact))))); @@ -1601,6 +1621,17 @@ create_and_show_popup_menu (FRAME_PTR f, widget_value *first_wv, #endif /* not USE_GTK */ +static Lisp_Object +cleanup_widget_value_tree (Lisp_Object arg) +{ + struct Lisp_Save_Value *p = XSAVE_VALUE (arg); + widget_value *wv = p->pointer; + + free_menubar_widget_value_tree (wv); + + return Qnil; +} + Lisp_Object xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, Lisp_Object title, const char **error_name, Time timestamp) @@ -1608,13 +1639,15 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, int i; widget_value *wv, *save_wv = 0, *first_wv = 0, *prev_wv = 0; widget_value **submenu_stack - = (widget_value **) alloca (menu_items_used * sizeof (widget_value *)); + = alloca (menu_items_used * sizeof *submenu_stack); Lisp_Object *subprefix_stack - = (Lisp_Object *) alloca (menu_items_used * sizeof (Lisp_Object)); + = alloca (menu_items_used * sizeof *subprefix_stack); int submenu_depth = 0; int first_pane; + ptrdiff_t specpdl_count = SPECPDL_INDEX (); + if (! FRAME_X_P (f)) abort (); @@ -1641,7 +1674,7 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, i = 0; while (i < menu_items_used) { - if (EQ (XVECTOR (menu_items)->contents[i], Qnil)) + if (EQ (AREF (menu_items, i), Qnil)) { submenu_stack[submenu_depth++] = save_wv; save_wv = prev_wv; @@ -1649,21 +1682,21 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, first_pane = 1; i++; } - else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda)) + else if (EQ (AREF (menu_items, i), Qlambda)) { prev_wv = save_wv; save_wv = submenu_stack[--submenu_depth]; first_pane = 0; i++; } - else if (EQ (XVECTOR (menu_items)->contents[i], Qt) + else if (EQ (AREF (menu_items, i), Qt) && submenu_depth != 0) i += MENU_ITEMS_PANE_LENGTH; /* Ignore a nil in the item list. It's meaningful only for dialog boxes. */ - else if (EQ (XVECTOR (menu_items)->contents[i], Qquote)) + else if (EQ (AREF (menu_items, i), Qquote)) i += 1; - else if (EQ (XVECTOR (menu_items)->contents[i], Qt)) + else if (EQ (AREF (menu_items, i), Qt)) { /* Create a new pane. */ Lisp_Object pane_name, prefix; @@ -1696,7 +1729,7 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, save_wv->next = wv; else first_wv->contents = wv; - wv->name = pane_string; + wv->name = (char *) pane_string; if (keymaps && !NILP (prefix)) wv->name++; wv->value = 0; @@ -1753,7 +1786,7 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, make the call_data null so that it won't display a box when the mouse is on it. */ wv->call_data - = (!NILP (def) ? (void *) &XVECTOR (menu_items)->contents[i] : 0); + = (!NILP (def) ? (void *) &AREF (menu_items, i) : 0); wv->enabled = !NILP (enable); if (NILP (type)) @@ -1809,11 +1842,15 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, /* No selection has been chosen yet. */ menu_item_selection = 0; + /* Make sure to free the widget_value objects we used to specify the + contents even with longjmp. */ + record_unwind_protect (cleanup_widget_value_tree, + make_save_value (first_wv, 0)); + /* Actually create and show the menu until popped down. */ create_and_show_popup_menu (f, first_wv, x, y, for_click, timestamp); - /* Free the widget_value objects we used to specify the contents. */ - free_menubar_widget_value_tree (first_wv); + unbind_to (specpdl_count, Qnil); /* Find the selected item, and its pane, to return the proper value. */ @@ -1825,32 +1862,32 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, i = 0; while (i < menu_items_used) { - if (EQ (XVECTOR (menu_items)->contents[i], Qnil)) + if (EQ (AREF (menu_items, i), Qnil)) { subprefix_stack[submenu_depth++] = prefix; prefix = entry; i++; } - else if (EQ (XVECTOR (menu_items)->contents[i], Qlambda)) + else if (EQ (AREF (menu_items, i), Qlambda)) { prefix = subprefix_stack[--submenu_depth]; i++; } - else if (EQ (XVECTOR (menu_items)->contents[i], Qt)) + else if (EQ (AREF (menu_items, i), Qt)) { prefix - = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; + = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); i += MENU_ITEMS_PANE_LENGTH; } /* Ignore a nil in the item list. It's meaningful only for dialog boxes. */ - else if (EQ (XVECTOR (menu_items)->contents[i], Qquote)) + else if (EQ (AREF (menu_items, i), Qquote)) i += 1; else { entry - = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE]; - if (menu_item_selection == &XVECTOR (menu_items)->contents[i]) + = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE); + if (menu_item_selection == &AREF (menu_items, i)) { if (keymaps != 0) { @@ -1906,7 +1943,7 @@ create_and_show_dialog (FRAME_PTR f, widget_value *first_wv) if (menu) { - int specpdl_count = SPECPDL_INDEX (); + ptrdiff_t specpdl_count = SPECPDL_INDEX (); record_unwind_protect (pop_down_menu, make_save_value (menu, 0)); /* Display the menu. */ @@ -1944,7 +1981,7 @@ create_and_show_dialog (FRAME_PTR f, widget_value *first_wv) LWLIB_ID dialog_id; if (!FRAME_X_P (f)) - abort(); + abort (); dialog_id = widget_id_tick++; #ifdef USE_LUCID @@ -1962,7 +1999,7 @@ create_and_show_dialog (FRAME_PTR f, widget_value *first_wv) /* Process events that apply to the dialog box. Also handle timers. */ { - int count = SPECPDL_INDEX (); + ptrdiff_t count = SPECPDL_INDEX (); int fact = 4 * sizeof (LWLIB_ID); /* xdialog_show_unwind is responsible for popping the dialog box down. */ @@ -2000,6 +2037,8 @@ xdialog_show (FRAME_PTR f, /* 1 means we've seen the boundary between left-hand elts and right-hand. */ int boundary_seen = 0; + ptrdiff_t specpdl_count = SPECPDL_INDEX (); + if (! FRAME_X_P (f)) abort (); @@ -2016,12 +2055,12 @@ xdialog_show (FRAME_PTR f, { Lisp_Object pane_name, prefix; const char *pane_string; - pane_name = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_NAME]; - prefix = XVECTOR (menu_items)->contents[MENU_ITEMS_PANE_PREFIX]; + pane_name = AREF (menu_items, MENU_ITEMS_PANE_NAME); + prefix = AREF (menu_items, MENU_ITEMS_PANE_PREFIX); pane_string = (NILP (pane_name) ? "" : SSDATA (pane_name)); prev_wv = xmalloc_widget_value (); - prev_wv->value = pane_string; + prev_wv->value = (char *) pane_string; if (keymaps && !NILP (prefix)) prev_wv->name++; prev_wv->enabled = 1; @@ -2036,10 +2075,10 @@ xdialog_show (FRAME_PTR f, /* Create a new item within current pane. */ Lisp_Object item_name, enable, descrip; - item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME]; - enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE]; + item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME); + enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE); descrip - = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY]; + = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY); if (NILP (item_name)) { @@ -2068,7 +2107,7 @@ xdialog_show (FRAME_PTR f, if (!NILP (descrip)) wv->key = SSDATA (descrip); wv->value = SSDATA (item_name); - wv->call_data = (void *) &XVECTOR (menu_items)->contents[i]; + wv->call_data = (void *) &AREF (menu_items, i); wv->enabled = !NILP (enable); wv->help = Qnil; prev_wv = wv; @@ -2092,7 +2131,7 @@ xdialog_show (FRAME_PTR f, /* Frame title: 'Q' = Question, 'I' = Information. Can also have 'E' = Error if, one day, we want a popup for errors. */ - if (NILP(header)) + if (NILP (header)) dialog_name[0] = 'Q'; else dialog_name[0] = 'I'; @@ -2113,11 +2152,15 @@ xdialog_show (FRAME_PTR f, /* No selection has been chosen yet. */ menu_item_selection = 0; + /* Make sure to free the widget_value objects we used to specify the + contents even with longjmp. */ + record_unwind_protect (cleanup_widget_value_tree, + make_save_value (first_wv, 0)); + /* Actually create and show the dialog. */ create_and_show_dialog (f, first_wv); - /* Free the widget_value objects we used to specify the contents. */ - free_menubar_widget_value_tree (first_wv); + unbind_to (specpdl_count, Qnil); /* Find the selected item, and its pane, to return the proper value. */ @@ -2131,13 +2174,13 @@ xdialog_show (FRAME_PTR f, { Lisp_Object entry; - if (EQ (XVECTOR (menu_items)->contents[i], Qt)) + if (EQ (AREF (menu_items, i), Qt)) { prefix - = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; + = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); i += MENU_ITEMS_PANE_LENGTH; } - else if (EQ (XVECTOR (menu_items)->contents[i], Qquote)) + else if (EQ (AREF (menu_items, i), Qquote)) { /* This is the boundary between left-side elts and right-side elts. */ @@ -2146,8 +2189,8 @@ xdialog_show (FRAME_PTR f, else { entry - = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE]; - if (menu_item_selection == &XVECTOR (menu_items)->contents[i]) + = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE); + if (menu_item_selection == &AREF (menu_items, i)) { if (keymaps != 0) { @@ -2259,7 +2302,7 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, int maxwidth; int dummy_int; unsigned int dummy_uint; - int specpdl_count = SPECPDL_INDEX (); + ptrdiff_t specpdl_count = SPECPDL_INDEX (); if (! FRAME_X_P (f) && ! FRAME_MSDOS_P (f)) abort (); @@ -2307,7 +2350,7 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, lpane = XM_FAILURE; while (i < menu_items_used) { - if (EQ (XVECTOR (menu_items)->contents[i], Qt)) + if (EQ (AREF (menu_items, i), Qt)) { /* Create a new pane. */ Lisp_Object pane_name, prefix; @@ -2315,8 +2358,8 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, maxlines = max (maxlines, lines); lines = 0; - pane_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_NAME]; - prefix = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; + pane_name = AREF (menu_items, i + MENU_ITEMS_PANE_NAME); + prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); pane_string = (NILP (pane_name) ? "" : SSDATA (pane_name)); if (keymaps && !NILP (prefix)) @@ -2336,7 +2379,7 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, while (j < menu_items_used) { Lisp_Object item; - item = XVECTOR (menu_items)->contents[j]; + item = AREF (menu_items, j); if (EQ (item, Qt)) break; if (NILP (item)) @@ -2353,7 +2396,7 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, } /* Ignore a nil in the item list. It's meaningful only for dialog boxes. */ - else if (EQ (XVECTOR (menu_items)->contents[i], Qquote)) + else if (EQ (AREF (menu_items, i), Qquote)) i += 1; else { @@ -2362,18 +2405,18 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, char *item_data; char const *help_string; - item_name = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_NAME]; - enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE]; + item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME); + enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE); descrip - = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY]; - help = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_HELP]; + = AREF (menu_items, i + MENU_ITEMS_ITEM_EQUIV_KEY); + help = AREF (menu_items, i + MENU_ITEMS_ITEM_HELP); help_string = STRINGP (help) ? SSDATA (help) : NULL; if (!NILP (descrip)) { /* if alloca is fast, use that to make the space, to reduce gc needs. */ - item_data = (char *) alloca (maxwidth + SBYTES (descrip) + 1); + item_data = alloca (maxwidth + SBYTES (descrip) + 1); memcpy (item_data, SSDATA (item_name), SBYTES (item_name)); for (j = SCHARS (item_name); j < maxwidth; j++) item_data[j] = ' '; @@ -2480,11 +2523,11 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, i = 0; while (i < menu_items_used) { - if (EQ (XVECTOR (menu_items)->contents[i], Qt)) + if (EQ (AREF (menu_items, i), Qt)) { if (pane == 0) pane_prefix - = XVECTOR (menu_items)->contents[i + MENU_ITEMS_PANE_PREFIX]; + = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX); pane--; i += MENU_ITEMS_PANE_LENGTH; } @@ -2495,7 +2538,7 @@ xmenu_show (FRAME_PTR f, int x, int y, int for_click, int keymaps, if (selidx == 0) { entry - = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_VALUE]; + = AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE); if (keymaps != 0) { entry = Fcons (entry, Qnil);