1 /*************************************<+>*************************************
2 *****************************************************************************
8 ** Description: This file contains source for the Manager Meta Widget.
10 *****************************************************************************
12 ** Copyright (c) 1988 by Hewlett-Packard Company
13 ** Copyright (c) 1988 by the Massachusetts Institute of Technology
15 ** Permission to use, copy, modify, and distribute this software
16 ** and its documentation for any purpose and without fee is hereby
17 ** granted, provided that the above copyright notice appear in all
18 ** copies and that both that copyright notice and this permission
19 ** notice appear in supporting documentation, and that the names of
20 ** Hewlett-Packard or M.I.T. not be used in advertising or publicity
21 ** pertaining to distribution of the software without specific, written
24 *****************************************************************************
25 *************************************<+>*************************************/
30 #include <X11/IntrinsicP.h>
31 #include <X11/Intrinsic.h>
32 #include <X11/Shell.h>
35 #include <X11/StringDefs.h>
37 static Boolean
XwFocusIsHere();
38 static void MgrDestroy();
39 static void MgrClassPartInit();
40 static void ClassInitialize();
41 static void Initialize();
42 static Boolean
SetValues();
46 /*************************************<->*************************************
48 * Default translations for all subclasses of Manager
50 * Note, if a manager subclass has additional translations it
51 * will have to duplicate this set as well.
52 *************************************<->***********************************/
54 static char defaultTranslations
[] =
55 "<EnterWindow>: enter() \n\
56 <LeaveWindow>: leave() \n\
57 <Visible>: visible() \n\
58 <FocusIn>: focusIn()";
62 /*************************************<->*************************************
64 * Default actions for all subclasses of Manager
67 *************************************<->***********************************/
69 static XtActionsRec actionsList
[] =
71 {"enter", (XtActionProc
) _XwManagerEnter
},
72 {"leave", (XtActionProc
) _XwManagerLeave
},
73 {"focusIn", (XtActionProc
) _XwManagerFocusIn
},
74 {"visible", (XtActionProc
) _XwManagerVisibility
},
78 * Resource definitions for Subclasses of Manager
81 static XtResource resources
[] =
84 XtNforeground
, XtCForeground
, XtRPixel
, sizeof (Pixel
),
85 XtOffset (XwManagerWidget
, manager
.foreground
),
86 XtRString
, "XtDefaultForeground"
90 XtNbackgroundTile
, XtCBackgroundTile
, XtRTileType
, sizeof (int),
91 XtOffset (XwManagerWidget
, manager
.background_tile
),
92 XtRString
, "background"
96 XtNhighlightThickness
, XtCHighlightThickness
, XtRInt
, sizeof (int),
97 XtOffset (XwManagerWidget
, manager
.highlight_thickness
),
102 XtNtraversalOn
, XtCTraversalOn
, XtRBoolean
, sizeof (Boolean
),
103 XtOffset (XwManagerWidget
, manager
.traversal_on
),
108 XtNlayout
, XtCLayout
, XtRLayout
, sizeof(int),
109 XtOffset(XwManagerWidget
, manager
.layout
),
110 XtRString
, "minimize"
114 XtNnextTop
, XtCCallback
, XtRCallback
, sizeof(caddr_t
),
115 XtOffset (XwManagerWidget
, manager
.next_top
),
116 XtRPointer
, (caddr_t
) NULL
122 /******************************************************************
123 * The Manager class record definition
124 ******************************************************************/
126 XwManagerClassRec XwmanagerClassRec
=
129 (WidgetClass
) &constraintClassRec
, /* superclass */
130 "XwManager", /* class_name */
131 sizeof(XwManagerRec
), /* widget_size */
132 ClassInitialize
, /* class_initialize */
133 MgrClassPartInit
, /* class part initialize */
134 FALSE
, /* class_inited */
135 Initialize
, /* initialize */
136 NULL
, /* initialize hook */
138 actionsList
, /* actions */
139 XtNumber(actionsList
), /* num_actions */
140 resources
, /* resources */
141 XtNumber(resources
), /* num_resources */
142 NULLQUARK
, /* xrm_class */
143 TRUE
, /* compress_motion */
144 TRUE
, /* compress_exposure */
145 TRUE
, /* compress enterleave */
146 FALSE
, /* visible_interest */
147 MgrDestroy
, /* destroy */
150 SetValues
, /* set_values */
151 NULL
, /* set_values_hook */
152 XtInheritSetValuesAlmost
, /* set_values_almost */
153 NULL
, /* get_values_hook */
154 NULL
, /* accept_focus */
155 XtVersion
, /* version */
156 NULL
, /* callback private */
158 NULL
, /* query geometry */
159 /* display_accelerator */ XtInheritDisplayAccelerator
,
162 { /* Composite class */
163 NULL
, /* Geometry Manager */
164 NULL
, /* Change Managed */
165 _XwManagerInsertChild
, /* Insert Child */
166 XtInheritDeleteChild
, /* Delete Child */
170 { /* constraint class fields */
181 (XwTraversalProc
) mgr_traversal
, /* Mgr class traversal handler */
182 NULL
, /* default translations */
186 WidgetClass XwmanagerWidgetClass
= (WidgetClass
) &XwmanagerClassRec
;
190 /************************************************************************
193 * Initialize the manager class structure. This is called only the
194 * first time a manager widget is created.
197 * After class init, the "translations" variable will contain the compiled
198 * translations to be used to augment a widget's translation
199 * table if they wish to have keyboard traversal on.
201 ************************************************************************/
203 static void ClassInitialize()
205 XwRegisterConverters(); /* Register Library Conversion Rtnes */
207 XwmanagerClassRec
.manager_class
.translations
=
208 XtParseTranslationTable(defaultTranslations
);
212 /************************************************************************
216 * Used by subclasses of manager to inherit class record procedures.
218 ************************************************************************/
220 static void MgrClassPartInit(w
)
224 XwManagerWidgetClass mw
= (XwManagerWidgetClass
) w
;
226 if (mw
->manager_class
.traversal_handler
== XtInheritTraversalProc
)
227 mw
->manager_class
.traversal_handler
= (XwTraversalProc
) mgr_traversal
;
235 /************************************************************************
238 * The main widget instance initialization routine.
240 ************************************************************************/
242 static void Initialize (request
, new)
245 XwManagerWidget mw
= (XwManagerWidget
) new;
249 if ((mw
->manager
.layout
< XwIGNORE
) || (mw
->manager
.layout
> XwSWINDOW
))
251 mw
->manager
.layout
= XwMINIMIZE
;
252 XtWarning("Manager: Invalid layout setting.");
256 mw
-> manager
.managed_children
= (WidgetList
) XtMalloc
257 (XwBLOCK
* sizeof(Widget
));
258 mw
-> manager
.num_slots
= XwBLOCK
;
259 mw
-> manager
.num_managed_children
= 0;
260 mw
-> manager
.active_child
= NULL
;
262 mw
-> composite
.children
= (WidgetList
) XtMalloc
263 (XwBLOCK
* sizeof(Widget
));
264 mw
-> composite
.num_slots
= XwBLOCK
;
265 mw
-> composite
.num_children
= 0;
266 /* mw -> composite.num_mapped_children = 0; for R3 */
268 mw
-> composite
.insert_position
= (XtOrderProc
) _XwInsertOrder
;
271 /* Verify the highlight and tiling resources */
273 if (mw
-> manager
.background_tile
!= XwBACKGROUND
)
275 XtWarning("Manager: Incorrect background tile.");
276 mw
-> manager
.background_tile
= XwBACKGROUND
;
280 /* If this widget is requesting traversal then augment its
281 * translation table with some additional events.
283 if (mw
->manager
.traversal_on
== True
)
285 XtAugmentTranslations((Widget
) mw
,
286 XwmanagerClassRec
.manager_class
.translations
);
287 mw
->core
.widget_class
->core_class
.visible_interest
= True
;
296 /*********************************************************************
298 * _XwManagerInsertChild
300 ********************************************************************/
303 void _XwManagerInsertChild(w
)
310 cw
= (CompositeWidget
) w
->core
.parent
;
311 if (cw
-> composite
.insert_position
!= NULL
)
312 position
= (*cw
->composite
.insert_position
)((Widget
)cw
);
314 position
= cw
->composite
.num_children
;
317 /*************************************************
318 * Allocate another block of space if needed
319 *************************************************/
320 if ((cw
-> composite
.num_children
+ 1) >
321 cw
-> composite
.num_slots
)
323 cw
-> composite
.num_slots
+= XwBLOCK
;
324 cw
-> composite
.children
= (WidgetList
)
325 XtRealloc ((caddr_t
) cw
-> composite
.children
,
326 (cw
-> composite
.num_slots
* sizeof(Widget
)));
330 /********************************************************
331 * Ripple children up one space from "position"
332 *********************************************************/
334 for (i
= cw
->composite
.num_children
; i
> position
; i
--) {
335 cw
->composite
.children
[i
] = cw
->composite
.children
[i
-1];
337 cw
->composite
.children
[position
] = w
;
338 cw
->composite
.num_children
++;
342 /***************************************************************************
345 * _XwInsertOrder (cw)
347 ************************************************************************/
349 Cardinal
_XwInsertOrder (cw
)
351 CompositeWidget cw
; /* Composite widget being inserted into */
353 Cardinal position
= cw
->composite
.num_children
;
358 /**********************************************************************
360 * _XwReManageChildren
362 * This procedure will be called by the ChangeManged procedure of
363 * each manager. It will reassemble the currently managed children
364 * into the "manager.managed_children" list.
366 ********************************************************************/
367 void _XwReManageChildren(mw
)
372 /* Put "managed children" info together again */
374 mw
-> manager
.num_managed_children
= 0;
375 for (i
=0; i
< mw
->composite
.num_children
; i
++)
377 if (mw
-> composite
.children
[i
]->core
.managed
)
379 if ((mw
-> manager
.num_managed_children
+ 1) >
380 mw
-> manager
.num_slots
)
382 mw
-> manager
.num_slots
+= XwBLOCK
;
383 mw
-> manager
.managed_children
= (WidgetList
)
384 XtRealloc ((caddr_t
) mw
-> manager
.managed_children
,
385 (mw
-> manager
.num_slots
* sizeof(Widget
)));
387 mw
-> manager
.managed_children
388 [mw
-> manager
.num_managed_children
++] =
389 mw
-> composite
.children
[i
];
395 /************************************************************************
398 * Perform and updating necessary for a set values call.
400 ************************************************************************/
402 static Boolean
SetValues (current
, request
, new, last
)
403 Widget current
, request
, new;
407 Boolean returnFlag
= False
;
408 Boolean tempTrav
, tempVisible
, tempSensitive
;
409 Boolean tempAnSensitive
, tempMapped
;
410 XwManagerWidget curmw
= (XwManagerWidget
) current
;
411 XwManagerWidget reqmw
= (XwManagerWidget
) request
;
412 XwManagerWidget newmw
= (XwManagerWidget
) new;
413 Widget tempoldActive
, old_active
;
414 XwManagerWidget parent
;
415 Boolean traversalIsHere
= False
;
416 Boolean parentIsMgr
= False
;
419 /* Verify correct new values. */
421 if (newmw
-> manager
.traversal_on
!= True
&&
422 newmw
-> manager
.traversal_on
!= False
)
423 newmw
-> manager
.traversal_on
= curmw
-> manager
.traversal_on
;
426 /* Process the change in values */
428 if ((curmw
->core
.mapped_when_managed
!= newmw
->core
.mapped_when_managed
) ||
429 (curmw
->core
.sensitive
!= newmw
->core
.sensitive
) ||
430 (curmw
->core
.ancestor_sensitive
!= newmw
->core
.ancestor_sensitive
) ||
431 (curmw
->core
.visible
!= newmw
-> core
.visible
) ||
432 (curmw
->manager
.traversal_on
!= newmw
->manager
.traversal_on
))
435 if (XwFocusIsHere(curmw
))
437 tempTrav
= curmw
->manager
.traversal_on
;
438 tempVisible
= curmw
->core
.visible
;
439 tempSensitive
= curmw
->core
.sensitive
;
440 tempAnSensitive
= curmw
->core
.ancestor_sensitive
;
441 tempMapped
= curmw
->core
.mapped_when_managed
;
443 curmw
->manager
.traversal_on
= newmw
->manager
.traversal_on
;
444 curmw
->core
.ancestor_sensitive
= newmw
->core
.ancestor_sensitive
;
445 curmw
->core
.sensitive
= newmw
->core
.sensitive
;
446 curmw
->core
.visible
= newmw
->core
.visible
;
447 curmw
->core
.mapped_when_managed
= newmw
->core
.mapped_when_managed
;
449 XwProcessTraversal (curmw
, XwTRAVERSE_HOME
, FALSE
);
451 curmw
->manager
.traversal_on
= tempTrav
;
452 curmw
->core
.visible
= tempVisible
;
453 curmw
->core
.sensitive
= tempSensitive
;
454 curmw
->core
.ancestor_sensitive
= tempAnSensitive
;
455 curmw
->core
.mapped_when_managed
= tempMapped
;
459 traversalIsHere
= False
;
462 /* There are special cases if we are the highest Xw mgr widget */
463 if (XtIsSubclass((Widget
)(parent
= (XwManagerWidget
)XtParent(newmw
)),
464 XwmanagerWidgetClass
))
467 if (parent
->manager
.active_child
== (Widget
)curmw
)
468 traversalIsHere
= True
;
470 else if (newmw
->manager
.active_child
)
471 traversalIsHere
= True
;
475 /* Clear the active child path, from us down */
476 old_active
= newmw
->manager
.active_child
;
477 newmw
->manager
.active_child
= NULL
;
479 parent
->manager
.active_child
= NULL
;
480 while (old_active
!= NULL
)
482 if (!XtIsSubclass(old_active
, XwmanagerWidgetClass
))
486 tempoldActive
= ((XwManagerWidget
)old_active
)->manager
.
488 ((XwManagerWidget
)old_active
)->manager
.active_child
= NULL
;
489 old_active
= tempoldActive
;
493 /* Find the top most manager */
496 while ((parent
->core
.parent
!= NULL
) &&
497 (XtIsSubclass(parent
->core
.parent
, XwmanagerWidgetClass
)))
498 parent
= (XwManagerWidget
)parent
->core
.parent
;
503 /* Clear the toolkit kbd focus */
504 XtSetKeyboardFocus((Widget
)parent
, NULL
);
510 if (newmw
->manager
.layout
!= curmw
->manager
.layout
)
512 if ((newmw
->manager
.layout
< XwIGNORE
) ||
513 (newmw
->manager
.layout
> XwSWINDOW
))
515 newmw
->manager
.layout
= curmw
->manager
.layout
;
516 XtWarning("Manager: Invalid layout setting.");
518 else returnFlag
= True
;
522 if (newmw
-> manager
.highlight_thickness
< 0)
524 XtWarning ("Manager: Invalid highlight thickness.");
525 newmw
-> manager
.highlight_thickness
=
526 curmw
-> manager
.highlight_thickness
;
530 if (newmw
-> manager
.background_tile
!= XwBACKGROUND
)
532 XtWarning("Manager: Incorrect background tile.");
533 newmw
-> manager
.background_tile
=
534 curmw
-> manager
.background_tile
;
537 /* Set the widget's background tile */
539 if (newmw
-> manager
.background_tile
!=
540 curmw
-> manager
.background_tile
||
541 newmw
-> manager
.foreground
!=
542 curmw
-> manager
.foreground
||
543 newmw
-> core
.background_pixel
!=
544 curmw
-> core
.background_pixel
)
547 XSetWindowAttributes attributes
;
549 if (newmw
-> manager
.background_tile
== XwFOREGROUND
)
551 valueMask
= CWBackPixel
;
552 attributes
.background_pixel
= newmw
-> manager
.foreground
;
556 valueMask
= CWBackPixel
;
557 attributes
.background_pixel
= newmw
-> core
.background_pixel
;
560 if (XtIsRealized ((Widget
)newmw
))
561 XChangeWindowAttributes (XtDisplay(newmw
), newmw
-> core
.window
,
562 valueMask
, &attributes
);
568 /* Check the geometry in relationship to the highlight thickness */
570 if ((request
-> core
.width
== 0) && (current
-> core
.width
== 0))
571 newmw
-> core
.width
+= newmw
-> manager
.highlight_thickness
* 2;
573 if ((request
-> core
.height
== 0) && (current
-> core
.height
== 0))
574 newmw
-> core
.height
+= newmw
-> manager
.highlight_thickness
* 2;
577 /* If this widget is requesting traversal then augment its
578 * translation table with some additional events.
580 if ((newmw
->manager
.traversal_on
!= curmw
->manager
.traversal_on
) &&
581 (newmw
->manager
.traversal_on
== True
))
583 /* XXX this was a hard bug! where were the XXX's?
585 * In R2 we could not pass newmw to this toolkit call! But I
586 * have found the bug!!!! In R2 it was a temporary structure (stack)
587 * but now curmw is the temporary one and newmw is real!
588 * I can see why they were worried before. Now there is no worry.
589 * Go ahead and pass newmw!
591 XtAugmentTranslations((Widget
) newmw
,
592 XwmanagerClassRec
.manager_class
.translations
);
593 newmw
->core
.widget_class
->core_class
.visible_interest
= True
;
598 /* Return flag to indicate if redraw is needed. */
605 /************************************************************************
607 * Enter, FocusIn and Leave Window procs
609 * These two procedures handle traversal activation and deactivation
610 * for manager widgets. They are invoked directly throught the
611 * the action table of a widget.
613 ************************************************************************/
615 void _XwManagerEnter (mw
, event
)
622 ul
.x
= ul
.y
= lr
.x
= lr
.y
= 0;
624 /* Only the top level manager should invoke a traversal handler*/
625 if (!XtIsSubclass (mw
-> core
.parent
, XwmanagerWidgetClass
))
628 * All external entry points into the traversal code must take
629 * care of initializing the traversal list.
633 (*(((XwManagerWidgetClass
) mw
-> core
.widget_class
) ->
634 manager_class
.traversal_handler
))
635 ((Widget
)mw
, ul
, lr
, XwTRAVERSE_CURRENT
);
643 void _XwManagerFocusIn (mw
, event
)
648 _XwManagerEnter (mw
, event
);
653 void _XwManagerLeave (mw
, event
)
660 /* if my parent is NOT a subclass of XwManager then I will assume
661 that I have left the traversal hierarchy. For the time being
662 I will set the focus back to pointer root--I should not have to
663 do this if the window manager people can come to an agreement
664 on conventions for focus change.
666 if (!XtIsSubclass (mw
-> core
.parent
, XwmanagerWidgetClass
))
667 XSetInputFocus (XtDisplay (mw
->core
.parent
),
668 PointerRoot
, RevertToNone
, CurrentTime
);
674 /************************************************************************
676 * Find a Traversable Primitive
677 * This functions is used by manager widget's traversal handlers
678 * to determine if there is a primitive in their hierarchy which
679 * can be traversed to.
681 ************************************************************************/
683 Boolean
_XwFindTraversablePrim (cw
)
691 wList
= cw
-> composite
.children
;
693 for (i
= 0; i
< cw
-> composite
.num_children
; i
++)
697 if (XtIsSubclass(w
, XwmanagerWidgetClass
) &&
698 ((((XwManagerWidget
)w
)->manager
.traversal_on
== False
) ||
699 (w
->core
.visible
== FALSE
)))
704 if (XtIsSubclass (w
, compositeWidgetClass
) && w
-> core
.managed
== True
)
706 if (_XwFindTraversablePrim ((CompositeWidget
) w
))
712 else if (XtIsSubclass (w
, XwprimitiveWidgetClass
))
714 if (w
-> core
.sensitive
== True
&&
715 w
-> core
.ancestor_sensitive
== True
&&
716 w
-> core
.visible
== True
&&
717 w
-> core
.managed
== True
&&
718 w
-> core
.mapped_when_managed
== True
&&
719 w
-> core
.being_destroyed
== False
&&
720 ((XwPrimitiveWidget
) w
)->primitive
.traversal_type
==
721 XwHIGHLIGHT_TRAVERSAL
)
728 else /* Check for non - primitive class primitives?? */
737 /*************************************<->*************************************
740 * XwTestTraversability(widget, widgetType)
744 * xxxxxxxxxxxxxxxxxxxxxxx
749 * xxxxxxxxxxxx = xxxxxxxxxxxxx
753 * xxxxxxxxxxxx = xxxxxxxxxxxxx
758 *************************************<->***********************************/
760 Boolean
XwTestTraversability(widget
, widgetType
)
764 Boolean returnFlag
=FALSE
;
766 if (XtIsSubclass (widget
, XwprimitiveWidgetClass
))
768 *widgetType
= XwPRIMITIVE
;
769 if (((XwPrimitiveWidget
) widget
)->primitive
.traversal_type
==
770 XwHIGHLIGHT_TRAVERSAL
)
774 if (XtIsSubclass (widget
, XwmanagerWidgetClass
))
776 *widgetType
= XwMANAGER
;
777 if (((XwManagerWidget
)widget
) -> manager
.traversal_on
)
784 if (widget
-> core
.sensitive
!= True
||
785 widget
-> core
.ancestor_sensitive
!= True
||
786 widget
-> core
.visible
!= True
||
787 widget
-> core
.managed
!= True
||
788 widget
-> core
.mapped_when_managed
!= True
||
789 widget
-> core
.being_destroyed
== True
)
798 static Boolean
XwFocusIsHere(mw
)
804 if (mw
->manager
.active_child
== NULL
) return(FALSE
);
805 if (XtIsSubclass(mw
->manager
.active_child
, XwmanagerWidgetClass
))
806 mw
= (XwManagerWidget
)mw
->manager
.active_child
;
808 if (XtIsSubclass(mw
->manager
.active_child
, XwprimitiveWidgetClass
))
810 if (((XwPrimitiveWidget
)mw
->manager
.active_child
)
811 ->primitive
.I_have_traversal
) return(TRUE
);
818 /*************************************<->*************************************
824 * Free up space allocated to track managed children.
828 * w = manager subclass to be destroyed.
831 *************************************<->***********************************/
833 static void MgrDestroy(w
)
836 XwManagerWidget parent
;
839 * If we are in the traversal focus path, then we need to clean
842 if (XwFocusIsHere(w
))
843 XwProcessTraversal(w
, XwTRAVERSE_HOME
, FALSE
);
844 else if ((XtIsSubclass((Widget
)(parent
= (XwManagerWidget
)XtParent(w
)),
845 XwmanagerWidgetClass
)) &&
846 (parent
->manager
.active_child
== (Widget
)w
))
848 parent
->manager
.active_child
= NULL
;
850 XtRemoveCallbacks ((Widget
)w
, XtNnextTop
, w
-> manager
.next_top
);
851 XtFree((char *) w
->manager
.managed_children
);
855 /************************************************************************
858 * Track whether a widget is visible.
860 ***********************************************************************/
861 void _XwManagerVisibility (mw
, event
)
865 XVisibilityEvent
* vEvent
= (XVisibilityEvent
*)event
;
867 if (vEvent
->state
== VisibilityFullyObscured
)
869 mw
->core
.visible
= False
;
870 if (XwFocusIsHere(mw
))
871 XwProcessTraversal (mw
, XwTRAVERSE_HOME
, FALSE
);
874 mw
->core
.visible
= True
;
880 /************************************************************************
883 * Track whether a widget is visible.
885 ***********************************************************************/
886 void _XwManagerUnmap (mw
, event
)
890 mw
->core
.visible
= False
;
891 if (XwFocusIsHere(mw
))
892 XwProcessTraversal (mw
, XwTRAVERSE_HOME
, FALSE
);