Mercurial > hg > xemacs-beta
comparison src/menubar-gtk.c @ 2081:e8db6a10ad42
[xemacs-hg @ 2004-05-15 07:31:43 by malcolmp]
Added support for Gtk menu bar, menu item and dialog button mnemonics.
author | malcolmp |
---|---|
date | Sat, 15 May 2004 07:31:49 +0000 |
parents | 91d4c8c65a0f |
children | 95fee4a1420e |
comparison
equal
deleted
inserted
replaced
2080:ebba17579ace | 2081:e8db6a10ad42 |
---|---|
1 /* Implements an elisp-programmable menubar -- X interface. | 1 /* Implements an elisp-programmable menubar -- Gtk interface. |
2 Copyright (C) 1993, 1994 Free Software Foundation, Inc. | 2 Copyright (C) 1993, 1994 Free Software Foundation, Inc. |
3 Copyright (C) 1995 Tinker Systems and INS Engineering Corp. | 3 Copyright (C) 1995 Tinker Systems and INS Engineering Corp. |
4 Copyright (C) 2002, 2003 Ben Wing. | 4 Copyright (C) 2002, 2003 Ben Wing. |
5 | 5 |
6 This file is part of XEmacs. | 6 This file is part of XEmacs. |
47 | 47 |
48 #define MENUBAR_TYPE 0 | 48 #define MENUBAR_TYPE 0 |
49 #define SUBMENU_TYPE 1 | 49 #define SUBMENU_TYPE 1 |
50 #define POPUP_TYPE 2 | 50 #define POPUP_TYPE 2 |
51 | 51 |
52 static GtkWidget *menu_descriptor_to_widget_1 (Lisp_Object descr); | 52 static GtkWidget *menu_descriptor_to_widget_1 (Lisp_Object descr, GtkAccelGroup* accel_group); |
53 | 53 |
54 #define FRAME_GTK_MENUBAR_DATA(f) (FRAME_GTK_DATA (f)->menubar_data) | 54 #define FRAME_GTK_MENUBAR_DATA(f) (FRAME_GTK_DATA (f)->menubar_data) |
55 #define XFRAME_GTK_MENUBAR_DATA_LASTBUFF(f) XCAR (FRAME_GTK_MENUBAR_DATA (f)) | 55 #define XFRAME_GTK_MENUBAR_DATA_LASTBUFF(f) XCAR (FRAME_GTK_MENUBAR_DATA (f)) |
56 #define XFRAME_GTK_MENUBAR_DATA_UPTODATE(f) XCDR (FRAME_GTK_MENUBAR_DATA (f)) | 56 #define XFRAME_GTK_MENUBAR_DATA_UPTODATE(f) XCDR (FRAME_GTK_MENUBAR_DATA (f)) |
57 | 57 |
111 } | 111 } |
112 | 112 |
113 return xemacs_menubar_type; | 113 return xemacs_menubar_type; |
114 } | 114 } |
115 | 115 |
116 static GtkWidgetClass *parent_class; | 116 static GtkWidgetClass *menubar_parent_class; |
117 | 117 |
118 static void | 118 static void |
119 gtk_xemacs_menubar_class_init (GtkXEmacsMenubarClass *klass) | 119 gtk_xemacs_menubar_class_init (GtkXEmacsMenubarClass *klass) |
120 { | 120 { |
121 GtkWidgetClass *widget_class; | 121 GtkWidgetClass *widget_class; |
122 | 122 |
123 widget_class = (GtkWidgetClass*) klass; | 123 widget_class = (GtkWidgetClass*) klass; |
124 parent_class = (GtkWidgetClass *) gtk_type_class (gtk_menu_bar_get_type ()); | 124 menubar_parent_class = (GtkWidgetClass *) gtk_type_class (gtk_menu_bar_get_type ()); |
125 | 125 |
126 widget_class->size_request = gtk_xemacs_menubar_size_request; | 126 widget_class->size_request = gtk_xemacs_menubar_size_request; |
127 } | 127 } |
128 | 128 |
129 static void | 129 static void |
135 gtk_xemacs_menubar_size_request (GtkWidget *widget, GtkRequisition *requisition) | 135 gtk_xemacs_menubar_size_request (GtkWidget *widget, GtkRequisition *requisition) |
136 { | 136 { |
137 GtkXEmacsMenubar *x = GTK_XEMACS_MENUBAR (widget); | 137 GtkXEmacsMenubar *x = GTK_XEMACS_MENUBAR (widget); |
138 GtkRequisition frame_size; | 138 GtkRequisition frame_size; |
139 | 139 |
140 parent_class->size_request (widget, requisition); | 140 menubar_parent_class->size_request (widget, requisition); |
141 | 141 |
142 /* #### BILL! | 142 /* #### BILL! |
143 ** We should really only do this if the menu has not been detached! | 143 ** We should really only do this if the menu has not been detached! |
144 ** | 144 ** |
145 ** WMP 9/9/2000 | 145 ** WMP 9/9/2000 |
158 menubar->frame = f; | 158 menubar->frame = f; |
159 | 159 |
160 return (GTK_WIDGET (menubar)); | 160 return (GTK_WIDGET (menubar)); |
161 } | 161 } |
162 | 162 |
163 /* | |
164 * Label with XEmacs accelerator character support. | |
165 * | |
166 * The default interfaces to GtkAccelLabel does not understand XEmacs | |
167 * keystroke printing conventions, nor is it convenient in the places where is | |
168 * it needed. This subclass provides an alternative interface more suited to | |
169 * XEmacs needs but does not add new functionality. | |
170 */ | |
171 #define GTK_TYPE_XEMACS_ACCEL_LABEL (gtk_xemacs_accel_label_get_type ()) | |
172 #define GTK_XEMACS_ACCEL_LABEL(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_ACCEL_LABEL, GtkXEmacsAccelLabel)) | |
173 #define GTK_XEMACS_ACCEL_LABEL_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_ACCEL_LABEL, GtkXEmacsAccelLabelClass)) | |
174 #define GTK_IS_XEMACS_ACCEL_LABEL(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_XEMACS_ACCEL_LABEL)) | |
175 #define GTK_IS_XEMACS_ACCEL_LABEL_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_XEMACS_ACCEL_LABEL)) | |
176 | |
177 typedef struct _GtkXEmacsAccelLabel GtkXEmacsAccelLabel; | |
178 typedef struct _GtkXEmacsAccelLabelClass GtkXEmacsAccelLabelClass; | |
179 | |
180 /* Instance structure. No additional fields required. */ | |
181 struct _GtkXEmacsAccelLabel | |
182 { | |
183 GtkAccelLabel label; | |
184 }; | |
185 | |
186 /* Class structure. No additional fields required. */ | |
187 struct _GtkXEmacsAccelLabelClass | |
188 { | |
189 GtkAccelLabelClass parent_class; | |
190 }; | |
191 | |
192 static GtkType gtk_xemacs_accel_label_get_type(void); | |
193 static GtkWidget* gtk_xemacs_accel_label_new(const gchar *string); | |
194 static void gtk_xemacs_set_accel_keys(GtkXEmacsAccelLabel* l, | |
195 Lisp_Object keys); | |
196 static void gtk_xemacs_accel_label_class_init(GtkXEmacsAccelLabelClass *klass); | |
197 static void gtk_xemacs_accel_label_init(GtkXEmacsAccelLabel *xemacs); | |
198 | |
199 static GtkType | |
200 gtk_xemacs_accel_label_get_type(void) | |
201 { | |
202 static GtkType xemacs_accel_label_type = 0; | |
203 | |
204 if (!xemacs_accel_label_type) | |
205 { | |
206 static const GtkTypeInfo xemacs_accel_label_info = | |
207 { | |
208 "GtkXEmacsAccelLabel", | |
209 sizeof (GtkXEmacsAccelLabel), | |
210 sizeof (GtkXEmacsAccelLabelClass), | |
211 (GtkClassInitFunc) gtk_xemacs_accel_label_class_init, | |
212 (GtkObjectInitFunc) gtk_xemacs_accel_label_init, | |
213 /* reserved_1 */ NULL, | |
214 /* reserved_2 */ NULL, | |
215 (GtkClassInitFunc) NULL, | |
216 }; | |
217 | |
218 xemacs_accel_label_type = gtk_type_unique (gtk_accel_label_get_type(), &xemacs_accel_label_info); | |
219 } | |
220 | |
221 return xemacs_accel_label_type; | |
222 } | |
223 | |
224 static void | |
225 gtk_xemacs_accel_label_class_init(GtkXEmacsAccelLabelClass *klass) | |
226 { | |
227 /* Nothing to do. */ | |
228 } | |
229 | |
230 static void | |
231 gtk_xemacs_accel_label_init(GtkXEmacsAccelLabel *xemacs) | |
232 { | |
233 /* Nothing to do. */ | |
234 } | |
235 | |
236 static GtkWidget* | |
237 gtk_xemacs_accel_label_new (const gchar *string) | |
238 { | |
239 GtkXEmacsAccelLabel *xemacs_accel_label; | |
240 | |
241 xemacs_accel_label = (GtkXEmacsAccelLabel*) gtk_type_new (GTK_TYPE_XEMACS_ACCEL_LABEL); | |
242 | |
243 if (string && *string) | |
244 gtk_label_set_text (GTK_LABEL (xemacs_accel_label), string); | |
245 | |
246 return GTK_WIDGET (xemacs_accel_label); | |
247 } | |
248 | |
249 /* Make the string <keys> the accelerator string for the label. */ | |
250 static void | |
251 gtk_xemacs_set_accel_keys(GtkXEmacsAccelLabel* l, Lisp_Object keys) | |
252 { | |
253 g_return_if_fail (l != NULL); | |
254 g_return_if_fail (GTK_IS_XEMACS_ACCEL_LABEL (l)); | |
255 | |
256 /* Disable the standard way of finding the accelerator string for the | |
257 label. */ | |
258 gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL(l), NULL); | |
259 | |
260 /* Set the string straight from the object. */ | |
261 if (STRINGP (keys) && XSTRING_LENGTH (keys)) | |
262 { | |
263 C_STRING_TO_EXTERNAL_MALLOC(XSTRING_DATA (keys), | |
264 l->label.accel_string, | |
265 Qctext); | |
266 } | |
267 else | |
268 { | |
269 /* l->label.accel_string = NULL;*/ | |
270 } | |
271 } | |
272 | |
273 | |
163 /* We now return you to your regularly scheduled menus... */ | 274 /* We now return you to your regularly scheduled menus... */ |
164 | 275 |
165 int dockable_menubar; | 276 int dockable_menubar; |
166 | 277 |
167 /* #define TEAR_OFF_MENUS */ | 278 /* #define TEAR_OFF_MENUS */ |
318 /* Signal an error here? The NILP handling is handled a | 429 /* Signal an error here? The NILP handling is handled a |
319 layer higher where appropriate */ | 430 layer higher where appropriate */ |
320 } | 431 } |
321 else | 432 else |
322 { | 433 { |
323 next = menu_descriptor_to_widget_1 (child); | 434 next = menu_descriptor_to_widget_1 (child, |
435 gtk_menu_ensure_uline_accel_group (GTK_MENU (item->submenu))); | |
324 } | 436 } |
325 | 437 |
326 if (!next) | 438 if (!next) |
327 { | 439 { |
328 continue; | 440 continue; |
353 gtk_timeout_remove (mi->timer); | 465 gtk_timeout_remove (mi->timer); |
354 mi->timer = 0; | 466 mi->timer = 0; |
355 } | 467 } |
356 } | 468 } |
357 | 469 |
470 /* Convert the XEmacs menu accelerator representation to Gtk mnemonic form. If | |
471 no accelerator has been provided, put one at the start of the string (this | |
472 mirrors the behaviour under X). This algorithm is also found in | |
473 dialog-gtk.el:gtk-popup-convert-underscores. | |
474 */ | |
358 static char * | 475 static char * |
359 remove_underscores(const Ibyte* name) | 476 convert_underscores(const Ibyte *name) |
360 { | 477 { |
361 char *rval = (char*) xmalloc_and_zero (strlen((char*) name) + 1); | 478 char *rval; |
479 int i,j; | |
480 int found_accel = FALSE; | |
481 int underscores = 0; | |
482 | |
483 for (i = 0; name[i]; ++i) | |
484 if (name[i] == '%' && name[i+1] == '_') | |
485 { | |
486 found_accel = TRUE; | |
487 } | |
488 else if (name[i] == '_') | |
489 { | |
490 underscores++; | |
491 } | |
492 | |
493 /* Allocate space for the original string, plus zero byte plus extra space | |
494 for all quoted underscores plus possible additional leading accelerator. */ | |
495 rval = (char*) xmalloc_and_zero (qxestrlen(name) + 1 + underscores | |
496 + (found_accel ? 0 : 1)); | |
497 | |
498 if (!found_accel) | |
499 rval[0] = '_'; | |
500 | |
501 for (i = 0, j = (found_accel ? 0 : 1); name[i]; i++) | |
502 { | |
503 if (name[i]=='%') | |
504 { | |
505 i++; | |
506 if (!(name[i])) | |
507 continue; | |
508 | |
509 if ((name[i] != '_') && (name[i] != '%')) | |
510 i--; | |
511 | |
512 found_accel = TRUE; | |
513 } | |
514 else if (name[i] == '_') | |
515 { | |
516 rval[j++] = '_'; | |
517 } | |
518 | |
519 rval[j++] = name[i]; | |
520 } | |
521 | |
522 return rval; | |
523 } | |
524 | |
525 /* Remove the XEmacs menu accellerator representation from a string. */ | |
526 static char * | |
527 remove_underscores(const Ibyte *name) | |
528 { | |
529 char *rval = (char*) xmalloc_and_zero (qxestrlen(name) + 1); | |
362 int i,j; | 530 int i,j; |
363 | 531 |
364 for (i = 0, j = 0; name[i]; i++) | 532 for (i = 0, j = 0; name[i]; i++) |
365 { | 533 { |
366 if (name[i]=='%') { | 534 if (name[i]=='%') { |
367 i++; | 535 i++; |
368 if (!(name[i])) | 536 if (!(name[i])) |
369 continue; | 537 continue; |
370 | 538 |
371 if ((name[i] == '_')) | 539 if ((name[i] != '_') && (name[i] != '%')) |
540 i--; | |
541 else | |
372 continue; | 542 continue; |
373 } | 543 } |
374 rval[j++] = name[i]; | 544 rval[j++] = name[i]; |
375 } | 545 } |
376 return rval; | 546 return rval; |
379 /* This converts an entire menu into a GtkMenuItem (with an attached | 549 /* This converts an entire menu into a GtkMenuItem (with an attached |
380 submenu). A menu is a list of (STRING [:keyword value]+ [DESCR]+) | 550 submenu). A menu is a list of (STRING [:keyword value]+ [DESCR]+) |
381 DESCR is either a list (meaning a submenu), a vector, or nil (if | 551 DESCR is either a list (meaning a submenu), a vector, or nil (if |
382 you include a :filter keyword) */ | 552 you include a :filter keyword) */ |
383 static GtkWidget * | 553 static GtkWidget * |
384 menu_convert (Lisp_Object desc, GtkWidget *reuse) | 554 menu_convert (Lisp_Object desc, GtkWidget *reuse, |
555 GtkAccelGroup* menubar_accel_group) | |
385 { | 556 { |
386 GtkWidget *menu_item = NULL; | 557 GtkWidget *menu_item = NULL; |
387 GtkWidget *submenu = NULL; | 558 GtkWidget *submenu = NULL; |
388 Lisp_Object key, val; | 559 Lisp_Object key, val; |
389 Lisp_Object include_p = Qnil, hook_fn = Qnil, config_tag = Qnil; | 560 Lisp_Object include_p = Qnil, hook_fn = Qnil, config_tag = Qnil; |
396 { | 567 { |
397 accel = menu_name_to_accelerator (XSTRING_DATA (XCAR (desc))); | 568 accel = menu_name_to_accelerator (XSTRING_DATA (XCAR (desc))); |
398 | 569 |
399 if (!reuse) | 570 if (!reuse) |
400 { | 571 { |
401 char *temp_menu_name = remove_underscores (XSTRING_DATA (XCAR (desc))); | 572 char *temp_menu_name = convert_underscores (XSTRING_DATA (XCAR (desc))); |
402 menu_item = gtk_menu_item_new_with_label (temp_menu_name); | 573 GtkWidget* accel_label = gtk_xemacs_accel_label_new(NULL); |
574 guint accel_key; | |
575 | |
576 gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5); | |
577 accel_key = gtk_label_parse_uline (GTK_LABEL (accel_label), temp_menu_name); | |
578 | |
579 menu_item = gtk_menu_item_new (); | |
580 gtk_container_add (GTK_CONTAINER (menu_item), accel_label); | |
581 gtk_widget_show (accel_label); | |
582 | |
583 if (menubar_accel_group) | |
584 gtk_widget_add_accelerator (menu_item, | |
585 "activate_item", | |
586 menubar_accel_group, | |
587 accel_key, GDK_MOD1_MASK, | |
588 GTK_ACCEL_LOCKED); | |
403 free (temp_menu_name); | 589 free (temp_menu_name); |
404 } | 590 } |
405 else | 591 else |
406 { | 592 { |
407 menu_item = reuse; | 593 menu_item = reuse; |
581 /* Convert a single menu item descriptor to a suitable GtkMenuItem */ | 767 /* Convert a single menu item descriptor to a suitable GtkMenuItem */ |
582 /* This function cannot GC. | 768 /* This function cannot GC. |
583 It is only called from menu_item_descriptor_to_widget_value, which | 769 It is only called from menu_item_descriptor_to_widget_value, which |
584 prohibits GC. */ | 770 prohibits GC. */ |
585 static GtkWidget * | 771 static GtkWidget * |
586 menu_descriptor_to_widget_1 (Lisp_Object descr) | 772 menu_descriptor_to_widget_1 (Lisp_Object descr, GtkAccelGroup* accel_group) |
587 { | 773 { |
588 if (STRINGP (descr)) | 774 if (STRINGP (descr)) |
589 { | 775 { |
590 /* It is a separator. Unfortunately GTK does not allow us to | 776 /* It is a separator. Unfortunately GTK does not allow us to |
591 specify what our separators look like, so we can't do all the | 777 specify what our separators look like, so we can't do all the |
594 return (gtk_menu_item_new ()); | 780 return (gtk_menu_item_new ()); |
595 } | 781 } |
596 else if (LISTP (descr)) | 782 else if (LISTP (descr)) |
597 { | 783 { |
598 /* It is a submenu */ | 784 /* It is a submenu */ |
599 return (menu_convert (descr, NULL)); | 785 return (menu_convert (descr, NULL, accel_group)); |
600 } | 786 } |
601 else if (VECTORP (descr)) | 787 else if (VECTORP (descr)) |
602 { | 788 { |
603 /* An actual menu item description! This gets yucky. */ | 789 /* An actual menu item description! This gets yucky. */ |
604 Lisp_Object name = Qnil; | 790 Lisp_Object name = Qnil; |
615 int length = XVECTOR_LENGTH (descr); | 801 int length = XVECTOR_LENGTH (descr); |
616 Lisp_Object *contents = XVECTOR_DATA (descr); | 802 Lisp_Object *contents = XVECTOR_DATA (descr); |
617 int plist_p; | 803 int plist_p; |
618 int selected_spec = 0, included_spec = 0; | 804 int selected_spec = 0, included_spec = 0; |
619 GtkWidget *widget = NULL; | 805 GtkWidget *widget = NULL; |
806 guint accel_key; | |
620 | 807 |
621 if (length < 2) | 808 if (length < 2) |
622 sferror ("button descriptors must be at least 2 long", descr); | 809 sferror ("button descriptors must be at least 2 long", descr); |
623 | 810 |
624 /* length 2: [ "name" callback ] | 811 /* length 2: [ "name" callback ] |
710 { | 897 { |
711 label_buffer = (Ibyte*) ALLOCA (XSTRING_LENGTH (name) + 15); | 898 label_buffer = (Ibyte*) ALLOCA (XSTRING_LENGTH (name) + 15); |
712 sprintf ((char*) label_buffer, "%s ", XSTRING_DATA (name)); | 899 sprintf ((char*) label_buffer, "%s ", XSTRING_DATA (name)); |
713 } | 900 } |
714 | 901 |
715 temp_label = remove_underscores (label_buffer); | 902 temp_label = convert_underscores (label_buffer); |
716 main_label = gtk_accel_label_new (temp_label); | 903 main_label = gtk_xemacs_accel_label_new (NULL); |
904 accel_key = gtk_label_parse_uline (GTK_LABEL (main_label), temp_label); | |
717 free (temp_label); | 905 free (temp_label); |
718 } | 906 } |
719 | 907 |
720 /* Evaluate the selected and active items now */ | 908 /* Evaluate the selected and active items now */ |
721 if (selected_spec) | 909 if (selected_spec) |
835 | 1023 |
836 gtk_signal_connect (GTK_OBJECT (widget), "activate", | 1024 gtk_signal_connect (GTK_OBJECT (widget), "activate", |
837 GTK_SIGNAL_FUNC (__generic_button_callback), | 1025 GTK_SIGNAL_FUNC (__generic_button_callback), |
838 LISP_TO_VOID (callback)); | 1026 LISP_TO_VOID (callback)); |
839 | 1027 |
840 /* We cheat here... GtkAccelLabel usually builds its | 1028 /* Now that all the information about the menu item is know, set the |
841 `accel_string' from the widget it is attached to, but we do | 1029 remaining properties. |
842 not want to go thru the overhead of converting our nice | |
843 string back into the modifier + key format that requires, | |
844 just so that they can convert it back into a (possibly | |
845 different/wrong) string | |
846 | |
847 We set the label string manually, and things should 'just | |
848 work' | |
849 | |
850 In an ideal world we would just subclass GtkLabel ourselves, | |
851 but I have known for a very long time that this is not an | |
852 ideal world. | |
853 | |
854 #### Should do menu shortcuts `correctly' one of these days. | |
855 */ | 1030 */ |
856 | 1031 |
857 if (main_label) | 1032 if (main_label) |
858 { | 1033 { |
859 GtkAccelLabel *l = GTK_ACCEL_LABEL (main_label); | |
860 | |
861 gtk_container_add (GTK_CONTAINER (widget), main_label); | 1034 gtk_container_add (GTK_CONTAINER (widget), main_label); |
862 | 1035 |
863 gtk_accel_label_set_accel_widget (l, NULL); | 1036 gtk_misc_set_alignment (GTK_MISC (main_label), 0.0, 0.5); |
864 gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.5); | 1037 gtk_xemacs_set_accel_keys(GTK_XEMACS_ACCEL_LABEL(main_label), keys); |
865 | 1038 |
866 if (STRINGP (keys) && XSTRING_LENGTH (keys)) | 1039 if (accel_group) |
867 { | 1040 gtk_widget_add_accelerator (widget, |
868 C_STRING_TO_EXTERNAL_MALLOC (XSTRING_DATA (keys), l->accel_string, | 1041 "activate_item", |
869 Qctext); | 1042 accel_group, |
870 stderr_out ("accel: %s\n", l->accel_string); | 1043 accel_key, 0, |
871 } | 1044 GTK_ACCEL_LOCKED); |
872 else | |
873 { | |
874 /* l->accel_string = ""; */ | |
875 } | |
876 } | 1045 } |
877 | 1046 |
878 return (widget); | 1047 return (widget); |
879 } | 1048 } |
880 else | 1049 else |
883 /* abort (); ???? */ | 1052 /* abort (); ???? */ |
884 } | 1053 } |
885 } | 1054 } |
886 | 1055 |
887 static GtkWidget * | 1056 static GtkWidget * |
888 menu_descriptor_to_widget (Lisp_Object descr) | 1057 menu_descriptor_to_widget (Lisp_Object descr, GtkAccelGroup* accel_group) |
889 { | 1058 { |
890 GtkWidget *rval = NULL; | 1059 GtkWidget *rval = NULL; |
891 int count = begin_gc_forbidden (); | 1060 int count = begin_gc_forbidden (); |
892 | 1061 |
893 /* Cannot GC from here on out... */ | 1062 /* Cannot GC from here on out... */ |
894 rval = menu_descriptor_to_widget_1 (descr); | 1063 rval = menu_descriptor_to_widget_1 (descr, accel_group); |
895 unbind_to (count); | 1064 unbind_to (count); |
896 return (rval); | 1065 return (rval); |
897 | 1066 |
898 } | 1067 } |
899 | 1068 |
900 static gboolean | 1069 static gboolean |
901 menu_can_reuse_widget (GtkWidget *child, const Ibyte *label) | 1070 menu_can_reuse_widget (GtkWidget *child, const Ibyte *label) |
902 { | 1071 { |
903 /* Everything up at the top level was done using | 1072 /* Everything up at the top level was done using |
904 ** gtk_menu_item_new_with_label(), but we still double check to make | 1073 ** gtk_xemacs_accel_label_new(), but we still double check to make |
905 ** sure we don't seriously foobar ourselves. | 1074 ** sure we don't seriously foobar ourselves. |
906 */ | 1075 */ |
907 char *temp_label = NULL; | 1076 gpointer possible_child = |
908 gpointer possible_child = g_list_nth_data (gtk_container_children (GTK_CONTAINER (child)), 0); | 1077 g_list_nth_data (gtk_container_children (GTK_CONTAINER (child)), 0); |
1078 gboolean ret_val = FALSE; | |
909 | 1079 |
910 if (possible_child && GTK_IS_LABEL (possible_child)) | 1080 if (possible_child && GTK_IS_LABEL (possible_child)) |
911 { | 1081 { |
912 if (!temp_label) temp_label = remove_underscores (label); | 1082 char *temp_label = remove_underscores (label); |
1083 | |
913 if (!strcmp (GTK_LABEL (possible_child)->label, temp_label)) | 1084 if (!strcmp (GTK_LABEL (possible_child)->label, temp_label)) |
914 { | 1085 ret_val = TRUE; |
915 free (temp_label); | 1086 |
916 return (TRUE); | 1087 free (temp_label); |
917 } | 1088 } |
918 } | 1089 |
919 if (temp_label) free (temp_label); | 1090 return ret_val; |
920 return (FALSE); | |
921 } | 1091 } |
922 | 1092 |
923 /* Converts a menubar description into a GtkMenuBar... a menubar is a | 1093 /* Converts a menubar description into a GtkMenuBar... a menubar is a |
924 list of menus or buttons | 1094 list of menus or buttons |
925 */ | 1095 */ |
931 Lisp_Object value = descr; | 1101 Lisp_Object value = descr; |
932 Lisp_Object item_descr = Qnil; | 1102 Lisp_Object item_descr = Qnil; |
933 GtkWidget *menubar = FRAME_GTK_MENUBAR_WIDGET (f); | 1103 GtkWidget *menubar = FRAME_GTK_MENUBAR_WIDGET (f); |
934 GUI_ID id = (GUI_ID) gtk_object_get_data (GTK_OBJECT (menubar), XEMACS_MENU_GUIID_TAG); | 1104 GUI_ID id = (GUI_ID) gtk_object_get_data (GTK_OBJECT (menubar), XEMACS_MENU_GUIID_TAG); |
935 guint menu_position = 0; | 1105 guint menu_position = 0; |
1106 GtkAccelGroup *menubar_accel_group; | |
936 | 1107 |
937 /* Remove any existing protection for old menu items */ | 1108 /* Remove any existing protection for old menu items */ |
938 ungcpro_popup_callbacks (id); | 1109 ungcpro_popup_callbacks (id); |
939 | 1110 |
940 /* GCPRO the whole damn thing */ | 1111 /* GCPRO the whole damn thing */ |
941 gcpro_popup_callbacks (id, descr); | 1112 gcpro_popup_callbacks (id, descr); |
1113 | |
1114 menubar_accel_group = gtk_accel_group_new(); | |
942 | 1115 |
943 EXTERNAL_LIST_LOOP (tail, value) | 1116 EXTERNAL_LIST_LOOP (tail, value) |
944 { | 1117 { |
945 gpointer current_child = g_list_nth_data (GTK_MENU_SHELL (menubar)->children, menu_position); | 1118 gpointer current_child = g_list_nth_data (GTK_MENU_SHELL (menubar)->children, menu_position); |
946 | 1119 |
955 else if (VECTORP (item_descr)) | 1128 else if (VECTORP (item_descr)) |
956 { | 1129 { |
957 /* It is a button description */ | 1130 /* It is a button description */ |
958 GtkWidget *item; | 1131 GtkWidget *item; |
959 | 1132 |
960 item = menu_descriptor_to_widget (item_descr); | 1133 item = menu_descriptor_to_widget (item_descr, menubar_accel_group); |
961 gtk_widget_set_name (item, "XEmacsMenuButton"); | 1134 gtk_widget_set_name (item, "XEmacsMenuButton"); |
962 | 1135 |
963 if (!item) | 1136 if (!item) |
964 { | 1137 { |
965 item = gtk_menu_item_new_with_label ("ITEM CREATION ERROR"); | 1138 item = gtk_menu_item_new_with_label ("ITEM CREATION ERROR"); |
977 | 1150 |
978 /* We may be able to reuse the widget, let's at least check. */ | 1151 /* We may be able to reuse the widget, let's at least check. */ |
979 if (current_child && menu_can_reuse_widget (GTK_WIDGET (current_child), | 1152 if (current_child && menu_can_reuse_widget (GTK_WIDGET (current_child), |
980 XSTRING_DATA (XCAR (item_descr)))) | 1153 XSTRING_DATA (XCAR (item_descr)))) |
981 { | 1154 { |
982 widget = menu_convert (item_descr, GTK_WIDGET (current_child)); | 1155 widget = menu_convert (item_descr, GTK_WIDGET (current_child), |
1156 menubar_accel_group); | |
983 reused_p = TRUE; | 1157 reused_p = TRUE; |
984 } | 1158 } |
985 else | 1159 else |
986 { | 1160 { |
987 widget = menu_convert (item_descr, NULL); | 1161 widget = menu_convert (item_descr, NULL, menubar_accel_group); |
988 if (current_child) gtk_widget_destroy (GTK_WIDGET (current_child)); | 1162 if (current_child) gtk_widget_destroy (GTK_WIDGET (current_child)); |
989 gtk_menu_bar_insert (GTK_MENU_BAR (menubar), widget, menu_position); | 1163 gtk_menu_bar_insert (GTK_MENU_BAR (menubar), widget, menu_position); |
990 } | 1164 } |
991 | 1165 |
992 if (widget) | 1166 if (widget) |
1021 { | 1195 { |
1022 gtk_widget_destroy (GTK_WIDGET (data)); | 1196 gtk_widget_destroy (GTK_WIDGET (data)); |
1023 } | 1197 } |
1024 } | 1198 } |
1025 } | 1199 } |
1200 | |
1201 /* Attach the new accelerator group to the frame. */ | |
1202 gtk_window_add_accel_group (GTK_WINDOW (FRAME_GTK_SHELL_WIDGET(f)), | |
1203 menubar_accel_group); | |
1026 } | 1204 } |
1027 | 1205 |
1028 | 1206 |
1029 /* Deal with getting/setting the menubar */ | 1207 /* Deal with getting/setting the menubar */ |
1030 #ifndef GNOME_IS_APP | 1208 #ifndef GNOME_IS_APP |
1244 menu_desc = Fsymbol_value (menu_desc); | 1422 menu_desc = Fsymbol_value (menu_desc); |
1245 CHECK_CONS (menu_desc); | 1423 CHECK_CONS (menu_desc); |
1246 CHECK_STRING (XCAR (menu_desc)); | 1424 CHECK_STRING (XCAR (menu_desc)); |
1247 | 1425 |
1248 /* Now lets get down to business... */ | 1426 /* Now lets get down to business... */ |
1249 widget = menu_descriptor_to_widget (menu_desc); | 1427 widget = menu_descriptor_to_widget (menu_desc, NULL); |
1250 menu = GTK_MENU_ITEM (widget)->submenu; | 1428 menu = GTK_MENU_ITEM (widget)->submenu; |
1251 gtk_widget_set_name (widget, "XEmacsPopupMenu"); | 1429 gtk_widget_set_name (widget, "XEmacsPopupMenu"); |
1252 id = gtk_object_get_data (GTK_OBJECT (widget), XEMACS_MENU_GUIID_TAG); | 1430 id = gtk_object_get_data (GTK_OBJECT (widget), XEMACS_MENU_GUIID_TAG); |
1253 | 1431 |
1254 __activate_menu (GTK_MENU_ITEM (widget), id); | 1432 __activate_menu (GTK_MENU_ITEM (widget), id); |
1288 Returns a GTK menu item from MENU, a standard XEmacs menu description. | 1466 Returns a GTK menu item from MENU, a standard XEmacs menu description. |
1289 See the definition of `popup-menu' for more information on the format of MENU. | 1467 See the definition of `popup-menu' for more information on the format of MENU. |
1290 */ | 1468 */ |
1291 (menu)) | 1469 (menu)) |
1292 { | 1470 { |
1293 GtkWidget *w = menu_descriptor_to_widget (menu); | 1471 GtkWidget *w = menu_descriptor_to_widget (menu, NULL); |
1294 | 1472 |
1295 return (w ? build_gtk_object (GTK_OBJECT (w)) : Qnil); | 1473 return (w ? build_gtk_object (GTK_OBJECT (w)) : Qnil); |
1296 } | 1474 } |
1297 | 1475 |
1298 | 1476 |
1331 If non-nil, menus can be torn off into their own top-level windows. | 1509 If non-nil, menus can be torn off into their own top-level windows. |
1332 */ ); | 1510 */ ); |
1333 #endif | 1511 #endif |
1334 reinit_vars_of_menubar_gtk (); | 1512 reinit_vars_of_menubar_gtk (); |
1335 } | 1513 } |
1514 | |
1515 /*---------------------------------------------------------------------------*/ | |
1516 |