Mercurial > hg > xemacs-beta
comparison lwlib/lwlib-Xm.c @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | ac2d302a0011 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 /* The lwlib interface to Motif widgets. | |
2 Copyright (C) 1992, 1993, 1994 Lucid, Inc. | |
3 Copyright (C) 1995 Tinker Systems and INS Engineering Corp. | |
4 | |
5 This file is part of the Lucid Widget Library. | |
6 | |
7 The Lucid Widget Library is free software; you can redistribute it and/or | |
8 modify it under the terms of the GNU General Public License as published by | |
9 the Free Software Foundation; either version 2, or (at your option) | |
10 any later version. | |
11 | |
12 The Lucid Widget Library is distributed in the hope that it will be useful, | |
13 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 GNU General Public License for more details. | |
16 | |
17 You should have received a copy of the GNU General Public License | |
18 along with GNU Emacs; see the file COPYING. If not, write to | |
19 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | |
21 #include <stdlib.h> | |
22 #include <unistd.h> | |
23 #include <string.h> | |
24 #include <stdio.h> | |
25 #include <limits.h> | |
26 | |
27 #include <X11/StringDefs.h> | |
28 #include <X11/IntrinsicP.h> | |
29 #include <X11/ObjectP.h> | |
30 #include <X11/CoreP.h> | |
31 #include <X11/CompositeP.h> | |
32 | |
33 #include "lwlib-Xm.h" | |
34 #include "lwlib-utils.h" | |
35 | |
36 #include <Xm/Xm.h> | |
37 #include <Xm/BulletinB.h> | |
38 #include <Xm/CascadeB.h> | |
39 #include <Xm/DrawingA.h> | |
40 #include <Xm/FileSB.h> | |
41 #include <Xm/Label.h> | |
42 #include <Xm/List.h> | |
43 #include <Xm/MenuShell.h> | |
44 #include <Xm/MessageB.h> | |
45 #include <Xm/PushB.h> | |
46 #include <Xm/PushBG.h> | |
47 #include <Xm/ArrowB.h> | |
48 #include <Xm/ScrollBar.h> | |
49 #include <Xm/SelectioB.h> | |
50 #include <Xm/Text.h> | |
51 #include <Xm/TextF.h> | |
52 #include <Xm/ToggleB.h> | |
53 #include <Xm/ToggleBG.h> | |
54 #include <Xm/RowColumn.h> | |
55 #include <Xm/ScrolledW.h> | |
56 #include <Xm/Separator.h> | |
57 #include <Xm/DialogS.h> | |
58 #include <Xm/Form.h> | |
59 | |
60 #ifdef MENUBARS_MOTIF | |
61 static void xm_pull_down_callback (Widget, XtPointer, XtPointer); | |
62 #if 0 | |
63 static void xm_pop_down_callback (Widget, XtPointer, XtPointer); | |
64 #endif /* 0 */ | |
65 #endif | |
66 static void xm_internal_update_other_instances (Widget, XtPointer, | |
67 XtPointer); | |
68 static void xm_generic_callback (Widget, XtPointer, XtPointer); | |
69 #ifdef DIALOGS_MOTIF | |
70 static void xm_nosel_callback (Widget, XtPointer, XtPointer); | |
71 #endif | |
72 #ifdef SCROLLBARS_MOTIF | |
73 static void xm_scrollbar_callback (Widget, XtPointer, XtPointer); | |
74 #endif | |
75 | |
76 #ifdef MENUBARS_MOTIF | |
77 static void | |
78 xm_update_menu (widget_instance* instance, Widget widget, widget_value* val, | |
79 Boolean deep_p); | |
80 #endif | |
81 | |
82 /* Structures to keep destroyed instances */ | |
83 typedef struct _destroyed_instance | |
84 { | |
85 char* name; | |
86 char* type; | |
87 Widget widget; | |
88 Widget parent; | |
89 Boolean pop_up_p; | |
90 struct _destroyed_instance* next; | |
91 } destroyed_instance; | |
92 | |
93 static destroyed_instance* | |
94 all_destroyed_instances = NULL; | |
95 | |
96 /* Utility function. */ | |
97 static char * | |
98 safe_strdup (char* s) | |
99 { | |
100 char *result; | |
101 if (! s) return 0; | |
102 result = (char *) malloc (strlen (s) + 1); | |
103 if (! result) | |
104 return 0; | |
105 strcpy (result, s); | |
106 return result; | |
107 } | |
108 | |
109 static destroyed_instance* | |
110 make_destroyed_instance (char* name, char* type, Widget widget, Widget parent, | |
111 Boolean pop_up_p) | |
112 { | |
113 destroyed_instance* instance = | |
114 (destroyed_instance*)malloc (sizeof (destroyed_instance)); | |
115 instance->name = safe_strdup (name); | |
116 instance->type = safe_strdup (type); | |
117 instance->widget = widget; | |
118 instance->parent = parent; | |
119 instance->pop_up_p = pop_up_p; | |
120 instance->next = NULL; | |
121 return instance; | |
122 } | |
123 | |
124 static void | |
125 free_destroyed_instance (destroyed_instance* instance) | |
126 { | |
127 free (instance->name); | |
128 free (instance->type); | |
129 free (instance); | |
130 } | |
131 | |
132 /* motif utility functions */ | |
133 Widget | |
134 first_child (Widget widget) | |
135 { | |
136 return ((CompositeWidget)widget)->composite.children [0]; | |
137 } | |
138 | |
139 Boolean | |
140 lw_motif_widget_p (Widget widget) | |
141 { | |
142 return | |
143 #ifdef DIALOGS_MOTIF | |
144 XtClass (widget) == xmDialogShellWidgetClass || | |
145 #endif | |
146 XmIsPrimitive (widget) || XmIsManager (widget) || XmIsGadget (widget); | |
147 } | |
148 | |
149 static char * | |
150 resource_string (Widget widget, char *name) | |
151 { | |
152 XtResource resource; | |
153 char *result = NULL; | |
154 | |
155 resource.resource_name = "labelString"; | |
156 resource.resource_class = "LabelString"; /* #### should be Xmsomething... */ | |
157 resource.resource_type = XtRString; | |
158 resource.resource_size = sizeof (String); | |
159 resource.resource_offset = 0; | |
160 resource.default_type = XtRImmediate; | |
161 resource.default_addr = 0; | |
162 | |
163 XtGetSubresources (widget, (XtPointer)&result, name, | |
164 name, &resource, 1, NULL, 0); | |
165 return result; | |
166 } | |
167 | |
168 #ifdef MENUBARS_MOTIF | |
169 | |
170 static void | |
171 destroy_all_children (Widget widget) | |
172 { | |
173 Widget* children; | |
174 unsigned int number; | |
175 int i; | |
176 | |
177 children = XtCompositeChildren (widget, &number); | |
178 if (children) | |
179 { | |
180 /* Unmanage all children and destroy them. They will only be | |
181 * really destroyed when we get out of DispatchEvent. */ | |
182 for (i = 0; i < number; i++) | |
183 { | |
184 Widget child = children [i]; | |
185 if (!child->core.being_destroyed) | |
186 { | |
187 XtUnmanageChild (child); | |
188 XtDestroyWidget (child); | |
189 } | |
190 } | |
191 XtFree ((char *) children); | |
192 } | |
193 } | |
194 | |
195 #endif /* MENUBARS_MOTIF */ | |
196 | |
197 | |
198 | |
199 #ifdef DIALOGS_MOTIF | |
200 | |
201 static Boolean | |
202 is_in_dialog_box (Widget w) | |
203 { | |
204 Widget wmshell; | |
205 | |
206 wmshell = XtParent (w); | |
207 while (wmshell && (XtClass (wmshell) != xmDialogShellWidgetClass)) | |
208 wmshell = XtParent (wmshell); | |
209 | |
210 if (wmshell && XtClass (wmshell) == xmDialogShellWidgetClass) | |
211 return True; | |
212 else | |
213 return False; | |
214 } | |
215 | |
216 #endif /* DIALOGS_MOTIF */ | |
217 | |
218 #if defined (DIALOGS_MOTIF) || defined (MENUBARS_MOTIF) | |
219 | |
220 /* update the label of anything subclass of a label */ | |
221 static void | |
222 xm_update_label (widget_instance* instance, Widget widget, widget_value* val) | |
223 { | |
224 XmString built_string = 0; | |
225 XmString key_string = 0; | |
226 XmString val_string = 0; | |
227 XmString name_string = 0; | |
228 Arg al [256]; | |
229 int ac; | |
230 | |
231 ac = 0; | |
232 | |
233 if (val->value) | |
234 { | |
235 #ifdef DIALOGS_MOTIF | |
236 /* | |
237 * Sigh. The main text of a label is the name field for menubar | |
238 * entries. The value field is a possible additional field to be | |
239 * contatenated on to the name field. HOWEVER, with dialog boxes | |
240 * the value field is the complete text which is supposed to be | |
241 * displayed as the label. Yuck. | |
242 */ | |
243 if (is_in_dialog_box (widget)) | |
244 { | |
245 char *value_name = NULL; | |
246 | |
247 value_name = resource_string (widget, val->value); | |
248 if (!value_name) | |
249 value_name = val->value; | |
250 | |
251 built_string = | |
252 XmStringCreateLtoR (value_name, XmSTRING_DEFAULT_CHARSET); | |
253 } | |
254 else | |
255 #endif | |
256 { | |
257 char *value_name = NULL; | |
258 char *res_name = NULL; | |
259 | |
260 res_name = resource_string (widget, val->name); | |
261 if (!res_name) | |
262 res_name = val->name; | |
263 | |
264 name_string = | |
265 XmStringCreateLtoR (res_name, XmSTRING_DEFAULT_CHARSET); | |
266 | |
267 value_name = XtMalloc (strlen (val->value) + 2); | |
268 *value_name = 0; | |
269 strcat (value_name, " "); | |
270 strcat (value_name, val->value); | |
271 | |
272 val_string = | |
273 XmStringCreateLtoR (value_name, XmSTRING_DEFAULT_CHARSET); | |
274 | |
275 built_string = | |
276 XmStringConcat (name_string, val_string); | |
277 | |
278 XtFree (value_name); | |
279 } | |
280 | |
281 XtSetArg (al [ac], XmNlabelString, built_string); ac++; | |
282 XtSetArg (al [ac], XmNlabelType, XmSTRING); ac++; | |
283 } | |
284 | |
285 if (val->key) | |
286 { | |
287 key_string = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET); | |
288 XtSetArg (al [ac], XmNacceleratorText, key_string); ac++; | |
289 } | |
290 | |
291 if (ac) | |
292 XtSetValues (widget, al, ac); | |
293 | |
294 if (built_string) | |
295 XmStringFree (built_string); | |
296 | |
297 if (key_string) | |
298 XmStringFree (key_string); | |
299 | |
300 if (name_string) | |
301 XmStringFree (name_string); | |
302 } | |
303 | |
304 #endif /* defined (DIALOGS_MOTIF) || defined (MENUBARS_MOTIF) */ | |
305 | |
306 /* update of list */ | |
307 static void | |
308 xm_update_list (widget_instance* instance, Widget widget, widget_value* val) | |
309 { | |
310 widget_value* cur; | |
311 int i; | |
312 XtRemoveAllCallbacks (widget, XmNsingleSelectionCallback); | |
313 XtAddCallback (widget, XmNsingleSelectionCallback, xm_generic_callback, | |
314 instance); | |
315 for (cur = val->contents, i = 0; cur; cur = cur->next) | |
316 if (cur->value) | |
317 { | |
318 XmString xmstr = XmStringCreate (cur->value, XmSTRING_DEFAULT_CHARSET); | |
319 i += 1; | |
320 XmListAddItem (widget, xmstr, 0); | |
321 if (cur->selected) | |
322 XmListSelectPos (widget, i, False); | |
323 XmStringFree (xmstr); | |
324 } | |
325 } | |
326 | |
327 /* update of buttons */ | |
328 static void | |
329 xm_update_pushbutton (widget_instance* instance, Widget widget, | |
330 widget_value* val) | |
331 { | |
332 XtVaSetValues (widget, XmNalignment, XmALIGNMENT_CENTER, 0); | |
333 XtRemoveAllCallbacks (widget, XmNactivateCallback); | |
334 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance); | |
335 } | |
336 | |
337 #ifdef MENUBARS_MOTIF | |
338 | |
339 static void | |
340 xm_update_cascadebutton (widget_instance* instance, Widget widget, | |
341 widget_value* val) | |
342 { | |
343 /* Should also rebuild the menu by calling ...update_menu... */ | |
344 if (val | |
345 && val->type == CASCADE_TYPE | |
346 && val->contents | |
347 && val->contents->type == INCREMENTAL_TYPE) | |
348 { | |
349 /* okay, we're now doing a lisp callback to incrementally generate | |
350 more of the menu. */ | |
351 XtRemoveAllCallbacks (widget, XmNcascadingCallback); | |
352 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback, | |
353 instance); | |
354 XtCallCallbacks ((Widget)widget, | |
355 XmNcascadingCallback, | |
356 (XtPointer)val->contents); | |
357 | |
358 } else { | |
359 XtRemoveAllCallbacks (widget, XmNcascadingCallback); | |
360 XtAddCallback (widget, XmNcascadingCallback, xm_pull_down_callback, | |
361 instance); | |
362 } | |
363 } | |
364 | |
365 #endif /* MENUBARS_MOTIF */ | |
366 | |
367 /* update toggle and radiobox */ | |
368 static void | |
369 xm_update_toggle (widget_instance* instance, Widget widget, widget_value* val) | |
370 { | |
371 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback); | |
372 #ifndef ENERGIZE | |
373 XtAddCallback (widget, XmNvalueChangedCallback, xm_generic_callback, | |
374 instance); | |
375 #else | |
376 XtAddCallback (widget, XmNvalueChangedCallback, | |
377 xm_internal_update_other_instances, instance); | |
378 #endif | |
379 XtVaSetValues (widget, XmNset, val->selected, | |
380 XmNalignment, XmALIGNMENT_BEGINNING, 0); | |
381 } | |
382 | |
383 static void | |
384 xm_update_radiobox (widget_instance* instance, Widget widget, | |
385 widget_value* val) | |
386 { | |
387 Widget toggle; | |
388 widget_value* cur; | |
389 | |
390 /* update the callback */ | |
391 XtRemoveAllCallbacks (widget, XmNentryCallback); | |
392 XtAddCallback (widget, XmNentryCallback, xm_generic_callback, instance); | |
393 | |
394 /* first update all the toggles */ | |
395 /* Energize kernel interface is currently bad. It sets the selected widget | |
396 with the selected flag but returns it by its name. So we currently | |
397 have to support both setting the selection with the selected slot | |
398 of val contents and setting it with the "value" slot of val. The latter | |
399 has a higher priority. This to be removed when the kernel is fixed. */ | |
400 for (cur = val->contents; cur; cur = cur->next) | |
401 { | |
402 toggle = XtNameToWidget (widget, cur->value); | |
403 if (toggle) | |
404 { | |
405 XtVaSetValues (toggle, XmNsensitive, cur->enabled, 0); | |
406 if (!val->value && cur->selected) | |
407 XtVaSetValues (toggle, XmNset, cur->selected, 0); | |
408 if (val->value && strcmp (val->value, cur->value)) | |
409 XtVaSetValues (toggle, XmNset, False, 0); | |
410 } | |
411 } | |
412 | |
413 /* The selected was specified by the value slot */ | |
414 if (val->value) | |
415 { | |
416 toggle = XtNameToWidget (widget, val->value); | |
417 if (toggle) | |
418 XtVaSetValues (toggle, XmNset, True, 0); | |
419 } | |
420 } | |
421 | |
422 #ifdef MENUBARS_MOTIF | |
423 | |
424 /* update a popup menu, pulldown menu or a menubar */ | |
425 static void | |
426 make_menu_in_widget (widget_instance* instance, Widget widget, | |
427 widget_value* val) | |
428 { | |
429 Widget* children = 0; | |
430 int num_children; | |
431 int child_index; | |
432 widget_value* cur; | |
433 Widget button = 0; | |
434 Widget menu; | |
435 Arg al [256]; | |
436 int ac; | |
437 Boolean menubar_p; | |
438 | |
439 /* Allocate the children array */ | |
440 for (num_children = 0, cur = val; cur; num_children++, cur = cur->next); | |
441 children = (Widget*)XtMalloc (num_children * sizeof (Widget)); | |
442 | |
443 /* tricky way to know if this RowColumn is a menubar or a pulldown... */ | |
444 menubar_p = False; | |
445 XtVaGetValues (widget, XmNisHomogeneous, &menubar_p, NULL); | |
446 | |
447 /* add the unmap callback for popups and pulldowns */ | |
448 /*** this sounds bogus ***/ | |
449 /* probably because it is -- cet */ | |
450 /* | |
451 if (!menubar_p) | |
452 XtAddCallback (XtParent (widget), XmNpopdownCallback, | |
453 xm_pop_down_callback, (XtPointer)instance); | |
454 */ | |
455 | |
456 num_children = 0; | |
457 for (child_index = 0, cur = val; cur; child_index++, cur = cur->next) | |
458 { | |
459 ac = 0; | |
460 button = 0; | |
461 XtSetArg (al [ac], XmNsensitive, cur->enabled); ac++; | |
462 XtSetArg (al [ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++; | |
463 XtSetArg (al [ac], XmNuserData, cur->call_data); ac++; | |
464 | |
465 switch (cur->type) | |
466 { | |
467 case PUSHRIGHT_TYPE: | |
468 /* A pushright marker which is not needed for the real Motif | |
469 menubar. */ | |
470 break; | |
471 case SEPARATOR_TYPE: | |
472 ac = 0; | |
473 if (cur->value) | |
474 { | |
475 /* #### - xlwmenu.h supports several types that motif does | |
476 not. Also, motif supports pixmaps w/ type NO_LINE and | |
477 lwlib provides no way to access that functionality. --Stig */ | |
478 XtSetArg (al [ac], XmNseparatorType, cur->value), ac++; | |
479 } | |
480 button = XmCreateSeparator (widget, "separator", al, ac); | |
481 break; | |
482 case CASCADE_TYPE: | |
483 menu = XmCreatePulldownMenu (widget, "pulldown", NULL, 0); | |
484 make_menu_in_widget (instance, menu, cur->contents); | |
485 XtSetArg (al [ac], XmNsubMenuId, menu); ac++; | |
486 button = XmCreateCascadeButton (widget, cur->name, al, ac); | |
487 | |
488 xm_update_label (instance, button, cur); | |
489 | |
490 XtAddCallback (button, XmNcascadingCallback, xm_pull_down_callback, | |
491 (XtPointer)instance); | |
492 break; | |
493 default: | |
494 if (menubar_p) | |
495 button = XmCreateCascadeButton (widget, cur->name, al, ac); | |
496 else if (!cur->call_data) | |
497 button = XmCreateLabel (widget, cur->name, al, ac); | |
498 else if (cur->type == TOGGLE_TYPE || cur->type == RADIO_TYPE) | |
499 { | |
500 if (cur->type == TOGGLE_TYPE) | |
501 { | |
502 XtSetArg (al [ac], XmNindicatorType, XmN_OF_MANY); ac++; | |
503 } | |
504 else | |
505 { | |
506 XtSetArg (al [ac], XmNindicatorType, XmONE_OF_MANY); ac++; | |
507 } | |
508 | |
509 XtSetArg (al [ac], XmNvisibleWhenOff, True); ac++; | |
510 button = XmCreateToggleButtonGadget (widget, cur->name, al, ac); | |
511 } | |
512 else | |
513 button = XmCreatePushButtonGadget (widget, cur->name, al, ac); | |
514 | |
515 xm_update_label (instance, button, cur); | |
516 | |
517 /* don't add a callback to a simple label */ | |
518 if (cur->type == TOGGLE_TYPE || cur->type == RADIO_TYPE) | |
519 xm_update_toggle (instance, button, cur); | |
520 else if (cur->call_data) | |
521 XtAddCallback (button, XmNactivateCallback, xm_generic_callback, | |
522 (XtPointer)instance); | |
523 } /* switch (cur->type) */ | |
524 | |
525 if (button) | |
526 children [num_children++] = button; | |
527 } | |
528 | |
529 /* Last entry is the help button. This used be done after managing | |
530 the buttons. The comment claimed that it had to be done this way | |
531 otherwise the menubar ended up only 4 pixels high. That must | |
532 have been in the Old World. In the New World it stays the proper | |
533 height if you don't manage them until after you set this and as a | |
534 bonus the Help menu ends up where it is supposed to. */ | |
535 if (button) | |
536 { | |
537 ac = 0; | |
538 XtSetArg (al [ac], XmNmenuHelpWidget, button); ac++; | |
539 XtSetValues (widget, al, ac); | |
540 } | |
541 | |
542 if (num_children) | |
543 XtManageChildren (children, num_children); | |
544 | |
545 XtFree ((char *) children); | |
546 } | |
547 | |
548 static void | |
549 update_one_menu_entry (widget_instance* instance, Widget widget, | |
550 widget_value* val, Boolean deep_p) | |
551 { | |
552 Arg al [256]; | |
553 int ac; | |
554 Widget menu; | |
555 widget_value* contents; | |
556 | |
557 if (val->change == NO_CHANGE) | |
558 return; | |
559 | |
560 /* update the sensitivity and userdata */ | |
561 /* Common to all widget types */ | |
562 XtVaSetValues (widget, | |
563 XmNsensitive, val->enabled, | |
564 XmNuserData, val->call_data, | |
565 0); | |
566 | |
567 /* update the menu button as a label. */ | |
568 if (val->change >= VISIBLE_CHANGE) | |
569 { | |
570 xm_update_label (instance, widget, val); | |
571 if (XtClass (widget) == xmToggleButtonWidgetClass | |
572 || XtClass (widget) == xmToggleButtonGadgetClass) | |
573 { | |
574 xm_update_toggle (instance, widget, val); | |
575 } | |
576 } | |
577 | |
578 | |
579 /* update the pulldown/pullaside as needed */ | |
580 menu = NULL; | |
581 XtVaGetValues (widget, XmNsubMenuId, &menu, NULL); | |
582 | |
583 contents = val->contents; | |
584 | |
585 if (!menu) | |
586 { | |
587 if (contents) | |
588 { | |
589 menu = XmCreatePulldownMenu (widget, "pulldown", NULL, 0); | |
590 make_menu_in_widget (instance, menu, contents); | |
591 ac = 0; | |
592 XtSetArg (al [ac], XmNsubMenuId, menu); ac++; | |
593 XtSetValues (widget, al, ac); | |
594 } | |
595 } | |
596 else if (!contents) | |
597 { | |
598 ac = 0; | |
599 XtSetArg (al [ac], XmNsubMenuId, NULL); ac++; | |
600 XtSetValues (widget, al, ac); | |
601 XtDestroyWidget (menu); | |
602 } | |
603 else if (deep_p && contents->change != NO_CHANGE) | |
604 xm_update_menu (instance, menu, val, 1); | |
605 } | |
606 | |
607 static void | |
608 xm_update_menu (widget_instance* instance, Widget widget, widget_value* val, | |
609 Boolean deep_p) | |
610 { | |
611 /* Widget is a RowColumn widget whose contents have to be updated | |
612 * to reflect the list of items in val->contents */ | |
613 if (val->contents->change == STRUCTURAL_CHANGE) | |
614 { | |
615 destroy_all_children (widget); | |
616 make_menu_in_widget (instance, widget, val->contents); | |
617 } | |
618 else | |
619 { | |
620 /* Update all the buttons of the RowColumn in order. */ | |
621 Widget* children; | |
622 unsigned int num_children; | |
623 int i; | |
624 widget_value *cur = 0; | |
625 | |
626 children = XtCompositeChildren (widget, &num_children); | |
627 if (children) | |
628 { | |
629 for (i = 0, cur = val->contents; i < num_children; i++) | |
630 { | |
631 if (!cur) | |
632 abort (); | |
633 /* skip if this is a pushright marker or a separator */ | |
634 if (cur->type == PUSHRIGHT_TYPE || cur->type == SEPARATOR_TYPE) | |
635 { | |
636 cur = cur->next; | |
637 #if 0 | |
638 /* #### - this could puke if you have a separator as the | |
639 last item on a pullright menu. */ | |
640 if (!cur) | |
641 abort (); | |
642 #else | |
643 if (!cur) | |
644 continue; | |
645 #endif | |
646 } | |
647 if (children [i]->core.being_destroyed | |
648 || strcmp (XtName (children [i]), cur->name)) | |
649 continue; | |
650 update_one_menu_entry (instance, children [i], cur, deep_p); | |
651 cur = cur->next; | |
652 } | |
653 XtFree ((char *) children); | |
654 } | |
655 if (cur) | |
656 abort (); | |
657 } | |
658 } | |
659 | |
660 #endif /* MENUBARS_MOTIF */ | |
661 | |
662 | |
663 #ifdef DIALOGS_MOTIF | |
664 | |
665 /* update text widgets */ | |
666 | |
667 static void | |
668 xm_update_text (widget_instance* instance, Widget widget, widget_value* val) | |
669 { | |
670 XmTextSetString (widget, val->value ? val->value : ""); | |
671 XtRemoveAllCallbacks (widget, XmNactivateCallback); | |
672 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance); | |
673 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback); | |
674 XtAddCallback (widget, XmNvalueChangedCallback, | |
675 xm_internal_update_other_instances, instance); | |
676 } | |
677 | |
678 static void | |
679 xm_update_text_field (widget_instance* instance, Widget widget, | |
680 widget_value* val) | |
681 { | |
682 XmTextFieldSetString (widget, val->value ? val->value : ""); | |
683 XtRemoveAllCallbacks (widget, XmNactivateCallback); | |
684 XtAddCallback (widget, XmNactivateCallback, xm_generic_callback, instance); | |
685 XtRemoveAllCallbacks (widget, XmNvalueChangedCallback); | |
686 XtAddCallback (widget, XmNvalueChangedCallback, | |
687 xm_internal_update_other_instances, instance); | |
688 } | |
689 | |
690 #endif /* DIALOGS_MOTIF */ | |
691 | |
692 #ifdef SCROLLBARS_MOTIF | |
693 | |
694 /* | |
695 * If this function looks like it does a lot more work than it needs to, | |
696 * you're right. Blame the Motif scrollbar for not being smart about | |
697 * updating its appearance. | |
698 */ | |
699 static void | |
700 xm_update_scrollbar (widget_instance *instance, Widget widget, | |
701 widget_value *val) | |
702 { | |
703 if (val->scrollbar_data) | |
704 { | |
705 scrollbar_values *data = val->scrollbar_data; | |
706 int widget_sliderSize, widget_val; | |
707 int new_sliderSize, new_value; | |
708 double percent; | |
709 double h_water, l_water; | |
710 | |
711 /* | |
712 * First size and position the scrollbar widget. | |
713 */ | |
714 XtVaSetValues (widget, | |
715 XtNx, data->scrollbar_x, | |
716 XtNy, data->scrollbar_y, | |
717 XtNwidth, data->scrollbar_width, | |
718 XtNheight, data->scrollbar_height, | |
719 0); | |
720 | |
721 /* | |
722 * Now the size the scrollbar's slider. | |
723 */ | |
724 | |
725 XtVaGetValues (widget, | |
726 XmNsliderSize, &widget_sliderSize, | |
727 XmNvalue, &widget_val, | |
728 0); | |
729 | |
730 percent = (double) data->slider_size / | |
731 (double) (data->maximum - data->minimum); | |
732 new_sliderSize = (int) ((double) (INT_MAX - 1) * percent); | |
733 | |
734 percent = (double) (data->slider_position - data->minimum) / | |
735 (double) (data->maximum - data->minimum); | |
736 new_value = (int) ((double) (INT_MAX - 1) * percent); | |
737 | |
738 if (new_sliderSize > (INT_MAX - 1)) | |
739 new_sliderSize = INT_MAX - 1; | |
740 if (new_sliderSize < 1) | |
741 new_sliderSize = 1; | |
742 | |
743 if (new_value > (INT_MAX - new_sliderSize)) | |
744 new_value = INT_MAX - new_sliderSize; | |
745 else if (new_value < 1) | |
746 new_value = 1; | |
747 | |
748 h_water = 1.05; | |
749 l_water = 0.95; | |
750 if (new_sliderSize != widget_sliderSize || new_value != widget_val) | |
751 { | |
752 int force = ((INT_MAX - widget_sliderSize - widget_val) | |
753 ? 0 | |
754 : (INT_MAX - new_sliderSize - new_value)); | |
755 | |
756 if (force | |
757 || (double)new_sliderSize < (l_water * (double)widget_sliderSize) | |
758 || (double)new_sliderSize > (h_water * (double)widget_sliderSize) | |
759 || (double)new_value < (l_water * (double)widget_val) | |
760 || (double)new_value > (h_water * (double)widget_val)) | |
761 { | |
762 XmScrollBarSetValues (widget, new_value, new_sliderSize, 1, 1, | |
763 False); | |
764 } | |
765 } | |
766 } | |
767 } | |
768 | |
769 #endif /* SCROLLBARS_MOTIF */ | |
770 | |
771 | |
772 /* update a motif widget */ | |
773 | |
774 void | |
775 xm_update_one_widget (widget_instance* instance, Widget widget, | |
776 widget_value* val, Boolean deep_p) | |
777 { | |
778 WidgetClass class; | |
779 | |
780 /* Mark as not edited */ | |
781 val->edited = False; | |
782 | |
783 /* Common to all widget types */ | |
784 XtVaSetValues (widget, | |
785 XmNsensitive, val->enabled, | |
786 XmNuserData, val->call_data, | |
787 0); | |
788 | |
789 #if defined (DIALOGS_MOTIF) || defined (MENUBARS_MOTIF) | |
790 /* Common to all label like widgets */ | |
791 if (XtIsSubclass (widget, xmLabelWidgetClass)) | |
792 xm_update_label (instance, widget, val); | |
793 #endif | |
794 | |
795 class = XtClass (widget); | |
796 /* Class specific things */ | |
797 if (class == xmPushButtonWidgetClass || | |
798 class == xmArrowButtonWidgetClass) | |
799 { | |
800 xm_update_pushbutton (instance, widget, val); | |
801 } | |
802 #ifdef MENUBARS_MOTIF | |
803 else if (class == xmCascadeButtonWidgetClass) | |
804 { | |
805 xm_update_cascadebutton (instance, widget, val); | |
806 } | |
807 #endif | |
808 else if (class == xmToggleButtonWidgetClass | |
809 || class == xmToggleButtonGadgetClass) | |
810 { | |
811 xm_update_toggle (instance, widget, val); | |
812 } | |
813 else if (class == xmRowColumnWidgetClass) | |
814 { | |
815 Boolean radiobox = 0; | |
816 | |
817 XtVaGetValues (widget, XmNradioBehavior, &radiobox, NULL); | |
818 | |
819 if (radiobox) | |
820 xm_update_radiobox (instance, widget, val); | |
821 #ifdef MENUBARS_MOTIF | |
822 else | |
823 xm_update_menu (instance, widget, val, deep_p); | |
824 #endif | |
825 } | |
826 #ifdef DIALOGS_MOTIF | |
827 else if (class == xmTextWidgetClass) | |
828 { | |
829 xm_update_text (instance, widget, val); | |
830 } | |
831 else if (class == xmTextFieldWidgetClass) | |
832 { | |
833 xm_update_text_field (instance, widget, val); | |
834 } | |
835 #endif | |
836 else if (class == xmListWidgetClass) | |
837 { | |
838 xm_update_list (instance, widget, val); | |
839 } | |
840 #ifdef SCROLLBARS_MOTIF | |
841 else if (class == xmScrollBarWidgetClass) | |
842 { | |
843 xm_update_scrollbar (instance, widget, val); | |
844 } | |
845 #endif | |
846 } | |
847 | |
848 /* getting the value back */ | |
849 void | |
850 xm_update_one_value (widget_instance* instance, Widget widget, | |
851 widget_value* val) | |
852 { | |
853 WidgetClass class = XtClass (widget); | |
854 widget_value *old_wv; | |
855 | |
856 /* copy the call_data slot into the "return" widget_value */ | |
857 for (old_wv = instance->info->val->contents; old_wv; old_wv = old_wv->next) | |
858 if (!strcmp (val->name, old_wv->name)) | |
859 { | |
860 val->call_data = old_wv->call_data; | |
861 break; | |
862 } | |
863 | |
864 if (class == xmToggleButtonWidgetClass || class == xmToggleButtonGadgetClass) | |
865 { | |
866 XtVaGetValues (widget, XmNset, &val->selected, 0); | |
867 val->edited = True; | |
868 } | |
869 #ifdef DIALOGS_MOTIF | |
870 else if (class == xmTextWidgetClass) | |
871 { | |
872 if (val->value) | |
873 free (val->value); | |
874 val->value = XmTextGetString (widget); | |
875 val->edited = True; | |
876 } | |
877 else if (class == xmTextFieldWidgetClass) | |
878 { | |
879 if (val->value) | |
880 free (val->value); | |
881 val->value = XmTextFieldGetString (widget); | |
882 val->edited = True; | |
883 } | |
884 #endif | |
885 else if (class == xmRowColumnWidgetClass) | |
886 { | |
887 Boolean radiobox = 0; | |
888 | |
889 XtVaGetValues (widget, XmNradioBehavior, &radiobox, NULL); | |
890 | |
891 if (radiobox) | |
892 { | |
893 CompositeWidget radio = (CompositeWidget)widget; | |
894 int i; | |
895 for (i = 0; i < radio->composite.num_children; i++) | |
896 { | |
897 int set = False; | |
898 Widget toggle = radio->composite.children [i]; | |
899 | |
900 XtVaGetValues (toggle, XmNset, &set, 0); | |
901 if (set) | |
902 { | |
903 if (val->value) | |
904 free (val->value); | |
905 val->value = safe_strdup (XtName (toggle)); | |
906 } | |
907 } | |
908 val->edited = True; | |
909 } | |
910 } | |
911 else if (class == xmListWidgetClass) | |
912 { | |
913 int pos_cnt; | |
914 int* pos_list; | |
915 if (XmListGetSelectedPos (widget, &pos_list, &pos_cnt)) | |
916 { | |
917 int i; | |
918 widget_value* cur; | |
919 for (cur = val->contents, i = 0; cur; cur = cur->next) | |
920 if (cur->value) | |
921 { | |
922 int j; | |
923 cur->selected = False; | |
924 i += 1; | |
925 for (j = 0; j < pos_cnt; j++) | |
926 if (pos_list [j] == i) | |
927 { | |
928 cur->selected = True; | |
929 val->value = safe_strdup (cur->name); | |
930 } | |
931 } | |
932 val->edited = 1; | |
933 XtFree ((char *) pos_list); | |
934 } | |
935 } | |
936 #ifdef SCROLLBARS_MOTIF | |
937 else if (class == xmScrollBarWidgetClass) | |
938 { | |
939 /* This function is not used by the scrollbar. */ | |
940 return; | |
941 } | |
942 #endif | |
943 } | |
944 | |
945 | |
946 /* This function is for activating a button from a program. It's wrong because | |
947 we pass a NULL argument in the call_data which is not Motif compatible. | |
948 This is used from the XmNdefaultAction callback of the List widgets to | |
949 have a dble-click put down a dialog box like the button woudl do. | |
950 I could not find a way to do that with accelerators. | |
951 */ | |
952 static void | |
953 activate_button (Widget widget, XtPointer closure, XtPointer call_data) | |
954 { | |
955 Widget button = (Widget)closure; | |
956 XtCallCallbacks (button, XmNactivateCallback, NULL); | |
957 } | |
958 | |
959 /* creation functions */ | |
960 | |
961 #ifdef DIALOGS_MOTIF | |
962 | |
963 /* dialogs */ | |
964 | |
965 #if (XmVersion >= 1002) | |
966 # define ARMANDACTIVATE_KLUDGE | |
967 # define DND_KLUDGE | |
968 #endif | |
969 | |
970 #ifdef ARMANDACTIVATE_KLUDGE | |
971 /* We want typing Return at a dialog box to select the default button; but | |
972 we're satisfied with having it select the leftmost button instead. | |
973 | |
974 In Motif 1.1.5 we could do this by putting this resource in the | |
975 app-defaults file: | |
976 | |
977 *dialog*button1.accelerators:#override\ | |
978 <KeyPress>Return: ArmAndActivate()\n\ | |
979 <KeyPress>KP_Enter: ArmAndActivate()\n\ | |
980 Ctrl<KeyPress>m: ArmAndActivate()\n | |
981 | |
982 but that doesn't work with 1.2.1 and I don't understand why. However, | |
983 doing the equivalent C code does work, with the notable disadvantage that | |
984 the user can't override it. So that's what we do until we figure out | |
985 something better.... | |
986 */ | |
987 static char button_trans[] = "\ | |
988 <KeyPress>Return: ArmAndActivate()\n\ | |
989 <KeyPress>KP_Enter: ArmAndActivate()\n\ | |
990 Ctrl<KeyPress>m: ArmAndActivate()\n"; | |
991 | |
992 #endif /* ARMANDACTIVATE_KLUDGE */ | |
993 | |
994 | |
995 #ifdef DND_KLUDGE | |
996 /* This is a kludge to disable drag-and-drop in dialog boxes. The symptom | |
997 was a segv down in libXm somewhere if you used the middle button on a | |
998 dialog box to begin a drag; when you released the button to make a drop | |
999 things would lose if you were not over the button where you started the | |
1000 drag (canceling the operation). This was probably due to the fact that | |
1001 the dialog boxes were not set up to handle a drag but were trying to do | |
1002 so anyway for some reason. | |
1003 | |
1004 So we disable drag-and-drop in dialog boxes by turning off the binding for | |
1005 Btn2Down which, by default, initiates a drag. Clearly this is a shitty | |
1006 solution as it only works in default configurations, but... | |
1007 */ | |
1008 static char disable_dnd_trans[] = "<Btn2Down>: "; | |
1009 #endif /* DND_KLUDGE */ | |
1010 | |
1011 | |
1012 static Widget | |
1013 make_dialog (char* name, Widget parent, Boolean pop_up_p, | |
1014 char* shell_title, char* icon_name, Boolean text_input_slot, | |
1015 Boolean radio_box, Boolean list, | |
1016 int left_buttons, int right_buttons) | |
1017 { | |
1018 Widget result; | |
1019 Widget form; | |
1020 Widget row; | |
1021 Widget icon; | |
1022 Widget icon_separator; | |
1023 Widget message; | |
1024 Widget value = 0; | |
1025 Widget separator; | |
1026 Widget button = 0; | |
1027 Widget children [16]; /* for the final XtManageChildren */ | |
1028 int n_children; | |
1029 Arg al[64]; /* Arg List */ | |
1030 int ac; /* Arg Count */ | |
1031 int i; | |
1032 | |
1033 #ifdef DND_KLUDGE | |
1034 XtTranslations dnd_override = XtParseTranslationTable (disable_dnd_trans); | |
1035 # define DO_DND_KLUDGE(widget) XtOverrideTranslations ((widget), dnd_override) | |
1036 #else /* ! DND_KLUDGE */ | |
1037 # define DO_DND_KLUDGE(widget) | |
1038 #endif /* ! DND_KLUDGE */ | |
1039 | |
1040 if (pop_up_p) | |
1041 { | |
1042 ac = 0; | |
1043 XtSetArg(al[ac], XmNtitle, shell_title); ac++; | |
1044 XtSetArg(al[ac], XtNallowShellResize, True); ac++; | |
1045 XtSetArg(al[ac], XmNdeleteResponse, XmUNMAP); ac++; | |
1046 result = XmCreateDialogShell (parent, "dialog", al, ac); | |
1047 | |
1048 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++; | |
1049 /* XtSetArg(al[ac], XmNautoUnmanage, TRUE); ac++; */ /* ####is this ok? */ | |
1050 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; | |
1051 form = XmCreateForm (result, shell_title, al, ac); | |
1052 } | |
1053 else | |
1054 { | |
1055 ac = 0; | |
1056 XtSetArg(al[ac], XmNautoUnmanage, FALSE); ac++; | |
1057 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; | |
1058 form = XmCreateForm (parent, shell_title, al, ac); | |
1059 result = form; | |
1060 } | |
1061 | |
1062 ac = 0; | |
1063 XtSetArg(al[ac], XmNpacking, XmPACK_COLUMN); ac++; | |
1064 XtSetArg(al[ac], XmNorientation, XmVERTICAL); ac++; | |
1065 XtSetArg(al[ac], XmNnumColumns, left_buttons + right_buttons + 1); ac++; | |
1066 XtSetArg(al[ac], XmNmarginWidth, 0); ac++; | |
1067 XtSetArg(al[ac], XmNmarginHeight, 0); ac++; | |
1068 XtSetArg(al[ac], XmNspacing, 13); ac++; | |
1069 XtSetArg(al[ac], XmNadjustLast, False); ac++; | |
1070 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++; | |
1071 XtSetArg(al[ac], XmNisAligned, True); ac++; | |
1072 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++; | |
1073 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_FORM); ac++; | |
1074 XtSetArg(al[ac], XmNbottomOffset, 13); ac++; | |
1075 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; | |
1076 XtSetArg(al[ac], XmNleftOffset, 13); ac++; | |
1077 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; | |
1078 XtSetArg(al[ac], XmNrightOffset, 13); ac++; | |
1079 row = XmCreateRowColumn (form, "row", al, ac); | |
1080 | |
1081 n_children = 0; | |
1082 for (i = 0; i < left_buttons; i++) | |
1083 { | |
1084 char button_name [16]; | |
1085 sprintf (button_name, "button%d", i + 1); | |
1086 ac = 0; | |
1087 if (i == 0) | |
1088 { | |
1089 XtSetArg(al[ac], XmNhighlightThickness, 1); ac++; | |
1090 XtSetArg(al[ac], XmNshowAsDefault, TRUE); ac++; | |
1091 } | |
1092 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; | |
1093 children [n_children] = XmCreatePushButton (row, button_name, al, ac); | |
1094 DO_DND_KLUDGE (children [n_children]); | |
1095 | |
1096 if (i == 0) | |
1097 { | |
1098 button = children [n_children]; | |
1099 ac = 0; | |
1100 XtSetArg(al[ac], XmNdefaultButton, button); ac++; | |
1101 XtSetValues (row, al, ac); | |
1102 | |
1103 #ifdef ARMANDACTIVATE_KLUDGE /* See comment above */ | |
1104 { | |
1105 XtTranslations losers = XtParseTranslationTable (button_trans); | |
1106 XtOverrideTranslations (button, losers); | |
1107 XtFree ((char *) losers); | |
1108 } | |
1109 #endif /* ARMANDACTIVATE_KLUDGE */ | |
1110 } | |
1111 | |
1112 n_children++; | |
1113 } | |
1114 | |
1115 /* invisible seperator button */ | |
1116 ac = 0; | |
1117 XtSetArg (al[ac], XmNmappedWhenManaged, FALSE); ac++; | |
1118 children [n_children] = XmCreateLabel (row, "separator_button", al, ac); | |
1119 DO_DND_KLUDGE (children [n_children]); | |
1120 n_children++; | |
1121 | |
1122 for (i = 0; i < right_buttons; i++) | |
1123 { | |
1124 char button_name [16]; | |
1125 sprintf (button_name, "button%d", left_buttons + i + 1); | |
1126 ac = 0; | |
1127 XtSetArg(al[ac], XmNnavigationType, XmTAB_GROUP); ac++; | |
1128 children [n_children] = XmCreatePushButton (row, button_name, al, ac); | |
1129 DO_DND_KLUDGE (children [n_children]); | |
1130 if (! button) button = children [n_children]; | |
1131 n_children++; | |
1132 } | |
1133 | |
1134 XtManageChildren (children, n_children); | |
1135 | |
1136 ac = 0; | |
1137 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++; | |
1138 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; | |
1139 XtSetArg(al[ac], XmNbottomOffset, 13); ac++; | |
1140 XtSetArg(al[ac], XmNbottomWidget, row); ac++; | |
1141 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; | |
1142 XtSetArg(al[ac], XmNleftOffset, 0); ac++; | |
1143 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; | |
1144 XtSetArg(al[ac], XmNrightOffset, 0); ac++; | |
1145 separator = XmCreateSeparator (form, "", al, ac); | |
1146 | |
1147 ac = 0; | |
1148 XtSetArg(al[ac], XmNlabelType, XmPIXMAP); ac++; | |
1149 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; | |
1150 XtSetArg(al[ac], XmNtopOffset, 13); ac++; | |
1151 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_NONE); ac++; | |
1152 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; | |
1153 XtSetArg(al[ac], XmNleftOffset, 13); ac++; | |
1154 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++; | |
1155 icon = XmCreateLabel (form, icon_name, al, ac); | |
1156 DO_DND_KLUDGE (icon); | |
1157 | |
1158 ac = 0; | |
1159 XtSetArg(al[ac], XmNmappedWhenManaged, FALSE); ac++; | |
1160 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_WIDGET); ac++; | |
1161 XtSetArg(al[ac], XmNtopOffset, 6); ac++; | |
1162 XtSetArg(al[ac], XmNtopWidget, icon); ac++; | |
1163 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; | |
1164 XtSetArg(al[ac], XmNbottomOffset, 6); ac++; | |
1165 XtSetArg(al[ac], XmNbottomWidget, separator); ac++; | |
1166 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_NONE); ac++; | |
1167 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_NONE); ac++; | |
1168 icon_separator = XmCreateLabel (form, "", al, ac); | |
1169 DO_DND_KLUDGE (icon_separator); | |
1170 | |
1171 if (text_input_slot) | |
1172 { | |
1173 ac = 0; | |
1174 XtSetArg(al[ac], XmNcolumns, 50); ac++; | |
1175 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++; | |
1176 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; | |
1177 XtSetArg(al[ac], XmNbottomOffset, 13); ac++; | |
1178 XtSetArg(al[ac], XmNbottomWidget, separator); ac++; | |
1179 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++; | |
1180 XtSetArg(al[ac], XmNleftOffset, 13); ac++; | |
1181 XtSetArg(al[ac], XmNleftWidget, icon); ac++; | |
1182 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; | |
1183 XtSetArg(al[ac], XmNrightOffset, 13); ac++; | |
1184 value = XmCreateTextField (form, "value", al, ac); | |
1185 DO_DND_KLUDGE (value); | |
1186 } | |
1187 else if (radio_box) | |
1188 { | |
1189 Widget radio_butt; | |
1190 ac = 0; | |
1191 XtSetArg(al[ac], XmNmarginWidth, 0); ac++; | |
1192 XtSetArg(al[ac], XmNmarginHeight, 0); ac++; | |
1193 XtSetArg(al[ac], XmNspacing, 13); ac++; | |
1194 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_CENTER); ac++; | |
1195 XtSetArg(al[ac], XmNorientation, XmHORIZONTAL); ac++; | |
1196 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; | |
1197 XtSetArg(al[ac], XmNbottomOffset, 13); ac++; | |
1198 XtSetArg(al[ac], XmNbottomWidget, separator); ac++; | |
1199 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++; | |
1200 XtSetArg(al[ac], XmNleftOffset, 13); ac++; | |
1201 XtSetArg(al[ac], XmNleftWidget, icon); ac++; | |
1202 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; | |
1203 XtSetArg(al[ac], XmNrightOffset, 13); ac++; | |
1204 value = XmCreateRadioBox (form, "radiobutton1", al, ac); | |
1205 ac = 0; | |
1206 i = 0; | |
1207 radio_butt = XmCreateToggleButtonGadget (value, "radio1", al, ac); | |
1208 children [i++] = radio_butt; | |
1209 radio_butt = XmCreateToggleButtonGadget (value, "radio2", al, ac); | |
1210 children [i++] = radio_butt; | |
1211 radio_butt = XmCreateToggleButtonGadget (value, "radio3", al, ac); | |
1212 children [i++] = radio_butt; | |
1213 XtManageChildren (children, i); | |
1214 } | |
1215 else if (list) | |
1216 { | |
1217 ac = 0; | |
1218 XtSetArg(al[ac], XmNvisibleItemCount, 5); ac++; | |
1219 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_NONE); ac++; | |
1220 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; | |
1221 XtSetArg(al[ac], XmNbottomOffset, 13); ac++; | |
1222 XtSetArg(al[ac], XmNbottomWidget, separator); ac++; | |
1223 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++; | |
1224 XtSetArg(al[ac], XmNleftOffset, 13); ac++; | |
1225 XtSetArg(al[ac], XmNleftWidget, icon); ac++; | |
1226 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; | |
1227 XtSetArg(al[ac], XmNrightOffset, 13); ac++; | |
1228 value = XmCreateScrolledList (form, "list", al, ac); | |
1229 | |
1230 /* this is the easiest way I found to have the dble click in the | |
1231 list activate the default button */ | |
1232 XtAddCallback (value, XmNdefaultActionCallback, activate_button, button); | |
1233 } | |
1234 | |
1235 ac = 0; | |
1236 XtSetArg(al[ac], XmNalignment, XmALIGNMENT_BEGINNING); ac++; | |
1237 XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; | |
1238 XtSetArg(al[ac], XmNtopOffset, 13); ac++; | |
1239 XtSetArg(al[ac], XmNbottomAttachment, XmATTACH_WIDGET); ac++; | |
1240 XtSetArg(al[ac], XmNbottomOffset, 13); ac++; | |
1241 XtSetArg(al[ac], XmNbottomWidget, | |
1242 text_input_slot || radio_box || list ? value : separator); ac++; | |
1243 XtSetArg(al[ac], XmNleftAttachment, XmATTACH_WIDGET); ac++; | |
1244 XtSetArg(al[ac], XmNleftOffset, 13); ac++; | |
1245 XtSetArg(al[ac], XmNleftWidget, icon); ac++; | |
1246 XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; | |
1247 XtSetArg(al[ac], XmNrightOffset, 13); ac++; | |
1248 message = XmCreateLabel (form, "message", al, ac); | |
1249 DO_DND_KLUDGE (message); | |
1250 | |
1251 if (list) | |
1252 XtManageChild (value); | |
1253 | |
1254 i = 0; | |
1255 children [i] = row; i++; | |
1256 children [i] = separator; i++; | |
1257 if (text_input_slot || radio_box) | |
1258 { | |
1259 children [i] = value; i++; | |
1260 } | |
1261 children [i] = message; i++; | |
1262 children [i] = icon; i++; | |
1263 children [i] = icon_separator; i++; | |
1264 XtManageChildren (children, i); | |
1265 | |
1266 if (text_input_slot || list) | |
1267 { | |
1268 XtInstallAccelerators (value, button); | |
1269 XmProcessTraversal(value, XmTRAVERSE_CURRENT); | |
1270 } | |
1271 else | |
1272 { | |
1273 XtInstallAccelerators (form, button); | |
1274 XmProcessTraversal(value, XmTRAVERSE_CURRENT); | |
1275 } | |
1276 | |
1277 #ifdef DND_KLUDGE | |
1278 XtFree ((char *) dnd_override); | |
1279 #endif | |
1280 #undef DO_DND_KLUDGE | |
1281 | |
1282 return result; | |
1283 } | |
1284 | |
1285 static destroyed_instance* | |
1286 find_matching_instance (widget_instance* instance) | |
1287 { | |
1288 destroyed_instance* cur; | |
1289 destroyed_instance* prev; | |
1290 char* type = instance->info->type; | |
1291 char* name = instance->info->name; | |
1292 | |
1293 for (prev = NULL, cur = all_destroyed_instances; | |
1294 cur; | |
1295 prev = cur, cur = cur->next) | |
1296 { | |
1297 if (!strcmp (cur->name, name) | |
1298 && !strcmp (cur->type, type) | |
1299 && cur->parent == instance->parent | |
1300 && cur->pop_up_p == instance->pop_up_p) | |
1301 { | |
1302 if (prev) | |
1303 prev->next = cur->next; | |
1304 else | |
1305 all_destroyed_instances = cur->next; | |
1306 return cur; | |
1307 } | |
1308 /* do some cleanup */ | |
1309 else if (!cur->widget) | |
1310 { | |
1311 if (prev) | |
1312 prev->next = cur->next; | |
1313 else | |
1314 all_destroyed_instances = cur->next; | |
1315 free_destroyed_instance (cur); | |
1316 cur = prev ? prev : all_destroyed_instances; | |
1317 } | |
1318 } | |
1319 return NULL; | |
1320 } | |
1321 | |
1322 static void | |
1323 mark_dead_instance_destroyed (Widget widget, XtPointer closure, | |
1324 XtPointer call_data) | |
1325 { | |
1326 destroyed_instance* instance = (destroyed_instance*)closure; | |
1327 instance->widget = NULL; | |
1328 } | |
1329 | |
1330 static void | |
1331 recenter_widget (Widget widget) | |
1332 { | |
1333 Widget parent = XtParent (widget); | |
1334 Screen* screen = XtScreen (widget); | |
1335 Dimension screen_width = WidthOfScreen (screen); | |
1336 Dimension screen_height = HeightOfScreen (screen); | |
1337 Dimension parent_width = 0; | |
1338 Dimension parent_height = 0; | |
1339 Dimension child_width = 0; | |
1340 Dimension child_height = 0; | |
1341 Position x; | |
1342 Position y; | |
1343 | |
1344 XtVaGetValues (widget, XtNwidth, &child_width, XtNheight, &child_height, 0); | |
1345 XtVaGetValues (parent, XtNwidth, &parent_width, XtNheight, &parent_height, | |
1346 0); | |
1347 | |
1348 x = (((Position)parent_width) - ((Position)child_width)) / 2; | |
1349 y = (((Position)parent_height) - ((Position)child_height)) / 2; | |
1350 | |
1351 XtTranslateCoords (parent, x, y, &x, &y); | |
1352 | |
1353 if ((Dimension) (x + child_width) > screen_width) | |
1354 x = screen_width - child_width; | |
1355 if (x < 0) | |
1356 x = 0; | |
1357 | |
1358 if ((Dimension) (y + child_height) > screen_height) | |
1359 y = screen_height - child_height; | |
1360 if (y < 0) | |
1361 y = 0; | |
1362 | |
1363 XtVaSetValues (widget, XtNx, x, XtNy, y, 0); | |
1364 } | |
1365 | |
1366 static Widget | |
1367 recycle_instance (destroyed_instance* instance) | |
1368 { | |
1369 Widget widget = instance->widget; | |
1370 | |
1371 /* widget is NULL if the parent was destroyed. */ | |
1372 if (widget) | |
1373 { | |
1374 Widget focus; | |
1375 Widget separator; | |
1376 | |
1377 /* Remove the destroy callback as the instance is not in the list | |
1378 anymore */ | |
1379 XtRemoveCallback (instance->parent, XtNdestroyCallback, | |
1380 mark_dead_instance_destroyed, | |
1381 (XtPointer)instance); | |
1382 | |
1383 /* Give the focus to the initial item */ | |
1384 focus = XtNameToWidget (widget, "*value"); | |
1385 if (!focus) | |
1386 focus = XtNameToWidget (widget, "*button1"); | |
1387 if (focus) | |
1388 XmProcessTraversal(focus, XmTRAVERSE_CURRENT); | |
1389 | |
1390 /* shrink the separator label back to their original size */ | |
1391 separator = XtNameToWidget (widget, "*separator_button"); | |
1392 if (separator) | |
1393 XtVaSetValues (separator, XtNwidth, 5, XtNheight, 5, 0); | |
1394 | |
1395 /* Center the dialog in its parent */ | |
1396 recenter_widget (widget); | |
1397 } | |
1398 free_destroyed_instance (instance); | |
1399 return widget; | |
1400 } | |
1401 | |
1402 Widget | |
1403 xm_create_dialog (widget_instance* instance) | |
1404 { | |
1405 char* name = instance->info->type; | |
1406 Widget parent = instance->parent; | |
1407 Widget widget; | |
1408 Boolean pop_up_p = instance->pop_up_p; | |
1409 char* shell_name = 0; | |
1410 char* icon_name = 0; | |
1411 Boolean text_input_slot = False; | |
1412 Boolean radio_box = False; | |
1413 Boolean list = False; | |
1414 int total_buttons; | |
1415 int left_buttons = 0; | |
1416 int right_buttons = 1; | |
1417 destroyed_instance* dead_one; | |
1418 | |
1419 /* try to find a widget to recycle */ | |
1420 dead_one = find_matching_instance (instance); | |
1421 if (dead_one) | |
1422 { | |
1423 Widget recycled_widget = recycle_instance (dead_one); | |
1424 if (recycled_widget) | |
1425 return recycled_widget; | |
1426 } | |
1427 | |
1428 switch (name [0]){ | |
1429 case 'E': case 'e': | |
1430 icon_name = "dbox-error"; | |
1431 shell_name = "Error"; | |
1432 break; | |
1433 | |
1434 case 'I': case 'i': | |
1435 icon_name = "dbox-info"; | |
1436 shell_name = "Information"; | |
1437 break; | |
1438 | |
1439 case 'L': case 'l': | |
1440 list = True; | |
1441 icon_name = "dbox-question"; | |
1442 shell_name = "Prompt"; | |
1443 break; | |
1444 | |
1445 case 'P': case 'p': | |
1446 text_input_slot = True; | |
1447 icon_name = "dbox-question"; | |
1448 shell_name = "Prompt"; | |
1449 break; | |
1450 | |
1451 case 'Q': case 'q': | |
1452 icon_name = "dbox-question"; | |
1453 shell_name = "Question"; | |
1454 break; | |
1455 } | |
1456 | |
1457 total_buttons = name [1] - '0'; | |
1458 | |
1459 if (name [3] == 'T' || name [3] == 't') | |
1460 { | |
1461 text_input_slot = False; | |
1462 radio_box = True; | |
1463 } | |
1464 else if (name [3]) | |
1465 right_buttons = name [4] - '0'; | |
1466 | |
1467 left_buttons = total_buttons - right_buttons; | |
1468 | |
1469 widget = make_dialog (name, parent, pop_up_p, | |
1470 shell_name, icon_name, text_input_slot, radio_box, | |
1471 list, left_buttons, right_buttons); | |
1472 | |
1473 XtAddCallback (widget, XmNpopdownCallback, xm_nosel_callback, | |
1474 (XtPointer) instance); | |
1475 return widget; | |
1476 } | |
1477 | |
1478 #endif /* DIALOGS_MOTIF */ | |
1479 | |
1480 #ifdef MENUBARS_MOTIF | |
1481 static Widget | |
1482 make_menubar (widget_instance* instance) | |
1483 { | |
1484 Arg al[10]; | |
1485 int ac = 0; | |
1486 | |
1487 XtSetArg(al[ac], XmNmarginHeight, 0); ac++; | |
1488 XtSetArg(al[ac], XmNshadowThickness, 3); ac++; | |
1489 | |
1490 return XmCreateMenuBar (instance->parent, instance->info->name, al, ac); | |
1491 } | |
1492 | |
1493 static void | |
1494 remove_grabs (Widget shell, XtPointer closure, XtPointer call_data) | |
1495 { | |
1496 Widget menu = (Widget) closure; | |
1497 XmRemoveFromPostFromList (menu, XtParent (XtParent ((Widget) menu))); | |
1498 } | |
1499 | |
1500 static Widget | |
1501 make_popup_menu (widget_instance* instance) | |
1502 { | |
1503 Widget parent = instance->parent; | |
1504 Window parent_window = parent->core.window; | |
1505 Widget result; | |
1506 | |
1507 /* sets the parent window to 0 to fool Motif into not generating a grab */ | |
1508 parent->core.window = 0; | |
1509 result = XmCreatePopupMenu (parent, instance->info->name, NULL, 0); | |
1510 XtAddCallback (XtParent (result), XmNpopdownCallback, remove_grabs, | |
1511 (XtPointer)result); | |
1512 parent->core.window = parent_window; | |
1513 return result; | |
1514 } | |
1515 #endif /* MENUBARS_MOTIF */ | |
1516 | |
1517 #ifdef SCROLLBARS_MOTIF | |
1518 static Widget | |
1519 make_scrollbar (widget_instance *instance, int vertical) | |
1520 { | |
1521 Arg al[20]; | |
1522 int ac = 0; | |
1523 Widget scrollbar; | |
1524 | |
1525 XtSetArg (al[ac], XmNminimum, 1); ac++; | |
1526 XtSetArg (al[ac], XmNmaximum, INT_MAX); ac++; | |
1527 XtSetArg (al[ac], XmNincrement, 1); ac++; | |
1528 XtSetArg (al[ac], XmNpageIncrement, 1); ac++; | |
1529 XtSetArg (al[ac], XmNborderWidth, 0); ac++; | |
1530 if (vertical) | |
1531 { | |
1532 XtSetArg (al[ac], XmNorientation, XmVERTICAL); ac++; | |
1533 } | |
1534 else | |
1535 { | |
1536 XtSetArg (al[ac], XmNorientation, XmHORIZONTAL); ac++; | |
1537 } | |
1538 | |
1539 scrollbar = | |
1540 XmCreateScrollBar (instance->parent, instance->info->name, al, ac); | |
1541 | |
1542 XtRemoveAllCallbacks (scrollbar, XmNdecrementCallback); | |
1543 XtRemoveAllCallbacks (scrollbar, XmNdragCallback); | |
1544 XtRemoveAllCallbacks (scrollbar, XmNincrementCallback); | |
1545 XtRemoveAllCallbacks (scrollbar, XmNpageDecrementCallback); | |
1546 XtRemoveAllCallbacks (scrollbar, XmNpageIncrementCallback); | |
1547 XtRemoveAllCallbacks (scrollbar, XmNtoBottomCallback); | |
1548 XtRemoveAllCallbacks (scrollbar, XmNtoTopCallback); | |
1549 XtRemoveAllCallbacks (scrollbar, XmNvalueChangedCallback); | |
1550 | |
1551 XtAddCallback(scrollbar, XmNdecrementCallback, xm_scrollbar_callback, | |
1552 (XtPointer) instance); | |
1553 XtAddCallback(scrollbar, XmNdragCallback, xm_scrollbar_callback, | |
1554 (XtPointer) instance); | |
1555 XtAddCallback(scrollbar, XmNincrementCallback, xm_scrollbar_callback, | |
1556 (XtPointer) instance); | |
1557 XtAddCallback(scrollbar, XmNpageDecrementCallback, xm_scrollbar_callback, | |
1558 (XtPointer) instance); | |
1559 XtAddCallback(scrollbar, XmNpageIncrementCallback, xm_scrollbar_callback, | |
1560 (XtPointer) instance); | |
1561 XtAddCallback(scrollbar, XmNtoBottomCallback, xm_scrollbar_callback, | |
1562 (XtPointer) instance); | |
1563 XtAddCallback(scrollbar, XmNtoTopCallback, xm_scrollbar_callback, | |
1564 (XtPointer) instance); | |
1565 XtAddCallback(scrollbar, XmNvalueChangedCallback, xm_scrollbar_callback, | |
1566 (XtPointer) instance); | |
1567 | |
1568 return scrollbar; | |
1569 } | |
1570 | |
1571 static Widget | |
1572 make_vertical_scrollbar (widget_instance *instance) | |
1573 { | |
1574 return make_scrollbar (instance, 1); | |
1575 } | |
1576 | |
1577 static Widget | |
1578 make_horizontal_scrollbar (widget_instance *instance) | |
1579 { | |
1580 return make_scrollbar (instance, 0); | |
1581 } | |
1582 | |
1583 #endif /* SCROLLBARS_MOTIF */ | |
1584 | |
1585 /* Table of functions to create widgets */ | |
1586 | |
1587 #ifdef ENERGIZE | |
1588 | |
1589 /* interface with the XDesigner generated functions */ | |
1590 typedef Widget (*widget_maker) (Widget); | |
1591 extern Widget create_project_p_sheet (Widget parent); | |
1592 extern Widget create_debugger_p_sheet (Widget parent); | |
1593 extern Widget create_breaklist_p_sheet (Widget parent); | |
1594 extern Widget create_le_browser_p_sheet (Widget parent); | |
1595 extern Widget create_class_browser_p_sheet (Widget parent); | |
1596 extern Widget create_call_browser_p_sheet (Widget parent); | |
1597 extern Widget create_build_dialog (Widget parent); | |
1598 extern Widget create_editmode_dialog (Widget parent); | |
1599 extern Widget create_search_dialog (Widget parent); | |
1600 extern Widget create_project_display_dialog (Widget parent); | |
1601 | |
1602 static Widget | |
1603 make_one (widget_instance* instance, widget_maker fn) | |
1604 { | |
1605 Widget result; | |
1606 Arg al [64]; | |
1607 int ac = 0; | |
1608 | |
1609 if (instance->pop_up_p) | |
1610 { | |
1611 XtSetArg (al [ac], XmNallowShellResize, TRUE); ac++; | |
1612 result = XmCreateDialogShell (instance->parent, "dialog", NULL, 0); | |
1613 XtAddCallback (result, XmNpopdownCallback, &xm_nosel_callback, | |
1614 (XtPointer) instance); | |
1615 (*fn) (result); | |
1616 } | |
1617 else | |
1618 { | |
1619 result = (*fn) (instance->parent); | |
1620 XtRealizeWidget (result); | |
1621 } | |
1622 return result; | |
1623 } | |
1624 | |
1625 static Widget | |
1626 make_project_p_sheet (widget_instance* instance) | |
1627 { | |
1628 return make_one (instance, create_project_p_sheet); | |
1629 } | |
1630 | |
1631 static Widget | |
1632 make_debugger_p_sheet (widget_instance* instance) | |
1633 { | |
1634 return make_one (instance, create_debugger_p_sheet); | |
1635 } | |
1636 | |
1637 static Widget | |
1638 make_breaklist_p_sheet (widget_instance* instance) | |
1639 { | |
1640 return make_one (instance, create_breaklist_p_sheet); | |
1641 } | |
1642 | |
1643 static Widget | |
1644 make_le_browser_p_sheet (widget_instance* instance) | |
1645 { | |
1646 return make_one (instance, create_le_browser_p_sheet); | |
1647 } | |
1648 | |
1649 static Widget | |
1650 make_class_browser_p_sheet (widget_instance* instance) | |
1651 { | |
1652 return make_one (instance, create_class_browser_p_sheet); | |
1653 } | |
1654 | |
1655 static Widget | |
1656 make_call_browser_p_sheet (widget_instance* instance) | |
1657 { | |
1658 return make_one (instance, create_call_browser_p_sheet); | |
1659 } | |
1660 | |
1661 static Widget | |
1662 make_build_dialog (widget_instance* instance) | |
1663 { | |
1664 return make_one (instance, create_build_dialog); | |
1665 } | |
1666 | |
1667 static Widget | |
1668 make_editmode_dialog (widget_instance* instance) | |
1669 { | |
1670 return make_one (instance, create_editmode_dialog); | |
1671 } | |
1672 | |
1673 static Widget | |
1674 make_search_dialog (widget_instance* instance) | |
1675 { | |
1676 return make_one (instance, create_search_dialog); | |
1677 } | |
1678 | |
1679 static Widget | |
1680 make_project_display_dialog (widget_instance* instance) | |
1681 { | |
1682 return make_one (instance, create_project_display_dialog); | |
1683 } | |
1684 | |
1685 #endif /* ENERGIZE */ | |
1686 | |
1687 widget_creation_entry | |
1688 xm_creation_table [] = | |
1689 { | |
1690 #ifdef MENUBARS_MOTIF | |
1691 {"menubar", make_menubar}, | |
1692 {"popup", make_popup_menu}, | |
1693 #endif | |
1694 #ifdef SCROLLBARS_MOTIF | |
1695 {"vertical-scrollbar", make_vertical_scrollbar}, | |
1696 {"horizontal-scrollbar", make_horizontal_scrollbar}, | |
1697 #endif | |
1698 #ifdef ENERGIZE | |
1699 {"project_p_sheet", make_project_p_sheet}, | |
1700 {"debugger_p_sheet", make_debugger_p_sheet}, | |
1701 {"breaklist_psheet", make_breaklist_p_sheet}, | |
1702 {"leb_psheet", make_le_browser_p_sheet}, | |
1703 {"class_browser_psheet", make_class_browser_p_sheet}, | |
1704 {"ctree_browser_psheet", make_call_browser_p_sheet}, | |
1705 {"build", make_build_dialog}, | |
1706 {"editmode", make_editmode_dialog}, | |
1707 {"search", make_search_dialog}, | |
1708 {"project_display", make_project_display_dialog}, | |
1709 #endif /* ENERGIZE */ | |
1710 {NULL, NULL} | |
1711 }; | |
1712 | |
1713 /* Destruction of instances */ | |
1714 void | |
1715 xm_destroy_instance (widget_instance* instance) | |
1716 { | |
1717 #ifdef DIALOGS_MOTIF | |
1718 /* It appears that this is used only for dialog boxes. */ | |
1719 Widget widget = instance->widget; | |
1720 /* recycle the dialog boxes */ | |
1721 /* Disable the recycling until we can find a way to have the dialog box | |
1722 get reasonable layout after we modify its contents. */ | |
1723 if (0 | |
1724 && XtClass (widget) == xmDialogShellWidgetClass) | |
1725 { | |
1726 destroyed_instance* dead_instance = | |
1727 make_destroyed_instance (instance->info->name, | |
1728 instance->info->type, | |
1729 instance->widget, | |
1730 instance->parent, | |
1731 instance->pop_up_p); | |
1732 dead_instance->next = all_destroyed_instances; | |
1733 all_destroyed_instances = dead_instance; | |
1734 XtUnmanageChild (first_child (instance->widget)); | |
1735 XFlush (XtDisplay (instance->widget)); | |
1736 XtAddCallback (instance->parent, XtNdestroyCallback, | |
1737 mark_dead_instance_destroyed, (XtPointer)dead_instance); | |
1738 } | |
1739 else | |
1740 { | |
1741 /* This might not be necessary now that the nosel is attached to | |
1742 popdown instead of destroy, but it can't hurt. */ | |
1743 XtRemoveCallback (instance->widget, XtNdestroyCallback, | |
1744 xm_nosel_callback, (XtPointer)instance); | |
1745 | |
1746 XtDestroyWidget (instance->widget); | |
1747 } | |
1748 #endif /* DIALOGS_MOTIF */ | |
1749 } | |
1750 | |
1751 /* popup utility */ | |
1752 #ifdef MENUBARS_MOTIF | |
1753 | |
1754 void | |
1755 xm_popup_menu (Widget widget, XEvent *event) | |
1756 { | |
1757 if (event->type == ButtonPress || event->type == ButtonRelease) | |
1758 { | |
1759 /* This is so totally ridiculous: there's NO WAY to tell Motif | |
1760 that *any* button can select a menu item. Only one button | |
1761 can have that honor. | |
1762 */ | |
1763 char *trans = 0; | |
1764 if (event->xbutton.state & Button5Mask) trans = "<Btn5Down>"; | |
1765 else if (event->xbutton.state & Button4Mask) trans = "<Btn4Down>"; | |
1766 else if (event->xbutton.state & Button3Mask) trans = "<Btn3Down>"; | |
1767 else if (event->xbutton.state & Button2Mask) trans = "<Btn2Down>"; | |
1768 else if (event->xbutton.state & Button1Mask) trans = "<Btn1Down>"; | |
1769 if (trans) XtVaSetValues (widget, XmNmenuPost, trans, 0); | |
1770 XmMenuPosition (widget, (XButtonPressedEvent *) event); | |
1771 } | |
1772 XtManageChild (widget); | |
1773 } | |
1774 | |
1775 #endif | |
1776 | |
1777 #ifdef DIALOGS_MOTIF | |
1778 | |
1779 static void | |
1780 set_min_dialog_size (Widget w) | |
1781 { | |
1782 short width; | |
1783 short height; | |
1784 XtVaGetValues (w, XmNwidth, &width, XmNheight, &height, 0); | |
1785 XtVaSetValues (w, XmNminWidth, width, XmNminHeight, height, 0); | |
1786 } | |
1787 | |
1788 #endif | |
1789 | |
1790 void | |
1791 xm_pop_instance (widget_instance* instance, Boolean up) | |
1792 { | |
1793 Widget widget = instance->widget; | |
1794 | |
1795 #ifdef DIALOGS_MOTIF | |
1796 if (XtClass (widget) == xmDialogShellWidgetClass) | |
1797 { | |
1798 Widget widget_to_manage = first_child (widget); | |
1799 if (up) | |
1800 { | |
1801 XtManageChild (widget_to_manage); | |
1802 set_min_dialog_size (widget); | |
1803 XmProcessTraversal(widget, XmTRAVERSE_CURRENT); | |
1804 } | |
1805 else | |
1806 XtUnmanageChild (widget_to_manage); | |
1807 } | |
1808 else | |
1809 #endif | |
1810 { | |
1811 if (up) | |
1812 XtManageChild (widget); | |
1813 else | |
1814 XtUnmanageChild (widget); | |
1815 } | |
1816 } | |
1817 | |
1818 | |
1819 /* motif callback */ | |
1820 | |
1821 enum do_call_type { pre_activate, selection, no_selection, post_activate }; | |
1822 | |
1823 static void | |
1824 do_call (Widget widget, XtPointer closure, enum do_call_type type) | |
1825 { | |
1826 XtPointer user_data; | |
1827 widget_instance* instance = (widget_instance*)closure; | |
1828 Widget instance_widget; | |
1829 LWLIB_ID id; | |
1830 | |
1831 if (!instance) | |
1832 return; | |
1833 if (widget->core.being_destroyed) | |
1834 return; | |
1835 | |
1836 instance_widget = instance->widget; | |
1837 if (!instance_widget) | |
1838 return; | |
1839 | |
1840 id = instance->info->id; | |
1841 user_data = NULL; | |
1842 XtVaGetValues (widget, XmNuserData, &user_data, NULL); | |
1843 switch (type) | |
1844 { | |
1845 case pre_activate: | |
1846 if (instance->info->pre_activate_cb) | |
1847 instance->info->pre_activate_cb (widget, id, user_data); | |
1848 break; | |
1849 case selection: | |
1850 if (instance->info->selection_cb) | |
1851 instance->info->selection_cb (widget, id, user_data); | |
1852 break; | |
1853 case no_selection: | |
1854 if (instance->info->selection_cb) | |
1855 instance->info->selection_cb (widget, id, (XtPointer) -1); | |
1856 break; | |
1857 case post_activate: | |
1858 if (instance->info->post_activate_cb) | |
1859 instance->info->post_activate_cb (widget, id, user_data); | |
1860 break; | |
1861 default: | |
1862 abort (); | |
1863 } | |
1864 } | |
1865 | |
1866 /* Like lw_internal_update_other_instances except that it does not do | |
1867 anything if its shell parent is not managed. This is to protect | |
1868 lw_internal_update_other_instances to dereference freed memory | |
1869 if the widget was ``destroyed'' by caching it in the all_destroyed_instances | |
1870 list */ | |
1871 static void | |
1872 xm_internal_update_other_instances (Widget widget, XtPointer closure, | |
1873 XtPointer call_data) | |
1874 { | |
1875 Widget parent; | |
1876 for (parent = widget; parent; parent = XtParent (parent)) | |
1877 if (XtIsShell (parent)) | |
1878 break; | |
1879 else if (!XtIsManaged (parent)) | |
1880 return; | |
1881 lw_internal_update_other_instances (widget, closure, call_data); | |
1882 } | |
1883 | |
1884 static void | |
1885 xm_generic_callback (Widget widget, XtPointer closure, XtPointer call_data) | |
1886 { | |
1887 #if !defined (ENERGIZE) && (defined (MENUBARS_MOTIF) || defined (DIALOGS_MOTIF)) | |
1888 /* We want the selected status to change only when we decide it | |
1889 should change. Yuck but correct. */ | |
1890 if (XtClass (widget) == xmToggleButtonWidgetClass | |
1891 || XtClass (widget) == xmToggleButtonGadgetClass) | |
1892 { | |
1893 Boolean check; | |
1894 XtVaGetValues (widget, XmNset, &check, 0); | |
1895 XtVaSetValues (widget, XmNset, !check, 0); | |
1896 } | |
1897 #endif | |
1898 lw_internal_update_other_instances (widget, closure, call_data); | |
1899 do_call (widget, closure, selection); | |
1900 } | |
1901 | |
1902 #ifdef DIALOGS_MOTIF | |
1903 | |
1904 static void | |
1905 xm_nosel_callback (Widget widget, XtPointer closure, XtPointer call_data) | |
1906 { | |
1907 /* This callback is only called when a dialog box is dismissed with the wm's | |
1908 destroy button (WM_DELETE_WINDOW.) We want the dialog box to be destroyed | |
1909 in that case, not just unmapped, so that it releases its keyboard grabs. | |
1910 But there are problems with running our callbacks while the widget is in | |
1911 the process of being destroyed, so we set XmNdeleteResponse to XmUNMAP | |
1912 instead of XmDESTROY and then destroy it ourself after having run the | |
1913 callback. | |
1914 */ | |
1915 do_call (widget, closure, no_selection); | |
1916 XtDestroyWidget (widget); | |
1917 } | |
1918 | |
1919 #endif | |
1920 | |
1921 #ifdef MENUBARS_MOTIF | |
1922 | |
1923 static void | |
1924 xm_pull_down_callback (Widget widget, XtPointer closure, XtPointer call_data) | |
1925 { | |
1926 #if 0 | |
1927 if (call_data) | |
1928 { | |
1929 /* new behavior for incremental menu construction */ | |
1930 | |
1931 } | |
1932 else | |
1933 #endif | |
1934 do_call (widget, closure, pre_activate); | |
1935 } | |
1936 | |
1937 #if 0 | |
1938 static void | |
1939 xm_pop_down_callback (Widget widget, XtPointer closure, XtPointer call_data) | |
1940 { | |
1941 do_call (widget, closure, post_activate); | |
1942 } | |
1943 #endif /* 0 */ | |
1944 | |
1945 #endif /* MENUBARS_MOTIF */ | |
1946 | |
1947 #ifdef SCROLLBARS_MOTIF | |
1948 static void | |
1949 xm_scrollbar_callback (Widget widget, XtPointer closure, XtPointer call_data) | |
1950 { | |
1951 widget_instance *instance = (widget_instance *) closure; | |
1952 LWLIB_ID id; | |
1953 XmScrollBarCallbackStruct *data = | |
1954 (XmScrollBarCallbackStruct *) call_data; | |
1955 scroll_event event_data; | |
1956 scrollbar_values *val = | |
1957 (scrollbar_values *) instance->info->val->scrollbar_data; | |
1958 double percent; | |
1959 | |
1960 if (!instance || widget->core.being_destroyed) | |
1961 return; | |
1962 | |
1963 id = instance->info->id; | |
1964 | |
1965 percent = (double) (data->value - 1) / (double) (INT_MAX - 1); | |
1966 event_data.slider_value = | |
1967 (int) (percent * (double) (val->maximum - val->minimum)) + val->minimum; | |
1968 | |
1969 if (event_data.slider_value > (val->maximum - val->slider_size)) | |
1970 event_data.slider_value = val->maximum - val->slider_size; | |
1971 else if (event_data.slider_value < 1) | |
1972 event_data.slider_value = 1; | |
1973 | |
1974 if (data->event) | |
1975 { | |
1976 switch (data->event->xany.type) | |
1977 { | |
1978 case KeyPress: | |
1979 case KeyRelease: | |
1980 event_data.time = data->event->xkey.time; | |
1981 break; | |
1982 case ButtonPress: | |
1983 case ButtonRelease: | |
1984 event_data.time = data->event->xbutton.time; | |
1985 break; | |
1986 case MotionNotify: | |
1987 event_data.time = data->event->xmotion.time; | |
1988 break; | |
1989 case EnterNotify: | |
1990 case LeaveNotify: | |
1991 event_data.time = data->event->xcrossing.time; | |
1992 break; | |
1993 default: | |
1994 event_data.time = 0; | |
1995 break; | |
1996 } | |
1997 } | |
1998 else | |
1999 event_data.time = 0; | |
2000 | |
2001 switch (data->reason) | |
2002 { | |
2003 case XmCR_DECREMENT: | |
2004 event_data.action = SCROLLBAR_LINE_UP; | |
2005 break; | |
2006 case XmCR_INCREMENT: | |
2007 event_data.action = SCROLLBAR_LINE_DOWN; | |
2008 break; | |
2009 case XmCR_PAGE_DECREMENT: | |
2010 event_data.action = SCROLLBAR_PAGE_UP; | |
2011 break; | |
2012 case XmCR_PAGE_INCREMENT: | |
2013 event_data.action = SCROLLBAR_PAGE_DOWN; | |
2014 break; | |
2015 case XmCR_TO_TOP: | |
2016 event_data.action = SCROLLBAR_TOP; | |
2017 break; | |
2018 case XmCR_TO_BOTTOM: | |
2019 event_data.action = SCROLLBAR_BOTTOM; | |
2020 break; | |
2021 case XmCR_DRAG: | |
2022 event_data.action = SCROLLBAR_DRAG; | |
2023 break; | |
2024 case XmCR_VALUE_CHANGED: | |
2025 event_data.action = SCROLLBAR_CHANGE; | |
2026 break; | |
2027 default: | |
2028 event_data.action = SCROLLBAR_CHANGE; | |
2029 break; | |
2030 } | |
2031 | |
2032 if (instance->info->pre_activate_cb) | |
2033 instance->info->pre_activate_cb (widget, id, (XtPointer) &event_data); | |
2034 } | |
2035 #endif /* SCROLLBARS_MOTIF */ | |
2036 | |
2037 | |
2038 /* set the keyboard focus */ | |
2039 void | |
2040 xm_set_keyboard_focus (Widget parent, Widget w) | |
2041 { | |
2042 XmProcessTraversal (w, XmTRAVERSE_CURRENT); | |
2043 /* At some point we believed that it was necessary to use XtSetKeyboardFocus | |
2044 instead of XmProcessTraversal when using Motif >= 1.2.1, but that's bogus. | |
2045 Presumably the problem was elsewhere, and is now gone... | |
2046 */ | |
2047 } |