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