Mercurial > hg > xemacs-beta
annotate src/gui-x.c @ 4766:32b358a240b0
Avoid calling Xft if not built in.
| author | Stephen J. Turnbull <stephen@xemacs.org> |
|---|---|
| date | Sat, 05 Dec 2009 01:02:33 +0900 |
| parents | 8f1ee2d15784 |
| children | 16112448d484 4aebb0131297 |
| rev | line source |
|---|---|
| 428 | 1 /* General GUI code -- X-specific. (menubars, scrollbars, toolbars, dialogs) |
| 2 Copyright (C) 1995 Board of Trustees, University of Illinois. | |
| 1261 | 3 Copyright (C) 1995, 1996, 2000, 2001, 2002, 2003 Ben Wing. |
| 428 | 4 Copyright (C) 1995 Sun Microsystems, Inc. |
| 5 Copyright (C) 1998 Free Software Foundation, Inc. | |
| 6 | |
| 7 This file is part of XEmacs. | |
| 8 | |
| 9 XEmacs is free software; you can redistribute it and/or modify it | |
| 10 under the terms of the GNU General Public License as published by the | |
| 11 Free Software Foundation; either version 2, or (at your option) any | |
| 12 later version. | |
| 13 | |
| 14 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
| 15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 17 for more details. | |
| 18 | |
| 19 You should have received a copy of the GNU General Public License | |
| 20 along with XEmacs; see the file COPYING. If not, write to | |
| 21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
| 22 Boston, MA 02111-1307, USA. */ | |
| 23 | |
| 24 /* Synched up with: Not in FSF. */ | |
| 25 | |
| 442 | 26 /* This file Mule-ized by Ben Wing, 7-8-00. */ |
| 27 | |
| 428 | 28 #include <config.h> |
| 29 #include "lisp.h" | |
| 30 | |
| 872 | 31 #include "buffer.h" |
| 32 #include "device-impl.h" | |
| 33 #include "events.h" | |
| 34 #include "frame.h" | |
| 35 #include "glyphs.h" | |
| 36 #include "gui.h" | |
| 37 #include "menubar.h" | |
| 38 #include "opaque.h" | |
| 39 #include "redisplay.h" | |
| 40 | |
| 41 #include "console-x-impl.h" | |
| 42 | |
| 428 | 43 #ifdef LWLIB_USES_MOTIF |
| 1315 | 44 #include "xmotif.h" /* for XmVersion */ |
| 428 | 45 #endif |
| 46 | |
| 47 /* we need a unique id for each popup menu, dialog box, and scrollbar */ | |
| 647 | 48 static LWLIB_ID lwlib_id_tick; |
| 428 | 49 |
| 50 LWLIB_ID | |
| 51 new_lwlib_id (void) | |
| 52 { | |
| 1346 | 53 lwlib_id_tick++; |
| 54 if (!lwlib_id_tick) | |
| 55 lwlib_id_tick++; | |
| 56 return lwlib_id_tick; | |
| 428 | 57 } |
| 58 | |
| 59 widget_value * | |
| 60 xmalloc_widget_value (void) | |
| 61 { | |
| 62 widget_value *tmp = malloc_widget_value (); | |
| 63 if (!tmp) memory_full (); | |
| 64 return tmp; | |
| 65 } | |
| 66 | |
| 67 | |
| 1346 | 68 |
| 69 /* This contains an alist of (id . protect-me) for GCPRO'ing the callbacks | |
| 70 of the popup menus and dialog boxes. */ | |
| 71 static Lisp_Object Vpopup_callbacks; | |
| 428 | 72 |
| 1346 | 73 struct widget_value_mapper |
| 74 { | |
| 75 Lisp_Object protect_me; | |
| 1204 | 76 }; |
| 77 | |
| 78 static int | |
| 79 snarf_widget_value_mapper (widget_value *val, void *closure) | |
| 80 { | |
| 1346 | 81 struct widget_value_mapper *z = (struct widget_value_mapper *) closure; |
| 1204 | 82 |
| 83 if (val->call_data) | |
| 1346 | 84 z->protect_me = Fcons (VOID_TO_LISP (val->call_data), z->protect_me); |
| 1204 | 85 if (val->accel) |
| 1346 | 86 z->protect_me = Fcons (VOID_TO_LISP (val->accel), z->protect_me); |
| 1204 | 87 |
| 88 return 0; | |
| 89 } | |
| 90 | |
| 1261 | 91 /* Snarf the callbacks and other Lisp data that are hidden in the lwlib |
| 1346 | 92 call-data and accel associated with id ID and return them for |
| 93 proper marking. */ | |
| 1261 | 94 |
| 1346 | 95 static Lisp_Object |
| 96 snarf_widget_values_for_gcpro (LWLIB_ID id) | |
| 1261 | 97 { |
| 1346 | 98 struct widget_value_mapper z; |
| 1261 | 99 |
| 1346 | 100 z.protect_me = Qnil; |
| 101 lw_map_widget_values (id, snarf_widget_value_mapper, &z); | |
| 102 return z.protect_me; | |
| 103 } | |
| 1261 | 104 |
| 1346 | 105 /* Given an lwlib id ID associated with a widget tree, make sure that all |
| 106 Lisp callbacks in the tree are GC-protected. This can be called | |
| 107 multiple times on the same widget tree -- this should be done at | |
| 108 creation time and each time the tree is modified. */ | |
| 1261 | 109 |
| 428 | 110 void |
| 111 gcpro_popup_callbacks (LWLIB_ID id) | |
| 112 { | |
| 113 Lisp_Object lid = make_int (id); | |
| 2552 | 114 Lisp_Object this_callback = assq_no_quit (lid, Vpopup_callbacks); |
| 428 | 115 |
| 2552 | 116 if (!NILP (this_callback)) |
| 1346 | 117 { |
| 2552 | 118 free_list (XCDR (this_callback)); |
| 119 XCDR (this_callback) = snarf_widget_values_for_gcpro (id); | |
| 1346 | 120 } |
| 121 else | |
| 122 Vpopup_callbacks = Fcons (Fcons (lid, snarf_widget_values_for_gcpro (id)), | |
| 123 Vpopup_callbacks); | |
| 124 } | |
| 1204 | 125 |
| 1346 | 126 /* Remove GC-protection from the just-destroyed widget tree associated |
| 127 with lwlib id ID. */ | |
| 428 | 128 |
| 129 void | |
| 130 ungcpro_popup_callbacks (LWLIB_ID id) | |
| 131 { | |
| 132 Lisp_Object lid = make_int (id); | |
| 2552 | 133 Lisp_Object this_callback = assq_no_quit (lid, Vpopup_callbacks); |
| 1346 | 134 |
| 2552 | 135 assert (!NILP (this_callback)); |
| 136 free_list (XCDR (this_callback)); | |
| 137 Vpopup_callbacks = delq_no_quit (this_callback, Vpopup_callbacks); | |
| 428 | 138 } |
| 139 | |
| 140 int | |
| 141 popup_handled_p (LWLIB_ID id) | |
| 142 { | |
| 143 return NILP (assq_no_quit (make_int (id), Vpopup_callbacks)); | |
| 144 } | |
| 145 | |
| 146 /* menu_item_descriptor_to_widget_value() et al. mallocs a | |
| 147 widget_value, but then may signal lisp errors. If an error does | |
| 148 not occur, the opaque ptr we have here has had its pointer set to 0 | |
| 149 to tell us not to do anything. Otherwise we free the widget value. | |
| 150 (This has nothing to do with GC, it's just about not dropping | |
| 151 pointers to malloc'd data when errors happen.) */ | |
| 152 | |
| 153 Lisp_Object | |
| 154 widget_value_unwind (Lisp_Object closure) | |
| 155 { | |
| 156 widget_value *wv = (widget_value *) get_opaque_ptr (closure); | |
| 157 free_opaque_ptr (closure); | |
| 158 if (wv) | |
| 436 | 159 free_widget_value_tree (wv); |
| 428 | 160 return Qnil; |
| 161 } | |
| 162 | |
| 163 #if 0 | |
| 164 static void | |
| 165 print_widget_value (widget_value *wv, int depth) | |
| 166 { | |
| 442 | 167 /* strings in wv are in external format; use printf not stdout_out |
| 168 because the latter takes internal-format strings */ | |
| 169 Extbyte d [200]; | |
| 428 | 170 int i; |
| 171 for (i = 0; i < depth; i++) d[i] = ' '; | |
| 172 d[depth]=0; | |
| 173 /* #### - print type field */ | |
| 174 printf ("%sname: %s\n", d, (wv->name ? wv->name : "(null)")); | |
| 175 if (wv->value) printf ("%svalue: %s\n", d, wv->value); | |
| 176 if (wv->key) printf ("%skey: %s\n", d, wv->key); | |
| 177 printf ("%senabled: %d\n", d, wv->enabled); | |
| 178 if (wv->contents) | |
| 179 { | |
| 180 printf ("\n%scontents: \n", d); | |
| 181 print_widget_value (wv->contents, depth + 5); | |
| 182 } | |
| 183 if (wv->next) | |
| 184 { | |
| 185 printf ("\n"); | |
| 186 print_widget_value (wv->next, depth); | |
| 187 } | |
| 188 } | |
| 189 #endif | |
| 190 | |
| 191 /* This recursively calls free_widget_value() on the tree of widgets. | |
| 192 It must free all data that was malloc'ed for these widget_values. | |
| 193 | |
| 194 It used to be that emacs only allocated new storage for the `key' slot. | |
| 195 All other slots are pointers into the data of Lisp_Strings, and must be | |
| 196 left alone. */ | |
| 197 void | |
| 198 free_popup_widget_value_tree (widget_value *wv) | |
| 199 { | |
| 200 if (! wv) return; | |
| 1726 | 201 if (wv->key) xfree (wv->key, char *); |
| 202 if (wv->value) xfree (wv->value, char *); | |
| 203 if (wv->name) xfree (wv->name, char *); | |
| 428 | 204 |
| 1204 | 205 wv->name = wv->value = wv->key = (char *) 0xDEADBEEF; /* -559038737 base 10*/ |
| 428 | 206 |
| 207 if (wv->contents && (wv->contents != (widget_value*)1)) | |
| 208 { | |
| 209 free_popup_widget_value_tree (wv->contents); | |
| 210 wv->contents = (widget_value *) 0xDEADBEEF; | |
| 211 } | |
| 212 if (wv->next) | |
| 213 { | |
| 214 free_popup_widget_value_tree (wv->next); | |
| 215 wv->next = (widget_value *) 0xDEADBEEF; | |
| 216 } | |
| 217 free_widget_value (wv); | |
| 218 } | |
| 219 | |
| 220 /* The following is actually called from somewhere within XtDispatchEvent(), | |
| 2168 | 221 called from XtAppProcessEvent() in event-Xt.c. |
| 222 | |
| 223 Callback function for widgets and menus. | |
| 224 */ | |
| 428 | 225 |
| 226 void | |
| 2286 | 227 popup_selection_callback (Widget widget, LWLIB_ID UNUSED (id), |
| 428 | 228 XtPointer client_data) |
| 229 { | |
| 442 | 230 Lisp_Object data, image_instance, callback, callback_ex; |
| 231 Lisp_Object frame, event; | |
| 232 int update_subwindows_p = 0; | |
| 428 | 233 struct device *d = get_device_from_display (XtDisplay (widget)); |
| 234 struct frame *f = x_any_widget_or_parent_to_frame (d, widget); | |
| 235 | |
| 872 | 236 #ifdef HAVE_MENUBARS |
| 428 | 237 /* set in lwlib to the time stamp associated with the most recent menu |
| 238 operation */ | |
| 239 extern Time x_focus_timestamp_really_sucks_fix_me_better; | |
| 872 | 240 #endif |
| 428 | 241 |
| 242 if (!f) | |
| 243 return; | |
| 244 if (((EMACS_INT) client_data) == 0) | |
| 245 return; | |
| 826 | 246 data = VOID_TO_LISP (client_data); |
| 793 | 247 frame = wrap_frame (f); |
| 428 | 248 |
| 249 #if 0 | |
| 250 /* #### What the hell? I can't understand why this call is here, | |
| 251 and doing it is really courting disaster in the new event | |
| 252 model, since popup_selection_callback is called from | |
| 253 within next_event_internal() and Faccept_process_output() | |
| 254 itself calls next_event_internal(). --Ben */ | |
| 255 | |
| 256 /* Flush the X and process input */ | |
| 257 Faccept_process_output (Qnil, Qnil, Qnil); | |
| 258 #endif | |
| 259 | |
| 260 if (((EMACS_INT) client_data) == -1) | |
| 261 { | |
| 442 | 262 event = Fmake_event (Qnil, Qnil); |
| 263 | |
| 934 | 264 XSET_EVENT_TYPE (event, misc_user_event); |
| 265 XSET_EVENT_CHANNEL (event, frame); | |
| 1204 | 266 XSET_EVENT_MISC_USER_FUNCTION (event, Qrun_hooks); |
| 267 XSET_EVENT_MISC_USER_OBJECT (event, Qmenu_no_selection_hook); | |
| 428 | 268 } |
| 269 else | |
| 270 { | |
| 442 | 271 image_instance = XCAR (data); |
| 272 callback = XCAR (XCDR (data)); | |
| 273 callback_ex = XCDR (XCDR (data)); | |
| 274 update_subwindows_p = 1; | |
| 275 /* It is possible for a widget action to cause it to get out of | |
| 276 sync with its instantiator. Thus it is necessary to signal | |
| 277 this possibility. */ | |
| 278 if (IMAGE_INSTANCEP (image_instance)) | |
| 279 XIMAGE_INSTANCE_WIDGET_ACTION_OCCURRED (image_instance) = 1; | |
| 280 | |
| 281 if (!NILP (callback_ex) && !UNBOUNDP (callback_ex)) | |
| 282 { | |
| 283 event = Fmake_event (Qnil, Qnil); | |
| 284 | |
| 934 | 285 XSET_EVENT_TYPE (event, misc_user_event); |
| 286 XSET_EVENT_CHANNEL (event, frame); | |
| 1204 | 287 XSET_EVENT_MISC_USER_FUNCTION (event, Qeval); |
| 288 XSET_EVENT_MISC_USER_OBJECT (event, list4 (Qfuncall, callback_ex, image_instance, event)); | |
| 442 | 289 } |
| 290 else if (NILP (callback) || UNBOUNDP (callback)) | |
| 291 event = Qnil; | |
| 292 else | |
| 293 { | |
| 294 Lisp_Object fn, arg; | |
| 295 | |
| 296 event = Fmake_event (Qnil, Qnil); | |
| 297 | |
| 298 get_gui_callback (callback, &fn, &arg); | |
| 934 | 299 XSET_EVENT_TYPE (event, misc_user_event); |
| 300 XSET_EVENT_CHANNEL (event, frame); | |
| 1204 | 301 XSET_EVENT_MISC_USER_FUNCTION (event, fn); |
| 302 XSET_EVENT_MISC_USER_OBJECT (event, arg); | |
| 442 | 303 } |
| 428 | 304 } |
| 305 | |
| 306 /* This is the timestamp used for asserting focus so we need to get an | |
| 444 | 307 up-to-date value event if no events have been dispatched to emacs |
| 428 | 308 */ |
| 872 | 309 #ifdef HAVE_MENUBARS |
| 428 | 310 DEVICE_X_MOUSE_TIMESTAMP (d) = x_focus_timestamp_really_sucks_fix_me_better; |
| 311 #else | |
| 312 DEVICE_X_MOUSE_TIMESTAMP (d) = DEVICE_X_GLOBAL_MOUSE_TIMESTAMP (d); | |
| 313 #endif | |
| 442 | 314 if (!NILP (event)) |
| 1204 | 315 enqueue_dispatch_event (event); |
| 442 | 316 /* The result of this evaluation could cause other instances to change so |
| 317 enqueue an update callback to check this. */ | |
| 318 if (update_subwindows_p && !NILP (event)) | |
| 319 enqueue_magic_eval_event (update_widget_instances, frame); | |
| 428 | 320 } |
| 321 | |
| 322 #if 1 | |
| 323 /* Eval the activep slot of the menu item */ | |
| 1914 | 324 # define wv_set_evalable_slot(slot,form) do { \ |
| 325 Lisp_Object wses_form = (form); \ | |
| 326 (slot) = (NILP (wses_form) ? 0 : \ | |
| 327 EQ (wses_form, Qt) ? 1 : \ | |
|
4677
8f1ee2d15784
Support full Common Lisp multiple values in C.
Aidan Kehoe <kehoea@parhasard.net>
parents:
2552
diff
changeset
|
328 !NILP (in_display ? \ |
|
8f1ee2d15784
Support full Common Lisp multiple values in C.
Aidan Kehoe <kehoea@parhasard.net>
parents:
2552
diff
changeset
|
329 IGNORE_MULTIPLE_VALUES (eval_within_redisplay (wses_form)) \ |
|
8f1ee2d15784
Support full Common Lisp multiple values in C.
Aidan Kehoe <kehoea@parhasard.net>
parents:
2552
diff
changeset
|
330 : IGNORE_MULTIPLE_VALUES (Feval (wses_form)))); \ |
| 428 | 331 } while (0) |
| 332 #else | |
| 333 /* Treat the activep slot of the menu item as a boolean */ | |
| 334 # define wv_set_evalable_slot(slot,form) \ | |
| 335 ((void) (slot = (!NILP (form)))) | |
| 336 #endif | |
| 337 | |
| 442 | 338 Extbyte * |
| 867 | 339 menu_separator_style_and_to_external (const Ibyte *s) |
| 428 | 340 { |
| 867 | 341 const Ibyte *p; |
| 342 Ibyte first; | |
| 428 | 343 |
| 344 if (!s || s[0] == '\0') | |
| 345 return NULL; | |
| 346 first = s[0]; | |
| 347 if (first != '-' && first != '=') | |
| 348 return NULL; | |
| 349 for (p = s; *p == first; p++) | |
| 350 DO_NOTHING; | |
| 351 | |
| 352 /* #### - cannot currently specify a separator tag "--!tag" and a | |
| 353 separator style "--:style" at the same time. */ | |
| 354 /* #### - Also, the motif menubar code doesn't deal with the | |
| 355 double etched style yet, so it's not good to get into the habit of | |
| 356 using "===" in menubars to get double-etched lines */ | |
| 357 if (*p == '!' || *p == '\0') | |
| 358 return ((first == '-') | |
| 359 ? NULL /* single etched is the default */ | |
| 360 : xstrdup ("shadowDoubleEtchedIn")); | |
| 361 else if (*p == ':') | |
| 442 | 362 { |
| 363 Extbyte *retval; | |
| 364 | |
| 365 C_STRING_TO_EXTERNAL_MALLOC (p + 1, retval, Qlwlib_encoding); | |
| 366 return retval; | |
| 367 } | |
| 428 | 368 |
| 369 return NULL; | |
| 370 } | |
| 371 | |
| 442 | 372 Extbyte * |
| 373 add_accel_and_to_external (Lisp_Object string) | |
| 374 { | |
| 375 int i; | |
| 376 int found_accel = 0; | |
| 377 Extbyte *retval; | |
| 867 | 378 Ibyte *name = XSTRING_DATA (string); |
| 442 | 379 |
| 380 for (i = 0; name[i]; ++i) | |
| 381 if (name[i] == '%' && name[i+1] == '_') | |
| 382 { | |
| 383 found_accel = 1; | |
| 384 break; | |
| 385 } | |
| 386 | |
| 387 if (found_accel) | |
| 388 LISP_STRING_TO_EXTERNAL_MALLOC (string, retval, Qlwlib_encoding); | |
| 389 else | |
| 390 { | |
| 647 | 391 Bytecount namelen = XSTRING_LENGTH (string); |
| 2367 | 392 Ibyte *chars = alloca_ibytes (namelen + 3); |
| 442 | 393 chars[0] = '%'; |
| 394 chars[1] = '_'; | |
| 395 memcpy (chars + 2, name, namelen + 1); | |
| 396 C_STRING_TO_EXTERNAL_MALLOC (chars, retval, Qlwlib_encoding); | |
| 397 } | |
| 398 | |
| 399 return retval; | |
| 400 } | |
| 428 | 401 |
| 853 | 402 /* This does the dirty work. GC is inhibited when this is called. |
| 403 */ | |
| 428 | 404 int |
| 442 | 405 button_item_to_widget_value (Lisp_Object gui_object_instance, |
| 406 Lisp_Object gui_item, widget_value *wv, | |
| 407 int allow_text_field_p, int no_keys_p, | |
| 408 int menu_entry_p, int accel_p) | |
| 428 | 409 { |
| 853 | 410 /* This function cannot GC because GC is inhibited when it's called */ |
| 440 | 411 Lisp_Gui_Item* pgui = 0; |
| 428 | 412 |
| 413 /* degenerate case */ | |
| 414 if (STRINGP (gui_item)) | |
| 415 { | |
| 416 wv->type = TEXT_TYPE; | |
| 442 | 417 if (accel_p) |
| 418 wv->name = add_accel_and_to_external (gui_item); | |
| 419 else | |
| 420 LISP_STRING_TO_EXTERNAL_MALLOC (gui_item, wv->name, Qlwlib_encoding); | |
| 428 | 421 return 1; |
| 422 } | |
| 423 else if (!GUI_ITEMP (gui_item)) | |
| 563 | 424 invalid_argument ("need a string or a gui_item here", gui_item); |
| 428 | 425 |
| 426 pgui = XGUI_ITEM (gui_item); | |
| 427 | |
| 428 if (!NILP (pgui->filter)) | |
| 563 | 429 sferror (":filter keyword not permitted on leaf nodes", gui_item); |
| 428 | 430 |
| 431 #ifdef HAVE_MENUBARS | |
| 442 | 432 if (menu_entry_p && !gui_item_included_p (gui_item, Vmenubar_configuration)) |
| 428 | 433 { |
| 434 /* the include specification says to ignore this item. */ | |
| 435 return 0; | |
| 436 } | |
| 437 #endif /* HAVE_MENUBARS */ | |
| 438 | |
| 442 | 439 if (!STRINGP (pgui->name)) |
|
4677
8f1ee2d15784
Support full Common Lisp multiple values in C.
Aidan Kehoe <kehoea@parhasard.net>
parents:
2552
diff
changeset
|
440 pgui->name = IGNORE_MULTIPLE_VALUES (Feval (pgui->name)); |
| 442 | 441 |
| 428 | 442 CHECK_STRING (pgui->name); |
| 442 | 443 if (accel_p) |
| 444 { | |
| 445 wv->name = add_accel_and_to_external (pgui->name); | |
| 446 wv->accel = LISP_TO_VOID (gui_item_accelerator (gui_item)); | |
| 447 } | |
| 448 else | |
| 449 { | |
| 450 LISP_STRING_TO_EXTERNAL_MALLOC (pgui->name, wv->name, Qlwlib_encoding); | |
| 451 wv->accel = LISP_TO_VOID (Qnil); | |
| 452 } | |
| 428 | 453 |
| 454 if (!NILP (pgui->suffix)) | |
| 455 { | |
| 456 Lisp_Object suffix2; | |
| 457 | |
| 458 /* Shortcut to avoid evaluating suffix each time */ | |
| 459 if (STRINGP (pgui->suffix)) | |
| 460 suffix2 = pgui->suffix; | |
| 461 else | |
| 462 { | |
|
4677
8f1ee2d15784
Support full Common Lisp multiple values in C.
Aidan Kehoe <kehoea@parhasard.net>
parents:
2552
diff
changeset
|
463 suffix2 = IGNORE_MULTIPLE_VALUES (Feval (pgui->suffix)); |
| 428 | 464 CHECK_STRING (suffix2); |
| 465 } | |
| 466 | |
| 442 | 467 LISP_STRING_TO_EXTERNAL_MALLOC (suffix2, wv->value, Qlwlib_encoding); |
| 428 | 468 } |
| 469 | |
| 470 wv_set_evalable_slot (wv->enabled, pgui->active); | |
| 471 wv_set_evalable_slot (wv->selected, pgui->selected); | |
| 472 | |
| 442 | 473 if (!NILP (pgui->callback) || !NILP (pgui->callback_ex)) |
| 474 wv->call_data = LISP_TO_VOID (cons3 (gui_object_instance, | |
| 475 pgui->callback, | |
| 476 pgui->callback_ex)); | |
| 428 | 477 |
| 478 if (no_keys_p | |
| 479 #ifdef HAVE_MENUBARS | |
| 442 | 480 || (menu_entry_p && !menubar_show_keybindings) |
| 428 | 481 #endif |
| 482 ) | |
| 483 wv->key = 0; | |
| 484 else if (!NILP (pgui->keys)) /* Use this string to generate key bindings */ | |
| 485 { | |
| 486 CHECK_STRING (pgui->keys); | |
| 487 pgui->keys = Fsubstitute_command_keys (pgui->keys); | |
| 488 if (XSTRING_LENGTH (pgui->keys) > 0) | |
| 442 | 489 LISP_STRING_TO_EXTERNAL_MALLOC (pgui->keys, wv->key, Qlwlib_encoding); |
| 428 | 490 else |
| 491 wv->key = 0; | |
| 492 } | |
| 493 else if (SYMBOLP (pgui->callback)) /* Show the binding of this command. */ | |
| 494 { | |
| 793 | 495 DECLARE_EISTRING_MALLOC (buf); |
| 428 | 496 /* #### Warning, dependency here on current_buffer and point */ |
| 497 where_is_to_char (pgui->callback, buf); | |
| 793 | 498 if (eilen (buf) > 0) |
| 499 C_STRING_TO_EXTERNAL_MALLOC (eidata (buf), wv->key, Qlwlib_encoding); | |
| 428 | 500 else |
| 501 wv->key = 0; | |
| 793 | 502 eifree (buf); |
| 428 | 503 } |
| 504 | |
| 505 CHECK_SYMBOL (pgui->style); | |
| 506 if (NILP (pgui->style)) | |
| 507 { | |
| 867 | 508 Ibyte *intname; |
| 2286 | 509 Bytecount unused_intlen; |
| 428 | 510 /* If the callback is nil, treat this item like unselectable text. |
| 511 This way, dashes will show up as a separator. */ | |
| 512 if (!wv->enabled) | |
| 513 wv->type = BUTTON_TYPE; | |
| 444 | 514 TO_INTERNAL_FORMAT (C_STRING, wv->name, |
| 2286 | 515 ALLOCA, (intname, unused_intlen), |
| 444 | 516 Qlwlib_encoding); |
| 442 | 517 if (separator_string_p (intname)) |
| 428 | 518 { |
| 519 wv->type = SEPARATOR_TYPE; | |
| 442 | 520 wv->value = menu_separator_style_and_to_external (intname); |
| 428 | 521 } |
| 522 else | |
| 523 { | |
| 524 #if 0 | |
| 525 /* #### - this is generally desirable for menubars, but it breaks | |
| 526 a package that uses dialog boxes and next_command_event magic | |
| 527 to use the callback slot in dialog buttons for data instead of | |
| 528 a real callback. | |
| 529 | |
| 530 Code is data, right? The beauty of LISP abuse. --Stig */ | |
| 531 if (NILP (callback)) | |
| 532 wv->type = TEXT_TYPE; | |
| 533 else | |
| 534 #endif | |
| 535 wv->type = BUTTON_TYPE; | |
| 536 } | |
| 537 } | |
| 538 else if (EQ (pgui->style, Qbutton)) | |
| 539 wv->type = BUTTON_TYPE; | |
| 540 else if (EQ (pgui->style, Qtoggle)) | |
| 541 wv->type = TOGGLE_TYPE; | |
| 542 else if (EQ (pgui->style, Qradio)) | |
| 543 wv->type = RADIO_TYPE; | |
| 544 else if (EQ (pgui->style, Qtext)) | |
| 545 { | |
| 546 wv->type = TEXT_TYPE; | |
| 547 #if 0 | |
| 548 wv->value = wv->name; | |
| 549 wv->name = "value"; | |
| 550 #endif | |
| 551 } | |
| 552 else | |
| 563 | 553 invalid_constant_2 ("Unknown style", pgui->style, gui_item); |
| 428 | 554 |
| 555 if (!allow_text_field_p && (wv->type == TEXT_TYPE)) | |
| 563 | 556 sferror ("Text field not allowed in this context", gui_item); |
| 428 | 557 |
| 558 if (!NILP (pgui->selected) && EQ (pgui->style, Qtext)) | |
| 563 | 559 sferror |
| 442 | 560 (":selected only makes sense with :style toggle, radio or button", |
| 561 gui_item); | |
| 428 | 562 return 1; |
| 563 } | |
| 564 | |
| 565 /* parse tree's of gui items into widget_value hierarchies */ | |
| 442 | 566 static void gui_item_children_to_widget_values (Lisp_Object |
| 567 gui_object_instance, | |
| 568 Lisp_Object items, | |
| 569 widget_value* parent, | |
| 570 int accel_p); | |
| 428 | 571 |
| 572 static widget_value * | |
| 442 | 573 gui_items_to_widget_values_1 (Lisp_Object gui_object_instance, |
| 574 Lisp_Object items, widget_value* parent, | |
| 575 widget_value* prev, int accel_p) | |
| 428 | 576 { |
| 577 widget_value* wv = 0; | |
| 578 | |
| 579 assert ((parent || prev) && !(parent && prev)); | |
| 580 /* now walk the tree creating widget_values as appropriate */ | |
| 581 if (!CONSP (items)) | |
| 582 { | |
| 442 | 583 wv = xmalloc_widget_value (); |
| 428 | 584 if (parent) |
| 585 parent->contents = wv; | |
| 440 | 586 else |
| 428 | 587 prev->next = wv; |
| 442 | 588 if (!button_item_to_widget_value (gui_object_instance, |
| 589 items, wv, 0, 1, 0, accel_p)) | |
| 428 | 590 { |
| 436 | 591 free_widget_value_tree (wv); |
| 428 | 592 if (parent) |
| 593 parent->contents = 0; | |
| 440 | 594 else |
| 428 | 595 prev->next = 0; |
| 596 } | |
| 440 | 597 else |
| 442 | 598 wv->value = xstrdup (wv->name); /* what a mess... */ |
| 428 | 599 } |
| 600 else | |
| 601 { | |
| 602 /* first one is the parent */ | |
| 603 if (CONSP (XCAR (items))) | |
| 563 | 604 sferror ("parent item must not be a list", XCAR (items)); |
| 428 | 605 |
| 606 if (parent) | |
| 442 | 607 wv = gui_items_to_widget_values_1 (gui_object_instance, |
| 608 XCAR (items), parent, 0, accel_p); | |
| 428 | 609 else |
| 442 | 610 wv = gui_items_to_widget_values_1 (gui_object_instance, |
| 611 XCAR (items), 0, prev, accel_p); | |
| 428 | 612 /* the rest are the children */ |
| 442 | 613 gui_item_children_to_widget_values (gui_object_instance, |
| 614 XCDR (items), wv, accel_p); | |
| 428 | 615 } |
| 616 return wv; | |
| 617 } | |
| 618 | |
| 619 static void | |
| 442 | 620 gui_item_children_to_widget_values (Lisp_Object gui_object_instance, |
| 621 Lisp_Object items, widget_value* parent, | |
| 622 int accel_p) | |
| 428 | 623 { |
| 624 widget_value* wv = 0, *prev = 0; | |
| 625 Lisp_Object rest; | |
| 626 CHECK_CONS (items); | |
| 627 | |
| 628 /* first one is master */ | |
| 442 | 629 prev = gui_items_to_widget_values_1 (gui_object_instance, XCAR (items), |
| 630 parent, 0, accel_p); | |
| 428 | 631 /* the rest are the children */ |
| 632 LIST_LOOP (rest, XCDR (items)) | |
| 633 { | |
| 634 Lisp_Object tab = XCAR (rest); | |
| 442 | 635 wv = gui_items_to_widget_values_1 (gui_object_instance, tab, 0, prev, |
| 636 accel_p); | |
| 428 | 637 prev = wv; |
| 638 } | |
| 639 } | |
| 640 | |
| 641 widget_value * | |
| 442 | 642 gui_items_to_widget_values (Lisp_Object gui_object_instance, Lisp_Object items, |
| 643 int accel_p) | |
| 428 | 644 { |
| 645 /* This function can GC */ | |
| 646 widget_value *control = 0, *tmp = 0; | |
| 771 | 647 int count; |
| 428 | 648 Lisp_Object wv_closure; |
| 649 | |
| 650 if (NILP (items)) | |
| 563 | 651 sferror ("must have some items", items); |
| 428 | 652 |
| 653 /* Inhibit GC during this conversion. The reasons for this are | |
| 654 the same as in menu_item_descriptor_to_widget_value(); see | |
| 655 the large comment above that function. */ | |
| 771 | 656 count = begin_gc_forbidden (); |
| 428 | 657 |
| 658 /* Also make sure that we free the partially-created widget_value | |
| 659 tree on Lisp error. */ | |
| 442 | 660 control = xmalloc_widget_value (); |
| 428 | 661 wv_closure = make_opaque_ptr (control); |
| 662 record_unwind_protect (widget_value_unwind, wv_closure); | |
| 663 | |
| 442 | 664 gui_items_to_widget_values_1 (gui_object_instance, items, control, 0, |
| 665 accel_p); | |
| 428 | 666 |
| 667 /* mess about getting the data we really want */ | |
| 668 tmp = control; | |
| 669 control = control->contents; | |
| 670 tmp->next = 0; | |
| 671 tmp->contents = 0; | |
| 436 | 672 free_widget_value_tree (tmp); |
| 428 | 673 |
| 674 /* No more need to free the half-filled-in structures. */ | |
| 675 set_opaque_ptr (wv_closure, 0); | |
| 771 | 676 unbind_to (count); |
| 428 | 677 |
| 678 return control; | |
| 679 } | |
| 680 | |
| 681 void | |
| 682 syms_of_gui_x (void) | |
| 683 { | |
| 684 } | |
| 685 | |
| 686 void | |
| 687 reinit_vars_of_gui_x (void) | |
| 688 { | |
| 689 lwlib_id_tick = (1<<16); /* start big, to not conflict with Energize */ | |
| 690 #ifdef HAVE_POPUPS | |
| 691 popup_up_p = 0; | |
| 692 #endif | |
| 693 } | |
| 694 | |
| 695 void | |
| 696 vars_of_gui_x (void) | |
| 697 { | |
| 698 Vpopup_callbacks = Qnil; | |
| 699 staticpro (&Vpopup_callbacks); | |
| 700 } |
