1 /**
2 *
3 * $Header: /cvsroot/lesstif/lesstif/lib/Xm-2.1/DialogS.c,v 1.3 2007/02/04 13:26:15 dannybackx Exp $
4 *
5 * derived from Xt Vendor class.c
6 *
7 * Copyright � 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 LessTif Development Team
8 * Copyright (C) 1995 Free Software Foundation, Inc.
9 * Copyright 1989 Massachusetts Institute of Technology
10 *
11 * This file is part of the GNU LessTif Library.
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Library General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Library General Public License for more details.
22 *
23 * You should have received a copy of the GNU Library General Public
24 * License along with this library; if not, write to the Free
25 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 *
27 **/
28
29 static const char rcsid[] = "$Header: /cvsroot/lesstif/lesstif/lib/Xm-2.1/DialogS.c,v 1.3 2007/02/04 13:26:15 dannybackx Exp $";
30
31 /*
32 * This controls questionable behavior. It will go away
33 *
34 #define USE_SHELL_PARENT
35 */
36
37 #include <LTconfig.h>
38
39 #include <stdio.h>
40 #include <string.h>
41
42 #include <XmI/XmI.h>
43 #include <Xm/XmP.h>
44 #include <Xm/ExtObjectP.h>
45 #include <Xm/DialogSP.h>
46 #include <Xm/DialogSEP.h>
47 #include <Xm/VendorSP.h>
48 #include <Xm/VendorSEP.h>
49 #include <Xm/BulletinBP.h>
50 #include <Xm/DisplayP.h>
51 #include <X11/StringDefs.h>
52 #include <X11/ShellP.h>
53
54 #include <XmI/DebugUtil.h>
55
56
57 static void class_initialize(void);
58 static void class_part_initialize(WidgetClass wclass);
59 static void initialize(Widget request, Widget new_w,
60 ArgList args, Cardinal *num_args);
61 static void change_managed(Widget w);
62 static void insert_child(Widget w);
63 static void delete_child(Widget w);
64 static void StructureNotifyHandler(Widget w, XtPointer closure,
65 XEvent *event, Boolean *cont);
66 static void WmProtocolHandler(Widget w, XtPointer client, XtPointer call);
67 static Boolean set_values(Widget old, Widget req, Widget new_w,
68 ArgList args, Cardinal *num_args);
69
70 static XmBaseClassExtRec _XmDialogSCoreClassExtRec = {
71 /* next_extension */ NULL,
72 /* record_type */ NULLQUARK,
73 /* version */ XmBaseClassExtVersion,
74 /* size */ sizeof(XmBaseClassExtRec),
75 /* initialize_prehook */ XmInheritInitializePrehook,
76 /* set_values_prehook */ XmInheritSetValuesPrehook,
77 /* initialize_posthook */ XmInheritInitializePosthook,
78 /* set_values_posthook */ XmInheritSetValuesPosthook,
79 /* secondary_object_class */ (WidgetClass)&xmDialogShellExtClassRec,
80 /* secondary_object_create */ XmInheritSecObjectCreate,
81 /* get_secondary_resources */ XmInheritGetSecResData,
82 /* fast_subclass */ { 0 },
83 /* get_values_prehook */ XmInheritGetValuesPrehook,
84 /* get_values_posthook */ XmInheritGetValuesPosthook,
85 /* class_part_init_prehook */ XmInheritClassPartInitPrehook,
86 /* class_part_init_posthook */ XmInheritClassPartInitPosthook,
87 /* ext_resources */ NULL,
88 /* compiled_ext_resources */ NULL,
89 /* num_ext_resources */ 0,
90 /* use_sub_resources */ False,
91 /* widget_navigable */ NULL,
92 /* focus_change */ NULL,
93 /* wrapper_data */ NULL
94 };
95
96 XmDialogShellClassRec xmDialogShellClassRec = {
97 /* Core class part */
98 {
99 /* superclass */ (WidgetClass) &transientShellClassRec,
100 /* class_name */ "XmDialogShell",
101 /* size */ sizeof(XmDialogShellRec),
102 /* class_initialize */ class_initialize,
103 /* class_part_initialize */ class_part_initialize,
104 /* class_inited */ False,
105 /* initialize */ initialize,
106 /* initialize_hook */ NULL,
107 /* realize */ XtInheritRealize,
108 /* actions */ NULL,
109 /* num_actions */ 0,
110 /* resources */ NULL,
111 /* resource_count */ 0,
112 /* xrm_class */ NULLQUARK,
113 /* compress_motion */ False,
114 /* compress_exposure */ True,
115 /* compress_enterleave */ False,
116 /* visible_interest */ False,
117 /* destroy */ NULL,
118 /* resize */ XtInheritResize,
119 /* expose */ NULL,
120 /* set_values */ set_values,
121 /* set_values_hook */ NULL,
122 /* set_values_almost */ XtInheritSetValuesAlmost,
123 /* get_values_hook */ NULL,
124 /* accept_focus */ NULL,
125 /* intrinsics version */ XtVersion,
126 /* callback offsets */ NULL,
127 /* tm_table */ XtInheritTranslations,
128 /* query_geometry */ XtInheritQueryGeometry,
129 /* display_accelerator */ NULL,
130 /* extension */ (XtPointer)&_XmDialogSCoreClassExtRec
131 },
132 /* Composite Class Part */
133 {
134 /* geometry_manager */ XtInheritGeometryManager,
135 /* change_managed */ change_managed,
136 /* insert_child */ insert_child,
137 /* delete_child */ delete_child,
138 /* extension */ NULL
139 },
140 /* Shell Class Part */
141 {
142 /* extension */ NULL
143 },
144 /* WMShell Class Part*/
145 {
146 /* extension */ NULL
147 },
148 /* Vendor Shell Class */
149 {
150 /* extension */ NULL
151 },
152 /* TransientShell Class Part */
153 {
154 /* extension */ NULL
155 },
156 /* XmDialogShell Class Part */
157 {
158 /* extension */ NULL
159 }
160 };
161
162 WidgetClass xmDialogShellWidgetClass = (WidgetClass) (&xmDialogShellClassRec);
163
164 /*
165 * resources
166 */
167 static XtResource ext_resources[] = {
168 {
169 XmNdeleteResponse, XmCDeleteResponse, XmRDeleteResponse,
170 sizeof(unsigned char),
171 XtOffsetOf(XmDialogShellExtRec, vendor.delete_response),
172 XmRImmediate, (XtPointer)XmUNMAP
173 },
174 };
175
176 XmDialogShellExtClassRec xmDialogShellExtClassRec = {
177 /* Object class part */
178 {
179 /* superclass */ (WidgetClass) &xmVendorShellExtClassRec,
180 /* class_name */ "XmDialogShellExtClass",
181 /* widget_size */ sizeof(XmDialogShellExtRec),
182 /* class_initialize */ NULL,
183 /* class_part_initialize */ NULL,
184 /* class_inited */ False,
185 /* initialize */ NULL,
186 /* initialize_hook */ NULL,
187 /* realize */ NULL,
188 /* actions */ NULL,
189 /* num_actions */ 0,
190 /* resources */ ext_resources,
191 /* num_resources */ XtNumber(ext_resources),
192 /* xrm_class */ NULLQUARK,
193 /* compress_motion */ 0,
194 /* compress_exposure */ 0,
195 /* compress_enterleave */ 0,
196 /* visible_interest */ 0,
197 /* destroy */ NULL,
198 /* resize */ NULL,
199 /* expose */ NULL,
200 /* set_values */ NULL,
201 /* set_values_hook */ NULL,
202 /* set_values_almost */ NULL,
203 /* get_values_hook */ NULL,
204 /* accept_focus */ NULL,
205 /* version */ XtVersion,
206 /* callback offsets */ NULL,
207 /* tm_table */ NULL,
208 /* query_geometry */ NULL,
209 /* display_accelerator */ NULL,
210 /* extension */ NULL
211 },
212 /* XmExtObject part */
213 {
214 /* syn_resources */ NULL,
215 /* num_syn_resources */ 0,
216 /* extension */ NULL
217 },
218 /* Desktop Class part */
219 {
220 /* child_class */ NULL,
221 /* insert_child */ XmInheritWidgetProc,
222 /* delete_child */ XmInheritWidgetProc,
223 /* extension */ NULL
224 },
225 /* ShellExt Class part */
226 {
227 /* structure_notify */ StructureNotifyHandler,
228 /* extension */ NULL
229 },
230 /* VendorClassExt Part */
231 {
232 /* delete_window_handler */ WmProtocolHandler,
233 /* offset_handler */ NULL,
234 /* extension */ NULL
235 },
236 /* DialogShellExt Part */
237 {
238 /* extension */ NULL
239 }
240 };
241
242
243 WidgetClass xmDialogShellExtObjectClass = (WidgetClass)&xmDialogShellExtClassRec;
244
245 static void
class_initialize(void)246 class_initialize(void)
247 {
248 int ncom, addon;
249 XtResourceList combined, shells;
250 Cardinal nshells, i, j;
251
252 _XmDialogSCoreClassExtRec.record_type = XmQmotif;
253
254 ncom = XtNumber(ext_resources) +
255 xmVendorShellExtClassRec.object_class.num_resources;
256
257 _XmTransformSubResources(xmVendorShellExtClassRec.object_class.resources,
258 xmVendorShellExtClassRec.object_class.
259 num_resources,
260 &shells, &nshells);
261
262 combined = (XtResourceList)XtMalloc(sizeof(XtResource) * ncom);
263
264 memcpy(combined, shells, nshells * sizeof(XtResource));
265
266 /* can't just copy. We know we need to drop one */
267 for (i = 0, addon = 0; i < XtNumber(ext_resources); i++)
268 {
269 for (j = 0; j < nshells; j++)
270 {
271 if (strcmp(combined[j].resource_name,
272 ext_resources[i].resource_name) == 0)
273 {
274 combined[j] = ext_resources[i];
275 break;
276 }
277 }
278
279 if (j == nshells)
280 {
281 combined[nshells + addon] = ext_resources[i];
282 addon++;
283 }
284 }
285
286 XtFree((char *)shells);
287
288 xmDialogShellExtClassRec.object_class.resources = combined;
289 xmDialogShellExtClassRec.object_class.num_resources = nshells + addon;
290
291 }
292
293 static void
class_part_initialize(WidgetClass widget_class)294 class_part_initialize(WidgetClass widget_class)
295 {
296 _XmFastSubclassInit(widget_class, XmDIALOG_SHELL_BIT);
297 }
298
299 static void
initialize(Widget request,Widget new_w,ArgList args,Cardinal * num_args)300 initialize(Widget request,
301 Widget new_w,
302 ArgList args,
303 Cardinal *num_args)
304 {
305 Widget par;
306
307 par = _XmFindTopMostShell(XtParent(new_w));
308
309 if (par && XtIsRealized(par))
310 {
311 Arg args[2];
312 int argc = 0;
313
314 XtSetArg(args[argc], XmNtransientFor, par);
315 argc++;
316 XtSetArg(args[argc], XmNwindowGroup, XtWindow(par));
317 argc++;
318 XtSetValues(new_w, args, argc);
319 }
320
321 if (XtWidth(new_w) == 0)
322 {
323 XtWidth(new_w) = 1;
324 }
325 if (XtHeight(new_w) == 0)
326 {
327 XtHeight(new_w) = 1;
328 }
329 }
330
331
332 static Widget
GetChild(Widget w)333 GetChild(Widget w)
334 {
335 CompositeWidget cw = (CompositeWidget)w;
336 Cardinal i;
337 extern WidgetClass xmVendorShellExtObjectClass; /* FIX ME */
338
339 /*
340 * LessTif implementation dependency : vendor shell extension objects must
341 * be ignored
342 */
343 for (i = 0; i < cw->composite.num_children; i++)
344 {
345 if ((!XtIsSubclass(cw->composite.children[i],
346 xmVendorShellExtObjectClass)) &&
347 (!XtIsSubclass(cw->composite.children[i], xmDisplayClass)))
348 {
349 return cw->composite.children[i];
350 }
351 }
352
353 return NULL;
354 }
355
356 static Boolean
set_values(Widget old,Widget req,Widget new_w,ArgList args,Cardinal * num_args)357 set_values(Widget old, Widget req, Widget new_w, ArgList args, Cardinal *num_args)
358 {
359 Widget child;
360
361 DEBUGOUT(_LtDebug(__FILE__, new_w,
362 "%s(%d):set_values - %i args\n"
363 "\t old X %5i Y %5i W %5i H %5i\n"
364 "\trequest X %5i Y %5i W %5i H %5i\n"
365 "\t new_w X %5i Y %5i W %5i H %5i\n",
366 __FILE__, __LINE__,
367 *num_args,
368 XtX(old), XtY(old),
369 XtWidth(old), XtHeight(old),
370 XtX(req), XtY(req),
371 XtWidth(req), XtHeight(req),
372 XtX(new_w), XtY(new_w),
373 XtWidth(new_w), XtHeight(new_w)));
374 DEBUGOUT(_LtDebugPrintArgList(__FILE__, new_w, args, *num_args, False));
375
376 if (CoreMappedWhenManaged(old) || !CoreMappedWhenManaged(new_w))
377 return False;
378
379 child = GetChild(new_w);
380 if (!XtIsManaged(child))
381 return False;
382
383 XtPopup(new_w, XtGrabNone);
384 return False;
385 }
386
387 static void
change_managed(Widget w)388 change_managed(Widget w)
389 {
390 Widget child;
391
392 child = GetChild(w);
393
394 DEBUGOUT(_LtDebug2(__FILE__, w, child, "ChangeManaged\n"));
395
396 /* not doing this was why popup dialogs wouldn't take focus */
397 XtSetKeyboardFocus(w, child);
398
399 if (XtIsManaged(child))
400 {
401 Boolean InitialPlacement = False;
402
403 DEBUGOUT(_LtDebug2(__FILE__, w, child, "... was not managed\n"));
404 if (!XtIsRealized(child))
405 {
406 DEBUGOUT(_LtDebug(__FILE__, child, "... Realizing\n"));
407
408 XtRealizeWidget(child);
409
410 if (XtX(w) == 0 && XtY(w) == 0)
411 {
412 InitialPlacement = True;
413 }
414 }
415
416 /* Pick up child size */
417 (void)XtMakeResizeRequest(w, XtWidth(child), XtHeight(child),
418 NULL, NULL);
419
420 /* Dialog's child should be at 0,0 */
421 if (XtX(child) != 0 || XtY(child) != 0)
422 {
423 DEBUGOUT(_LtDebug2(__FILE__, w, child,
424 "Child position %d,%d set to 0,0\n",
425 XtX(child), XtY(child)));
426 _XmMoveObject(child, 0, 0);
427 }
428
429 DEBUGOUT(_LtDebug2(__FILE__, w, child, "Shell size %d %d %d %d\n",
430 XtWidth(child), XtHeight(child),
431 XtX(w), XtY(w)));
432
433 if (XmIsBulletinBoard(child) &&
434 (InitialPlacement || BB_DefaultPosition(child)))
435 {
436 Position px, py;
437 Widget p;
438
439 p = XtParent(w);
440 /* XXX XtX and XtY give position of parent relative to its parent.
441 we need it's position relative to the screen. Let XtTranslateCoords do it. */
442 px = (XtWidth(p) - XtWidth(child)) / 2;
443 py = (XtHeight(p) - XtHeight(child)) / 2;
444 if (XtIsRealized(p))
445 {
446 XtTranslateCoords(p, px, py, &px, &py);
447 }
448
449 DEBUGOUT(_LtDebug(__FILE__, w, "def. pos. %d %d\n", px, py));
450
451 if (px < 0)
452 {
453 px = 0;
454 }
455 if (py < 0)
456 {
457 py = 0;
458 }
459
460 XtMoveWidget(w, px, py);
461 BB_DefaultPosition(child) = False;
462 }
463
464 if (XmIsBulletinBoard(child))
465 _XmBulletinBoardMap(child);
466
467 if (CoreMappedWhenManaged(w))
468 {
469 DEBUGOUT(_LtDebug(__FILE__, w, "XtPopup\n"));
470
471 XtPopup(w, XtGrabNone);
472
473 DEBUGOUT(_LtDebug2(__FILE__, w, child,
474 "Mapping shell, just to be sure\n"));
475
476 XtMapWidget(w);
477 }
478 }
479 else
480 {
481 DEBUGOUT(_LtDebug(__FILE__, (Widget)w, "XtPopDown\n"));
482 XtPopdown((Widget)w);
483
484 /* rws 1 Jun 1997
485 * Made this a 0 again because any modal grabs added to the shell with
486 * the above XtPopup do not get removed unless there is a corresponding
487 * XtPopdown.
488 * MLM: enabled this again, but moved it to *after* the popdown. This
489 * fixes certain cases (like nedit->open->ok, with no file selected).
490 */
491 DEBUGOUT(_LtDebug(__FILE__, w, "XtUnmapWidget\n"));
492 if (XmIsBulletinBoard(child)) {
493 _XmBulletinBoardUnmap(child);
494 }
495 XtUnmapWidget(w);
496 }
497
498 _XmNavigChangeManaged(w);
499 }
500
501 static void
insert_child(Widget w)502 insert_child(Widget w)
503 {
504 CompositeWidget p = (CompositeWidget)XtParent(w);
505
506 DEBUGOUT(_LtDebug2(__FILE__, (Widget)p, w, "insert_child\n"));
507
508 /* Avoid nasty side effects with the shell extension object */
509 if (!XtIsRectObj(w))
510 {
511 return;
512 }
513
514 if (!XtIsRealized((Widget)p))
515 {
516 /*
517 * Avoid Xt errors on zero width/height here by
518 * temporarily setting p's width/height to 1 and
519 * restoring them after realize.
520 */
521 Dimension ww, hh;
522
523 ww = XtWidth(p);
524 hh = XtHeight(p);
525
526 XtWidth(p) = XtHeight(p) = 1;
527
528 XtRealizeWidget((Widget)p);
529
530 XtWidth(p) = ww;
531 XtHeight(p) = hh;
532 }
533
534 #define superclass (&transientShellClassRec)
535 (*superclass->composite_class.insert_child) (w);
536 #undef superclass
537 }
538
539 static void
delete_child(Widget w)540 delete_child(Widget w)
541 {
542 Widget s = XtParent(w);
543
544 DEBUGOUT(_LtDebug2(__FILE__, s, w, "delete_child\n"));
545 DEBUGOUT(_LtDebug2("RWS", s, w,"%s:delete_child(%d)\n",
546 __FILE__, __LINE__
547 ));
548
549 if (!XtIsRectObj(w))
550 {
551 return;
552 }
553
554 /*
555 * The XtIsManaged part is probably never true. Should check Xt manuals.
556 * When we have two children, this means only one will be left. We know
557 * that's the extension object, so unmap ourselves.
558 */
559 if (XtIsManaged(w) || MGR_NumChildren(s) == 1)
560 {
561 #if 1
562 DEBUGOUT(_LtDebug(__FILE__, s, "XtUnmapWidget\n"));
563 XtUnmapWidget(s);
564 #else
565 DEBUGOUT(_LtDebug(__FILE__, s, "XtPopdown\n"));
566 XtPopdown(s);
567 #endif
568 }
569
570 #define superclass (&transientShellClassRec)
571 (*superclass->composite_class.delete_child) (w);
572 #undef superclass
573 }
574
575 static void
WmProtocolHandler(Widget w,XtPointer client,XtPointer call)576 WmProtocolHandler(Widget w, XtPointer client, XtPointer call)
577 {
578 XmVendorShellExtObject ve = (XmVendorShellExtObject)client;
579 Cardinal i;
580
581 DEBUGOUT(_LtDebug(__FILE__, w, "Dialog's WmProtocolHandler\n"));
582
583 switch (VSEP_DeleteResponse(ve))
584 {
585 case XmDESTROY:
586 XtDestroyWidget(w);
587 DEBUGOUT(_LtDebug(__FILE__, w,
588 "WmProtocolHandler(DeleteResponse XmDESTROY)\n"));
589 break;
590
591 case XmUNMAP:
592 /* The word says UNMAP but we really have to unMANAGE */
593 for (i = 0; i < MGR_NumChildren(w); i++)
594 {
595 if (XtIsManaged(MGR_Children(w)[i]))
596 {
597 DEBUGOUT(_LtDebug2(__FILE__, w, MGR_Children(w)[i],
598 "XtUnmanageChild(child)\n"));
599 XtUnmanageChild(MGR_Children(w)[i]);
600 return;
601 }
602 }
603 break;
604
605 case XmDO_NOTHING:
606 DEBUGOUT(_LtDebug(__FILE__, w,
607 "WmProtocolHandler(DeleteResponse XmNO_NOTHING)\n"));
608 return;
609 }
610 }
611
612 String
_XmMakeDialogName(String name)613 _XmMakeDialogName(String name)
614 {
615 String s;
616
617 s = XtMalloc((name ? strlen(name) : 0) + strlen(XmDIALOG_SUFFIX) + 1);
618 if (name)
619 {
620 strcpy(s, name);
621 }
622 else
623 {
624 s[0] = '\0';
625 }
626
627 strcat(s, XmDIALOG_SUFFIX);
628
629 return s;
630 }
631
632 Widget
XmCreateDialogShell(Widget parent,char * name,Arg * arglist,Cardinal argcount)633 XmCreateDialogShell(Widget parent,
634 char *name,
635 Arg *arglist,
636 Cardinal argcount)
637 {
638 Widget composite_parent;
639
640 /*
641 * First we find the first widget (starting at the parent argument)
642 * that is a composite subclass. We use this as the parent when
643 * creating the shell
644 * Correction: find shell parent, so that we can correctly set
645 * transientFor. -- MLM
646 */
647 composite_parent = parent;
648 #ifdef USE_SHELL_PARENT
649 while (!XtIsVendorShell(composite_parent))
650 {
651 composite_parent = XtParent(composite_parent);
652 }
653 #else
654 while (!XtIsComposite(composite_parent))
655 {
656 composite_parent = XtParent(composite_parent);
657 }
658 #endif
659
660 return XtCreatePopupShell(name,
661 xmDialogShellWidgetClass,
662 composite_parent,
663 arglist,
664 argcount);
665 }
666
667 static void
StructureNotifyHandler(Widget w,XtPointer closure,XEvent * event,Boolean * cont)668 StructureNotifyHandler(Widget w, XtPointer closure,
669 XEvent *event, Boolean *cont)
670 {
671 XConfigureEvent *cev = (XConfigureEvent *)event;
672 XMapEvent *mev = (XMapEvent *)event;
673 XUnmapEvent *uev = (XUnmapEvent *)event;
674 XReparentEvent *rev = (XReparentEvent *)event;
675
676 if (!XtIsSubclass(w, xmDialogShellWidgetClass))
677 {
678 return;
679 }
680
681 switch (event->type)
682 {
683 case ConfigureNotify:
684 DEBUGOUT(_LtDebug(__FILE__, w, "CONFIGURE NOTIFY: layout %d %d %d %d\n",
685 cev->x, cev->y, cev->width, cev->height));
686 break;
687
688 case MapNotify:
689 DEBUGOUT(_LtDebug(__FILE__, w, "MAP NOTIFY: window %08x\n",
690 mev->window));
691 /* rws 22 Sep 1998
692 This is causing nedit's File->Open to un-map as soon as it is
693 mapped. It seems that XtPopup never gets called for it. Does
694 nedit map this itself???
695 */
696 /*
697 if (!Shell_PoppedUp(w))
698 {
699 XtUnmapWidget(w);
700 }
701 */
702
703 break;
704
705 case UnmapNotify:
706 DEBUGOUT(_LtDebug(__FILE__, w, "UNMAP NOTIFY: window %08x\n",
707 uev->window));
708 break;
709
710 case ReparentNotify:
711 DEBUGOUT(_LtDebug(__FILE__, w, "REPARENT NOTIFY: window %08x\n",
712 rev->window));
713 break;
714
715 default:
716 DEBUGOUT(_LtDebug(__FILE__, w, "Got UNKNOWN TYPE: %d\n",
717 event->type));
718 break;
719 }
720 }
721