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