entered into RCS
[bpt/emacs.git] / lwlib / lwlib-Xm.c
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, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <stdio.h>
24
25 #include <X11/StringDefs.h>
26 #include <X11/IntrinsicP.h>
27 #include <X11/ObjectP.h>
28 #include <X11/CoreP.h>
29 #include <X11/CompositeP.h>
30
31 #include "lwlib-Xm.h"
32 #include "lwlib-utils.h"
33
34 #include <Xm/BulletinB.h>
35 #include <Xm/CascadeB.h>
36 #include <Xm/DrawingA.h>
37 #include <Xm/FileSB.h>
38 #include <Xm/Label.h>
39 #include <Xm/List.h>
40 #include <Xm/MainW.h>
41 #include <Xm/MenuShell.h>
42 #include <Xm/MessageB.h>
43 #include <Xm/PanedW.h>
44 #include <Xm/PushB.h>
45 #include <Xm/PushBG.h>
46 #include <Xm/ArrowB.h>
47 #include <Xm/SelectioB.h>
48 #include <Xm/Text.h>
49 #include <Xm/TextF.h>
50 #include <Xm/ToggleB.h>
51 #include <Xm/ToggleBG.h>
52 #include <Xm/RowColumn.h>
53 #include <Xm/ScrolledW.h>
54 #include <Xm/Separator.h>
55 #include <Xm/DialogS.h>
56 #include <Xm/Form.h>
57
58 static void xm_pull_down_callback (Widget, XtPointer, XtPointer);
59 static void xm_internal_update_other_instances (Widget, XtPointer,
60 XtPointer);
61 static void xm_generic_callback (Widget, XtPointer, XtPointer);
62 static void xm_nosel_callback (Widget, XtPointer, XtPointer);
63 static void xm_pop_down_callback (Widget, XtPointer, XtPointer);
64
65 static void
66 xm_update_menu (widget_instance* instance, Widget widget, widget_value* val,
67 Boolean deep_p);
68
69 \f/* Structures to keep destroyed instances */
70 typedef struct _destroyed_instance
71 {
72 char* name;
73 char* type;
74 Widget widget;
75 Widget parent;
76 Boolean pop_up_p;
77 struct _destroyed_instance* next;
78 } destroyed_instance;
79
80 static destroyed_instance*
81 all_destroyed_instances = NULL;
82
83 static destroyed_instance*
84 make_destroyed_instance (char* name, char* type, Widget widget, Widget parent,
85 Boolean pop_up_p)
86 {
87 destroyed_instance* instance =
88 (destroyed_instance*)malloc (sizeof (destroyed_instance));
89 instance->name = safe_strdup (name);
90 instance->type = safe_strdup (type);
91 instance->widget = widget;
92 instance->parent = parent;
93 instance->pop_up_p = pop_up_p;
94 instance->next = NULL;
95 return instance;
96 }
97
98 static void
99 free_destroyed_instance (destroyed_instance* instance)
100 {
101 free (instance->name);
102 free (instance->type);
103 free (instance);
104 }
105
106 \f/* motif utility functions */
107 Widget
108 first_child (Widget widget)
109 {
110 return ((CompositeWidget)widget)->composite.children [0];
111 }
112
113 Boolean
114 lw_motif_widget_p (Widget widget)
115 {
116 return
117 XtClass (widget) == xmDialogShellWidgetClass
118 || XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget);
119 }
120
121 static XmString
122 resource_motif_string (Widget widget, char* name)
123 {
124 XtResource resource;
125 XmString result = 0;
126
127 resource.resource_name = name;
128 resource.resource_class = XmCXmString;
129 resource.resource_type = XmRXmString;
130 resource.resource_size = sizeof (XmString);
131 resource.resource_offset = 0;
132 resource.default_type = XtRImmediate;
133 resource.default_addr = 0;
134
135 XtGetSubresources (widget, (XtPointer)&result, "dialogString",
136 "DialogString", &resource, 1, NULL, 0);
137 return result;
138 }
139
140 static void
141 destroy_all_children (Widget widget)
142 {
143 Widget* children;
144 unsigned int number;
145 int i;
146
147 children = XtCompositeChildren (widget, &number);
148 if (children)
149 {
150 /* Unmanage all children and destroy them. They will only be
151 * really destroyed when we get out of DispatchEvent. */
152 for (i = 0; i < number; i++)
153 {
154 Widget child = children [i];
155 if (!child->core.being_destroyed)
156 {
157 XtUnmanageChild (child);
158 XtDestroyWidget (child);
159 }
160 }
161 XtFree ((char *) children);
162 }
163 }
164
165 \f/* update the label of anything subclass of a label */
166 static void
167 xm_update_label (widget_instance* instance, Widget widget, widget_value* val)
168 {
169 XmString res_string = 0;
170 XmString built_string = 0;
171 XmString key_string = 0;
172 Arg al [256];
173 int ac;
174
175 ac = 0;
176
177 if (val->value)
178 {
179 res_string = resource_motif_string (widget, val->value);
180
181 if (res_string)
182 {
183 XtSetArg (al [ac], XmNlabelString, res_string); ac++;
184 }
185 else
186 {
187 built_string =
188 XmStringCreateLtoR (val->value, XmSTRING_DEFAULT_CHARSET);
189 XtSetArg (al [ac], XmNlabelString, built_string); ac++;
190 }
191 XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++;
192 }
193
194 if (val->key)
195 {
196 key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET);
197 XtSetArg (al [ac], XmNacceleratorText, key_string); ac++;
198 }
199
200 if (ac)
201 XtSetValues (widget, al, ac);
202
203 if (built_string)
204 XmStringFree (built_string);
205
206 if (key_string)
207 XmStringFree (key_string);
208 }
209
210 \f/* update of list */
211 static void
212 xm_update_list (widget_instance* instance, Widget widget, widget_value* val)
213 {
214 widget_value* cur;
215 int i;
216 XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback);
217 XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback,
218 instance);
219 for (cur = val->contents, i = 0; cur; cur = cur->next)
220 if (cur->value)
221 {
222 XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET);
223 i += 1;
224 XmListAddItem (widget, xmstr, 0);
225 if (cur->selected)
226 XmListSelectPos (widget, i, False);
227 XmStringFree (xmstr);
228 }
229 }
230
231 \f/* update of buttons */
232 static void
233 xm_update_pushbutton (widget_instance* instance, Widget widget,
234 widget_value* val)
235 {
236 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, 0);
237 XtRemoveAllCallbacks (widget, XmNactivateCallback);
238 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
239 }
240
241 static void
242 xm_update_cascadebutton (widget_instance* instance, Widget widget,
243 widget_value* val)
244 {
245 /* Should also rebuild the menu by calling ...update_menu... */
246 XtRemoveAllCallbacks (widget, XmNcascadingCallback);
247 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback,
248 instance);
249 }
250
251 \f/* update toggle and radiobox */
252 static void
253 xm_update_toggle (widget_instance* instance, Widget widget, widget_value* val)
254 {
255 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
256 XtAddCallback (widget, XmNvalueChangedCallback,
257 xm_internal_update_other_instances, instance);
258 XtVaSetValues (widget, XmNset, val->selected,
259 XmNalignment, XmALIGNMENT_BEGINNING, 0);
260 }
261
262 static void
263 xm_update_radiobox (widget_instance* instance, Widget widget,
264 widget_value* val)
265 {
266 Widget toggle;
267 widget_value* cur;
268
269 /* update the callback */
270 XtRemoveAllCallbacks (widget, XmNentryCallback);
271 XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance);
272
273 /* first update all the toggles */
274 /* Energize kernel interface is currently bad. It sets the selected widget
275 with the selected flag but returns it by its name. So we currently
276 have to support both setting the selection with the selected slot
277 of val contents and setting it with the "value" slot of val. The latter
278 has a higher priority. This to be removed when the kernel is fixed. */
279 for (cur = val->contents; cur; cur = cur->next)
280 {
281 toggle = XtNameToWidget (widget, cur->value);
282 if (toggle)
283 {
284 XtVaSetValues (toggle, XmNsensitive, cur->enabled, 0);
285 if (!val->value && cur->selected)
286 XtVaSetValues (toggle, XmNset, cur->selected, 0);
287 if (val->value && strcmp (val->value, cur->value))
288 XtVaSetValues (toggle, XmNset, False, 0);
289 }
290 }
291
292 /* The selected was specified by the value slot */
293 if (val->value)
294 {
295 toggle = XtNameToWidget (widget, val->value);
296 if (toggle)
297 XtVaSetValues (toggle, XmNset, True, 0);
298 }
299 }
300
301 \f/* update a popup menu, pulldown menu or a menubar */
302 static Boolean
303 all_dashes_p (char* s)
304 {
305 char* t;
306 for (t = s; *t; t++)
307 if (*t != '-')
308 return False;
309 return True;
310 }
311
312 static void
313 make_menu_in_widget (widget_instance* instance, Widget widget,
314 widget_value* val)
315 {
316 Widget* children = 0;
317 int num_children;
318 int child_index;
319 widget_value* cur;
320 Widget button = 0;
321 Widget menu;
322 Arg al [256];
323 int ac;
324 Boolean menubar_p;
325
326 /* Allocate the children array */
327 for (num_children = 0, cur = val; cur; num_children++, cur = cur->next);
328 children = (Widget*)XtMalloc (num_children * sizeof (Widget));
329
330 /* tricky way to know if this RowColumn is a menubar or a pulldown... */
331 menubar_p = False;
332 XtSetArg (al[0], XmNisHomogeneous, &menubar_p);
333 XtGetValues (widget, al, 1);
334
335 /* add the unmap callback for popups and pulldowns */
336 /*** this sounds bogus ***/
337 if (!menubar_p)
338 XtAddCallback (XtParent (widget), XmNpopdownCallback,
339 xm_pop_down_callback, (XtPointer)instance);
340
341 for (child_index = 0, cur = val; cur; child_index++, cur = cur->next)
342 {
343 ac = 0;
344 XtSetArg (al [ac], XmNsensitive, cur->enabled); ac++;
345 XtSetArg (al [ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
346 XtSetArg (al [ac], XmNuserData, cur->call_data); ac++;
347
348 if (all_dashes_p (cur->name))
349 {
350 button = XmCreateSeparator (widget, cur->name, NULL, 0);
351 }
352 else if (!cur->contents)
353 {
354 if (menubar_p)
355 button = XmCreateCascadeButton (widget, cur->name, al, ac);
356 else if (!cur->call_data)
357 button = XmCreateLabel (widget, cur->name, al, ac);
358 else
359 button = XmCreatePushButtonGadget (widget, cur->name, al, ac);
360
361 xm_update_label (instance, button, cur);
362
363 /* don't add a callback to a simple label */
364 if (cur->call_data)
365 XtAddCallback (button, XmNactivateCallback, xm_generic_callback,
366 (XtPointer)instance);
367 }
368 else
369 {
370 menu = XmCreatePulldownMenu (widget, "pulldown", NULL, 0);
371 make_menu_in_widget (instance, menu, cur->contents);
372 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
373 button = XmCreateCascadeButton (widget, cur->name, al, ac);
374
375 xm_update_label (instance, button, cur);
376
377 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback,
378 (XtPointer)instance);
379 }
380
381 children [child_index] = button;
382 }
383
384 XtManageChildren (children, num_children);
385
386 /* Last entry is the help button. Has to be done after managing
387 * the buttons otherwise the menubar is only 4 pixels high... */
388 if (button)
389 {
390 ac = 0;
391 XtSetArg (al [ac], XmNmenuHelpWidget, button); ac++;
392 XtSetValues (widget, al, ac);
393 }
394
395 XtFree ((char *) children);
396 }
397
398 static void
399 update_one_menu_entry (widget_instance* instance, Widget widget,
400 widget_value* val, Boolean deep_p)
401 {
402 Arg al [256];
403 int ac;
404 Widget menu;
405 widget_value* contents;
406
407 if (val->change == NO_CHANGE)
408 return;
409
410 /* update the sensitivity and userdata */
411 /* Common to all widget types */
412 XtVaSetValues (widget,
413 XmNsensitive, val->enabled,
414 XmNuserData, val->call_data,
415 0);
416
417 /* update the menu button as a label. */
418 if (val->change >= VISIBLE_CHANGE)
419 xm_update_label (instance, widget, val);
420
421 /* update the pulldown/pullaside as needed */
422 ac = 0;
423 menu = NULL;
424 XtSetArg (al [ac], XmNsubMenuId, &menu); ac++;
425 XtGetValues (widget, al, ac);
426
427 contents = val->contents;
428
429 if (!menu)
430 {
431 if (contents)
432 {
433 menu = XmCreatePulldownMenu (widget, "pulldown", NULL, 0);
434 make_menu_in_widget (instance, menu, contents);
435 ac = 0;
436 XtSetArg (al [ac], XmNsubMenuId, menu); ac++;
437 XtSetValues (widget, al, ac);
438 }
439 }
440 else if (!contents)
441 {
442 ac = 0;
443 XtSetArg (al [ac], XmNsubMenuId, NULL); ac++;
444 XtSetValues (widget, al, ac);
445 XtDestroyWidget (menu);
446 }
447 else if (deep_p && contents->change != NO_CHANGE)
448 xm_update_menu (instance, menu, val, 1);
449 }
450
451 static void
452 xm_update_menu (widget_instance* instance, Widget widget, widget_value* val,
453 Boolean deep_p)
454 {
455 /* Widget is a RowColumn widget whose contents have to be updated
456 * to reflect the list of items in val->contents */
457 if (val->contents->change == STRUCTURAL_CHANGE)
458 {
459 destroy_all_children (widget);
460 make_menu_in_widget (instance, widget, val->contents);
461 }
462 else
463 {
464 /* Update all the buttons of the RowColumn in order. */
465 Widget* children;
466 unsigned int num_children;
467 int i;
468 widget_value* cur;
469
470 children = XtCompositeChildren (widget, &num_children);
471 if (children)
472 {
473 for (i = 0, cur = val->contents; i < num_children; i++)
474 {
475 if (!cur)
476 abort ();
477 if (children [i]->core.being_destroyed
478 || strcmp (XtName (children [i]), cur->name))
479 continue;
480 update_one_menu_entry (instance, children [i], cur, deep_p);
481 cur = cur->next;
482 }
483 XtFree ((char *) children);
484 }
485 if (cur)
486 abort ();
487 }
488 }
489
490 \f
491 /* update text widgets */
492
493 static void
494 xm_update_text (widget_instance* instance, Widget widget, widget_value* val)
495 {
496 XmTextSetString (widget, val->value ? val->value : "");
497 XtRemoveAllCallbacks (widget, XmNactivateCallback);
498 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
499 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
500 XtAddCallback (widget, XmNvalueChangedCallback,
501 xm_internal_update_other_instances, instance);
502 }
503
504 static void
505 xm_update_text_field (widget_instance* instance, Widget widget,
506 widget_value* val)
507 {
508 XmTextFieldSetString (widget, val->value ? val->value : "");
509 XtRemoveAllCallbacks (widget, XmNactivateCallback);
510 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance);
511 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback);
512 XtAddCallback (widget, XmNvalueChangedCallback,
513 xm_internal_update_other_instances, instance);
514 }
515
516 \f
517 /* update a motif widget */
518
519 void
520 xm_update_one_widget (widget_instance* instance, Widget widget,
521 widget_value* val, Boolean deep_p)
522 {
523 WidgetClass class;
524
525 /* Mark as not edited */
526 val->edited = False;
527
528 /* Common to all widget types */
529 XtVaSetValues (widget,
530 XmNsensitive, val->enabled,
531 XmNuserData, val->call_data,
532 0);
533
534 /* Common to all label like widgets */
535 if (XtIsSubclass (widget, xmLabelWidgetClass))
536 xm_update_label (instance, widget, val);
537
538 class = XtClass (widget);
539 /* Class specific things */
540 if (class == xmPushButtonWidgetClass ||
541 class == xmArrowButtonWidgetClass)
542 {
543 xm_update_pushbutton (instance, widget, val);
544 }
545 else if (class == xmCascadeButtonWidgetClass)
546 {
547 xm_update_cascadebutton (instance, widget, val);
548 }
549 else if (class == xmToggleButtonWidgetClass
550 || class == xmToggleButtonGadgetClass)
551 {
552 xm_update_toggle (instance, widget, val);
553 }
554 else if (class == xmRowColumnWidgetClass)
555 {
556 Boolean radiobox = 0;
557 int ac = 0;
558 Arg al [1];
559
560 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
561 XtGetValues (widget, al, ac);
562
563 if (radiobox)
564 xm_update_radiobox (instance, widget, val);
565 else
566 xm_update_menu (instance, widget, val, deep_p);
567 }
568 else if (class == xmTextWidgetClass)
569 {
570 xm_update_text (instance, widget, val);
571 }
572 else if (class == xmTextFieldWidgetClass)
573 {
574 xm_update_text_field (instance, widget, val);
575 }
576 else if (class == xmListWidgetClass)
577 {
578 xm_update_list (instance, widget, val);
579 }
580 }
581
582 \f/* getting the value back */
583 void
584 xm_update_one_value (widget_instance* instance, Widget widget,
585 widget_value* val)
586 {
587 WidgetClass class = XtClass (widget);
588 widget_value *old_wv;
589
590 /* copy the call_data slot into the "return" widget_value */
591 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next)
592 if (!strcmp (val->name, old_wv->name))
593 {
594 val->call_data = old_wv->call_data;
595 break;
596 }
597
598 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass)
599 {
600 XtVaGetValues (widget, XmNset, &val->selected, 0);
601 val->edited = True;
602 }
603 else if (class == xmTextWidgetClass)
604 {
605 if (val->value)
606 free (val->value);
607 val->value = XmTextGetString (widget);
608 val->edited = True;
609 }
610 else if (class == xmTextFieldWidgetClass)
611 {
612 if (val->value)
613 free (val->value);
614 val->value = XmTextFieldGetString (widget);
615 val->edited = True;
616 }
617 else if (class == xmRowColumnWidgetClass)
618 {
619 Boolean radiobox = 0;
620 int ac = 0;
621 Arg al [1];
622
623 XtSetArg (al [ac], XmNradioBehavior, &radiobox); ac++;
624 XtGetValues (widget, al, ac);
625
626 if (radiobox)
627 {
628 CompositeWidget radio = (CompositeWidget)widget;
629 int i;
630 for (i = 0; i < radio->composite.num_children; i++)
631 {
632 int set = False;
633 Widget toggle = radio->composite.children [i];
634
635 XtVaGetValues (toggle, XmNset, &set, 0);
636 if (set)
637 {
638 if (val->value)
639 free (val->value);
640 val->value = safe_strdup (XtName (toggle));
641 }
642 }
643 val->edited = True;
644 }
645 }
646 else if (class == xmListWidgetClass)
647 {
648 int pos_cnt;
649 int* pos_list;
650 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt))
651 {
652 int i;
653 widget_value* cur;
654 for (cur = val->contents, i = 0; cur; cur = cur->next)
655 if (cur->value)
656 {
657 int j;
658 cur->selected = False;
659 i += 1;
660 for (j = 0; j < pos_cnt; j++)
661 if (pos_list [j] == i)
662 {
663 cur->selected = True;
664 val->value = safe_strdup (cur->name);
665 }
666 }
667 val->edited = 1;
668 XtFree ((char *) pos_list);
669 }
670 }
671 }
672
673 \f
674 /* This function is for activating a button from a program. It's wrong because
675 we pass a NULL argument in the call_data which is not Motif compatible.
676 This is used from the XmNdefaultAction callback of the List widgets to
677 have a dble-click put down a dialog box like the button woudl do.
678 I could not find a way to do that with accelerators.
679 */
680 static void
681 activate_button (Widget widget, XtPointer closure, XtPointer call_data)
682 {
683 Widget button = (Widget)closure;
684 XtCallCallbacks (button, XmNactivateCallback, NULL);
685 }
686
687 /* creation functions */
688
689 /* dialogs */
690 static Widget
691 make_dialog (char* name, Widget parent, Boolean pop_up_p,
692 char* shell_title, char* icon_name, Boolean text_input_slot,
693 Boolean radio_box, Boolean list,
694 int left_buttons, int right_buttons)
695 {
696 Widget result;
697 Widget form;
698 Widget row;
699 Widget icon;
700 Widget icon_separator;
701 Widget message;
702 Widget value = 0;
703 Widget separator;
704 Widget button = 0;
705 Widget children [16]; /* for the final XtManageChildren */
706 int n_children;
707 Arg al[64]; /* Arg List */
708 int ac; /* Arg Count */
709 int i;
710
711 if (pop_up_p)
712 {
713 ac = 0;
714 XtSetArg(al[ac], XmNtitle, shell_title); ac++;
715 XtSetArg(al[ac], XtNallowShellResize, True); ac++;
716 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++;
717 result = XmCreateDialogShell (parent, "dialog", al, ac);
718 ac = 0;
719 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
720 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */
721 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
722 form = XmCreateForm (result, shell_title, al, ac);
723 }
724 else
725 {
726 ac = 0;
727 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++;
728 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
729 form = XmCreateForm (parent, shell_title, al, ac);
730 result = form;
731 }
732
733 n_children = left_buttons + right_buttons + 1;
734 ac = 0;
735 XtSetArg(al[ac], XmNpacking, n_children == 3?
736 XmPACK_COLUMN: XmPACK_TIGHT); ac++;
737 XtSetArg(al[ac], XmNorientation, n_children == 3?
738 XmVERTICAL: XmHORIZONTAL); ac++;
739 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++;
740 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
741 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
742 XtSetArg(al[ac], XmNspacing, 13); ac++;
743 XtSetArg(al[ac], XmNadjustLast, False); ac++;
744 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
745 XtSetArg(al[ac], XmNisAligned, True); ac++;
746 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
747 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
748 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
749 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
750 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
751 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
752 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
753 row = XmCreateRowColumn (form, "row", al, ac);
754
755 n_children = 0;
756 for (i = 0; i < left_buttons; i++)
757 {
758 char button_name [16];
759 sprintf (button_name, "button%d", i + 1);
760 ac = 0;
761 if (i == 0)
762 {
763 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++;
764 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++;
765 }
766 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
767 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
768 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
769
770 if (i == 0)
771 {
772 button = children [n_children];
773 ac = 0;
774 XtSetArg(al[ac], XmNdefaultButton, button); ac++;
775 XtSetValues (row, al, ac);
776 }
777
778 n_children++;
779 }
780
781 /* invisible seperator button */
782 ac = 0;
783 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++;
784 children [n_children] = XmCreateLabel (row, "separator_button", al, ac);
785 n_children++;
786
787 for (i = 0; i < right_buttons; i++)
788 {
789 char button_name [16];
790 sprintf (button_name, "button%d", left_buttons + i + 1);
791 ac = 0;
792 XtSetArg(al[ac], XmNmarginWidth, 10); ac++;
793 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++;
794 children [n_children] = XmCreatePushButton (row, button_name, al, ac);
795 if (! button) button = children [n_children];
796 n_children++;
797 }
798
799 XtManageChildren (children, n_children);
800
801 ac = 0;
802 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
803 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
804 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
805 XtSetArg(al[ac], XmNbottomWidget, row); ac++;
806 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
807 XtSetArg(al[ac], XmNleftOffset, 0); ac++;
808 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
809 XtSetArg(al[ac], XmNrightOffset, 0); ac++;
810 separator = XmCreateSeparator (form, "", al, ac);
811
812 ac = 0;
813 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++;
814 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
815 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
816 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++;
817 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
818 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
819 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
820 icon = XmCreateLabel (form, icon_name, al, ac);
821
822 ac = 0;
823 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++;
824 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++;
825 XtSetArg(al[ac], XmNtopOffset, 6); ac++;
826 XtSetArg(al[ac], XmNtopWidget, icon); ac++;
827 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
828 XtSetArg(al[ac], XmNbottomOffset, 6); ac++;
829 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
830 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++;
831 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++;
832 icon_separator = XmCreateLabel (form, "", al, ac);
833
834 if (text_input_slot)
835 {
836 ac = 0;
837 XtSetArg(al[ac], XmNcolumns, 50); ac++;
838 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
839 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
840 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
841 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
842 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
843 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
844 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
845 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
846 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
847 value = XmCreateTextField (form, "value", al, ac);
848 }
849 else if (radio_box)
850 {
851 Widget radio_butt;
852 ac = 0;
853 XtSetArg(al[ac], XmNmarginWidth, 0); ac++;
854 XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
855 XtSetArg(al[ac], XmNspacing, 13); ac++;
856 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++;
857 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++;
858 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
859 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
860 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
861 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
862 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
863 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
864 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
865 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
866 value = XmCreateRadioBox (form, "radiobutton1", al, ac);
867 ac = 0;
868 i = 0;
869 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac);
870 children [i++] = radio_butt;
871 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac);
872 children [i++] = radio_butt;
873 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac);
874 children [i++] = radio_butt;
875 XtManageChildren (children, i);
876 }
877 else if (list)
878 {
879 ac = 0;
880 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++;
881 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++;
882 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
883 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
884 XtSetArg(al[ac], XmNbottomWidget, separator); ac++;
885 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
886 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
887 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
888 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
889 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
890 value = XmCreateScrolledList (form, "list", al, ac);
891
892 /* this is the easiest way I found to have the dble click in the
893 list activate the default button */
894 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button);
895 }
896
897 ac = 0;
898 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++;
899 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
900 XtSetArg(al[ac], XmNtopOffset, 13); ac++;
901 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++;
902 XtSetArg(al[ac], XmNbottomOffset, 13); ac++;
903 XtSetArg(al[ac], XmNbottomWidget,
904 text_input_slot || radio_box || list ? value : separator); ac++;
905 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++;
906 XtSetArg(al[ac], XmNleftOffset, 13); ac++;
907 XtSetArg(al[ac], XmNleftWidget, icon); ac++;
908 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
909 XtSetArg(al[ac], XmNrightOffset, 13); ac++;
910 message = XmCreateLabel (form, "message", al, ac);
911
912 if (list)
913 XtManageChild (value);
914
915 i = 0;
916 children [i] = row; i++;
917 children [i] = separator; i++;
918 if (text_input_slot || radio_box)
919 {
920 children [i] = value; i++;
921 }
922 children [i] = message; i++;
923 children [i] = icon; i++;
924 children [i] = icon_separator; i++;
925 XtManageChildren (children, i);
926
927 if (text_input_slot || list)
928 {
929 XtInstallAccelerators (value, button);
930 XtSetKeyboardFocus (result, value);
931 }
932 else
933 {
934 XtInstallAccelerators (form, button);
935 XtSetKeyboardFocus (result, button);
936 }
937
938 return result;
939 }
940
941 static destroyed_instance*
942 find_matching_instance (widget_instance* instance)
943 {
944 destroyed_instance* cur;
945 destroyed_instance* prev;
946 char* type = instance->info->type;
947 char* name = instance->info->name;
948
949 for (prev = NULL, cur = all_destroyed_instances;
950 cur;
951 prev = cur, cur = cur->next)
952 {
953 if (!strcmp (cur->name, name)
954 && !strcmp (cur->type, type)
955 && cur->parent == instance->parent
956 && cur->pop_up_p == instance->pop_up_p)
957 {
958 if (prev)
959 prev->next = cur->next;
960 else
961 all_destroyed_instances = cur->next;
962 return cur;
963 }
964 /* do some cleanup */
965 else if (!cur->widget)
966 {
967 if (prev)
968 prev->next = cur->next;
969 else
970 all_destroyed_instances = cur->next;
971 free_destroyed_instance (cur);
972 cur = prev ? prev : all_destroyed_instances;
973 }
974 }
975 return NULL;
976 }
977
978 static void
979 mark_dead_instance_destroyed (Widget widget, XtPointer closure,
980 XtPointer call_data)
981 {
982 destroyed_instance* instance = (destroyed_instance*)closure;
983 instance->widget = NULL;
984 }
985
986 static void
987 recenter_widget (Widget widget)
988 {
989 Widget parent = XtParent (widget);
990 Screen* screen = XtScreen (widget);
991 Dimension screen_width = WidthOfScreen (screen);
992 Dimension screen_height = HeightOfScreen (screen);
993 Dimension parent_width = 0;
994 Dimension parent_height = 0;
995 Dimension child_width = 0;
996 Dimension child_height = 0;
997 Position x;
998 Position y;
999
1000 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, 0);
1001 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height,
1002 0);
1003
1004 x = (((Position)parent_width) - ((Position)child_width)) / 2;
1005 y = (((Position)parent_height) - ((Position)child_height)) / 2;
1006
1007 XtTranslateCoords (parent, x, y, &x, &y);
1008
1009 if (x + child_width > screen_width)
1010 x = screen_width - child_width;
1011 if (x < 0)
1012 x = 0;
1013
1014 if (y + child_height > screen_height)
1015 y = screen_height - child_height;
1016 if (y < 0)
1017 y = 0;
1018
1019 XtVaSetValues (widget, XtNx, x, XtNy, y, 0);
1020 }
1021
1022 static Widget
1023 recycle_instance (destroyed_instance* instance)
1024 {
1025 Widget widget = instance->widget;
1026
1027 /* widget is NULL if the parent was destroyed. */
1028 if (widget)
1029 {
1030 Widget focus;
1031 Widget separator;
1032
1033 /* Remove the destroy callback as the instance is not in the list
1034 anymore */
1035 XtRemoveCallback (instance->parent, XtNdestroyCallback,
1036 mark_dead_instance_destroyed,
1037 (XtPointer)instance);
1038
1039 /* Give the focus to the initial item */
1040 focus = XtNameToWidget (widget, "*value");
1041 if (!focus)
1042 focus = XtNameToWidget (widget, "*button1");
1043 if (focus)
1044 XtSetKeyboardFocus (widget, focus);
1045
1046 /* shrink the separator label back to their original size */
1047 separator = XtNameToWidget (widget, "*separator_button");
1048 if (separator)
1049 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, 0);
1050
1051 /* Center the dialog in its parent */
1052 recenter_widget (widget);
1053 }
1054 free_destroyed_instance (instance);
1055 return widget;
1056 }
1057
1058 Widget
1059 xm_create_dialog (widget_instance* instance)
1060 {
1061 char* name = instance->info->type;
1062 Widget parent = instance->parent;
1063 Widget widget;
1064 Boolean pop_up_p = instance->pop_up_p;
1065 char* shell_name = 0;
1066 char* icon_name;
1067 Boolean text_input_slot = False;
1068 Boolean radio_box = False;
1069 Boolean list = False;
1070 int total_buttons;
1071 int left_buttons = 0;
1072 int right_buttons = 1;
1073 destroyed_instance* dead_one;
1074
1075 /* try to find a widget to recycle */
1076 dead_one = find_matching_instance (instance);
1077 if (dead_one)
1078 {
1079 Widget recycled_widget = recycle_instance (dead_one);
1080 if (recycled_widget)
1081 return recycled_widget;
1082 }
1083
1084 switch (name [0]){
1085 case 'E': case 'e':
1086 icon_name = "dbox-error";
1087 shell_name = "Error";
1088 break;
1089
1090 case 'I': case 'i':
1091 icon_name = "dbox-info";
1092 shell_name = "Information";
1093 break;
1094
1095 case 'L': case 'l':
1096 list = True;
1097 icon_name = "dbox-question";
1098 shell_name = "Prompt";
1099 break;
1100
1101 case 'P': case 'p':
1102 text_input_slot = True;
1103 icon_name = "dbox-question";
1104 shell_name = "Prompt";
1105 break;
1106
1107 case 'Q': case 'q':
1108 icon_name = "dbox-question";
1109 shell_name = "Question";
1110 break;
1111 }
1112
1113 total_buttons = name [1] - '0';
1114
1115 if (name [3] == 'T' || name [3] == 't')
1116 {
1117 text_input_slot = False;
1118 radio_box = True;
1119 }
1120 else if (name [3])
1121 right_buttons = name [4] - '0';
1122
1123 left_buttons = total_buttons - right_buttons;
1124
1125 widget = make_dialog (name, parent, pop_up_p,
1126 shell_name, icon_name, text_input_slot, radio_box,
1127 list, left_buttons, right_buttons);
1128
1129 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback,
1130 (XtPointer) instance);
1131 return widget;
1132 }
1133
1134 static Widget
1135 make_menubar (widget_instance* instance)
1136 {
1137 return XmCreateMenuBar (instance->parent, instance->info->name, NULL, 0);
1138 }
1139
1140 static void
1141 remove_grabs (Widget shell, XtPointer closure, XtPointer call_data)
1142 {
1143 XmRowColumnWidget menu = (XmRowColumnWidget) closure;
1144 XmRemoveFromPostFromList (menu, XtParent (XtParent ((Widget) menu)));
1145 }
1146
1147 static Widget
1148 make_popup_menu (widget_instance* instance)
1149 {
1150 Widget parent = instance->parent;
1151 Window parent_window = parent->core.window;
1152 Widget result;
1153
1154 /* sets the parent window to 0 to fool Motif into not generating a grab */
1155 parent->core.window = 0;
1156 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0);
1157 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs,
1158 (XtPointer)result);
1159 parent->core.window = parent_window;
1160 return result;
1161 }
1162 static Widget
1163 make_main (widget_instance* instance)
1164 {
1165 Widget parent = instance->parent;
1166 Widget result;
1167 Arg al[2];
1168 int ac;
1169
1170 ac = 0;
1171 XtSetArg (al[ac], XtNborderWidth, 0); ac++;
1172 XtSetArg (al[ac], XmNspacing, 0); ac++;
1173 result = XmCreateMainWindow (parent, instance->info->name, al, ac);
1174 return result;
1175 }
1176
1177 \f/* Table of functions to create widgets */
1178
1179 #ifdef ENERGIZE
1180
1181 /* interface with the XDesigner generated functions */
1182 typedef Widget (*widget_maker) (Widget);
1183 extern Widget create_project_p_sheet (Widget parent);
1184 extern Widget create_debugger_p_sheet (Widget parent);
1185 extern Widget create_breaklist_p_sheet (Widget parent);
1186 extern Widget create_le_browser_p_sheet (Widget parent);
1187 extern Widget create_class_browser_p_sheet (Widget parent);
1188 extern Widget create_call_browser_p_sheet (Widget parent);
1189 extern Widget create_build_dialog (Widget parent);
1190 extern Widget create_editmode_dialog (Widget parent);
1191 extern Widget create_search_dialog (Widget parent);
1192 extern Widget create_project_display_dialog (Widget parent);
1193
1194 static Widget
1195 make_one (widget_instance* instance, widget_maker fn)
1196 {
1197 Widget result;
1198 Arg al [64];
1199 int ac = 0;
1200
1201 if (instance->pop_up_p)
1202 {
1203 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++;
1204 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0);
1205 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback,
1206 (XtPointer) instance);
1207 (*fn) (result);
1208 }
1209 else
1210 {
1211 result = (*fn) (instance->parent);
1212 XtRealizeWidget (result);
1213 }
1214 return result;
1215 }
1216
1217 static Widget
1218 make_project_p_sheet (widget_instance* instance)
1219 {
1220 return make_one (instance, create_project_p_sheet);
1221 }
1222
1223 static Widget
1224 make_debugger_p_sheet (widget_instance* instance)
1225 {
1226 return make_one (instance, create_debugger_p_sheet);
1227 }
1228
1229 static Widget
1230 make_breaklist_p_sheet (widget_instance* instance)
1231 {
1232 return make_one (instance, create_breaklist_p_sheet);
1233 }
1234
1235 static Widget
1236 make_le_browser_p_sheet (widget_instance* instance)
1237 {
1238 return make_one (instance, create_le_browser_p_sheet);
1239 }
1240
1241 static Widget
1242 make_class_browser_p_sheet (widget_instance* instance)
1243 {
1244 return make_one (instance, create_class_browser_p_sheet);
1245 }
1246
1247 static Widget
1248 make_call_browser_p_sheet (widget_instance* instance)
1249 {
1250 return make_one (instance, create_call_browser_p_sheet);
1251 }
1252
1253 static Widget
1254 make_build_dialog (widget_instance* instance)
1255 {
1256 return make_one (instance, create_build_dialog);
1257 }
1258
1259 static Widget
1260 make_editmode_dialog (widget_instance* instance)
1261 {
1262 return make_one (instance, create_editmode_dialog);
1263 }
1264
1265 static Widget
1266 make_search_dialog (widget_instance* instance)
1267 {
1268 return make_one (instance, create_search_dialog);
1269 }
1270
1271 static Widget
1272 make_project_display_dialog (widget_instance* instance)
1273 {
1274 return make_one (instance, create_project_display_dialog);
1275 }
1276
1277 #endif /* ENERGIZE */
1278
1279 widget_creation_entry
1280 xm_creation_table [] =
1281 {
1282 {"menubar", make_menubar},
1283 {"popup", make_popup_menu},
1284 {"main", make_main},
1285 #ifdef ENERGIZE
1286 {"project_p_sheet", make_project_p_sheet},
1287 {"debugger_p_sheet", make_debugger_p_sheet},
1288 {"breaklist_psheet", make_breaklist_p_sheet},
1289 {"leb_psheet", make_le_browser_p_sheet},
1290 {"class_browser_psheet", make_class_browser_p_sheet},
1291 {"ctree_browser_psheet", make_call_browser_p_sheet},
1292 {"build", make_build_dialog},
1293 {"editmode", make_editmode_dialog},
1294 {"search", make_search_dialog},
1295 {"project_display", make_project_display_dialog},
1296 #endif /* ENERGIZE */
1297 {NULL, NULL}
1298 };
1299
1300 \f/* Destruction of instances */
1301 void
1302 xm_destroy_instance (widget_instance* instance)
1303 {
1304 Widget widget = instance->widget;
1305 /* recycle the dialog boxes */
1306 /* Disable the recycling until we can find a way to have the dialog box
1307 get reasonable layout after we modify its contents. */
1308 if (0
1309 && XtClass (widget) == xmDialogShellWidgetClass)
1310 {
1311 destroyed_instance* dead_instance =
1312 make_destroyed_instance (instance->info->name,
1313 instance->info->type,
1314 instance->widget,
1315 instance->parent,
1316 instance->pop_up_p);
1317 dead_instance->next = all_destroyed_instances;
1318 all_destroyed_instances = dead_instance;
1319 XtUnmanageChild (first_child (instance->widget));
1320 XFlush (XtDisplay (instance->widget));
1321 XtAddCallback (instance->parent, XtNdestroyCallback,
1322 mark_dead_instance_destroyed, (XtPointer)dead_instance);
1323 }
1324 else
1325 {
1326 /* This might not be necessary now that the nosel is attached to
1327 popdown instead of destroy, but it can't hurt. */
1328 XtRemoveCallback (instance->widget, XtNdestroyCallback,
1329 xm_nosel_callback, (XtPointer)instance);
1330 XtDestroyWidget (instance->widget);
1331 }
1332 }
1333
1334 \f/* popup utility */
1335 void
1336 xm_popup_menu (Widget widget)
1337 {
1338 XButtonPressedEvent dummy;
1339 XEvent* event;
1340
1341 dummy.type = ButtonPress;
1342 dummy.serial = 0;
1343 dummy.send_event = 0;
1344 dummy.display = XtDisplay (widget);
1345 dummy.window = XtWindow (XtParent (widget));
1346 dummy.time = 0;
1347 dummy.button = 0;
1348 XQueryPointer (dummy.display, dummy.window, &dummy.root,
1349 &dummy.subwindow, &dummy.x_root, &dummy.y_root,
1350 &dummy.x, &dummy.y, &dummy.state);
1351 event = (XEvent *) &dummy;
1352
1353 if (event->type == ButtonPress || event->type == ButtonRelease)
1354 {
1355 /* This is so totally ridiculous: there's NO WAY to tell Motif
1356 that *any* button can select a menu item. Only one button
1357 can have that honor.
1358 */
1359 char *trans = 0;
1360 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>";
1361 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>";
1362 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>";
1363 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>";
1364 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>";
1365 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, 0);
1366 XmMenuPosition (widget, (XButtonPressedEvent *) event);
1367 }
1368 XtManageChild (widget);
1369 }
1370
1371 static void
1372 set_min_dialog_size (Widget w)
1373 {
1374 short width;
1375 short height;
1376 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, 0);
1377 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, 0);
1378 }
1379
1380 void
1381 xm_pop_instance (widget_instance* instance, Boolean up)
1382 {
1383 Widget widget = instance->widget;
1384
1385 if (XtClass (widget) == xmDialogShellWidgetClass)
1386 {
1387 Widget widget_to_manage = first_child (widget);
1388 if (up)
1389 {
1390 XtManageChild (widget_to_manage);
1391 set_min_dialog_size (widget);
1392 XtSetKeyboardFocus (instance->parent, widget);
1393 }
1394 else
1395 XtUnmanageChild (widget_to_manage);
1396 }
1397 else
1398 {
1399 if (up)
1400 XtManageChild (widget);
1401 else
1402 XtUnmanageChild (widget);
1403 }
1404 }
1405
1406 \f
1407 /* motif callback */
1408
1409 enum do_call_type { pre_activate, selection, no_selection, post_activate };
1410
1411 static void
1412 do_call (Widget widget, XtPointer closure, enum do_call_type type)
1413 {
1414 Arg al [256];
1415 int ac;
1416 XtPointer user_data;
1417 widget_instance* instance = (widget_instance*)closure;
1418 Widget instance_widget;
1419 LWLIB_ID id;
1420
1421 if (!instance)
1422 return;
1423 if (widget->core.being_destroyed)
1424 return;
1425
1426 instance_widget = instance->widget;
1427 if (!instance_widget)
1428 return;
1429
1430 id = instance->info->id;
1431 ac = 0;
1432 user_data = NULL;
1433 XtSetArg (al [ac], XmNuserData, &user_data); ac++;
1434 XtGetValues (widget, al, ac);
1435 switch (type)
1436 {
1437 case pre_activate:
1438 if (instance->info->pre_activate_cb)
1439 instance->info->pre_activate_cb (widget, id, user_data);
1440 break;
1441 case selection:
1442 if (instance->info->selection_cb)
1443 instance->info->selection_cb (widget, id, user_data);
1444 break;
1445 case no_selection:
1446 if (instance->info->selection_cb)
1447 instance->info->selection_cb (widget, id, (XtPointer) -1);
1448 break;
1449 case post_activate:
1450 if (instance->info->post_activate_cb)
1451 instance->info->post_activate_cb (widget, id, user_data);
1452 break;
1453 default:
1454 abort ();
1455 }
1456 }
1457
1458 /* Like lw_internal_update_other_instances except that it does not do
1459 anything if its shell parent is not managed. This is to protect
1460 lw_internal_update_other_instances to dereference freed memory
1461 if the widget was ``destroyed'' by caching it in the all_destroyed_instances
1462 list */
1463 static void
1464 xm_internal_update_other_instances (Widget widget, XtPointer closure,
1465 XtPointer call_data)
1466 {
1467 Widget parent;
1468 for (parent = widget; parent; parent = XtParent (parent))
1469 if (XtIsShell (parent))
1470 break;
1471 else if (!XtIsManaged (parent))
1472 return;
1473 lw_internal_update_other_instances (widget, closure, call_data);
1474 }
1475
1476 static void
1477 xm_generic_callback (Widget widget, XtPointer closure, XtPointer call_data)
1478 {
1479 lw_internal_update_other_instances (widget, closure, call_data);
1480 do_call (widget, closure, selection);
1481 }
1482
1483 static void
1484 xm_nosel_callback (Widget widget, XtPointer closure, XtPointer call_data)
1485 {
1486 /* This callback is only called when a dialog box is dismissed with the wm's
1487 destroy button (WM_DELETE_WINDOW.) We want the dialog box to be destroyed
1488 in that case, not just unmapped, so that it releases its keyboard grabs.
1489 But there are problems with running our callbacks while the widget is in
1490 the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP
1491 instead of XmDESTROY and then destroy it ourself after having run the
1492 callback.
1493 */
1494 do_call (widget, closure, no_selection);
1495 XtDestroyWidget (widget);
1496 }
1497
1498 static void
1499 xm_pull_down_callback (Widget widget, XtPointer closure, XtPointer call_data)
1500 {
1501 do_call (widget, closure, pre_activate);
1502 }
1503
1504 static void
1505 xm_pop_down_callback (Widget widget, XtPointer closure, XtPointer call_data)
1506 {
1507 do_call (widget, closure, post_activate);
1508 }
1509
1510 \f
1511 /* set the keyboard focus */
1512 void
1513 xm_set_keyboard_focus (Widget parent, Widget w)
1514 {
1515 XmProcessTraversal (w, 0);
1516 XtSetKeyboardFocus (parent, w);
1517 }