1 /* Implements an elisp-programmable menubar -- Gtk interface.
2 Copyright (C) 1993, 1994 Free Software Foundation, Inc.
3 Copyright (C) 1995 Tinker Systems and INS Engineering Corp.
5 This file is part of SXEmacs
7 SXEmacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 SXEmacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 /* Synched up with: Not in FSF. */
23 /* created 16-dec-91 by jwz */
28 #include "console-gtk.h"
32 #include "commands.h" /* zmacs_regions */
35 #include "events/events.h"
38 #include "ui/window.h"
41 #include <libgnomeui/libgnomeui.h>
44 #define MENUBAR_TYPE 0
45 #define SUBMENU_TYPE 1
48 static GtkWidget *menu_descriptor_to_widget_1(Lisp_Object descr,
49 GtkAccelGroup * accel_group);
51 #define FRAME_MENUBAR_DATA(frame) ((frame)->menubar_data)
52 #define XFRAME_MENUBAR_DATA_LASTBUFF(frame) (XCAR ((frame)->menubar_data))
53 #define XFRAME_MENUBAR_DATA_UPTODATE(frame) (XCDR ((frame)->menubar_data))
55 /* This is a bogus subclass of GtkMenuBar so that the menu never tries
56 ** to be bigger than the text widget. This prevents weird resizing
57 ** when jumping around between buffers with radically different menu
61 #define GTK_XEMACS_MENUBAR(obj) GTK_CHECK_CAST (obj, gtk_xemacs_menubar_get_type (), GtkXEmacsMenubar)
62 #define GTK_XEMACS_MENUBAR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_xemacs_menubar_get_type (), GtkXEmacsMenubarClass)
63 #define GTK_IS_XEMACS_MENUBAR(obj) GTK_CHECK_TYPE (obj, gtk_xemacs_menubar_get_type ())
64 #define GTK_XEMACS_MENUBAR_FRAME(obj) GTK_XEMACS_MENUBAR (obj)->f
66 typedef struct _GtkXEmacsMenubar GtkXEmacsMenubar;
67 typedef struct _GtkXEmacsMenubarClass GtkXEmacsMenubarClass;
69 struct _GtkXEmacsMenubar {
74 struct _GtkXEmacsMenubarClass {
75 GtkMenuBarClass parent_class;
78 guint gtk_xemacs_menubar_get_type(void);
79 GtkWidget *gtk_xemacs_menubar_new(struct frame *f);
81 static void gtk_xemacs_menubar_class_init(GtkXEmacsMenubarClass * klass);
82 static void gtk_xemacs_menubar_init(GtkXEmacsMenubar * xemacs);
83 static void gtk_xemacs_menubar_size_request(GtkWidget * widget,
84 GtkRequisition * requisition);
86 guint gtk_xemacs_menubar_get_type(void)
88 static guint xemacs_menubar_type;
90 if (!xemacs_menubar_type) {
91 static const GtkTypeInfo xemacs_menubar_info = {
93 sizeof(GtkXEmacsMenubar),
94 sizeof(GtkXEmacsMenubarClass),
95 (GtkClassInitFunc) gtk_xemacs_menubar_class_init,
96 (GtkObjectInitFunc) gtk_xemacs_menubar_init,
97 /* reserved_1 */ NULL,
98 /* reserved_2 */ NULL,
99 (GtkClassInitFunc) NULL,
102 xemacs_menubar_type =
103 gtk_type_unique(gtk_menu_bar_get_type(),
104 &xemacs_menubar_info);
107 return xemacs_menubar_type;
110 static GtkWidgetClass *menubar_parent_class;
112 static void gtk_xemacs_menubar_class_init(GtkXEmacsMenubarClass * klass)
114 GtkWidgetClass *widget_class;
116 widget_class = (GtkWidgetClass *) klass;
117 menubar_parent_class =
118 (GtkWidgetClass *) gtk_type_class(gtk_menu_bar_get_type());
120 widget_class->size_request = gtk_xemacs_menubar_size_request;
123 static void gtk_xemacs_menubar_init(GtkXEmacsMenubar * xemacs)
127 static void gtk_xemacs_menubar_size_request(GtkWidget * widget,
128 GtkRequisition * requisition)
130 GtkXEmacsMenubar *x = GTK_XEMACS_MENUBAR(widget);
131 GtkRequisition frame_size;
133 menubar_parent_class->size_request(widget, requisition);
136 ** We should really only do this if the menu has not been detached!
141 gtk_widget_size_request(FRAME_GTK_TEXT_WIDGET(x->frame), &frame_size);
143 requisition->width = frame_size.width;
146 GtkWidget *gtk_xemacs_menubar_new(struct frame *f)
148 GtkXEmacsMenubar *menubar = gtk_type_new(gtk_xemacs_menubar_get_type());
152 return (GTK_WIDGET(menubar));
156 * Label with XEmacs accelerator character support.
158 * The default interfaces to GtkAccelLabel does not understand XEmacs
159 * keystroke printing conventions, nor is it convenient in the places where is
160 * it needed. This subclass provides an alternative interface more suited to
161 * XEmacs needs but does not add new functionality.
163 #define GTK_TYPE_XEMACS_ACCEL_LABEL (gtk_xemacs_accel_label_get_type ())
164 #define GTK_XEMACS_ACCEL_LABEL(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_ACCEL_LABEL, GtkXEmacsAccelLabel))
165 #define GTK_XEMACS_ACCEL_LABEL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_ACCEL_LABEL, GtkXEmacsAccelLabelClass))
166 #define GTK_IS_XEMACS_ACCEL_LABEL(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_XEMACS_ACCEL_LABEL))
167 #define GTK_IS_XEMACS_ACCEL_LABEL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_XEMACS_ACCEL_LABEL))
169 typedef struct _GtkXEmacsAccelLabel GtkXEmacsAccelLabel;
170 typedef struct _GtkXEmacsAccelLabelClass GtkXEmacsAccelLabelClass;
172 /* Instance structure. No additional fields required. */
173 struct _GtkXEmacsAccelLabel {
177 /* Class structure. No additional fields required. */
178 struct _GtkXEmacsAccelLabelClass {
179 GtkAccelLabelClass parent_class;
182 static GtkType gtk_xemacs_accel_label_get_type(void);
183 static GtkWidget *gtk_xemacs_accel_label_new(const gchar * string);
184 static void gtk_xemacs_set_accel_keys(GtkXEmacsAccelLabel * l,
186 static void gtk_xemacs_accel_label_class_init(GtkXEmacsAccelLabelClass * klass);
187 static void gtk_xemacs_accel_label_init(GtkXEmacsAccelLabel * xemacs);
189 static GtkType gtk_xemacs_accel_label_get_type(void)
191 static GtkType xemacs_accel_label_type = 0;
193 if (!xemacs_accel_label_type) {
194 static const GtkTypeInfo xemacs_accel_label_info = {
195 "GtkXEmacsAccelLabel",
196 sizeof(GtkXEmacsAccelLabel),
197 sizeof(GtkXEmacsAccelLabelClass),
198 (GtkClassInitFunc) gtk_xemacs_accel_label_class_init,
199 (GtkObjectInitFunc) gtk_xemacs_accel_label_init,
200 /* reserved_1 */ NULL,
201 /* reserved_2 */ NULL,
202 (GtkClassInitFunc) NULL,
205 xemacs_accel_label_type =
206 gtk_type_unique(gtk_accel_label_get_type(),
207 &xemacs_accel_label_info);
210 return xemacs_accel_label_type;
213 static void gtk_xemacs_accel_label_class_init(GtkXEmacsAccelLabelClass * klass)
218 static void gtk_xemacs_accel_label_init(GtkXEmacsAccelLabel * xemacs)
223 static GtkWidget *gtk_xemacs_accel_label_new(const gchar * string)
225 GtkXEmacsAccelLabel *xemacs_accel_label;
227 xemacs_accel_label = gtk_type_new(GTK_TYPE_XEMACS_ACCEL_LABEL);
229 if (string && *string)
230 gtk_label_set_text(GTK_LABEL(xemacs_accel_label), string);
232 return GTK_WIDGET(xemacs_accel_label);
235 /* Make the string <keys> the accelerator string for the label. */
236 static void gtk_xemacs_set_accel_keys(GtkXEmacsAccelLabel * l, Lisp_Object keys)
238 g_return_if_fail(l != NULL);
239 g_return_if_fail(GTK_IS_XEMACS_ACCEL_LABEL(l));
241 /* Disable the standard way of finding the accelerator string for the
243 gtk_accel_label_set_accel_widget(GTK_ACCEL_LABEL(l), NULL);
245 /* Set the string straight from the object. */
246 if (STRINGP(keys) && XSTRING_LENGTH(keys)) {
247 C_STRING_TO_EXTERNAL_MALLOC(XSTRING_DATA(keys),
248 l->label.accel_string, Qctext);
250 /* l->label.accel_string = NULL; */
254 /* We now return you to your regularly scheduled menus... */
256 int dockable_menubar;
258 /* #define TEAR_OFF_MENUS */
260 #ifdef TEAR_OFF_MENUS
264 /* Converting from XEmacs to GTK representation */
265 static Lisp_Object menu_name_to_accelerator(char *name)
272 if (*name == '_' && *(name + 1)) {
274 (int)(unsigned char)(*(name + 1));
275 return make_char(tolower(accelerator));
283 #define XEMACS_MENU_DESCR_TAG "xemacs::menu::description"
284 #define XEMACS_MENU_FILTER_TAG "xemacs::menu::filter"
285 #define XEMACS_MENU_GUIID_TAG "xemacs::menu::gui_id"
286 #define XEMACS_MENU_FIRSTTIME_TAG "xemacs::menu::first_time"
288 static void __activate_menu(GtkMenuItem *, gpointer);
290 #ifdef TEAR_OFF_MENUS
291 static void __torn_off_sir(GtkMenuItem * item, gpointer user_data)
293 GtkWidget *menu_item = GTK_WIDGET(user_data);
295 if (GTK_TEAROFF_MENU_ITEM(item)->torn_off) {
296 /* Menu was just torn off */
297 GUI_ID id = new_gui_id();
298 Lisp_Object menu_desc = Qnil;
299 GtkWidget *old_submenu = GTK_MENU_ITEM(menu_item)->submenu;
301 VOID_TO_LISP(menu_desc,
302 gtk_object_get_data(GTK_OBJECT(menu_item),
303 XEMACS_MENU_DESCR_TAG));
305 /* GCPRO all of our very own */
306 gcpro_popup_callbacks(id, menu_desc);
308 /* Hide the now detached menu from the attentions of
309 __activate_menu destroying the old submenu */
311 gtk_widget_ref(old_submenu);
312 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item),
314 gtk_widget_show_all(old_submenu);
320 /* This is called when a menu is about to be shown... this is what
321 does the delayed creation of the menu items. We populate the
322 submenu and away we go. */
323 static void __maybe_destroy(GtkWidget * child, GtkWidget * precious)
325 if (GTK_IS_MENU_ITEM(child) && !GTK_IS_TEAROFF_MENU_ITEM(child)) {
326 if (GTK_WIDGET_VISIBLE(child)) {
327 /* If we delete the menu item that was 'active' when the
328 menu was cancelled, GTK gets upset because it tries to
329 remove the focus rectangle from a (now) dead widget.
331 This widget will eventually get killed because it will
332 not be visible the next time the window is shown.
334 gtk_widget_set_sensitive(child, FALSE);
335 gtk_widget_hide_all(child);
337 gtk_widget_destroy(child);
342 /* If user_data != 0x00 then we are using a hook to build the menu. */
343 static void __activate_menu(GtkMenuItem * item, gpointer user_data)
346 gpointer force_clear =
347 gtk_object_get_data(GTK_OBJECT(item), XEMACS_MENU_FIRSTTIME_TAG);
349 gtk_object_set_data(GTK_OBJECT(item), XEMACS_MENU_FIRSTTIME_TAG, 0x00);
351 /* Delete the old contents of the menu if we are the top level menubar */
352 if (GTK_IS_MENU_BAR(GTK_WIDGET(item)->parent) || force_clear) {
353 GtkWidget *selected =
354 gtk_menu_get_active(GTK_MENU(item->submenu));
356 gtk_container_foreach(GTK_CONTAINER(item->submenu),
357 (GtkCallback) __maybe_destroy, selected);
358 } else if (gtk_container_children(GTK_CONTAINER(item->submenu))) {
363 gtk_object_get_data(GTK_OBJECT(item),
364 XEMACS_MENU_DESCR_TAG));
366 #ifdef TEAR_OFF_MENUS
367 /* Lets stick in a detacher just for giggles */
369 && !gtk_container_children(GTK_CONTAINER(item->submenu))) {
370 GtkWidget *w = gtk_tearoff_menu_item_new();
372 gtk_menu_append(GTK_MENU(item->submenu), w);
373 gtk_signal_connect(GTK_OBJECT(w), "activate",
374 GTK_SIGNAL_FUNC(__torn_off_sir), item);
380 (GUI_ID) gtk_object_get_data(GTK_OBJECT(item),
381 XEMACS_MENU_GUIID_TAG);
383 struct gcpro gcpro1, gcpro2;
385 VOID_TO_LISP(hook_fn,
386 gtk_object_get_data(GTK_OBJECT(item),
387 XEMACS_MENU_FILTER_TAG));
389 GCPRO2(desc, hook_fn);
391 desc = call1(hook_fn, desc);
395 ungcpro_popup_callbacks(id);
396 gcpro_popup_callbacks(id, desc);
399 /* Build the child widgets */
400 for (; !NILP(desc); desc = Fcdr(desc)) {
401 GtkWidget *next = NULL;
402 Lisp_Object child = Fcar(desc);
404 if (NILP(child)) { /* the partition */
405 /* Signal an error here? The NILP handling is handled a
406 layer higher where appropriate */
408 next = menu_descriptor_to_widget_1(child,
409 gtk_menu_ensure_uline_accel_group
418 gtk_widget_show_all(next);
419 gtk_menu_append(GTK_MENU(item->submenu), next);
423 /* This is called whenever an item with a GUI_ID associated with it is
424 destroyed. This allows us to remove the references in gui-gtk.c
425 that made sure callbacks and such were GCPRO-ed
427 static void __remove_gcpro_by_id(gpointer user_data)
429 ungcpro_popup_callbacks((GUI_ID) user_data);
432 static void __kill_stupid_gtk_timer(GtkObject * obj, gpointer user_data)
434 GtkMenuItem *mi = GTK_MENU_ITEM(obj);
437 gtk_timeout_remove(mi->timer);
442 /* Convert the XEmacs menu accelerator representation to Gtk mnemonic form. If
443 no accelerator has been provided, put one at the start of the string (this
444 mirrors the behaviour under X). This algorithm is also found in
445 dialog-gtk.el:gtk-popup-convert-underscores.
447 static char *convert_underscores(const char *name)
451 int found_accel = FALSE;
454 for (i = 0; name[i]; ++i)
455 if (name[i] == '%' && name[i + 1] == '_') {
457 } else if (name[i] == '_') {
461 /* Allocate space for the original string, plus zero byte plus extra space
462 for all quoted underscores plus possible additional leading accelerator. */
463 rval = xmalloc_and_zero(strlen(name) + 1 + underscores
464 + (found_accel ? 0 : 1));
469 for (i = 0, j = (found_accel ? 0 : 1); name[i]; i++) {
470 if (name[i] == '%') {
475 if ((name[i] != '_') && (name[i] != '%'))
479 } else if (name[i] == '_') {
489 /* Remove the XEmacs menu accellerator representation from a string. */
490 static char *remove_underscores(const char *name)
492 char *rval = xmalloc_and_zero(strlen(name) + 1);
495 for (i = 0, j = 0; name[i]; i++) {
496 if (name[i] == '%') {
501 if ((name[i] != '_') && (name[i] != '%'))
511 /* This converts an entire menu into a GtkMenuItem (with an attached
512 submenu). A menu is a list of (STRING [:keyword value]+ [DESCR]+)
513 DESCR is either a list (meaning a submenu), a vector, or nil (if
514 you include a :filter keyword) */
515 static GtkWidget *menu_convert(Lisp_Object desc, GtkWidget * reuse,
516 GtkAccelGroup * menubar_accel_group)
518 GtkWidget *menu_item = NULL;
519 GtkWidget *submenu = NULL;
520 Lisp_Object key, val;
521 Lisp_Object include_p = Qnil, hook_fn = Qnil, config_tag = Qnil;
522 Lisp_Object active_p = Qt;
524 int included_spec = 0;
527 if (STRINGP(XCAR(desc))) {
528 accel = menu_name_to_accelerator(XSTRING_DATA(XCAR(desc)));
531 char *temp_menu_name =
532 convert_underscores(XSTRING_DATA(XCAR(desc)));
533 GtkWidget *accel_label =
534 gtk_xemacs_accel_label_new(NULL);
537 gtk_misc_set_alignment(GTK_MISC(accel_label), 0.0, 0.5);
539 gtk_label_parse_uline(GTK_LABEL(accel_label),
542 menu_item = gtk_menu_item_new();
543 gtk_container_add(GTK_CONTAINER(menu_item),
545 gtk_widget_show(accel_label);
547 if (menubar_accel_group)
548 gtk_widget_add_accelerator(menu_item,
554 free(temp_menu_name);
559 submenu = gtk_menu_new();
560 gtk_widget_show(menu_item);
561 gtk_widget_show(submenu);
564 gtk_signal_connect(GTK_OBJECT(menu_item), "destroy",
566 (__kill_stupid_gtk_timer), NULL);
568 /* Without this sometimes a submenu gets left on the screen -
571 if (GTK_MENU_ITEM(menu_item)->submenu) {
572 gtk_widget_destroy(GTK_MENU_ITEM(menu_item)->submenu);
575 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_item), submenu);
577 /* We put this bogus menu item in so that GTK does the right
578 ** thing when the menu is near the screen border.
583 GtkWidget *bogus_item =
584 gtk_menu_item_new_with_label
585 ("A suitably long label here...");
587 gtk_object_set_data(GTK_OBJECT(menu_item),
588 XEMACS_MENU_FIRSTTIME_TAG,
590 gtk_widget_show_all(bogus_item);
591 gtk_menu_append(GTK_MENU(submenu), bogus_item);
596 while (key = Fcar(desc), KEYWORDP(key)) {
597 Lisp_Object cascade = desc;
601 ("keyword in menu lacks a value", cascade);
604 if (EQ(key, Q_included))
605 include_p = val, included_spec = 1;
606 else if (EQ(key, Q_config))
608 else if (EQ(key, Q_filter))
610 else if (EQ(key, Q_active))
611 active_p = val, active_spec = 1;
612 else if (EQ(key, Q_accelerator)) {
616 wv->accel = LISP_TO_VOID(val);
619 ("bad keyboard accelerator", val);
621 } else if (EQ(key, Q_label)) {
622 /* implement in 21.2 */
625 ("unknown menu cascade keyword", cascade);
628 gtk_object_set_data(GTK_OBJECT(menu_item),
629 XEMACS_MENU_DESCR_TAG, LISP_TO_VOID(desc));
630 gtk_object_set_data(GTK_OBJECT(menu_item),
631 XEMACS_MENU_FILTER_TAG,
632 LISP_TO_VOID(hook_fn));
634 if ((!NILP(config_tag)
635 && NILP(Fmemq(config_tag, Vmenubar_configuration)))
636 || (included_spec && NILP(Feval(include_p)))) {
641 active_p = Feval(active_p);
643 gtk_widget_set_sensitive(GTK_WIDGET(menu_item),
647 ("menu name (first element) must be a string", desc);
650 /* If we are reusing a widget, we need to make sure we clean
655 gtk_object_get_data(GTK_OBJECT(reuse),
656 XEMACS_MENU_GUIID_TAG);
659 /* If the menu item had a GUI_ID that means it was a filter menu */
660 __remove_gcpro_by_id(id);
661 gtk_signal_disconnect_by_func(GTK_OBJECT(reuse),
666 gtk_signal_disconnect_by_func(GTK_OBJECT(reuse),
668 (__activate_menu), NULL);
671 GTK_MENU_ITEM(reuse)->right_justify = 0;
675 /* Generic menu builder */
676 gtk_signal_connect(GTK_OBJECT(menu_item), "activate",
677 GTK_SIGNAL_FUNC(__activate_menu), NULL);
679 GUI_ID id = new_gui_id();
681 gtk_object_set_data(GTK_OBJECT(menu_item),
682 XEMACS_MENU_GUIID_TAG, (gpointer) id);
684 /* Make sure we gcpro the menu descriptions */
685 gcpro_popup_callbacks(id, desc);
686 gtk_object_weakref(GTK_OBJECT(menu_item), __remove_gcpro_by_id,
689 gtk_signal_connect(GTK_OBJECT(menu_item), "activate",
690 GTK_SIGNAL_FUNC(__activate_menu),
697 /* Called whenever a button, radio, or toggle is selected in the menu */
698 static void __generic_button_callback(GtkMenuItem * item, gpointer user_data)
700 Lisp_Object callback, function, data, channel;
702 XSETFRAME(channel, gtk_widget_to_frame(GTK_WIDGET(item)));
704 VOID_TO_LISP(callback, user_data);
706 get_gui_callback(callback, &function, &data);
708 signal_special_gtk_user_event(channel, function, data);
711 /* Convert a single menu item descriptor to a suitable GtkMenuItem */
712 /* This function cannot GC.
713 It is only called from menu_item_descriptor_to_widget_value, which
715 static GtkWidget *menu_descriptor_to_widget_1(Lisp_Object descr,
716 GtkAccelGroup * accel_group)
718 if (STRINGP(descr)) {
719 /* It is a separator. Unfortunately GTK does not allow us to
720 specify what our separators look like, so we can't do all the
721 fancy stuff that the X code does.
723 return (gtk_menu_item_new());
724 } else if (LISTP(descr)) {
725 /* It is a submenu */
726 return (menu_convert(descr, NULL, accel_group));
727 } else if (VECTORP(descr)) {
728 /* An actual menu item description! This gets yucky. */
729 Lisp_Object name = Qnil;
730 Lisp_Object callback = Qnil;
731 Lisp_Object suffix = Qnil;
732 Lisp_Object active_p = Qt;
733 Lisp_Object include_p = Qt;
734 Lisp_Object selected_p = Qnil;
735 Lisp_Object keys = Qnil;
736 Lisp_Object style = Qnil;
737 Lisp_Object config_tag = Qnil;
738 Lisp_Object accel = Qnil;
739 GtkWidget *main_label = NULL;
740 int length = XVECTOR_LENGTH(descr);
741 Lisp_Object *contents = XVECTOR_DATA(descr);
743 int selected_spec = 0, included_spec = 0;
744 GtkWidget *widget = NULL;
749 ("button descriptors must be at least 2 long",
752 /* length 2: [ "name" callback ]
753 length 3: [ "name" callback active-p ]
754 length 4: [ "name" callback active-p suffix ]
755 or [ "name" callback keyword value ]
756 length 5+: [ "name" callback [ keyword value ]+ ]
758 plist_p = (length >= 5
759 || (length > 2 && KEYWORDP(contents[2])));
761 if (!plist_p && length > 2)
765 callback = contents[1];
766 active_p = contents[2];
768 suffix = contents[3];
774 ("button descriptor has an odd number of keywords and values",
778 callback = contents[1];
779 for (i = 2; i < length;) {
780 Lisp_Object key = contents[i++];
781 Lisp_Object val = contents[i++];
783 signal_simple_error_2("not a keyword",
786 if (EQ(key, Q_active))
788 else if (EQ(key, Q_suffix))
790 else if (EQ(key, Q_keys))
792 else if (EQ(key, Q_key_sequence)) ; /* ignored for FSF compat */
793 else if (EQ(key, Q_label)) ; /* implement for 21.0 */
794 else if (EQ(key, Q_style))
796 else if (EQ(key, Q_selected))
797 selected_p = val, selected_spec = 1;
798 else if (EQ(key, Q_included))
799 include_p = val, included_spec = 1;
800 else if (EQ(key, Q_config))
802 else if (EQ(key, Q_accelerator)) {
803 if (SYMBOLP(val) || CHARP(val))
807 ("bad keyboard accelerator",
809 } else if (EQ(key, Q_filter))
811 (":filter keyword not permitted on leaf nodes",
814 signal_simple_error_2
815 ("unknown menu item keyword", key,
821 if ((!NILP(config_tag)
822 && NILP(Fmemq(config_tag, Vmenubar_configuration)))
823 || (included_spec && NILP(Feval(include_p)))) {
824 /* the include specification says to ignore this item. */
827 #endif /* HAVE_MENUBARS */
832 accel = menu_name_to_accelerator(XSTRING_DATA(name));
835 suffix = Feval(suffix);
837 if (!separator_string_p(XSTRING_DATA(name))) {
838 char *label_buffer = NULL;
839 char *temp_label = NULL;
841 if (STRINGP(suffix) && XSTRING_LENGTH(suffix)) {
843 alloca(XSTRING_LENGTH(name) + 15 +
844 XSTRING_LENGTH(suffix));
845 sprintf(label_buffer, "%s %s ",
847 XSTRING_DATA(suffix));
850 alloca(XSTRING_LENGTH(name) + 15);
851 sprintf(label_buffer, "%s ",
855 temp_label = convert_underscores(label_buffer);
856 main_label = gtk_xemacs_accel_label_new(NULL);
858 gtk_label_parse_uline(GTK_LABEL(main_label),
863 /* Evaluate the selected and active items now */
865 if (NILP(selected_p) || EQ(selected_p, Qt)) {
868 selected_p = Feval(selected_p);
872 if (NILP(active_p) || EQ(active_p, Qt)) {
875 active_p = Feval(active_p);
880 menubar_show_keybindings
883 /* Need to get keybindings */
885 /* User-specified string to generate key bindings with */
888 keys = Fsubstitute_command_keys(keys);
889 } else if (SYMBOLP(callback)) {
892 /* #### Warning, dependency here on current_buffer and point */
893 where_is_to_char(callback, buf);
895 keys = build_string(buf);
899 /* Now we get down to the dirty business of creating the widgets */
900 if (NILP(style) || EQ(style, Qtext) || EQ(style, Qbutton)) {
901 /* A normal menu item */
902 widget = gtk_menu_item_new();
903 } else if (EQ(style, Qtoggle) || EQ(style, Qradio)) {
904 /* They are radio or toggle buttons.
906 XEmacs' menu descriptions are fairly lame in that they do
907 not have the idea of a 'group' of radio buttons. They
908 are exactly like toggle buttons except that they get
911 GTK rips us a new one again. If you have a radio button
912 in a group by itself, it always draws it as highlighted.
913 So we dummy up and create a second radio button that does
914 not get added to the menu, but gets invisibly set/unset
915 when the other gets unset/set. *sigh*
918 if (EQ(style, Qradio)) {
919 GtkWidget *dummy_sibling = NULL;
920 GSList *group = NULL;
922 dummy_sibling = gtk_radio_menu_item_new(group);
924 gtk_radio_menu_item_group
925 (GTK_RADIO_MENU_ITEM(dummy_sibling));
926 widget = gtk_radio_menu_item_new(group);
928 /* We need to notice when the 'real' one gets destroyed
929 so we can clean up the dummy as well. */
930 gtk_object_weakref(GTK_OBJECT(widget),
935 widget = gtk_check_menu_item_new();
938 /* What horrible defaults you have GTK dear! The default
939 for a toggle menu item is to not show the toggle unless it
940 is turned on or actively highlighted. How absolutely
942 gtk_check_menu_item_set_show_toggle(GTK_CHECK_MENU_ITEM
944 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM
946 NILP(selected_p) ? FALSE
949 signal_simple_error_2("unknown style", style, descr);
952 gtk_widget_set_sensitive(widget, !NILP(active_p));
954 gtk_signal_connect(GTK_OBJECT(widget), "activate-item",
955 GTK_SIGNAL_FUNC(__generic_button_callback),
956 LISP_TO_VOID(callback));
958 gtk_signal_connect(GTK_OBJECT(widget), "activate",
959 GTK_SIGNAL_FUNC(__generic_button_callback),
960 LISP_TO_VOID(callback));
962 /* Now that all the information about the menu item is know, set the
963 remaining properties.
967 gtk_container_add(GTK_CONTAINER(widget), main_label);
969 gtk_misc_set_alignment(GTK_MISC(main_label), 0.0, 0.5);
970 gtk_xemacs_set_accel_keys(GTK_XEMACS_ACCEL_LABEL
974 gtk_widget_add_accelerator(widget,
988 static GtkWidget *menu_descriptor_to_widget(Lisp_Object descr,
989 GtkAccelGroup * accel_group)
991 int count = specpdl_depth();
992 GtkWidget *rval = NULL;
994 record_unwind_protect(restore_gc_inhibit,
995 make_int(gc_currently_forbidden));
997 gc_currently_forbidden = 1;
999 /* Cannot GC from here on out... */
1000 rval = menu_descriptor_to_widget_1(descr, accel_group);
1001 unbind_to(count, Qnil);
1006 static gboolean menu_can_reuse_widget(GtkWidget * child, const char *label)
1008 /* Everything up at the top level was done using
1009 ** gtk_xemacs_accel_label_new(), but we still double check to make
1010 ** sure we don't seriously foobar ourselves.
1012 gpointer possible_child =
1013 g_list_nth_data(gtk_container_children(GTK_CONTAINER(child)), 0);
1014 gboolean ret_val = FALSE;
1016 if (possible_child && GTK_IS_LABEL(possible_child)) {
1017 char *temp_label = remove_underscores(label);
1019 if (!strcmp(GTK_LABEL(possible_child)->label, temp_label))
1028 /* Converts a menubar description into a GtkMenuBar... a menubar is a
1029 list of menus or buttons
1031 static void menu_create_menubar(struct frame *f, Lisp_Object descr)
1033 gboolean right_justify = FALSE;
1034 Lisp_Object tail = Qnil;
1035 Lisp_Object value = descr;
1036 Lisp_Object item_descr = Qnil;
1037 GtkWidget *menubar = FRAME_GTK_MENUBAR_WIDGET(f);
1039 (GUI_ID) gtk_object_get_data(GTK_OBJECT(menubar),
1040 XEMACS_MENU_GUIID_TAG);
1041 guint menu_position = 0;
1042 GtkAccelGroup *menubar_accel_group;
1044 /* Remove any existing protection for old menu items */
1045 ungcpro_popup_callbacks(id);
1047 /* GCPRO the whole damn thing */
1048 gcpro_popup_callbacks(id, descr);
1050 menubar_accel_group = gtk_accel_group_new();
1052 EXTERNAL_LIST_LOOP(tail, value) {
1053 gpointer current_child =
1054 g_list_nth_data(GTK_MENU_SHELL(menubar)->children,
1057 item_descr = XCAR(tail);
1059 if (NILP(item_descr)) {
1060 /* Need to start right-justifying menus */
1061 right_justify = TRUE;
1063 } else if (VECTORP(item_descr)) {
1064 /* It is a button description */
1068 menu_descriptor_to_widget(item_descr,
1069 menubar_accel_group);
1070 gtk_widget_set_name(item, "XEmacsMenuButton");
1074 gtk_menu_item_new_with_label
1075 ("ITEM CREATION ERROR");
1078 gtk_widget_show_all(item);
1080 gtk_widget_destroy(GTK_WIDGET(current_child));
1081 gtk_menu_bar_insert(GTK_MENU_BAR(menubar), item,
1083 } else if (LISTP(item_descr)) {
1084 /* Need to actually convert it into a menu and slap it in */
1086 gboolean reused_p = FALSE;
1088 /* We may be able to reuse the widget, let's at least check. */
1090 && menu_can_reuse_widget(GTK_WIDGET(current_child),
1095 menu_convert(item_descr,
1096 GTK_WIDGET(current_child),
1097 menubar_accel_group);
1101 menu_convert(item_descr, NULL,
1102 menubar_accel_group);
1104 gtk_widget_destroy(GTK_WIDGET
1106 gtk_menu_bar_insert(GTK_MENU_BAR(menubar),
1107 widget, menu_position);
1112 gtk_menu_item_right_justify
1113 (GTK_MENU_ITEM(widget));
1115 widget = gtk_menu_item_new_with_label("ERROR");
1118 gtk_widget_show_all(widget);
1119 } else if (STRINGP(item_descr)) {
1120 /* Do I really want to be this careful? Anything else in a
1121 menubar description is illegal */
1126 /* Need to delete any menu items that were past the bounds of the new one */
1131 g_list_nth(GTK_MENU_SHELL(menubar)->children,
1133 gpointer data = l->data;
1134 g_list_remove_link(GTK_MENU_SHELL(menubar)->children,
1138 gtk_widget_destroy(GTK_WIDGET(data));
1143 /* Attach the new accelerator group to the frame. */
1144 gtk_window_add_accel_group(GTK_WINDOW(FRAME_GTK_SHELL_WIDGET(f)),
1145 menubar_accel_group);
1148 /* Deal with getting/setting the menubar */
1149 #ifndef GNOME_IS_APP
1150 #define GNOME_IS_APP(x) 0
1151 #define gnome_app_set_menus(x,y)
1155 run_menubar_hook(GtkWidget * widget, GdkEventButton * event, gpointer user_data)
1157 if (!GTK_MENU_SHELL(widget)->active) {
1158 run_hook(Qactivate_menubar_hook);
1163 static void create_menubar_widget(struct frame *f)
1165 GUI_ID id = new_gui_id();
1166 GtkWidget *handlebox = NULL;
1167 GtkWidget *menubar = gtk_xemacs_menubar_new(f);
1169 if (GNOME_IS_APP(FRAME_GTK_SHELL_WIDGET(f))) {
1170 gnome_app_set_menus(GNOME_APP(FRAME_GTK_SHELL_WIDGET(f)),
1171 GTK_MENU_BAR(menubar));
1172 } else if (dockable_menubar) {
1173 handlebox = gtk_handle_box_new();
1174 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(handlebox),
1176 gtk_container_add(GTK_CONTAINER(handlebox), menubar);
1177 gtk_box_pack_start(GTK_BOX(FRAME_GTK_CONTAINER_WIDGET(f)),
1178 handlebox, FALSE, FALSE, 0);
1180 gtk_box_pack_start(GTK_BOX(FRAME_GTK_CONTAINER_WIDGET(f)),
1181 menubar, FALSE, FALSE, 0);
1184 gtk_signal_connect(GTK_OBJECT(menubar), "button-press-event",
1185 GTK_SIGNAL_FUNC(run_menubar_hook), NULL);
1187 FRAME_GTK_MENUBAR_WIDGET(f) = menubar;
1188 gtk_object_set_data(GTK_OBJECT(menubar), XEMACS_MENU_GUIID_TAG,
1190 gtk_object_weakref(GTK_OBJECT(menubar), __remove_gcpro_by_id,
1194 static int set_frame_menubar(struct frame *f, int first_time_p)
1196 Lisp_Object menubar;
1197 int menubar_visible;
1198 /* As for the toolbar, the minibuffer does not have its own menubar. */
1199 struct window *w = XWINDOW(FRAME_LAST_NONMINIBUF_WINDOW(f));
1201 if (!FRAME_GTK_P(f))
1204 /***** first compute the contents of the menubar *****/
1206 if (!first_time_p) {
1207 /* evaluate `current-menubar' in the buffer of the selected window
1208 of the frame in question. */
1209 menubar = symbol_value_in_buffer(Qcurrent_menubar, w->buffer);
1211 /* That's a little tricky the first time since the frame isn't
1212 fully initialized yet. */
1213 menubar = Fsymbol_value(Qcurrent_menubar);
1216 if (NILP(menubar)) {
1217 menubar = Vblank_menubar;
1218 menubar_visible = 0;
1220 menubar_visible = !NILP(w->menubar_visible_p);
1223 if (!FRAME_GTK_MENUBAR_WIDGET(f)) {
1224 create_menubar_widget(f);
1227 /* Populate the menubar, but nothing is shown yet */
1229 Lisp_Object old_buffer;
1230 int count = specpdl_depth();
1232 old_buffer = Fcurrent_buffer();
1233 record_unwind_protect(Fset_buffer, old_buffer);
1234 Fset_buffer(XWINDOW(FRAME_SELECTED_WINDOW(f))->buffer);
1236 menu_create_menubar(f, menubar);
1238 Fset_buffer(old_buffer);
1239 unbind_to(count, Qnil);
1242 FRAME_MENUBAR_DATA(f) =
1243 Fcons(XWINDOW(FRAME_LAST_NONMINIBUF_WINDOW(f))->buffer, Qt);
1245 return (menubar_visible);
1248 /* Called from gtk_create_widgets() to create the inital menubar of a frame
1249 before it is mapped, so that the window is mapped with the menubar already
1250 there instead of us tacking it on later and thrashing the window after it
1252 int gtk_initialize_frame_menubar(struct frame *f)
1254 create_menubar_widget(f);
1255 return set_frame_menubar(f, 1);
1258 static void gtk_update_frame_menubar_internal(struct frame *f)
1260 /* We assume the menubar contents has changed if the global flag is set,
1261 or if the current buffer has changed, or if the menubar has never
1262 been updated before.
1264 int menubar_contents_changed =
1265 (f->menubar_changed || NILP(FRAME_MENUBAR_DATA(f))
1266 || (!EQ(XFRAME_MENUBAR_DATA_LASTBUFF(f),
1267 XWINDOW(FRAME_LAST_NONMINIBUF_WINDOW(f))->buffer)));
1269 gboolean menubar_was_visible =
1270 GTK_WIDGET_VISIBLE(FRAME_GTK_MENUBAR_WIDGET(f));
1271 gboolean menubar_will_be_visible = menubar_was_visible;
1272 gboolean menubar_visibility_changed;
1274 if (menubar_contents_changed) {
1275 menubar_will_be_visible = set_frame_menubar(f, 0);
1278 menubar_visibility_changed =
1279 menubar_was_visible != menubar_will_be_visible;
1281 if (!menubar_visibility_changed) {
1285 /* We hide and show the menubar's parent (which is actually the
1286 GtkHandleBox)... this is to simplify the code that destroys old
1287 menu items, etc. There is no easy way to get the child out of a
1288 handle box, and I didn't want to add yet another stupid widget
1289 slot to struct gtk_frame. */
1290 if (menubar_will_be_visible) {
1291 gtk_widget_show_all(FRAME_GTK_MENUBAR_WIDGET(f)->parent);
1293 gtk_widget_hide_all(FRAME_GTK_MENUBAR_WIDGET(f)->parent);
1296 MARK_FRAME_SIZE_SLIPPED(f);
1299 static void gtk_update_frame_menubars(struct frame *f)
1301 GtkWidget *menubar = NULL;
1303 assert(FRAME_GTK_P(f));
1305 menubar = FRAME_GTK_MENUBAR_WIDGET(f);
1307 if ((GTK_MENU_SHELL(menubar)->active) ||
1308 (GTK_MENU_SHELL(menubar)->have_grab) ||
1309 (GTK_MENU_SHELL(menubar)->have_xgrab)) {
1313 gtk_update_frame_menubar_internal(f);
1316 static void gtk_free_frame_menubars(struct frame *f)
1318 GtkWidget *menubar_widget;
1320 assert(FRAME_GTK_P(f));
1322 menubar_widget = FRAME_GTK_MENUBAR_WIDGET(f);
1323 if (menubar_widget) {
1324 gtk_widget_destroy(menubar_widget);
1328 static void popdown_menu_cb(GtkMenuShell * menu, gpointer user_data)
1333 static void gtk_popup_menu(Lisp_Object menu_desc, Lisp_Object event)
1335 struct Lisp_Event *eev = NULL;
1336 GtkWidget *widget = NULL;
1337 GtkWidget *menu = NULL;
1340 /* Do basic error checking first... */
1341 if (SYMBOLP(menu_desc))
1342 menu_desc = Fsymbol_value(menu_desc);
1343 CHECK_CONS(menu_desc);
1344 CHECK_STRING(XCAR(menu_desc));
1346 /* Now lets get down to business... */
1347 widget = menu_descriptor_to_widget(menu_desc, NULL);
1348 menu = GTK_MENU_ITEM(widget)->submenu;
1349 gtk_widget_set_name(widget, "XEmacsPopupMenu");
1350 id = gtk_object_get_data(GTK_OBJECT(widget), XEMACS_MENU_GUIID_TAG);
1352 __activate_menu(GTK_MENU_ITEM(widget), id);
1355 CHECK_LIVE_EVENT(event);
1356 eev = XEVENT(event);
1358 if ((eev->event_type != button_press_event) &&
1359 (eev->event_type != button_release_event))
1360 wrong_type_argument(Qmouse_event_p, event);
1361 } else if (!NILP(Vthis_command_keys)) {
1362 /* If an event wasn't passed, use the last event of the event
1363 sequence currently being executed, if that event is a mouse
1365 eev = XEVENT(Vthis_command_keys);
1366 if ((eev->event_type != button_press_event) &&
1367 (eev->event_type != button_release_event))
1371 gtk_widget_show(menu);
1374 gtk_signal_connect(GTK_OBJECT(menu), "deactivate",
1375 GTK_SIGNAL_FUNC(popdown_menu_cb), NULL);
1377 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1378 eev ? eev->event.button.button : 0,
1379 eev ? eev->timestamp : GDK_CURRENT_TIME);
1382 DEFUN("gtk-build-xemacs-menu", Fgtk_build_xemacs_menu, 1, 1, 0, /*
1383 Returns a GTK menu item from MENU, a standard XEmacs menu description.
1384 See the definition of `popup-menu' for more information on the format of MENU.
1388 GtkWidget *w = menu_descriptor_to_widget(menu, NULL);
1390 return (w ? build_gtk_object(GTK_OBJECT(w)) : Qnil);
1393 void syms_of_menubar_gtk(void)
1395 DEFSUBR(Fgtk_build_xemacs_menu);
1398 void console_type_create_menubar_gtk(void)
1400 CONSOLE_HAS_METHOD(gtk, update_frame_menubars);
1401 CONSOLE_HAS_METHOD(gtk, free_frame_menubars);
1402 CONSOLE_HAS_METHOD(gtk, popup_menu);
1405 void reinit_vars_of_menubar_gtk(void)
1407 dockable_menubar = 1;
1408 #ifdef TEAR_OFF_MENUS
1413 void vars_of_menubar_gtk(void)
1415 Fprovide(intern("gtk-menubars"));
1416 DEFVAR_BOOL("menubar-dockable-p", &dockable_menubar /*
1417 If non-nil, the frame menubar can be detached into its own top-level window.
1419 #ifdef TEAR_OFF_MENUS
1420 DEFVAR_BOOL("menubar-tearable-p", &tear_off_menus /*
1421 If non-nil, menus can be torn off into their own top-level windows.
1424 reinit_vars_of_menubar_gtk();