Mercurial > hg > xemacs-beta
annotate src/menubar-x.c @ 4928:ea701c23ed84
change text_width method to take a window, in preparation for unicode-internal changes
-------------------- ChangeLog entries follow: --------------------
src/ChangeLog addition:
2010-01-19 Ben Wing <ben@xemacs.org>
* console-impl.h (struct console_methods):
* console-stream.c (stream_text_width):
* redisplay-msw.c (mswindows_output_string):
* redisplay-msw.c (mswindows_text_width):
* redisplay-tty.c (tty_text_width):
* redisplay-xlike-inc.c (XLIKE_text_width):
* redisplay-xlike-inc.c (XLIKE_output_string):
* redisplay.c:
* redisplay.c (redisplay_window_text_width_ichar_string):
* redisplay.c (redisplay_text_width_string):
Change the text_width method to take a window instead of a frame.
Needed for Unicode-internal.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Tue, 19 Jan 2010 11:21:34 -0600 |
parents | 726060ee587c |
children | 19a72041c5ed |
rev | line source |
---|---|
428 | 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. | |
1261 | 4 Copyright (C) 2000, 2001, 2002, 2003 Ben Wing. |
428 | 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 | |
442 | 25 /* This file Mule-ized by Ben Wing, 7-8-00. */ |
26 | |
27 /* Authorship: | |
28 | |
29 Created 16-dec-91 by Jamie Zawinski. | |
30 Menu filters and many other keywords added by Stig for 19.12. | |
31 Original device-abstraction work and GC cleanup work by Ben Wing for 19.13. | |
32 Menu accelerators c. 1997? by ??. Moved here from event-stream.c. | |
33 Other work post-1996 by ??. | |
34 */ | |
428 | 35 |
36 #include <config.h> | |
37 #include "lisp.h" | |
38 | |
39 #include "buffer.h" | |
40 #include "commands.h" /* zmacs_regions */ | |
872 | 41 #include "device-impl.h" |
428 | 42 #include "events.h" |
872 | 43 #include "frame-impl.h" |
442 | 44 #include "gui.h" |
45 #include "keymap.h" | |
46 #include "menubar.h" | |
428 | 47 #include "opaque.h" |
872 | 48 #include "window-impl.h" |
428 | 49 |
872 | 50 #include "console-x-impl.h" |
800 | 51 |
52 #include "EmacsFrame.h" | |
53 #include "../lwlib/lwlib.h" | |
54 | |
428 | 55 static int set_frame_menubar (struct frame *f, |
56 int deep_p, | |
57 int first_time_p); | |
58 | |
59 #define MENUBAR_TYPE 0 | |
60 #define SUBMENU_TYPE 1 | |
61 #define POPUP_TYPE 2 | |
62 | |
63 | |
64 /* Converting Lisp menu tree descriptions to lwlib's `widget_value' form. | |
65 | |
66 menu_item_descriptor_to_widget_value() converts a lisp description of a | |
67 menubar into a tree of widget_value structures. It allocates widget_values | |
68 with malloc_widget_value() and allocates other storage only for the `key' | |
69 slot. All other slots are filled with pointers to Lisp_String data. We | |
70 allocate a widget_value description of the menu or menubar, and hand it to | |
71 lwlib, which then makes a copy of it, which it manages internally. We then | |
72 immediately free our widget_value tree; it will not be referenced again. | |
73 | |
74 Incremental menu construction callbacks operate just a bit differently. | |
75 They allocate widget_values and call replace_widget_value_tree() to tell | |
76 lwlib to destructively modify the incremental stub (subtree) of its | |
77 separate widget_value tree. | |
78 | |
79 This function is highly recursive (it follows the menu trees) and may call | |
80 eval. The reason we keep pointers to lisp string data instead of copying | |
81 it and freeing it later is to avoid the speed penalty that would entail | |
82 (since this needs to be fast, in the simple cases at least). (The reason | |
83 we malloc/free the keys slot is because there's not a lisp string around | |
84 for us to use in that case.) | |
85 | |
86 Since we keep pointers to lisp strings, and we call eval, we could lose if | |
87 GC relocates (or frees) those strings. It's not easy to gc protect the | |
88 strings because of the recursive nature of this function, and the fact that | |
89 it returns a data structure that gets freed later. So... we do the | |
90 sleaziest thing possible and inhibit GC for the duration. This is probably | |
91 not a big deal... | |
92 | |
93 We do not have to worry about the pointers to Lisp_String data after | |
94 this function successfully finishes. lwlib copies all such data with | |
95 strdup(). */ | |
96 | |
97 static widget_value * | |
98 menu_item_descriptor_to_widget_value_1 (Lisp_Object desc, | |
99 int menu_type, int deep_p, | |
100 int filter_p, | |
101 int depth) | |
102 { | |
103 /* This function cannot GC. | |
104 It is only called from menu_item_descriptor_to_widget_value, which | |
105 prohibits GC. */ | |
106 int menubar_root_p = (menu_type == MENUBAR_TYPE && depth == 0); | |
107 int count = specpdl_depth (); | |
108 int partition_seen = 0; | |
438 | 109 widget_value *wv = xmalloc_widget_value (); |
110 Lisp_Object wv_closure = make_opaque_ptr (wv); | |
428 | 111 |
112 record_unwind_protect (widget_value_unwind, wv_closure); | |
113 | |
114 if (STRINGP (desc)) | |
115 { | |
867 | 116 Ibyte *string_chars = XSTRING_DATA (desc); |
428 | 117 wv->type = (separator_string_p (string_chars) ? SEPARATOR_TYPE : |
118 TEXT_TYPE); | |
119 if (wv->type == SEPARATOR_TYPE) | |
120 { | |
442 | 121 wv->value = menu_separator_style_and_to_external (string_chars); |
428 | 122 } |
123 else | |
124 { | |
442 | 125 LISP_STRING_TO_EXTERNAL_MALLOC (desc, wv->name, Qlwlib_encoding); |
428 | 126 wv->enabled = 1; |
127 /* dverna Dec. 98: command_builder_operate_menu_accelerator will | |
128 manipulate the accel as a Lisp_Object if the widget has a name. | |
129 Since simple labels have a name, but no accel, we *must* set it | |
130 to nil */ | |
131 wv->accel = LISP_TO_VOID (Qnil); | |
132 } | |
133 } | |
134 else if (VECTORP (desc)) | |
135 { | |
136 Lisp_Object gui_item = gui_parse_item_keywords (desc); | |
442 | 137 if (!button_item_to_widget_value (Qmenubar, |
138 gui_item, wv, 1, | |
428 | 139 (menu_type == MENUBAR_TYPE |
442 | 140 && depth <= 1), 1, 1)) |
428 | 141 { |
142 /* :included form was nil */ | |
143 wv = NULL; | |
144 goto menu_item_done; | |
145 } | |
146 } | |
147 else if (CONSP (desc)) | |
148 { | |
149 Lisp_Object incremental_data = desc; | |
150 widget_value *prev = 0; | |
151 | |
152 if (STRINGP (XCAR (desc))) | |
153 { | |
154 Lisp_Object key, val; | |
155 Lisp_Object include_p = Qnil, hook_fn = Qnil, config_tag = Qnil; | |
156 Lisp_Object active_p = Qt; | |
157 Lisp_Object accel; | |
158 int included_spec = 0; | |
159 int active_spec = 0; | |
160 wv->type = CASCADE_TYPE; | |
161 wv->enabled = 1; | |
442 | 162 wv->name = add_accel_and_to_external (XCAR (desc)); |
428 | 163 |
442 | 164 accel = gui_name_accelerator (XCAR (desc)); |
428 | 165 wv->accel = LISP_TO_VOID (accel); |
166 | |
167 desc = Fcdr (desc); | |
168 | |
169 while (key = Fcar (desc), KEYWORDP (key)) | |
170 { | |
171 Lisp_Object cascade = desc; | |
172 desc = Fcdr (desc); | |
173 if (NILP (desc)) | |
563 | 174 sferror ("Keyword in menu lacks a value", cascade); |
428 | 175 val = Fcar (desc); |
176 desc = Fcdr (desc); | |
177 if (EQ (key, Q_included)) | |
178 include_p = val, included_spec = 1; | |
179 else if (EQ (key, Q_config)) | |
180 config_tag = val; | |
181 else if (EQ (key, Q_filter)) | |
182 hook_fn = val; | |
183 else if (EQ (key, Q_active)) | |
184 active_p = val, active_spec = 1; | |
185 else if (EQ (key, Q_accelerator)) | |
186 { | |
187 if ( SYMBOLP (val) | |
188 || CHARP (val)) | |
189 wv->accel = LISP_TO_VOID (val); | |
190 else | |
563 | 191 invalid_argument ("bad keyboard accelerator", val); |
428 | 192 } |
193 else if (EQ (key, Q_label)) | |
194 { | |
195 /* implement in 21.2 */ | |
196 } | |
197 else | |
563 | 198 invalid_argument ("Unknown menu cascade keyword", cascade); |
428 | 199 } |
200 | |
201 if ((!NILP (config_tag) | |
202 && NILP (Fmemq (config_tag, Vmenubar_configuration))) | |
203 || (included_spec && NILP (Feval (include_p)))) | |
204 { | |
205 wv = NULL; | |
206 goto menu_item_done; | |
207 } | |
208 | |
209 if (active_spec) | |
210 active_p = Feval (active_p); | |
211 | |
212 if (!NILP (hook_fn) && !NILP (active_p)) | |
213 { | |
214 #if defined LWLIB_MENUBARS_LUCID || defined LWLIB_MENUBARS_MOTIF | |
215 if (filter_p || depth == 0) | |
216 { | |
217 #endif | |
853 | 218 desc = call1 (hook_fn, desc); |
428 | 219 if (UNBOUNDP (desc)) |
220 desc = Qnil; | |
221 #if defined LWLIB_MENUBARS_LUCID || defined LWLIB_MENUBARS_MOTIF | |
222 } | |
223 else | |
224 { | |
225 widget_value *incr_wv = xmalloc_widget_value (); | |
226 wv->contents = incr_wv; | |
227 incr_wv->type = INCREMENTAL_TYPE; | |
228 incr_wv->enabled = 1; | |
229 incr_wv->name = wv->name; | |
436 | 230 incr_wv->name = xstrdup (wv->name); |
428 | 231 /* This is automatically GC protected through |
232 the call to lw_map_widget_values(); no need | |
233 to worry. */ | |
234 incr_wv->call_data = LISP_TO_VOID (incremental_data); | |
235 goto menu_item_done; | |
236 } | |
237 #endif /* LWLIB_MENUBARS_LUCID || LWLIB_MENUBARS_MOTIF */ | |
238 } | |
239 if (menu_type == POPUP_TYPE && popup_menu_titles && depth == 0) | |
240 { | |
241 /* Simply prepend three more widget values to the contents of | |
242 the menu: a label, and two separators (to get a double | |
243 line). */ | |
244 widget_value *title_wv = xmalloc_widget_value (); | |
245 widget_value *sep_wv = xmalloc_widget_value (); | |
246 title_wv->type = TEXT_TYPE; | |
436 | 247 title_wv->name = xstrdup (wv->name); |
428 | 248 title_wv->enabled = 1; |
249 title_wv->next = sep_wv; | |
250 sep_wv->type = SEPARATOR_TYPE; | |
867 | 251 sep_wv->value = menu_separator_style_and_to_external ((Ibyte *) "=="); |
428 | 252 sep_wv->next = 0; |
253 | |
254 wv->contents = title_wv; | |
255 prev = sep_wv; | |
256 } | |
257 wv->enabled = ! NILP (active_p); | |
258 if (deep_p && !wv->enabled && !NILP (desc)) | |
259 { | |
260 widget_value *dummy; | |
261 /* Add a fake entry so the menus show up */ | |
262 wv->contents = dummy = xmalloc_widget_value (); | |
436 | 263 dummy->name = xstrdup ("(inactive)"); |
428 | 264 dummy->accel = LISP_TO_VOID (Qnil); |
265 dummy->enabled = 0; | |
266 dummy->selected = 0; | |
267 dummy->value = NULL; | |
268 dummy->type = BUTTON_TYPE; | |
269 dummy->call_data = NULL; | |
270 dummy->next = NULL; | |
271 | |
272 goto menu_item_done; | |
442 | 273 } |
428 | 274 |
275 } | |
276 else if (menubar_root_p) | |
277 { | |
436 | 278 wv->name = xstrdup ("menubar"); |
428 | 279 wv->type = CASCADE_TYPE; /* Well, nothing else seems to fit and |
280 this is ignored anyway... */ | |
281 } | |
282 else | |
283 { | |
563 | 284 sferror ("Menu name (first element) must be a string", desc); |
428 | 285 } |
286 | |
287 if (deep_p || menubar_root_p) | |
288 { | |
289 widget_value *next; | |
290 for (; !NILP (desc); desc = Fcdr (desc)) | |
291 { | |
292 Lisp_Object child = Fcar (desc); | |
293 if (menubar_root_p && NILP (child)) /* the partition */ | |
294 { | |
295 if (partition_seen) | |
563 | 296 sferror |
442 | 297 ("More than one partition (nil) in menubar description", |
298 desc); | |
428 | 299 partition_seen = 1; |
300 next = xmalloc_widget_value (); | |
301 next->type = PUSHRIGHT_TYPE; | |
302 } | |
303 else | |
304 { | |
305 next = menu_item_descriptor_to_widget_value_1 | |
306 (child, menu_type, deep_p, filter_p, depth + 1); | |
307 } | |
308 if (! next) | |
309 continue; | |
310 else if (prev) | |
311 prev->next = next; | |
312 else | |
313 wv->contents = next; | |
314 prev = next; | |
315 } | |
316 } | |
317 if (deep_p && !wv->contents) | |
318 wv = NULL; | |
319 } | |
320 else if (NILP (desc)) | |
563 | 321 sferror ("nil may not appear in menu descriptions", desc); |
428 | 322 else |
563 | 323 sferror ("Unrecognized menu descriptor", desc); |
428 | 324 |
442 | 325 menu_item_done: |
428 | 326 |
327 if (wv) | |
328 { | |
329 /* Completed normally. Clear out the object that widget_value_unwind() | |
330 will be called with to tell it not to free the wv (as we are | |
331 returning it.) */ | |
332 set_opaque_ptr (wv_closure, 0); | |
333 } | |
334 | |
771 | 335 unbind_to (count); |
428 | 336 return wv; |
337 } | |
338 | |
853 | 339 struct menu_item_descriptor_to_widget_value |
340 { | |
341 Lisp_Object desc; | |
342 int menu_type, deep_p, filter_p; | |
343 widget_value *wv; | |
344 }; | |
428 | 345 |
346 static Lisp_Object | |
853 | 347 protected_menu_item_descriptor_to_widget_value_1 (void *gack) |
428 | 348 { |
853 | 349 struct menu_item_descriptor_to_widget_value *midtwv = |
350 (struct menu_item_descriptor_to_widget_value *) gack; | |
1918 | 351 int count = begin_gc_forbidden (); |
352 /* Can't GC! */ | |
353 midtwv->wv = menu_item_descriptor_to_widget_value_1 (midtwv->desc, | |
354 midtwv->menu_type, | |
355 midtwv->deep_p, | |
356 midtwv->filter_p, | |
357 0); | |
358 unbind_to (count); | |
442 | 359 return Qnil; |
428 | 360 } |
853 | 361 |
362 /* Inside of the pre_activate_callback, we absolutely need to protect | |
363 against errors, esp. but not exclusively in the filter code. (We do | |
364 other evalling, too.) We also need to reenable quit checking, which | |
365 was disabled by next_event_internal() so as to read C-g as an | |
366 event. */ | |
428 | 367 |
853 | 368 static widget_value * |
369 protected_menu_item_descriptor_to_widget_value (Lisp_Object desc, | |
370 int menu_type, int deep_p, | |
371 int filter_p) | |
428 | 372 { |
853 | 373 struct menu_item_descriptor_to_widget_value midtwv; |
1279 | 374 int depth = internal_bind_int (&in_menu_callback, 1); |
375 Lisp_Object retval; | |
428 | 376 |
853 | 377 midtwv.desc = desc; |
378 midtwv.menu_type = menu_type; | |
379 midtwv.deep_p = deep_p; | |
380 midtwv.filter_p = filter_p; | |
428 | 381 |
1279 | 382 retval = event_stream_protect_modal_loop |
383 ("Error during menu callback", | |
384 protected_menu_item_descriptor_to_widget_value_1, &midtwv, | |
385 UNINHIBIT_QUIT); | |
386 unbind_to (depth); | |
387 | |
388 if (UNBOUNDP (retval)) | |
853 | 389 return 0; |
390 | |
391 return midtwv.wv; | |
428 | 392 } |
853 | 393 |
1918 | 394 /* The two callers of menu_item_descriptor_to_widget_value may both run while |
395 in redisplay. Some descriptor to widget value conversions call Feval, and | |
396 at least one calls QUIT. Hence, we have to establish protection here.. */ | |
397 | |
398 static widget_value * | |
399 menu_item_descriptor_to_widget_value (Lisp_Object desc, | |
400 int menu_type, /* if this is a menubar, | |
401 popup or sub menu */ | |
402 int deep_p, /* */ | |
403 int filter_p) /* if :filter forms | |
404 should run now */ | |
405 { | |
406 struct menu_item_descriptor_to_widget_value midtwv; | |
407 Lisp_Object retval; | |
408 | |
409 midtwv.desc = desc; | |
410 midtwv.menu_type = menu_type; | |
411 midtwv.deep_p = deep_p; | |
412 midtwv.filter_p = filter_p; | |
413 | |
414 retval = call_trapping_problems | |
415 (Qevent, "Error during menu construction", 0, NULL, | |
416 protected_menu_item_descriptor_to_widget_value_1, &midtwv); | |
417 | |
418 if (UNBOUNDP (retval)) | |
419 return NULL; | |
420 | |
421 return midtwv.wv; | |
422 } | |
423 | |
428 | 424 /* The order in which callbacks are run is funny to say the least. |
425 It's sometimes tricky to avoid running a callback twice, and to | |
426 avoid returning prematurely. So, this function returns true | |
427 if the menu's callbacks are no longer gc protected. So long | |
428 as we unprotect them before allowing other callbacks to run, | |
429 everything should be ok. | |
430 | |
431 The pre_activate_callback() *IS* intentionally called multiple times. | |
432 If client_data == NULL, then it's being called before the menu is posted. | |
433 If client_data != NULL, then client_data is a (widget_value *) and | |
434 client_data->data is a Lisp_Object pointing to a lisp submenu description | |
435 that must be converted into widget_values. *client_data is destructively | |
436 modified. | |
437 | |
438 #### Stig thinks that there may be a GC problem here due to the | |
439 fact that pre_activate_callback() is called multiple times, but I | |
440 think he's wrong. | |
441 | |
442 */ | |
443 | |
444 static void | |
2286 | 445 pre_activate_callback (Widget widget, LWLIB_ID UNUSED (id), |
446 XtPointer client_data) | |
428 | 447 { |
448 /* This function can GC */ | |
449 struct device *d = get_device_from_display (XtDisplay (widget)); | |
450 struct frame *f = x_any_window_to_frame (d, XtWindow (widget)); | |
451 Lisp_Object frame; | |
452 | |
453 /* set in lwlib to the time stamp associated with the most recent menu | |
454 operation */ | |
455 extern Time x_focus_timestamp_really_sucks_fix_me_better; | |
456 | |
457 if (!f) | |
458 f = x_any_window_to_frame (d, XtWindow (XtParent (widget))); | |
459 if (!f) | |
460 return; | |
461 | |
462 /* make sure f is the selected frame */ | |
793 | 463 frame = wrap_frame (f); |
428 | 464 Fselect_frame (frame); |
465 | |
466 if (client_data) | |
467 { | |
468 /* this is an incremental menu construction callback */ | |
469 widget_value *hack_wv = (widget_value *) client_data; | |
470 Lisp_Object submenu_desc; | |
471 widget_value *wv; | |
472 | |
473 assert (hack_wv->type == INCREMENTAL_TYPE); | |
826 | 474 submenu_desc = VOID_TO_LISP (hack_wv->call_data); |
428 | 475 |
853 | 476 wv = (protected_menu_item_descriptor_to_widget_value |
477 (submenu_desc, SUBMENU_TYPE, 1, 0)); | |
428 | 478 |
479 if (!wv) | |
480 { | |
481 wv = xmalloc_widget_value (); | |
482 wv->type = CASCADE_TYPE; | |
483 wv->next = NULL; | |
484 wv->accel = LISP_TO_VOID (Qnil); | |
485 wv->contents = xmalloc_widget_value (); | |
486 wv->contents->type = TEXT_TYPE; | |
436 | 487 wv->contents->name = xstrdup ("No menu"); |
428 | 488 wv->contents->next = NULL; |
489 wv->contents->accel = LISP_TO_VOID (Qnil); | |
490 } | |
491 assert (wv && wv->type == CASCADE_TYPE && wv->contents); | |
492 replace_widget_value_tree (hack_wv, wv->contents); | |
493 free_popup_widget_value_tree (wv); | |
1261 | 494 /* Now that we've destructively modified part of the widget value |
495 hierarchy, our list of protected callbacks will no longer be | |
496 valid, so we need to recompute it. */ | |
1346 | 497 gcpro_popup_callbacks (FRAME_X_MENUBAR_ID (f)); |
428 | 498 } |
1346 | 499 else if (!FRAME_X_MENUBAR_ID (f)) |
428 | 500 return; |
501 else | |
502 { | |
503 /* #### - It is necessary to *ALWAYS* call set_frame_menubar() now that | |
504 incremental menus are implemented. If a subtree of a menu has been | |
505 updated incrementally (a destructive operation), then that subtree | |
506 must somehow be wiped. | |
507 | |
508 It is difficult to undo the destructive operation in lwlib because | |
509 a pointer back to lisp data needs to be hidden away somewhere. So | |
510 that an INCREMENTAL_TYPE widget_value can be recreated... Hmmmmm. */ | |
853 | 511 run_hook_trapping_problems |
1333 | 512 (Qmenubar, Qactivate_menubar_hook, |
853 | 513 INHIBIT_EXISTING_PERMANENT_DISPLAY_OBJECT_DELETION); |
428 | 514 set_frame_menubar (f, 1, 0); |
515 DEVICE_X_MOUSE_TIMESTAMP (XDEVICE (FRAME_DEVICE (f))) = | |
516 DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (XDEVICE (FRAME_DEVICE (f))) = | |
517 x_focus_timestamp_really_sucks_fix_me_better; | |
518 } | |
519 } | |
520 | |
521 static widget_value * | |
522 compute_menubar_data (struct frame *f, Lisp_Object menubar, int deep_p) | |
523 { | |
524 if (NILP (menubar)) | |
438 | 525 return 0; |
428 | 526 else |
527 { | |
438 | 528 widget_value *data; |
428 | 529 int count = specpdl_depth (); |
530 | |
438 | 531 record_unwind_protect (Fset_buffer, Fcurrent_buffer ()); |
532 Fset_buffer (XWINDOW (FRAME_SELECTED_WINDOW (f))->buffer); | |
428 | 533 data = menu_item_descriptor_to_widget_value (menubar, MENUBAR_TYPE, |
534 deep_p, 0); | |
771 | 535 unbind_to (count); |
438 | 536 |
537 return data; | |
428 | 538 } |
539 } | |
540 | |
541 static int | |
542 set_frame_menubar (struct frame *f, int deep_p, int first_time_p) | |
543 { | |
544 widget_value *data; | |
545 Lisp_Object menubar; | |
546 int menubar_visible; | |
547 long id; | |
438 | 548 /* As with the toolbar, the minibuffer does not have its own menubar. */ |
428 | 549 struct window *w = XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f)); |
550 | |
551 if (! FRAME_X_P (f)) | |
552 return 0; | |
553 | |
554 /***** first compute the contents of the menubar *****/ | |
555 | |
556 if (! first_time_p) | |
557 { | |
558 /* evaluate `current-menubar' in the buffer of the selected window | |
559 of the frame in question. */ | |
560 menubar = symbol_value_in_buffer (Qcurrent_menubar, w->buffer); | |
561 } | |
562 else | |
563 { | |
564 /* That's a little tricky the first time since the frame isn't | |
565 fully initialized yet. */ | |
566 menubar = Fsymbol_value (Qcurrent_menubar); | |
567 } | |
568 | |
569 if (NILP (menubar)) | |
570 { | |
571 menubar = Vblank_menubar; | |
572 menubar_visible = 0; | |
573 } | |
574 else | |
575 menubar_visible = !NILP (w->menubar_visible_p); | |
576 | |
577 data = compute_menubar_data (f, menubar, deep_p); | |
578 if (!data || (!data->next && !data->contents)) | |
2500 | 579 ABORT (); |
428 | 580 |
1346 | 581 if (!FRAME_X_MENUBAR_ID (f)) |
582 FRAME_X_MENUBAR_ID (f) = new_lwlib_id (); | |
428 | 583 |
584 /***** now store into the menubar widget, creating it if necessary *****/ | |
585 | |
1346 | 586 id = FRAME_X_MENUBAR_ID (f); |
428 | 587 if (!FRAME_X_MENUBAR_WIDGET (f)) |
588 { | |
589 Widget parent = FRAME_X_CONTAINER_WIDGET (f); | |
590 | |
591 assert (first_time_p); | |
592 | |
593 /* It's the first time we've mapped the menubar so compute its | |
594 contents completely once. This makes sure that the menubar | |
595 components are created with the right type. */ | |
596 if (!deep_p) | |
597 { | |
598 free_popup_widget_value_tree (data); | |
599 data = compute_menubar_data (f, menubar, 1); | |
600 } | |
601 | |
602 | |
603 FRAME_X_MENUBAR_WIDGET (f) = | |
604 lw_create_widget ("menubar", "menubar", id, data, parent, | |
605 0, pre_activate_callback, | |
606 popup_selection_callback, 0); | |
607 | |
608 } | |
609 else | |
610 { | |
611 lw_modify_all_widgets (id, data, deep_p ? True : False); | |
612 } | |
613 free_popup_widget_value_tree (data); | |
614 | |
1261 | 615 /* Buried inside of the lwlib data are pointers to Lisp objects that may |
616 have been freshly created. They need to be GC-protected, so snarf them | |
617 now and record them into the popup-data object associated with the | |
618 frame. */ | |
1346 | 619 gcpro_popup_callbacks (id); |
1261 | 620 |
1346 | 621 FRAME_X_MENUBAR_CONTENTS_UP_TO_DATE (f) = deep_p; |
622 FRAME_X_LAST_MENUBAR_BUFFER (f) = | |
428 | 623 XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f))->buffer; |
624 return menubar_visible; | |
625 } | |
626 | |
627 | |
628 /* Called from x_create_widgets() to create the initial menubar of a frame | |
629 before it is mapped, so that the window is mapped with the menubar already | |
630 there instead of us tacking it on later and thrashing the window after it | |
631 is visible. */ | |
632 int | |
633 x_initialize_frame_menubar (struct frame *f) | |
634 { | |
635 return set_frame_menubar (f, 1, 1); | |
636 } | |
637 | |
638 | |
639 static LWLIB_ID last_popup_menu_selection_callback_id; | |
640 | |
641 static void | |
642 popup_menu_selection_callback (Widget widget, LWLIB_ID id, | |
643 XtPointer client_data) | |
644 { | |
645 last_popup_menu_selection_callback_id = id; | |
646 popup_selection_callback (widget, id, client_data); | |
647 /* lw_destroy_all_widgets() will be called from popup_down_callback() */ | |
648 } | |
649 | |
650 static void | |
2286 | 651 popup_menu_down_callback (Widget widget, LWLIB_ID id, |
652 XtPointer UNUSED (client_data)) | |
428 | 653 { |
654 if (popup_handled_p (id)) | |
655 return; | |
656 assert (popup_up_p != 0); | |
657 ungcpro_popup_callbacks (id); | |
658 popup_up_p--; | |
659 /* if this isn't called immediately after the selection callback, then | |
660 there wasn't a menu selection. */ | |
661 if (id != last_popup_menu_selection_callback_id) | |
662 popup_selection_callback (widget, id, (XtPointer) -1); | |
663 lw_destroy_all_widgets (id); | |
664 } | |
665 | |
666 | |
667 static void | |
440 | 668 make_dummy_xbutton_event (XEvent *dummy, Widget daddy, Lisp_Event *eev) |
428 | 669 /* NULL for eev means query pointer */ |
670 { | |
671 XButtonPressedEvent *btn = (XButtonPressedEvent *) dummy; | |
672 | |
673 btn->type = ButtonPress; | |
674 btn->serial = 0; | |
675 btn->send_event = 0; | |
676 btn->display = XtDisplay (daddy); | |
677 btn->window = XtWindow (daddy); | |
678 if (eev) | |
679 { | |
680 Position shellx, shelly, framex, framey; | |
681 Arg al [2]; | |
934 | 682 btn->time = EVENT_TIMESTAMP (eev); |
1204 | 683 btn->button = EVENT_BUTTON_BUTTON (eev); |
934 | 684 btn->root = RootWindowOfScreen (XtScreen (daddy)); |
685 btn->subwindow = (Window) NULL; | |
1204 | 686 btn->x = EVENT_BUTTON_X (eev); |
687 btn->y = EVENT_BUTTON_Y (eev); | |
428 | 688 shellx = shelly = 0; |
689 #ifndef HAVE_WMCOMMAND | |
690 { | |
691 Widget shell = XtParent (daddy); | |
692 | |
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
693 Xt_SET_ARG (al [0], XtNx, &shellx); |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
694 Xt_SET_ARG (al [1], XtNy, &shelly); |
428 | 695 XtGetValues (shell, al, 2); |
696 } | |
438 | 697 #endif |
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
698 Xt_SET_ARG (al [0], XtNx, &framex); |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
699 Xt_SET_ARG (al [1], XtNy, &framey); |
428 | 700 XtGetValues (daddy, al, 2); |
701 btn->x_root = shellx + framex + btn->x; | |
702 btn->y_root = shelly + framey + btn->y; | |
703 btn->state = ButtonPressMask; /* all buttons pressed */ | |
704 } | |
705 else | |
706 { | |
707 /* CurrentTime is just ZERO, so it's worthless for | |
708 determining relative click times. */ | |
709 struct device *d = get_device_from_display (XtDisplay (daddy)); | |
710 btn->time = DEVICE_X_MOUSE_TIMESTAMP (d); /* event-Xt maintains this */ | |
711 btn->button = 0; | |
712 XQueryPointer (btn->display, btn->window, &btn->root, | |
713 &btn->subwindow, &btn->x_root, &btn->y_root, | |
714 &btn->x, &btn->y, &btn->state); | |
715 } | |
716 } | |
717 | |
718 | |
719 | |
720 static void | |
721 x_update_frame_menubar_internal (struct frame *f) | |
722 { | |
723 /* We assume the menubar contents has changed if the global flag is set, | |
724 or if the current buffer has changed, or if the menubar has never | |
725 been updated before. | |
726 */ | |
727 int menubar_contents_changed = | |
728 (f->menubar_changed | |
1346 | 729 || !FRAME_X_MENUBAR_ID (f) |
730 || (!EQ (FRAME_X_LAST_MENUBAR_BUFFER (f), | |
428 | 731 XWINDOW (FRAME_LAST_NONMINIBUF_WINDOW (f))->buffer))); |
732 | |
733 Boolean menubar_was_visible = XtIsManaged (FRAME_X_MENUBAR_WIDGET (f)); | |
734 Boolean menubar_will_be_visible = menubar_was_visible; | |
735 Boolean menubar_visibility_changed; | |
736 | |
737 if (menubar_contents_changed) | |
738 menubar_will_be_visible = set_frame_menubar (f, 0, 0); | |
739 | |
740 menubar_visibility_changed = menubar_was_visible != menubar_will_be_visible; | |
741 | |
742 if (!menubar_visibility_changed) | |
743 return; | |
744 | |
745 /* Set menubar visibility */ | |
746 (menubar_will_be_visible ? XtManageChild : XtUnmanageChild) | |
747 (FRAME_X_MENUBAR_WIDGET (f)); | |
748 | |
749 MARK_FRAME_SIZE_SLIPPED (f); | |
750 } | |
751 | |
752 static void | |
753 x_update_frame_menubars (struct frame *f) | |
754 { | |
755 assert (FRAME_X_P (f)); | |
756 | |
757 x_update_frame_menubar_internal (f); | |
758 | |
759 /* #### This isn't going to work right now that this function works on | |
760 a per-frame, not per-device basis. Guess what? I don't care. */ | |
761 } | |
762 | |
763 static void | |
764 x_free_frame_menubars (struct frame *f) | |
765 { | |
766 Widget menubar_widget; | |
767 | |
768 assert (FRAME_X_P (f)); | |
769 | |
770 menubar_widget = FRAME_X_MENUBAR_WIDGET (f); | |
771 if (menubar_widget) | |
772 { | |
1346 | 773 LWLIB_ID id = FRAME_X_MENUBAR_ID (f); |
428 | 774 lw_destroy_all_widgets (id); |
1346 | 775 ungcpro_popup_callbacks (id); |
776 FRAME_X_MENUBAR_ID (f) = 0; | |
428 | 777 } |
778 } | |
779 | |
780 static void | |
781 x_popup_menu (Lisp_Object menu_desc, Lisp_Object event) | |
782 { | |
783 int menu_id; | |
784 struct frame *f = selected_frame (); | |
785 widget_value *data; | |
786 Widget parent; | |
787 Widget menu; | |
440 | 788 Lisp_Event *eev = NULL; |
428 | 789 XEvent xev; |
793 | 790 Lisp_Object frame = wrap_frame (f); |
428 | 791 |
792 CHECK_X_FRAME (frame); | |
793 parent = FRAME_X_SHELL_WIDGET (f); | |
794 | |
795 if (!NILP (event)) | |
796 { | |
797 CHECK_LIVE_EVENT (event); | |
798 eev= XEVENT (event); | |
799 if (eev->event_type != button_press_event | |
800 && eev->event_type != button_release_event) | |
801 wrong_type_argument (Qmouse_event_p, event); | |
802 } | |
803 else if (!NILP (Vthis_command_keys)) | |
804 { | |
805 /* if an event wasn't passed, use the last event of the event sequence | |
806 currently being executed, if that event is a mouse event */ | |
807 eev = XEVENT (Vthis_command_keys); /* last event first */ | |
808 if (eev->event_type != button_press_event | |
809 && eev->event_type != button_release_event) | |
810 eev = NULL; | |
811 } | |
812 make_dummy_xbutton_event (&xev, parent, eev); | |
813 | |
814 if (SYMBOLP (menu_desc)) | |
815 menu_desc = Fsymbol_value (menu_desc); | |
816 CHECK_CONS (menu_desc); | |
817 CHECK_STRING (XCAR (menu_desc)); | |
818 data = menu_item_descriptor_to_widget_value (menu_desc, POPUP_TYPE, 1, 1); | |
819 | |
563 | 820 if (! data) signal_error (Qgui_error, "no menu", Qunbound); |
428 | 821 |
822 menu_id = new_lwlib_id (); | |
823 menu = lw_create_widget ("popup", "popup" /* data->name */, menu_id, data, | |
824 parent, 1, 0, | |
825 popup_menu_selection_callback, | |
826 popup_menu_down_callback); | |
827 free_popup_widget_value_tree (data); | |
828 | |
829 gcpro_popup_callbacks (menu_id); | |
830 | |
831 /* Setting zmacs-region-stays is necessary here because executing a command | |
832 from a menu is really a two-command process: the first command (bound to | |
833 the button-click) simply pops up the menu, and returns. This causes a | |
834 sequence of magic-events (destined for the popup-menu widget) to begin. | |
835 Eventually, a menu item is selected, and a menu-event blip is pushed onto | |
836 the end of the input stream, which is then executed by the event loop. | |
837 | |
838 So there are two command-events, with a bunch of magic-events between | |
839 them. We don't want the *first* command event to alter the state of the | |
840 region, so that the region can be available as an argument for the second | |
841 command. | |
442 | 842 */ |
428 | 843 if (zmacs_regions) |
844 zmacs_region_stays = 1; | |
845 | |
846 popup_up_p++; | |
847 lw_popup_menu (menu, &xev); | |
848 /* this speeds up display of pop-up menus */ | |
849 XFlush (XtDisplay (parent)); | |
850 } | |
851 | |
852 | |
442 | 853 |
854 #if defined(LWLIB_MENUBARS_LUCID) | |
855 static void | |
856 menu_move_up (void) | |
857 { | |
858 widget_value *current = lw_get_entries (False); | |
859 widget_value *entries = lw_get_entries (True); | |
860 widget_value *prev = NULL; | |
861 | |
862 while (entries != current) | |
863 { | |
864 if (entries->name /*&& entries->enabled*/) prev = entries; | |
865 entries = entries->next; | |
866 assert (entries); | |
867 } | |
868 | |
869 if (!prev) | |
870 /* move to last item */ | |
871 { | |
872 while (entries->next) | |
873 { | |
874 if (entries->name /*&& entries->enabled*/) prev = entries; | |
875 entries = entries->next; | |
876 } | |
877 if (prev) | |
878 { | |
879 if (entries->name /*&& entries->enabled*/) | |
880 prev = entries; | |
881 } | |
882 else | |
883 { | |
884 /* no selectable items in this menu, pop up to previous level */ | |
885 lw_pop_menu (); | |
886 return; | |
887 } | |
888 } | |
889 lw_set_item (prev); | |
890 } | |
891 | |
892 static void | |
893 menu_move_down (void) | |
894 { | |
895 widget_value *current = lw_get_entries (False); | |
3025 | 896 widget_value *new_ = current; |
442 | 897 |
3025 | 898 while (new_->next) |
442 | 899 { |
3025 | 900 new_ = new_->next; |
901 if (new_->name /*&& new_->enabled*/) break; | |
442 | 902 } |
903 | |
3025 | 904 if (new_==current||!(new_->name/*||new_->enabled*/)) |
442 | 905 { |
3025 | 906 new_ = lw_get_entries (True); |
907 while (new_!=current) | |
442 | 908 { |
3025 | 909 if (new_->name /*&& new_->enabled*/) break; |
910 new_ = new_->next; | |
442 | 911 } |
3025 | 912 if (new_==current&&!(new_->name /*|| new_->enabled*/)) |
442 | 913 { |
914 lw_pop_menu (); | |
915 return; | |
916 } | |
917 } | |
918 | |
3025 | 919 lw_set_item (new_); |
442 | 920 } |
921 | |
922 static void | |
923 menu_move_left (void) | |
924 { | |
925 int level = lw_menu_level (); | |
926 int l = level; | |
927 widget_value *current; | |
928 | |
929 while (level-- >= 3) | |
930 lw_pop_menu (); | |
931 | |
932 menu_move_up (); | |
933 current = lw_get_entries (False); | |
934 if (l > 2 && current->contents) | |
935 lw_push_menu (current->contents); | |
936 } | |
937 | |
938 static void | |
939 menu_move_right (void) | |
940 { | |
941 int level = lw_menu_level (); | |
942 int l = level; | |
943 widget_value *current; | |
944 | |
945 while (level-- >= 3) | |
946 lw_pop_menu (); | |
947 | |
948 menu_move_down (); | |
949 current = lw_get_entries (False); | |
950 if (l > 2 && current->contents) | |
951 lw_push_menu (current->contents); | |
952 } | |
953 | |
954 static void | |
955 menu_select_item (widget_value *val) | |
956 { | |
957 if (val == NULL) | |
958 val = lw_get_entries (False); | |
959 | |
960 /* is match a submenu? */ | |
961 | |
962 if (val->contents) | |
963 { | |
964 /* enter the submenu */ | |
965 | |
966 lw_set_item (val); | |
967 lw_push_menu (val->contents); | |
968 } | |
969 else | |
970 { | |
971 /* Execute the menu entry by calling the menu's `select' | |
972 callback function | |
973 */ | |
974 lw_kill_menus (val); | |
975 } | |
976 } | |
977 | |
978 Lisp_Object | |
979 command_builder_operate_menu_accelerator (struct command_builder *builder) | |
980 { | |
981 /* this function can GC */ | |
982 | |
983 struct console *con = XCONSOLE (Vselected_console); | |
984 Lisp_Object evee = builder->most_current_event; | |
985 Lisp_Object binding; | |
986 widget_value *entries; | |
987 | |
988 extern int lw_menu_accelerate; /* lwlib.c */ | |
989 | |
990 #if 0 | |
991 { | |
992 int i; | |
993 Lisp_Object t; | |
994 | |
995 t = builder->current_events; | |
996 i = 0; | |
997 while (!NILP (t)) | |
998 { | |
999 i++; | |
800 | 1000 write_fmt_string (Qexternal_debugging_output, "OPERATE (%d): ",i); |
442 | 1001 print_internal (t, Qexternal_debugging_output, 1); |
826 | 1002 write_c_string (Qexternal_debugging_output, "\n"); |
442 | 1003 t = XEVENT_NEXT (t); |
1004 } | |
1005 } | |
1006 #endif /* 0 */ | |
1007 | |
1008 /* menu accelerator keys don't go into keyboard macros */ | |
1009 if (!NILP (con->defining_kbd_macro) && NILP (Vexecuting_macro)) | |
1010 con->kbd_macro_ptr = con->kbd_macro_end; | |
1011 | |
1012 /* don't echo menu accelerator keys */ | |
1013 /*reset_key_echo (builder, 1);*/ | |
1014 | |
1015 if (!lw_menu_accelerate) | |
1016 { | |
1017 /* `convert' mouse display to keyboard display | |
1018 by entering the open submenu | |
1019 */ | |
1020 entries = lw_get_entries (False); | |
1021 if (entries->contents) | |
1022 { | |
1023 lw_push_menu (entries->contents); | |
1024 lw_display_menu (CurrentTime); | |
1025 } | |
1026 } | |
1027 | |
1028 /* compare event to the current menu accelerators */ | |
1029 | |
1030 entries=lw_get_entries (True); | |
1031 | |
1032 while (entries) | |
1033 { | |
1034 Lisp_Object accel; | |
826 | 1035 accel = VOID_TO_LISP (entries->accel); |
442 | 1036 if (entries->name && !NILP (accel)) |
1037 { | |
1204 | 1038 if (event_matches_key_specifier_p (evee, accel)) |
442 | 1039 { |
1040 /* a match! */ | |
1041 | |
1042 menu_select_item (entries); | |
1043 | |
1044 if (lw_menu_active) lw_display_menu (CurrentTime); | |
1045 | |
1046 reset_this_command_keys (Vselected_console, 1); | |
1047 /*reset_command_builder_event_chain (builder);*/ | |
1048 return Vmenu_accelerator_map; | |
1049 } | |
1050 } | |
1051 entries = entries->next; | |
1052 } | |
1053 | |
1054 /* try to look up event in menu-accelerator-map */ | |
1055 | |
1056 binding = event_binding_in (evee, Vmenu_accelerator_map, 1); | |
1057 | |
1058 if (NILP (binding)) | |
1059 { | |
1060 /* beep at user for undefined key */ | |
1061 return Qnil; | |
1062 } | |
1063 else | |
1064 { | |
1065 if (EQ (binding, Qmenu_quit)) | |
1066 { | |
1067 /* turn off menus and set quit flag */ | |
1068 lw_kill_menus (NULL); | |
1069 Vquit_flag = Qt; | |
1070 } | |
1071 else if (EQ (binding, Qmenu_up)) | |
1072 { | |
1073 int level = lw_menu_level (); | |
1074 if (level > 2) | |
1075 menu_move_up (); | |
1076 } | |
1077 else if (EQ (binding, Qmenu_down)) | |
1078 { | |
1079 int level = lw_menu_level (); | |
1080 if (level > 2) | |
1081 menu_move_down (); | |
1082 else | |
1083 menu_select_item (NULL); | |
1084 } | |
1085 else if (EQ (binding, Qmenu_left)) | |
1086 { | |
1087 int level = lw_menu_level (); | |
1088 if (level > 3) | |
1089 { | |
1090 lw_pop_menu (); | |
1091 lw_display_menu (CurrentTime); | |
1092 } | |
1093 else | |
1094 menu_move_left (); | |
1095 } | |
1096 else if (EQ (binding, Qmenu_right)) | |
1097 { | |
1098 int level = lw_menu_level (); | |
1099 if (level > 2 && | |
1100 lw_get_entries (False)->contents) | |
1101 { | |
1102 widget_value *current = lw_get_entries (False); | |
1103 if (current->contents) | |
1104 menu_select_item (NULL); | |
1105 } | |
1106 else | |
1107 menu_move_right (); | |
1108 } | |
1109 else if (EQ (binding, Qmenu_select)) | |
1110 menu_select_item (NULL); | |
1111 else if (EQ (binding, Qmenu_escape)) | |
1112 { | |
1113 int level = lw_menu_level (); | |
1114 | |
1115 if (level > 2) | |
1116 { | |
1117 lw_pop_menu (); | |
1118 lw_display_menu (CurrentTime); | |
1119 } | |
1120 else | |
1121 { | |
1122 /* turn off menus quietly */ | |
1123 lw_kill_menus (NULL); | |
1124 } | |
1125 } | |
1126 else if (KEYMAPP (binding)) | |
1127 { | |
1128 /* prefix key */ | |
1129 reset_this_command_keys (Vselected_console, 1); | |
1130 /*reset_command_builder_event_chain (builder);*/ | |
1131 return binding; | |
1132 } | |
1133 else | |
1134 { | |
1135 /* turn off menus and execute binding */ | |
1136 lw_kill_menus (NULL); | |
1137 reset_this_command_keys (Vselected_console, 1); | |
1138 /*reset_command_builder_event_chain (builder);*/ | |
1139 return binding; | |
1140 } | |
1141 } | |
1142 | |
1143 if (lw_menu_active) lw_display_menu (CurrentTime); | |
1144 | |
1145 reset_this_command_keys (Vselected_console, 1); | |
1146 /*reset_command_builder_event_chain (builder);*/ | |
1147 | |
1148 return Vmenu_accelerator_map; | |
1149 } | |
1150 | |
1151 static Lisp_Object | |
2286 | 1152 menu_accelerator_junk_on_error (Lisp_Object errordata, |
1153 Lisp_Object UNUSED (ignored)) | |
442 | 1154 { |
1155 Vmenu_accelerator_prefix = Qnil; | |
1156 Vmenu_accelerator_modifiers = Qnil; | |
1157 Vmenu_accelerator_enabled = Qnil; | |
1158 if (!NILP (errordata)) | |
1159 { | |
1160 /* #### This should call | |
1161 (with-output-to-string (display-error errordata)) | |
1162 but that stuff is all in Lisp currently. */ | |
1163 warn_when_safe_lispobj | |
1164 (Qerror, Qwarning, | |
771 | 1165 emacs_sprintf_string_lisp |
1166 ("%s: %s", Qnil, 2, | |
1167 build_msg_string ("Error in menu accelerators (setting to nil)"), | |
1168 errordata)); | |
442 | 1169 } |
1170 | |
1171 return Qnil; | |
1172 } | |
1173 | |
1174 static Lisp_Object | |
1175 menu_accelerator_safe_compare (Lisp_Object event0) | |
1176 { | |
1177 if (CONSP (Vmenu_accelerator_prefix)) | |
1178 { | |
1179 Lisp_Object t; | |
1180 t=Vmenu_accelerator_prefix; | |
1181 while (!NILP (t) | |
1182 && !NILP (event0) | |
1204 | 1183 && event_matches_key_specifier_p (event0, Fcar (t))) |
442 | 1184 { |
1185 t = Fcdr (t); | |
1186 event0 = XEVENT_NEXT (event0); | |
1187 } | |
1188 if (!NILP (t)) | |
1189 return Qnil; | |
1190 } | |
1191 else if (NILP (event0)) | |
1192 return Qnil; | |
1204 | 1193 else if (event_matches_key_specifier_p (event0, Vmenu_accelerator_prefix)) |
442 | 1194 event0 = XEVENT_NEXT (event0); |
1195 else | |
1196 return Qnil; | |
1197 return event0; | |
1198 } | |
1199 | |
1200 static Lisp_Object | |
1201 menu_accelerator_safe_mod_compare (Lisp_Object cons) | |
1202 { | |
1204 | 1203 return (event_matches_key_specifier_p (XCAR (cons), XCDR (cons)) ? Qt |
442 | 1204 : Qnil); |
1205 } | |
1206 | |
1207 Lisp_Object | |
1208 command_builder_find_menu_accelerator (struct command_builder *builder) | |
1209 { | |
1210 /* this function can GC */ | |
1211 Lisp_Object event0 = builder->current_events; | |
1212 struct console *con = XCONSOLE (Vselected_console); | |
1213 struct frame *f = XFRAME (CONSOLE_SELECTED_FRAME (con)); | |
1214 Widget menubar_widget; | |
1215 | |
1216 /* compare entries in event0 against the menu prefix */ | |
1217 | |
1218 if ((!CONSOLE_X_P (XCONSOLE (builder->console))) || NILP (event0) || | |
1219 XEVENT (event0)->event_type != key_press_event) | |
1220 return Qnil; | |
1221 | |
1222 if (!NILP (Vmenu_accelerator_prefix)) | |
1223 { | |
1224 event0 = condition_case_1 (Qerror, | |
1225 menu_accelerator_safe_compare, | |
1226 event0, | |
1227 menu_accelerator_junk_on_error, | |
1228 Qnil); | |
1229 } | |
1230 | |
1231 if (NILP (event0)) | |
1232 return Qnil; | |
1233 | |
1234 menubar_widget = FRAME_X_MENUBAR_WIDGET (f); | |
1235 if (menubar_widget | |
1236 && CONSP (Vmenu_accelerator_modifiers)) | |
1237 { | |
446 | 1238 Lisp_Object fake = Qnil; |
442 | 1239 Lisp_Object last = Qnil; |
1240 struct gcpro gcpro1; | |
1241 Lisp_Object matchp; | |
1242 | |
1243 widget_value *val; | |
1346 | 1244 LWLIB_ID id = FRAME_X_MENUBAR_ID (f); |
442 | 1245 |
1246 val = lw_get_all_values (id); | |
1247 if (val) | |
1248 { | |
1249 val = val->contents; | |
1250 | |
1251 fake = Fcopy_sequence (Vmenu_accelerator_modifiers); | |
1252 last = fake; | |
1253 | |
1254 while (!NILP (Fcdr (last))) | |
1255 last = Fcdr (last); | |
1256 | |
1257 Fsetcdr (last, Fcons (Qnil, Qnil)); | |
1258 last = Fcdr (last); | |
1259 } | |
1260 | |
1261 fake = Fcons (Qnil, fake); | |
1262 | |
1263 GCPRO1 (fake); | |
1264 | |
1265 while (val) | |
1266 { | |
1267 Lisp_Object accel; | |
826 | 1268 accel = VOID_TO_LISP (val->accel); |
442 | 1269 if (val->name && !NILP (accel)) |
1270 { | |
1271 Fsetcar (last, accel); | |
1272 Fsetcar (fake, event0); | |
1273 matchp = condition_case_1 (Qerror, | |
1274 menu_accelerator_safe_mod_compare, | |
1275 fake, | |
1276 menu_accelerator_junk_on_error, | |
1277 Qnil); | |
1278 if (!NILP (matchp)) | |
1279 { | |
1280 /* we found one! */ | |
1281 | |
1282 lw_set_menu (menubar_widget, val); | |
1283 /* yah - yet another hack. | |
1284 pretend emacs timestamp is the same as an X timestamp, | |
1285 which for the moment it is. (read events.h) | |
1286 */ | |
1287 lw_map_menu (XEVENT (event0)->timestamp); | |
1288 | |
1289 if (val->contents) | |
1290 lw_push_menu (val->contents); | |
1291 | |
1292 lw_display_menu (CurrentTime); | |
1293 | |
1294 /* menu accelerator keys don't go into keyboard macros */ | |
1295 if (!NILP (con->defining_kbd_macro) | |
1296 && NILP (Vexecuting_macro)) | |
1297 con->kbd_macro_ptr = con->kbd_macro_end; | |
1298 | |
1299 /* don't echo menu accelerator keys */ | |
1300 /*reset_key_echo (builder, 1);*/ | |
1301 reset_this_command_keys (Vselected_console, 1); | |
1302 UNGCPRO; | |
1303 | |
1304 return Vmenu_accelerator_map; | |
1305 } | |
1306 } | |
1307 | |
1308 val = val->next; | |
1309 } | |
1310 | |
1311 UNGCPRO; | |
1312 } | |
1313 return Qnil; | |
1314 } | |
1315 | |
1316 int | |
1317 x_kludge_lw_menu_active (void) | |
1318 { | |
1319 return lw_menu_active; | |
1320 } | |
1321 | |
1322 DEFUN ("accelerate-menu", Faccelerate_menu, 0, 0, "_", /* | |
1323 Make the menubar active. Menu items can be selected using menu accelerators | |
1324 or by actions defined in menu-accelerator-map. | |
1325 */ | |
1326 ()) | |
1327 { | |
1328 struct console *con = XCONSOLE (Vselected_console); | |
1329 struct frame *f = XFRAME (CONSOLE_SELECTED_FRAME (con)); | |
1330 LWLIB_ID id; | |
1331 widget_value *val; | |
1332 | |
1346 | 1333 if (!FRAME_X_MENUBAR_ID (f)) |
563 | 1334 invalid_argument ("Frame has no menubar", Qunbound); |
442 | 1335 |
1346 | 1336 id = FRAME_X_MENUBAR_ID (f); |
442 | 1337 val = lw_get_all_values (id); |
1338 val = val->contents; | |
1339 lw_set_menu (FRAME_X_MENUBAR_WIDGET (f), val); | |
1340 lw_map_menu (CurrentTime); | |
1341 | |
1342 lw_display_menu (CurrentTime); | |
1343 | |
1344 /* menu accelerator keys don't go into keyboard macros */ | |
1345 if (!NILP (con->defining_kbd_macro) && NILP (Vexecuting_macro)) | |
1346 con->kbd_macro_ptr = con->kbd_macro_end; | |
1347 | |
1348 return Qnil; | |
1349 } | |
1350 #endif /* LWLIB_MENUBARS_LUCID */ | |
1351 | |
1352 | |
428 | 1353 void |
1354 syms_of_menubar_x (void) | |
1355 { | |
442 | 1356 #if defined(LWLIB_MENUBARS_LUCID) |
1357 DEFSUBR (Faccelerate_menu); | |
1358 #endif | |
428 | 1359 } |
1360 | |
1361 void | |
1362 console_type_create_menubar_x (void) | |
1363 { | |
1364 CONSOLE_HAS_METHOD (x, update_frame_menubars); | |
1365 CONSOLE_HAS_METHOD (x, free_frame_menubars); | |
1366 CONSOLE_HAS_METHOD (x, popup_menu); | |
1367 } | |
1368 | |
1369 void | |
1370 reinit_vars_of_menubar_x (void) | |
1371 { | |
1372 last_popup_menu_selection_callback_id = (LWLIB_ID) -1; | |
1373 } | |
1374 | |
1375 void | |
1376 vars_of_menubar_x (void) | |
1377 { | |
1378 #if defined (LWLIB_MENUBARS_LUCID) | |
1379 Fprovide (intern ("lucid-menubars")); | |
1380 #elif defined (LWLIB_MENUBARS_MOTIF) | |
1381 Fprovide (intern ("motif-menubars")); | |
1382 #elif defined (LWLIB_MENUBARS_ATHENA) | |
1383 Fprovide (intern ("athena-menubars")); | |
1384 #endif | |
1385 } |