1 /*************************************<+>*************************************
2 *****************************************************************************
8 ** Description: Code to support a generalized traversal handler for
9 ** subclasses of XwManager.
11 *****************************************************************************
13 ** Copyright (c) 1988 by Hewlett-Packard Company
14 ** Copyright (c) 1988 by the Massachusetts Institute of Technology
16 ** Permission to use, copy, modify, and distribute this software
17 ** and its documentation for any purpose and without fee is hereby
18 ** granted, provided that the above copyright notice appear in all
19 ** copies and that both that copyright notice and this permission
20 ** notice appear in supporting documentation, and that the names of
21 ** Hewlett-Packard or M.I.T. not be used in advertising or publicity
22 ** pertaining to distribution of the software without specific, written
25 *****************************************************************************
26 *************************************<+>*************************************/
28 #include <X11/IntrinsicP.h>
29 #include <X11/Intrinsic.h>
30 #include <X11/Xutil.h>
31 #include <X11/StringDefs.h>
34 #include <stdlib.h> /* abs */
38 static void MoveNext();
39 static void MovePrev();
40 static void MoveTraversal();
43 static void TraverseToChild ();
44 static void ClearKbdFocus();
45 static Widget
RightCheck();
46 static Widget
LeftCheck();
47 static Widget
UpCheck();
48 static Widget
DownCheck();
49 static Widget
ValidChoice();
50 static Boolean
_XwManagerIsTraversable();
53 /* Structures used to maintain the traversal checklist */
60 } XwValidChoiceActions
;
75 * Globals used to maintain a list of those widgets already checked
76 * during a traversal request.
79 _XwCheckListEntry
* _XwCheckList
= NULL
;
80 int _XwCheckListSize
= 0;
81 int _XwCheckListIndex
= 0;
85 A manager's traversal handler will be invoked with:
87 Upper Left Point: (x1, y1)
88 Lower Right Point: (x2, y2)
89 Direction: XwTRAVERSE_CURRENT
102 A manager has an active child which may be NULL. Widgets under
103 consideration to receive the keyboard focus are called candidate widgets.
104 In order to be a candidate, a widget must be traversable. This means
107 1) a subclass of primitive, and
108 sensitive (it and its ancestor)
111 have its "mapped_when_managed" flag set to TRUE, and
112 traversal_type=XwHIGHLIGHT_TRAVERSAL
114 2) a composite with a traversable primitive
119 Step 1: See if the manager contains any children which are traversable.
120 If not, set the "active_child" to NULL and
121 if the parent of this manager is a subclass of manager AND
122 that parent has traversal on, then invoke its traversal
123 handling procedure directly, otherwise return focus to
126 <<<<NOTE TEST WHETHER THIS IS THE CORRECT THING TO DO, WE
127 MAY NEED 2 DIFFERENT ACTIONS DEPENDING ON THE FOCUS MODEL
130 If we do have someone who can accept the focus, then continue.
133 Step 2: The caller of this procedure supplies POINT1, POINT2 and the
134 DIRECTION. Pass control to the specified direction handler.
140 /**********************************/
141 /* Globals for Traversal Routines */
142 /**********************************/
143 static int widget_type
;
144 static XwManagerWidget parent
;
145 static Boolean parent_is_manager
;
147 void mgr_traversal (mgr
, ul
, lr
, direction
)
156 parent
= (XwManagerWidget
)mgr
->core
.parent
;
157 parent_is_manager
= XtIsSubclass((Widget
)parent
,XwmanagerWidgetClass
);
159 if (direction
== XwTRAVERSE_NEXT_TOP
)
161 if (parent_is_manager
)
163 newUl
.x
= newUl
.y
= newLr
.x
= newLr
.y
= 0;
165 (*(((XwManagerWidgetClass
)(parent
->core
.widget_class
)) ->
166 manager_class
.traversal_handler
))
167 ((Widget
)parent
, newUl
, newLr
, direction
);
171 XtCallCallbacks((Widget
)mgr
, XtNnextTop
, NULL
);
177 if ((_XwFindTraversablePrim (mgr
) == FALSE
) ||
178 (!_XwManagerIsTraversable(mgr
)))
180 if (mgr
->manager
.active_child
!= NULL
)
181 mgr
->manager
.active_child
= (Widget
)NULL
;
184 if (parent_is_manager
&& parent
->manager
.traversal_on
)
186 newUl
.x
= ul
.x
+ mgr
->core
.x
;
187 newUl
.y
= ul
.y
+ mgr
->core
.y
;
188 newLr
.x
= lr
.x
+ mgr
->core
.x
;
189 newLr
.y
= lr
.y
+ mgr
->core
.y
;
190 (*(((XwManagerWidgetClass
)(parent
->core
.widget_class
)) ->
191 manager_class
.traversal_handler
))
192 ((Widget
)parent
, newUl
, newLr
, direction
);
195 ClearKbdFocus((Widget
) mgr
);
199 /************************************
201 * THERE IS A CHILD TO TRAVERSE TO,
202 * DETERMINE DIRECTION & DO TRAVERSAL
204 ************************************/
207 case XwTRAVERSE_NEXT
:
208 MoveNext((XwManagerWidget
)mgr
,ul
, lr
, direction
); return;
209 case XwTRAVERSE_PREV
:
210 MovePrev((XwManagerWidget
)mgr
,ul
, lr
, direction
); return;
211 case XwTRAVERSE_DOWN
:
213 case XwTRAVERSE_RIGHT
:
214 case XwTRAVERSE_LEFT
:
215 MoveTraversal((XwManagerWidget
)mgr
,ul
, lr
, direction
); return;
216 case XwTRAVERSE_CURRENT
:
217 Start((XwManagerWidget
)mgr
, ul
, lr
,direction
); return;
218 case XwTRAVERSE_HOME
:
219 Home((XwManagerWidget
)mgr
, ul
, lr
,direction
); return;
225 DIRECTION = RIGHT (All other directions are just variations of this)
228 Step 1) Find the widget to the right of the active child.
230 If widget A is the current active child and its upper left and lower right
231 points are defined by (x1,y1) and (x2,y2) respectively; and widget B is
232 a candidate widget whose upper left and lower right points are defined by
233 (x1',y1') and (x2',y2'). Then widget B is to the right of widget A
235 IFF ((x1 < x1') OR (if (x1 = x1') then (x2' > x2))
236 AND (y1 <= y2') AND (y2 >= y1')
238 If there is more than 1 candidate then choose the candidate with the
243 If 2 or more candidates have the same value for (x1'-x1) then choose the
244 candidate with the smallest value for:
248 If 2 or more candidates have the same value for |(x2'-x2)| then choose
249 the candidate with the largest overlap of widget A along its y dimension:
256 overlap = height of active child
264 overlap = height of candidate
266 If 2 or more candidates have the same overlap then choose the widget with
267 the smallest value for y1'.
269 If 2 or more candidates have the same value for y1' then choose the widget with
270 the smallest value for y2'.
272 It should not be possible for 2 candidates to get this far since it would
273 mean that one exactly overlaps the other, which should mean that the
274 visibility flag of the obscured widget should be FALSE (thus making it
275 un-traversable), however, if we do get this far, arbitrarily choose the
279 Step 2) If no widget is to the right of the active child then:
281 if widget A's grandparent is a subclass of XwManager
283 -set manager's active child field to NULL
284 -invoke grandparent's traversal handler with:
286 Upper Left Point: x1=x1+parent's x coordinate
287 y1=y1+parent's y coordinate
290 Lower Right Point: x2=x2+parent's x coordinate
291 y2=y2+parent's y coordinate
293 Direction = XwTRAVERSE_RIGHT
297 if widget A's grandparent is NOT a subclass of XwManager
299 -set manager's active child field to NULL
300 -invoke parent's traversal handler with:
302 Upper Left Point: x1=0, y1=y1;
304 Lower Right Point: x2=0, y2=y2;
306 Direction = XwTRAVERSE_RIGHT
309 Step 3) If a candidate has been chosen, then set it as the active child of
312 if it is a subclass of XwPrimitive
314 -give it keyboard focus using XSetInputFocus function.
317 else (its a manager subclass)
318 -invoke its traversal handler with:
320 Upper Left Point: x1=x1 - x1'; y1=y1 - y1'
322 Lower Right Point: x2=x2 - x2'; y2=y2 - y2'
324 Direction = XwTRAVERSE_RIGHT
328 static void MoveTraversal (mw
, ul
, lr
, direction
)
334 Widget candidate
, chosen
;
335 int chosen_widget_type
;
337 XPoint cand_ul
, cand_lr
;
341 while (++i
< mw
->composite
.num_children
)
343 candidate
= mw
->composite
.children
[i
];
344 if ((candidate
!= mw
->manager
.active_child
) &&
345 XwTestTraversability(candidate
, &widget_type
))
347 cand_ul
.x
= candidate
->core
.x
;
348 cand_ul
.y
= candidate
->core
.y
;
349 cand_lr
.x
= candidate
->core
.x
+ candidate
->core
.width
+
350 (candidate
->core
.border_width
<< 1) - 1;
351 cand_lr
.y
= candidate
->core
.y
+ candidate
->core
.height
+
352 (candidate
->core
.border_width
<< 1) - 1;
356 case XwTRAVERSE_RIGHT
:
357 chosen
=RightCheck (chosen
, ul
, lr
, candidate
, cand_ul
, cand_lr
);
360 case XwTRAVERSE_LEFT
:
361 chosen
= LeftCheck (chosen
, ul
, lr
, candidate
, cand_ul
, cand_lr
);
365 chosen
= UpCheck (chosen
, ul
, lr
, candidate
, cand_ul
, cand_lr
);
368 case XwTRAVERSE_DOWN
:
369 chosen
= DownCheck (chosen
, ul
, lr
, candidate
, cand_ul
, cand_lr
);
375 if (chosen
== candidate
) chosen_widget_type
= widget_type
;
378 if (chosen
== NULL
) /* no widget in specified direction! */
381 * Since our parent is a manager, see if there is another sibling
382 * of ours which can be traversed to.
384 mw
->manager
.active_child
= NULL
;
385 if (parent_is_manager
) /* really grandparent of active child */
387 /* Add ourselves to the active list */
388 ValidChoice (mw
, mw
, XwADD_TO_ACTIVE_LIST
);
394 (*(((XwManagerWidgetClass
)(parent
->core
.widget_class
)) ->
395 manager_class
.traversal_handler
))
396 ((Widget
)parent
, ul
, lr
, direction
);
400 /* Wrap to opposite edge */
402 /* Clear the active traversal list */
403 ValidChoice (NULL
, NULL
, XwCLEAR_ACTIVE_LIST
);
407 case XwTRAVERSE_RIGHT
:
414 case XwTRAVERSE_LEFT
:
416 ul
.x
= mw
->core
.width
+ (mw
->core
.border_width
<< 1);
417 lr
.x
= mw
->core
.width
+ (mw
->core
.border_width
<< 1);
423 ul
.y
= mw
->core
.height
+ (mw
->core
.border_width
<< 1);
424 lr
.y
= mw
->core
.height
+ (mw
->core
.border_width
<< 1);
428 case XwTRAVERSE_DOWN
:
436 (*(((XwManagerWidgetClass
)(mw
->core
.widget_class
)) ->
437 manager_class
.traversal_handler
))
438 ((Widget
)mw
, ul
, lr
, direction
);
443 ValidChoice(chosen
, chosen
, XwADD_TO_CHOSEN_LIST
);
444 TraverseToChild(mw
, chosen
, ul
, lr
, direction
);
450 static void Start (mw
, ul
, lr
, direction
)
455 Widget candidate
, chosen
;
460 /* To prevent endless recursion, see if the child has already been checked */
461 if ((mw
->manager
.active_child
!= NULL
) &&
462 (ValidChoice(NULL
, mw
->manager
.active_child
, XwVERIFY_ONLY
)))
464 if (XwTestTraversability(mw
->manager
.active_child
, &widget_type
))
466 ValidChoice(chosen
, chosen
, XwADD_TO_CHOSEN_LIST
);
467 TraverseToChild (mw
, mw
->manager
.active_child
, ul
, lr
, direction
);
472 while (i
< mw
->composite
.num_children
)
474 candidate
= mw
->composite
.children
[i
];
475 if (XwTestTraversability(candidate
, &widget_type
))
478 chosen
= ValidChoice(chosen
, candidate
, XwVERIFY_ONLY
);
482 if ((candidate
->core
.x
+candidate
->core
.y
) <
483 (chosen
->core
.x
+chosen
->core
.y
))
484 chosen
= ValidChoice(chosen
, candidate
,
492 ValidChoice(chosen
, chosen
, XwADD_TO_CHOSEN_LIST
);
493 TraverseToChild(mw
, chosen
, ul
, lr
, direction
);
500 /* We are guaranteed that there is a child to traverse to! */
502 static void MoveNext (mw
, ul
, lr
, direction
)
509 parent
= (XwManagerWidget
)mw
->core
.parent
;
510 parent_is_manager
= XtIsSubclass((Widget
)parent
,XwmanagerWidgetClass
);
512 if (mw
->manager
.active_child
!= NULL
)
514 ul
.x
= (mw
->manager
.active_child
)->core
.x
;
515 ul
.y
= (mw
->manager
.active_child
)->core
.y
;
516 lr
.x
= ul
.x
+ (mw
->manager
.active_child
)->core
.width
+
517 ((mw
->manager
.active_child
)->core
.border_width
<< 1) - 1;
518 lr
.y
= ul
.y
+ (mw
->manager
.active_child
)->core
.height
+
519 ((mw
->manager
.active_child
)->core
.border_width
<< 1) - 1;
521 /* FIND INDEX OF CURRENTLY ACTIVE CHILD */
522 while ((mw
->composite
.children
[i
] != mw
->manager
.active_child
) &&
523 (i
< mw
->composite
.num_children
))i
++;
526 /* START LOOKING AT START OF LIST + 1 (TO ALLOW FOR 1ST DECREMENT)
527 * NOTE: THIS ALSO TAKES CARE OF THE DEGENERATE CASE WHEN THERE
528 * ARE NO CHILDREN. IN THIS CASE THE PARENT "MUST" BE A SUBCLASS
529 * OF XWMANAGER OR WE WOULD NEVER HAVE GOTTEN HERE.
534 * IF WE'VE COME TO THE END OF THE WIDGET LIST AND THE PARENT
535 * IS ALSO A SUBCLASS OF XWMANAGER, THEN INVOKE THE PARENT'S
536 * TRAVERSAL HANDLER, OTHERWISE, WRAP THE COUNTER TO START LOOKING
539 if (++i
>= mw
->composite
.num_children
)
541 if (parent_is_manager
)
543 mw
->manager
.active_child
= NULL
;
544 (*(((XwManagerWidgetClass
)(parent
->core
.widget_class
)) ->
545 manager_class
.traversal_handler
))
546 ((Widget
)parent
, ul
, lr
, direction
);
553 /* FIND NEXT TRAVERSABLE WIDGET --THERE MUST BE ONE! */
554 while (! XwTestTraversability(mw
->composite
.children
[i
], &widget_type
))
555 if (++i
>= mw
->composite
.num_children
) i
=0;
557 TraverseToChild(mw
, mw
->composite
.children
[i
], ul
, lr
, direction
);
563 /* We are guaranteed that there is a child to traverse to! */
565 static void MovePrev (mw
, ul
, lr
, direction
)
572 parent
= (XwManagerWidget
)mw
->core
.parent
;
573 parent_is_manager
= XtIsSubclass((Widget
)parent
,XwmanagerWidgetClass
);
575 if (mw
->manager
.active_child
!= NULL
)
577 ul
.x
= (mw
->manager
.active_child
)->core
.x
;
578 ul
.y
= (mw
->manager
.active_child
)->core
.y
;
579 lr
.x
= ul
.x
+ (mw
->manager
.active_child
)->core
.width
+
580 ((mw
->manager
.active_child
)->core
.border_width
<< 1) - 1;
581 lr
.y
= ul
.y
+ (mw
->manager
.active_child
)->core
.height
+
582 ((mw
->manager
.active_child
)->core
.border_width
<< 1) - 1;
584 /* FIND INDEX OF CURRENTLY ACTIVE CHILD */
585 i
=mw
->composite
.num_children
-1;
586 while ((mw
->composite
.children
[i
] != mw
->manager
.active_child
) &&
590 /* START LOOKING AT END OF LIST + 1 (TO ALLOW FOR 1ST DECREMENT)
591 * NOTE: THIS ALSO TAKES CARE OF THE DEGENERATE CASE WHEN THERE
592 * ARE NO CHILDREN. IN THIS CASE THE PARENT "MUST" BE A SUBCLASS
593 * OF XWMANAGER OR WE WOULD NEVER HAVE GOTTEN HERE.
595 i
= mw
->composite
.num_children
;
599 * IF WE'VE COME TO THE END OF THE WIDGET LIST AND THE PARENT
600 * IS ALSO A SUBCLASS OF XWMANAGER, THEN INVOKE THE PARENT'S
601 * TRAVERSAL HANDLER, OTHERWISE, WRAP THE COUNTER TO START LOOKING
606 if (parent_is_manager
)
608 mw
->manager
.active_child
= NULL
;
609 (*(((XwManagerWidgetClass
)(parent
->core
.widget_class
)) ->
610 manager_class
.traversal_handler
))
611 ((Widget
)parent
, ul
, lr
, direction
);
615 i
= (mw
->composite
.num_children
)-1;
619 /* FIND NEXT TRAVERSABLE WIDGET --THERE MUST BE ONE! */
620 while (! XwTestTraversability(mw
->composite
.children
[i
], &widget_type
))
621 if (--i
< 0) i
= (mw
->composite
.num_children
)-1;
623 TraverseToChild (mw
, mw
->composite
.children
[i
], ul
, lr
, direction
);
631 static int Overlap (pt1
, pt2
, w
)
635 XPoint pt1_prime
, pt2_prime
;
637 pt1_prime
.x
= w
->core
.x
;
638 pt1_prime
.y
= w
->core
.y
;
639 pt2_prime
.x
= w
->core
.x
+ w
->core
.width
+ (w
->core
.border_width
<< 1) - 1;
640 pt2_prime
.y
= w
->core
.y
+ w
->core
.height
+ (w
->core
.border_width
<< 1) - 1;
642 if (pt2_prime
.y
>= pt2
.y
)
644 if (pt1_prime
.y
<= pt1
.y
)
645 return(pt2
.y
- pt1
.y
);
647 return(pt2
.y
- pt1_prime
.y
);
651 if (pt1_prime
.y
<= pt1
.y
)
652 return(pt2_prime
.y
- pt1
.y
);
654 return(w
->core
.height
);
659 /* CALCULATE OVERLAP IN X DIRECTION */
660 static int xOverlap (pt1
, pt2
, w
)
664 XPoint pt1_prime
, pt2_prime
;
666 pt1_prime
.x
= w
->core
.x
;
667 pt1_prime
.y
= w
->core
.y
;
668 pt2_prime
.x
= w
->core
.x
+ w
->core
.width
+ (w
->core
.border_width
<< 1) - 1;
669 pt2_prime
.y
= w
->core
.y
+ w
->core
.height
+ (w
->core
.border_width
<< 1) - 1;
671 if (pt2_prime
.x
>= pt2
.x
)
673 if (pt1_prime
.x
<= pt1
.x
)
674 return(pt2
.x
- pt1
.x
);
676 return(pt2
.x
- pt1_prime
.x
);
680 if (pt1_prime
.x
<= pt1
.x
)
681 return(pt2_prime
.x
- pt1
.x
);
683 return(w
->core
.width
);
689 * HOME: If I get called there is NO guarantee that there is something
690 * which is traversable. This is due to the way that X generates
691 * its visiblity events; the manager is notified before its children.
692 * Thus, the manager may still think it has traversable children,
693 * when in fact it doesn't. That is why we must have a special
694 * check to see that a child really was chosen.
697 static void Home (mw
, ul
, lr
, direction
)
702 Widget candidate
, chosen
;
703 int chosen_widget_type
;
709 search thru list of children to find child which is closest to
710 origin and which is traversable.
712 while (++i
< mw
->composite
.num_children
)
714 candidate
= mw
->composite
.children
[i
];
715 if (XwTestTraversability(candidate
, &widget_type
))
718 chosen
= ValidChoice(chosen
, candidate
, XwVERIFY_ONLY
);
721 if ((candidate
->core
.x
+candidate
->core
.y
) <
722 (chosen
->core
.x
+chosen
->core
.y
))
723 chosen
= ValidChoice(chosen
, candidate
, XwVERIFY_ONLY
);
726 if (chosen
== candidate
) chosen_widget_type
= widget_type
;
730 * If the closest to home widget is NOT the current active child then
731 * make it the active child. Otherwise, try and go up a level.
734 if (mw
->manager
.active_child
!= chosen
)
736 mw
->manager
.active_child
=chosen
;
737 ValidChoice(chosen
, chosen
, XwADD_TO_CHOSEN_LIST
);
739 if (chosen_widget_type
== XwPRIMITIVE
)
741 TraverseToChild(mw
, chosen
, ul
, lr
, direction
);
744 (*(((XwManagerWidgetClass
)(chosen
->core
.widget_class
)) ->
745 manager_class
.traversal_handler
))
746 (chosen
, ul
, lr
, direction
);
749 else /* WE ARE ALREADY HOMED IN THIS MANAGER, GO UP */
751 if (parent_is_manager
) /* really grandparent of active child */
753 mw
->manager
.active_child
= NULL
;
754 (*(((XwManagerWidgetClass
)(parent
->core
.widget_class
)) ->
755 manager_class
.traversal_handler
))
756 ((Widget
)parent
, ul
, lr
, direction
);
759 /* If our parent is not a manager, then we are already
760 as HOME as we are going to get, so do nothing. */
766 static void TraverseToChild (mw
, chosen
, ul
, lr
, direction
)
773 Widget topmost_manager
= (Widget
) mw
;
775 mw
->manager
.active_child
= chosen
;
776 if (XtIsSubclass(chosen
, XwprimitiveWidgetClass
))
778 while ((topmost_manager
->core
.parent
!= NULL
) &&
779 XtIsSubclass((Widget
)(topmost_manager
->core
.parent
),
780 XwmanagerWidgetClass
))
781 topmost_manager
= topmost_manager
->core
.parent
;
783 XtSetKeyboardFocus(topmost_manager
, chosen
);
787 ul
.x
-= chosen
->core
.x
;
788 ul
.y
-= chosen
->core
.y
;
789 lr
.x
-= chosen
->core
.x
;
790 lr
.y
-= chosen
->core
.y
;
791 (*(((XwManagerWidgetClass
)(chosen
->core
.widget_class
)) ->
792 manager_class
.traversal_handler
))
793 (chosen
, ul
, lr
, direction
);
800 /*************************************<->*************************************
806 * Useful when an application has created multiple top level
807 * hierarchies of widgets, is using keyboard traversal and
808 * wishes to move between them.
811 * Inputs: w = widget which is the new top level widget.
814 *************************************<->***********************************/
822 /* MOVE MOUSE INTO NEW WINDOW HIERARCHY */
823 XWarpPointer(XtDisplay(w
), None
, XtWindow(w
),0,0,0,0,1,1);
825 /* SET FOCUS HERE, SHOULD WORK FOR ALL FOCUS MODES */
826 XSetInputFocus (XtDisplay(w
), XtWindow(w
), RevertToParent
,
832 static Widget
RightCheck (chosen
, ul
, lr
, candidate
, cand_ul
, cand_lr
)
834 Widget chosen
, candidate
;
835 XPoint ul
, lr
, cand_ul
, cand_lr
;
838 if (((ul
.x
< cand_ul
.x
) || ((ul
.x
== cand_ul
.x
) && (lr
.x
< cand_lr
.x
))) &&
839 (ul
.y
<= cand_lr
.y
) && (lr
.y
>= cand_ul
.y
))
842 chosen
= ValidChoice(chosen
, candidate
, XwVERIFY_ONLY
);
845 if (chosen
->core
.x
> cand_ul
.x
)
846 chosen
= ValidChoice(chosen
, candidate
, XwVERIFY_ONLY
);
848 if (cand_ul
.x
== chosen
->core
.x
)
850 if (abs(cand_lr
.x
- lr
.x
) <
851 abs((chosen
->core
.x
+chosen
->core
.width
+
852 (chosen
->core
.border_width
<< 1))-lr
.x
))
853 chosen
= ValidChoice(chosen
, candidate
, XwVERIFY_ONLY
);
855 if (abs(cand_lr
.x
- lr
.x
) ==
856 abs((chosen
->core
.x
+chosen
->core
.width
+
857 (chosen
->core
.border_width
<< 1))-lr
.x
))
859 if (Overlap(ul
, lr
, candidate
) > Overlap(ul
, lr
, chosen
))
860 chosen
= ValidChoice(chosen
, candidate
, XwVERIFY_ONLY
);
863 if (Overlap(ul
,lr
,candidate
) == Overlap(ul
,lr
,chosen
))
864 if (cand_ul
.y
< chosen
->core
.y
)
865 chosen
= ValidChoice(chosen
, candidate
,
869 if (cand_ul
.y
== chosen
->core
.y
)
870 if (cand_lr
.y
< chosen
->core
.y
+
871 chosen
->core
.height
+
872 (chosen
->core
.border_width
<< 1))
873 chosen
= ValidChoice(chosen
,
885 static Widget
LeftCheck (chosen
, ul
, lr
, candidate
, cand_ul
, cand_lr
)
887 Widget chosen
, candidate
;
888 XPoint ul
, lr
, cand_ul
, cand_lr
;
891 if (((cand_ul
.x
< ul
.x
) || ((cand_ul
.x
== ul
.x
) && (cand_lr
.x
< lr
.x
))) &&
892 (ul
.y
<= cand_lr
.y
) && (lr
.y
>= cand_ul
.y
))
895 chosen
= ValidChoice(chosen
, candidate
, XwVERIFY_ONLY
);
898 if (cand_ul
.x
> chosen
->core
.x
)
899 chosen
= ValidChoice(chosen
, candidate
, XwVERIFY_ONLY
);
901 if (cand_ul
.x
== chosen
->core
.x
)
903 if (abs(cand_lr
.x
- lr
.x
) < abs(chosen
->core
.x
+
904 chosen
->core
.width
+(chosen
->core
.border_width
<<1)-lr
.x
))
905 chosen
= ValidChoice(chosen
, candidate
, XwVERIFY_ONLY
);
907 if (abs(cand_lr
.x
- lr
.x
) == abs(chosen
->core
.x
+
908 chosen
->core
.width
+(chosen
->core
.border_width
<<1)-lr
.x
))
909 if (Overlap(ul
, lr
, candidate
) > Overlap(ul
, lr
, chosen
))
910 chosen
= ValidChoice(chosen
, candidate
, XwVERIFY_ONLY
);
913 if (Overlap(ul
,lr
,candidate
) == Overlap(ul
,lr
,chosen
))
914 if (cand_ul
.y
> chosen
->core
.y
)
915 chosen
= ValidChoice(chosen
, candidate
,
919 if (cand_ul
.y
== chosen
->core
.y
)
921 chosen
->core
.y
+ chosen
->core
.height
+
922 (chosen
->core
.border_width
<< 1))
923 chosen
= ValidChoice(chosen
, candidate
,
934 static Widget
UpCheck (chosen
, ul
, lr
, candidate
, cand_ul
, cand_lr
)
936 Widget chosen
, candidate
;
937 XPoint ul
, lr
, cand_ul
, cand_lr
;
940 if (((cand_ul
.y
< ul
.y
) || ((cand_ul
.y
== ul
.y
) && (cand_lr
.y
< lr
.y
))) &&
941 (ul
.x
<= cand_lr
.x
) && (lr
.x
>= cand_ul
.x
))
944 chosen
= ValidChoice(chosen
, candidate
, XwVERIFY_ONLY
);
947 if (cand_ul
.y
> chosen
->core
.y
)
948 chosen
= ValidChoice(chosen
, candidate
, XwVERIFY_ONLY
);
950 if (cand_ul
.y
== chosen
->core
.y
)
952 if (abs(cand_lr
.y
- lr
.y
) < abs(chosen
->core
.y
+
953 chosen
->core
.height
+(chosen
->core
.border_width
<<1)-lr
.y
))
954 chosen
= ValidChoice(chosen
, candidate
, XwVERIFY_ONLY
);
956 if (abs(cand_lr
.y
- lr
.y
) == abs(chosen
->core
.y
+
957 chosen
->core
.height
+(chosen
->core
.border_width
<<1)-lr
.y
))
958 if (xOverlap(ul
, lr
, candidate
) > xOverlap(ul
, lr
, chosen
))
959 chosen
= ValidChoice(chosen
, candidate
, XwVERIFY_ONLY
);
962 if (xOverlap(ul
, lr
, candidate
) ==
963 xOverlap(ul
, lr
, chosen
))
964 if (cand_ul
.x
> chosen
->core
.x
)
965 chosen
= ValidChoice(chosen
, candidate
,
969 if (cand_ul
.x
== chosen
->core
.x
)
971 chosen
->core
.x
+ chosen
->core
.width
+
972 (chosen
->core
.border_width
<< 1))
973 chosen
= ValidChoice(chosen
,candidate
,
984 static Widget
DownCheck (chosen
, ul
, lr
, candidate
, cand_ul
, cand_lr
)
986 Widget chosen
, candidate
;
987 XPoint ul
, lr
, cand_ul
, cand_lr
;
990 if (((ul
.y
< cand_ul
.y
) || ((ul
.y
== cand_ul
.y
) && (lr
.y
< cand_lr
.y
))) &&
991 (ul
.x
<= cand_lr
.x
) && (lr
.x
>= cand_ul
.x
))
994 chosen
= ValidChoice(chosen
, candidate
, XwVERIFY_ONLY
);
997 if (chosen
->core
.y
> cand_ul
.y
)
998 chosen
= ValidChoice(chosen
, candidate
, XwVERIFY_ONLY
);
1000 if (cand_ul
.y
== chosen
->core
.y
)
1002 if (abs(cand_lr
.y
- lr
.y
) <
1003 abs((chosen
->core
.y
+chosen
->core
.height
+
1004 (chosen
->core
.border_width
<< 1))-lr
.y
))
1005 chosen
= ValidChoice(chosen
, candidate
, XwVERIFY_ONLY
);
1007 if (abs(cand_lr
.y
- lr
.y
) ==
1008 abs((chosen
->core
.y
+chosen
->core
.height
+
1009 (chosen
->core
.border_width
<< 1))-lr
.y
))
1011 if (xOverlap(ul
, lr
, candidate
) > xOverlap(ul
, lr
, chosen
))
1012 chosen
= ValidChoice(chosen
, candidate
, XwVERIFY_ONLY
);
1015 if (xOverlap(ul
, lr
, candidate
) ==
1016 xOverlap(ul
, lr
, chosen
))
1017 if (cand_ul
.x
< chosen
->core
.x
)
1018 chosen
= ValidChoice(chosen
, candidate
,
1022 if (cand_ul
.x
== chosen
->core
.x
)
1024 chosen
->core
.x
+ chosen
->core
.width
+
1025 (chosen
->core
.border_width
<< 1))
1026 chosen
= ValidChoice(chosen
, candidate
,
1038 * To prevent the traversal mechanism from getting into an infinite
1039 * recursion, we need to keep a list of those widgets already checked
1040 * during a given traversal request. If a candidate has already been
1041 * checked once, we don't want to give it a second chance. This is
1042 * normally a problem only when a traversal request causes the search
1043 * to wrap to the opposite edge.
1045 * There are two types of entries maintained on the list: active entries
1046 * and chosen entries. An entry is a chosen entry if its parent has
1047 * determined that the entry can possible accept the traversal request,
1048 * and has thus chosen it to in turn check its children to see if they
1049 * can accept the traversal. An entry is an active entry if it is part
1050 * of the current traversal path, but it does not have any children which
1051 * can currently accept the traversal request; a widget is added to this
1052 * list only if it is not already on the chosen list, AND it is passing
1053 * the traversal request up to its parent.
1055 * The active list prevents any of the widgets in the current traversal
1056 * path from being rechecked by their parent, once they have already
1057 * decided they can't accept the traversal request, until the upper most
1058 * manager decides to wrap at an edge and start looking again; at this
1059 * point, all active entries are cleared from the list, so that they can
1060 * have a chance to regain the traversal if no other widget can.
1062 * If an entry is marked as being on the
1063 * active list, and then a request comes to place it on the chosen list,
1064 * then the move will occur. If, however, a widget is on the chosen list,
1065 * and it asks to move to the active list, this will be denied, since we
1066 * don't want this widget to have the chance of being chosen again. An
1067 * entry on the active list has not yet been chosen, it mearly was part of
1068 * the original active child list.
1071 static Widget
ValidChoice (chosen
, candidate
, action
)
1073 Widget chosen
, candidate
;
1074 XwValidChoiceActions action
;
1079 /* If candidate is already on the list, then don't reprocess it */
1080 if (action
== XwVERIFY_ONLY
)
1082 /* Don't consider it unless it has some traversable primitives */
1083 if (XtIsSubclass(candidate
, XwmanagerWidgetClass
) &&
1084 _XwFindTraversablePrim(candidate
) == False
)
1087 for (i
= 0; i
< _XwCheckListIndex
; i
++)
1089 if ((_XwCheckList
[i
].widget
== candidate
) &&
1090 (_XwCheckList
[i
].type
!= XwNONE
))
1095 if ((action
== XwADD_TO_CHOSEN_LIST
) || (action
== XwADD_TO_ACTIVE_LIST
))
1097 /* See if already on the list; then just update type field */
1098 for (i
= 0; i
< _XwCheckListIndex
; i
++)
1100 if (_XwCheckList
[i
].widget
== candidate
)
1102 if (_XwCheckList
[i
].type
!= XwCHOSEN
)
1104 _XwCheckList
[_XwCheckListIndex
].type
=
1105 (action
== XwADD_TO_CHOSEN_LIST
) ? XwCHOSEN
: XwACTIVE
;
1111 /* See if the list needs to grow */
1112 if (_XwCheckListIndex
>= _XwCheckListSize
)
1114 _XwCheckListSize
+= 20;
1115 _XwCheckList
= (_XwCheckListEntry
*)XtRealloc((char *)_XwCheckList
,
1116 (sizeof(_XwCheckListEntry
) * _XwCheckListSize
));
1119 /* Add to the checklist */
1120 _XwCheckList
[_XwCheckListIndex
].widget
= candidate
;
1121 _XwCheckList
[_XwCheckListIndex
].type
= (action
== XwADD_TO_CHOSEN_LIST
) ?
1122 XwCHOSEN
: XwACTIVE
;
1123 _XwCheckListIndex
++;
1126 /* Clear all entries which were not on the chosen list */
1127 if (action
== XwCLEAR_ACTIVE_LIST
)
1129 for (i
= 0; i
< _XwCheckListIndex
; i
++)
1131 if (_XwCheckList
[i
].type
== XwACTIVE
)
1132 _XwCheckList
[i
].type
= XwNONE
;
1139 void _XwInitCheckList()
1142 /* Initialize the traversal checklist */
1143 if (_XwCheckList
== NULL
)
1145 _XwCheckList
=(_XwCheckListEntry
*)XtMalloc(sizeof(_XwCheckListEntry
)*20);
1146 _XwCheckListSize
= 20;
1149 /* Always reset the checklist to the beginning */
1150 _XwCheckListIndex
= 0;
1155 * This function verifies that all of the ancestors of a manager
1156 * have traversal enabled.
1159 static Boolean
_XwManagerIsTraversable (w
)
1164 while (w
&& XtIsSubclass((Widget
)w
, XwmanagerWidgetClass
))
1166 if ((w
->manager
.traversal_on
== FALSE
) || (w
->core
.visible
== False
))
1169 w
= (XwManagerWidget
)w
->core
.parent
;
1176 static void ClearKbdFocus (topmost_manager
)
1178 Widget topmost_manager
;
1181 while ((topmost_manager
->core
.parent
!= NULL
) &&
1182 XtIsSubclass((Widget
)(topmost_manager
->core
.parent
),
1183 XwmanagerWidgetClass
))
1184 topmost_manager
= topmost_manager
->core
.parent
;
1186 XtSetKeyboardFocus(topmost_manager
, NULL
);