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