root/trunk/lwlib/lwlib.c

Revision 4220, 38.5 kB (checked in by miyoshi, 5 months ago)

Sync up with Emacs22.2.

  • Property svn:eol-style set to native
Line 
1 /* A general interface to the widgets of different toolkits.
2 Copyright (C) 1992, 1993 Lucid, Inc.
3 Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2003, 2004,
4   2005, 2006, 2007, 2008  Free Software Foundation, Inc.
5
6 This file is part of the Lucid Widget Library.
7
8 The Lucid Widget Library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 The Lucid Widget Library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs; see the file COPYING.  If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.  */
22
23 #ifdef NeXT
24 #undef __STRICT_BSD__ /* ick */
25 #endif
26
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30
31 #include "../src/lisp.h"
32
33 #include <sys/types.h>
34 #include <stdio.h>
35 #include <ctype.h>
36 #include "lwlib-int.h"
37 #include "lwlib-utils.h"
38 #include <X11/StringDefs.h>
39
40 #if defined (USE_LUCID)
41 #include "lwlib-Xlw.h"
42 #endif
43 #if defined (USE_MOTIF)
44 #include "lwlib-Xm.h"
45 #else /* not USE_MOTIF */
46 #if defined (USE_LUCID)
47 #define USE_XAW
48 #endif /* not USE_MOTIF && USE_LUCID */
49 #endif
50 #if defined (USE_XAW)
51 #include <X11/Xaw/Paned.h>
52 #include "lwlib-Xaw.h"
53 #endif
54
55 #if !defined (USE_LUCID) && !defined (USE_MOTIF)
56  #error  At least one of USE_LUCID or USE_MOTIF must be defined.
57 #endif
58
59 #ifndef max
60 #define max(x, y) ((x) > (y) ? (x) : (y))
61 #endif
62
63 /* List of all widgets managed by the library. */
64 static widget_info*
65 all_widget_info = NULL;
66
67 #ifdef USE_MOTIF
68 char *lwlib_toolkit_type = "motif";
69 #else
70 char *lwlib_toolkit_type = "lucid";
71 #endif
72
73 static widget_value *merge_widget_value P_ ((widget_value *,
74                                              widget_value *,
75                                              int, int *));
76 static void instantiate_widget_instance P_ ((widget_instance *));
77 static int my_strcasecmp P_ ((char *, char *));
78 static void safe_free_str P_ ((char *));
79 static void free_widget_value_tree P_ ((widget_value *));
80 static widget_value *copy_widget_value_tree P_ ((widget_value *,
81                                                  change_type));
82 static widget_info *allocate_widget_info P_ ((char *, char *, LWLIB_ID,
83                                               widget_value *,
84                                               lw_callback, lw_callback,
85                                               lw_callback, lw_callback));
86 static void free_widget_info P_ ((widget_info *));
87 static void mark_widget_destroyed P_ ((Widget, XtPointer, XtPointer));
88 static widget_instance *allocate_widget_instance P_ ((widget_info *,
89                                                       Widget, Boolean));
90 static void free_widget_instance P_ ((widget_instance *));
91 static widget_info *get_widget_info P_ ((LWLIB_ID, Boolean));
92 static widget_instance *get_widget_instance P_ ((Widget, Boolean));
93 static widget_instance *find_instance P_ ((LWLIB_ID, Widget, Boolean));
94 static Boolean safe_strcmp P_ ((char *, char *));
95 static Widget name_to_widget P_ ((widget_instance *, char *));
96 static void set_one_value P_ ((widget_instance *, widget_value *, Boolean));
97 static void update_one_widget_instance P_ ((widget_instance *, Boolean));
98 static void update_all_widget_values P_ ((widget_info *, Boolean));
99 static void initialize_widget_instance P_ ((widget_instance *));
100 static widget_creation_function find_in_table P_ ((char *, widget_creation_entry *));
101 static Boolean dialog_spec_p P_ ((char *));
102 static void destroy_one_instance P_ ((widget_instance *));
103 static void lw_pop_all_widgets P_ ((LWLIB_ID, Boolean));
104 static Boolean get_one_value P_ ((widget_instance *, widget_value *));
105 static void show_one_widget_busy P_ ((Widget, Boolean));
106
107 void
108 lwlib_memset (address, value, length)
109      char *address;
110      int value;
111      size_t length;
112 {
113   int i;
114
115   for (i = 0; i < length; i++)
116     address[i] = value;
117 }
118
119 void
120 lwlib_bcopy (from, to, length)
121      char *from;
122      char *to;
123      int length;
124 {
125   int i;
126
127   for (i = 0; i < length; i++)
128     to[i] = from[i];
129 }
130 /* utility functions for widget_instance and widget_info */
131 char *
132 safe_strdup (s)
133      const char *s;
134 {
135   char *result;
136   if (! s) return 0;
137   result = (char *) malloc (strlen (s) + 1);
138   if (! result)
139     return 0;
140   strcpy (result, s);
141   return result;
142 }
143
144 /* Like strcmp but ignore differences in case.  */
145
146 static int
147 my_strcasecmp (s1, s2)
148      char *s1, *s2;
149 {
150   while (1)
151     {
152       int c1 = *s1++;
153       int c2 = *s2++;
154       if (isupper (c1))
155         c1 = tolower (c1);
156       if (isupper (c2))
157         c2 = tolower (c2);
158       if (c1 != c2)
159         return (c1 > c2 ? 1 : -1);
160       if (c1 == 0)
161         return 0;
162     }
163 }
164
165 static void
166 safe_free_str (s)
167      char *s;
168 {
169   if (s) free (s);
170 }
171
172 static widget_value *widget_value_free_list = 0;
173 static int malloc_cpt = 0;
174
175 widget_value *
176 malloc_widget_value ()
177 {
178   widget_value *wv;
179   if (widget_value_free_list)
180     {
181       wv = widget_value_free_list;
182       widget_value_free_list = wv->free_list;
183       wv->free_list = 0;
184     }
185   else
186     {
187       wv = (widget_value *) malloc (sizeof (widget_value));
188       malloc_cpt++;
189     }
190   lwlib_memset ((void*) wv, 0, sizeof (widget_value));
191   return wv;
192 }
193
194 /* this is analogous to free().  It frees only what was allocated
195    by malloc_widget_value(), and no substructures.
196  */
197 void
198 free_widget_value (wv)
199      widget_value *wv;
200 {
201   if (wv->free_list)
202     abort ();
203
204   if (malloc_cpt > 25)
205     {
206       /* When the number of already allocated cells is too big,
207          We free it.  */
208       free (wv);
209       malloc_cpt--;
210     }
211   else
212     {
213       wv->free_list = widget_value_free_list;
214       widget_value_free_list = wv;
215     }
216 }
217
218 static void
219 free_widget_value_tree (wv)
220      widget_value *wv;
221 {
222   if (!wv)
223     return;
224
225   if (wv->name) free (wv->name);
226   if (wv->value) free (wv->value);
227   if (wv->key) free (wv->key);
228
229   wv->name = wv->value = wv->key = (char *) 0xDEADBEEF;
230
231   if (wv->toolkit_data && wv->free_toolkit_data)
232     {
233       XtFree (wv->toolkit_data);
234       wv->toolkit_data = (void *) 0xDEADBEEF;
235     }
236
237   if (wv->contents && (wv->contents != (widget_value*)1))
238     {
239       free_widget_value_tree (wv->contents);
240       wv->contents = (widget_value *) 0xDEADBEEF;
241     }
242   if (wv->next)
243     {
244       free_widget_value_tree (wv->next);
245       wv->next = (widget_value *) 0xDEADBEEF;
246     }
247   free_widget_value (wv);
248 }
249
250 static widget_value *
251 copy_widget_value_tree (val, change)
252      widget_value* val;
253      change_type change;
254 {
255   widget_value* copy;
256
257   if (!val)
258     return NULL;
259   if (val == (widget_value *) 1)
260     return val;
261
262   copy = malloc_widget_value ();
263   copy->name = safe_strdup (val->name);
264   copy->value = safe_strdup (val->value);
265   copy->key = safe_strdup (val->key);
266   copy->help = val->help;
267   copy->enabled = val->enabled;
268   copy->button_type = val->button_type;
269   copy->selected = val->selected;
270   copy->edited = False;
271   copy->change = change;
272   copy->this_one_change = change;
273   copy->contents = copy_widget_value_tree (val->contents, change);
274   copy->call_data = val->call_data;
275   copy->next = copy_widget_value_tree (val->next, change);
276   copy->toolkit_data = NULL;
277   copy->free_toolkit_data = False;
278   return copy;
279 }
280
281 static widget_info *
282 allocate_widget_info (type, name, id, val, pre_activate_cb,
283                       selection_cb, post_activate_cb, highlight_cb)
284      char* type;
285      char* name;
286      LWLIB_ID id;
287      widget_value* val;
288      lw_callback pre_activate_cb;
289      lw_callback selection_cb;
290      lw_callback post_activate_cb;
291      lw_callback highlight_cb;
292 {
293   widget_info* info = (widget_info*)malloc (sizeof (widget_info));
294   info->type = safe_strdup (type);
295   info->name = safe_strdup (name);
296   info->id = id;
297   info->val = copy_widget_value_tree (val, STRUCTURAL_CHANGE);
298   info->busy = False;
299   info->pre_activate_cb = pre_activate_cb;
300   info->selection_cb = selection_cb;
301   info->post_activate_cb = post_activate_cb;
302   info->highlight_cb = highlight_cb;
303   info->instances = NULL;
304
305   info->next = all_widget_info;
306   all_widget_info = info;
307
308   return info;
309 }
310
311 static void
312 free_widget_info (info)
313      widget_info* info;
314 {
315   safe_free_str (info->type);
316   safe_free_str (info->name);
317   free_widget_value_tree (info->val);
318   lwlib_memset ((void*)info, 0xDEADBEEF, sizeof (widget_info));
319   free (info);
320 }
321
322 static void
323 mark_widget_destroyed (widget, closure, call_data)
324      Widget widget;
325      XtPointer closure;
326      XtPointer call_data;
327 {
328   widget_instance* instance = (widget_instance*)closure;
329
330   /* be very conservative */
331   if (instance->widget == widget)
332     instance->widget = NULL;
333 }
334
335 /* The messy #ifdef PROTOTYPES here and elsewhere are prompted by a
336    flood of warnings about argument promotion from proprietary ISO C
337    compilers.  (etags still only makes one entry for each function.)  */
338 static widget_instance *
339 #ifdef PROTOTYPES
340 allocate_widget_instance (widget_info* info, Widget parent, Boolean pop_up_p)
341 #else
342 allocate_widget_instance (info, parent, pop_up_p)
343      widget_info* info;
344      Widget parent;
345      Boolean pop_up_p;
346 #endif
347 {
348   widget_instance* instance =
349     (widget_instance*)malloc (sizeof (widget_instance));
350   bzero (instance, sizeof *instance);
351   instance->parent = parent;
352   instance->pop_up_p = pop_up_p;
353   instance->info = info;
354   instance->next = info->instances;
355   info->instances = instance;
356
357   instantiate_widget_instance (instance);
358
359   XtAddCallback (instance->widget, XtNdestroyCallback,
360                  mark_widget_destroyed, (XtPointer)instance);
361   return instance;
362 }
363
364 static void
365 free_widget_instance (instance)
366      widget_instance* instance;
367 {
368   lwlib_memset ((void*)instance, 0xDEADBEEF, sizeof (widget_instance));
369   free (instance);
370 }
371
372 static widget_info *
373 #ifdef PROTOTYPES
374 get_widget_info (LWLIB_ID id, Boolean remove_p)
375 #else
376 get_widget_info (id, remove_p)
377      LWLIB_ID id;
378      Boolean remove_p;
379 #endif
380 {
381   widget_info* info;
382   widget_info* prev;
383   for (prev = NULL, info = all_widget_info;
384        info;
385        prev = info, info = info->next)
386     if (info->id == id)
387      {
388        if (remove_p)
389          {
390            if (prev)
391              prev->next = info->next;
392            else
393              all_widget_info = info->next;
394          }
395       return info;
396      }
397   return NULL;
398 }
399
400 /* Internal function used by the library dependent implementation to get the
401    widget_value for a given widget in an instance */
402 widget_info *
403 lw_get_widget_info (id)
404      LWLIB_ID id;
405 {
406   return get_widget_info (id, 0);
407 }
408
409 static widget_instance *
410 #ifdef PROTOTYPES
411 get_widget_instance (Widget widget, Boolean remove_p)
412 #else
413 get_widget_instance (widget, remove_p)
414      Widget widget;
415      Boolean remove_p;
416 #endif
417 {
418   widget_info* info;
419   widget_instance* instance;
420   widget_instance* prev;
421   for (info = all_widget_info; info; info = info->next)
422     for (prev = NULL, instance = info->instances;
423          instance;
424          prev = instance, instance = instance->next)
425       if (instance->widget == widget)
426         {
427           if (remove_p)
428             {
429               if (prev)
430                 prev->next = instance->next;
431               else
432                 info->instances = instance->next;
433             }
434           return instance;
435         }
436   return (widget_instance *) 0;
437 }
438
439 /* Value is a pointer to the widget_instance corresponding to
440    WIDGET, or null if WIDGET is not a lwlib widget.  */
441
442 widget_instance *
443 lw_get_widget_instance (widget)
444      Widget widget;
445 {
446   return get_widget_instance (widget, False);
447 }
448
449 static widget_instance*
450 #ifdef PROTOTYPES
451 find_instance (LWLIB_ID id, Widget parent, Boolean pop_up_p)
452 #else
453 find_instance (id, parent, pop_up_p)
454      LWLIB_ID id;
455      Widget parent;
456      Boolean pop_up_p;
457 #endif
458 {
459   widget_info* info = get_widget_info (id, False);
460   widget_instance* instance;
461
462   if (info)
463     for (instance = info->instances; instance; instance = instance->next)
464       if (instance->parent == parent && instance->pop_up_p == pop_up_p)
465         return instance;
466
467   return NULL;
468 }
469
470
471 /* utility function for widget_value */
472 static Boolean
473 safe_strcmp (s1, s2)
474      char* s1;
475      char* s2;
476 {
477   if (!!s1 ^ !!s2) return True;
478   return (s1 && s2) ? strcmp (s1, s2) : s1 ? False : !!s2;
479 }
480
481
482 #if 0
483 # define EXPLAIN(name, oc, nc, desc, a1, a2)                            \
484    printf ("Change: \"%s\"\tmax(%s=%d,%s=%d)\t%s %d %d\n",              \
485            name,                                                        \
486            (oc == NO_CHANGE ? "none" :                                  \
487             (oc == INVISIBLE_CHANGE ? "invisible" :                     \
488              (oc == VISIBLE_CHANGE ? "visible" :                        \
489               (oc == STRUCTURAL_CHANGE ? "structural" : "???")))),      \
490            oc,                                                          \
491            (nc == NO_CHANGE ? "none" :                                  \
492             (nc == INVISIBLE_CHANGE ? "invisible" :                     \
493              (nc == VISIBLE_CHANGE ? "visible" :                        \
494               (nc == STRUCTURAL_CHANGE ? "structural" : "???")))),      \
495            nc, desc, a1, a2)
496 #else
497 # define EXPLAIN(name, oc, nc, desc, a1, a2)
498 #endif
499
500
501 static widget_value *
502 merge_widget_value (val1, val2, level, change_p)
503      widget_value* val1;
504      widget_value* val2;
505      int level;
506      int *change_p;
507 {
508   change_type change, this_one_change;
509   widget_value* merged_next;
510   widget_value* merged_contents;
511
512   if (!val1)
513     {
514       if (val2)
515         {
516           *change_p = 1;
517           return copy_widget_value_tree (val2, STRUCTURAL_CHANGE);
518         }
519       else
520         return NULL;
521     }
522   if (!val2)
523     {
524       *change_p = 1;
525       free_widget_value_tree (val1);
526       return NULL;
527     }
528
529   change = NO_CHANGE;
530
531   if (safe_strcmp (val1->name, val2->name))
532     {
533       EXPLAIN (val1->name, change, STRUCTURAL_CHANGE, "name change",
534                val1->name, val2->name);
535       change = max (change, STRUCTURAL_CHANGE);
536       safe_free_str (val1->name);
537       val1->name = safe_strdup (val2->name);
538     }
539   if (safe_strcmp (val1->value, val2->value))
540     {
541       EXPLAIN (val1->name, change, VISIBLE_CHANGE, "value change",
542                val1->value, val2->value);
543       change = max (change, VISIBLE_CHANGE);
544       safe_free_str (val1->value);
545       val1->value = safe_strdup (val2->value);
546     }
547   if (safe_strcmp (val1->key, val2->key))
548     {
549       EXPLAIN (val1->name, change, VISIBLE_CHANGE, "key change",
550                val1->key, val2->key);
551       change = max (change, VISIBLE_CHANGE);
552       safe_free_str (val1->key);
553       val1->key = safe_strdup (val2->key);
554     }
555   if (! EQ (val1->help, val2->help))
556     {
557       EXPLAIN (val1->name, change, VISIBLE_CHANGE, "help change",
558                val1->help, val2->help)