diff options
| author | Jeff Walsh | 2019-06-15 14:44:47 +1000 |
|---|---|---|
| committer | Jeff Walsh | 2020-11-22 14:46:55 +1100 |
| commit | cdc04b4509772f2324c4ca63732caed2858cedf3 (patch) | |
| tree | 4c25236482f6faedb806dca4040c098a1364e96c /src | |
| parent | 12cc104cd54dd80a9bc1d391a256de49f4b77077 (diff) | |
| download | emacs-cdc04b4509772f2324c4ca63732caed2858cedf3.tar.gz emacs-cdc04b4509772f2324c4ca63732caed2858cedf3.zip | |
Implement menubar for pgtk emacs
* src/xdisp.c (display_menu_bar): add pgtk case
* ../src/pgtkterm.c (pgtk_create_terminal): update hooks
(pgtk_menu_show): delete
* src/pgtkterm.h: add decls
* src/pgtkmenu.c: new file
* ../src/pgtkfns.c (x_set_menu_bar_lines)
(x_change_tool_bar_height, x_set_tool_bar_lines)
(Fx_create_frame):
Diffstat (limited to 'src')
| -rw-r--r-- | src/emacs.c | 1 | ||||
| -rw-r--r-- | src/lisp.h | 2 | ||||
| -rw-r--r-- | src/menu.h | 6 | ||||
| -rw-r--r-- | src/pgtkfns.c | 117 | ||||
| -rw-r--r-- | src/pgtkmenu.c | 476 | ||||
| -rw-r--r-- | src/pgtkterm.c | 11 | ||||
| -rw-r--r-- | src/pgtkterm.h | 6 | ||||
| -rw-r--r-- | src/xdisp.c | 5 |
8 files changed, 541 insertions, 83 deletions
diff --git a/src/emacs.c b/src/emacs.c index 769a852e733..42d93737b93 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -1921,6 +1921,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 1921 | syms_of_pgtkterm(); | 1921 | syms_of_pgtkterm(); |
| 1922 | syms_of_pgtkfns(); | 1922 | syms_of_pgtkfns(); |
| 1923 | syms_of_pgtkselect (); | 1923 | syms_of_pgtkselect (); |
| 1924 | syms_of_pgtkmenu (); | ||
| 1924 | syms_of_fontset (); | 1925 | syms_of_fontset (); |
| 1925 | syms_of_xsettings (); | 1926 | syms_of_xsettings (); |
| 1926 | syms_of_xwidget (); | 1927 | syms_of_xwidget (); |
diff --git a/src/lisp.h b/src/lisp.h index 718c0f12a59..76d74200ac8 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -3298,7 +3298,7 @@ struct frame; | |||
| 3298 | #endif | 3298 | #endif |
| 3299 | 3299 | ||
| 3300 | /* Define if the windowing system provides a tool-bar. */ | 3300 | /* Define if the windowing system provides a tool-bar. */ |
| 3301 | #if (defined (USE_GTK) && !defined(HAVE_PGTK)) || defined (HAVE_NS) | 3301 | #if defined (USE_GTK) || defined (HAVE_NS) |
| 3302 | #define HAVE_EXT_TOOL_BAR true | 3302 | #define HAVE_EXT_TOOL_BAR true |
| 3303 | #endif | 3303 | #endif |
| 3304 | 3304 | ||
diff --git a/src/menu.h b/src/menu.h index 44749ade75a..baad4496e4d 100644 --- a/src/menu.h +++ b/src/menu.h | |||
| @@ -59,6 +59,12 @@ extern Lisp_Object ns_menu_show (struct frame *, int, int, int, | |||
| 59 | Lisp_Object, const char **); | 59 | Lisp_Object, const char **); |
| 60 | extern void ns_activate_menubar (struct frame *); | 60 | extern void ns_activate_menubar (struct frame *); |
| 61 | #endif | 61 | #endif |
| 62 | #ifdef HAVE_PGTK | ||
| 63 | extern Lisp_Object pgtk_menu_show (struct frame *, int, int, int, | ||
| 64 | Lisp_Object, const char **); | ||
| 65 | extern void pgtk_activate_menubar (struct frame *); | ||
| 66 | #endif | ||
| 67 | |||
| 62 | extern Lisp_Object tty_menu_show (struct frame *, int, int, int, | 68 | extern Lisp_Object tty_menu_show (struct frame *, int, int, int, |
| 63 | Lisp_Object, const char **); | 69 | Lisp_Object, const char **); |
| 64 | extern ptrdiff_t menu_item_width (const unsigned char *); | 70 | extern ptrdiff_t menu_item_width (const unsigned char *); |
diff --git a/src/pgtkfns.c b/src/pgtkfns.c index ce702028348..140f29a473b 100644 --- a/src/pgtkfns.c +++ b/src/pgtkfns.c | |||
| @@ -465,31 +465,63 @@ pgtk_set_doc_edited (void) | |||
| 465 | static void | 465 | static void |
| 466 | x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) | 466 | x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) |
| 467 | { | 467 | { |
| 468 | #if 0 | ||
| 469 | int nlines; | 468 | int nlines; |
| 470 | if (FRAME_MINIBUF_ONLY_P (f)) | 469 | /* Right now, menu bars don't work properly in minibuf-only frames; |
| 470 | most of the commands try to apply themselves to the minibuffer | ||
| 471 | frame itself, and get an error because you can't switch buffers | ||
| 472 | in or split the minibuffer window. */ | ||
| 473 | if (FRAME_MINIBUF_ONLY_P (f) || FRAME_PARENT_FRAME (f)) | ||
| 471 | return; | 474 | return; |
| 472 | 475 | ||
| 473 | if (TYPE_RANGED_INTEGERP (int, value)) | 476 | if (TYPE_RANGED_FIXNUMP (int, value)) |
| 474 | nlines = XFIXNUM (value); | 477 | nlines = XFIXNUM (value); |
| 475 | else | 478 | else |
| 476 | nlines = 0; | 479 | nlines = 0; |
| 477 | 480 | ||
| 481 | /* Make sure we redisplay all windows in this frame. */ | ||
| 482 | fset_redisplay (f); | ||
| 483 | |||
| 478 | FRAME_MENU_BAR_LINES (f) = 0; | 484 | FRAME_MENU_BAR_LINES (f) = 0; |
| 485 | FRAME_MENU_BAR_HEIGHT (f) = 0; | ||
| 479 | if (nlines) | 486 | if (nlines) |
| 480 | { | 487 | { |
| 481 | FRAME_EXTERNAL_MENU_BAR (f) = 1; | 488 | FRAME_EXTERNAL_MENU_BAR (f) = 1; |
| 482 | /* does for all frames, whereas we just want for one frame | 489 | if (FRAME_PGTK_P (f) && f->output_data.pgtk->menubar_widget == 0) |
| 483 | [NSMenu setMenuBarVisible: YES]; */ | 490 | /* Make sure next redisplay shows the menu bar. */ |
| 491 | XWINDOW (FRAME_SELECTED_WINDOW (f))->update_mode_line = true; | ||
| 484 | } | 492 | } |
| 485 | else | 493 | else |
| 486 | { | 494 | { |
| 487 | if (FRAME_EXTERNAL_MENU_BAR (f) == 1) | 495 | if (FRAME_EXTERNAL_MENU_BAR (f) == 1) |
| 488 | free_frame_menubar (f); | 496 | free_frame_menubar (f); |
| 489 | /* [NSMenu setMenuBarVisible: NO]; */ | ||
| 490 | FRAME_EXTERNAL_MENU_BAR (f) = 0; | 497 | FRAME_EXTERNAL_MENU_BAR (f) = 0; |
| 498 | if (FRAME_X_P (f)) | ||
| 499 | f->output_data.pgtk->menubar_widget = 0; | ||
| 500 | } | ||
| 501 | |||
| 502 | adjust_frame_glyphs (f); | ||
| 503 | } | ||
| 504 | |||
| 505 | /* Set the pixel height of the tool bar of frame F to HEIGHT. */ | ||
| 506 | static void | ||
| 507 | x_change_tool_bar_height (struct frame *f, int height) | ||
| 508 | { | ||
| 509 | FRAME_TOOL_BAR_LINES (f) = 0; | ||
| 510 | FRAME_TOOL_BAR_HEIGHT (f) = 0; | ||
| 511 | if (height) | ||
| 512 | { | ||
| 513 | FRAME_EXTERNAL_TOOL_BAR (f) = true; | ||
| 514 | if (FRAME_X_P (f) && f->output_data.pgtk->toolbar_widget == 0) | ||
| 515 | /* Make sure next redisplay shows the tool bar. */ | ||
| 516 | XWINDOW (FRAME_SELECTED_WINDOW (f))->update_mode_line = true; | ||
| 517 | update_frame_tool_bar (f); | ||
| 518 | } | ||
| 519 | else | ||
| 520 | { | ||
| 521 | if (FRAME_EXTERNAL_TOOL_BAR (f)) | ||
| 522 | free_frame_tool_bar (f); | ||
| 523 | FRAME_EXTERNAL_TOOL_BAR (f) = false; | ||
| 491 | } | 524 | } |
| 492 | #endif | ||
| 493 | } | 525 | } |
| 494 | 526 | ||
| 495 | 527 | ||
| @@ -497,70 +529,20 @@ x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) | |||
| 497 | static void | 529 | static void |
| 498 | x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) | 530 | x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) |
| 499 | { | 531 | { |
| 500 | #if 0 | ||
| 501 | /* Currently, when the tool bar change state, the frame is resized. | ||
| 502 | |||
| 503 | TODO: It would be better if this didn't occur when 1) the frame | ||
| 504 | is full height or maximized or 2) when specified by | ||
| 505 | `frame-inhibit-implied-resize'. */ | ||
| 506 | int nlines; | 532 | int nlines; |
| 507 | 533 | ||
| 508 | NSTRACE ("x_set_tool_bar_lines"); | 534 | /* Treat tool bars like menu bars. */ |
| 509 | |||
| 510 | if (FRAME_MINIBUF_ONLY_P (f)) | 535 | if (FRAME_MINIBUF_ONLY_P (f)) |
| 511 | return; | 536 | return; |
| 512 | 537 | ||
| 513 | if (RANGED_INTEGERP (0, value, INT_MAX)) | 538 | /* Use VALUE only if an int >= 0. */ |
| 539 | if (RANGED_FIXNUMP (0, value, INT_MAX)) | ||
| 514 | nlines = XFIXNAT (value); | 540 | nlines = XFIXNAT (value); |
| 515 | else | 541 | else |
| 516 | nlines = 0; | 542 | nlines = 0; |
| 517 | 543 | ||
| 518 | if (nlines) | 544 | x_change_tool_bar_height (f, nlines * FRAME_LINE_HEIGHT (f)); |
| 519 | { | ||
| 520 | FRAME_EXTERNAL_TOOL_BAR (f) = 1; | ||
| 521 | update_frame_tool_bar (f); | ||
| 522 | } | ||
| 523 | else | ||
| 524 | { | ||
| 525 | if (FRAME_EXTERNAL_TOOL_BAR (f)) | ||
| 526 | { | ||
| 527 | free_frame_tool_bar (f); | ||
| 528 | FRAME_EXTERNAL_TOOL_BAR (f) = 0; | ||
| 529 | |||
| 530 | { | ||
| 531 | EmacsView *view = FRAME_PGTK_VIEW (f); | ||
| 532 | int fs_state = [view fullscreenState]; | ||
| 533 | |||
| 534 | if (fs_state == FULLSCREEN_MAXIMIZED) | ||
| 535 | { | ||
| 536 | [view setFSValue:FULLSCREEN_WIDTH]; | ||
| 537 | } | ||
| 538 | else if (fs_state == FULLSCREEN_HEIGHT) | ||
| 539 | { | ||
| 540 | [view setFSValue:FULLSCREEN_NONE]; | ||
| 541 | } | ||
| 542 | } | ||
| 543 | } | ||
| 544 | } | ||
| 545 | 545 | ||
| 546 | { | ||
| 547 | int inhibit | ||
| 548 | = ((f->after_make_frame | ||
| 549 | && !f->tool_bar_resized | ||
| 550 | && (EQ (frame_inhibit_implied_resize, Qt) | ||
| 551 | || (CONSP (frame_inhibit_implied_resize) | ||
| 552 | && !NILP (Fmemq (Qtool_bar_lines, | ||
| 553 | frame_inhibit_implied_resize)))) | ||
| 554 | && NILP (get_frame_param (f, Qfullscreen))) | ||
| 555 | ? 0 | ||
| 556 | : 2); | ||
| 557 | |||
| 558 | NSTRACE_MSG ("inhibit:%d", inhibit); | ||
| 559 | |||
| 560 | frame_size_history_add (f, Qupdate_frame_tool_bar, 0, 0, Qnil); | ||
| 561 | adjust_frame_size (f, -1, -1, inhibit, 0, Qtool_bar_lines); | ||
| 562 | } | ||
| 563 | #endif | ||
| 564 | } | 546 | } |
| 565 | 547 | ||
| 566 | 548 | ||
| @@ -1327,25 +1309,14 @@ This function is an internal primitive--use `make-frame' instead. */) | |||
| 1327 | gui_default_parameter (f, parms, Qno_accept_focus, Qnil, | 1309 | gui_default_parameter (f, parms, Qno_accept_focus, Qnil, |
| 1328 | NULL, NULL, RES_TYPE_BOOLEAN); | 1310 | NULL, NULL, RES_TYPE_BOOLEAN); |
| 1329 | 1311 | ||
| 1330 | #if defined (USE_X_TOOLKIT) || defined (USE_GTK) | ||
| 1331 | /* Create the menu bar. */ | 1312 | /* Create the menu bar. */ |
| 1332 | if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f)) | 1313 | if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f)) |
| 1333 | { | 1314 | { |
| 1334 | #if 0 | ||
| 1335 | /* If this signals an error, we haven't set size hints for the | 1315 | /* If this signals an error, we haven't set size hints for the |
| 1336 | frame and we didn't make it visible. */ | 1316 | frame and we didn't make it visible. */ |
| 1337 | initialize_frame_menubar (f); | 1317 | initialize_frame_menubar (f); |
| 1338 | #endif | ||
| 1339 | 1318 | ||
| 1340 | #ifndef USE_GTK | ||
| 1341 | /* This is a no-op, except under Motif where it arranges the | ||
| 1342 | main window for the widgets on it. */ | ||
| 1343 | lw_set_main_areas (FRAME_X_OUTPUT(f)->column_widget, | ||
| 1344 | FRAME_X_OUTPUT(f)->menubar_widget, | ||
| 1345 | FRAME_X_OUTPUT(f)->edit_widget); | ||
| 1346 | #endif /* not USE_GTK */ | ||
| 1347 | } | 1319 | } |
| 1348 | #endif /* USE_X_TOOLKIT || USE_GTK */ | ||
| 1349 | 1320 | ||
| 1350 | /* Consider frame official, now. */ | 1321 | /* Consider frame official, now. */ |
| 1351 | f->can_set_window_size = true; | 1322 | f->can_set_window_size = true; |
diff --git a/src/pgtkmenu.c b/src/pgtkmenu.c new file mode 100644 index 00000000000..bbe47ddad6b --- /dev/null +++ b/src/pgtkmenu.c | |||
| @@ -0,0 +1,476 @@ | |||
| 1 | /* Pure GTK3 menu and toolbar module. | ||
| 2 | Copyright (C) 2019 Free Software Foundation, Inc. | ||
| 3 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 9 | your option) any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 18 | |||
| 19 | /* | ||
| 20 | */ | ||
| 21 | |||
| 22 | |||
| 23 | /* This should be the first include, as it may set up #defines affecting | ||
| 24 | interpretation of even the system includes. */ | ||
| 25 | #include <config.h> | ||
| 26 | |||
| 27 | #include "lisp.h" | ||
| 28 | #include "frame.h" | ||
| 29 | #include "window.h" | ||
| 30 | #include "character.h" | ||
| 31 | #include "buffer.h" | ||
| 32 | #include "keymap.h" | ||
| 33 | #include "coding.h" | ||
| 34 | #include "commands.h" | ||
| 35 | #include "blockinput.h" | ||
| 36 | #include "termhooks.h" | ||
| 37 | #include "keyboard.h" | ||
| 38 | #include "menu.h" | ||
| 39 | #include "pdumper.h" | ||
| 40 | |||
| 41 | #include "gtkutil.h" | ||
| 42 | #include <gtk/gtk.h> | ||
| 43 | |||
| 44 | |||
| 45 | Lisp_Object | ||
| 46 | pgtk_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents) | ||
| 47 | { | ||
| 48 | return Qnil; | ||
| 49 | } | ||
| 50 | |||
| 51 | |||
| 52 | |||
| 53 | /* Gtk calls callbacks just because we tell it what item should be | ||
| 54 | selected in a radio group. If this variable is set to a non-zero | ||
| 55 | value, we are creating menus and don't want callbacks right now. | ||
| 56 | */ | ||
| 57 | static bool xg_crazy_callback_abort; | ||
| 58 | |||
| 59 | /* This callback is called from the menu bar pulldown menu | ||
| 60 | when the user makes a selection. | ||
| 61 | Figure out what the user chose | ||
| 62 | and put the appropriate events into the keyboard buffer. */ | ||
| 63 | static void | ||
| 64 | menubar_selection_callback (GtkWidget *widget, gpointer client_data) | ||
| 65 | { | ||
| 66 | xg_menu_item_cb_data *cb_data = client_data; | ||
| 67 | |||
| 68 | if (xg_crazy_callback_abort) | ||
| 69 | return; | ||
| 70 | |||
| 71 | if (! cb_data || ! cb_data->cl_data || ! cb_data->cl_data->f) | ||
| 72 | return; | ||
| 73 | |||
| 74 | /* For a group of radio buttons, GTK calls the selection callback first | ||
| 75 | for the item that was active before the selection and then for the one that | ||
| 76 | is active after the selection. For C-h k this means we get the help on | ||
| 77 | the deselected item and then the selected item is executed. Prevent that | ||
| 78 | by ignoring the non-active item. */ | ||
| 79 | if (GTK_IS_RADIO_MENU_ITEM (widget) | ||
| 80 | && ! gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget))) | ||
| 81 | return; | ||
| 82 | |||
| 83 | /* When a menu is popped down, X generates a focus event (i.e. focus | ||
| 84 | goes back to the frame below the menu). Since GTK buffers events, | ||
| 85 | we force it out here before the menu selection event. Otherwise | ||
| 86 | sit-for will exit at once if the focus event follows the menu selection | ||
| 87 | event. */ | ||
| 88 | |||
| 89 | block_input (); | ||
| 90 | while (gtk_events_pending ()) | ||
| 91 | gtk_main_iteration (); | ||
| 92 | unblock_input (); | ||
| 93 | |||
| 94 | find_and_call_menu_selection (cb_data->cl_data->f, | ||
| 95 | cb_data->cl_data->menu_bar_items_used, | ||
| 96 | cb_data->cl_data->menu_bar_vector, | ||
| 97 | cb_data->call_data); | ||
| 98 | } | ||
| 99 | |||
| 100 | static void | ||
| 101 | menu_highlight_callback (GtkWidget *widget, gpointer call_data) | ||
| 102 | { | ||
| 103 | xg_menu_item_cb_data *cb_data; | ||
| 104 | Lisp_Object help; | ||
| 105 | |||
| 106 | cb_data = g_object_get_data (G_OBJECT (widget), XG_ITEM_DATA); | ||
| 107 | if (! cb_data) return; | ||
| 108 | |||
| 109 | help = call_data ? cb_data->help : Qnil; | ||
| 110 | } | ||
| 111 | |||
| 112 | |||
| 113 | /* This callback is invoked when a dialog or menu is finished being | ||
| 114 | used and has been unposted. */ | ||
| 115 | |||
| 116 | static void | ||
| 117 | popup_deactivate_callback (GtkWidget *widget, gpointer client_data) | ||
| 118 | { | ||
| 119 | } | ||
| 120 | |||
| 121 | |||
| 122 | |||
| 123 | |||
| 124 | /* Set the contents of the menubar widgets of frame F. | ||
| 125 | The argument FIRST_TIME is currently ignored; | ||
| 126 | it is set the first time this is called, from initialize_frame_menubar. */ | ||
| 127 | |||
| 128 | void | ||
| 129 | set_frame_menubar (struct frame *f, bool first_time, bool deep_p) | ||
| 130 | { | ||
| 131 | GtkWidget * menubar_widget; | ||
| 132 | Lisp_Object items; | ||
| 133 | widget_value *wv, *first_wv, *prev_wv = 0; | ||
| 134 | int i; | ||
| 135 | int *submenu_start, *submenu_end; | ||
| 136 | bool *submenu_top_level_items; | ||
| 137 | int *submenu_n_panes; | ||
| 138 | |||
| 139 | |||
| 140 | menubar_widget = f->output_data.pgtk->menubar_widget; | ||
| 141 | |||
| 142 | XSETFRAME(Vmenu_updating_frame, f); | ||
| 143 | |||
| 144 | if (! menubar_widget) | ||
| 145 | deep_p = true; | ||
| 146 | |||
| 147 | if (deep_p) | ||
| 148 | { | ||
| 149 | struct buffer *prev = current_buffer; | ||
| 150 | Lisp_Object buffer; | ||
| 151 | ptrdiff_t specpdl_count = SPECPDL_INDEX (); | ||
| 152 | int previous_menu_items_used = f->menu_bar_items_used; | ||
| 153 | Lisp_Object *previous_items | ||
| 154 | = alloca (previous_menu_items_used * sizeof *previous_items); | ||
| 155 | int subitems; | ||
| 156 | |||
| 157 | /* If we are making a new widget, its contents are empty, | ||
| 158 | do always reinitialize them. */ | ||
| 159 | if (! menubar_widget) | ||
| 160 | previous_menu_items_used = 0; | ||
| 161 | |||
| 162 | buffer = XWINDOW (FRAME_SELECTED_WINDOW (f))->contents; | ||
| 163 | specbind (Qinhibit_quit, Qt); | ||
| 164 | /* Don't let the debugger step into this code | ||
| 165 | because it is not reentrant. */ | ||
| 166 | specbind (Qdebug_on_next_call, Qnil); | ||
| 167 | |||
| 168 | record_unwind_save_match_data (); | ||
| 169 | if (NILP (Voverriding_local_map_menu_flag)) | ||
| 170 | { | ||
| 171 | specbind (Qoverriding_terminal_local_map, Qnil); | ||
| 172 | specbind (Qoverriding_local_map, Qnil); | ||
| 173 | } | ||
| 174 | |||
| 175 | set_buffer_internal_1 (XBUFFER (buffer)); | ||
| 176 | |||
| 177 | /* Run the Lucid hook. */ | ||
| 178 | safe_run_hooks (Qactivate_menubar_hook); | ||
| 179 | |||
| 180 | /* If it has changed current-menubar from previous value, | ||
| 181 | really recompute the menubar from the value. */ | ||
| 182 | if (! NILP (Vlucid_menu_bar_dirty_flag)) | ||
| 183 | call0 (Qrecompute_lucid_menubar); | ||
| 184 | safe_run_hooks (Qmenu_bar_update_hook); | ||
| 185 | fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f))); | ||
| 186 | |||
| 187 | items = FRAME_MENU_BAR_ITEMS (f); | ||
| 188 | |||
| 189 | /* Save the frame's previous menu bar contents data. */ | ||
| 190 | if (previous_menu_items_used) | ||
| 191 | memcpy (previous_items, XVECTOR (f->menu_bar_vector)->contents, | ||
| 192 | previous_menu_items_used * word_size); | ||
| 193 | |||
| 194 | /* Fill in menu_items with the current menu bar contents. | ||
| 195 | This can evaluate Lisp code. */ | ||
| 196 | save_menu_items (); | ||
| 197 | |||
| 198 | menu_items = f->menu_bar_vector; | ||
| 199 | menu_items_allocated = VECTORP (menu_items) ? ASIZE (menu_items) : 0; | ||
| 200 | subitems = ASIZE (items) / 4; | ||
| 201 | submenu_start = alloca ((subitems + 1) * sizeof *submenu_start); | ||
| 202 | submenu_end = alloca (subitems * sizeof *submenu_end); | ||
| 203 | submenu_n_panes = alloca (subitems * sizeof *submenu_n_panes); | ||
| 204 | submenu_top_level_items = alloca (subitems | ||
| 205 | * sizeof *submenu_top_level_items); | ||
| 206 | init_menu_items (); | ||
| 207 | for (i = 0; i < subitems; i++) | ||
| 208 | { | ||
| 209 | Lisp_Object key, string, maps; | ||
| 210 | |||
| 211 | key = AREF (items, 4 * i); | ||
| 212 | string = AREF (items, 4 * i + 1); | ||
| 213 | maps = AREF (items, 4 * i + 2); | ||
| 214 | if (NILP (string)) | ||
| 215 | break; | ||
| 216 | |||
| 217 | submenu_start[i] = menu_items_used; | ||
| 218 | |||
| 219 | menu_items_n_panes = 0; | ||
| 220 | submenu_top_level_items[i] | ||
| 221 | = parse_single_submenu (key, string, maps); | ||
| 222 | submenu_n_panes[i] = menu_items_n_panes; | ||
| 223 | |||
| 224 | submenu_end[i] = menu_items_used; | ||
| 225 | } | ||
| 226 | |||
| 227 | submenu_start[i] = -1; | ||
| 228 | finish_menu_items (); | ||
| 229 | |||
| 230 | /* Convert menu_items into widget_value trees | ||
| 231 | to display the menu. This cannot evaluate Lisp code. */ | ||
| 232 | |||
| 233 | wv = make_widget_value ("menubar", NULL, true, Qnil); | ||
| 234 | wv->button_type = BUTTON_TYPE_NONE; | ||
| 235 | first_wv = wv; | ||
| 236 | |||
| 237 | for (i = 0; submenu_start[i] >= 0; i++) | ||
| 238 | { | ||
| 239 | menu_items_n_panes = submenu_n_panes[i]; | ||
| 240 | wv = digest_single_submenu (submenu_start[i], submenu_end[i], | ||
| 241 | submenu_top_level_items[i]); | ||
| 242 | if (prev_wv) | ||
| 243 | prev_wv->next = wv; | ||
| 244 | else | ||
| 245 | first_wv->contents = wv; | ||
| 246 | /* Don't set wv->name here; GC during the loop might relocate it. */ | ||
| 247 | wv->enabled = true; | ||
| 248 | wv->button_type = BUTTON_TYPE_NONE; | ||
| 249 | prev_wv = wv; | ||
| 250 | } | ||
| 251 | |||
| 252 | set_buffer_internal_1 (prev); | ||
| 253 | |||
| 254 | /* If there has been no change in the Lisp-level contents | ||
| 255 | of the menu bar, skip redisplaying it. Just exit. */ | ||
| 256 | |||
| 257 | /* Compare the new menu items with the ones computed last time. */ | ||
| 258 | for (i = 0; i < previous_menu_items_used; i++) | ||
| 259 | if (menu_items_used == i | ||
| 260 | || (!EQ (previous_items[i], AREF (menu_items, i)))) | ||
| 261 | break; | ||
| 262 | if (i == menu_items_used && i == previous_menu_items_used && i != 0) | ||
| 263 | { | ||
| 264 | /* The menu items have not changed. Don't bother updating | ||
| 265 | the menus in any form, since it would be a no-op. */ | ||
| 266 | free_menubar_widget_value_tree (first_wv); | ||
| 267 | discard_menu_items (); | ||
| 268 | unbind_to (specpdl_count, Qnil); | ||
| 269 | return; | ||
| 270 | } | ||
| 271 | |||
| 272 | /* The menu items are different, so store them in the frame. */ | ||
| 273 | fset_menu_bar_vector (f, menu_items); | ||
| 274 | f->menu_bar_items_used = menu_items_used; | ||
| 275 | |||
| 276 | /* This undoes save_menu_items. */ | ||
| 277 | unbind_to (specpdl_count, Qnil); | ||
| 278 | |||
| 279 | /* Now GC cannot happen during the lifetime of the widget_value, | ||
| 280 | so it's safe to store data from a Lisp_String. */ | ||
| 281 | wv = first_wv->contents; | ||
| 282 | for (i = 0; i < ASIZE (items); i += 4) | ||
| 283 | { | ||
| 284 | Lisp_Object string; | ||
| 285 | string = AREF (items, i + 1); | ||
| 286 | if (NILP (string)) | ||
| 287 | break; | ||
| 288 | wv->name = SSDATA (string); | ||
| 289 | update_submenu_strings (wv->contents); | ||
| 290 | wv = wv->next; | ||
| 291 | } | ||
| 292 | |||
| 293 | } | ||
| 294 | else | ||
| 295 | { | ||
| 296 | /* Make a widget-value tree containing | ||
| 297 | just the top level menu bar strings. */ | ||
| 298 | |||
| 299 | wv = make_widget_value ("menubar", NULL, true, Qnil); | ||
| 300 | wv->button_type = BUTTON_TYPE_NONE; | ||
| 301 | first_wv = wv; | ||
| 302 | |||
| 303 | items = FRAME_MENU_BAR_ITEMS (f); | ||
| 304 | for (i = 0; i < ASIZE (items); i += 4) | ||
| 305 | { | ||
| 306 | Lisp_Object string; | ||
| 307 | |||
| 308 | string = AREF (items, i + 1); | ||
| 309 | if (NILP (string)) | ||
| 310 | break; | ||
| 311 | |||
| 312 | wv = make_widget_value (SSDATA (string), NULL, true, Qnil); | ||
| 313 | wv->button_type = BUTTON_TYPE_NONE; | ||
| 314 | /* This prevents lwlib from assuming this | ||
| 315 | menu item is really supposed to be empty. */ | ||
| 316 | /* The intptr_t cast avoids a warning. | ||
| 317 | This value just has to be different from small integers. */ | ||
| 318 | wv->call_data = (void *) (intptr_t) (-1); | ||
| 319 | |||
| 320 | if (prev_wv) | ||
| 321 | prev_wv->next = wv; | ||
| 322 | else | ||
| 323 | first_wv->contents = wv; | ||
| 324 | prev_wv = wv; | ||
| 325 | } | ||
| 326 | |||
| 327 | /* Forget what we thought we knew about what is in the | ||
| 328 | detailed contents of the menu bar menus. | ||
| 329 | Changing the top level always destroys the contents. */ | ||
| 330 | f->menu_bar_items_used = 0; | ||
| 331 | } | ||
| 332 | |||
| 333 | block_input(); | ||
| 334 | |||
| 335 | xg_crazy_callback_abort = true; | ||
| 336 | if (menubar_widget) | ||
| 337 | { | ||
| 338 | /* The fourth arg is DEEP_P, which says to consider the entire | ||
| 339 | menu trees we supply, rather than just the menu bar item names. */ | ||
| 340 | xg_modify_menubar_widgets (menubar_widget, | ||
| 341 | f, | ||
| 342 | first_wv, | ||
| 343 | deep_p, | ||
| 344 | G_CALLBACK (menubar_selection_callback), | ||
| 345 | G_CALLBACK (popup_deactivate_callback), | ||
| 346 | G_CALLBACK (menu_highlight_callback)); | ||
| 347 | } | ||
| 348 | else | ||
| 349 | { | ||
| 350 | menubar_widget | ||
| 351 | = xg_create_widget ("menubar", "menubar", f, first_wv, | ||
| 352 | G_CALLBACK (menubar_selection_callback), | ||
| 353 | G_CALLBACK (popup_deactivate_callback), | ||
| 354 | G_CALLBACK (menu_highlight_callback)); | ||
| 355 | |||
| 356 | f->output_data.pgtk->menubar_widget = menubar_widget; | ||
| 357 | } | ||
| 358 | |||
| 359 | free_menubar_widget_value_tree (first_wv); | ||
| 360 | xg_update_frame_menubar (f); | ||
| 361 | |||
| 362 | xg_crazy_callback_abort = false; | ||
| 363 | |||
| 364 | unblock_input (); | ||
| 365 | } | ||
| 366 | |||
| 367 | |||
| 368 | |||
| 369 | /* Called from Fx_create_frame to create the initial menubar of a frame | ||
| 370 | before it is mapped, so that the window is mapped with the menubar already | ||
| 371 | there instead of us tacking it on later and thrashing the window after it | ||
| 372 | is visible. */ | ||
| 373 | |||
| 374 | void | ||
| 375 | initialize_frame_menubar (struct frame *f) | ||
| 376 | { | ||
| 377 | /* This function is called before the first chance to redisplay | ||
| 378 | the frame. It has to be, so the frame will have the right size. */ | ||
| 379 | fset_menu_bar_items (f, menu_bar_items (FRAME_MENU_BAR_ITEMS (f))); | ||
| 380 | set_frame_menubar (f, true, true); | ||
| 381 | } | ||
| 382 | |||
| 383 | |||
| 384 | void pgtk_activate_menubar (struct frame *f) | ||
| 385 | { | ||
| 386 | set_frame_menubar(f, false, false); | ||
| 387 | |||
| 388 | /* f->output_data.pgtk->menubar_active = 1; */ | ||
| 389 | } | ||
| 390 | |||
| 391 | |||
| 392 | Lisp_Object | ||
| 393 | pgtk_menu_show (struct frame *f, int x, int y, int menuflags, | ||
| 394 | Lisp_Object title, const char **error_name) | ||
| 395 | { | ||
| 396 | Lisp_Object tem; | ||
| 397 | |||
| 398 | block_input (); | ||
| 399 | |||
| 400 | |||
| 401 | unblock_input (); | ||
| 402 | |||
| 403 | // not implemented. | ||
| 404 | return Qnil; | ||
| 405 | } | ||
| 406 | |||
| 407 | DEFUN ("x-menu-bar-open-internal", Fx_menu_bar_open_internal, Sx_menu_bar_open_internal, 0, 1, "i", | ||
| 408 | doc: /* Start key navigation of the menu bar in FRAME. | ||
| 409 | This initially opens the first menu bar item and you can then navigate with the | ||
| 410 | arrow keys, select a menu entry with the return key or cancel with the | ||
| 411 | escape key. If FRAME has no menu bar this function does nothing. | ||
| 412 | |||
| 413 | If FRAME is nil or not given, use the selected frame. */) | ||
| 414 | (Lisp_Object frame) | ||
| 415 | { | ||
| 416 | GtkWidget *menubar; | ||
| 417 | struct frame *f; | ||
| 418 | |||
| 419 | block_input (); | ||
| 420 | f = decode_window_system_frame (frame); | ||
| 421 | |||
| 422 | if (FRAME_EXTERNAL_MENU_BAR (f)) | ||
| 423 | set_frame_menubar (f, false, true); | ||
| 424 | |||
| 425 | menubar = FRAME_X_OUTPUT (f)->menubar_widget; | ||
| 426 | if (menubar) | ||
| 427 | { | ||
| 428 | /* Activate the first menu. */ | ||
| 429 | GList *children = gtk_container_get_children (GTK_CONTAINER (menubar)); | ||
| 430 | |||
| 431 | if (children) | ||
| 432 | { | ||
| 433 | g_signal_emit_by_name (children->data, "activate_item"); | ||
| 434 | g_list_free (children); | ||
| 435 | } | ||
| 436 | } | ||
| 437 | unblock_input (); | ||
| 438 | |||
| 439 | return Qnil; | ||
| 440 | } | ||
| 441 | |||
| 442 | |||
| 443 | static const char * button_names [] = { | ||
| 444 | "button1", "button2", "button3", "button4", "button5", | ||
| 445 | "button6", "button7", "button8", "button9", "button10" }; | ||
| 446 | |||
| 447 | extern Lisp_Object | ||
| 448 | pgtk_dialog_show (struct frame *f, Lisp_Object title, | ||
| 449 | Lisp_Object header, char **error) | ||
| 450 | { | ||
| 451 | return Qnil; | ||
| 452 | } | ||
| 453 | |||
| 454 | /* The following is used by delayed window autoselection. */ | ||
| 455 | |||
| 456 | DEFUN ("menu-or-popup-active-p", Fmenu_or_popup_active_p, Smenu_or_popup_active_p, 0, 0, 0, | ||
| 457 | doc: /* SKIP: real doc in xmenu.c. */) | ||
| 458 | (void) | ||
| 459 | { | ||
| 460 | struct frame *f; | ||
| 461 | f = SELECTED_FRAME (); | ||
| 462 | // return (f->output_data.pgtk->menubar_active > 0) ? Qt : Qnil; | ||
| 463 | return Qnil; | ||
| 464 | } | ||
| 465 | |||
| 466 | void | ||
| 467 | syms_of_pgtkmenu (void) | ||
| 468 | { | ||
| 469 | // current_popup_menu = NULL; | ||
| 470 | // PDUMPER_IGNORE (current_popup_menu); | ||
| 471 | |||
| 472 | DEFSYM (Qdebug_on_next_call, "debug-on-next-call"); | ||
| 473 | DEFSYM (Qunsupported__w32_dialog, "unsupported--w32-dialog"); | ||
| 474 | |||
| 475 | defsubr (&Smenu_or_popup_active_p); | ||
| 476 | } | ||
diff --git a/src/pgtkterm.c b/src/pgtkterm.c index a380c11eb15..ed8d7e841be 100644 --- a/src/pgtkterm.c +++ b/src/pgtkterm.c | |||
| @@ -4253,14 +4253,6 @@ pgtk_fullscreen_hook (struct frame *f) | |||
| 4253 | } | 4253 | } |
| 4254 | } | 4254 | } |
| 4255 | 4255 | ||
| 4256 | static Lisp_Object | ||
| 4257 | pgtk_menu_show (struct frame *f, int x, int y, int menuflags, | ||
| 4258 | Lisp_Object title, const char **error_name) | ||
| 4259 | { | ||
| 4260 | // not implemented. | ||
| 4261 | return Qnil; | ||
| 4262 | } | ||
| 4263 | |||
| 4264 | /* This function is called when the last frame on a display is deleted. */ | 4256 | /* This function is called when the last frame on a display is deleted. */ |
| 4265 | void | 4257 | void |
| 4266 | pgtk_delete_terminal (struct terminal *terminal) | 4258 | pgtk_delete_terminal (struct terminal *terminal) |
| @@ -4332,7 +4324,8 @@ pgtk_create_terminal (struct pgtk_display_info *dpyinfo) | |||
| 4332 | // terminal->frame_raise_lower_hook = pgtk_frame_raise_lower; | 4324 | // terminal->frame_raise_lower_hook = pgtk_frame_raise_lower; |
| 4333 | terminal->fullscreen_hook = pgtk_fullscreen_hook; | 4325 | terminal->fullscreen_hook = pgtk_fullscreen_hook; |
| 4334 | terminal->menu_show_hook = pgtk_menu_show; | 4326 | terminal->menu_show_hook = pgtk_menu_show; |
| 4335 | // terminal->popup_dialog_hook = pgtk_popup_dialog; | 4327 | terminal->activate_menubar_hook = pgtk_activate_menubar; |
| 4328 | terminal->popup_dialog_hook = pgtk_popup_dialog; | ||
| 4336 | terminal->set_vertical_scroll_bar_hook = pgtk_set_vertical_scroll_bar; | 4329 | terminal->set_vertical_scroll_bar_hook = pgtk_set_vertical_scroll_bar; |
| 4337 | terminal->set_horizontal_scroll_bar_hook = pgtk_set_horizontal_scroll_bar; | 4330 | terminal->set_horizontal_scroll_bar_hook = pgtk_set_horizontal_scroll_bar; |
| 4338 | terminal->condemn_scroll_bars_hook = pgtk_condemn_scroll_bars; | 4331 | terminal->condemn_scroll_bars_hook = pgtk_condemn_scroll_bars; |
diff --git a/src/pgtkterm.h b/src/pgtkterm.h index d14525e740c..10dc9fc9793 100644 --- a/src/pgtkterm.h +++ b/src/pgtkterm.h | |||
| @@ -548,6 +548,12 @@ extern void pgtk_set_cr_source_with_color (struct frame *f, unsigned long color) | |||
| 548 | extern void pgtk_cr_draw_frame (cairo_t *cr, struct frame *f); | 548 | extern void pgtk_cr_draw_frame (cairo_t *cr, struct frame *f); |
| 549 | extern void pgtk_cr_destroy_surface(struct frame *f); | 549 | extern void pgtk_cr_destroy_surface(struct frame *f); |
| 550 | 550 | ||
| 551 | /* Defined in pgtkmenu.c */ | ||
| 552 | extern Lisp_Object pgtk_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents); | ||
| 553 | extern Lisp_Object pgtk_dialog_show (struct frame *f, Lisp_Object title, Lisp_Object header, char **error); | ||
| 554 | extern void initialize_frame_menubar (struct frame *); | ||
| 555 | |||
| 556 | |||
| 551 | /* Symbol initializations implemented in each pgtk sources. */ | 557 | /* Symbol initializations implemented in each pgtk sources. */ |
| 552 | extern void syms_of_pgtkterm (void); | 558 | extern void syms_of_pgtkterm (void); |
| 553 | extern void syms_of_pgtkfns (void); | 559 | extern void syms_of_pgtkfns (void); |
diff --git a/src/xdisp.c b/src/xdisp.c index e722a757806..c523111fbd1 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -25028,6 +25028,11 @@ display_menu_bar (struct window *w) | |||
| 25028 | if (FRAME_W32_P (f)) | 25028 | if (FRAME_W32_P (f)) |
| 25029 | return; | 25029 | return; |
| 25030 | #endif | 25030 | #endif |
| 25031 | #if defined (HAVE_PGTK) | ||
| 25032 | if (FRAME_PGTK_P (f)) | ||
| 25033 | return; | ||
| 25034 | #endif | ||
| 25035 | |||
| 25031 | #if defined (USE_X_TOOLKIT) || defined (USE_GTK) | 25036 | #if defined (USE_X_TOOLKIT) || defined (USE_GTK) |
| 25032 | if (FRAME_X_P (f)) | 25037 | if (FRAME_X_P (f)) |
| 25033 | return; | 25038 | return; |