root/trunk/lwlib/lwlib-Xm.c

Revision 4220, 56.4 kB (checked in by miyoshi, 6 months ago)

Sync up with Emacs22.2.

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