/*
* Motif
*
* Copyright (c) 1987-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef REV_INFO
#ifndef lint
static char rcsid[] = "$XConsortium: TrackLoc.c /main/12 1995/10/25 20:24:41 cde-sun $"
#endif
#endif
/*
* (c) Copyright 1990, 1991, 1992 HEWLETT-PACKARD COMPANY */
#include <Xm/XmP.h>
#include "XmI.h"
#include "MessagesI.h"
#define GRABPTRERROR _XmMMsgCascadeB_0003
/******** Static Function Declarations ********/
static Widget _XmInputInWidget(
Widget w,
#if NeedWidePrototypes
int x,
int y) ;
#else
Position x,
Position y) ;
#endif /* NeedWidePrototypes */
/******** End Static Function Declarations ********/
/******************************************************/
/* copy from XmeGadgetAtPoint, buts works for widget too,
only used in this module so far, so let it static */
static Widget
_XmInputInWidget(
Widget w,
#if NeedWidePrototypes
int x,
int y)
#else
Position x,
Position y)
#endif /* NeedWidePrototypes */
{
int i;
Widget child;
CompositeWidget cw = (CompositeWidget) w;
/* loop over the child list to find if there is one at x,y */
/* well, overlapping won't really work, since I have no standard way to
check visibility */
for (i = 0; i < cw->composite.num_children; i++) {
child = cw->composite.children[i];
if (XtIsManaged (child)) {
if (x >= child->core.x && y >= child->core.y &&
x < child->core.x + child->core.width &&
y < child->core.y + child->core.height)
return (child);
}
}
return (NULL);
}
/* new tracking locate function that returns the event that trigerred
the return + this function uses XNextEvent instead of just XMaskEvent
which was only eating some events and thus causing problem when
back to the application */
Widget
XmTrackingEvent(
Widget widget,
Cursor cursor,
#if NeedWidePrototypes
int confineTo,
#else
Boolean confineTo,
#endif /* NeedWidePrototypes */
XEvent * pev)
{
Window w, confine_to = None;
Time lastTime;
Widget child;
Boolean key_has_been_pressed= False;
Widget target ;
Position x, y ;
XtAppContext app;
if (widget == NULL) return(NULL);
app = XtWidgetToApplicationContext(widget);
_XmAppLock(app);
w = XtWindowOfObject(widget);
if (confineTo) confine_to = w;
lastTime = XtLastTimestampProcessed(XtDisplay(widget));
XmUpdateDisplay(widget);
if (XtGrabPointer(widget, True,
/* The following truncation of masks is due to a bug in the Xt API.*/
(unsigned int) (ButtonPressMask | ButtonReleaseMask),
GrabModeAsync, GrabModeAsync,
confine_to, cursor, lastTime) != GrabSuccess) {
XmeWarning(widget, GRABPTRERROR);
_XmAppUnlock(app);
return NULL ;
}
while (True) {
/* eat all events, not just button's */
XNextEvent(XtDisplay(widget), pev);
/* track only button1release and non first keyrelease */
if (((pev->type == ButtonRelease) &&
(pev->xbutton.button & Button1)) ||
((pev->type == KeyRelease) && key_has_been_pressed)) {
if ((!confineTo) && (pev->xbutton.window == w)) {
/* this is the case where we are not confine, so the user
can click outside the window, but we want to return
NULL */
if ((pev->xbutton.x < 0) || (pev->xbutton.y < 0) ||
(pev->xbutton.x > widget->core.width) ||
(pev->xbutton.y > widget->core.height))
{
XtUngrabPointer(widget, lastTime);
_XmAppUnlock(app);
return(NULL);
}
}
target = XtWindowToWidget(pev->xbutton.display,
pev->xbutton.window);
/* New algorithm that solves the problem of mouse insensitive widgets:
( i.e you can't get help on Label.)
When we get the Btn1Up event with the window in which the event ocurred,
and convert it to a widget. If that widget is a primitive, return it.
Otherwise, it is a composite or a shell, and we do the following:
Walk down the child list (for gadgets AND WIDGETS), looking for one which
contains the x,y. If none is found, return the manager itself,
If a primitive or gadget is found, return the object found.
If a manager is found, execute the above algorithm recursively with
that manager. */
if (target) {
/* do not change the original pev coordinates */
x = pev->xbutton.x ;
y = pev->xbutton.y ;
/* do not enter the loop for primitive */
while (XtIsComposite(target) || XtIsShell(target)) {
if ((child = _XmInputInWidget(target, x,y)) != NULL) {
target = child;
/* if a gadget or a primitive is found, return */
if (!XtIsComposite(child)) break ;
/* otherwise, loop */
x = x - XtX(child) ;
y = y - XtY(child) ;
} else break ;
/* no child found at this place: return the manager */
}
}
break ;
} else if (pev->type == KeyPress) key_has_been_pressed = True ;
/* to avoid exiting on the first keyreleased coming from
the keypress activatation of the function itself */
}
XtUngrabPointer(widget, lastTime);
_XmAppUnlock(app);
return(target);
}
/* reimplementation of the old function using the new one and a dummy event */
Widget
XmTrackingLocate(
Widget widget,
Cursor cursor,
#if NeedWidePrototypes
int confineTo )
#else
Boolean confineTo )
#endif /* NeedWidePrototypes */
{
XEvent ev ;
return XmTrackingEvent(widget, cursor, confineTo, &ev);
}
/***********************************************************************
* Certain widgets, such as those in a menu, would like the application
* to look non-scraged (i.e. all exposure events have been processed)
* before invoking a callback which takes a long time to do its thing.
* This function grabs all exposure events off the queue, and processes
* them.
***********************************************************************/
void
XmUpdateDisplay(
Widget w )
{
XEvent event;
Display * display = XtDisplay(w);
_XmWidgetToAppContext(w);
_XmAppLock(app);
XSync (display, 0);
while (XCheckMaskEvent(display, ExposureMask, &event))
XtDispatchEvent(&event);
_XmAppUnlock(app);
}