Mercurial > hg > xemacs-beta
annotate src/menubar-gtk.c @ 4981:4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
-------------------- ChangeLog entries follow: --------------------
modules/ChangeLog addition:
2010-02-05 Ben Wing <ben@xemacs.org>
* postgresql/postgresql.c:
* postgresql/postgresql.c (CHECK_LIVE_CONNECTION):
* postgresql/postgresql.c (Fpq_connectdb):
* postgresql/postgresql.c (Fpq_connect_start):
* postgresql/postgresql.c (Fpq_lo_import):
* postgresql/postgresql.c (Fpq_lo_export):
* ldap/eldap.c (Fldap_open):
* ldap/eldap.c (Fldap_search_basic):
* ldap/eldap.c (Fldap_add):
* ldap/eldap.c (Fldap_modify):
* ldap/eldap.c (Fldap_delete):
* canna/canna_api.c (Fcanna_initialize):
* canna/canna_api.c (Fcanna_store_yomi):
* canna/canna_api.c (Fcanna_parse):
* canna/canna_api.c (Fcanna_henkan_begin):
EXTERNAL_TO_C_STRING returns its argument instead of storing it
in a parameter, and is renamed to EXTERNAL_TO_ITEXT. Similar
things happen to related macros. See entry in src/ChangeLog.
More Mule-izing of postgresql.c. Extract out common code
between `pq-connectdb' and `pq-connect-start'. Fix places
that signal an error string using a formatted string to instead
follow the standard and have a fixed reason followed by the
particular error message stored as one of the frobs.
src/ChangeLog addition:
2010-02-05 Ben Wing <ben@xemacs.org>
* console-msw.c (write_string_to_mswindows_debugging_output):
* console-msw.c (Fmswindows_message_box):
* console-x.c (x_perhaps_init_unseen_key_defaults):
* console.c:
* database.c (dbm_get):
* database.c (dbm_put):
* database.c (dbm_remove):
* database.c (berkdb_get):
* database.c (berkdb_put):
* database.c (berkdb_remove):
* database.c (Fopen_database):
* device-gtk.c (gtk_init_device):
* device-msw.c (msprinter_init_device_internal):
* device-msw.c (msprinter_default_printer):
* device-msw.c (msprinter_init_device):
* device-msw.c (sync_printer_with_devmode):
* device-msw.c (Fmsprinter_select_settings):
* device-x.c (sanity_check_geometry_resource):
* device-x.c (Dynarr_add_validified_lisp_string):
* device-x.c (x_init_device):
* device-x.c (Fx_put_resource):
* device-x.c (Fx_valid_keysym_name_p):
* device-x.c (Fx_set_font_path):
* dialog-msw.c (push_lisp_string_as_unicode):
* dialog-msw.c (handle_directory_dialog_box):
* dialog-msw.c (handle_file_dialog_box):
* dialog-x.c (dbox_descriptor_to_widget_value):
* editfns.c (Fformat_time_string):
* editfns.c (Fencode_time):
* editfns.c (Fset_time_zone_rule):
* emacs.c (make_argc_argv):
* emacs.c (Fdump_emacs):
* emodules.c (emodules_load):
* eval.c:
* eval.c (maybe_signal_error_1):
* event-msw.c (Fdde_alloc_advise_item):
* event-msw.c (mswindows_dde_callback):
* event-msw.c (mswindows_wnd_proc):
* fileio.c (report_error_with_errno):
* fileio.c (Fsysnetunam):
* fileio.c (Fdo_auto_save):
* font-mgr.c (extract_fcapi_string):
* font-mgr.c (Ffc_config_app_font_add_file):
* font-mgr.c (Ffc_config_app_font_add_dir):
* font-mgr.c (Ffc_config_filename):
* frame-gtk.c (gtk_set_frame_text_value):
* frame-gtk.c (gtk_create_widgets):
* frame-msw.c (mswindows_init_frame_1):
* frame-msw.c (mswindows_set_title_from_ibyte):
* frame-msw.c (msprinter_init_frame_3):
* frame-x.c (x_set_frame_text_value):
* frame-x.c (x_set_frame_properties):
* frame-x.c (start_drag_internal_1):
* frame-x.c (x_cde_transfer_callback):
* frame-x.c (x_create_widgets):
* glyphs-eimage.c (my_jpeg_output_message):
* glyphs-eimage.c (jpeg_instantiate):
* glyphs-eimage.c (gif_instantiate):
* glyphs-eimage.c (png_instantiate):
* glyphs-eimage.c (tiff_instantiate):
* glyphs-gtk.c (xbm_instantiate_1):
* glyphs-gtk.c (gtk_xbm_instantiate):
* glyphs-gtk.c (gtk_xpm_instantiate):
* glyphs-gtk.c (gtk_xface_instantiate):
* glyphs-gtk.c (cursor_font_instantiate):
* glyphs-gtk.c (gtk_redisplay_widget):
* glyphs-gtk.c (gtk_widget_instantiate_1):
* glyphs-gtk.c (gtk_add_tab_item):
* glyphs-msw.c (mswindows_xpm_instantiate):
* glyphs-msw.c (bmp_instantiate):
* glyphs-msw.c (mswindows_resource_instantiate):
* glyphs-msw.c (xbm_instantiate_1):
* glyphs-msw.c (mswindows_xbm_instantiate):
* glyphs-msw.c (mswindows_xface_instantiate):
* glyphs-msw.c (mswindows_redisplay_widget):
* glyphs-msw.c (mswindows_widget_instantiate):
* glyphs-msw.c (add_tree_item):
* glyphs-msw.c (add_tab_item):
* glyphs-msw.c (mswindows_combo_box_instantiate):
* glyphs-msw.c (mswindows_widget_query_string_geometry):
* glyphs-x.c (x_locate_pixmap_file):
* glyphs-x.c (xbm_instantiate_1):
* glyphs-x.c (x_xbm_instantiate):
* glyphs-x.c (extract_xpm_color_names):
* glyphs-x.c (x_xpm_instantiate):
* glyphs-x.c (x_xface_instantiate):
* glyphs-x.c (autodetect_instantiate):
* glyphs-x.c (safe_XLoadFont):
* glyphs-x.c (cursor_font_instantiate):
* glyphs-x.c (x_redisplay_widget):
* glyphs-x.c (Fchange_subwindow_property):
* glyphs-x.c (x_widget_instantiate):
* glyphs-x.c (x_tab_control_redisplay):
* glyphs.c (pixmap_to_lisp_data):
* gui-x.c (menu_separator_style_and_to_external):
* gui-x.c (add_accel_and_to_external):
* gui-x.c (button_item_to_widget_value):
* hpplay.c (player_error_internal):
* hpplay.c (play_sound_file):
* hpplay.c (play_sound_data):
* intl.c (Fset_current_locale):
* lisp.h:
* menubar-gtk.c (gtk_xemacs_set_accel_keys):
* menubar-msw.c (populate_menu_add_item):
* menubar-msw.c (populate_or_checksum_helper):
* menubar-x.c (menu_item_descriptor_to_widget_value_1):
* nt.c (init_user_info):
* nt.c (get_long_basename):
* nt.c (nt_get_resource):
* nt.c (init_mswindows_environment):
* nt.c (get_cached_volume_information):
* nt.c (mswindows_readdir):
* nt.c (read_unc_volume):
* nt.c (mswindows_stat):
* nt.c (mswindows_getdcwd):
* nt.c (mswindows_executable_type):
* nt.c (Fmswindows_short_file_name):
* ntplay.c (nt_play_sound_file):
* objects-gtk.c:
* objects-gtk.c (gtk_valid_color_name_p):
* objects-gtk.c (gtk_initialize_font_instance):
* objects-gtk.c (gtk_font_list):
* objects-msw.c (font_enum_callback_2):
* objects-msw.c (parse_font_spec):
* objects-x.c (x_parse_nearest_color):
* objects-x.c (x_valid_color_name_p):
* objects-x.c (x_initialize_font_instance):
* objects-x.c (x_font_instance_truename):
* objects-x.c (x_font_list):
* objects-xlike-inc.c (XFUN):
* objects-xlike-inc.c (xft_find_charset_font):
* process-nt.c (mswindows_report_winsock_error):
* process-nt.c (nt_create_process):
* process-nt.c (get_internet_address):
* process-nt.c (nt_open_network_stream):
* process-unix.c:
* process-unix.c (allocate_pty):
* process-unix.c (get_internet_address):
* process-unix.c (unix_canonicalize_host_name):
* process-unix.c (unix_open_network_stream):
* realpath.c:
* select-common.h (lisp_data_to_selection_data):
* select-gtk.c (symbol_to_gtk_atom):
* select-gtk.c (atom_to_symbol):
* select-msw.c (symbol_to_ms_cf):
* select-msw.c (mswindows_register_selection_data_type):
* select-x.c (symbol_to_x_atom):
* select-x.c (x_atom_to_symbol):
* select-x.c (hack_motif_clipboard_selection):
* select-x.c (Fx_store_cutbuffer_internal):
* sound.c (Fplay_sound_file):
* sound.c (Fplay_sound):
* sound.h (sound_perror):
* sysdep.c:
* sysdep.c (qxe_allocating_getcwd):
* sysdep.c (qxe_execve):
* sysdep.c (copy_in_passwd):
* sysdep.c (qxe_getpwnam):
* sysdep.c (qxe_ctime):
* sysdll.c (dll_open):
* sysdll.c (dll_function):
* sysdll.c (dll_variable):
* sysdll.c (search_linked_libs):
* sysdll.c (dll_error):
* sysfile.h:
* sysfile.h (PATHNAME_CONVERT_OUT_TSTR):
* sysfile.h (PATHNAME_CONVERT_OUT_UTF_8):
* sysfile.h (PATHNAME_CONVERT_OUT):
* sysfile.h (LISP_PATHNAME_CONVERT_OUT):
* syswindows.h (ITEXT_TO_TSTR):
* syswindows.h (LOCAL_FILE_FORMAT_TO_TSTR):
* syswindows.h (TSTR_TO_LOCAL_FILE_FORMAT):
* syswindows.h (LOCAL_FILE_FORMAT_TO_INTERNAL_MSWIN):
* syswindows.h (LISP_LOCAL_FILE_FORMAT_MAYBE_URL_TO_TSTR):
* text.h:
* text.h (eicpy_ext_len):
* text.h (enum new_dfc_src_type):
* text.h (EXTERNAL_TO_ITEXT):
* text.h (GET_STRERROR):
* tooltalk.c (check_status):
* tooltalk.c (Fadd_tooltalk_message_arg):
* tooltalk.c (Fadd_tooltalk_pattern_attribute):
* tooltalk.c (Fadd_tooltalk_pattern_arg):
* win32.c (tstr_to_local_file_format):
* win32.c (mswindows_lisp_error_1):
* win32.c (mswindows_report_process_error):
* win32.c (Fmswindows_shell_execute):
* win32.c (mswindows_read_link_1):
Changes involving external/internal format conversion,
mostly code cleanup and renaming.
1. Eliminate the previous macros like LISP_STRING_TO_EXTERNAL
that stored its result in a parameter. The new version of
LISP_STRING_TO_EXTERNAL returns its result through the
return value, same as the previous NEW_LISP_STRING_TO_EXTERNAL.
Use the new-style macros throughout the code.
2. Rename C_STRING_TO_EXTERNAL and friends to ITEXT_TO_EXTERNAL,
in keeping with overall naming rationalization involving
Itext and related types.
Macros involved in previous two:
EXTERNAL_TO_C_STRING -> EXTERNAL_TO_ITEXT
EXTERNAL_TO_C_STRING_MALLOC -> EXTERNAL_TO_ITEXT_MALLOC
SIZED_EXTERNAL_TO_C_STRING -> SIZED_EXTERNAL_TO_ITEXT
SIZED_EXTERNAL_TO_C_STRING_MALLOC -> SIZED_EXTERNAL_TO_ITEXT_MALLOC
C_STRING_TO_EXTERNAL -> ITEXT_TO_EXTERNAL
C_STRING_TO_EXTERNAL_MALLOC -> ITEXT_TO_EXTERNAL_MALLOC
LISP_STRING_TO_EXTERNAL
LISP_STRING_TO_EXTERNAL_MALLOC
LISP_STRING_TO_TSTR
C_STRING_TO_TSTR -> ITEXT_TO_TSTR
TSTR_TO_C_STRING -> TSTR_TO_ITEXT
The following four still return their values through parameters,
since they have more than one value to return:
C_STRING_TO_SIZED_EXTERNAL -> ITEXT_TO_SIZED_EXTERNAL
LISP_STRING_TO_SIZED_EXTERNAL
C_STRING_TO_SIZED_EXTERNAL_MALLOC -> ITEXT_TO_SIZED_EXTERNAL_MALLOC
LISP_STRING_TO_SIZED_EXTERNAL_MALLOC
Sometimes additional casts had to be inserted, since the old
macros played strange games and completely defeated the type system
of the store params.
3. Rewrite many places where direct calls to TO_EXTERNAL_FORMAT
occurred with calls to one of the convenience macros listed above,
or to make_extstring().
4. Eliminate SIZED_C_STRING macros (they were hardly used, anyway)
and use a direct call to TO_EXTERNAL_FORMAT or TO_INTERNAL_FORMAT.
4. Use LISP_PATHNAME_CONVERT_OUT in many places instead of something
like LISP_STRING_TO_EXTERNAL(..., Qfile_name).
5. Eliminate some temporary variables that are no longer necessary
now that we return a value rather than storing it into a variable.
6. Some Mule-izing in database.c.
7. Error functions:
-- A bit of code cleanup in maybe_signal_error_1.
-- Eliminate report_file_type_error; it's just an alias for
signal_error_2 with params in a different order.
-- Fix some places in the hostname-handling code that directly
inserted externally-retrieved error strings into the
supposed ASCII "reason" param instead of doing the right thing
and sticking text descriptive of what was going on in "reason"
and putting the external message in a frob.
8. Use Ascbyte instead of CIbyte in process-unix.c and maybe one
or two other places.
9. Some code cleanup in copy_in_passwd() in sysdep.c.
10. Fix a real bug due to accidental variable shadowing in
tstr_to_local_file_format() in win32.c.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Fri, 05 Feb 2010 11:02:24 -0600 |
parents | 8f1ee2d15784 |
children | ae48681c47fa |
rev | line source |
---|---|
2081 | 1 /* Implements an elisp-programmable menubar -- Gtk interface. |
462 | 2 Copyright (C) 1993, 1994 Free Software Foundation, Inc. |
3 Copyright (C) 1995 Tinker Systems and INS Engineering Corp. | |
1346 | 4 Copyright (C) 2002, 2003 Ben Wing. |
462 | 5 |
6 This file is part of XEmacs. | |
7 | |
8 XEmacs is free software; you can redistribute it and/or modify it | |
9 under the terms of the GNU General Public License as published by the | |
10 Free Software Foundation; either version 2, or (at your option) any | |
11 later version. | |
12 | |
13 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 for more details. | |
17 | |
18 You should have received a copy of the GNU General Public License | |
19 along with XEmacs; see the file COPYING. If not, write to | |
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
21 Boston, MA 02111-1307, USA. */ | |
22 | |
23 /* Synched up with: Not in FSF. */ | |
24 | |
25 /* created 16-dec-91 by jwz */ | |
26 | |
27 #include <config.h> | |
28 #include "lisp.h" | |
29 | |
30 #include "buffer.h" | |
31 #include "commands.h" /* zmacs_regions */ | |
1346 | 32 #include "device-impl.h" |
462 | 33 #include "events.h" |
872 | 34 #include "frame-impl.h" |
35 #include "gui.h" | |
462 | 36 #include "opaque.h" |
37 #include "window.h" | |
876 | 38 #include "window-impl.h" |
462 | 39 |
872 | 40 #include "console-gtk-impl.h" |
41 #include "ui-gtk.h" | |
876 | 42 #include "menubar.h" |
872 | 43 |
462 | 44 #ifdef HAVE_GNOME |
45 #include <libgnomeui/libgnomeui.h> | |
46 #endif | |
47 | |
48 #define MENUBAR_TYPE 0 | |
49 #define SUBMENU_TYPE 1 | |
50 #define POPUP_TYPE 2 | |
51 | |
2081 | 52 static GtkWidget *menu_descriptor_to_widget_1 (Lisp_Object descr, GtkAccelGroup* accel_group); |
462 | 53 |
1346 | 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)) | |
56 #define XFRAME_GTK_MENUBAR_DATA_UPTODATE(f) XCDR (FRAME_GTK_MENUBAR_DATA (f)) | |
462 | 57 |
58 | |
59 /* This is a bogus subclass of GtkMenuBar so that the menu never tries | |
60 ** to be bigger than the text widget. This prevents weird resizing | |
61 ** when jumping around between buffers with radically different menu | |
62 ** sizes. | |
63 */ | |
64 | |
65 #define GTK_XEMACS_MENUBAR(obj) GTK_CHECK_CAST (obj, gtk_xemacs_menubar_get_type (), GtkXEmacsMenubar) | |
66 #define GTK_XEMACS_MENUBAR_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_xemacs_menubar_get_type (), GtkXEmacsMenubarClass) | |
67 #define GTK_IS_XEMACS_MENUBAR(obj) GTK_CHECK_TYPE (obj, gtk_xemacs_menubar_get_type ()) | |
68 #define GTK_XEMACS_MENUBAR_FRAME(obj) GTK_XEMACS_MENUBAR (obj)->f | |
69 | |
70 typedef struct _GtkXEmacsMenubar GtkXEmacsMenubar; | |
71 typedef struct _GtkXEmacsMenubarClass GtkXEmacsMenubarClass; | |
72 | |
73 struct _GtkXEmacsMenubar | |
74 { | |
75 GtkMenuBar menu; | |
76 struct frame *frame; | |
77 }; | |
78 | |
79 struct _GtkXEmacsMenubarClass | |
80 { | |
81 GtkMenuBarClass parent_class; | |
82 }; | |
83 | |
84 guint gtk_xemacs_menubar_get_type (void); | |
85 GtkWidget *gtk_xemacs_menubar_new (struct frame *f); | |
86 | |
87 static void gtk_xemacs_menubar_class_init (GtkXEmacsMenubarClass *klass); | |
88 static void gtk_xemacs_menubar_init (GtkXEmacsMenubar *xemacs); | |
89 static void gtk_xemacs_menubar_size_request (GtkWidget *widget, GtkRequisition *requisition); | |
90 | |
91 guint | |
92 gtk_xemacs_menubar_get_type (void) | |
93 { | |
94 static guint xemacs_menubar_type; | |
95 | |
96 if (!xemacs_menubar_type) | |
97 { | |
98 static const GtkTypeInfo xemacs_menubar_info = | |
99 { | |
100 "GtkXEmacsMenubar", | |
101 sizeof (GtkXEmacsMenubar), | |
102 sizeof (GtkXEmacsMenubarClass), | |
103 (GtkClassInitFunc) gtk_xemacs_menubar_class_init, | |
104 (GtkObjectInitFunc) gtk_xemacs_menubar_init, | |
105 /* reserved_1 */ NULL, | |
106 /* reserved_2 */ NULL, | |
107 (GtkClassInitFunc) NULL, | |
108 }; | |
109 | |
110 xemacs_menubar_type = gtk_type_unique (gtk_menu_bar_get_type (), &xemacs_menubar_info); | |
111 } | |
112 | |
113 return xemacs_menubar_type; | |
114 } | |
115 | |
2081 | 116 static GtkWidgetClass *menubar_parent_class; |
462 | 117 |
1416 | 118 static void |
119 gtk_xemacs_menubar_class_init (GtkXEmacsMenubarClass *klass) | |
462 | 120 { |
121 GtkWidgetClass *widget_class; | |
122 | |
123 widget_class = (GtkWidgetClass*) klass; | |
2081 | 124 menubar_parent_class = (GtkWidgetClass *) gtk_type_class (gtk_menu_bar_get_type ()); |
462 | 125 |
126 widget_class->size_request = gtk_xemacs_menubar_size_request; | |
127 } | |
128 | |
1416 | 129 static void |
2286 | 130 gtk_xemacs_menubar_init (GtkXEmacsMenubar *UNUSED (xemacs)) |
462 | 131 { |
132 } | |
133 | |
1416 | 134 static void |
135 gtk_xemacs_menubar_size_request (GtkWidget *widget, GtkRequisition *requisition) | |
462 | 136 { |
137 GtkXEmacsMenubar *x = GTK_XEMACS_MENUBAR (widget); | |
138 GtkRequisition frame_size; | |
139 | |
2081 | 140 menubar_parent_class->size_request (widget, requisition); |
462 | 141 |
142 /* #### BILL! | |
143 ** We should really only do this if the menu has not been detached! | |
144 ** | |
145 ** WMP 9/9/2000 | |
146 */ | |
147 | |
148 gtk_widget_size_request (FRAME_GTK_TEXT_WIDGET (x->frame), &frame_size); | |
149 | |
150 requisition->width = frame_size.width; | |
151 } | |
152 | |
153 GtkWidget * | |
154 gtk_xemacs_menubar_new (struct frame *f) | |
155 { | |
2054 | 156 GtkXEmacsMenubar *menubar = (GtkXEmacsMenubar*) gtk_type_new (gtk_xemacs_menubar_get_type ()); |
462 | 157 |
158 menubar->frame = f; | |
159 | |
160 return (GTK_WIDGET (menubar)); | |
161 } | |
162 | |
2081 | 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 | |
2286 | 225 gtk_xemacs_accel_label_class_init(GtkXEmacsAccelLabelClass *UNUSED (klass)) |
2081 | 226 { |
227 /* Nothing to do. */ | |
228 } | |
229 | |
230 static void | |
2286 | 231 gtk_xemacs_accel_label_init(GtkXEmacsAccelLabel *UNUSED (xemacs)) |
2081 | 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 { | |
4981
4aebb0131297
Cleanups/renaming of EXTERNAL_TO_C_STRING and friends
Ben Wing <ben@xemacs.org>
parents:
4677
diff
changeset
|
263 l->label.accel_string = ITEXT_TO_EXTERNAL_MALLOC (XSTRING_DATA (keys), Qctext); |
2081 | 264 } |
265 else | |
266 { | |
267 /* l->label.accel_string = NULL;*/ | |
268 } | |
269 } | |
270 | |
271 | |
462 | 272 /* We now return you to your regularly scheduled menus... */ |
273 | |
274 int dockable_menubar; | |
275 | |
276 /* #define TEAR_OFF_MENUS */ | |
277 | |
278 #ifdef TEAR_OFF_MENUS | |
279 int tear_off_menus; | |
280 #endif | |
281 | |
282 | |
283 /* Converting from XEmacs to GTK representation */ | |
284 static Lisp_Object | |
2054 | 285 menu_name_to_accelerator (Ibyte *name) |
462 | 286 { |
287 while (*name) { | |
288 if (*name=='%') { | |
289 ++name; | |
290 if (!(*name)) | |
291 return Qnil; | |
292 if (*name=='_' && *(name+1)) | |
293 { | |
2054 | 294 int accelerator = (int) (*(name+1)); |
462 | 295 return make_char (tolower (accelerator)); |
296 } | |
297 } | |
298 ++name; | |
299 } | |
300 return Qnil; | |
301 } | |
302 | |
303 #define XEMACS_MENU_DESCR_TAG "xemacs::menu::description" | |
304 #define XEMACS_MENU_FILTER_TAG "xemacs::menu::filter" | |
305 #define XEMACS_MENU_GUIID_TAG "xemacs::menu::gui_id" | |
306 #define XEMACS_MENU_FIRSTTIME_TAG "xemacs::menu::first_time" | |
307 | |
308 static void __activate_menu(GtkMenuItem *, gpointer); | |
309 | |
310 #ifdef TEAR_OFF_MENUS | |
311 static void | |
2286 | 312 __torn_off_sir(GtkMenuItem *UNUSED (item), gpointer user_data) |
462 | 313 { |
314 GtkWidget *menu_item = GTK_WIDGET (user_data); | |
315 | |
316 if (GTK_TEAROFF_MENU_ITEM (item)->torn_off) | |
317 { | |
318 /* Menu was just torn off */ | |
319 GUI_ID id = new_gui_id (); | |
320 Lisp_Object menu_desc = Qnil; | |
321 GtkWidget *old_submenu = GTK_MENU_ITEM (menu_item)->submenu; | |
322 | |
826 | 323 menu_desc = VOID_TO_LISP (gtk_object_get_data (GTK_OBJECT (menu_item), XEMACS_MENU_DESCR_TAG)); |
462 | 324 |
325 /* GCPRO all of our very own */ | |
326 gcpro_popup_callbacks (id, menu_desc); | |
327 | |
328 /* Hide the now detached menu from the attentions of | |
329 __activate_menu destroying the old submenu */ | |
330 #if 0 | |
331 gtk_widget_ref (old_submenu); | |
332 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), gtk_menu_new ()); | |
333 gtk_widget_show_all (old_submenu); | |
334 #endif | |
335 } | |
336 } | |
337 #endif | |
338 | |
339 /* This is called when a menu is about to be shown... this is what | |
340 does the delayed creation of the menu items. We populate the | |
341 submenu and away we go. */ | |
342 static void | |
2286 | 343 __maybe_destroy (GtkWidget *child, GtkWidget *UNUSED (precious)) |
462 | 344 { |
345 if (GTK_IS_MENU_ITEM (child) && !GTK_IS_TEAROFF_MENU_ITEM (child)) | |
346 { | |
347 if (GTK_WIDGET_VISIBLE (child)) | |
348 { | |
349 /* If we delete the menu item that was 'active' when the | |
350 menu was cancelled, GTK gets upset because it tries to | |
351 remove the focus rectangle from a (now) dead widget. | |
352 | |
353 This widget will eventually get killed because it will | |
354 not be visible the next time the window is shown. | |
355 */ | |
356 gtk_widget_set_sensitive (child, FALSE); | |
357 gtk_widget_hide_all (child); | |
358 } | |
359 else | |
360 { | |
361 gtk_widget_destroy (child); | |
362 } | |
363 } | |
364 } | |
365 | |
366 /* If user_data != 0x00 then we are using a hook to build the menu. */ | |
367 static void | |
368 __activate_menu(GtkMenuItem *item, gpointer user_data) | |
369 { | |
370 Lisp_Object desc; | |
371 gpointer force_clear = gtk_object_get_data (GTK_OBJECT (item), XEMACS_MENU_FIRSTTIME_TAG); | |
372 | |
373 gtk_object_set_data (GTK_OBJECT (item), XEMACS_MENU_FIRSTTIME_TAG, 0x00); | |
374 | |
375 /* Delete the old contents of the menu if we are the top level menubar */ | |
376 if (GTK_IS_MENU_BAR (GTK_WIDGET (item)->parent) || force_clear) | |
377 { | |
378 GtkWidget *selected = gtk_menu_get_active (GTK_MENU (item->submenu)); | |
379 | |
380 gtk_container_foreach (GTK_CONTAINER (item->submenu),(GtkCallback) __maybe_destroy, | |
381 selected); | |
382 } | |
383 else if (gtk_container_children (GTK_CONTAINER (item->submenu))) | |
384 { | |
385 return; | |
386 } | |
387 | |
826 | 388 desc = VOID_TO_LISP (gtk_object_get_data (GTK_OBJECT (item), XEMACS_MENU_DESCR_TAG)); |
462 | 389 |
390 #ifdef TEAR_OFF_MENUS | |
391 /* Lets stick in a detacher just for giggles */ | |
392 if (tear_off_menus && !gtk_container_children (GTK_CONTAINER (item->submenu))) | |
393 { | |
394 GtkWidget *w = gtk_tearoff_menu_item_new (); | |
395 gtk_widget_show (w); | |
396 gtk_menu_append (GTK_MENU (item->submenu), w); | |
397 gtk_signal_connect (GTK_OBJECT (w), "activate", GTK_SIGNAL_FUNC (__torn_off_sir), item); | |
398 } | |
399 #endif | |
400 | |
401 if (user_data) | |
402 { | |
403 GUI_ID id = (GUI_ID) gtk_object_get_data (GTK_OBJECT (item), XEMACS_MENU_GUIID_TAG); | |
404 Lisp_Object hook_fn; | |
405 struct gcpro gcpro1, gcpro2; | |
406 | |
826 | 407 hook_fn = VOID_TO_LISP (gtk_object_get_data (GTK_OBJECT (item), XEMACS_MENU_FILTER_TAG)); |
462 | 408 |
409 GCPRO2 (desc, hook_fn); | |
410 | |
411 desc = call1 (hook_fn, desc); | |
412 | |
413 UNGCPRO; | |
414 | |
415 ungcpro_popup_callbacks (id); | |
416 gcpro_popup_callbacks (id, desc); | |
417 } | |
418 | |
419 /* Build the child widgets */ | |
420 for (; !NILP (desc); desc = Fcdr (desc)) | |
421 { | |
422 GtkWidget *next = NULL; | |
423 Lisp_Object child = Fcar (desc); | |
424 | |
425 if (NILP (child)) /* the partition */ | |
426 { | |
427 /* Signal an error here? The NILP handling is handled a | |
428 layer higher where appropriate */ | |
429 } | |
430 else | |
431 { | |
2081 | 432 next = menu_descriptor_to_widget_1 (child, |
433 gtk_menu_ensure_uline_accel_group (GTK_MENU (item->submenu))); | |
462 | 434 } |
435 | |
436 if (!next) | |
437 { | |
438 continue; | |
439 } | |
440 | |
441 gtk_widget_show_all (next); | |
442 gtk_menu_append (GTK_MENU (item->submenu), next); | |
443 } | |
444 } | |
445 | |
446 /* This is called whenever an item with a GUI_ID associated with it is | |
447 destroyed. This allows us to remove the references in gui-gtk.c | |
448 that made sure callbacks and such were GCPRO-ed | |
449 */ | |
450 static void | |
451 __remove_gcpro_by_id (gpointer user_data) | |
452 { | |
453 ungcpro_popup_callbacks ((GUI_ID) user_data); | |
454 } | |
455 | |
456 static void | |
2286 | 457 __kill_stupid_gtk_timer (GtkObject *obj, gpointer UNUSED (user_data)) |
462 | 458 { |
459 GtkMenuItem *mi = GTK_MENU_ITEM (obj); | |
460 | |
461 if (mi->timer) | |
462 { | |
463 gtk_timeout_remove (mi->timer); | |
464 mi->timer = 0; | |
465 } | |
466 } | |
467 | |
2081 | 468 /* Convert the XEmacs menu accelerator representation to Gtk mnemonic form. If |
469 no accelerator has been provided, put one at the start of the string (this | |
470 mirrors the behaviour under X). This algorithm is also found in | |
471 dialog-gtk.el:gtk-popup-convert-underscores. | |
472 */ | |
462 | 473 static char * |
2081 | 474 convert_underscores(const Ibyte *name) |
462 | 475 { |
2081 | 476 char *rval; |
477 int i,j; | |
478 int found_accel = FALSE; | |
479 int underscores = 0; | |
480 | |
481 for (i = 0; name[i]; ++i) | |
482 if (name[i] == '%' && name[i+1] == '_') | |
483 { | |
484 found_accel = TRUE; | |
485 } | |
486 else if (name[i] == '_') | |
487 { | |
488 underscores++; | |
489 } | |
490 | |
491 /* Allocate space for the original string, plus zero byte plus extra space | |
492 for all quoted underscores plus possible additional leading accelerator. */ | |
493 rval = (char*) xmalloc_and_zero (qxestrlen(name) + 1 + underscores | |
494 + (found_accel ? 0 : 1)); | |
495 | |
496 if (!found_accel) | |
497 rval[0] = '_'; | |
498 | |
499 for (i = 0, j = (found_accel ? 0 : 1); name[i]; i++) | |
500 { | |
501 if (name[i]=='%') | |
502 { | |
503 i++; | |
504 if (!(name[i])) | |
505 continue; | |
506 | |
507 if ((name[i] != '_') && (name[i] != '%')) | |
508 i--; | |
509 | |
510 found_accel = TRUE; | |
511 } | |
512 else if (name[i] == '_') | |
513 { | |
514 rval[j++] = '_'; | |
515 } | |
516 | |
517 rval[j++] = name[i]; | |
518 } | |
519 | |
520 return rval; | |
521 } | |
522 | |
523 /* Remove the XEmacs menu accellerator representation from a string. */ | |
524 static char * | |
525 remove_underscores(const Ibyte *name) | |
526 { | |
527 char *rval = (char*) xmalloc_and_zero (qxestrlen(name) + 1); | |
462 | 528 int i,j; |
529 | |
530 for (i = 0, j = 0; name[i]; i++) | |
531 { | |
532 if (name[i]=='%') { | |
533 i++; | |
534 if (!(name[i])) | |
535 continue; | |
536 | |
2081 | 537 if ((name[i] != '_') && (name[i] != '%')) |
538 i--; | |
539 else | |
462 | 540 continue; |
541 } | |
542 rval[j++] = name[i]; | |
543 } | |
544 return rval; | |
545 } | |
546 | |
547 /* This converts an entire menu into a GtkMenuItem (with an attached | |
548 submenu). A menu is a list of (STRING [:keyword value]+ [DESCR]+) | |
549 DESCR is either a list (meaning a submenu), a vector, or nil (if | |
550 you include a :filter keyword) */ | |
551 static GtkWidget * | |
2081 | 552 menu_convert (Lisp_Object desc, GtkWidget *reuse, |
553 GtkAccelGroup* menubar_accel_group) | |
462 | 554 { |
555 GtkWidget *menu_item = NULL; | |
556 GtkWidget *submenu = NULL; | |
557 Lisp_Object key, val; | |
558 Lisp_Object include_p = Qnil, hook_fn = Qnil, config_tag = Qnil; | |
559 Lisp_Object active_p = Qt; | |
560 Lisp_Object accel; | |
561 int included_spec = 0; | |
562 int active_spec = 0; | |
563 | |
564 if (STRINGP (XCAR (desc))) | |
565 { | |
566 accel = menu_name_to_accelerator (XSTRING_DATA (XCAR (desc))); | |
567 | |
568 if (!reuse) | |
569 { | |
2081 | 570 char *temp_menu_name = convert_underscores (XSTRING_DATA (XCAR (desc))); |
571 GtkWidget* accel_label = gtk_xemacs_accel_label_new(NULL); | |
572 guint accel_key; | |
573 | |
574 gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5); | |
575 accel_key = gtk_label_parse_uline (GTK_LABEL (accel_label), temp_menu_name); | |
576 | |
577 menu_item = gtk_menu_item_new (); | |
578 gtk_container_add (GTK_CONTAINER (menu_item), accel_label); | |
579 gtk_widget_show (accel_label); | |
580 | |
581 if (menubar_accel_group) | |
582 gtk_widget_add_accelerator (menu_item, | |
583 "activate_item", | |
584 menubar_accel_group, | |
585 accel_key, GDK_MOD1_MASK, | |
586 GTK_ACCEL_LOCKED); | |
462 | 587 free (temp_menu_name); |
588 } | |
589 else | |
590 { | |
591 menu_item = reuse; | |
592 } | |
593 | |
594 submenu = gtk_menu_new (); | |
595 gtk_widget_show (menu_item); | |
596 gtk_widget_show (submenu); | |
597 | |
598 if (!reuse) | |
599 gtk_signal_connect (GTK_OBJECT (menu_item), "destroy", | |
600 GTK_SIGNAL_FUNC (__kill_stupid_gtk_timer), NULL); | |
601 | |
602 /* Without this sometimes a submenu gets left on the screen - | |
603 ** urk | |
604 */ | |
605 if (GTK_MENU_ITEM (menu_item)->submenu) | |
606 { | |
607 gtk_widget_destroy (GTK_MENU_ITEM (menu_item)->submenu); | |
608 } | |
609 | |
610 gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), submenu); | |
611 | |
612 /* We put this bogus menu item in so that GTK does the right | |
613 ** thing when the menu is near the screen border. | |
614 ** | |
615 ** Aug 29, 2000 | |
616 */ | |
617 { | |
618 GtkWidget *bogus_item = gtk_menu_item_new_with_label ("A suitably long label here..."); | |
619 | |
620 gtk_object_set_data (GTK_OBJECT (menu_item), XEMACS_MENU_FIRSTTIME_TAG, (gpointer)0x01); | |
621 gtk_widget_show_all (bogus_item); | |
622 gtk_menu_append (GTK_MENU (submenu), bogus_item); | |
623 } | |
624 | |
625 desc = Fcdr (desc); | |
626 | |
627 while (key = Fcar (desc), KEYWORDP (key)) | |
628 { | |
629 Lisp_Object cascade = desc; | |
630 desc = Fcdr (desc); | |
631 if (NILP (desc)) | |
563 | 632 sferror ("keyword in menu lacks a value", |
462 | 633 cascade); |
634 val = Fcar (desc); | |
635 desc = Fcdr (desc); | |
636 if (EQ (key, Q_included)) | |
637 include_p = val, included_spec = 1; | |
638 else if (EQ (key, Q_config)) | |
639 config_tag = val; | |
640 else if (EQ (key, Q_filter)) | |
641 hook_fn = val; | |
642 else if (EQ (key, Q_active)) | |
643 active_p = val, active_spec = 1; | |
644 else if (EQ (key, Q_accelerator)) | |
645 { | |
646 #if 0 | |
647 if ( SYMBOLP (val) | |
648 || CHARP (val)) | |
649 wv->accel = LISP_TO_VOID (val); | |
650 else | |
563 | 651 invalid_argument ("bad keyboard accelerator", val); |
462 | 652 #endif |
653 } | |
654 else if (EQ (key, Q_label)) | |
655 { | |
656 /* implement in 21.2 */ | |
657 } | |
658 else | |
563 | 659 invalid_argument ("unknown menu cascade keyword", cascade); |
462 | 660 } |
661 | |
662 gtk_object_set_data (GTK_OBJECT (menu_item), XEMACS_MENU_DESCR_TAG, LISP_TO_VOID (desc)); | |
663 gtk_object_set_data (GTK_OBJECT (menu_item), XEMACS_MENU_FILTER_TAG, LISP_TO_VOID (hook_fn)); | |
664 | |
665 if ((!NILP (config_tag) | |
666 && NILP (Fmemq (config_tag, Vmenubar_configuration))) | |
4677
8f1ee2d15784
Support full Common Lisp multiple values in C.
Aidan Kehoe <kehoea@parhasard.net>
parents:
2500
diff
changeset
|
667 || (included_spec && |
8f1ee2d15784
Support full Common Lisp multiple values in C.
Aidan Kehoe <kehoea@parhasard.net>
parents:
2500
diff
changeset
|
668 NILP (IGNORE_MULTIPLE_VALUES (Feval (include_p))))) |
462 | 669 { |
670 return (NULL); | |
671 } | |
672 | |
673 if (active_spec) | |
4677
8f1ee2d15784
Support full Common Lisp multiple values in C.
Aidan Kehoe <kehoea@parhasard.net>
parents:
2500
diff
changeset
|
674 active_p = IGNORE_MULTIPLE_VALUES (Feval (active_p)); |
462 | 675 |
676 gtk_widget_set_sensitive (GTK_WIDGET (menu_item), ! NILP (active_p)); | |
677 } | |
678 else | |
679 { | |
563 | 680 invalid_argument ("menu name (first element) must be a string", |
462 | 681 desc); |
682 } | |
683 | |
684 /* If we are reusing a widget, we need to make sure we clean | |
685 ** everything up. | |
686 */ | |
687 if (reuse) | |
688 { | |
689 gpointer id = gtk_object_get_data (GTK_OBJECT (reuse), XEMACS_MENU_GUIID_TAG); | |
690 | |
691 if (id) | |
692 { | |
693 /* If the menu item had a GUI_ID that means it was a filter menu */ | |
694 __remove_gcpro_by_id (id); | |
695 gtk_signal_disconnect_by_func (GTK_OBJECT (reuse), | |
696 GTK_SIGNAL_FUNC (__activate_menu), | |
697 (gpointer) 0x01 ); | |
698 } | |
699 else | |
700 { | |
701 gtk_signal_disconnect_by_func (GTK_OBJECT (reuse), | |
702 GTK_SIGNAL_FUNC (__activate_menu), | |
703 NULL); | |
704 } | |
705 | |
706 GTK_MENU_ITEM (reuse)->right_justify = 0; | |
707 } | |
708 | |
709 if (NILP (hook_fn)) | |
710 { | |
711 /* Generic menu builder */ | |
712 gtk_signal_connect (GTK_OBJECT (menu_item), "activate", | |
713 GTK_SIGNAL_FUNC (__activate_menu), | |
714 NULL); | |
715 } | |
716 else | |
717 { | |
718 GUI_ID id = new_gui_id (); | |
719 | |
720 gtk_object_set_data (GTK_OBJECT (menu_item), XEMACS_MENU_GUIID_TAG, | |
721 (gpointer) id); | |
722 | |
723 /* Make sure we gcpro the menu descriptions */ | |
724 gcpro_popup_callbacks (id, desc); | |
725 gtk_object_weakref (GTK_OBJECT (menu_item), __remove_gcpro_by_id, | |
726 (gpointer) id); | |
727 | |
728 gtk_signal_connect (GTK_OBJECT (menu_item), "activate", | |
729 GTK_SIGNAL_FUNC (__activate_menu), | |
730 (gpointer) 0x01); | |
731 } | |
732 | |
733 return (menu_item); | |
734 } | |
735 | |
736 /* Called whenever a button, radio, or toggle is selected in the menu */ | |
737 static void | |
738 __generic_button_callback (GtkMenuItem *item, gpointer user_data) | |
739 { | |
740 Lisp_Object callback, function, data, channel; | |
741 | |
2168 | 742 channel = wrap_frame (gtk_widget_to_frame (GTK_WIDGET (item))); |
462 | 743 |
826 | 744 callback = VOID_TO_LISP (user_data); |
462 | 745 |
746 get_gui_callback (callback, &function, &data); | |
747 | |
748 signal_special_gtk_user_event (channel, function, data); | |
749 } | |
750 | |
751 /* Convert a single menu item descriptor to a suitable GtkMenuItem */ | |
752 /* This function cannot GC. | |
753 It is only called from menu_item_descriptor_to_widget_value, which | |
754 prohibits GC. */ | |
1416 | 755 static GtkWidget * |
2081 | 756 menu_descriptor_to_widget_1 (Lisp_Object descr, GtkAccelGroup* accel_group) |
462 | 757 { |
758 if (STRINGP (descr)) | |
759 { | |
760 /* It is a separator. Unfortunately GTK does not allow us to | |
761 specify what our separators look like, so we can't do all the | |
762 fancy stuff that the X code does. | |
763 */ | |
764 return (gtk_menu_item_new ()); | |
765 } | |
766 else if (LISTP (descr)) | |
767 { | |
768 /* It is a submenu */ | |
2081 | 769 return (menu_convert (descr, NULL, accel_group)); |
462 | 770 } |
771 else if (VECTORP (descr)) | |
772 { | |
773 /* An actual menu item description! This gets yucky. */ | |
774 Lisp_Object name = Qnil; | |
775 Lisp_Object callback = Qnil; | |
776 Lisp_Object suffix = Qnil; | |
777 Lisp_Object active_p = Qt; | |
778 Lisp_Object include_p = Qt; | |
779 Lisp_Object selected_p = Qnil; | |
780 Lisp_Object keys = Qnil; | |
781 Lisp_Object style = Qnil; | |
782 Lisp_Object config_tag = Qnil; | |
783 Lisp_Object accel = Qnil; | |
784 GtkWidget *main_label = NULL; | |
785 int length = XVECTOR_LENGTH (descr); | |
786 Lisp_Object *contents = XVECTOR_DATA (descr); | |
787 int plist_p; | |
788 int selected_spec = 0, included_spec = 0; | |
789 GtkWidget *widget = NULL; | |
2081 | 790 guint accel_key; |
462 | 791 |
792 if (length < 2) | |
563 | 793 sferror ("button descriptors must be at least 2 long", descr); |
462 | 794 |
795 /* length 2: [ "name" callback ] | |
796 length 3: [ "name" callback active-p ] | |
797 length 4: [ "name" callback active-p suffix ] | |
798 or [ "name" callback keyword value ] | |
799 length 5+: [ "name" callback [ keyword value ]+ ] | |
800 */ | |
801 plist_p = (length >= 5 || (length > 2 && KEYWORDP (contents [2]))); | |
802 | |
803 if (!plist_p && length > 2) | |
804 /* the old way */ | |
805 { | |
806 name = contents [0]; | |
807 callback = contents [1]; | |
808 active_p = contents [2]; | |
809 if (length == 4) | |
810 suffix = contents [3]; | |
811 } | |
812 else | |
813 { | |
814 /* the new way */ | |
815 int i; | |
816 if (length & 1) | |
563 | 817 sferror ( |
462 | 818 "button descriptor has an odd number of keywords and values", |
819 descr); | |
820 | |
821 name = contents [0]; | |
822 callback = contents [1]; | |
823 for (i = 2; i < length;) | |
824 { | |
825 Lisp_Object key = contents [i++]; | |
826 Lisp_Object val = contents [i++]; | |
827 if (!KEYWORDP (key)) | |
563 | 828 invalid_argument_2 ("not a keyword", key, descr); |
462 | 829 |
830 if (EQ (key, Q_active)) active_p = val; | |
831 else if (EQ (key, Q_suffix)) suffix = val; | |
832 else if (EQ (key, Q_keys)) keys = val; | |
833 else if (EQ (key, Q_key_sequence)) ; /* ignored for FSF compat */ | |
834 else if (EQ (key, Q_label)) ; /* implement for 21.0 */ | |
835 else if (EQ (key, Q_style)) style = val; | |
836 else if (EQ (key, Q_selected)) selected_p = val, selected_spec = 1; | |
837 else if (EQ (key, Q_included)) include_p = val, included_spec = 1; | |
838 else if (EQ (key, Q_config)) config_tag = val; | |
839 else if (EQ (key, Q_accelerator)) | |
840 { | |
841 if ( SYMBOLP (val) || CHARP (val)) | |
842 accel = val; | |
843 else | |
563 | 844 invalid_argument ("bad keyboard accelerator", val); |
462 | 845 } |
846 else if (EQ (key, Q_filter)) | |
563 | 847 sferror(":filter keyword not permitted on leaf nodes", descr); |
462 | 848 else |
563 | 849 invalid_argument_2 ("unknown menu item keyword", key, descr); |
462 | 850 } |
851 } | |
852 | |
853 #ifdef HAVE_MENUBARS | |
854 if ((!NILP (config_tag) && NILP (Fmemq (config_tag, Vmenubar_configuration))) | |
4677
8f1ee2d15784
Support full Common Lisp multiple values in C.
Aidan Kehoe <kehoea@parhasard.net>
parents:
2500
diff
changeset
|
855 || (included_spec && NILP (IGNORE_MULTIPLE_VALUES (Feval (include_p))))) |
8f1ee2d15784
Support full Common Lisp multiple values in C.
Aidan Kehoe <kehoea@parhasard.net>
parents:
2500
diff
changeset
|
856 |
462 | 857 { |
858 /* the include specification says to ignore this item. */ | |
859 return 0; | |
860 } | |
861 #endif /* HAVE_MENUBARS */ | |
862 | |
863 CHECK_STRING (name); | |
864 | |
865 if (NILP (accel)) | |
866 accel = menu_name_to_accelerator (XSTRING_DATA (name)); | |
867 | |
868 if (!NILP (suffix)) | |
4677
8f1ee2d15784
Support full Common Lisp multiple values in C.
Aidan Kehoe <kehoea@parhasard.net>
parents:
2500
diff
changeset
|
869 suffix = IGNORE_MULTIPLE_VALUES (Feval (suffix)); |
8f1ee2d15784
Support full Common Lisp multiple values in C.
Aidan Kehoe <kehoea@parhasard.net>
parents:
2500
diff
changeset
|
870 |
462 | 871 |
872 if (!separator_string_p (XSTRING_DATA (name))) | |
873 { | |
2054 | 874 Ibyte *label_buffer = NULL; |
462 | 875 char *temp_label = NULL; |
876 | |
877 if (STRINGP (suffix) && XSTRING_LENGTH (suffix)) | |
878 { | |
2367 | 879 /* !!#### */ |
880 label_buffer = alloca_ibytes (XSTRING_LENGTH (name) + 15 + XSTRING_LENGTH (suffix)); | |
881 qxesprintf (label_buffer, "%s %s ", XSTRING_DATA (name), | |
882 XSTRING_DATA (suffix)); | |
462 | 883 } |
884 else | |
885 { | |
2367 | 886 label_buffer = alloca_ibytes (XSTRING_LENGTH (name) + 15); |
887 qxesprintf (label_buffer, "%s ", XSTRING_DATA (name)); | |
462 | 888 } |
889 | |
2081 | 890 temp_label = convert_underscores (label_buffer); |
891 main_label = gtk_xemacs_accel_label_new (NULL); | |
892 accel_key = gtk_label_parse_uline (GTK_LABEL (main_label), temp_label); | |
462 | 893 free (temp_label); |
894 } | |
895 | |
896 /* Evaluate the selected and active items now */ | |
897 if (selected_spec) | |
898 { | |
899 if (NILP (selected_p) || EQ (selected_p, Qt)) | |
900 { | |
901 /* Do nothing */ | |
902 } | |
903 else | |
904 { | |
4677
8f1ee2d15784
Support full Common Lisp multiple values in C.
Aidan Kehoe <kehoea@parhasard.net>
parents:
2500
diff
changeset
|
905 selected_p = IGNORE_MULTIPLE_VALUES (Feval (selected_p)); |
462 | 906 } |
907 } | |
908 | |
909 if (NILP (active_p) || EQ (active_p, Qt)) | |
910 { | |
911 /* Do Nothing */ | |
912 } | |
913 else | |
914 { | |
4677
8f1ee2d15784
Support full Common Lisp multiple values in C.
Aidan Kehoe <kehoea@parhasard.net>
parents:
2500
diff
changeset
|
915 active_p = IGNORE_MULTIPLE_VALUES (Feval (active_p)); |
462 | 916 } |
917 | |
918 if (0 || | |
919 #ifdef HAVE_MENUBARS | |
920 menubar_show_keybindings | |
921 #endif | |
922 ) | |
923 { | |
924 /* Need to get keybindings */ | |
925 if (!NILP (keys)) | |
926 { | |
927 /* User-specified string to generate key bindings with */ | |
928 CHECK_STRING (keys); | |
929 | |
930 keys = Fsubstitute_command_keys (keys); | |
931 } | |
932 else if (SYMBOLP (callback)) | |
933 { | |
793 | 934 DECLARE_EISTRING_MALLOC (buf); |
462 | 935 |
936 /* #### Warning, dependency here on current_buffer and point */ | |
937 where_is_to_char (callback, buf); | |
938 | |
833 | 939 if (eilen (buf) > 0) |
940 keys = eimake_string (buf); | |
941 else | |
942 { | |
943 | |
944 keys = Qnil; | |
945 } | |
946 | |
793 | 947 eifree (buf); |
462 | 948 } |
949 } | |
950 | |
951 /* Now we get down to the dirty business of creating the widgets */ | |
952 if (NILP (style) || EQ (style, Qtext) || EQ (style, Qbutton)) | |
953 { | |
954 /* A normal menu item */ | |
955 widget = gtk_menu_item_new (); | |
956 } | |
957 else if (EQ (style, Qtoggle) || EQ (style, Qradio)) | |
958 { | |
959 /* They are radio or toggle buttons. | |
960 | |
961 XEmacs' menu descriptions are fairly lame in that they do | |
962 not have the idea of a 'group' of radio buttons. They | |
963 are exactly like toggle buttons except that they get | |
964 drawn differently. | |
965 | |
966 GTK rips us a new one again. If you have a radio button | |
967 in a group by itself, it always draws it as highlighted. | |
968 So we dummy up and create a second radio button that does | |
969 not get added to the menu, but gets invisibly set/unset | |
970 when the other gets unset/set. *sigh* | |
971 | |
972 */ | |
973 if (EQ (style, Qradio)) | |
974 { | |
975 GtkWidget *dummy_sibling = NULL; | |
976 GSList *group = NULL; | |
977 | |
978 dummy_sibling = gtk_radio_menu_item_new (group); | |
979 group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (dummy_sibling)); | |
980 widget = gtk_radio_menu_item_new (group); | |
981 | |
982 /* We need to notice when the 'real' one gets destroyed | |
983 so we can clean up the dummy as well. */ | |
984 gtk_object_weakref (GTK_OBJECT (widget), | |
985 (GtkDestroyNotify) gtk_widget_destroy, | |
986 dummy_sibling); | |
987 } | |
988 else | |
989 { | |
990 widget = gtk_check_menu_item_new (); | |
991 } | |
992 | |
993 /* What horrible defaults you have GTK dear! The default | |
994 for a toggle menu item is to not show the toggle unless it | |
995 is turned on or actively highlighted. How absolutely | |
996 hideous. */ | |
997 gtk_check_menu_item_set_show_toggle (GTK_CHECK_MENU_ITEM (widget), TRUE); | |
998 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (widget), | |
999 NILP (selected_p) ? FALSE : TRUE); | |
1000 } | |
1001 else | |
1002 { | |
563 | 1003 invalid_argument_2 ("unknown style", style, descr); |
462 | 1004 } |
1005 | |
1006 gtk_widget_set_sensitive (widget, ! NILP (active_p)); | |
1007 | |
1008 gtk_signal_connect (GTK_OBJECT (widget), "activate-item", | |
1009 GTK_SIGNAL_FUNC (__generic_button_callback), | |
1010 LISP_TO_VOID (callback)); | |
1011 | |
1012 gtk_signal_connect (GTK_OBJECT (widget), "activate", | |
1013 GTK_SIGNAL_FUNC (__generic_button_callback), | |
1014 LISP_TO_VOID (callback)); | |
1015 | |
2081 | 1016 /* Now that all the information about the menu item is know, set the |
1017 remaining properties. | |
462 | 1018 */ |
1019 | |
1020 if (main_label) | |
1021 { | |
1022 gtk_container_add (GTK_CONTAINER (widget), main_label); | |
1023 | |
2081 | 1024 gtk_misc_set_alignment (GTK_MISC (main_label), 0.0, 0.5); |
1025 gtk_xemacs_set_accel_keys(GTK_XEMACS_ACCEL_LABEL(main_label), keys); | |
462 | 1026 |
2081 | 1027 if (accel_group) |
1028 gtk_widget_add_accelerator (widget, | |
1029 "activate_item", | |
1030 accel_group, | |
1031 accel_key, 0, | |
1032 GTK_ACCEL_LOCKED); | |
462 | 1033 } |
1034 | |
1035 return (widget); | |
1036 } | |
1037 else | |
1038 { | |
1039 return (NULL); | |
2500 | 1040 /* ABORT (); ???? */ |
462 | 1041 } |
1042 } | |
1043 | |
1416 | 1044 static GtkWidget * |
2081 | 1045 menu_descriptor_to_widget (Lisp_Object descr, GtkAccelGroup* accel_group) |
462 | 1046 { |
1047 GtkWidget *rval = NULL; | |
771 | 1048 int count = begin_gc_forbidden (); |
462 | 1049 |
1050 /* Cannot GC from here on out... */ | |
2081 | 1051 rval = menu_descriptor_to_widget_1 (descr, accel_group); |
771 | 1052 unbind_to (count); |
462 | 1053 return (rval); |
1054 | |
1055 } | |
1056 | |
1057 static gboolean | |
2054 | 1058 menu_can_reuse_widget (GtkWidget *child, const Ibyte *label) |
462 | 1059 { |
1060 /* Everything up at the top level was done using | |
2081 | 1061 ** gtk_xemacs_accel_label_new(), but we still double check to make |
462 | 1062 ** sure we don't seriously foobar ourselves. |
1063 */ | |
2081 | 1064 gpointer possible_child = |
1065 g_list_nth_data (gtk_container_children (GTK_CONTAINER (child)), 0); | |
1066 gboolean ret_val = FALSE; | |
462 | 1067 |
1068 if (possible_child && GTK_IS_LABEL (possible_child)) | |
1069 { | |
2081 | 1070 char *temp_label = remove_underscores (label); |
1071 | |
462 | 1072 if (!strcmp (GTK_LABEL (possible_child)->label, temp_label)) |
2081 | 1073 ret_val = TRUE; |
1074 | |
1075 free (temp_label); | |
462 | 1076 } |
2081 | 1077 |
1078 return ret_val; | |
462 | 1079 } |
1080 | |
1081 /* Converts a menubar description into a GtkMenuBar... a menubar is a | |
1082 list of menus or buttons | |
1083 */ | |
1084 static void | |
1085 menu_create_menubar (struct frame *f, Lisp_Object descr) | |
1086 { | |
1087 gboolean right_justify = FALSE; | |
1088 Lisp_Object value = descr; | |
1089 GtkWidget *menubar = FRAME_GTK_MENUBAR_WIDGET (f); | |
1090 GUI_ID id = (GUI_ID) gtk_object_get_data (GTK_OBJECT (menubar), XEMACS_MENU_GUIID_TAG); | |
1091 guint menu_position = 0; | |
2081 | 1092 GtkAccelGroup *menubar_accel_group; |
462 | 1093 |
1094 /* Remove any existing protection for old menu items */ | |
1095 ungcpro_popup_callbacks (id); | |
1096 | |
1097 /* GCPRO the whole damn thing */ | |
1098 gcpro_popup_callbacks (id, descr); | |
1099 | |
2081 | 1100 menubar_accel_group = gtk_accel_group_new(); |
1101 | |
2367 | 1102 { |
1103 EXTERNAL_LIST_LOOP_2 (item_descr, value) | |
1104 { | |
1105 gpointer current_child = g_list_nth_data (GTK_MENU_SHELL (menubar)->children, menu_position); | |
462 | 1106 |
2367 | 1107 if (NILP (item_descr)) |
1108 { | |
1109 /* Need to start right-justifying menus */ | |
1110 right_justify = TRUE; | |
1111 menu_position--; | |
1112 } | |
1113 else if (VECTORP (item_descr)) | |
1114 { | |
1115 /* It is a button description */ | |
1116 GtkWidget *item; | |
462 | 1117 |
2367 | 1118 item = menu_descriptor_to_widget (item_descr, menubar_accel_group); |
1119 gtk_widget_set_name (item, "XEmacsMenuButton"); | |
1120 | |
1121 if (!item) | |
1122 { | |
1123 item = gtk_menu_item_new_with_label ("ITEM CREATION ERROR"); | |
1124 } | |
462 | 1125 |
2367 | 1126 gtk_widget_show_all (item); |
1127 if (current_child) gtk_widget_destroy (GTK_WIDGET (current_child)); | |
1128 gtk_menu_bar_insert (GTK_MENU_BAR (menubar), item, menu_position); | |
1129 } | |
1130 else if (LISTP (item_descr)) | |
1131 { | |
1132 /* Need to actually convert it into a menu and slap it in */ | |
1133 GtkWidget *widget; | |
1134 gboolean reused_p = FALSE; | |
462 | 1135 |
2367 | 1136 /* We may be able to reuse the widget, let's at least check. */ |
1137 if (current_child && menu_can_reuse_widget (GTK_WIDGET (current_child), | |
1138 XSTRING_DATA (XCAR (item_descr)))) | |
1139 { | |
1140 widget = menu_convert (item_descr, GTK_WIDGET (current_child), | |
1141 menubar_accel_group); | |
1142 reused_p = TRUE; | |
1143 } | |
1144 else | |
1145 { | |
1146 widget = menu_convert (item_descr, NULL, menubar_accel_group); | |
1147 if (current_child) gtk_widget_destroy (GTK_WIDGET (current_child)); | |
1148 gtk_menu_bar_insert (GTK_MENU_BAR (menubar), widget, menu_position); | |
1149 } | |
462 | 1150 |
2367 | 1151 if (widget) |
1152 { | |
1153 if (right_justify) gtk_menu_item_right_justify (GTK_MENU_ITEM (widget)); | |
1154 } | |
1155 else | |
1156 { | |
1157 widget = gtk_menu_item_new_with_label ("ERROR"); | |
2500 | 1158 /* ABORT() */ |
2367 | 1159 } |
1160 gtk_widget_show_all (widget); | |
1161 } | |
1162 else if (STRINGP (item_descr)) | |
1163 { | |
1164 /* Do I really want to be this careful? Anything else in a | |
1165 menubar description is illegal */ | |
1166 } | |
1167 menu_position++; | |
1168 } | |
1169 } | |
462 | 1170 |
1171 /* Need to delete any menu items that were past the bounds of the new one */ | |
1172 { | |
1173 GList *l = NULL; | |
1174 | |
1175 while ((l = g_list_nth (GTK_MENU_SHELL (menubar)->children, menu_position))) | |
1176 { | |
1177 gpointer data = l->data; | |
1178 g_list_remove_link (GTK_MENU_SHELL (menubar)->children, l); | |
1179 | |
1180 if (data) | |
1181 { | |
1182 gtk_widget_destroy (GTK_WIDGET (data)); | |
1183 } | |
1184 } | |
1185 } | |
2081 | 1186 |
1187 /* Attach the new accelerator group to the frame. */ | |
1188 gtk_window_add_accel_group (GTK_WINDOW (FRAME_GTK_SHELL_WIDGET(f)), | |
1189 menubar_accel_group); | |
462 | 1190 } |
1191 | |
1192 | |
1193 /* Deal with getting/setting the menubar */ | |
1194 #ifndef GNOME_IS_APP | |
1195 #define GNOME_IS_APP(x) 0 | |
1196 #define gnome_app_set_menus(x,y) | |
1197 #endif | |
1198 | |
1199 static gboolean | |
2286 | 1200 run_menubar_hook (GtkWidget *widget, GdkEventButton *UNUSED (event), |
1201 gpointer UNUSED (user_data)) | |
462 | 1202 { |
1203 if (!GTK_MENU_SHELL(widget)->active) | |
1204 { | |
1205 run_hook (Qactivate_menubar_hook); | |
1206 } | |
1207 return(FALSE); | |
1208 } | |
1209 | |
1210 static void | |
1211 create_menubar_widget (struct frame *f) | |
1212 { | |
1213 GUI_ID id = new_gui_id (); | |
1214 GtkWidget *handlebox = NULL; | |
1215 GtkWidget *menubar = gtk_xemacs_menubar_new (f); | |
1216 | |
1217 if (GNOME_IS_APP (FRAME_GTK_SHELL_WIDGET (f))) | |
1218 { | |
1219 gnome_app_set_menus (GNOME_APP (FRAME_GTK_SHELL_WIDGET (f)), GTK_MENU_BAR (menubar)); | |
1220 } | |
1221 else if (dockable_menubar) | |
1222 { | |
1223 handlebox = gtk_handle_box_new (); | |
1224 gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (handlebox), GTK_POS_LEFT); | |
1225 gtk_container_add (GTK_CONTAINER (handlebox), menubar); | |
1226 gtk_box_pack_start (GTK_BOX (FRAME_GTK_CONTAINER_WIDGET (f)), handlebox, FALSE, FALSE, 0); | |
1227 } | |
1228 else | |
1229 { | |
1230 gtk_box_pack_start (GTK_BOX (FRAME_GTK_CONTAINER_WIDGET (f)), menubar, FALSE, FALSE, 0); | |
1231 } | |
1232 | |
1233 gtk_signal_connect (GTK_OBJECT (menubar), "button-press-event", | |
1234 GTK_SIGNAL_FUNC (run_menubar_hook), NULL); | |
1235 | |
1236 FRAME_GTK_MENUBAR_WIDGET (f) = menubar; | |
1237 gtk_object_set_data (GTK_OBJECT (menubar), XEMACS_MENU_GUIID_TAG, (gpointer) id); | |
1238 gtk_object_weakref (GTK_OBJECT (menubar), __remove_gcpro_by_id, (gpointer) id); | |
1239 } | |
1240 | |
1241 static int | |
1242 set_frame_menubar (struct frame *f, int first_time_p) | |
1243 { | |
1244 Lisp_Object menubar; | |
1245 int menubar_visible; | |
1246 /* As for the toolbar, the minibuffer does not have its own menubar. */ | |
1247 struct window *w = XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f)); | |
1248 | |
1249 if (! FRAME_GTK_P (f)) | |
1250 return 0; | |
1251 | |
1252 /***** first compute the contents of the menubar *****/ | |
1253 | |
1254 if (! first_time_p) | |
1255 { | |
1256 /* evaluate `current-menubar' in the buffer of the selected window | |
1257 of the frame in question. */ | |
1258 menubar = symbol_value_in_buffer (Qcurrent_menubar, w->buffer); | |
1259 } | |
1260 else | |
1261 { | |
1262 /* That's a little tricky the first time since the frame isn't | |
1263 fully initialized yet. */ | |
1264 menubar = Fsymbol_value (Qcurrent_menubar); | |
1265 } | |
1266 | |
1267 if (NILP (menubar)) | |
1268 { | |
1269 menubar = Vblank_menubar; | |
1270 menubar_visible = 0; | |
1271 } | |
1272 else | |
1273 { | |
1274 menubar_visible = !NILP (w->menubar_visible_p); | |
1275 } | |
1276 | |
1277 if (!FRAME_GTK_MENUBAR_WIDGET (f)) | |
1278 { | |
1279 create_menubar_widget (f); | |
1280 } | |
1281 | |
1282 /* Populate the menubar, but nothing is shown yet */ | |
1283 { | |
1284 Lisp_Object old_buffer; | |
1285 int count = specpdl_depth (); | |
1286 | |
1287 old_buffer = Fcurrent_buffer (); | |
1288 record_unwind_protect (Fset_buffer, old_buffer); | |
1289 Fset_buffer (XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer); | |
1290 | |
1291 menu_create_menubar (f, menubar); | |
1292 | |
1293 Fset_buffer (old_buffer); | |
771 | 1294 unbind_to (count); |
462 | 1295 } |
1296 | |
1346 | 1297 FRAME_GTK_MENUBAR_DATA (f) = Fcons (XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f))->buffer, Qt); |
462 | 1298 |
1299 return (menubar_visible); | |
1300 } | |
1301 | |
1302 /* Called from gtk_create_widgets() to create the inital menubar of a frame | |
1303 before it is mapped, so that the window is mapped with the menubar already | |
1304 there instead of us tacking it on later and thrashing the window after it | |
1305 is visible. */ | |
1306 int | |
1307 gtk_initialize_frame_menubar (struct frame *f) | |
1308 { | |
1309 create_menubar_widget (f); | |
1310 return set_frame_menubar (f, 1); | |
1311 } | |
1312 | |
1313 | |
1314 static void | |
1315 gtk_update_frame_menubar_internal (struct frame *f) | |
1316 { | |
1317 /* We assume the menubar contents has changed if the global flag is set, | |
1318 or if the current buffer has changed, or if the menubar has never | |
1319 been updated before. | |
1320 */ | |
1321 int menubar_contents_changed = | |
1322 (f->menubar_changed | |
1346 | 1323 || NILP (FRAME_GTK_MENUBAR_DATA (f)) |
1324 || (!EQ (XFRAME_GTK_MENUBAR_DATA_LASTBUFF (f), | |
462 | 1325 XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f))->buffer))); |
1326 | |
1327 gboolean menubar_was_visible = GTK_WIDGET_VISIBLE (FRAME_GTK_MENUBAR_WIDGET (f)); | |
1328 gboolean menubar_will_be_visible = menubar_was_visible; | |
1329 gboolean menubar_visibility_changed; | |
1330 | |
1331 if (menubar_contents_changed) | |
1332 { | |
1333 menubar_will_be_visible = set_frame_menubar (f, 0); | |
1334 } | |
1335 | |
1336 menubar_visibility_changed = menubar_was_visible != menubar_will_be_visible; | |
1337 | |
1338 if (!menubar_visibility_changed) | |
1339 { | |
1340 return; | |
1341 } | |
1342 | |
1343 /* We hide and show the menubar's parent (which is actually the | |
1344 GtkHandleBox)... this is to simplify the code that destroys old | |
1345 menu items, etc. There is no easy way to get the child out of a | |
1346 handle box, and I didn't want to add yet another stupid widget | |
1347 slot to struct gtk_frame. */ | |
1348 if (menubar_will_be_visible) | |
1349 { | |
1350 gtk_widget_show_all (FRAME_GTK_MENUBAR_WIDGET (f)->parent); | |
1351 } | |
1352 else | |
1353 { | |
1354 gtk_widget_hide_all (FRAME_GTK_MENUBAR_WIDGET (f)->parent); | |
1355 } | |
1356 | |
1357 MARK_FRAME_SIZE_SLIPPED (f); | |
1358 } | |
1359 | |
1360 static void | |
1361 gtk_update_frame_menubars (struct frame *f) | |
1362 { | |
1363 GtkWidget *menubar = NULL; | |
1364 | |
1365 assert (FRAME_GTK_P (f)); | |
1366 | |
1367 menubar = FRAME_GTK_MENUBAR_WIDGET (f); | |
1368 | |
1369 if ((GTK_MENU_SHELL (menubar)->active) || | |
1370 (GTK_MENU_SHELL (menubar)->have_grab) || | |
1371 (GTK_MENU_SHELL (menubar)->have_xgrab)) | |
1372 { | |
1373 return; | |
1374 } | |
1375 | |
1376 gtk_update_frame_menubar_internal (f); | |
1377 } | |
1378 | |
1379 static void | |
1380 gtk_free_frame_menubars (struct frame *f) | |
1381 { | |
1382 GtkWidget *menubar_widget; | |
1383 | |
1384 assert (FRAME_GTK_P (f)); | |
1385 | |
1386 menubar_widget = FRAME_GTK_MENUBAR_WIDGET (f); | |
1387 if (menubar_widget) | |
1388 { | |
1389 gtk_widget_destroy (menubar_widget); | |
1390 } | |
1391 } | |
1392 | |
1416 | 1393 static void |
2286 | 1394 popdown_menu_cb (GtkMenuShell *UNUSED (menu), gpointer UNUSED (user_data)) |
462 | 1395 { |
1396 popup_up_p--; | |
1397 } | |
1398 | |
1399 static void | |
1400 gtk_popup_menu (Lisp_Object menu_desc, Lisp_Object event) | |
1401 { | |
1402 struct Lisp_Event *eev = NULL; | |
714 | 1403 GtkWidget *widget = NULL; |
1404 GtkWidget *menu = NULL; | |
1405 gpointer id = NULL; | |
462 | 1406 |
714 | 1407 /* Do basic error checking first... */ |
1408 if (SYMBOLP (menu_desc)) | |
1409 menu_desc = Fsymbol_value (menu_desc); | |
1410 CHECK_CONS (menu_desc); | |
1411 CHECK_STRING (XCAR (menu_desc)); | |
1412 | |
1413 /* Now lets get down to business... */ | |
2081 | 1414 widget = menu_descriptor_to_widget (menu_desc, NULL); |
714 | 1415 menu = GTK_MENU_ITEM (widget)->submenu; |
462 | 1416 gtk_widget_set_name (widget, "XEmacsPopupMenu"); |
714 | 1417 id = gtk_object_get_data (GTK_OBJECT (widget), XEMACS_MENU_GUIID_TAG); |
462 | 1418 |
1419 __activate_menu (GTK_MENU_ITEM (widget), id); | |
1420 | |
1421 if (!NILP (event)) | |
1422 { | |
1423 CHECK_LIVE_EVENT (event); | |
1424 eev = XEVENT (event); | |
1425 | |
1426 if ((eev->event_type != button_press_event) && | |
1427 (eev->event_type != button_release_event)) | |
1428 wrong_type_argument (Qmouse_event_p, event); | |
1429 } | |
1430 else if (!NILP (Vthis_command_keys)) | |
1431 { | |
1432 /* If an event wasn't passed, use the last event of the event | |
1433 sequence currently being executed, if that event is a mouse | |
1434 event. */ | |
1435 eev = XEVENT (Vthis_command_keys); | |
1436 if ((eev->event_type != button_press_event) && | |
1437 (eev->event_type != button_release_event)) | |
1438 eev = NULL; | |
1439 } | |
1440 | |
1441 gtk_widget_show (menu); | |
1442 | |
1443 popup_up_p++; | |
1444 gtk_signal_connect (GTK_OBJECT (menu), "deactivate", | |
1445 GTK_SIGNAL_FUNC (popdown_menu_cb), NULL); | |
1446 | |
1447 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, | |
1204 | 1448 eev ? EVENT_BUTTON_BUTTON (eev) : 0, |
462 | 1449 eev ? eev->timestamp : GDK_CURRENT_TIME); |
1450 } | |
1451 | |
1452 DEFUN ("gtk-build-xemacs-menu", Fgtk_build_xemacs_menu, 1, 1, 0, /* | |
1453 Returns a GTK menu item from MENU, a standard XEmacs menu description. | |
1454 See the definition of `popup-menu' for more information on the format of MENU. | |
1455 */ | |
1456 (menu)) | |
1457 { | |
2081 | 1458 GtkWidget *w = menu_descriptor_to_widget (menu, NULL); |
462 | 1459 |
1460 return (w ? build_gtk_object (GTK_OBJECT (w)) : Qnil); | |
1461 } | |
1462 | |
1463 | |
1464 void | |
1465 syms_of_menubar_gtk (void) | |
1466 { | |
1467 DEFSUBR (Fgtk_build_xemacs_menu); | |
1468 } | |
1469 | |
1470 void | |
1471 console_type_create_menubar_gtk (void) | |
1472 { | |
1473 CONSOLE_HAS_METHOD (gtk, update_frame_menubars); | |
1474 CONSOLE_HAS_METHOD (gtk, free_frame_menubars); | |
1475 CONSOLE_HAS_METHOD (gtk, popup_menu); | |
1476 } | |
1477 | |
1416 | 1478 void |
1479 reinit_vars_of_menubar_gtk (void) | |
462 | 1480 { |
1481 dockable_menubar = 1; | |
1482 #ifdef TEAR_OFF_MENUS | |
1483 tear_off_menus = 1; | |
1484 #endif | |
1485 } | |
1486 | |
1487 void | |
1488 vars_of_menubar_gtk (void) | |
1489 { | |
1490 Fprovide (intern ("gtk-menubars")); | |
1491 DEFVAR_BOOL ("menubar-dockable-p", &dockable_menubar /* | |
1492 If non-nil, the frame menubar can be detached into its own top-level window. | |
1493 */ ); | |
1494 #ifdef TEAR_OFF_MENUS | |
1495 DEFVAR_BOOL ("menubar-tearable-p", &tear_off_menus /* | |
1496 If non-nil, menus can be torn off into their own top-level windows. | |
1497 */ ); | |
1498 #endif | |
1499 } | |
2081 | 1500 |
1501 /*---------------------------------------------------------------------------*/ | |
1502 |