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;
842 if (STRINGP(suffix) && XSTRING_LENGTH(suffix)) {
843 maxsz = XSTRING_LENGTH(name) + 15 +
844 XSTRING_LENGTH(suffix);
845 label_buffer = alloca(maxsz);
846 sz = snprintf(label_buffer, maxsz, "%s %s ",
848 XSTRING_DATA(suffix));
849 assert(sz>=0 && sz<maxsz);
851 maxsz = XSTRING_LENGTH(name) + 15;
852 label_buffer = alloca(maxsz);
853 sz = sprintf(label_buffer, maxsz, "%s ",
855 assert(sz>=0 && sz<maxsz);
858 temp_label = convert_underscores(label_buffer);
859 main_label = gtk_xemacs_accel_label_new(NULL);
861 gtk_label_parse_uline(GTK_LABEL(main_label),
866 /* Evaluate the selected and active items now */
868 if (NILP(selected_p) || EQ(selected_p, Qt)) {
871 selected_p = Feval(selected_p);
875 if (NILP(active_p) || EQ(active_p, Qt)) {
878 active_p = Feval(active_p);
883 menubar_show_keybindings
886 /* Need to get keybindings */
888 /* User-specified string to generate key bindings with */
891 keys = Fsubstitute_command_keys(keys);
892 } else if (SYMBOLP(callback)) {
895 /* #### Warning, dependency here on current_buffer and point */
896 where_is_to_char(callback, buf);
898 keys = build_string(buf);
902 /* Now we get down to the dirty business of creating the widgets */
903 if (NILP(style) || EQ(style, Qtext) || EQ(style, Qbutton)) {
904 /* A normal menu item */
905 widget = gtk_menu_item_new();
906 } else if (EQ(style, Qtoggle) || EQ(style, Qradio)) {
907 /* They are radio or toggle buttons.
909 XEmacs' menu descriptions are fairly lame in that they do
910 not have the idea of a 'group' of radio buttons. They
911 are exactly like toggle buttons except that they get
914 GTK rips us a new one again. If you have a radio button
915 in a group by itself, it always draws it as highlighted.
916 So we dummy up and create a second radio button that does
917 not get added to the menu, but gets invisibly set/unset
918 when the other gets unset/set. *sigh*
921 if (EQ(style, Qradio)) {
922 GtkWidget *dummy_sibling = NULL;
923 GSList *group = NULL;
925 dummy_sibling = gtk_radio_menu_item_new(group);
927 gtk_radio_menu_item_group
928 (GTK_RADIO_MENU_ITEM(dummy_sibling));
929 widget = gtk_radio_menu_item_new(group);
931 /* We need to notice when the 'real' one gets destroyed
932 so we can clean up the dummy as well. */
933 gtk_object_weakref(GTK_OBJECT(widget),
938 widget = gtk_check_menu_item_new();
941 /* What horrible defaults you have GTK dear! The default
942 for a toggle menu item is to not show the toggle unless it
943 is turned on or actively highlighted. How absolutely
945 gtk_check_menu_item_set_show_toggle(GTK_CHECK_MENU_ITEM
947 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM
949 NILP(selected_p) ? FALSE
952 signal_simple_error_2("unknown style", style, descr);
955 gtk_widget_set_sensitive(widget, !NILP(active_p));
957 gtk_signal_connect(GTK_OBJECT(widget), "activate-item",
958 GTK_SIGNAL_FUNC(__generic_button_callback),
959 LISP_TO_VOID(callback));
961 gtk_signal_connect(GTK_OBJECT(widget), "activate",
962 GTK_SIGNAL_FUNC(__generic_button_callback),
963 LISP_TO_VOID(callback));
965 /* Now that all the information about the menu item is know, set the
966 remaining properties.
970 gtk_container_add(GTK_CONTAINER(widget), main_label);
972 gtk_misc_set_alignment(GTK_MISC(main_label), 0.0, 0.5);
973 gtk_xemacs_set_accel_keys(GTK_XEMACS_ACCEL_LABEL
977 gtk_widget_add_accelerator(widget,
991 static GtkWidget *menu_descriptor_to_widget(Lisp_Object descr,
992 GtkAccelGroup * accel_group)
994 int count = specpdl_depth();
995 GtkWidget *rval = NULL;
997 record_unwind_protect(restore_gc_inhibit,
998 make_int(gc_currently_forbidden));
1000 gc_currently_forbidden = 1;
1002 /* Cannot GC from here on out... */
1003 rval = menu_descriptor_to_widget_1(descr, accel_group);
1004 unbind_to(count, Qnil);
1009 static gboolean menu_can_reuse_widget(GtkWidget * child, const char *label)
1011 /* Everything up at the top level was done using
1012 ** gtk_xemacs_accel_label_new(), but we still double check to make
1013 ** sure we don't seriously foobar ourselves.
1015 gpointer possible_child =
1016 g_list_nth_data(gtk_container_children(GTK_CONTAINER(child)), 0);
1017 gboolean ret_val = FALSE;
1019 if (possible_child && GTK_IS_LABEL(possible_child)) {
1020 char *temp_label = remove_underscores(label);
1022 if (!strcmp(GTK_LABEL(possible_child)->label, temp_label))
1031 /* Converts a menubar description into a GtkMenuBar... a menubar is a
1032 list of menus or buttons
1034 static void menu_create_menubar(struct frame *f, Lisp_Object descr)
1036 gboolean right_justify = FALSE;
1037 Lisp_Object tail = Qnil;
1038 Lisp_Object value = descr;
1039 Lisp_Object item_descr = Qnil;
1040 GtkWidget *menubar = FRAME_GTK_MENUBAR_WIDGET(f);
1042 (GUI_ID) gtk_object_get_data(GTK_OBJECT(menubar),
1043 XEMACS_MENU_GUIID_TAG);
1044 guint menu_position = 0;
1045 GtkAccelGroup *menubar_accel_group;
1047 /* Remove any existing protection for old menu items */
1048 ungcpro_popup_callbacks(id);
1050 /* GCPRO the whole damn thing */
1051 gcpro_popup_callbacks(id, descr);
1053 menubar_accel_group = gtk_accel_group_new();
1055 EXTERNAL_LIST_LOOP(tail, value) {
1056 gpointer current_child =
1057 g_list_nth_data(GTK_MENU_SHELL(menubar)->children,
1060 item_descr = XCAR(tail);
1062 if (NILP(item_descr)) {
1063 /* Need to start right-justifying menus */
1064 right_justify = TRUE;
1066 } else if (VECTORP(item_descr)) {
1067 /* It is a button description */
1071 menu_descriptor_to_widget(item_descr,
1072 menubar_accel_group);
1073 gtk_widget_set_name(item, "XEmacsMenuButton");
1077 gtk_menu_item_new_with_label
1078 ("ITEM CREATION ERROR");
1081 gtk_widget_show_all(item);
1083 gtk_widget_destroy(GTK_WIDGET(current_child));
1084 gtk_menu_bar_insert(GTK_MENU_BAR(menubar), item,
1086 } else if (LISTP(item_descr)) {
1087 /* Need to actually convert it into a menu and slap it in */
1089 gboolean reused_p = FALSE;
1091 /* We may be able to reuse the widget, let's at least check. */
1093 && menu_can_reuse_widget(GTK_WIDGET(current_child),
1098 menu_convert(item_descr,
1099 GTK_WIDGET(current_child),
1100 menubar_accel_group);
1104 menu_convert(item_descr, NULL,
1105 menubar_accel_group);
1107 gtk_widget_destroy(GTK_WIDGET
1109 gtk_menu_bar_insert(GTK_MENU_BAR(menubar),
1110 widget, menu_position);
1115 gtk_menu_item_right_justify
1116 (GTK_MENU_ITEM(widget));
1118 widget = gtk_menu_item_new_with_label("ERROR");
1121 gtk_widget_show_all(widget);
1122 } else if (STRINGP(item_descr)) {
1123 /* Do I really want to be this careful? Anything else in a
1124 menubar description is illegal */
1129 /* Need to delete any menu items that were past the bounds of the new one */
1134 g_list_nth(GTK_MENU_SHELL(menubar)->children,
1136 gpointer data = l->data;
1137 g_list_remove_link(GTK_MENU_SHELL(menubar)->children,
1141 gtk_widget_destroy(GTK_WIDGET(data));
1146 /* Attach the new accelerator group to the frame. */
1147 gtk_window_add_accel_group(GTK_WINDOW(FRAME_GTK_SHELL_WIDGET(f)),
1148 menubar_accel_group);
1151 /* Deal with getting/setting the menubar */
1152 #ifndef GNOME_IS_APP
1153 #define GNOME_IS_APP(x) 0
1154 #define gnome_app_set_menus(x,y)
1158 run_menubar_hook(GtkWidget * widget, GdkEventButton * event, gpointer user_data)
1160 if (!GTK_MENU_SHELL(widget)->active) {
1161 run_hook(Qactivate_menubar_hook);
1166 static void create_menubar_widget(struct frame *f)
1168 GUI_ID id = new_gui_id();
1169 GtkWidget *handlebox = NULL;
1170 GtkWidget *menubar = gtk_xemacs_menubar_new(f);
1172 if (GNOME_IS_APP(FRAME_GTK_SHELL_WIDGET(f))) {
1173 gnome_app_set_menus(GNOME_APP(FRAME_GTK_SHELL_WIDGET(f)),
1174 GTK_MENU_BAR(menubar));
1175 } else if (dockable_menubar) {
1176 handlebox = gtk_handle_box_new();
1177 gtk_handle_box_set_handle_position(GTK_HANDLE_BOX(handlebox),
1179 gtk_container_add(GTK_CONTAINER(handlebox), menubar);
1180 gtk_box_pack_start(GTK_BOX(FRAME_GTK_CONTAINER_WIDGET(f)),
1181 handlebox, FALSE, FALSE, 0);
1183 gtk_box_pack_start(GTK_BOX(FRAME_GTK_CONTAINER_WIDGET(f)),
1184 menubar, FALSE, FALSE, 0);
1187 gtk_signal_connect(GTK_OBJECT(menubar), "button-press-event",
1188 GTK_SIGNAL_FUNC(run_menubar_hook), NULL);
1190 FRAME_GTK_MENUBAR_WIDGET(f) = menubar;
1191 gtk_object_set_data(GTK_OBJECT(menubar), XEMACS_MENU_GUIID_TAG,
1193 gtk_object_weakref(GTK_OBJECT(menubar), __remove_gcpro_by_id,
1197 static int set_frame_menubar(struct frame *f, int first_time_p)
1199 Lisp_Object menubar;
1200 int menubar_visible;
1201 /* As for the toolbar, the minibuffer does not have its own menubar. */
1202 struct window *w = XWINDOW(FRAME_LAST_NONMINIBUF_WINDOW(f));
1204 if (!FRAME_GTK_P(f))
1207 /***** first compute the contents of the menubar *****/
1209 if (!first_time_p) {
1210 /* evaluate `current-menubar' in the buffer of the selected window
1211 of the frame in question. */
1212 menubar = symbol_value_in_buffer(Qcurrent_menubar, w->buffer);
1214 /* That's a little tricky the first time since the frame isn't
1215 fully initialized yet. */
1216 menubar = Fsymbol_value(Qcurrent_menubar);
1219 if (NILP(menubar)) {
1220 menubar = Vblank_menubar;
1221 menubar_visible = 0;
1223 menubar_visible = !NILP(w->menubar_visible_p);
1226 if (!FRAME_GTK_MENUBAR_WIDGET(f)) {
1227 create_menubar_widget(f);
1230 /* Populate the menubar, but nothing is shown yet */
1232 Lisp_Object old_buffer;
1233 int count = specpdl_depth();
1235 old_buffer = Fcurrent_buffer();
1236 record_unwind_protect(Fset_buffer, old_buffer);
1237 Fset_buffer(XWINDOW(FRAME_SELECTED_WINDOW(f))->buffer);
1239 menu_create_menubar(f, menubar);
1241 Fset_buffer(old_buffer);
1242 unbind_to(count, Qnil);
1245 FRAME_MENUBAR_DATA(f) =
1246 Fcons(XWINDOW(FRAME_LAST_NONMINIBUF_WINDOW(f))->buffer, Qt);
1248 return (menubar_visible);
1251 /* Called from gtk_create_widgets() to create the inital menubar of a frame
1252 before it is mapped, so that the window is mapped with the menubar already
1253 there instead of us tacking it on later and thrashing the window after it
1255 int gtk_initialize_frame_menubar(struct frame *f)
1257 create_menubar_widget(f);
1258 return set_frame_menubar(f, 1);
1261 static void gtk_update_frame_menubar_internal(struct frame *f)
1263 /* We assume the menubar contents has changed if the global flag is set,
1264 or if the current buffer has changed, or if the menubar has never
1265 been updated before.
1267 int menubar_contents_changed =
1268 (f->menubar_changed || NILP(FRAME_MENUBAR_DATA(f))
1269 || (!EQ(XFRAME_MENUBAR_DATA_LASTBUFF(f),
1270 XWINDOW(FRAME_LAST_NONMINIBUF_WINDOW(f))->buffer)));
1272 gboolean menubar_was_visible =
1273 GTK_WIDGET_VISIBLE(FRAME_GTK_MENUBAR_WIDGET(f));
1274 gboolean menubar_will_be_visible = menubar_was_visible;
1275 gboolean menubar_visibility_changed;
1277 if (menubar_contents_changed) {
1278 menubar_will_be_visible = set_frame_menubar(f, 0);
1281 menubar_visibility_changed =
1282 menubar_was_visible != menubar_will_be_visible;
1284 if (!menubar_visibility_changed) {
1288 /* We hide and show the menubar's parent (which is actually the
1289 GtkHandleBox)... this is to simplify the code that destroys old
1290 menu items, etc. There is no easy way to get the child out of a
1291 handle box, and I didn't want to add yet another stupid widget
1292 slot to struct gtk_frame. */
1293 if (menubar_will_be_visible) {
1294 gtk_widget_show_all(FRAME_GTK_MENUBAR_WIDGET(f)->parent);
1296 gtk_widget_hide_all(FRAME_GTK_MENUBAR_WIDGET(f)->parent);
1299 MARK_FRAME_SIZE_SLIPPED(f);
1302 static void gtk_update_frame_menubars(struct frame *f)
1304 GtkWidget *menubar = NULL;
1306 assert(FRAME_GTK_P(f));
1308 menubar = FRAME_GTK_MENUBAR_WIDGET(f);
1310 if ((GTK_MENU_SHELL(menubar)->active) ||
1311 (GTK_MENU_SHELL(menubar)->have_grab) ||
1312 (GTK_MENU_SHELL(menubar)->have_xgrab)) {
1316 gtk_update_frame_menubar_internal(f);
1319 static void gtk_free_frame_menubars(struct frame *f)
1321 GtkWidget *menubar_widget;
1323 assert(FRAME_GTK_P(f));
1325 menubar_widget = FRAME_GTK_MENUBAR_WIDGET(f);
1326 if (menubar_widget) {
1327 gtk_widget_destroy(menubar_widget);
1331 static void popdown_menu_cb(GtkMenuShell * menu, gpointer user_data)
1336 static void gtk_popup_menu(Lisp_Object menu_desc, Lisp_Object event)
1338 struct Lisp_Event *eev = NULL;
1339 GtkWidget *widget = NULL;
1340 GtkWidget *menu = NULL;
1343 /* Do basic error checking first... */
1344 if (SYMBOLP(menu_desc))
1345 menu_desc = Fsymbol_value(menu_desc);
1346 CHECK_CONS(menu_desc);
1347 CHECK_STRING(XCAR(menu_desc));
1349 /* Now lets get down to business... */
1350 widget = menu_descriptor_to_widget(menu_desc, NULL);
1351 menu = GTK_MENU_ITEM(widget)->submenu;
1352 gtk_widget_set_name(widget, "XEmacsPopupMenu");
1353 id = gtk_object_get_data(GTK_OBJECT(widget), XEMACS_MENU_GUIID_TAG);
1355 __activate_menu(GTK_MENU_ITEM(widget), id);
1358 CHECK_LIVE_EVENT(event);
1359 eev = XEVENT(event);
1361 if ((eev->event_type != button_press_event) &&
1362 (eev->event_type != button_release_event))
1363 wrong_type_argument(Qmouse_event_p, event);
1364 } else if (!NILP(Vthis_command_keys)) {
1365 /* If an event wasn't passed, use the last event of the event
1366 sequence currently being executed, if that event is a mouse
1368 eev = XEVENT(Vthis_command_keys);
1369 if ((eev->event_type != button_press_event) &&
1370 (eev->event_type != button_release_event))
1374 gtk_widget_show(menu);
1377 gtk_signal_connect(GTK_OBJECT(menu), "deactivate",
1378 GTK_SIGNAL_FUNC(popdown_menu_cb), NULL);
1380 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1381 eev ? eev->event.button.button : 0,
1382 eev ? eev->timestamp : GDK_CURRENT_TIME);
1385 DEFUN("gtk-build-xemacs-menu", Fgtk_build_xemacs_menu, 1, 1, 0, /*
1386 Returns a GTK menu item from MENU, a standard XEmacs menu description.
1387 See the definition of `popup-menu' for more information on the format of MENU.
1391 GtkWidget *w = menu_descriptor_to_widget(menu, NULL);
1393 return (w ? build_gtk_object(GTK_OBJECT(w)) : Qnil);
1396 void syms_of_menubar_gtk(void)
1398 DEFSUBR(Fgtk_build_xemacs_menu);
1401 void console_type_create_menubar_gtk(void)
1403 CONSOLE_HAS_METHOD(gtk, update_frame_menubars);
1404 CONSOLE_HAS_METHOD(gtk, free_frame_menubars);
1405 CONSOLE_HAS_METHOD(gtk, popup_menu);
1408 void reinit_vars_of_menubar_gtk(void)
1410 dockable_menubar = 1;
1411 #ifdef TEAR_OFF_MENUS
1416 void vars_of_menubar_gtk(void)
1418 Fprovide(intern("gtk-menubars"));
1419 DEFVAR_BOOL("menubar-dockable-p", &dockable_menubar /*
1420 If non-nil, the frame menubar can be detached into its own top-level window.
1422 #ifdef TEAR_OFF_MENUS
1423 DEFVAR_BOOL("menubar-tearable-p", &tear_off_menus /*
1424 If non-nil, menus can be torn off into their own top-level windows.
1427 reinit_vars_of_menubar_gtk();