Mercurial > hg > xemacs-beta
annotate src/gui-x.c @ 4888:c27efc9acb5a
merge
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Wed, 27 Jan 2010 00:37:59 -0600 |
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 } |