XEmacs 21.2.7
[chise/xemacs-chise.git.1] / src / gui.c
1 /* Generic GUI code. (menubars, scrollbars, toolbars, dialogs)
2    Copyright (C) 1995 Board of Trustees, University of Illinois.
3    Copyright (C) 1995, 1996 Ben Wing.
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
26 #include <config.h>
27 #include "lisp.h"
28 #include "gui.h"
29 #include "elhash.h"
30 #include "bytecode.h"
31
32 Lisp_Object Q_active, Q_suffix, Q_keys, Q_style, Q_selected;
33 Lisp_Object Q_filter, Q_config, Q_included, Q_key_sequence;
34 Lisp_Object Q_accelerator, Q_label;
35 Lisp_Object Qtoggle, Qradio;
36
37 #ifdef HAVE_POPUPS
38
39 /* count of menus/dboxes currently up */
40 int popup_up_p;
41
42 DEFUN ("popup-up-p", Fpopup_up_p, 0, 0, 0, /*
43 Return t if a popup menu or dialog box is up, nil otherwise.
44 See `popup-menu' and `popup-dialog-box'.
45 */
46        ())
47 {
48   return popup_up_p ? Qt : Qnil;
49 }
50 #endif /* HAVE_POPUPS */
51
52 int
53 separator_string_p (CONST char *s)
54 {
55   CONST char *p;
56   char first;
57
58   if (!s || s[0] == '\0')
59     return 0;
60   first = s[0];
61   if (first != '-' && first != '=')
62     return 0;
63   for (p = s; *p == first; p++)
64     ;
65
66   return (*p == '!' || *p == ':' || *p == '\0');
67 }
68
69 /* Massage DATA to find the correct function and argument.  Used by
70    popup_selection_callback() and the msw code. */
71 void
72 get_gui_callback (Lisp_Object data, Lisp_Object *fn, Lisp_Object *arg)
73 {
74   if (SYMBOLP (data)
75       || (COMPILED_FUNCTIONP (data)
76           && XCOMPILED_FUNCTION (data)->flags.interactivep)
77       || (EQ (XCAR (data), Qlambda)
78           && !NILP (Fassq (Qinteractive, Fcdr (Fcdr (data))))))
79     {
80       *fn = Qcall_interactively;
81       *arg = data;
82     }
83   else if (CONSP (data))
84     {
85       *fn = Qeval;
86       *arg = data;
87     }
88   else
89     {
90       *fn = Qeval;
91       *arg = list3 (Qsignal,
92                     list2 (Qquote, Qerror),
93                     list2 (Qquote, list2 (build_translated_string
94                                           ("illegal callback"),
95                                           data)));
96     }
97 }
98
99 /*
100  * Initialize the gui_item structure by setting all (GC-protected)
101  * fields to their default values. The defaults are t for :active and
102  * :included values, and nil for others.
103  */
104 void
105 gui_item_init (struct gui_item *pgui_item)
106 {
107   pgui_item->name     = Qnil;
108   pgui_item->callback = Qnil;
109   pgui_item->suffix   = Qnil;
110   pgui_item->active   = Qt;
111   pgui_item->included = Qt;
112   pgui_item->config   = Qnil;
113   pgui_item->filter   = Qnil;
114   pgui_item->style    = Qnil;
115   pgui_item->selected = Qnil;
116   pgui_item->keys     = Qnil;
117 }
118
119 /*
120  * Add a value VAL associated with keyword KEY into PGUI_ITEM
121  * structure. If KEY is not a keyword, or is an unknown keyword, then
122  * error is signaled.
123  */
124 void
125 gui_item_add_keyval_pair (struct gui_item *pgui_item,
126                           Lisp_Object key, Lisp_Object val)
127 {
128   if (!KEYWORDP (key))
129     signal_simple_error_2 ("Non-keyword in gui item", key, pgui_item->name);
130
131   if      (EQ (key, Q_suffix))   pgui_item->suffix   = val;
132   else if (EQ (key, Q_active))   pgui_item->active   = val;
133   else if (EQ (key, Q_included)) pgui_item->included = val;
134   else if (EQ (key, Q_config))   pgui_item->config   = val;
135   else if (EQ (key, Q_filter))   pgui_item->filter   = val;
136   else if (EQ (key, Q_style))    pgui_item->style    = val;
137   else if (EQ (key, Q_selected)) pgui_item->selected = val;
138   else if (EQ (key, Q_keys))     pgui_item->keys     = val;
139   else if (EQ (key, Q_key_sequence)) ;   /* ignored for FSF compatability */
140   else if (EQ (key, Q_label)) ;   /* ignored for 21.0 implement in 21.2  */
141   else
142     signal_simple_error_2 ("Unknown keyword in gui item", key, pgui_item->name);
143 }
144
145 /*
146  * ITEM is a lisp vector, describing a menu item or a button. The
147  * function extracts the description of the item into the PGUI_ITEM
148  * structure.
149  */
150 void
151 gui_parse_item_keywords (Lisp_Object item, struct gui_item *pgui_item)
152 {
153   int length, plist_p, start;
154   Lisp_Object *contents;
155
156   CHECK_VECTOR (item);
157   length = XVECTOR_LENGTH (item);
158   contents = XVECTOR_DATA (item);
159
160   if (length < 1)
161     signal_simple_error ("GUI item descriptors must be at least 1 elts long", item);
162
163   /* length 1:                  [ "name" ]
164      length 2:          [ "name" callback ]
165      length 3:          [ "name" callback active-p ]
166                    or   [ "name" keyword  value  ]
167      length 4:          [ "name" callback active-p suffix ]
168                    or   [ "name" callback keyword  value  ]
169      length 5+:         [ "name" callback [ keyword value ]+ ]
170                    or   [ "name" [ keyword value ]+ ]
171   */
172   plist_p = (length > 2 && (KEYWORDP (contents [1])
173                             || KEYWORDP (contents [2])));
174
175   pgui_item->name = contents [0];
176   if (length > 1 && !KEYWORDP (contents [1]))
177     {
178       pgui_item->callback = contents [1];
179       start = 2;
180     }
181   else 
182     start =1;
183
184   if (!plist_p && length > 2)
185     /* the old way */
186     {
187       pgui_item->active = contents [2];
188       if (length == 4)
189         pgui_item->suffix = contents [3];
190     }
191   else
192     /* the new way */
193     {
194       int i;
195       if ((length - start) & 1)
196         signal_simple_error (
197                 "GUI item descriptor has an odd number of keywords and values",
198                              item);
199
200       for (i = start; i < length;)
201         {
202           Lisp_Object key = contents [i++];
203           Lisp_Object val = contents [i++];
204           gui_item_add_keyval_pair (pgui_item, key, val);
205         }
206     }
207 }
208
209 /*
210  * Decide whether a GUI item is active by evaluating its :active form
211  * if any
212  */
213 int
214 gui_item_active_p (CONST struct gui_item *pgui_item)
215 {
216   /* This function can call lisp */
217
218   /* Shortcut to avoid evaluating Qt each time */
219   return (EQ (pgui_item->active, Qt)
220           || !NILP (Feval (pgui_item->active)));
221 }
222
223 /*
224  * Decide whether a GUI item is selected by evaluating its :selected form
225  * if any
226  */
227 int
228 gui_item_selected_p (CONST struct gui_item *pgui_item)
229 {
230   /* This function can call lisp */
231
232   /* Shortcut to avoid evaluating Qt each time */
233   return (EQ (pgui_item->selected, Qt)
234           || !NILP (Feval (pgui_item->selected)));
235 }
236
237 /*
238  * Decide whether a GUI item is included by evaluating its :included
239  * form if given, and testing its :config form against supplied CONFLIST
240  * configuration variable
241  */
242 int
243 gui_item_included_p (CONST struct gui_item *pgui_item, Lisp_Object conflist)
244 {
245   /* This function can call lisp */
246
247   /* Evaluate :included first. Shortcut to avoid evaluating Qt each time */
248   if (!EQ (pgui_item->included, Qt)
249       && NILP (Feval (pgui_item->included)))
250     return 0;
251
252   /* Do :config if conflist is given */
253   if (!NILP (conflist) && !NILP (pgui_item->config)
254       && NILP (Fmemq (pgui_item->config, conflist)))
255     return 0;
256
257   return 1;
258 }
259
260 static DOESNT_RETURN
261 signal_too_long_error (Lisp_Object name)
262 {
263   signal_simple_error ("GUI item produces too long displayable string", name);
264 }
265
266 #ifdef HAVE_WINDOW_SYSTEM
267 /*
268  * Format "left flush" display portion of an item into BUF, guarded by
269  * maximum buffer size BUF_LEN. BUF_LEN does not count for terminating
270  * null character, so actual maximum size of buffer consumed is
271  * BUF_LEN + 1 bytes. If buffer is not big enough, then error is
272  * signaled.
273  * Return value is the offset to the terminating null character into the
274  * buffer.
275  */
276 unsigned int
277 gui_item_display_flush_left  (CONST struct gui_item *pgui_item,
278                               char* buf, Bytecount buf_len)
279 {
280   char *p = buf;
281   Bytecount len;
282
283   /* Copy item name first */
284   CHECK_STRING (pgui_item->name);
285   len = XSTRING_LENGTH (pgui_item->name);
286   if (len > buf_len)
287     signal_too_long_error (pgui_item->name);
288   memcpy (p, XSTRING_DATA (pgui_item->name), len);
289   p += len;
290
291   /* Add space and suffix, if there is a suffix.
292    * If suffix is not string evaluate it */
293   if (!NILP (pgui_item->suffix))
294     {
295       Lisp_Object suffix = pgui_item->suffix;
296       /* Shortcut to avoid evaluating suffix each time */
297       if (!STRINGP (suffix))
298         {
299           suffix = Feval (suffix);
300           CHECK_STRING (suffix);
301         }
302
303       len = XSTRING_LENGTH (suffix);
304       if (p + len + 1 > buf + buf_len)
305         signal_too_long_error (pgui_item->name);
306       *(p++) = ' ';
307       memcpy (p, XSTRING_DATA (suffix), len);
308       p += len;
309     }
310   *p = '\0';
311   return p - buf;
312 }
313
314 /*
315  * Format "right flush" display portion of an item into BUF, guarded by
316  * maximum buffer size BUF_LEN. BUF_LEN does not count for terminating
317  * null character, so actual maximum size of buffer consumed is
318  * BUF_LEN + 1 bytes. If buffer is not big enough, then error is
319  * signaled.
320  * Return value is the offset to the terminating null character into the
321  * buffer.
322  */
323 unsigned int
324 gui_item_display_flush_right (CONST struct gui_item *pgui_item,
325                               char* buf, Bytecount buf_len)
326 {
327   *buf = 0;
328
329   /* Have keys? */
330   if (!menubar_show_keybindings)
331     return 0;
332
333   /* Try :keys first */
334   if (!NILP (pgui_item->keys))
335     {
336       CHECK_STRING (pgui_item->keys);
337       if (XSTRING_LENGTH (pgui_item->keys) > buf_len)
338         signal_too_long_error (pgui_item->name);
339       strcpy (buf, (CONST char *) XSTRING_DATA (pgui_item->keys));
340       return XSTRING_LENGTH (pgui_item->keys);
341     }
342
343   /* See if we can derive keys out of callback symbol */
344   if (SYMBOLP (pgui_item->callback))
345     {
346       char buf2 [1024];
347       Bytecount len;
348
349       where_is_to_char (pgui_item->callback, buf2);
350       len = strlen (buf2);
351       if (len > buf_len)
352         signal_too_long_error (pgui_item->name);
353       strcpy (buf, buf2);
354       return len;
355     }
356
357   /* No keys - no right flush display */
358   return 0;
359 }
360 #endif /* HAVE_WINDOW_SYSTEM */
361
362 Lisp_Object
363 mark_gui_item (struct gui_item* p, void (*markobj) (Lisp_Object))
364 {
365   markobj (p->name);
366   markobj (p->callback);
367   markobj (p->suffix);
368   markobj (p->active);
369   markobj (p->included);
370   markobj (p->config);
371   markobj (p->filter);
372   markobj (p->style);
373   markobj (p->selected);
374   markobj (p->keys);
375
376   return Qnil;
377 }
378
379 int
380 gui_item_hash (Lisp_Object hashtable, struct gui_item* g, int slot)
381 {
382   int hashid = HASH2 (internal_hash (g->callback, 0), internal_hash (g->name, 0));
383   int id = GUI_ITEM_ID_BITS (hashid, slot);
384   while (!NILP (Fgethash (make_int (id),
385                           hashtable, Qnil)))
386     {
387       id = GUI_ITEM_ID_BITS (id + 1, slot);
388     }
389   return id;
390 }
391
392 void
393 syms_of_gui (void)
394 {
395   defkeyword (&Q_active,   ":active");
396   defkeyword (&Q_suffix,   ":suffix");
397   defkeyword (&Q_keys,     ":keys");
398   defkeyword (&Q_key_sequence,":key-sequence");
399   defkeyword (&Q_style,    ":style");
400   defkeyword (&Q_selected, ":selected");
401   defkeyword (&Q_filter,   ":filter");
402   defkeyword (&Q_config,   ":config");
403   defkeyword (&Q_included, ":included");
404   defkeyword (&Q_accelerator, ":accelerator");
405   defkeyword (&Q_label, ":label");
406
407   defsymbol (&Qtoggle, "toggle");
408   defsymbol (&Qradio, "radio");
409
410 #ifdef HAVE_POPUPS
411   DEFSUBR (Fpopup_up_p);
412 #endif
413 }
414
415 void
416 vars_of_gui (void)
417 {
418 }