1 /*
2 * Motif
3 *
4 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
5 *
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
16 * details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
22 */
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27
28 #ifdef REV_INFO
29 #ifndef lint
30 static char rcsid[] = "$TOG: Traversal.c /main/20 1999/08/17 11:52:26 vipin $"
31 #endif
32 #endif
33
34 #include <Xm/GadgetP.h>
35 #include <Xm/ManagerP.h>
36 #include <Xm/MenuShellP.h>
37 #include <Xm/PrimitiveP.h>
38 #include <Xm/ScrolledWP.h>
39 #include <Xm/TraitP.h>
40 #include <Xm/TravConT.h>
41 #include <Xm/VendorSEP.h>
42 #include <Xm/VirtKeysP.h>
43 #include <Xm/DisplayP.h>
44 #include "BaseClassI.h"
45 #include "CallbackI.h"
46 #include "RepTypeI.h"
47 #include "TravActI.h"
48 #include "TraversalI.h"
49
50
51 /******** Static Function Declarations ********/
52
53 static Widget FindFirstManaged(
54 Widget wid) ;
55 static Boolean CallTraverseObsured(
56 Widget new_focus,
57 XmTraversalDirection dir) ;
58 static Boolean IsTraversable(
59 Widget wid,
60 Boolean require_in_view) ;
61 static Widget FindFirstFocus(
62 Widget wid) ;
63 static Boolean CallFocusMoved(Widget old,
64 Widget new_wid,
65 XEvent *event,
66 XmTraversalDirection direction);
67 static Widget RedirectTraversal(Widget old_focus,
68 Widget new_focus,
69 unsigned int focus_policy,
70 XmTraversalDirection direction,
71 unsigned int pass);
72
73 /******** End Static Function Declarations ********/
74
75
76 XmFocusData
_XmCreateFocusData(void)77 _XmCreateFocusData( void )
78 {
79 return (XmFocusData) XtCalloc(1, sizeof( XmFocusDataRec)) ;
80 }
81
82 void
_XmDestroyFocusData(XmFocusData focusData)83 _XmDestroyFocusData(
84 XmFocusData focusData )
85 {
86 _XmFreeTravGraph( &(focusData->trav_graph)) ;
87 XtFree((char *) focusData->trav_graph.excl_tab_list) ;
88 XtFree((char *) focusData) ;
89 }
90
91 void
_XmSetActiveTabGroup(XmFocusData focusData,Widget tabGroup)92 _XmSetActiveTabGroup(
93 XmFocusData focusData,
94 Widget tabGroup )
95 {
96 focusData->active_tab_group = tabGroup;
97 }
98
99 Widget
_XmGetActiveItem(Widget w)100 _XmGetActiveItem(
101 Widget w )
102 {
103 return XmGetFocusWidget( w) ;
104 }
105
106 /*ARGSUSED*/
107 void
_XmNavigInitialize(Widget request,Widget new_wid,ArgList args,Cardinal * num_args)108 _XmNavigInitialize(
109 Widget request, /* unused */
110 Widget new_wid,
111 ArgList args, /* unused */
112 Cardinal *num_args ) /* unused */
113 {
114 XmFocusData focusData ;
115
116 if( (focusData = _XmGetFocusData( new_wid)) != NULL )
117 {
118 XmNavigationType navType = _XmGetNavigationType( new_wid) ;
119
120 if( navType == XmEXCLUSIVE_TAB_GROUP )
121 {
122 ++(focusData->trav_graph.exclusive) ;
123 _XmTabListAdd( &(focusData->trav_graph), new_wid) ;
124 }
125 else
126 {
127 if( navType == XmSTICKY_TAB_GROUP )
128 {
129 _XmTabListAdd( &(focusData->trav_graph), new_wid) ;
130 }
131 }
132 if( focusData->trav_graph.num_entries
133 && _XmGetNavigability( new_wid) )
134 {
135 /* If the graph exists, add the new navigable widget.
136 */
137 _XmTravGraphAdd( &(focusData->trav_graph), new_wid) ;
138 }
139 }
140 /* If the traversal graph doesn't exist, do nothing, since the
141 * new widget will be picked-up when the graph is needed and created.
142 */
143 return ;
144 }
145
146 /*ARGSUSED*/
147 Boolean
_XmNavigSetValues(Widget current,Widget request,Widget new_wid,ArgList args,Cardinal * num_args)148 _XmNavigSetValues(
149 Widget current,
150 Widget request, /* unused */
151 Widget new_wid,
152 ArgList args, /* unused */
153 Cardinal *num_args ) /* unused */
154 {
155 /* This routine is called from the SetValues method of Manager,
156 * Primitive, and Gadget to keep the traversal data structures
157 * up-to-date in regards to changes in the traversability of widgets.
158 *
159 * There are three purposes for this routine:
160 *
161 * 1: Update the traversal graph in response to changes in
162 * a widget's resources such that the widget is newly
163 * eligible to receive the traversal focus.
164 *
165 * 2: Update the focus data according to changes in
166 * the Motif 1.0 "exclusive tab group" behavior.
167 *
168 * 3: If the new widget of the SetValues call is the focus
169 * widget and it becomes ineligible to have the focus,
170 * then find an alternative to receive the focus (or
171 * reset the focus for the hierarchy to the bootstrap
172 * condition).
173 */
174
175 XmFocusData focusData ;
176
177 if( (focusData = _XmGetFocusData( new_wid)) != NULL )
178 {
179 XmTravGraph graph = &(focusData->trav_graph) ;
180 XmNavigationType newNavType = _XmGetNavigationType( new_wid) ;
181 XmNavigationType curNavType = _XmGetNavigationType( current) ;
182 Boolean ChangeInExclusive = FALSE ;
183
184 if( curNavType != newNavType )
185 {
186 if( (curNavType == XmEXCLUSIVE_TAB_GROUP)
187 || (newNavType == XmEXCLUSIVE_TAB_GROUP) )
188 {
189 /* This widget was "exclusive", now it is not (or vice-versa).
190 * Update the value of the focus data "exclusive" field.
191 */
192 ChangeInExclusive = TRUE ;
193
194 if( newNavType == XmEXCLUSIVE_TAB_GROUP )
195 {
196 ++(graph->exclusive) ;
197 }
198 else
199 {
200 --(graph->exclusive) ;
201 }
202 }
203 if( (newNavType == XmEXCLUSIVE_TAB_GROUP)
204 || (newNavType == XmSTICKY_TAB_GROUP) )
205 {
206 if( (curNavType != XmEXCLUSIVE_TAB_GROUP)
207 && (curNavType != XmSTICKY_TAB_GROUP) )
208 {
209 _XmTabListAdd( graph, new_wid) ;
210 }
211 }
212 else
213 {
214 if( (curNavType == XmEXCLUSIVE_TAB_GROUP)
215 || (curNavType == XmSTICKY_TAB_GROUP) )
216 {
217 _XmTabListDelete( graph, new_wid) ;
218 }
219 }
220 }
221 if( XtIsRealized( new_wid)
222 && (focusData->focus_policy == XmEXPLICIT) )
223 {
224 if( graph->num_entries )
225 {
226 if( ChangeInExclusive )
227 {
228 /* Since widget has changed to/from exlusive tab group
229 * behavior, need to re-make the traversal graph (as needed).
230 */
231 _XmFreeTravGraph( graph) ;
232 }
233 else
234 {
235 XmNavigability cur_nav = _XmGetNavigability( current) ;
236 XmNavigability new_nav = _XmGetNavigability( new_wid) ;
237
238 if( !cur_nav && new_nav )
239 {
240 /* Newly navigable widget; add it to the
241 * traversal graph.
242 */
243 _XmTravGraphAdd( graph, new_wid) ;
244 }
245 else
246 {
247 if( cur_nav != new_nav )
248 {
249 /* Navigability changed; need to re-create the
250 * graph the next time it is needed.
251 */
252 _XmFreeTravGraph( graph) ;
253 }
254 }
255 }
256 }
257 if( !(focusData->focus_item) )
258 {
259 Widget shell ;
260
261 /* CR 5417: Remove (focusData->focalPoint != XmMySelf) test. */
262 if( XmIsTraversable( new_wid)
263 && (shell = _XmFindTopMostShell( new_wid))
264 && XmeFocusIsInShell( shell))
265 {
266 /* Hierarchy currently has no focus, and this widget is
267 * now traversable, so bootstrap the focus for the hierarchy.
268 */
269 _XmMgrTraversal( shell, XmTRAVERSE_CURRENT) ;
270 }
271 }
272 else
273 {
274 if( (focusData->focus_item == new_wid)
275 && !IsTraversable( new_wid, TRUE) )
276 {
277 /* The new_wid now has the focus and is no longer
278 * traversable, so traverse away from it to the
279 * next traversable item.
280 */
281 Widget new_focus = _XmTraverseAway( graph, new_wid,
282 (focusData->active_tab_group != new_wid)) ;
283 if( !new_focus )
284 {
285 /* Could not find another widget eligible to take
286 * the focus, so use any widget to re-initialize/clear
287 * the focus in the widget hierarchy.
288 */
289 new_focus = new_wid ;
290 }
291 _XmMgrTraversal( new_focus, XmTRAVERSE_CURRENT) ;
292
293 if( !XtIsSensitive( new_wid) )
294 {
295 /* Since widget has become insensitive, it did not
296 * receive the focus-out event. Call the focus
297 * change method directly.
298 */
299 _XmWidgetFocusChange( new_wid, XmFOCUS_OUT) ;
300 }
301 return TRUE ;
302 }
303 }
304 }
305 }
306 return FALSE ;
307 }
308
309 void
XmeNavigChangeManaged(Widget wid)310 XmeNavigChangeManaged(
311 Widget wid )
312 {
313 /* This routine must be called from the ChangeManaged method of
314 * all composite widgets that may have traversable children.
315 * This routine checks to see if the focus widget is traversable;
316 * if it is not, then an alternative traversable widget is found
317 * or the focus for the hierarchy is reset to the bootstrap condition.
318 *
319 * This routine also detects the condition for which there is no
320 * focus widget in the hierarchy and a newly managed widget is
321 * now eligible to have the focus; the focus is then initialized.
322 */
323 XmFocusData focus_data ;
324 _XmWidgetToAppContext(wid);
325
326 _XmAppLock(app);
327 if( XtIsRealized( wid)
328 && (focus_data = _XmGetFocusData( wid))
329 && (focus_data->focus_policy == XmEXPLICIT) )
330 {
331 if( focus_data->focus_item == NULL )
332 {
333 Widget firstManaged ;
334
335 if( XtIsShell( wid) )
336 {
337 if( focus_data->first_focus == NULL )
338 {
339 focus_data->first_focus = FindFirstFocus( wid) ;
340 }
341 if( (firstManaged = FindFirstManaged( wid)) != NULL )
342 {
343 /* Set bootstrap trigger for hierarchy that
344 * has no current focus.
345 */
346 XtSetKeyboardFocus( wid, firstManaged) ;
347 }
348 }
349 }
350 else
351 {
352 /* If the focus widget is being destroyed, do nothing for now.
353 * We need to wait until _XmNavigDestroy is called to initiate
354 * the focus change; if we don't defer selection of the focus
355 * widget, the Intrinsics-generated focus-out event for the
356 * focus widget will go to the newly-selected focus widget
357 * (instead of the widget being destroyed, as intended).
358 */
359 if( !(focus_data->focus_item->core.being_destroyed)
360 && !IsTraversable( focus_data->focus_item, TRUE) )
361 {
362 Widget new_focus = _XmTraverseAway( &(focus_data->trav_graph),
363 focus_data->focus_item,
364 (focus_data->active_tab_group
365 != focus_data->focus_item)) ;
366 if( !new_focus )
367 {
368 new_focus = focus_data->focus_item ;
369 }
370 if(new_focus)
371 _XmMgrTraversal( new_focus, XmTRAVERSE_CURRENT) ;
372 }
373 }
374 }
375 _XmAppUnlock(app);
376 return ;
377 }
378
379 static Widget
FindFirstManaged(Widget wid)380 FindFirstManaged(
381 Widget wid)
382 {
383 if( XtIsShell( wid) )
384 {
385 unsigned i = 0 ;
386
387 while( i < ((CompositeWidget) wid)->composite.num_children )
388 {
389 if( XtIsManaged( ((CompositeWidget) wid)
390 ->composite.children[i]) )
391 {
392 return ((CompositeWidget) wid)->composite.children[i] ;
393 }
394 ++i ;
395 }
396 }
397 return NULL ;
398 }
399
400 void
_XmNavigResize(Widget wid)401 _XmNavigResize(
402 Widget wid)
403 {
404 /* This routine must be called by all composites with (potentially)
405 * traversable children. This is generally handled for all managers
406 * in the resize wrapper routines.
407 *
408 * This routine makes sure that the focus widget is always in view,
409 * either by invoking the XmNtraverseObscurredCallback mechansism
410 * of Scrolled Window or by finding an alternative focus widget.
411 */
412 XmFocusData focus_data ;
413
414 if( XtIsRealized( wid) && !XtIsShell( wid)
415 && (focus_data = _XmGetFocusData( wid)) )
416 {
417 /* If the focus item is being destroyed, do nothing, since this
418 * will be handled more appropriately by _XmNavigDestroy().
419 */
420 if( (focus_data->focus_policy == XmEXPLICIT)
421 && ( !(focus_data->focus_item)
422 || !((focus_data->focus_item)->core.being_destroyed)) )
423 {
424 if( !(focus_data->focus_item) )
425 {
426 /* Hierarchy has no focus widget; re-initialize/clear the
427 * focus, but only if the parent is a managed shell (to
428 * avoid premature initialization during XtRealizeWidget).
429 */
430 Widget parent = XtParent( wid) ;
431 Widget firstManaged ;
432
433 if( parent && XtIsShell( parent)
434 && (firstManaged = FindFirstManaged( parent)) )
435 {
436 /* Set bootstrap trigger for hierarchy that
437 * has no current focus.
438 */
439 XtSetKeyboardFocus( wid, firstManaged) ;
440 }
441 }
442 else
443 {
444 if( !IsTraversable( focus_data->focus_item, TRUE) )
445 {
446 /* Widget is not traversable, either because it is not
447 * viewable or some other reason. Test again, this
448 * time allowing for obscured traversal.
449 *
450 * If it is not traversable regardless of the
451 * XmNtraverseObscuredCallback, or traversal to the
452 * obscured widget fails for some other reason, traverse
453 * away from the non-traversable widget.
454 */
455 if( !IsTraversable( focus_data->focus_item, FALSE)
456 || !_XmMgrTraversal( focus_data->focus_item,
457 XmTRAVERSE_CURRENT) )
458 {
459 Widget new_focus = _XmTraverseAway(
460 &(focus_data->trav_graph), focus_data->focus_item,
461 (focus_data->active_tab_group
462 != focus_data->focus_item)) ;
463 if( !new_focus )
464 {
465 new_focus = focus_data->focus_item ;
466 }
467 if(new_focus)
468 _XmMgrTraversal( new_focus, XmTRAVERSE_CURRENT) ;
469 }
470 }
471 }
472 }
473 }
474 }
475
476 void
_XmValidateFocus(Widget wid)477 _XmValidateFocus(
478 Widget wid )
479 {
480 XmFocusData focus_data = _XmGetFocusData( wid) ;
481
482 if( focus_data
483 && (focus_data->focus_policy == XmEXPLICIT)
484 && (focus_data->focus_item != NULL)
485 && !IsTraversable( focus_data->focus_item, TRUE) )
486 {
487 Widget new_focus = _XmTraverseAway( &(focus_data->trav_graph),
488 focus_data->focus_item,
489 (focus_data->active_tab_group != focus_data->focus_item)) ;
490 if( !new_focus )
491 {
492 new_focus = wid ;
493 }
494 _XmMgrTraversal( new_focus, XmTRAVERSE_CURRENT) ;
495 }
496 }
497
498 void
_XmNavigDestroy(Widget wid)499 _XmNavigDestroy(
500 Widget wid )
501 {
502 /* This routine is used to keep the traversal data up-to-date with
503 * regards to widgets which are being destroyed. It must be called
504 * by all composites that might have traversable children. The
505 * DeleteChild method for Manager calls this routine, so its
506 * subclasses can explicitly chain to its superclasses DeleteChild
507 * method or call this routine directly.
508 *
509 * In addition to finding a new focus widget if it is being
510 * destroyed, this routine must make sure that there are no
511 * stale pointers to the widget being destroyed in any of its
512 * data structures.
513 */
514 XmFocusData focusData = _XmGetFocusData( wid) ;
515
516 if( focusData )
517 {
518 XmTravGraph trav_list = &(focusData->trav_graph) ;
519 XmNavigationType navType = _XmGetNavigationType( wid) ;
520
521 if( wid == focusData->first_focus )
522 {
523 focusData->first_focus = NULL ;
524 }
525 if( navType == XmEXCLUSIVE_TAB_GROUP )
526 {
527 --(trav_list->exclusive) ;
528 _XmTabListDelete( trav_list, wid) ;
529 }
530 else
531 {
532 if( navType == XmSTICKY_TAB_GROUP )
533 {
534 _XmTabListDelete( trav_list, wid) ;
535 }
536 }
537 if( focusData->focus_item == wid )
538 {
539 /* The focus widget for this hierarhcy is being destroyed.
540 * Traverse away if in explicit mode, or just clear the
541 * focus item field.
542 */
543 Widget new_focus ;
544
545 if( (focusData->focus_policy != XmEXPLICIT)
546 || ( !(new_focus = _XmTraverseAway( trav_list,
547 focusData->focus_item,
548 (focusData->active_tab_group != wid)))
549 && !(new_focus = _XmFindTopMostShell( wid)))
550 || !_XmMgrTraversal( new_focus, XmTRAVERSE_CURRENT) )
551 {
552 focusData->focus_item = NULL ;
553 }
554 }
555 if( focusData->trav_graph.num_entries )
556 {
557 _XmTravGraphRemove( trav_list, wid) ;
558 }
559 if( focusData->active_tab_group == wid )
560 {
561 focusData->active_tab_group = NULL ;
562 }
563 if( focusData->old_focus_item == wid )
564 {
565 focusData->old_focus_item = NULL ;
566 }
567 if( focusData->pointer_item == wid )
568 {
569 focusData->pointer_item = NULL ;
570 }
571 }
572 return ;
573 }
574
575 static Boolean
CallFocusMoved(Widget old,Widget new_wid,XEvent * event,XmTraversalDirection direction)576 CallFocusMoved(Widget old,
577 Widget new_wid,
578 XEvent *event,
579 XmTraversalDirection direction)
580 {
581 Widget w ;
582 Widget topShell ;
583 XtCallbackList callbacks ;
584 Boolean contin = TRUE ;
585
586 if (old)
587 w = old;
588 else /* if (new_wid) -- if there's no w assignment we're in big trouble! */
589 w = new_wid;
590
591 topShell = (Widget) _XmFindTopMostShell(w);
592
593 /*
594 * make sure it's a shell that has a vendorExt object
595 */
596 if (XmIsVendorShell(topShell))
597 {
598 XmWidgetExtData extData;
599 XmVendorShellExtObject vendorExt;
600
601 extData = _XmGetWidgetExtData(topShell, XmSHELL_EXTENSION);
602 if(extData==NULL) return (contin);
603
604 if ((vendorExt = (XmVendorShellExtObject) extData->widget) != NULL)
605 {
606 if ((callbacks = vendorExt->vendor.focus_moved_callback) != NULL)
607 {
608 XmFocusMovedCallbackStruct callData;
609
610 callData.reason = XmCR_FOCUS_MOVED;
611 callData.event = event;
612 callData.cont = True;
613 callData.old_focus = old;
614 callData.new_focus = new_wid;
615 callData.focus_policy = vendorExt->vendor.focus_policy;
616 callData.direction = direction;
617
618 _XmCallCallbackList((Widget) vendorExt, callbacks,
619 (XtPointer) &callData);
620 contin = callData.cont ;
621 }
622 }
623 }
624 return( contin) ;
625 }
626
627 Boolean
_XmCallFocusMoved(Widget old,Widget new_wid,XEvent * event)628 _XmCallFocusMoved(
629 Widget old,
630 Widget new_wid,
631 XEvent *event )
632 {
633 return CallFocusMoved(old, new_wid, event, XmTRAVERSE_CURRENT);
634 }
635
636 Boolean
_XmMgrTraversal(Widget wid,XmTraversalDirection direction)637 _XmMgrTraversal(
638 Widget wid,
639 XmTraversalDirection direction)
640 {
641 /* This routine is the workhorse for all traversal activities. */
642 Widget top_shell ;
643 Widget old_focus ;
644 Widget new_focus ;
645 Widget new_active_tab ;
646 XmFocusData focus_data;
647 XmTravGraph trav_list ;
648 Boolean rtnVal = FALSE ;
649 XmTraversalDirection local_dir;
650 XmDisplay dd = (XmDisplay)XmGetXmDisplay(XtDisplay(wid));
651
652 #define traversal_in_progress \
653 ((XmDisplayInfo *)(dd->display.displayInfo))->traversal_in_progress
654
655 if( traversal_in_progress
656 || !(top_shell = _XmFindTopMostShell( wid))
657 || top_shell->core.being_destroyed
658 || !(focus_data = _XmGetFocusData( wid))
659 || (focus_data->focus_policy != XmEXPLICIT) )
660 {
661 return FALSE ;
662 }
663 traversal_in_progress = TRUE ;
664
665 /* Recursive traversal calls can sometimes be generated during
666 * the handling of focus events and associated callbacks.
667 * In this version of Motif, recursive calls always fail.
668 *
669 * Future enhancements could include the addition of a queue
670 * for recursive calls; these calls would then be serviced on
671 * a FIFO basis following the completion of the initial traversal
672 * processing. Sequential FIFO processing is essential for
673 * providing a consistent and predicable environment for
674 * focus change callbacks and event processing.
675 */
676 trav_list = &(focus_data->trav_graph) ;
677 old_focus = focus_data->focus_item ;
678
679 if( (old_focus == NULL)
680 && (wid == top_shell)
681 && focus_data->first_focus
682 && IsTraversable( focus_data->first_focus, TRUE) )
683 {
684 new_focus = focus_data->first_focus ;
685
686 if (direction == XmTRAVERSE_GLOBALLY_FORWARD)
687 local_dir = XmTRAVERSE_NEXT_TAB_GROUP;
688 else if (direction == XmTRAVERSE_GLOBALLY_BACKWARD)
689 local_dir = XmTRAVERSE_PREV_TAB_GROUP;
690 else
691 local_dir = direction;
692 }
693 else
694 {
695 new_focus = _XmTraverse(trav_list, direction, &local_dir, wid) ;
696 }
697
698 new_focus = RedirectTraversal(old_focus, new_focus,
699 focus_data->focus_policy, local_dir, 0);
700
701 if( new_focus
702 && (new_focus == old_focus)
703 && focus_data->old_focus_item )
704 {
705 /* When traversal does not cause the focus to change
706 * to a different widget, focus-change events should
707 * not be generated. The old_focus_item will be NULL
708 * when the focus is moving into this shell hierarchy
709 * from a different shell; in this case, focus-in
710 * events should be generated below.
711 */
712 rtnVal = TRUE ;
713 }
714 else if( new_focus
715 && (new_active_tab = XmGetTabGroup( new_focus))
716 && CallFocusMoved(old_focus, new_focus, NULL, local_dir)
717 && CallTraverseObsured(new_focus, local_dir))
718 {
719 /* Set the keyboard focus in two steps; first to None, then
720 * to the new focus widget. This will cause appropriate
721 * focus-in and focus-out events to be generated, even if
722 * the focus change is between two gadgets.
723 *
724 * Note that XtSetKeyboardFocus() generates focus change
725 * events "in-line", so focus data and manager active_child
726 * fields are not updated until after the focus-out events have
727 * been generated and dispatched to the current focus item.
728 *
729 * The FocusResetFlag is used to tell event actions procs to
730 * ignore any focus-in event that might be generated by the
731 * window manager (which won't like the fact that there the
732 * focus is now going to point to nobody).
733 */
734 _XmSetFocusFlag( top_shell, XmFOCUS_RESET, TRUE) ;
735 XtSetKeyboardFocus( top_shell, None) ;
736 _XmSetFocusFlag( top_shell, XmFOCUS_RESET, FALSE) ;
737
738 _XmClearFocusPath( old_focus) ;
739
740 focus_data->active_tab_group = new_active_tab ;
741
742 if( (new_active_tab != new_focus)
743 && XmIsManager( new_active_tab) )
744 {
745 XmManagerWidget manager = (XmManagerWidget) new_active_tab;
746 manager->manager.active_child = new_focus;
747 }
748 if( (new_active_tab != XtParent( new_focus)) /* Set above. */
749 && XmIsManager( XtParent( new_focus)) )
750 {
751 XmManagerWidget manager = (XmManagerWidget) XtParent(new_focus);
752 manager->manager.active_child = new_focus ;
753 }
754 focus_data->focus_item = new_focus ;
755 focus_data->old_focus_item = old_focus ? old_focus : new_focus ;
756
757 /* Setting the focus data and manager active_child fields enables
758 * focus-in events to be propagated to the new focus widget.
759 */
760 XtSetKeyboardFocus( top_shell, new_focus) ;
761
762 rtnVal = TRUE ;
763 }
764 else
765 {
766 /* Have failed to traverse to a new widget focus widget.
767 * If the current focus widget is no longer traversable,
768 * then reset focus data to its bootstrap state.
769 */
770 if( !old_focus
771 || !IsTraversable( old_focus, TRUE) )
772 {
773 Widget firstManaged = FindFirstManaged( top_shell) ;
774
775 _XmSetFocusFlag( top_shell, XmFOCUS_RESET, TRUE) ;
776 XtSetKeyboardFocus( top_shell, firstManaged) ;
777 _XmSetFocusFlag( top_shell, XmFOCUS_RESET, FALSE) ;
778
779 _XmClearFocusPath( old_focus) ;
780 _XmFreeTravGraph( trav_list) ;
781 }
782 }
783
784 if( trav_list->num_entries
785 && (focus_data->focalPoint == XmUnrelated)
786 && ( XmIsVendorShell( top_shell)
787 || !XmeFocusIsInShell( top_shell)) )
788 {
789 /* Free the graversal graph whenever the focus is out of this
790 * shell hierarchy, so memory use is limited to one traversal
791 * graph per display. Since VendorShell has a handler which
792 * tracks the input focus, all we need to do is look at the
793 * focusData field. For MenuShell and others, we need to go
794 * through the X server to find out where the focus is.
795 *
796 * Note the logic of the above conditional; VendorShell is the
797 * only shell class that maintains the focalPoint field of the
798 * focus data. So, if its a VendorShell and focalPoint says
799 * "unrelated", we have the answer; any other shell and we need
800 * to call the generic focus test routine.
801 */
802 _XmFreeTravGraph( trav_list) ;
803 }
804 traversal_in_progress = FALSE ;
805 return rtnVal ;
806 }
807
808 static Boolean
CallTraverseObsured(Widget new_focus,XmTraversalDirection dir)809 CallTraverseObsured(
810 Widget new_focus,
811 XmTraversalDirection dir)
812 {
813 Widget prev;
814 Widget ancestor = new_focus;
815 XRectangle focus_rect; /* Area we're trying to make visible. */
816 XRectangle clip_rect; /* Area a given ancestor obscures. */
817 XRectangle view_rect; /* Temporary intersection of the two. */
818 XmTraverseObscuredCallbackStruct call_data;
819
820 call_data.reason = XmCR_OBSCURED_TRAVERSAL;
821 call_data.event = NULL;
822 call_data.traversal_destination = new_focus;
823 call_data.direction = dir;
824
825 _XmSetRect(&focus_rect, new_focus);
826
827 /* Look for ancestors that clip this window. */
828 for (prev = ancestor;
829 ((ancestor = XtParent(ancestor)) != NULL) && !XtIsShell(ancestor);
830 prev = ancestor)
831 {
832 /* CR 9705: Special case overlapping work windows. */
833 if (!_XmIsScrollableClipWidget(ancestor, False, &clip_rect))
834 _XmSetRect(&clip_rect, ancestor);
835
836 if (!_XmIntersectionOf(&focus_rect, &clip_rect, &view_rect) ||
837 (view_rect.width != focus_rect.width) ||
838 (view_rect.height != focus_rect.height))
839 {
840 /* This ancestor clips somebody. */
841 Widget sw = _XmIsScrollableClipWidget(prev, True, &focus_rect);
842 if (sw != NULL)
843 {
844 XtCallbackList callbacks = ((XmScrolledWindowWidget) sw)
845 ->swindow.traverseObscuredCallback;
846 XtCallCallbackList(sw, callbacks, (XtPointer) &call_data);
847
848 ancestor = sw;
849 }
850 else
851 {
852 _XmIntersectRect(&focus_rect, ancestor, &focus_rect);
853 }
854 }
855 }
856
857 return IsTraversable( new_focus, TRUE);
858 }
859
860 void
_XmClearFocusPath(Widget wid)861 _XmClearFocusPath(
862 Widget wid )
863 {
864 /* This routine should be called whenever the focus of a shell
865 * hierarchy needs to be reset to the bootstrap condition.
866 *
867 * This routine clears the active_child field of all manager
868 * widget ancestors of the widget argument, and clears other
869 * focus widget fields of the focus data record. The clearing
870 * of the old_focus_item field indicates to the traversal code
871 * that the focus is not in this shell hierarchy.
872 */
873 XmFocusData focus_data ;
874
875 while( wid && !XtIsShell( wid) )
876 {
877 if( XmIsManager( wid) )
878 {
879 ((XmManagerWidget) wid)->manager.active_child = NULL ;
880 }
881 wid = XtParent( wid) ;
882 }
883 if( (focus_data = _XmGetFocusData( wid)) != NULL )
884 {
885 focus_data->focus_item = NULL ;
886 focus_data->old_focus_item = NULL ;
887 focus_data->active_tab_group = NULL ;
888 }
889 }
890
891 Boolean
_XmFocusIsHere(Widget w)892 _XmFocusIsHere(
893 Widget w )
894 {
895 XmFocusData focus_data;
896 Widget item;
897
898 if ((focus_data = _XmGetFocusData( w)) &&
899 (item = focus_data->focus_item))
900 {
901 for (; !XtIsShell(item); item = XtParent(item))
902 if (item == w)
903 return True;
904 }
905 return(False);
906 }
907
908 unsigned char
_XmGetFocusPolicy(Widget w)909 _XmGetFocusPolicy(
910 Widget w )
911 {
912 Widget topmost_shell ;
913
914 /* Find the topmost shell widget
915 */
916 topmost_shell = _XmFindTopMostShell( w) ;
917
918 if( XtIsVendorShell( topmost_shell) )
919 {
920 XmWidgetExtData xwed = _XmGetWidgetExtData(topmost_shell, XmSHELL_EXTENSION);
921
922 if(xwed == NULL) return(XmPOINTER);
923
924 return (((XmVendorShellExtObject)
925 (xwed)->widget)
926 ->vendor.focus_policy) ;
927 }
928 else
929 {
930 if( XmIsMenuShell( topmost_shell) )
931 {
932 return( ((XmMenuShellWidget) topmost_shell)->menu_shell.focus_policy);
933 }
934 }
935 return( XmPOINTER) ;
936 }
937
938 Widget
_XmFindTopMostShell(Widget w)939 _XmFindTopMostShell(
940 Widget w )
941 {
942 while( w && !XtIsShell( w) )
943 {
944 w = XtParent( w) ;
945 }
946 return( w) ;
947 }
948
949 /*ARGSUSED*/
950 void
_XmFocusModelChanged(Widget wid,XtPointer client_data,XtPointer call_data)951 _XmFocusModelChanged(
952 Widget wid,
953 XtPointer client_data, /* unused */
954 XtPointer call_data )
955 {
956 /* Invoked by the VendorShell widget, when the focus_policy changes.
957 * Registered as a callback by both the Manager and Primitive classes,
958 * when the parent is a VendorShell widget.
959 */
960 unsigned char new_focus_policy = (unsigned char)(unsigned long) call_data ;
961 Widget shell = _XmFindTopMostShell( wid) ;
962 XmFocusData focus_data = _XmGetFocusData( shell) ;
963
964 if( focus_data )
965 {
966 if( new_focus_policy == XmEXPLICIT )
967 {
968 Widget new_item = focus_data->pointer_item ;
969
970 if( new_item != NULL )
971 {
972 if( XmIsManager( new_item)
973 && (((XmManagerWidget) new_item)
974 ->manager.highlighted_widget != NULL) )
975 {
976 new_item = ((XmManagerWidget) new_item)
977 ->manager.highlighted_widget ;
978 }
979 _XmWidgetFocusChange( new_item, XmLEAVE) ;
980 }
981 if( (new_item == NULL)
982 || !_XmMgrTraversal( new_item, XmTRAVERSE_CURRENT) )
983 {
984 _XmMgrTraversal( shell, XmTRAVERSE_CURRENT) ;
985 }
986 }
987 else /* new_focus_policy == XmPOINTER */
988 {
989 if( focus_data->focus_item )
990 {
991 Widget firstManaged = FindFirstManaged( shell) ;
992
993 _XmWidgetFocusChange( focus_data->focus_item, XmFOCUS_OUT) ;
994
995 _XmClearFocusPath( focus_data->focus_item) ;
996 _XmSetFocusFlag( shell, XmFOCUS_RESET, TRUE) ;
997 XtSetKeyboardFocus( shell, firstManaged) ;
998 _XmSetFocusFlag( shell, XmFOCUS_RESET, FALSE) ;
999 }
1000 _XmFreeTravGraph( &(focus_data->trav_graph)) ;
1001 }
1002 }
1003 }
1004
1005
1006 XmFocusData
_XmGetFocusData(Widget wid)1007 _XmGetFocusData (Widget wid)
1008 {
1009 /* This function returns a pointer to the focus data associated with the
1010 * topmost shell. This allows us to treat the location opaquely.
1011 */
1012 while (wid && !XtIsShell (wid))
1013 {
1014 wid = XtParent (wid);
1015 }
1016 if (wid && !(wid->core.being_destroyed))
1017 {
1018 if (XmIsVendorShell (wid))
1019 {
1020 XmWidgetExtData xwed = _XmGetWidgetExtData (wid, XmSHELL_EXTENSION);
1021 XmVendorShellExtObject vse;
1022
1023 if (xwed == NULL)
1024 return NULL;
1025 vse = (XmVendorShellExtObject) xwed->widget;
1026 if (vse && vse->vendor.focus_data)
1027 {
1028 vse->vendor.focus_data->focus_policy = vse->vendor.focus_policy;
1029 return vse->vendor.focus_data;
1030 }
1031 }
1032 else
1033 {
1034 if (XmIsMenuShell (wid)
1035 && ((XmMenuShellWidget) wid)->menu_shell.focus_data)
1036 {
1037 ((XmMenuShellWidget) wid)->menu_shell.focus_data->
1038 focus_policy =
1039 ((XmMenuShellWidget) wid)->menu_shell.focus_policy;
1040 return ((XmMenuShellWidget) wid)->menu_shell.focus_data;
1041 }
1042 }
1043 }
1044 return NULL;
1045 }
1046
1047
1048 Boolean
_XmComputeVisibilityRect(Widget w,XRectangle * rectPtr,Boolean include_initial_border,Boolean allow_scrolling)1049 _XmComputeVisibilityRect(Widget w,
1050 XRectangle *rectPtr,
1051 Boolean include_initial_border,
1052 Boolean allow_scrolling)
1053 {
1054 /* This function will generate a rectangle describing the portion of
1055 * the specified widget which is not clipped by any of its ancestors.
1056 * It also verifies that the ancestors are both managed and
1057 * mapped_when_managed.
1058 *
1059 * It will return TRUE if the rectangle returned in rectPtr has a
1060 * non-zero area; it will return FALSE if the widget is not visible.
1061 *
1062 * If allow_scrolling is set and w is the work area child of an
1063 * automatic scrolled window with a non-null XmNtraverseObscuredCallback,
1064 * then the clip window is used as the initial rectangle for w.
1065 */
1066 Widget sw;
1067
1068 if (!_XmIsViewable(w))
1069 {
1070 _XmClearRect(rectPtr);
1071 return False;
1072 }
1073
1074 if (allow_scrolling && w && XtParent(w) &&
1075 ((sw = _XmIsScrollableClipWidget(w, True, rectPtr)) != NULL))
1076 {
1077 w = sw;
1078
1079 if (!_XmIsViewable(w))
1080 {
1081 _XmClearRect(rectPtr);
1082 return False;
1083 }
1084 }
1085 else
1086 {
1087 _XmSetRect(rectPtr, w);
1088 }
1089
1090 if (include_initial_border)
1091 {
1092 int border = XtBorderWidth(w);
1093
1094 rectPtr->x -= border;
1095 rectPtr->y -= border;
1096 rectPtr->width += 2 * border;
1097 rectPtr->height += 2 * border;
1098 }
1099
1100 /* Process all widgets, excluding the shell widget. */
1101 while (((w = XtParent(w)) != NULL) && !XtIsShell(w))
1102 {
1103 if (!_XmIsViewable(w) || !_XmIntersectRect(rectPtr, w, rectPtr))
1104 {
1105 _XmClearRect(rectPtr);
1106 return False;
1107 }
1108 }
1109
1110 return True;
1111 }
1112
1113 Boolean
_XmGetPointVisibility(Widget w,int root_x,int root_y)1114 _XmGetPointVisibility(Widget w,
1115 int root_x,
1116 int root_y)
1117 {
1118 /* Compute whether a point is really visible inside a widget. */
1119 XRectangle rect;
1120
1121 if (_XmComputeVisibilityRect(w, &rect, TRUE, FALSE))
1122 {
1123 return ((root_x >= rect.x) &&
1124 (root_x < rect.x + (int)rect.width) &&
1125 (root_y >= rect.y) &&
1126 (root_y < rect.y + (int)rect.height));
1127 }
1128
1129 return False;
1130 }
1131
1132 void
_XmSetRect(register XRectangle * rect,Widget w)1133 _XmSetRect(
1134 register XRectangle *rect,
1135 Widget w )
1136 {
1137 /* Initialize the rectangle structure to the specified values.
1138 * The widget must be realized.
1139 */
1140 Position x, y;
1141
1142 XtTranslateCoords(XtParent(w), w->core.x, w->core.y, &x, &y);
1143 rect->x = x + w->core.border_width;
1144 rect->y = y + w->core.border_width;
1145 rect->width = w->core.width;
1146 rect->height = w->core.height;
1147 }
1148
1149 int
_XmIntersectRect(register XRectangle * srcRectA,register Widget widget,register XRectangle * dstRect)1150 _XmIntersectRect(
1151 register XRectangle *srcRectA,
1152 register Widget widget,
1153 register XRectangle *dstRect )
1154 {
1155 /* Intersects the specified rectangle with the rectangle describing the
1156 * passed-in widget. Returns True if they intersect, or False if they
1157 * do not.
1158 */
1159 XRectangle srcRectB;
1160
1161 _XmSetRect(&srcRectB, widget);
1162
1163 return( (int) _XmIntersectionOf( srcRectA, &srcRectB, dstRect)) ;
1164 }
1165
1166 int
_XmEmptyRect(register XRectangle * r)1167 _XmEmptyRect(
1168 register XRectangle *r )
1169 {
1170 if (r->width <= 0 || r->height <= 0)
1171 return (TRUE);
1172
1173 return (FALSE);
1174 }
1175
1176 void
_XmClearRect(register XRectangle * r)1177 _XmClearRect(
1178 register XRectangle *r )
1179 {
1180 r->x = 0;
1181 r->y = 0;
1182 r->width = 0;
1183 r->height = 0;
1184 }
1185
1186 Boolean
_XmIsNavigable(Widget wid)1187 _XmIsNavigable(
1188 Widget wid)
1189 {
1190 XmNavigability nav = _XmGetNavigability( wid) ;
1191 if( (nav != XmTAB_NAVIGABLE)
1192 && (nav != XmCONTROL_NAVIGABLE) )
1193 {
1194 return FALSE ;
1195 }
1196 while( (wid = XtParent( wid)) && !XtIsShell( wid) )
1197 {
1198 if( !_XmGetNavigability( wid) )
1199 {
1200 return FALSE ;
1201 }
1202 }
1203 return TRUE ;
1204 }
1205
1206 void
_XmWidgetFocusChange(Widget wid,XmFocusChange change)1207 _XmWidgetFocusChange(
1208 Widget wid,
1209 XmFocusChange change)
1210 {
1211 XmBaseClassExt *er ;
1212
1213 if( XtIsRectObj( wid)
1214 && !wid->core.being_destroyed )
1215 {
1216 if( (er = _XmGetBaseClassExtPtr( XtClass( wid), XmQmotif))
1217 && (*er)
1218 && ((*er)->version >= XmBaseClassExtVersion)
1219 && (*er)->focusChange )
1220 {
1221 (*((*er)->focusChange))( wid, change) ;
1222 }
1223 else
1224 { /* From here on is compatibility code.
1225 */
1226 WidgetClass wc ;
1227
1228 if( XmIsPrimitive( wid) )
1229 {
1230 wc = (WidgetClass) &xmPrimitiveClassRec ;
1231 }
1232 else if( XmIsGadget( wid) )
1233 {
1234 wc = (WidgetClass) &xmGadgetClassRec ;
1235 }
1236 else if( XmIsManager( wid) )
1237 {
1238 wc = (WidgetClass) &xmManagerClassRec ;
1239 }
1240 else
1241 {
1242 wc = NULL ;
1243 }
1244
1245 if( wc
1246 && (er = _XmGetBaseClassExtPtr( wc, XmQmotif))
1247 && (*er)
1248 && ((*er)->version >= XmBaseClassExtVersion)
1249 && (*er)->focusChange )
1250 {
1251 (*((*er)->focusChange))( wid, change) ;
1252 }
1253 }
1254 }
1255 return ;
1256 }
1257
1258 Widget
_XmNavigate(Widget wid,XmTraversalDirection direction)1259 _XmNavigate(
1260 Widget wid,
1261 XmTraversalDirection direction )
1262 {
1263 XmTraversalDirection local_dir;
1264 XmFocusData focus_data;
1265 Widget nav_wid = NULL ;
1266 Widget shell = _XmFindTopMostShell( wid) ;
1267
1268 if( (focus_data = _XmGetFocusData( shell))
1269 && (focus_data->focus_policy == XmEXPLICIT) )
1270 {
1271 XmTravGraph trav_list = &(focus_data->trav_graph) ;
1272
1273 nav_wid = _XmTraverse( trav_list, direction, &local_dir, wid) ;
1274
1275 nav_wid = RedirectTraversal(focus_data->focus_item, nav_wid,
1276 focus_data->focus_policy, local_dir, 0);
1277
1278 if( trav_list->num_entries
1279 && (focus_data->focalPoint == XmUnrelated)
1280 && ( XmIsVendorShell( shell)
1281 || !XmeFocusIsInShell( shell)) )
1282 {
1283 _XmFreeTravGraph( trav_list) ;
1284 }
1285 }
1286 return nav_wid ;
1287 }
1288
1289 void
_XmSetInitialOfTabGroup(Widget tab_group,Widget init_focus)1290 _XmSetInitialOfTabGroup(
1291 Widget tab_group,
1292 Widget init_focus)
1293 {
1294 XmFocusData focus_data ;
1295
1296 if( XmIsManager( tab_group) )
1297 {
1298 ((XmManagerWidget) tab_group)->manager.initial_focus = init_focus ;
1299 }
1300 if( (focus_data = _XmGetFocusData( tab_group))
1301 && focus_data->trav_graph.num_entries )
1302 {
1303 _XmSetInitialOfTabGraph( &(focus_data->trav_graph),
1304 tab_group, init_focus) ;
1305 }
1306 }
1307
1308 static Boolean
IsTraversable(Widget wid,Boolean require_in_view)1309 IsTraversable(
1310 Widget wid,
1311 Boolean require_in_view)
1312 {
1313 if( wid
1314 && _XmIsNavigable( wid) )
1315 {
1316 if( require_in_view )
1317 {
1318 return (XmGetVisibility( wid) != XmVISIBILITY_FULLY_OBSCURED) ;
1319 }
1320 else
1321 {
1322 /* _XmGetEffectiveView() returns the view port in
1323 * which the widget could be viewed through the use
1324 * of the XmNtraverseObscuredCallback of ScrolledWindow.
1325 */
1326 XRectangle visRect ;
1327
1328 return _XmGetEffectiveView( wid, &visRect) ;
1329 }
1330 }
1331 return FALSE ;
1332 }
1333
1334 void
_XmResetTravGraph(Widget wid)1335 _XmResetTravGraph(
1336 Widget wid)
1337 {
1338 XmFocusData focus_data = _XmGetFocusData( wid) ;
1339
1340 if( focus_data && focus_data->trav_graph.num_entries )
1341 {
1342 _XmFreeTravGraph( &(focus_data->trav_graph)) ;
1343 }
1344 }
1345
1346 Boolean
XmeFocusIsInShell(Widget wid)1347 XmeFocusIsInShell(
1348 Widget wid)
1349 {
1350 Window focus ;
1351 Widget focus_wid ;
1352 Widget shell_of_wid = _XmFindTopMostShell( wid) ;
1353 XmFocusData focus_data ;
1354 int revert ;
1355 _XmWidgetToAppContext(wid);
1356
1357 _XmAppLock(app);
1358 if( XmIsVendorShell( shell_of_wid)
1359 && (focus_data = _XmGetFocusData( shell_of_wid)) )
1360 {
1361 if( focus_data->focalPoint != XmUnrelated )
1362 {
1363 _XmAppUnlock(app);
1364 return TRUE ;
1365 }
1366 }
1367 else
1368 {
1369 XGetInputFocus( XtDisplay( shell_of_wid), &focus, &revert) ;
1370
1371 if( (focus != PointerRoot)
1372 && (focus != None)
1373 && (focus_wid = XtWindowToWidget( XtDisplay( shell_of_wid), focus))
1374 && (shell_of_wid == _XmFindTopMostShell( focus_wid)) )
1375 {
1376 _XmAppUnlock(app);
1377 return TRUE ;
1378 }
1379 }
1380 _XmAppUnlock(app);
1381 return FALSE ;
1382 }
1383
1384 Boolean
_XmShellIsExclusive(Widget wid)1385 _XmShellIsExclusive(
1386 Widget wid)
1387 {
1388 XmFocusData focusData = _XmGetFocusData( wid) ;
1389
1390 if( focusData
1391 && focusData->trav_graph.exclusive )
1392 {
1393 return TRUE ;
1394 }
1395 return FALSE ;
1396 }
1397
1398 static Widget
FindFirstFocus(Widget wid)1399 FindFirstFocus(
1400 Widget wid)
1401 {
1402 Widget shell = _XmFindTopMostShell( wid) ;
1403
1404 return _XmNavigate( shell, XmTRAVERSE_CURRENT) ;
1405 }
1406
1407 Widget
_XmGetFirstFocus(Widget wid)1408 _XmGetFirstFocus(
1409 Widget wid)
1410 {
1411 XmFocusData focus_data = _XmGetFocusData( wid) ;
1412
1413 if( focus_data )
1414 {
1415 if( focus_data->focus_item )
1416 {
1417 return focus_data->focus_item ;
1418 }
1419 else
1420 {
1421 if( focus_data->first_focus == NULL )
1422 {
1423 focus_data->first_focus = FindFirstFocus( wid) ;
1424 }
1425 return focus_data->first_focus ;
1426 }
1427 }
1428 return NULL ;
1429 }
1430
1431
1432 /*******************
1433 * Public procedures
1434 *******************/
1435
1436 Boolean
XmIsTraversable(Widget wid)1437 XmIsTraversable(
1438 Widget wid)
1439 {
1440 Boolean traversable;
1441 _XmWidgetToAppContext(wid);
1442
1443 _XmAppLock(app);
1444 traversable = IsTraversable( wid, FALSE) ;
1445 _XmAppUnlock(app);
1446 return traversable;
1447 }
1448
1449 XmVisibility
XmGetVisibility(Widget wid)1450 XmGetVisibility(
1451 Widget wid)
1452 {
1453 XRectangle rect ;
1454 Window rootwindow, parent_window, p_window, *children;
1455 unsigned int numchildren;
1456 int i;
1457 Window *windowptr;
1458 _XmWidgetToAppContext(wid);
1459
1460 _XmAppLock(app);
1461 if( !wid
1462 || !_XmComputeVisibilityRect(wid, &rect, FALSE, TRUE) )
1463 {
1464 _XmAppUnlock(app);
1465 return( XmVISIBILITY_FULLY_OBSCURED) ;
1466 }
1467 if( (rect.width != XtWidth( wid))
1468 || (rect.height != XtHeight( wid)) )
1469 {
1470 _XmAppUnlock(app);
1471 return( XmVISIBILITY_PARTIALLY_OBSCURED) ;
1472 }
1473
1474 /* Obscurity by siblings */
1475
1476 children = NULL;
1477 if (!(parent_window = XtWindow(XtParent(wid))) ||
1478 XQueryTree( XtDisplay(wid), parent_window, &rootwindow,
1479 &p_window, &children, &numchildren ) == 0)
1480 {
1481 if (children) XFree(children);
1482 _XmAppUnlock(app);
1483 return( XmVISIBILITY_UNOBSCURED) ;
1484 }
1485
1486 windowptr = children;
1487
1488 /* walk through those which are under the window of interest */
1489 for ( i = 0; i < numchildren; i++ )
1490 {
1491 if ( *windowptr == XtWindow(wid))
1492 {
1493 break;
1494 }
1495 windowptr++;
1496 }
1497 i++;
1498 windowptr++;
1499
1500 /* process windows above the window of interest */
1501 if(i < numchildren) {
1502 XRectangle parent_rect, srcRectB, intersect_rect;
1503 XWindowAttributes window_attributes_return;
1504 Region region = XCreateRegion();
1505 Region tmp_region = XCreateRegion();
1506 Region left_region = XCreateRegion();
1507 XmVisibility value;
1508
1509 XUnionRectWithRegion(&rect, region, region);
1510 while(i < numchildren) {
1511 XGetWindowAttributes(XtDisplay(wid), *windowptr,
1512 &window_attributes_return);
1513
1514 if(window_attributes_return.map_state == IsViewable) {
1515 _XmSetRect(&parent_rect, XtParent(wid));
1516 srcRectB.x = parent_rect.x + window_attributes_return.x
1517 + window_attributes_return.border_width;
1518 srcRectB.y = parent_rect.y + window_attributes_return.y
1519 + window_attributes_return.border_width;
1520 srcRectB.width = window_attributes_return.width;
1521 srcRectB.height = window_attributes_return.height;
1522
1523 /* accumulate all the region covered by siblings */
1524 if(_XmIntersectionOf( &rect, &srcRectB, &intersect_rect)) {
1525 XUnionRectWithRegion(&intersect_rect, tmp_region, tmp_region);
1526 }
1527 }
1528 i++;
1529 windowptr++;
1530 }
1531
1532 XSubtractRegion(region, tmp_region, left_region);
1533 if(XEqualRegion(region, left_region)) {
1534 value = XmVISIBILITY_UNOBSCURED;
1535 } else if(XEmptyRegion(left_region)) {
1536 value = XmVISIBILITY_FULLY_OBSCURED;
1537 } else {
1538 value = XmVISIBILITY_PARTIALLY_OBSCURED;
1539 }
1540 XDestroyRegion(region);
1541 XDestroyRegion(tmp_region);
1542 XDestroyRegion(left_region);
1543 if (children) XFree(children);
1544 _XmAppUnlock(app);
1545 return (value);
1546 }
1547 XFree((Window*)children);
1548
1549 _XmAppUnlock(app);
1550 return( XmVISIBILITY_UNOBSCURED) ;
1551 }
1552
1553 Widget
XmGetTabGroup(Widget wid)1554 XmGetTabGroup(
1555 Widget wid)
1556 {
1557 XmFocusData focus_data ;
1558 Boolean exclusive ;
1559 _XmWidgetToAppContext(wid);
1560
1561 _XmAppLock(app);
1562 if( !wid
1563 || (_XmGetFocusPolicy( wid) != XmEXPLICIT)
1564 || !(focus_data = _XmGetFocusData( wid)) )
1565 {
1566 _XmAppUnlock(app);
1567 return( NULL) ;
1568 }
1569 exclusive = !!(focus_data->trav_graph.exclusive) ;
1570
1571 do
1572 {
1573 XmNavigationType nav_type = _XmGetNavigationType( wid) ;
1574
1575 if( (nav_type == XmSTICKY_TAB_GROUP)
1576 || (nav_type == XmEXCLUSIVE_TAB_GROUP)
1577 || ( (nav_type == XmTAB_GROUP)
1578 && !exclusive) )
1579 {
1580 _XmAppUnlock(app);
1581 return( wid) ;
1582 }
1583 } while( (wid = XtParent( wid)) && !XtIsShell( wid) ) ;
1584
1585 _XmAppUnlock(app);
1586 return wid ;
1587 }
1588
1589 Widget
XmGetFocusWidget(Widget wid)1590 XmGetFocusWidget(
1591 Widget wid)
1592 {
1593 Widget focus_wid = NULL ;
1594 XmFocusData focus_data = _XmGetFocusData( wid) ;
1595 _XmWidgetToAppContext(wid);
1596
1597 _XmAppLock(app);
1598 if( focus_data != NULL )
1599 {
1600 if( focus_data->focus_policy == XmEXPLICIT )
1601 {
1602 focus_wid = focus_data->focus_item ;
1603 }
1604 else
1605 {
1606 focus_wid = focus_data->pointer_item ;
1607
1608 if( (focus_wid != NULL)
1609 && XmIsManager( focus_wid)
1610 && (((XmManagerWidget) focus_wid)
1611 ->manager.highlighted_widget != NULL) )
1612 {
1613 focus_wid = ((XmManagerWidget) focus_wid)
1614 ->manager.highlighted_widget ;
1615 }
1616 }
1617 }
1618 _XmAppUnlock(app);
1619 return focus_wid ;
1620 }
1621
1622 Boolean
XmProcessTraversal(Widget w,XmTraversalDirection dir)1623 XmProcessTraversal(
1624 Widget w,
1625 XmTraversalDirection dir)
1626 {
1627 XmFocusData focus_data ;
1628 Boolean ret_val = FALSE;
1629
1630 if ( w )
1631 {
1632 _XmWidgetToAppContext(w);
1633
1634 _XmAppLock(app);
1635 if( (focus_data = _XmGetFocusData( w))
1636 && (focus_data->focus_policy == XmEXPLICIT) )
1637 {
1638 if( dir != XmTRAVERSE_CURRENT )
1639 {
1640 if( focus_data->focus_item )
1641 {
1642 w = focus_data->focus_item ;
1643 }
1644 else
1645 {
1646 w = _XmFindTopMostShell( w) ;
1647 }
1648 }
1649 ret_val = _XmMgrTraversal( w, dir) ;
1650 }
1651 _XmAppUnlock(app);
1652 }
1653 return ret_val;
1654 }
1655
1656 void
XmAddTabGroup(Widget tabGroup)1657 XmAddTabGroup(
1658 Widget tabGroup )
1659 {
1660 Arg arg;
1661
1662 XtSetArg(arg, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP);
1663 XtSetValues(tabGroup, &arg, 1);
1664 }
1665
1666 void
XmRemoveTabGroup(Widget w)1667 XmRemoveTabGroup(
1668 Widget w )
1669 {
1670 Arg arg;
1671
1672 XtSetArg(arg, XmNnavigationType, XmNONE);
1673 XtSetValues(w, &arg, 1);
1674 }
1675
1676 /*
1677 * Invoke the traversal redirection trait for all ancestors of both
1678 * old_focus and new_focus. Repeat until concensus is achieved.
1679 */
1680 static Widget
RedirectTraversal(Widget old_focus,Widget new_focus,unsigned int focus_policy,XmTraversalDirection direction,unsigned int pass)1681 RedirectTraversal(Widget old_focus,
1682 Widget new_focus,
1683 unsigned int focus_policy,
1684 XmTraversalDirection direction,
1685 unsigned int pass)
1686 {
1687 XmTraversalControlTrait trav_trait;
1688 Widget proposal = new_focus;
1689 Widget parent;
1690
1691 /* Try not to get into an infinite loop. */
1692 if (pass >= 255)
1693 {
1694 assert(FALSE);
1695 return NULL;
1696 }
1697
1698 /* Check ancestors of the old focus. */
1699 for (parent = old_focus; parent != NULL; parent = XtParent(parent))
1700 {
1701 trav_trait = (XmTraversalControlTrait)
1702 XmeTraitGet((XtPointer) XtClass(parent), XmQTtraversalControl);
1703
1704 if (trav_trait && trav_trait->redirect)
1705 {
1706 proposal = trav_trait->redirect(old_focus, new_focus,
1707 focus_policy, direction, pass);
1708 if (proposal != new_focus)
1709 return RedirectTraversal(old_focus, proposal,
1710 focus_policy, direction, pass + 1);
1711 }
1712 }
1713
1714 /* Check ancestors of the new focus. */
1715 for (parent = new_focus; parent != NULL; parent = XtParent(parent))
1716 {
1717 trav_trait = (XmTraversalControlTrait)
1718 XmeTraitGet((XtPointer) XtClass(parent), XmQTtraversalControl);
1719
1720 if (trav_trait && trav_trait->redirect)
1721 {
1722 proposal = trav_trait->redirect(old_focus, new_focus,
1723 focus_policy, direction, pass);
1724 if (proposal != new_focus)
1725 return RedirectTraversal(old_focus, proposal,
1726 focus_policy, direction, pass + 1);
1727 }
1728 }
1729
1730 /* Nobody changed our mind. */
1731 return new_focus;
1732 }
1733