1 /* Implements an elisp-programmable menubar -- X 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);
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 *parent_class;
115 static void gtk_xemacs_menubar_class_init (GtkXEmacsMenubarClass *klass)
117 GtkWidgetClass *widget_class;
119 widget_class = (GtkWidgetClass*) klass;
120 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 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));
157 /* We now return you to your regularly scheduled menus... */
159 int dockable_menubar;
161 /* #define TEAR_OFF_MENUS */
163 #ifdef TEAR_OFF_MENUS
168 /* Converting from XEmacs to GTK representation */
170 menu_name_to_accelerator (char *name)
177 if (*name=='_' && *(name+1))
179 int accelerator = (int) (unsigned char) (*(name+1));
180 return make_char (tolower (accelerator));
188 #define XEMACS_MENU_DESCR_TAG "xemacs::menu::description"
189 #define XEMACS_MENU_FILTER_TAG "xemacs::menu::filter"
190 #define XEMACS_MENU_GUIID_TAG "xemacs::menu::gui_id"
191 #define XEMACS_MENU_FIRSTTIME_TAG "xemacs::menu::first_time"
193 static void __activate_menu(GtkMenuItem *, gpointer);
195 #ifdef TEAR_OFF_MENUS
197 __torn_off_sir(GtkMenuItem *item, gpointer user_data)
199 GtkWidget *menu_item = GTK_WIDGET (user_data);
201 if (GTK_TEAROFF_MENU_ITEM (item)->torn_off)
203 /* Menu was just torn off */
204 GUI_ID id = new_gui_id ();
205 Lisp_Object menu_desc = Qnil;
206 GtkWidget *old_submenu = GTK_MENU_ITEM (menu_item)->submenu;
208 VOID_TO_LISP (menu_desc, gtk_object_get_data (GTK_OBJECT (menu_item), XEMACS_MENU_DESCR_TAG));
210 /* GCPRO all of our very own */
211 gcpro_popup_callbacks (id, menu_desc);
213 /* Hide the now detached menu from the attentions of
214 __activate_menu destroying the old submenu */
216 gtk_widget_ref (old_submenu);
217 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), gtk_menu_new ());
218 gtk_widget_show_all (old_submenu);
224 /* This is called when a menu is about to be shown... this is what
225 does the delayed creation of the menu items. We populate the
226 submenu and away we go. */
228 __maybe_destroy (GtkWidget *child, GtkWidget *precious)
230 if (GTK_IS_MENU_ITEM (child) && !GTK_IS_TEAROFF_MENU_ITEM (child))
232 if (GTK_WIDGET_VISIBLE (child))
234 /* If we delete the menu item that was 'active' when the
235 menu was cancelled, GTK gets upset because it tries to
236 remove the focus rectangle from a (now) dead widget.
238 This widget will eventually get killed because it will
239 not be visible the next time the window is shown.
241 gtk_widget_set_sensitive (child, FALSE);
242 gtk_widget_hide_all (child);
246 gtk_widget_destroy (child);
251 /* If user_data != 0x00 then we are using a hook to build the menu. */
253 __activate_menu(GtkMenuItem *item, gpointer user_data)
256 gpointer force_clear = gtk_object_get_data (GTK_OBJECT (item), XEMACS_MENU_FIRSTTIME_TAG);
258 gtk_object_set_data (GTK_OBJECT (item), XEMACS_MENU_FIRSTTIME_TAG, 0x00);
260 /* Delete the old contents of the menu if we are the top level menubar */
261 if (GTK_IS_MENU_BAR (GTK_WIDGET (item)->parent) || force_clear)
263 GtkWidget *selected = gtk_menu_get_active (GTK_MENU (item->submenu));
265 gtk_container_foreach (GTK_CONTAINER (item->submenu),(GtkCallback) __maybe_destroy,
268 else if (gtk_container_children (GTK_CONTAINER (item->submenu)))
273 VOID_TO_LISP (desc, gtk_object_get_data (GTK_OBJECT (item), XEMACS_MENU_DESCR_TAG));
275 #ifdef TEAR_OFF_MENUS
276 /* Lets stick in a detacher just for giggles */
277 if (tear_off_menus && !gtk_container_children (GTK_CONTAINER (item->submenu)))
279 GtkWidget *w = gtk_tearoff_menu_item_new ();
281 gtk_menu_append (GTK_MENU (item->submenu), w);
282 gtk_signal_connect (GTK_OBJECT (w), "activate", GTK_SIGNAL_FUNC (__torn_off_sir), item);
288 GUI_ID id = (GUI_ID) gtk_object_get_data (GTK_OBJECT (item), XEMACS_MENU_GUIID_TAG);
290 struct gcpro gcpro1, gcpro2;
292 VOID_TO_LISP (hook_fn, gtk_object_get_data (GTK_OBJECT (item), XEMACS_MENU_FILTER_TAG));
294 GCPRO2 (desc, hook_fn);
296 desc = call1 (hook_fn, desc);
300 ungcpro_popup_callbacks (id);
301 gcpro_popup_callbacks (id, desc);
304 /* Build the child widgets */
305 for (; !NILP (desc); desc = Fcdr (desc))
307 GtkWidget *next = NULL;
308 Lisp_Object child = Fcar (desc);
310 if (NILP (child)) /* the partition */
312 /* Signal an error here? The NILP handling is handled a
313 layer higher where appropriate */
317 next = menu_descriptor_to_widget_1 (child);
325 gtk_widget_show_all (next);
326 gtk_menu_append (GTK_MENU (item->submenu), next);
330 /* This is called whenever an item with a GUI_ID associated with it is
331 destroyed. This allows us to remove the references in gui-gtk.c
332 that made sure callbacks and such were GCPRO-ed
335 __remove_gcpro_by_id (gpointer user_data)
337 ungcpro_popup_callbacks ((GUI_ID) user_data);
341 __kill_stupid_gtk_timer (GtkObject *obj, gpointer user_data)
343 GtkMenuItem *mi = GTK_MENU_ITEM (obj);
347 gtk_timeout_remove (mi->timer);
353 remove_underscores(const char *name)
355 char *rval = xmalloc_and_zero (strlen(name) + 1);
358 for (i = 0, j = 0; name[i]; i++)
365 if ((name[i] == '_'))
373 /* This converts an entire menu into a GtkMenuItem (with an attached
374 submenu). A menu is a list of (STRING [:keyword value]+ [DESCR]+)
375 DESCR is either a list (meaning a submenu), a vector, or nil (if
376 you include a :filter keyword) */
378 menu_convert (Lisp_Object desc, GtkWidget *reuse)
380 GtkWidget *menu_item = NULL;
381 GtkWidget *submenu = NULL;
382 Lisp_Object key, val;
383 Lisp_Object include_p = Qnil, hook_fn = Qnil, config_tag = Qnil;
384 Lisp_Object active_p = Qt;
386 int included_spec = 0;
389 if (STRINGP (XCAR (desc)))
391 accel = menu_name_to_accelerator (XSTRING_DATA (XCAR (desc)));
395 char *temp_menu_name = remove_underscores (XSTRING_DATA (XCAR (desc)));
396 menu_item = gtk_menu_item_new_with_label (temp_menu_name);
397 free (temp_menu_name);
404 submenu = gtk_menu_new ();
405 gtk_widget_show (menu_item);
406 gtk_widget_show (submenu);
409 gtk_signal_connect (GTK_OBJECT (menu_item), "destroy",
410 GTK_SIGNAL_FUNC (__kill_stupid_gtk_timer), NULL);
412 /* Without this sometimes a submenu gets left on the screen -
415 if (GTK_MENU_ITEM (menu_item)->submenu)
417 gtk_widget_destroy (GTK_MENU_ITEM (menu_item)->submenu);
420 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), submenu);
422 /* We put this bogus menu item in so that GTK does the right
423 ** thing when the menu is near the screen border.
428 GtkWidget *bogus_item = gtk_menu_item_new_with_label ("A suitably long label here...");
430 gtk_object_set_data (GTK_OBJECT (menu_item), XEMACS_MENU_FIRSTTIME_TAG, (gpointer)0x01);
431 gtk_widget_show_all (bogus_item);
432 gtk_menu_append (GTK_MENU (submenu), bogus_item);
437 while (key = Fcar (desc), KEYWORDP (key))
439 Lisp_Object cascade = desc;
442 signal_simple_error ("keyword in menu lacks a value",
446 if (EQ (key, Q_included))
447 include_p = val, included_spec = 1;
448 else if (EQ (key, Q_config))
450 else if (EQ (key, Q_filter))
452 else if (EQ (key, Q_active))
453 active_p = val, active_spec = 1;
454 else if (EQ (key, Q_accelerator))
459 wv->accel = LISP_TO_VOID (val);
461 signal_simple_error ("bad keyboard accelerator", val);
464 else if (EQ (key, Q_label))
466 /* implement in 21.2 */
469 signal_simple_error ("unknown menu cascade keyword", cascade);
472 gtk_object_set_data (GTK_OBJECT (menu_item), XEMACS_MENU_DESCR_TAG, LISP_TO_VOID (desc));
473 gtk_object_set_data (GTK_OBJECT (menu_item), XEMACS_MENU_FILTER_TAG, LISP_TO_VOID (hook_fn));
475 if ((!NILP (config_tag)
476 && NILP (Fmemq (config_tag, Vmenubar_configuration)))
477 || (included_spec && NILP (Feval (include_p))))
483 active_p = Feval (active_p);
485 gtk_widget_set_sensitive (GTK_WIDGET (menu_item), ! NILP (active_p));
489 signal_simple_error ("menu name (first element) must be a string",
493 /* If we are reusing a widget, we need to make sure we clean
498 gpointer id = gtk_object_get_data (GTK_OBJECT (reuse), XEMACS_MENU_GUIID_TAG);
502 /* If the menu item had a GUI_ID that means it was a filter menu */
503 __remove_gcpro_by_id (id);
504 gtk_signal_disconnect_by_func (GTK_OBJECT (reuse),
505 GTK_SIGNAL_FUNC (__activate_menu),
510 gtk_signal_disconnect_by_func (GTK_OBJECT (reuse),
511 GTK_SIGNAL_FUNC (__activate_menu),
515 GTK_MENU_ITEM (reuse)->right_justify = 0;
520 /* Generic menu builder */
521 gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
522 GTK_SIGNAL_FUNC (__activate_menu),
527 GUI_ID id = new_gui_id ();
529 gtk_object_set_data (GTK_OBJECT (menu_item), XEMACS_MENU_GUIID_TAG,
532 /* Make sure we gcpro the menu descriptions */
533 gcpro_popup_callbacks (id, desc);
534 gtk_object_weakref (GTK_OBJECT (menu_item), __remove_gcpro_by_id,
537 gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
538 GTK_SIGNAL_FUNC (__activate_menu),
545 static struct frame *
546 __get_channel (GtkWidget *w)
548 struct frame *f = NULL;
550 for (; w; w = w->parent)
552 if ((f = (struct frame *) gtk_object_get_data (GTK_OBJECT (w), "xemacs::frame")))
556 return (selected_frame());
560 /* Called whenever a button, radio, or toggle is selected in the menu */
562 __generic_button_callback (GtkMenuItem *item, gpointer user_data)
564 Lisp_Object callback, function, data, channel;
566 XSETFRAME (channel, __get_channel (GTK_WIDGET (item)));
568 VOID_TO_LISP (callback, user_data);
570 get_gui_callback (callback, &function, &data);
572 signal_special_gtk_user_event (channel, function, data);
575 /* Convert a single menu item descriptor to a suitable GtkMenuItem */
576 /* This function cannot GC.
577 It is only called from menu_item_descriptor_to_widget_value, which
579 static GtkWidget *menu_descriptor_to_widget_1 (Lisp_Object descr)
583 /* It is a separator. Unfortunately GTK does not allow us to
584 specify what our separators look like, so we can't do all the
585 fancy stuff that the X code does.
587 return (gtk_menu_item_new ());
589 else if (LISTP (descr))
591 /* It is a submenu */
592 return (menu_convert (descr, NULL));
594 else if (VECTORP (descr))
596 /* An actual menu item description! This gets yucky. */
597 Lisp_Object name = Qnil;
598 Lisp_Object callback = Qnil;
599 Lisp_Object suffix = Qnil;
600 Lisp_Object active_p = Qt;
601 Lisp_Object include_p = Qt;
602 Lisp_Object selected_p = Qnil;
603 Lisp_Object keys = Qnil;
604 Lisp_Object style = Qnil;
605 Lisp_Object config_tag = Qnil;
606 Lisp_Object accel = Qnil;
607 GtkWidget *main_label = NULL;
608 int length = XVECTOR_LENGTH (descr);
609 Lisp_Object *contents = XVECTOR_DATA (descr);
611 int selected_spec = 0, included_spec = 0;
612 GtkWidget *widget = NULL;
615 signal_simple_error ("button descriptors must be at least 2 long", descr);
617 /* length 2: [ "name" callback ]
618 length 3: [ "name" callback active-p ]
619 length 4: [ "name" callback active-p suffix ]
620 or [ "name" callback keyword value ]
621 length 5+: [ "name" callback [ keyword value ]+ ]
623 plist_p = (length >= 5 || (length > 2 && KEYWORDP (contents [2])));
625 if (!plist_p && length > 2)
629 callback = contents [1];
630 active_p = contents [2];
632 suffix = contents [3];
639 signal_simple_error (
640 "button descriptor has an odd number of keywords and values",
644 callback = contents [1];
645 for (i = 2; i < length;)
647 Lisp_Object key = contents [i++];
648 Lisp_Object val = contents [i++];
650 signal_simple_error_2 ("not a keyword", key, descr);
652 if (EQ (key, Q_active)) active_p = val;
653 else if (EQ (key, Q_suffix)) suffix = val;
654 else if (EQ (key, Q_keys)) keys = val;
655 else if (EQ (key, Q_key_sequence)) ; /* ignored for FSF compat */
656 else if (EQ (key, Q_label)) ; /* implement for 21.0 */
657 else if (EQ (key, Q_style)) style = val;
658 else if (EQ (key, Q_selected)) selected_p = val, selected_spec = 1;
659 else if (EQ (key, Q_included)) include_p = val, included_spec = 1;
660 else if (EQ (key, Q_config)) config_tag = val;
661 else if (EQ (key, Q_accelerator))
663 if ( SYMBOLP (val) || CHARP (val))
666 signal_simple_error ("bad keyboard accelerator", val);
668 else if (EQ (key, Q_filter))
669 signal_simple_error(":filter keyword not permitted on leaf nodes", descr);
671 signal_simple_error_2 ("unknown menu item keyword", key, descr);
676 if ((!NILP (config_tag) && NILP (Fmemq (config_tag, Vmenubar_configuration)))
677 || (included_spec && NILP (Feval (include_p))))
679 /* the include specification says to ignore this item. */
682 #endif /* HAVE_MENUBARS */
687 accel = menu_name_to_accelerator (XSTRING_DATA (name));
690 suffix = Feval (suffix);
692 if (!separator_string_p (XSTRING_DATA (name)))
694 char *label_buffer = NULL;
695 char *temp_label = NULL;
697 if (STRINGP (suffix) && XSTRING_LENGTH (suffix))
699 label_buffer = alloca (XSTRING_LENGTH (name) + 15 + XSTRING_LENGTH (suffix));
700 sprintf (label_buffer, "%s %s ", XSTRING_DATA (name), XSTRING_DATA (suffix));
704 label_buffer = alloca (XSTRING_LENGTH (name) + 15);
705 sprintf (label_buffer, "%s ", XSTRING_DATA (name));
708 temp_label = remove_underscores (label_buffer);
709 main_label = gtk_accel_label_new (temp_label);
713 /* Evaluate the selected and active items now */
716 if (NILP (selected_p) || EQ (selected_p, Qt))
722 selected_p = Feval (selected_p);
726 if (NILP (active_p) || EQ (active_p, Qt))
732 active_p = Feval (active_p);
737 menubar_show_keybindings
741 /* Need to get keybindings */
744 /* User-specified string to generate key bindings with */
747 keys = Fsubstitute_command_keys (keys);
749 else if (SYMBOLP (callback))
753 /* #### Warning, dependency here on current_buffer and point */
754 where_is_to_char (callback, buf);
756 keys = build_string (buf);
760 /* Now we get down to the dirty business of creating the widgets */
761 if (NILP (style) || EQ (style, Qtext) || EQ (style, Qbutton))
763 /* A normal menu item */
764 widget = gtk_menu_item_new ();
766 else if (EQ (style, Qtoggle) || EQ (style, Qradio))
768 /* They are radio or toggle buttons.
770 XEmacs' menu descriptions are fairly lame in that they do
771 not have the idea of a 'group' of radio buttons. They
772 are exactly like toggle buttons except that they get
775 GTK rips us a new one again. If you have a radio button
776 in a group by itself, it always draws it as highlighted.
777 So we dummy up and create a second radio button that does
778 not get added to the menu, but gets invisibly set/unset
779 when the other gets unset/set. *sigh*
782 if (EQ (style, Qradio))
784 GtkWidget *dummy_sibling = NULL;
785 GSList *group = NULL;
787 dummy_sibling = gtk_radio_menu_item_new (group);
788 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (dummy_sibling));
789 widget = gtk_radio_menu_item_new (group);
791 /* We need to notice when the 'real' one gets destroyed
792 so we can clean up the dummy as well. */
793 gtk_object_weakref (GTK_OBJECT (widget),
794 (GtkDestroyNotify) gtk_widget_destroy,
799 widget = gtk_check_menu_item_new ();
802 /* What horrible defaults you have GTK dear! The default
803 for a toggle menu item is to not show the toggle unless it
804 is turned on or actively highlighted. How absolutely
806 gtk_check_menu_item_set_show_toggle (GTK_CHECK_MENU_ITEM (widget), TRUE);
807 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (widget),
808 NILP (selected_p) ? FALSE : TRUE);
812 signal_simple_error_2 ("unknown style", style, descr);
815 gtk_widget_set_sensitive (widget, ! NILP (active_p));
817 gtk_signal_connect (GTK_OBJECT (widget), "activate-item",
818 GTK_SIGNAL_FUNC (__generic_button_callback),
819 LISP_TO_VOID (callback));
821 gtk_signal_connect (GTK_OBJECT (widget), "activate",
822 GTK_SIGNAL_FUNC (__generic_button_callback),
823 LISP_TO_VOID (callback));
825 /* We cheat here... GtkAccelLabel usually builds its
826 `accel_string' from the widget it is attached to, but we do
827 not want to go thru the overhead of converting our nice
828 string back into the modifier + key format that requires,
829 just so that they can convert it back into a (possibly
830 different/wrong) string
832 We set the label string manually, and things should 'just
835 In an ideal world we would just subclass GtkLabel ourselves,
836 but I have known for a very long time that this is not an
839 #### Should do menu shortcuts `correctly' one of these days.
844 GtkAccelLabel *l = GTK_ACCEL_LABEL (main_label);
846 gtk_container_add (GTK_CONTAINER (widget), main_label);
848 gtk_accel_label_set_accel_widget (l, NULL);
849 gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.5);
851 if (STRINGP (keys) && XSTRING_LENGTH (keys))
853 l->accel_string = g_strdup (XSTRING_DATA (keys));
866 static GtkWidget *menu_descriptor_to_widget (Lisp_Object descr)
868 int count = specpdl_depth ();
869 GtkWidget *rval = NULL;
871 record_unwind_protect (restore_gc_inhibit, make_int (gc_currently_forbidden));
873 gc_currently_forbidden = 1;
875 /* Cannot GC from here on out... */
876 rval = menu_descriptor_to_widget_1 (descr);
877 unbind_to (count, Qnil);
883 menu_can_reuse_widget (GtkWidget *child, const char *label)
885 /* Everything up at the top level was done using
886 ** gtk_menu_item_new_with_label(), but we still double check to make
887 ** sure we don't seriously foobar ourselves.
889 char *temp_label = NULL;
890 gpointer possible_child = g_list_nth_data (gtk_container_children (GTK_CONTAINER (child)), 0);
892 if (possible_child && GTK_IS_LABEL (possible_child))
894 if (!temp_label) temp_label = remove_underscores (label);
895 if (!strcmp (GTK_LABEL (possible_child)->label, temp_label))
901 if (temp_label) free (temp_label);
905 /* Converts a menubar description into a GtkMenuBar... a menubar is a
906 list of menus or buttons
909 menu_create_menubar (struct frame *f, Lisp_Object descr)
911 gboolean right_justify = FALSE;
912 Lisp_Object tail = Qnil;
913 Lisp_Object value = descr;
914 Lisp_Object item_descr = Qnil;
915 GtkWidget *menubar = FRAME_GTK_MENUBAR_WIDGET (f);
916 GUI_ID id = (GUI_ID) gtk_object_get_data (GTK_OBJECT (menubar), XEMACS_MENU_GUIID_TAG);
917 guint menu_position = 0;
919 /* Remove any existing protection for old menu items */
920 ungcpro_popup_callbacks (id);
922 /* GCPRO the whole damn thing */
923 gcpro_popup_callbacks (id, descr);
925 EXTERNAL_LIST_LOOP (tail, value)
927 gpointer current_child = g_list_nth_data (GTK_MENU_SHELL (menubar)->children, menu_position);
929 item_descr = XCAR (tail);
931 if (NILP (item_descr))
933 /* Need to start right-justifying menus */
934 right_justify = TRUE;
937 else if (VECTORP (item_descr))
939 /* It is a button description */
942 item = menu_descriptor_to_widget (item_descr);
943 gtk_widget_set_name (item, "XEmacsMenuButton");
947 item = gtk_menu_item_new_with_label ("ITEM CREATION ERROR");
950 gtk_widget_show_all (item);
951 if (current_child) gtk_widget_destroy (GTK_WIDGET (current_child));
952 gtk_menu_bar_insert (GTK_MENU_BAR (menubar), item, menu_position);
954 else if (LISTP (item_descr))
956 /* Need to actually convert it into a menu and slap it in */
958 gboolean reused_p = FALSE;
960 /* We may be able to reuse the widget, let's at least check. */
961 if (current_child && menu_can_reuse_widget (GTK_WIDGET (current_child),
962 XSTRING_DATA (XCAR (item_descr))))
964 widget = menu_convert (item_descr, GTK_WIDGET (current_child));
969 widget = menu_convert (item_descr, NULL);
970 if (current_child) gtk_widget_destroy (GTK_WIDGET (current_child));
971 gtk_menu_bar_insert (GTK_MENU_BAR (menubar), widget, menu_position);
976 if (right_justify) gtk_menu_item_right_justify (GTK_MENU_ITEM (widget));
980 widget = gtk_menu_item_new_with_label ("ERROR");
983 gtk_widget_show_all (widget);
985 else if (STRINGP (item_descr))
987 /* Do I really want to be this careful? Anything else in a
988 menubar description is illegal */
993 /* Need to delete any menu items that were past the bounds of the new one */
997 while ((l = g_list_nth (GTK_MENU_SHELL (menubar)->children, menu_position)))
999 gpointer data = l->data;
1000 g_list_remove_link (GTK_MENU_SHELL (menubar)->children, l);
1004 gtk_widget_destroy (GTK_WIDGET (data));
1011 /* Deal with getting/setting the menubar */
1012 #ifndef GNOME_IS_APP
1013 #define GNOME_IS_APP(x) 0
1014 #define gnome_app_set_menus(x,y)
1018 run_menubar_hook (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
1020 if (!GTK_MENU_SHELL(widget)->active)
1022 run_hook (Qactivate_menubar_hook);
1028 create_menubar_widget (struct frame *f)
1030 GUI_ID id = new_gui_id ();
1031 GtkWidget *handlebox = NULL;
1032 GtkWidget *menubar = gtk_xemacs_menubar_new (f);
1034 if (GNOME_IS_APP (FRAME_GTK_SHELL_WIDGET (f)))
1036 gnome_app_set_menus (GNOME_APP (FRAME_GTK_SHELL_WIDGET (f)), GTK_MENU_BAR (menubar));
1038 else if (dockable_menubar)
1040 handlebox = gtk_handle_box_new ();
1041 gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (handlebox), GTK_POS_LEFT);
1042 gtk_container_add (GTK_CONTAINER (handlebox), menubar);
1043 gtk_box_pack_start (GTK_BOX (FRAME_GTK_CONTAINER_WIDGET (f)), handlebox, FALSE, FALSE, 0);
1047 gtk_box_pack_start (GTK_BOX (FRAME_GTK_CONTAINER_WIDGET (f)), menubar, FALSE, FALSE, 0);
1050 gtk_signal_connect (GTK_OBJECT (menubar), "button-press-event",
1051 GTK_SIGNAL_FUNC (run_menubar_hook), NULL);
1053 FRAME_GTK_MENUBAR_WIDGET (f) = menubar;
1054 gtk_object_set_data (GTK_OBJECT (menubar), XEMACS_MENU_GUIID_TAG, (gpointer) id);
1055 gtk_object_weakref (GTK_OBJECT (menubar), __remove_gcpro_by_id, (gpointer) id);
1059 set_frame_menubar (struct frame *f, int first_time_p)
1061 Lisp_Object menubar;
1062 int menubar_visible;
1063 /* As for the toolbar, the minibuffer does not have its own menubar. */
1064 struct window *w = XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f));
1066 if (! FRAME_GTK_P (f))
1069 /***** first compute the contents of the menubar *****/
1073 /* evaluate `current-menubar' in the buffer of the selected window
1074 of the frame in question. */
1075 menubar = symbol_value_in_buffer (Qcurrent_menubar, w->buffer);
1079 /* That's a little tricky the first time since the frame isn't
1080 fully initialized yet. */
1081 menubar = Fsymbol_value (Qcurrent_menubar);
1086 menubar = Vblank_menubar;
1087 menubar_visible = 0;
1091 menubar_visible = !NILP (w->menubar_visible_p);
1094 if (!FRAME_GTK_MENUBAR_WIDGET (f))
1096 create_menubar_widget (f);
1099 /* Populate the menubar, but nothing is shown yet */
1101 Lisp_Object old_buffer;
1102 int count = specpdl_depth ();
1104 old_buffer = Fcurrent_buffer ();
1105 record_unwind_protect (Fset_buffer, old_buffer);
1106 Fset_buffer (XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer);
1108 menu_create_menubar (f, menubar);
1110 Fset_buffer (old_buffer);
1111 unbind_to (count, Qnil);
1114 FRAME_MENUBAR_DATA (f) = Fcons (XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f))->buffer, Qt);
1116 return (menubar_visible);
1119 /* Called from gtk_create_widgets() to create the inital menubar of a frame
1120 before it is mapped, so that the window is mapped with the menubar already
1121 there instead of us tacking it on later and thrashing the window after it
1124 gtk_initialize_frame_menubar (struct frame *f)
1126 create_menubar_widget (f);
1127 return set_frame_menubar (f, 1);
1132 gtk_update_frame_menubar_internal (struct frame *f)
1134 /* We assume the menubar contents has changed if the global flag is set,
1135 or if the current buffer has changed, or if the menubar has never
1136 been updated before.
1138 int menubar_contents_changed =
1140 || NILP (FRAME_MENUBAR_DATA (f))
1141 || (!EQ (XFRAME_MENUBAR_DATA_LASTBUFF (f),
1142 XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f))->buffer)));
1144 gboolean menubar_was_visible = GTK_WIDGET_VISIBLE (FRAME_GTK_MENUBAR_WIDGET (f));
1145 gboolean menubar_will_be_visible = menubar_was_visible;
1146 gboolean menubar_visibility_changed;
1148 if (menubar_contents_changed)
1150 menubar_will_be_visible = set_frame_menubar (f, 0);
1153 menubar_visibility_changed = menubar_was_visible != menubar_will_be_visible;
1155 if (!menubar_visibility_changed)
1160 /* We hide and show the menubar's parent (which is actually the
1161 GtkHandleBox)... this is to simplify the code that destroys old
1162 menu items, etc. There is no easy way to get the child out of a
1163 handle box, and I didn't want to add yet another stupid widget
1164 slot to struct gtk_frame. */
1165 if (menubar_will_be_visible)
1167 gtk_widget_show_all (FRAME_GTK_MENUBAR_WIDGET (f)->parent);
1171 gtk_widget_hide_all (FRAME_GTK_MENUBAR_WIDGET (f)->parent);
1174 MARK_FRAME_SIZE_SLIPPED (f);
1178 gtk_update_frame_menubars (struct frame *f)
1180 GtkWidget *menubar = NULL;
1182 assert (FRAME_GTK_P (f));
1184 menubar = FRAME_GTK_MENUBAR_WIDGET (f);
1186 if ((GTK_MENU_SHELL (menubar)->active) ||
1187 (GTK_MENU_SHELL (menubar)->have_grab) ||
1188 (GTK_MENU_SHELL (menubar)->have_xgrab))
1193 gtk_update_frame_menubar_internal (f);
1197 gtk_free_frame_menubars (struct frame *f)
1199 GtkWidget *menubar_widget;
1201 assert (FRAME_GTK_P (f));
1203 menubar_widget = FRAME_GTK_MENUBAR_WIDGET (f);
1206 gtk_widget_destroy (menubar_widget);
1210 static void popdown_menu_cb (GtkMenuShell *menu, gpointer user_data)
1216 gtk_popup_menu (Lisp_Object menu_desc, Lisp_Object event)
1218 struct Lisp_Event *eev = NULL;
1219 GtkWidget *widget = NULL;
1220 GtkWidget *menu = NULL;
1223 /* Do basic error checking first... */
1224 if (SYMBOLP (menu_desc))
1225 menu_desc = Fsymbol_value (menu_desc);
1226 CHECK_CONS (menu_desc);
1227 CHECK_STRING (XCAR (menu_desc));
1229 /* Now lets get down to business... */
1230 widget = menu_descriptor_to_widget (menu_desc);
1231 menu = GTK_MENU_ITEM (widget)->submenu;
1232 gtk_widget_set_name (widget, "XEmacsPopupMenu");
1233 id = gtk_object_get_data (GTK_OBJECT (widget), XEMACS_MENU_GUIID_TAG);
1235 __activate_menu (GTK_MENU_ITEM (widget), id);
1239 CHECK_LIVE_EVENT (event);
1240 eev = XEVENT (event);
1242 if ((eev->event_type != button_press_event) &&
1243 (eev->event_type != button_release_event))
1244 wrong_type_argument (Qmouse_event_p, event);
1246 else if (!NILP (Vthis_command_keys))
1248 /* If an event wasn't passed, use the last event of the event
1249 sequence currently being executed, if that event is a mouse
1251 eev = XEVENT (Vthis_command_keys);
1252 if ((eev->event_type != button_press_event) &&
1253 (eev->event_type != button_release_event))
1257 gtk_widget_show (menu);
1260 gtk_signal_connect (GTK_OBJECT (menu), "deactivate",
1261 GTK_SIGNAL_FUNC (popdown_menu_cb), NULL);
1263 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
1264 eev ? eev->event.button.button : 0,
1265 eev ? eev->timestamp : GDK_CURRENT_TIME);
1268 DEFUN ("gtk-build-xemacs-menu", Fgtk_build_xemacs_menu, 1, 1, 0, /*
1269 Returns a GTK menu item from MENU, a standard XEmacs menu description.
1270 See the definition of `popup-menu' for more information on the format of MENU.
1274 GtkWidget *w = menu_descriptor_to_widget (menu);
1276 return (w ? build_gtk_object (GTK_OBJECT (w)) : Qnil);
1281 syms_of_menubar_gtk (void)
1283 DEFSUBR (Fgtk_build_xemacs_menu);
1287 console_type_create_menubar_gtk (void)
1289 CONSOLE_HAS_METHOD (gtk, update_frame_menubars);
1290 CONSOLE_HAS_METHOD (gtk, free_frame_menubars);
1291 CONSOLE_HAS_METHOD (gtk, popup_menu);
1294 void reinit_vars_of_menubar_gtk (void)
1296 dockable_menubar = 1;
1297 #ifdef TEAR_OFF_MENUS
1303 vars_of_menubar_gtk (void)
1305 Fprovide (intern ("gtk-menubars"));
1306 DEFVAR_BOOL ("menubar-dockable-p", &dockable_menubar /*
1307 If non-nil, the frame menubar can be detached into its own top-level window.
1309 #ifdef TEAR_OFF_MENUS
1310 DEFVAR_BOOL ("menubar-tearable-p", &tear_off_menus /*
1311 If non-nil, menus can be torn off into their own top-level windows.
1314 reinit_vars_of_menubar_gtk ();