root/branches/2.1/lwlib/lwlib-Xm.c

Revision 3212, 55.3 kB (checked in by miyoshi, 5 years ago)

Sync up with Emacs-21.3.

  • Property svn:eol-style set to native
Line 
1 /* The lwlib interface to Motif widgets.
2    Copyright (C) 1992 Lucid, Inc.
3
4 This file is part of the Lucid Widget Library.
5
6 The Lucid Widget Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
10
11 The Lucid Widget Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING.  If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <unistd.h>
26 #include <stdio.h>
27
28 #include <X11/StringDefs.h>
29 #include <X11/IntrinsicP.h>
30 #include <X11/ObjectP.h>
31 #include <X11/CoreP.h>
32 #include <X11/CompositeP.h>
33
34 #include "lwlib-Xm.h"
35 #include "lwlib-utils.h"
36
37 #include <Xm/BulletinB.h>
38 #include <Xm/CascadeB.h>
39 #include <Xm/CascadeBG.h>
40 #include <Xm/DrawingA.h>
41 #include <Xm/FileSB.h>
42 #include <Xm/Label.h>
43 #include <Xm/List.h>
44 #include <Xm/MainW.h>
45 #include <Xm/MenuShell.h>
46 #include <Xm/MessageB.h>
47 #include <Xm/PanedW.h>
48 #include <Xm/PushB.h>
49 #include <Xm/PushBG.h>
50 #include <Xm/ArrowB.h>
51 #include <Xm/SelectioB.h>
52 #include <Xm/Text.h>
53 #include <Xm/TextF.h>
54 #include <Xm/ToggleB.h>
55 #include <Xm/ToggleBG.h>
56 #include <Xm/RowColumn.h>
57 #include <Xm/ScrolledW.h>
58 #include <Xm/Separator.h>
59 #include <Xm/DialogS.h>
60 #include <Xm/Form.h>
61
62 #if defined __STDC__ || defined PROTOTYPES
63 #define P_(X) X
64 #else
65 #define P_(X) ()
66 #endif
67
68 enum do_call_type { pre_activate, selection, no_selection, post_activate };
69
70
71 /* Structures to keep destroyed instances */
72 typedef struct _destroyed_instance
73 {
74   char*         name;
75   char*         type;
76   Widget        widget;
77   Widget        parent;
78   Boolean       pop_up_p;
79   struct _destroyed_instance*   next;
80 } destroyed_instance;
81
82 static destroyed_instance *make_destroyed_instance P_ ((char *, char *,
83                                                         Widget, Widget,
84                                                         Boolean));
85 static void free_destroyed_instance P_ ((destroyed_instance*));
86 Widget first_child P_ ((Widget));
87 Boolean lw_motif_widget_p P_ ((Widget));
88 static XmString resource_motif_string P_ ((Widget, char *));
89 static void destroy_all_children P_ ((Widget, int));
90 static void xm_update_label P_ ((widget_instance *, Widget, widget_value *));
91 static void xm_update_list P_ ((widget_instance *, Widget, widget_value *));
92 static void xm_update_pushbutton P_ ((widget_instance *, Widget,
93                                       widget_value *));
94 static void xm_update_cascadebutton P_ ((widget_instance *, Widget,
95                                          widget_value *));
96 static void xm_update_toggle P_ ((widget_instance *, Widget, widget_value *));
97 static void xm_update_radiobox P_ ((widget_instance *, Widget, widget_value *));
98 static void make_menu_in_widget P_ ((widget_instance *, Widget,
99                                      widget_value *, int));
100 static void update_one_menu_entry P_ ((widget_instance *, Widget,
101                                        widget_value *, Boolean));
102 static void xm_update_menu P_ ((widget_instance *, Widget, widget_value *,
103                                 Boolean));
104 static void xm_update_text P_ ((widget_instance *, Widget, widget_value *));
105 static void xm_update_text_field P_ ((widget_instance *, Widget,
106                                       widget_value *));
107 void xm_update_one_value P_ ((widget_instance *, Widget, widget_value *));
108 static void activate_button P_ ((Widget, XtPointer, XtPointer));
109 static Widget make_dialog P_ ((char *, Widget, Boolean, char *, char *,
110                                Boolean, Boolean, Boolean, int, int));
111 static destroyed_instance* find_matching_instance P_ ((widget_instance*));
112 static void mark_dead_instance_destroyed P_ ((Widget, XtPointer, XtPointer));
113 static void recenter_widget P_ ((Widget));
114 static Widget recycle_instance P_ ((destroyed_instance*));
115 Widget xm_create_dialog P_ ((widget_instance*));
116 static Widget make_menubar P_ ((widget_instance*));
117 static void remove_grabs P_ ((Widget, XtPointer, XtPointer));
118 static Widget make_popup_menu P_ ((widget_instance*));
119 static Widget make_main P_ ((widget_instance*));
120 void xm_destroy_instance P_ ((widget_instance*));
121 void xm_popup_menu P_ ((Widget, XEvent *));
122 static void set_min_dialog_size P_ ((Widget));
123 static void do_call P_ ((Widget, XtPointer, enum do_call_type));
124 static void xm_generic_callback P_ ((Widget, XtPointer, XtPointer));
125 static void xm_nosel_callback P_ ((Widget, XtPointer, XtPointer));
126 static void xm_pull_down_callback P_ ((Widget, XtPointer, XtPointer));
127 static void xm_pop_down_callback P_ ((Widget, XtPointer, XtPointer));
128 void xm_set_keyboard_focus P_ ((Widget, Widget));
129 void xm_set_main_areas P_ ((Widget, Widget, Widget));
130 static void xm_internal_update_other_instances P_ ((Widget, XtPointer,
131                                                     XtPointer));
132 static void xm_arm_callback P_ ((Widget, XtPointer, XtPointer));
133
134 #if 0
135 void xm_update_one_widget P_ ((widget_instance *, Widget, widget_value *,
136                                Boolean));
137 void xm_pop_instance P_ ((widget_instance*, Boolean));
138 void xm_manage_resizing P_ ((Widget, Boolean));
139 #endif
140
141
142 #if 0
143
144 /* Print the complete X resource name of widget WIDGET to stderr.
145    This is sometimes handy to have available.  */
146
147 void
148 x_print_complete_resource_name (widget)
149      Widget widget;
150 {
151   int i;
152   String names[100];
153
154   for (i = 0; i < 100 && widget != NULL; ++i)
155     {
156       names[i] = XtName (widget);
157       widget = XtParent (widget);
158     }
159
160   for (--i; i >= 1; --i)
161     fprintf (stderr, "%s.", names[i]);
162   fprintf (stderr, "%s\n", names[0]);
163 }
164
165 #endif /* 0 */
166
167
168 static destroyed_instance *all_destroyed_instances = NULL;
169
170 static destroyed_instance*
171 make_destroyed_instance (name, type, widget, parent, pop_up_p)
172      char* name;
173      char* type;
174      Widget widget;
175      Widget parent;
176      Boolean pop_up_p;
177 {
178   destroyed_instance* instance =
179     (destroyed_instance*)malloc (sizeof (destroyed_instance));
180   instance->name = safe_strdup (name);
181   instance->type = safe_strdup (type);
182   instance->widget = widget;
183   instance->parent = parent;
184   instance->pop_up_p = pop_up_p;
185   instance->next = NULL;
186   return instance;
187 }
188                          
189 static void
190 free_destroyed_instance (instance)
191      destroyed_instance* instance;
192 {
193   free (instance->name);
194   free (instance->type);
195   free (instance);
196 }
197
198 /* motif utility functions */
199 Widget
200 first_child (widget)
201      Widget widget;
202 {
203   return ((CompositeWidget)widget)->composite.children [0];
204 }
205
206 Boolean
207 lw_motif_widget_p (widget)
208      Widget widget;
209 {
210   return
211     XtClass (widget) == xmDialogShellWidgetClass
212       || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
213 }
214
215 static XmString
216 resource_motif_string (widget, name)
217      Widget widget;
218      char* name;
219 {
220   XtResource resource;
221   XmString result = 0;
222  
223   resource.resource_name = name;
224   resource.resource_class = XmCXmString;
225   resource.resource_type = XmRXmString;
226   resource.resource_size = sizeof (XmString);
227   resource.resource_offset = 0;
228   resource.default_type = XtRImmediate;
229   resource.default_addr = 0;
230
231   XtGetSubresources (widget, (XtPointer)&result, "dialogString",
232                      "DialogString", &resource, 1, NULL, 0);
233   return result;
234 }
235
236 /* Destroy all of the children of WIDGET
237    starting with number FIRST_CHILD_TO_DESTROY.  */
238
239 static void
240 destroy_all_children (widget, first_child_to_destroy)
241      Widget widget;
242      int first_child_to_destroy;
243 {
244   Widget* children;
245   unsigned int number;
246   int i;
247
248   children = XtCompositeChildren (widget, &number);
249   if (children)
250     {
251       XtUnmanageChildren (children + first_child_to_destroy,
252                           number - first_child_to_destroy);
253
254       /* Unmanage all children and destroy them.  They will only be
255          really destroyed when we get out of DispatchEvent.  */
256       for (i = first_child_to_destroy; i < number; i++)
257         {
258           Arg al[2];
259           Widget submenu = 0;
260           /* Cascade buttons have submenus,and these submenus
261              need to be freed.  But they are not included in
262              XtCompositeChildren.  So get it out of the cascade button
263              and free it.  If this child is not a cascade button,
264              then submenu should remain unchanged.  */
265           XtSetArg (al[0], XmNsubMenuId, &submenu);
266           XtGetValues (children[i], al, 1);
267           if (submenu)
268             {
269               destroy_all_children (submenu, 0);
270               XtDestroyWidget (submenu);
271             }
272           XtDestroyWidget (children[i]);
273         }
274
275       XtFree ((char *) children);
276     }
277 }
278
279
280
281 /* Callback XmNarmCallback and XmNdisarmCallback for buttons in a
282    menu.  CLIENT_DATA contains a pointer to the widget_value
283    corresponding to widget W.  CALL_DATA contains a
284    XmPushButtonCallbackStruct containing the reason why the callback
285    is called.  */
286
287 static void
288 xm_arm_callback (w, client_data, call_data)
289      Widget w;
290      XtPointer client_data, call_data;
291 {
292   XmPushButtonCallbackStruct *cbs = (XmPushButtonCallbackStruct *) call_data;
293   widget_value *wv = (widget_value *) client_data;
294   widget_instance *instance;
295
296   /* Get the id of the menu bar or popup menu this widget is in.  */
297   while (w != NULL)
298     {
299       if (XmIsRowColumn (w))
300         {
301           unsigned char type = 0xff;
302
303           XtVaGetValues (w, XmNrowColumnType, &type, NULL);
304           if (type == XmMENU_BAR || type == XmMENU_POPUP)
305             break;
306         }
307
308       w = XtParent (w);
309     }
310
311   if (w != NULL)
312     {
313       instance = lw_get_widget_instance (w);
314       if (instance && instance->info->highlight_cb)
315         {
316           call_data = cbs->reason == XmCR_DISARM ? NULL : wv;
317           instance->info->highlight_cb (w, instance->info->id, call_data);
318         }
319     }
320 }
321
322
323
324 /* Update the label of widget WIDGET.  WIDGET must be a Label widget
325    or a subclass of Label.  WIDGET_INSTANCE is unused.  VAL contains
326    the value to update.
327
328    Menus:
329   
330    Emacs fills VAL->name with the text to display in the menu, and
331    sets VAL->value to null.  Function make_menu_in_widget creates
332    widgets with VAL->name as resource name.  This works because the
333    Label widget uses its resource name for display if no
334    XmNlabelString is set.
335
336    Dialogs:
337
338    VAL->name is again set to the resource name, but VAL->value is
339    not null, and contains the label string to display.  */
340
341 static void
342 xm_update_label (instance, widget, val)
343      widget_instance* instance;
344      Widget widget;
345      widget_value* val;
346 {
347   XmString res_string = 0;
348   XmString built_string = 0;
349   XmString key_string = 0;
350   Arg al [256];
351   int ac;
352
353   ac = 0;
354
355   if (val->value)
356     {
357       /* A label string is specified, i.e. we are in a dialog.  First
358          see if it is overridden by something from the resource file.  */
359       res_string = resource_motif_string (widget, val->value);
360
361       if (res_string)
362         {
363           XtSetArg (al [ac], XmNlabelString, res_string); ac++;
364         }
365       else
366         {
367           built_string =
368             XmStringCreateLtoR (val->value, XmSTRING_DEFAULT_CHARSET);
369           XtSetArg (al [ac], XmNlabelString, built_string); ac++;
370         }
371      
372       XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
373     }
374  
375   if (val->key)
376     {
377       key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
378       XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
379     }
380
381   if (ac)
382     XtSetValues (widget, al, ac);
383
384   if (built_string)
385     XmStringFree (built_string);
386
387   if (key_string)
388     XmStringFree (key_string);
389 }
390
391 /* update of list */
392 static void
393 xm_update_list (instance, widget, val)
394      widget_instance* instance;
395      Widget widget;
396      widget_value* val;
397 {
398   widget_value* cur;
399   int i;
400   XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
401   XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
402                  instance);
403   for (cur = val->contents, i = 0; cur; cur = cur->next)
404     if (cur->value)
405       {
406         XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET);
407         i += 1;
408         XmListAddItem (widget, xmstr, 0);
409         if (cur->selected)
410           XmListSelectPos (widget, i, False);
411         XmStringFree (xmstr);
412       }
413 }
414
415 /* update of buttons */
416 static void
417 xm_update_pushbutton (instance, widget, val)
418      widget_instance* instance;
419      Widget widget;
420      widget_value* val;
421 {
422   XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, NULL);
423   XtRemoveAllCallbacks (widget, XmNactivateCallback);
424   XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
425 }
426
427 static void
428 xm_update_cascadebutton (instance, widget, val)
429      widget_instance* instance;
430      Widget widget;
431      widget_value* val;
432 {
433   /* Should also rebuild the menu by calling ...update_menu... */
434   XtRemoveAllCallbacks (widget, XmNcascadingCallback);
435   XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
436                  instance);
437 }
438
439 /* update toggle and radiobox */
440 static void
441 xm_update_toggle (instance, widget, val)
442      widget_instance* instance;
443      Widget widget;
444      widget_value* val;
445 {
446   XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
447   XtAddCallback (widget, XmNvalueChangedCallback,
448                  xm_generic_callback, instance);
449   XtVaSetValues (widget, XmNset, val->selected,
450                  XmNalignment, XmALIGNMENT_BEGINNING, NULL);
451 }
452
453 static void
454 xm_update_radiobox (instance, widget, val)
455      widget_instance* instance;
456      Widget widget;
457      widget_value* val;
458
459 {
460   Widget toggle;
461   widget_value* cur;
462
463   /* update the callback */
464   XtRemoveAllCallbacks (widget, XmNentryCallback);
465   XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
466
467   /* first update all the toggles */
468   /* Energize kernel interface is currently bad.  It sets the selected widget
469      with the selected flag but returns it by its name.  So we currently
470      have to support both setting the selection with the selected slot
471      of val contents and setting it with the "value" slot of val.  The latter
472      has a higher priority.  This to be removed when the kernel is fixed. */
473   for (cur = val->contents; cur; cur = cur->next)
474     {
475       toggle = XtNameToWidget (widget, cur->value);
476       if (toggle)
477         {
478           XtSetSensitive (toggle, cur->enabled);
479           if (!val->value && cur->selected)
480             XtVaSetValues (toggle, XmNset, cur->selected, NULL);
481           if (val->value && strcmp (val->value, cur->value))
482             XtVaSetValues (toggle, XmNset, False, NULL);
483         }
484     }
485
486   /* The selected was specified by the value slot */
487   if (val->value)
488     {
489       toggle = XtNameToWidget (widget, val->value);
490       if (toggle)
491         XtVaSetValues (toggle, XmNset, True, NULL);
492     }
493 }
494
495
496 /* update a popup menu, pulldown menu or a menubar */
497
498 /* KEEP_FIRST_CHILDREN gives the number of initial children to keep.  */
499
500 static void
501 make_menu_in_widget (instance, widget, val, keep_first_children)
502      widget_instance* instance;
503      Widget widget;
504      widget_value* val;
505      int keep_first_children;
506 {
507   Widget* children = 0;
508   int num_children;
509   int child_index;
510   widget_value* cur;
511   Widget button = 0;
512   Widget title = 0;
513   Widget menu;
514   Arg al [256];
515   int ac;
516   Boolean menubar_p;
517   unsigned char type;
518
519   Widget* old_children;
520   unsigned int old_num_children;
521
522   old_children = XtCompositeChildren (widget, &old_num_children);
523
524   /* Allocate the children array */
525   for (num_children = 0, cur = val; cur; num_children++, cur = cur->next)
526     ;
527   children = (Widget*)XtMalloc (num_children * sizeof (Widget));
528
529   /* WIDGET should be a RowColumn.  */
530   if (!XmIsRowColumn (widget))
531     abort ();
532
533   /* Determine whether WIDGET is a menu bar.  */
534   type = -1;
535   XtSetArg (al[0], XmNrowColumnType, &type);
536   XtGetValues (widget, al, 1);
537   if (type != XmMENU_BAR && type != XmMENU_PULLDOWN && type != XmMENU_POPUP)
538     abort ();
539   menubar_p = type == XmMENU_BAR;
540
541   /* Add a callback to popups and pulldowns that is called when
542      it is made invisible again.  */
543   if (!menubar_p)
544     XtAddCallback (XtParent (widget), XmNpopdownCallback,
545                    xm_pop_down_callback, (XtPointer)instance);
546
547   /* Preserve the first KEEP_FIRST_CHILDREN old children.  */
548   for (child_index = 0, cur = val; child_index < keep_first_children;
549        child_index++, cur = cur->next)
550     children[child_index] = old_children[child_index];
551
552   /* Check that those are all we have
553      (the caller should have deleted the rest).  */
554   if (old_num_children != keep_first_children)
555     abort ();
556
557   /* Create the rest.  */
558   for