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