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