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 XEmacs.
7 XEmacs is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
22 /* Synched up with: Not in FSF. */
24 /* created 16-dec-91 by jwz */
29 #include "console-gtk.h"
33 #include "commands.h" /* zmacs_regions */
42 #include <libgnomeui/libgnomeui.h>
45 #define MENUBAR_TYPE 0
46 #define SUBMENU_TYPE 1
49 static GtkWidget *menu_descriptor_to_widget_1 (Lisp_Object descr, 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))
56 /* This is a bogus subclass of GtkMenuBar so that the menu never tries
57 ** to be bigger than the text widget. This prevents weird resizing
58 ** when jumping around between buffers with radically different menu
62 #define GTK_XEMACS_MENUBAR(obj) GTK_CHECK_CAST (obj, gtk_xemacs_menubar_get_type (), GtkXEmacsMenubar)
63 #define GTK_XEMACS_MENUBAR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_xemacs_menubar_get_type (), GtkXEmacsMenubarClass)
64 #define GTK_IS_XEMACS_MENUBAR(obj) GTK_CHECK_TYPE (obj, gtk_xemacs_menubar_get_type ())
65 #define GTK_XEMACS_MENUBAR_FRAME(obj) GTK_XEMACS_MENUBAR (obj)->f
67 typedef struct _GtkXEmacsMenubar GtkXEmacsMenubar;
68 typedef struct _GtkXEmacsMenubarClass GtkXEmacsMenubarClass;
70 struct _GtkXEmacsMenubar
76 struct _GtkXEmacsMenubarClass
78 GtkMenuBarClass parent_class;
81 guint gtk_xemacs_menubar_get_type (void);
82 GtkWidget *gtk_xemacs_menubar_new (struct frame *f);
84 static void gtk_xemacs_menubar_class_init (GtkXEmacsMenubarClass *klass);
85 static void gtk_xemacs_menubar_init (GtkXEmacsMenubar *xemacs);
86 static void gtk_xemacs_menubar_size_request (GtkWidget *widget, GtkRequisition *requisition);
89 gtk_xemacs_menubar_get_type (void)
91 static guint xemacs_menubar_type;
93 if (!xemacs_menubar_type)
95 static const GtkTypeInfo xemacs_menubar_info =
98 sizeof (GtkXEmacsMenubar),
99 sizeof (GtkXEmacsMenubarClass),
100 (GtkClassInitFunc) gtk_xemacs_menubar_class_init,
101 (GtkObjectInitFunc) gtk_xemacs_menubar_init,
102 /* reserved_1 */ NULL,
103 /* reserved_2 */ NULL,
104 (GtkClassInitFunc) NULL,
107 xemacs_menubar_type = gtk_type_unique (gtk_menu_bar_get_type (), &xemacs_menubar_info);
110 return xemacs_menubar_type;
113 static GtkWidgetClass *menubar_parent_class;
115 static void gtk_xemacs_menubar_class_init (GtkXEmacsMenubarClass *klass)
117 GtkWidgetClass *widget_class;
119 widget_class = (GtkWidgetClass*) klass;
120 menubar_parent_class = (GtkWidgetClass *) gtk_type_class (gtk_menu_bar_get_type ());
122 widget_class->size_request = gtk_xemacs_menubar_size_request;
125 static void gtk_xemacs_menubar_init (GtkXEmacsMenubar *xemacs)
129 static void gtk_xemacs_menubar_size_request (GtkWidget *widget, GtkRequisition *requisition)
131 GtkXEmacsMenubar *x = GTK_XEMACS_MENUBAR (widget);
132 GtkRequisition frame_size;
134 menubar_parent_class->size_request (widget, requisition);
137 ** We should really only do this if the menu has not been detached!
142 gtk_widget_size_request (FRAME_GTK_TEXT_WIDGET (x->frame), &frame_size);
144 requisition->width = frame_size.width;
148 gtk_xemacs_menubar_new (struct frame *f)
150 GtkXEmacsMenubar *menubar = gtk_type_new (gtk_xemacs_menubar_get_type ());
154 return (GTK_WIDGET (menubar));
158 * Label with XEmacs accelerator character support.
160 * The default interfaces to GtkAccelLabel does not understand XEmacs
161 * keystroke printing conventions, nor is it convenient in the places where is
162 * it needed. This subclass provides an alternative interface more suited to
163 * XEmacs needs but does not add new functionality.
165 #define GTK_TYPE_XEMACS_ACCEL_LABEL (gtk_xemacs_accel_label_get_type ())
166 #define GTK_XEMACS_ACCEL_LABEL(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_ACCEL_LABEL, GtkXEmacsAccelLabel))
167 #define GTK_XEMACS_ACCEL_LABEL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_ACCEL_LABEL, GtkXEmacsAccelLabelClass))
168 #define GTK_IS_XEMACS_ACCEL_LABEL(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_XEMACS_ACCEL_LABEL))
169 #define GTK_IS_XEMACS_ACCEL_LABEL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_XEMACS_ACCEL_LABEL))
171 typedef struct _GtkXEmacsAccelLabel GtkXEmacsAccelLabel;
172 typedef struct _GtkXEmacsAccelLabelClass GtkXEmacsAccelLabelClass;
174 /* Instance structure. No additional fields required. */
175 struct _GtkXEmacsAccelLabel
180 /* Class structure. No additional fields required. */
181 struct _GtkXEmacsAccelLabelClass
183 GtkAccelLabelClass parent_class;
186 static GtkType gtk_xemacs_accel_label_get_type(void);
187 static GtkWidget* gtk_xemacs_accel_label_new(const gchar *string);
188 static void gtk_xemacs_set_accel_keys(GtkXEmacsAccelLabel* l,
190 static void gtk_xemacs_accel_label_class_init(GtkXEmacsAccelLabelClass *klass);
191 static void gtk_xemacs_accel_label_init(GtkXEmacsAccelLabel *xemacs);
194 gtk_xemacs_accel_label_get_type(void)
196 static GtkType xemacs_accel_label_type = 0;
198 if (!xemacs_accel_label_type)
200 static const GtkTypeInfo xemacs_accel_label_info =
202 "GtkXEmacsAccelLabel",
203 sizeof (GtkXEmacsAccelLabel),
204 sizeof (GtkXEmacsAccelLabelClass),
205 (GtkClassInitFunc) gtk_xemacs_accel_label_class_init,
206 (GtkObjectInitFunc) gtk_xemacs_accel_label_init,
207 /* reserved_1 */ NULL,
208 /* reserved_2 */ NULL,
209 (GtkClassInitFunc) NULL,
212 xemacs_accel_label_type = gtk_type_unique (gtk_accel_label_get_type(), &xemacs_accel_label_info);
215 return xemacs_accel_label_type;
219 gtk_xemacs_accel_label_class_init(GtkXEmacsAccelLabelClass *klass)
225 gtk_xemacs_accel_label_init(GtkXEmacsAccelLabel *xemacs)
231 gtk_xemacs_accel_label_new (const gchar *string)
233 GtkXEmacsAccelLabel *xemacs_accel_label;
235 xemacs_accel_label = gtk_type_new (GTK_TYPE_XEMACS_ACCEL_LABEL);
237 if (string && *string)
238 gtk_label_set_text (GTK_LABEL (xemacs_accel_label), string);
240 return GTK_WIDGET (xemacs_accel_label);
243 /* Make the string <keys> the accelerator string for the label. */
245 gtk_xemacs_set_accel_keys(GtkXEmacsAccelLabel* l, Lisp_Object keys)
247 g_return_if_fail (l != NULL);
248 g_return_if_fail (GTK_IS_XEMACS_ACCEL_LABEL (l));
250 /* Disable the standard way of finding the accelerator string for the
252 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL(l), NULL);
254 /* Set the string straight from the object. */
255 if (STRINGP (keys) && XSTRING_LENGTH (keys))
257 C_STRING_TO_EXTERNAL_MALLOC(XSTRING_DATA (keys),
258 l->label.accel_string,
263 /* l->label.accel_string = NULL;*/
268 /* We now return you to your regularly scheduled menus... */
270 int dockable_menubar;
272 /* #define TEAR_OFF_MENUS */
274 #ifdef TEAR_OFF_MENUS
279 /* Converting from XEmacs to GTK representation */
281 menu_name_to_accelerator (char *name)
288 if (*name=='_' && *(name+1))
290 int accelerator = (int) (unsigned char) (*(name+1));
291 return make_char (tolower (accelerator));
299 #define XEMACS_MENU_DESCR_TAG "xemacs::menu::description"
300 #define XEMACS_MENU_FILTER_TAG "xemacs::menu::filter"
301 #define XEMACS_MENU_GUIID_TAG "xemacs::menu::gui_id"
302 #define XEMACS_MENU_FIRSTTIME_TAG "xemacs::menu::first_time"
304 static void __activate_menu(GtkMenuItem *, gpointer);
306 #ifdef TEAR_OFF_MENUS
308 __torn_off_sir(GtkMenuItem *item, gpointer user_data)
310 GtkWidget *menu_item = GTK_WIDGET (user_data);
312 if (GTK_TEAROFF_MENU_ITEM (item)->torn_off)
314 /* Menu was just torn off */
315 GUI_ID id = new_gui_id ();
316 Lisp_Object menu_desc = Qnil;
317 GtkWidget *old_submenu = GTK_MENU_ITEM (menu_item)->submenu;
319 VOID_TO_LISP (menu_desc, gtk_object_get_data (GTK_OBJECT (menu_item), XEMACS_MENU_DESCR_TAG));
321 /* GCPRO all of our very own */
322 gcpro_popup_callbacks (id, menu_desc);
324 /* Hide the now detached menu from the attentions of
325 __activate_menu destroying the old submenu */
327 gtk_widget_ref (old_submenu);
328 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), gtk_menu_new ());
329 gtk_widget_show_all (old_submenu);
335 /* This is called when a menu is about to be shown... this is what
336 does the delayed creation of the menu items. We populate the
337 submenu and away we go. */
339 __maybe_destroy (GtkWidget *child, GtkWidget *precious)
341 if (GTK_IS_MENU_ITEM (child) && !GTK_IS_TEAROFF_MENU_ITEM (child))
343 if (GTK_WIDGET_VISIBLE (child))
345 /* If we delete the menu item that was 'active' when the
346 menu was cancelled, GTK gets upset because it tries to
347 remove the focus rectangle from a (now) dead widget.
349 This widget will eventually get killed because it will
350 not be visible the next time the window is shown.
352 gtk_widget_set_sensitive (child, FALSE);
353 gtk_widget_hide_all (child);
357 gtk_widget_destroy (child);
362 /* If user_data != 0x00 then we are using a hook to build the menu. */
364 __activate_menu(GtkMenuItem *item, gpointer user_data)
367 gpointer force_clear = gtk_object_get_data (GTK_OBJECT (item), XEMACS_MENU_FIRSTTIME_TAG);
369 gtk_object_set_data (GTK_OBJECT (item), XEMACS_MENU_FIRSTTIME_TAG, 0x00);
371 /* Delete the old contents of the menu if we are the top level menubar */
372 if (GTK_IS_MENU_BAR (GTK_WIDGET (item)->parent) || force_clear)
374 GtkWidget *selected = gtk_menu_get_active (GTK_MENU (item->submenu));
376 gtk_container_foreach (GTK_CONTAINER (item->submenu),(GtkCallback) __maybe_destroy,
379 else if (gtk_container_children (GTK_CONTAINER (item->submenu)))
384 VOID_TO_LISP (desc, gtk_object_get_data (GTK_OBJECT (item), XEMACS_MENU_DESCR_TAG));
386 #ifdef TEAR_OFF_MENUS
387 /* Lets stick in a detacher just for giggles */
388 if (tear_off_menus && !gtk_container_children (GTK_CONTAINER (item->submenu)))
390 GtkWidget *w = gtk_tearoff_menu_item_new ();
392 gtk_menu_append (GTK_MENU (item->submenu), w);
393 gtk_signal_connect (GTK_OBJECT (w), "activate", GTK_SIGNAL_FUNC (__torn_off_sir), item);
399 GUI_ID id = (GUI_ID) gtk_object_get_data (GTK_OBJECT (item), XEMACS_MENU_GUIID_TAG);
401 struct gcpro gcpro1, gcpro2;
403 VOID_TO_LISP (hook_fn, gtk_object_get_data (GTK_OBJECT (item), XEMACS_MENU_FILTER_TAG));
405 GCPRO2 (desc, hook_fn);
407 desc = call1 (hook_fn, desc);
411 ungcpro_popup_callbacks (id);
412 gcpro_popup_callbacks (id, desc);
415 /* Build the child widgets */
416 for (; !NILP (desc); desc = Fcdr (desc))
418 GtkWidget *next = NULL;
419 Lisp_Object child = Fcar (desc);
421 if (NILP (child)) /* the partition */
423 /* Signal an error here? The NILP handling is handled a
424 layer higher where appropriate */
428 next = menu_descriptor_to_widget_1 (child,
429 gtk_menu_ensure_uline_accel_group (GTK_MENU (item->submenu)));
437 gtk_widget_show_all (next);
438 gtk_menu_append (GTK_MENU (item->submenu), next);
442 /* This is called whenever an item with a GUI_ID associated with it is
443 destroyed. This allows us to remove the references in gui-gtk.c
444 that made sure callbacks and such were GCPRO-ed
447 __remove_gcpro_by_id (gpointer user_data)
449 ungcpro_popup_callbacks ((GUI_ID) user_data);
453 __kill_stupid_gtk_timer (GtkObject *obj, gpointer user_data)
455 GtkMenuItem *mi = GTK_MENU_ITEM (obj);
459 gtk_timeout_remove (mi->timer);
464 /* Convert the XEmacs menu accelerator representation to Gtk mnemonic form. If
465 no accelerator has been provided, put one at the start of the string (this
466 mirrors the behaviour under X). This algorithm is also found in
467 dialog-gtk.el:gtk-popup-convert-underscores.
470 convert_underscores(const char *name)
474 int found_accel = FALSE;
477 for (i = 0; name[i]; ++i)
478 if (name[i] == '%' && name[i+1] == '_')
482 else if (name[i] == '_')
487 /* Allocate space for the original string, plus zero byte plus extra space
488 for all quoted underscores plus possible additional leading accelerator. */
489 rval = xmalloc_and_zero (strlen(name) + 1 + underscores
490 + (found_accel ? 0 : 1));
495 for (i = 0, j = (found_accel ? 0 : 1); name[i]; i++)
503 if ((name[i] != '_') && (name[i] != '%'))
508 else if (name[i] == '_')
520 /* Remove the XEmacs menu accellerator representation from a string. */
522 remove_underscores(const char *name)
524 char *rval = xmalloc_and_zero (strlen(name) + 1);
527 for (i = 0, j = 0; name[i]; i++)
534 if ((name[i] != '_') && (name[i] != '%'))
544 /* This converts an entire menu into a GtkMenuItem (with an attached
545 submenu). A menu is a list of (STRING [:keyword value]+ [DESCR]+)
546 DESCR is either a list (meaning a submenu), a vector, or nil (if
547 you include a :filter keyword) */
549 menu_convert (Lisp_Object desc, GtkWidget *reuse,
550 GtkAccelGroup* menubar_accel_group)
552 GtkWidget *menu_item = NULL;
553 GtkWidget *submenu = NULL;
554 Lisp_Object key, val;
555 Lisp_Object include_p = Qnil, hook_fn = Qnil, config_tag = Qnil;
556 Lisp_Object active_p = Qt;
558 int included_spec = 0;
561 if (STRINGP (XCAR (desc)))
563 accel = menu_name_to_accelerator (XSTRING_DATA (XCAR (desc)));
567 char *temp_menu_name = convert_underscores (XSTRING_DATA (XCAR (desc)));
568 GtkWidget* accel_label = gtk_xemacs_accel_label_new(NULL);
571 gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
572 accel_key = gtk_label_parse_uline (GTK_LABEL (accel_label), temp_menu_name);
574 menu_item = gtk_menu_item_new ();
575 gtk_container_add (GTK_CONTAINER (menu_item), accel_label);
576 gtk_widget_show (accel_label);
578 if (menubar_accel_group)
579 gtk_widget_add_accelerator (menu_item,
582 accel_key, GDK_MOD1_MASK,
584 free (temp_menu_name);
591 submenu = gtk_menu_new ();
592 gtk_widget_show (menu_item);
593 gtk_widget_show (submenu);
596 gtk_signal_connect (GTK_OBJECT (menu_item), "destroy",
597 GTK_SIGNAL_FUNC (__kill_stupid_gtk_timer), NULL);
599 /* Without this sometimes a submenu gets left on the screen -
602 if (GTK_MENU_ITEM (menu_item)->submenu)
604 gtk_widget_destroy (GTK_MENU_ITEM (menu_item)->submenu);
607 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), submenu);
609 /* We put this bogus menu item in so that GTK does the right
610 ** thing when the menu is near the screen border.
615 GtkWidget *bogus_item = gtk_menu_item_new_with_label ("A suitably long label here...");
617 gtk_object_set_data (GTK_OBJECT (menu_item), XEMACS_MENU_FIRSTTIME_TAG, (gpointer)0x01);
618 gtk_widget_show_all (bogus_item);
619 gtk_menu_append (GTK_MENU (submenu), bogus_item);
624 while (key = Fcar (desc), KEYWORDP (key))
626 Lisp_Object cascade = desc;
629 signal_simple_error ("keyword in menu lacks a value",
633 if (EQ (key, Q_included))
634 include_p = val, included_spec = 1;
635 else if (EQ (key, Q_config))
637 else if (EQ (key, Q_filter))
639 else if (EQ (key, Q_active))
640 active_p = val, active_spec = 1;
641 else if (EQ (key, Q_accelerator))
646 wv->accel = LISP_TO_VOID (val);
648 signal_simple_error ("bad keyboard accelerator", val);
651 else if (EQ (key, Q_label))
653 /* implement in 21.2 */
656 signal_simple_error ("unknown menu cascade keyword", cascade);
659 gtk_object_set_data (GTK_OBJECT (menu_item), XEMACS_MENU_DESCR_TAG, LISP_TO_VOID (desc));
660 gtk_object_set_data (GTK_OBJECT (menu_item), XEMACS_MENU_FILTER_TAG, LISP_TO_VOID (hook_fn));
662 if ((!NILP (config_tag)
663 && NILP (Fmemq (config_tag, Vmenubar_configuration)))
664 || (included_spec && NILP (Feval (include_p))))
670 active_p = Feval (active_p);
672 gtk_widget_set_sensitive (GTK_WIDGET (menu_item), ! NILP (active_p));
676 signal_simple_error ("menu name (first element) must be a string",
680 /* If we are reusing a widget, we need to make sure we clean
685 gpointer id = gtk_object_get_data (GTK_OBJECT (reuse), XEMACS_MENU_GUIID_TAG);
689 /* If the menu item had a GUI_ID that means it was a filter menu */
690 __remove_gcpro_by_id (id);
691 gtk_signal_disconnect_by_func (GTK_OBJECT (reuse),
692 GTK_SIGNAL_FUNC (__activate_menu),
697 gtk_signal_disconnect_by_func (GTK_OBJECT (reuse),
698 GTK_SIGNAL_FUNC (__activate_menu),
702 GTK_MENU_ITEM (reuse)->right_justify = 0;
707 /* Generic menu builder */
708 gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
709 GTK_SIGNAL_FUNC (__activate_menu),
714 GUI_ID id = new_gui_id ();
716 gtk_object_set_data (GTK_OBJECT (menu_item), XEMACS_MENU_GUIID_TAG,
719 /* Make sure we gcpro the menu descriptions */
720 gcpro_popup_callbacks (id, desc);
721 gtk_object_weakref (GTK_OBJECT (menu_item), __remove_gcpro_by_id,
724 gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
725 GTK_SIGNAL_FUNC (__activate_menu),
732 /* Called whenever a button, radio, or toggle is selected in the menu */
734 __generic_button_callback (GtkMenuItem *item, gpointer user_data)
736 Lisp_Object callback, function, data, channel;
738 XSETFRAME (channel, gtk_widget_to_frame (GTK_WIDGET (item)));
740 VOID_TO_LISP (callback, user_data);
742 get_gui_callback (callback, &function, &data);
744 signal_special_gtk_user_event (channel, function, data);
747 /* Convert a single menu item descriptor to a suitable GtkMenuItem */
748 /* This function cannot GC.
749 It is only called from menu_item_descriptor_to_widget_value, which
752 menu_descriptor_to_widget_1 (Lisp_Object descr, GtkAccelGroup* accel_group)
756 /* It is a separator. Unfortunately GTK does not allow us to
757 specify what our separators look like, so we can't do all the
758 fancy stuff that the X code does.
760 return (gtk_menu_item_new ());
762 else if (LISTP (descr))
764 /* It is a submenu */
765 return (menu_convert (descr, NULL, accel_group));
767 else if (VECTORP (descr))
769 /* An actual menu item description! This gets yucky. */
770 Lisp_Object name = Qnil;
771 Lisp_Object callback = Qnil;
772 Lisp_Object suffix = Qnil;
773 Lisp_Object active_p = Qt;
774 Lisp_Object include_p = Qt;
775 Lisp_Object selected_p = Qnil;
776 Lisp_Object keys = Qnil;
777 Lisp_Object style = Qnil;
778 Lisp_Object config_tag = Qnil;
779 Lisp_Object accel = Qnil;
780 GtkWidget *main_label = NULL;
781 int length = XVECTOR_LENGTH (descr);
782 Lisp_Object *contents = XVECTOR_DATA (descr);
784 int selected_spec = 0, included_spec = 0;
785 GtkWidget *widget = NULL;
789 signal_simple_error ("button descriptors must be at least 2 long", descr);
791 /* length 2: [ "name" callback ]
792 length 3: [ "name" callback active-p ]
793 length 4: [ "name" callback active-p suffix ]
794 or [ "name" callback keyword value ]
795 length 5+: [ "name" callback [ keyword value ]+ ]
797 plist_p = (length >= 5 || (length > 2 && KEYWORDP (contents [2])));
799 if (!plist_p && length > 2)
803 callback = contents [1];
804 active_p = contents [2];
806 suffix = contents [3];
813 signal_simple_error (
814 "button descriptor has an odd number of keywords and values",
818 callback = contents [1];
819 for (i = 2; i < length;)
821 Lisp_Object key = contents [i++];
822 Lisp_Object val = contents [i++];
824 signal_simple_error_2 ("not a keyword", key, descr);
826 if (EQ (key, Q_active)) active_p = val;
827 else if (EQ (key, Q_suffix)) suffix = val;
828 else if (EQ (key, Q_keys)) keys = val;
829 else if (EQ (key, Q_key_sequence)) ; /* ignored for FSF compat */
830 else if (EQ (key, Q_label)) ; /* implement for 21.0 */
831 else if (EQ (key, Q_style)) style = val;
832 else if (EQ (key, Q_selected)) selected_p = val, selected_spec = 1;
833 else if (EQ (key, Q_included)) include_p = val, included_spec = 1;
834 else if (EQ (key, Q_config)) config_tag = val;
835 else if (EQ (key, Q_accelerator))
837 if ( SYMBOLP (val) || CHARP (val))
840 signal_simple_error ("bad keyboard accelerator", val);
842 else if (EQ (key, Q_filter))
843 signal_simple_error(":filter keyword not permitted on leaf nodes", descr);
845 signal_simple_error_2 ("unknown menu item keyword", key, descr);
850 if ((!NILP (config_tag) && NILP (Fmemq (config_tag, Vmenubar_configuration)))
851 || (included_spec && NILP (Feval (include_p))))
853 /* the include specification says to ignore this item. */
856 #endif /* HAVE_MENUBARS */
861 accel = menu_name_to_accelerator (XSTRING_DATA (name));
864 suffix = Feval (suffix);
866 if (!separator_string_p (XSTRING_DATA (name)))
868 char *label_buffer = NULL;
869 char *temp_label = NULL;
871 if (STRINGP (suffix) && XSTRING_LENGTH (suffix))
873 label_buffer = alloca (XSTRING_LENGTH (name) + 15 + XSTRING_LENGTH (suffix));
874 sprintf (label_buffer, "%s %s ", XSTRING_DATA (name), XSTRING_DATA (suffix));
878 label_buffer = alloca (XSTRING_LENGTH (name) + 15);
879 sprintf (label_buffer, "%s ", XSTRING_DATA (name));
882 temp_label = convert_underscores (label_buffer);
883 main_label = gtk_xemacs_accel_label_new (NULL);
884 accel_key = gtk_label_parse_uline (GTK_LABEL (main_label), temp_label);
888 /* Evaluate the selected and active items now */
891 if (NILP (selected_p) || EQ (selected_p, Qt))
897 selected_p = Feval (selected_p);
901 if (NILP (active_p) || EQ (active_p, Qt))
907 active_p = Feval (active_p);
912 menubar_show_keybindings
916 /* Need to get keybindings */
919 /* User-specified string to generate key bindings with */
922 keys = Fsubstitute_command_keys (keys);
924 else if (SYMBOLP (callback))
928 /* #### Warning, dependency here on current_buffer and point */
929 where_is_to_char (callback, buf);
931 keys = build_string (buf);
935 /* Now we get down to the dirty business of creating the widgets */
936 if (NILP (style) || EQ (style, Qtext) || EQ (style, Qbutton))
938 /* A normal menu item */
939 widget = gtk_menu_item_new ();
941 else if (EQ (style, Qtoggle) || EQ (style, Qradio))
943 /* They are radio or toggle buttons.
945 XEmacs' menu descriptions are fairly lame in that they do
946 not have the idea of a 'group' of radio buttons. They
947 are exactly like toggle buttons except that they get
950 GTK rips us a new one again. If you have a radio button
951 in a group by itself, it always draws it as highlighted.
952 So we dummy up and create a second radio button that does
953 not get added to the menu, but gets invisibly set/unset
954 when the other gets unset/set. *sigh*
957 if (EQ (style, Qradio))
959 GtkWidget *dummy_sibling = NULL;
960 GSList *group = NULL;
962 dummy_sibling = gtk_radio_menu_item_new (group);
963 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (dummy_sibling));
964 widget = gtk_radio_menu_item_new (group);
966 /* We need to notice when the 'real' one gets destroyed
967 so we can clean up the dummy as well. */
968 gtk_object_weakref (GTK_OBJECT (widget),
969 (GtkDestroyNotify) gtk_widget_destroy,
974 widget = gtk_check_menu_item_new ();
977 /* What horrible defaults you have GTK dear! The default
978 for a toggle menu item is to not show the toggle unless it
979 is turned on or actively highlighted. How absolutely
981 gtk_check_menu_item_set_show_toggle (GTK_CHECK_MENU_ITEM (widget), TRUE);
982 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (widget),
983 NILP (selected_p) ? FALSE : TRUE);
987 signal_simple_error_2 ("unknown style", style, descr);
990 gtk_widget_set_sensitive (widget, ! NILP (active_p));
992 gtk_signal_connect (GTK_OBJECT (widget), "activate-item",
993 GTK_SIGNAL_FUNC (__generic_button_callback),
994 LISP_TO_VOID (callback));
996 gtk_signal_connect (GTK_OBJECT (widget), "activate",
997 GTK_SIGNAL_FUNC (__generic_button_callback),
998 LISP_TO_VOID (callback));
1000 /* Now that all the information about the menu item is know, set the
1001 remaining properties.
1006 gtk_container_add (GTK_CONTAINER (widget), main_label);
1008 gtk_misc_set_alignment (GTK_MISC (main_label), 0.0, 0.5);
1009 gtk_xemacs_set_accel_keys(GTK_XEMACS_ACCEL_LABEL(main_label), keys);
1012 gtk_widget_add_accelerator (widget,
1024 /* ABORT (); ???? */
1029 menu_descriptor_to_widget (Lisp_Object descr, GtkAccelGroup* accel_group)
1031 int count = specpdl_depth ();
1032 GtkWidget *rval = NULL;
1034 record_unwind_protect (restore_gc_inhibit, make_int (gc_currently_forbidden));
1036 gc_currently_forbidden = 1;
1038 /* Cannot GC from here on out... */
1039 rval = menu_descriptor_to_widget_1 (descr, accel_group);
1040 unbind_to (count, Qnil);
1046 menu_can_reuse_widget (GtkWidget *child, const char *label)
1048 /* Everything up at the top level was done using
1049 ** gtk_xemacs_accel_label_new(), but we still double check to make
1050 ** sure we don't seriously foobar ourselves.
1052 gpointer possible_child =
1053 g_list_nth_data (gtk_container_children (GTK_CONTAINER (child)), 0);
1054 gboolean ret_val = FALSE;
1056 if (possible_child && GTK_IS_LABEL (possible_child))
1058 char *temp_label = remove_underscores (label);
1060 if (!strcmp (GTK_LABEL (possible_child)->label, temp_label))
1069 /* Converts a menubar description into a GtkMenuBar... a menubar is a
1070 list of menus or buttons
1073 menu_create_menubar (struct frame *f, Lisp_Object descr)
1075 gboolean right_justify = FALSE;
1076 Lisp_Object tail = Qnil;
1077 Lisp_Object value = descr;
1078 Lisp_Object item_descr = Qnil;
1079 GtkWidget *menubar = FRAME_GTK_MENUBAR_WIDGET (f);
1080 GUI_ID id = (GUI_ID) gtk_object_get_data (GTK_OBJECT (menubar), XEMACS_MENU_GUIID_TAG);
1081 guint menu_position = 0;
1082 GtkAccelGroup *menubar_accel_group;
1084 /* Remove any existing protection for old menu items */
1085 ungcpro_popup_callbacks (id);
1087 /* GCPRO the whole damn thing */
1088 gcpro_popup_callbacks (id, descr);
1090 menubar_accel_group = gtk_accel_group_new();
1092 EXTERNAL_LIST_LOOP (tail, value)
1094 gpointer current_child = g_list_nth_data (GTK_MENU_SHELL (menubar)->children, menu_position);
1096 item_descr = XCAR (tail);
1098 if (NILP (item_descr))
1100 /* Need to start right-justifying menus */
1101 right_justify = TRUE;
1104 else if (VECTORP (item_descr))
1106 /* It is a button description */
1109 item = menu_descriptor_to_widget (item_descr, menubar_accel_group);
1110 gtk_widget_set_name (item, "XEmacsMenuButton");
1114 item = gtk_menu_item_new_with_label ("ITEM CREATION ERROR");
1117 gtk_widget_show_all (item);
1118 if (current_child) gtk_widget_destroy (GTK_WIDGET (current_child));
1119 gtk_menu_bar_insert (GTK_MENU_BAR (menubar), item, menu_position);
1121 else if (LISTP (item_descr))
1123 /* Need to actually convert it into a menu and slap it in */
1125 gboolean reused_p = FALSE;
1127 /* We may be able to reuse the widget, let's at least check. */
1128 if (current_child && menu_can_reuse_widget (GTK_WIDGET (current_child),
1129 XSTRING_DATA (XCAR (item_descr))))
1131 widget = menu_convert (item_descr, GTK_WIDGET (current_child),
1132 menubar_accel_group);
1137 widget = menu_convert (item_descr, NULL, menubar_accel_group);
1138 if (current_child) gtk_widget_destroy (GTK_WIDGET (current_child));
1139 gtk_menu_bar_insert (GTK_MENU_BAR (menubar), widget, menu_position);
1144 if (right_justify) gtk_menu_item_right_justify (GTK_MENU_ITEM (widget));
1148 widget = gtk_menu_item_new_with_label ("ERROR");
1151 gtk_widget_show_all (widget);
1153 else if (STRINGP (item_descr))
1155 /* Do I really want to be this careful? Anything else in a
1156 menubar description is illegal */
1161 /* Need to delete any menu items that were past the bounds of the new one */
1165 while ((l = g_list_nth (GTK_MENU_SHELL (menubar)->children, menu_position)))
1167 gpointer data = l->data;
1168 g_list_remove_link (GTK_MENU_SHELL (menubar)->children, l);
1172 gtk_widget_destroy (GTK_WIDGET (data));
1177 /* Attach the new accelerator group to the frame. */
1178 gtk_window_add_accel_group (GTK_WINDOW (FRAME_GTK_SHELL_WIDGET(f)),
1179 menubar_accel_group);
1183 /* Deal with getting/setting the menubar */
1184 #ifndef GNOME_IS_APP
1185 #define GNOME_IS_APP(x) 0
1186 #define gnome_app_set_menus(x,y)
1190 run_menubar_hook (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
1192 if (!GTK_MENU_SHELL(widget)->active)
1194 run_hook (Qactivate_menubar_hook);
1200 create_menubar_widget (struct frame *f)
1202 GUI_ID id = new_gui_id ();
1203 GtkWidget *handlebox = NULL;
1204 GtkWidget *menubar = gtk_xemacs_menubar_new (f);
1206 if (GNOME_IS_APP (FRAME_GTK_SHELL_WIDGET (f)))
1208 gnome_app_set_menus (GNOME_APP (FRAME_GTK_SHELL_WIDGET (f)), GTK_MENU_BAR (menubar));
1210 else if (dockable_menubar)
1212 handlebox = gtk_handle_box_new ();
1213 gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (handlebox), GTK_POS_LEFT);
1214 gtk_container_add (GTK_CONTAINER (handlebox), menubar);
1215 gtk_box_pack_start (GTK_BOX (FRAME_GTK_CONTAINER_WIDGET (f)), handlebox, FALSE, FALSE, 0);
1219 gtk_box_pack_start (GTK_BOX (FRAME_GTK_CONTAINER_WIDGET (f)), menubar, FALSE, FALSE, 0);
1222 gtk_signal_connect (GTK_OBJECT (menubar), "button-press-event",
1223 GTK_SIGNAL_FUNC (run_menubar_hook), NULL);
1225 FRAME_GTK_MENUBAR_WIDGET (f) = menubar;
1226 gtk_object_set_data (GTK_OBJECT (menubar), XEMACS_MENU_GUIID_TAG, (gpointer) id);
1227 gtk_object_weakref (GTK_OBJECT (menubar), __remove_gcpro_by_id, (gpointer) id);
1231 set_frame_menubar (struct frame *f, int first_time_p)
1233 Lisp_Object menubar;
1234 int menubar_visible;
1235 /* As for the toolbar, the minibuffer does not have its own menubar. */
1236 struct window *w = XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f));
1238 if (! FRAME_GTK_P (f))
1241 /***** first compute the contents of the menubar *****/
1245 /* evaluate `current-menubar' in the buffer of the selected window
1246 of the frame in question. */
1247 menubar = symbol_value_in_buffer (Qcurrent_menubar, w->buffer);
1251 /* That's a little tricky the first time since the frame isn't
1252 fully initialized yet. */
1253 menubar = Fsymbol_value (Qcurrent_menubar);
1258 menubar = Vblank_menubar;
1259 menubar_visible = 0;
1263 menubar_visible = !NILP (w->menubar_visible_p);
1266 if (!FRAME_GTK_MENUBAR_WIDGET (f))
1268 create_menubar_widget (f);
1271 /* Populate the menubar, but nothing is shown yet */
1273 Lisp_Object old_buffer;
1274 int count = specpdl_depth ();
1276 old_buffer = Fcurrent_buffer ();
1277 record_unwind_protect (Fset_buffer, old_buffer);
1278 Fset_buffer (XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer);
1280 menu_create_menubar (f, menubar);
1282 Fset_buffer (old_buffer);
1283 unbind_to (count, Qnil);
1286 FRAME_MENUBAR_DATA (f) = Fcons (XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f))->buffer, Qt);
1288 return (menubar_visible);
1291 /* Called from gtk_create_widgets() to create the inital menubar of a frame
1292 before it is mapped, so that the window is mapped with the menubar already
1293 there instead of us tacking it on later and thrashing the window after it
1296 gtk_initialize_frame_menubar (struct frame *f)
1298 create_menubar_widget (f);
1299 return set_frame_menubar (f, 1);
1304 gtk_update_frame_menubar_internal (struct frame *f)
1306 /* We assume the menubar contents has changed if the global flag is set,
1307 or if the current buffer has changed, or if the menubar has never
1308 been updated before.
1310 int menubar_contents_changed =
1312 || NILP (FRAME_MENUBAR_DATA (f))
1313 || (!EQ (XFRAME_MENUBAR_DATA_LASTBUFF (f),
1314 XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f))->buffer)));
1316 gboolean menubar_was_visible = GTK_WIDGET_VISIBLE (FRAME_GTK_MENUBAR_WIDGET (f));
1317 gboolean menubar_will_be_visible = menubar_was_visible;
1318 gboolean menubar_visibility_changed;
1320 if (menubar_contents_changed)
1322 menubar_will_be_visible = set_frame_menubar (f, 0);
1325 menubar_visibility_changed = menubar_was_visible != menubar_will_be_visible;
1327 if (!menubar_visibility_changed)
1332 /* We hide and show the menubar's parent (which is actually the
1333 GtkHandleBox)... this is to simplify the code that destroys old
1334 menu items, etc. There is no easy way to get the child out of a
1335 handle box, and I didn't want to add yet another stupid widget
1336 slot to struct gtk_frame. */
1337 if (menubar_will_be_visible)
1339 gtk_widget_show_all (FRAME_GTK_MENUBAR_WIDGET (f)->parent);
1343 gtk_widget_hide_all (FRAME_GTK_MENUBAR_WIDGET (f)->parent);
1346 MARK_FRAME_SIZE_SLIPPED (f);
1350 gtk_update_frame_menubars (struct frame *f)
1352 GtkWidget *menubar = NULL;
1354 assert (FRAME_GTK_P (f));
1356 menubar = FRAME_GTK_MENUBAR_WIDGET (f);
1358 if ((GTK_MENU_SHELL (menubar)->active) ||
1359 (GTK_MENU_SHELL (menubar)->have_grab) ||
1360 (GTK_MENU_SHELL (menubar)->have_xgrab))
1365 gtk_update_frame_menubar_internal (f);
1369 gtk_free_frame_menubars (struct frame *f)
1371 GtkWidget *menubar_widget;
1373 assert (FRAME_GTK_P (f));
1375 menubar_widget = FRAME_GTK_MENUBAR_WIDGET (f);
1378 gtk_widget_destroy (menubar_widget);
1382 static void popdown_menu_cb (GtkMenuShell *menu, gpointer user_data)
1388 gtk_popup_menu (Lisp_Object menu_desc, Lisp_Object event)
1390 struct Lisp_Event *eev = NULL;
1391 GtkWidget *widget = NULL;
1392 GtkWidget *menu = NULL;
1395 /* Do basic error checking first... */
1396 if (SYMBOLP (menu_desc))
1397 menu_desc = Fsymbol_value (menu_desc);
1398 CHECK_CONS (menu_desc);
1399 CHECK_STRING (XCAR (menu_desc));
1401 /* Now lets get down to business... */
1402 widget = menu_descriptor_to_widget (menu_desc, NULL);
1403 menu = GTK_MENU_ITEM (widget)->submenu;
1404 gtk_widget_set_name (widget, "XEmacsPopupMenu");
1405 id = gtk_object_get_data (GTK_OBJECT (widget), XEMACS_MENU_GUIID_TAG);
1407 __activate_menu (GTK_MENU_ITEM (widget), id);
1411 CHECK_LIVE_EVENT (event);
1412 eev = XEVENT (event);
1414 if ((eev->event_type != button_press_event) &&
1415 (eev->event_type != button_release_event))
1416 wrong_type_argument (Qmouse_event_p, event);
1418 else if (!NILP (Vthis_command_keys))
1420 /* If an event wasn't passed, use the last event of the event
1421 sequence currently being executed, if that event is a mouse
1423 eev = XEVENT (Vthis_command_keys);
1424 if ((eev->event_type != button_press_event) &&
1425 (eev->event_type != button_release_event))
1429 gtk_widget_show (menu);
1432 gtk_signal_connect (GTK_OBJECT (menu), "deactivate",
1433 GTK_SIGNAL_FUNC (popdown_menu_cb), NULL);
1435 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
1436 eev ? eev->event.button.button : 0,
1437 eev ? eev->timestamp : GDK_CURRENT_TIME);
1440 DEFUN ("gtk-build-xemacs-menu", Fgtk_build_xemacs_menu, 1, 1, 0, /*
1441 Returns a GTK menu item from MENU, a standard XEmacs menu description.
1442 See the definition of `popup-menu' for more information on the format of MENU.
1446 GtkWidget *w = menu_descriptor_to_widget (menu, NULL);
1448 return (w ? build_gtk_object (GTK_OBJECT (w)) : Qnil);
1453 syms_of_menubar_gtk (void)
1455 DEFSUBR (Fgtk_build_xemacs_menu);
1459 console_type_create_menubar_gtk (void)
1461 CONSOLE_HAS_METHOD (gtk, update_frame_menubars);
1462 CONSOLE_HAS_METHOD (gtk, free_frame_menubars);
1463 CONSOLE_HAS_METHOD (gtk, popup_menu);
1466 void reinit_vars_of_menubar_gtk (void)
1468 dockable_menubar = 1;
1469 #ifdef TEAR_OFF_MENUS
1475 vars_of_menubar_gtk (void)
1477 Fprovide (intern ("gtk-menubars"));
1478 DEFVAR_BOOL ("menubar-dockable-p", &dockable_menubar /*
1479 If non-nil, the frame menubar can be detached into its own top-level window.
1481 #ifdef TEAR_OFF_MENUS
1482 DEFVAR_BOOL ("menubar-tearable-p", &tear_off_menus /*
1483 If non-nil, menus can be torn off into their own top-level windows.
1486 reinit_vars_of_menubar_gtk ();