2
* @OPENGROUP_COPYRIGHT@
4
* Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc.
5
* Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group
6
* ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for
7
* the full copyright text.
9
* This software is subject to an open license. It may only be
10
* used on, with or for operating systems which are themselves open
11
* source systems. You must contact The Open Group for a license
12
* allowing distribution and sublicensing of this software on, with,
13
* or for operating systems which are not Open Source programs.
15
* See http://www.opengroup.org/openmotif/license for full
16
* details of the license agreement. Any use, reproduction, or
17
* distribution of the program constitutes recipient's acceptance of
20
* EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
21
* PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
22
* KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
23
* WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
24
* OR FITNESS FOR A PARTICULAR PURPOSE
26
* EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
27
* NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT,
28
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29
* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED
30
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32
* ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
33
* EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
34
* POSSIBILITY OF SUCH DAMAGES.
46
static char rcsid[] = "$TOG: TravAct.c /main/14 1999/05/27 13:58:09 mgreess $"
50
/* (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 HEWLETT-PACKARD COMPANY */
52
#include "TraversalI.h"
54
#include <Xm/GadgetP.h>
55
#include <Xm/PrimitiveP.h>
56
#include <Xm/ManagerP.h>
57
#include <Xm/VendorSEP.h>
58
#include <Xm/MenuShellP.h>
60
#include <Xm/VirtKeysP.h>
61
#include <Xm/DisplayP.h>
62
#include <Xm/ScrolledWP.h>
67
#define EVENTS_EQ(ev1, ev2) \
68
((((ev1)->type == (ev2)->type) &&\
69
((ev1)->serial == (ev2)->serial) &&\
70
((ev1)->time == (ev2)->time) &&\
71
((ev1)->x == (ev2)->x) &&\
72
((ev1)->y == (ev2)->y)) ? TRUE : FALSE)
75
/******** Static Function Declarations ********/
77
static Boolean UpdatePointerData(Widget w, XEvent *event);
78
static void FlushPointerData(Widget w, XEvent *event);
79
static void DispatchGadgetInput(XmGadget g, XEvent *event, Mask mask);
81
/******** End Static Function Declarations ********/
85
* The following functions are used by the widgets to query or modify one
86
* of the display dependent global variabled used by traversal mechanism.
90
_XmGetFocusFlag(Widget w,
93
XmDisplay dd = (XmDisplay)XmGetXmDisplay(XtDisplay(w));
95
return ((unsigned short)((XmDisplayInfo *)
96
(dd->display.displayInfo))->resetFocusFlag & mask);
101
_XmSetFocusFlag(Widget w,
103
#if NeedWidePrototypes
107
#endif /* NeedWidePrototypes */
109
XmDisplay dd = (XmDisplay)XmGetXmDisplay(XtDisplay(w));
113
(dd->display.displayInfo))->resetFocusFlag |= mask;
116
(dd->display.displayInfo))->resetFocusFlag &= ~mask;
121
UpdatePointerData(Widget w,
124
XmFocusData focusData;
126
if ((focusData = _XmGetFocusData(w)) != NULL)
128
XCrossingEvent *lastEvent = &(focusData->lastCrossingEvent);
130
focusData->needToFlush = TRUE;
132
if (!EVENTS_EQ(lastEvent, (XCrossingEvent *)event))
134
focusData->old_pointer_item = focusData->pointer_item;
135
focusData->pointer_item = w;
136
focusData->lastCrossingEvent = *(XCrossingEvent *) event;
145
FlushPointerData(Widget w,
148
XmFocusData focusData = _XmGetFocusData(w);
150
if (focusData && focusData->needToFlush)
152
XCrossingEvent lastEvent;
154
lastEvent = focusData->lastCrossingEvent;
156
focusData->needToFlush = FALSE;
158
* We are munging data into the event to fake out the focus
159
* code when Mwm is trying to catch up with the pointer.
160
* This event that we are munging might already have been
161
* munged by XmDispatchGadgetInput from a motion event to a
162
* crossing event !!!!!
165
lastEvent.serial = event->xany.serial;
166
if ( (LeaveNotify == event->type) || (EnterNotify == event->type) )
167
lastEvent.time = event->xcrossing.time;
169
/* Approximation; the code appears to need even Focus events,
170
** so make up a time and try to continue, rather than limit
171
** lastEvent to XCrossingEvents. (It is a flaw in the X
172
** Protocol that Focus events do not have timestamps.)
174
lastEvent.time = XtLastTimestampProcessed(XtDisplay(w));
175
lastEvent.focus = True;
176
XtDispatchEvent((XEvent *) &lastEvent);
180
/************************************************************************
184
* This handler is added by ShellExt initialize to the front of the
187
************************************************************************/
190
_XmTrackShellFocus(Widget widget,
191
XtPointer client_data,
193
Boolean *dontSwallow)
195
XmVendorShellExtObject ve = (XmVendorShellExtObject) client_data;
196
XmFocusData focusData;
197
XmGeneology oldFocalPoint;
198
XmGeneology newFocalPoint;
200
if (widget->core.being_destroyed)
202
*dontSwallow = False;
206
if ((focusData = ve->vendor.focus_data) == NULL)
209
oldFocalPoint = newFocalPoint = focusData->focalPoint;
216
* If operating in a focus driven model, then enter and
217
* leave events do not affect the keyboard focus.
219
if ((event->xcrossing.detail != NotifyInferior) &&
220
(event->xcrossing.focus))
222
switch (oldFocalPoint)
225
if (event->type == EnterNotify)
226
newFocalPoint = XmMyAncestor;
229
if (event->type == LeaveNotify)
230
newFocalPoint = XmUnrelated;
242
switch (event->xfocus.detail)
244
case NotifyNonlinear:
247
newFocalPoint = XmMySelf;
249
case NotifyNonlinearVirtual:
251
newFocalPoint = XmMyDescendant;
254
newFocalPoint = XmMyAncestor;
260
switch (event->xfocus.detail)
263
case NotifyNonlinear:
265
case NotifyNonlinearVirtual:
267
newFocalPoint = XmUnrelated;
275
if (newFocalPoint == XmUnrelated)
277
focusData->old_focus_item = NULL;
279
if (focusData->trav_graph.num_alloc)
281
/* Free traversal graph, since focus is leaving hierarchy. */
282
_XmFreeTravGraph(&(focusData->trav_graph));
286
if ((focusData->focus_policy == XmEXPLICIT) &&
287
(oldFocalPoint != newFocalPoint) &&
288
focusData->focus_item)
290
if (oldFocalPoint == XmUnrelated)
291
_XmCallFocusMoved(NULL, focusData->focus_item, event);
292
else if (newFocalPoint == XmUnrelated)
293
_XmCallFocusMoved(focusData->focus_item, NULL, event);
296
focusData->focalPoint = newFocalPoint;
299
/************************************************************************
302
* Enter and leave event processing routines.
304
************************************************************************/
308
_XmPrimitiveEnter(Widget wid,
310
String *params, /* unused */
311
Cardinal *num_params) /* unused */
313
_XmToolTipEnter(wid, event, params, num_params);
314
if (_XmGetFocusPolicy(wid) == XmPOINTER)
316
if (event->xcrossing.focus)
318
_XmCallFocusMoved(XtParent(wid), wid, event);
319
_XmWidgetFocusChange(wid, XmENTER);
322
UpdatePointerData(wid, event);
328
_XmPrimitiveLeave(Widget wid,
330
String *params, /* unused */
331
Cardinal *num_params) /* unused */
333
_XmToolTipLeave(wid, event, params, num_params);
334
if (_XmGetFocusPolicy(wid) == XmPOINTER)
336
if (event->xcrossing.focus)
338
_XmCallFocusMoved(wid, XtParent(wid), event);
339
_XmWidgetFocusChange(wid, XmLEAVE);
344
/************************************************************************
348
************************************************************************/
352
_XmPrimitiveFocusInInternal(Widget wid,
354
String *params, /* unused */
355
Cardinal *num_params) /* unused */
357
if (!(event->xfocus.send_event) ||
358
_XmGetFocusFlag(wid, XmFOCUS_IGNORE))
361
if (_XmGetFocusPolicy(wid) == XmPOINTER)
363
/* Maybe Mwm trying to catch up with us. */
364
if (XtIsShell(XtParent(wid)))
365
FlushPointerData(wid, event);
369
/* We should only be recieving the focus from a traversal request. */
370
if (!_XmGetActiveTabGroup(wid))
371
_XmMgrTraversal(_XmFindTopMostShell(wid), XmTRAVERSE_NEXT_TAB_GROUP);
373
_XmWidgetFocusChange(wid, XmFOCUS_IN);
379
_XmPrimitiveFocusOut(Widget wid,
381
String *params, /* unused */
382
Cardinal *num_params) /* unused */
384
if (event->xfocus.send_event &&
385
!(wid->core.being_destroyed) &&
386
(_XmGetFocusPolicy(wid) == XmEXPLICIT))
388
_XmWidgetFocusChange(wid, XmFOCUS_OUT);
393
_XmPrimitiveFocusIn(Widget pw,
396
Cardinal *num_params)
398
_XmPrimitiveFocusInInternal(pw, event, params, num_params);
401
/************************************************************************
404
* This function processes enter window conditions occuring in a gadget
406
************************************************************************/
410
_XmEnterGadget(Widget wid,
412
String *params, /* unused */
413
Cardinal *num_params) /* unused */
415
if (XmIsGadget(wid) && ((XmGadget)wid)->gadget.traversal_on)
417
_XmToolTipEnter(wid, event, params, num_params);
419
if (_XmGetFocusPolicy(wid) == XmPOINTER)
421
XmFocusData focusData = _XmGetFocusData(wid);
423
/* We may be getting called as a result of Mwm catching up
424
* with the pointer and setting input focus to the shell
425
* which then gets forwarded to us.
427
if (focusData && (focusData->focalPoint != XmUnrelated))
429
_XmCallFocusMoved(XtParent(wid), wid, event);
430
_XmWidgetFocusChange(wid, XmENTER);
435
/************************************************************************
437
* DispatchGadgetInput
438
* This routine is used instead of _XmDispatchGadgetInput due to
439
* the fact that it needs to dispatch to unmanaged gadgets
441
************************************************************************/
443
DispatchGadgetInput(XmGadget g,
447
if ((g->gadget.event_mask & mask) && XtIsSensitive((Widget)g))
449
(*(((XmGadgetClass) (g->object.widget_class))->
450
gadget_class.input_dispatch)) ((Widget) g, event, mask);
454
/************************************************************************
457
* This function processes leave window conditions occuring in a gadget
459
************************************************************************/
463
_XmLeaveGadget(Widget wid,
465
String *params, /* unused */
466
Cardinal *num_params) /* unused */
468
if (XmIsGadget(wid) && ((XmGadget)wid)->gadget.traversal_on)
470
_XmToolTipLeave(wid, event, params, num_params);
473
if (_XmGetFocusPolicy(wid) == XmPOINTER)
475
_XmCallFocusMoved(wid, XtParent(wid), event);
476
_XmWidgetFocusChange(wid, XmLEAVE);
480
/************************************************************************
483
* This function processes focusIn conditions occuring in a gadget
486
************************************************************************/
489
_XmFocusInGadget(Widget wid,
490
XEvent *event, /* unused */
491
String *params, /* unused */
492
Cardinal *num_params) /* unused */
494
if (_XmGetFocusPolicy(wid) == XmEXPLICIT)
495
_XmWidgetFocusChange(wid, XmFOCUS_IN);
498
/************************************************************************
501
* This function processes FocusOut conditions occuring in a gadget
503
************************************************************************/
507
_XmFocusOutGadget(Widget wid,
508
XEvent *event, /* unused */
509
String *params, /* unused */
510
Cardinal *num_params) /* unused */
512
if (_XmGetFocusPolicy(wid) == XmEXPLICIT)
513
_XmWidgetFocusChange(wid, XmFOCUS_OUT);
516
/************************************************************************
518
* Enter, FocusIn and Leave Window procs
520
* These two procedures handle traversal activation and deactivation
521
* for manager widgets. They are invoked directly throught the
522
* the action table of a widget.
524
************************************************************************/
526
/************************************************************************
529
* This function handles both focusIn and Enter. Don't ask me why
532
************************************************************************/
536
_XmManagerEnter(Widget wid,
538
String *params, /* unused */
539
Cardinal *num_params) /* unused */
541
XmManagerWidget mw = (XmManagerWidget) wid;
542
XCrossingEvent *event = (XCrossingEvent *) event_in;
544
if (_XmGetFocusPolicy((Widget) mw) == XmPOINTER)
546
if (UpdatePointerData((Widget) mw, event_in) && event->focus)
550
if (event->detail == NotifyInferior)
551
old = XtWindowToWidget(event->display, event->subwindow);
555
_XmCallFocusMoved(old, (Widget) mw, (XEvent *) event);
556
_XmWidgetFocusChange((Widget) mw, XmENTER);
563
_XmManagerLeave(Widget wid,
565
String *params, /* unused */
566
Cardinal *num_params) /* unused */
569
* This code is inefficient since it is called twice for each
570
* internal move in the hierarchy |||
572
if (event->type == LeaveNotify)
574
if (_XmGetFocusPolicy(wid) == XmPOINTER)
578
if (event->xcrossing.detail == NotifyInferior)
579
new_wid = XtWindowToWidget(event->xcrossing.display,
580
event->xcrossing.subwindow);
582
new_wid = XtParent(wid);
584
if (UpdatePointerData(wid, event) && event->xcrossing.focus)
586
_XmCallFocusMoved(wid, new_wid, event);
587
_XmWidgetFocusChange(wid, XmLEAVE);
595
_XmManagerFocusInInternal(Widget wid,
597
String *params, /* unused */
598
Cardinal *num_params) /* unused */
603
* Managers ignore all focus events which have been generated by the
604
* window system; only those sent to us by a window manager or the
605
* Xtk focus code is accepted.
606
* Bail out if the focus policy is not set to explicit
608
if (!(event->xfocus.send_event) ||
609
_XmGetFocusFlag(wid, XmFOCUS_RESET | XmFOCUS_IGNORE))
612
if (_XmGetFocusPolicy(wid) == XmPOINTER)
614
FlushPointerData(wid, event);
616
else if (!_XmGetActiveTabGroup(wid))
618
/* If the heirarchy doesn't have an active tab group give it one. */
619
_XmMgrTraversal(_XmFindTopMostShell(wid), XmTRAVERSE_NEXT_TAB_GROUP);
621
else if ((child = ((XmManagerWidget) wid)->manager.active_child) &&
624
/* If focus went to a gadget, then force it to highlight */
625
DispatchGadgetInput((XmGadget) child, event, XmFOCUS_IN_EVENT);
629
_XmWidgetFocusChange(wid, XmFOCUS_IN);
634
* Non-menu widgets use this entry point, so that they will ignore focus
635
* events during menu activities.
638
_XmManagerFocusIn(Widget mw,
641
Cardinal *num_params)
643
_XmManagerFocusInInternal(mw, event, params, num_params);
647
* If the manager widget received a FocusOut while it is processing its
648
* FocusIn event, then it knows that the focus has been successfully moved
649
* to one of its children. However, if no FocusOut is received, then the
650
* manager widget must manually force the child to take the focus.
655
_XmManagerFocusOut(Widget wid,
657
String *params, /* unused */
658
Cardinal *num_params) /* unused */
662
if (!event->xfocus.send_event)
665
if (_XmGetFocusPolicy(wid) == XmEXPLICIT)
667
/* If focus is in a gadget, then force it to unhighlight. */
668
if ((child = ((XmManagerWidget) wid)->manager.active_child) &&
671
DispatchGadgetInput((XmGadget) child, event, XmFOCUS_OUT_EVENT);
675
_XmWidgetFocusChange(wid, XmFOCUS_OUT);
682
_XmManagerUnmap(Widget mw,
683
XEvent *event, /* unused */
684
String *params, /* unused */
685
Cardinal *num_params) /* unused */
687
/* This functionality is bogus, since a good implementation
688
* requires more code (hooks for mapping of widgets) than it's
689
* worth. To move focus away from a widget when it is unmapped
690
* implies the ability to recover from the case when the last
691
* traversable widget in a hierarchy is unmapped and then re-mapped.
692
* Since we don't have the hooks in place for the mapping of these
693
* widgets, and since the old code only worked some of the time,
694
* and since it is arguable that the focus should never be
695
* changed in response to a widget being unmapped, we should choose
696
* to do NO traversal in response to the unmapping of a widget.
697
* However, historical precedent again defeats good design.
699
_XmValidateFocus(mw);
704
_XmPrimitiveUnmap(Widget pw,
705
XEvent *event, /* unused */
706
String *params, /* unused */
707
Cardinal *num_params) /* unused */
709
_XmValidateFocus(pw);