Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: aadffb8864
Fetching contributors…

Cannot retrieve contributors at this time

1191 lines (1072 sloc) 31.574 kb
/*
* tkMacOSXMouseEvent.c --
*
* This file implements functions that decode & handle mouse events on
* MacOS X.
*
* Copyright 2001, Apple Computer, Inc.
* Copyright (c) 2005-2007 Daniel A. Steffen <das@users.sourceforge.net>
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* The following terms apply to all files originating from Apple
* Computer, Inc. ("Apple") and associated with the software unless
* explicitly disclaimed in individual files.
*
* Apple hereby grants permission to use, copy, modify, distribute, and
* license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that
* this notice is included verbatim in any distributions. No written
* agreement, license, or royalty fee is required for any of the
* authorized uses. Modifications to this software may be copyrighted by
* their authors and need not follow the licensing terms described here,
* provided that the new terms are clearly indicated on the first page of
* each file where they apply.
*
* IN NO EVENT SHALL APPLE, THE AUTHORS OR DISTRIBUTORS OF THE SOFTWARE
* BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
* CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE, ITS
* DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN IF APPLE OR THE
* AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. APPLE,
* THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
* NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND
* APPLE,THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
* MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* GOVERNMENT USE: If you are acquiring this software on behalf of the
* U.S. government, the Government shall have only "Restricted Rights" in
* the software and related documentation as defined in the Federal
* Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are
* acquiring the software on behalf of the Department of Defense, the
* software shall be classified as "Commercial Computer Software" and the
* Government shall have only "Restricted Rights" as defined in Clause
* 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
* authors grant the U.S. Government and others acting in its behalf
* permission to use and distribute the software in accordance with the
* terms specified in this license.
*/
#include "tkMacOSXPrivate.h"
#include "tkMacOSXWm.h"
#include "tkMacOSXEvent.h"
#include "tkMacOSXDebug.h"
typedef struct {
WindowRef whichWin;
WindowRef activeNonFloating;
WindowPartCode windowPart;
unsigned int state;
long delta;
Window window;
Point global;
Point local;
} MouseEventData;
/*
* Declarations of static variables used in this file.
*/
static int gEatButtonUp = 0; /* 1 if we need to eat the next up event. */
/*
* Declarations of functions used only in this file.
*/
static void BringWindowForward(WindowRef wRef, int isFrontProcess,
int frontWindowOnly);
static int GeneratePollingEvents(MouseEventData *medPtr);
static int GenerateMouseWheelEvent(MouseEventData *medPtr);
static int GenerateButtonEvent(MouseEventData *medPtr);
static int GenerateToolbarButtonEvent(MouseEventData *medPtr);
static int HandleWindowTitlebarMouseDown(MouseEventData *medPtr,
Tk_Window tkwin);
static unsigned int ButtonModifiers2State(UInt32 buttonState,
UInt32 keyModifiers);
static Tk_Window GetGrabWindowForWindow(Tk_Window tkwin);
static int TkMacOSXGetEatButtonUp(void);
static void TkMacOSXSetEatButtonUp(int f);
/*
*----------------------------------------------------------------------
*
* TkMacOSXProcessMouseEvent --
*
* This routine processes the event in eventPtr, and generates the
* appropriate Tk events from it.
*
* Results:
* True if event(s) are generated - false otherwise.
*
* Side effects:
* Additional events may be place on the Tk event queue.
*
*----------------------------------------------------------------------
*/
MODULE_SCOPE int
TkMacOSXProcessMouseEvent(
TkMacOSXEvent *eventPtr,
MacEventStatus *statusPtr)
{
Tk_Window tkwin;
Point where, where2;
int result;
TkDisplay *dispPtr;
OSStatus err;
MouseEventData mouseEventData, *medPtr = &mouseEventData;
int isFrontProcess;
switch (eventPtr->eKind) {
case kEventMouseDown:
case kEventMouseUp:
case kEventMouseMoved:
case kEventMouseDragged:
case kEventMouseWheelMoved:
break;
default:
return false;
}
err = ChkErr(GetEventParameter, eventPtr->eventRef,
kEventParamMouseLocation, typeQDPoint, NULL, sizeof(where), NULL,
&where);
if (err != noErr) {
GetGlobalMouse(&where);
}
err = ChkErr(GetEventParameter, eventPtr->eventRef, kEventParamWindowRef,
typeWindowRef, NULL, sizeof(WindowRef), NULL, &medPtr->whichWin);
if (err == noErr) {
err = ChkErr(GetEventParameter, eventPtr->eventRef,
kEventParamWindowPartCode, typeWindowPartCode, NULL,
sizeof(WindowPartCode), NULL, &medPtr->windowPart);
}
if (err != noErr) {
medPtr->windowPart = FindWindow(where, &medPtr->whichWin);
}
medPtr->window = TkMacOSXGetXWindow(medPtr->whichWin);
if (medPtr->whichWin != NULL && medPtr->window == None) {
return false;
}
if (eventPtr->eKind == kEventMouseDown) {
if (IsWindowActive(medPtr->whichWin) && IsWindowPathSelectEvent(
medPtr->whichWin, eventPtr->eventRef)) {
ChkErr(WindowPathSelect, medPtr->whichWin, NULL, NULL);
return false;
}
if (medPtr->windowPart == inProxyIcon) {
TkMacOSXTrackingLoop(1);
err = ChkErr(TrackWindowProxyDrag, medPtr->whichWin, where);
TkMacOSXTrackingLoop(0);
if (err == errUserWantsToDragWindow) {
medPtr->windowPart = inDrag;
} else {
return false;
}
}
}
isFrontProcess = Tk_MacOSXIsAppInFront();
if (isFrontProcess) {
medPtr->state = ButtonModifiers2State(GetCurrentEventButtonState(),
GetCurrentEventKeyModifiers());
} else {
medPtr->state = ButtonModifiers2State(GetCurrentButtonState(),
GetCurrentKeyModifiers());
}
medPtr->global = where;
err = ChkErr(GetEventParameter, eventPtr->eventRef,
kEventParamWindowMouseLocation, typeQDPoint, NULL,
sizeof(Point), NULL, &medPtr->local);
if (err == noErr) {
if (medPtr->whichWin) {
Rect widths;
GetWindowStructureWidths(medPtr->whichWin, &widths);
medPtr->local.h -= widths.left;
medPtr->local.v -= widths.top;
}
} else {
medPtr->local = where;
if (medPtr->whichWin) {
QDGlobalToLocalPoint(GetWindowPort(medPtr->whichWin),
&medPtr->local);
}
}
medPtr->activeNonFloating = ActiveNonFloatingWindow();
dispPtr = TkGetDisplayList();
tkwin = Tk_IdToWindow(dispPtr->display, medPtr->window);
if (eventPtr->eKind != kEventMouseDown) {
int res = false;
switch (eventPtr->eKind) {
case kEventMouseUp:
/*
* The window manager only needs to know about mouse down events
* and sometimes we need to "eat" the mouse up. Otherwise, we just
* pass the event to Tk.
*/
if (TkMacOSXGetEatButtonUp()) {
TkMacOSXSetEatButtonUp(false);
} else {
res = GenerateButtonEvent(medPtr);
}
break;
case kEventMouseWheelMoved:
err = ChkErr(GetEventParameter, eventPtr->eventRef,
kEventParamMouseWheelDelta, typeLongInteger, NULL,
sizeof(long), NULL, &medPtr->delta);
if (err != noErr ) {
statusPtr->err = 1;
} else {
EventMouseWheelAxis axis;
err = ChkErr(GetEventParameter, eventPtr->eventRef,
kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL,
sizeof(EventMouseWheelAxis), NULL, &axis);
if (err == noErr && axis == kEventMouseWheelAxisX) {
medPtr->state |= ShiftMask;
}
res = GenerateMouseWheelEvent(medPtr);
}
break;
case kEventMouseMoved:
case kEventMouseDragged:
res = GeneratePollingEvents(medPtr);
break;
default:
Tcl_Panic("Unknown mouse event !");
}
if (res) {
statusPtr->stopProcessing = 1;
}
return res;
}
TkMacOSXSetEatButtonUp(false);
if (!medPtr->whichWin) {
return false;
}
/*
* We got a mouse down in a window, so see if this is the activate click.
* This click moves the window forward. We don't want the corresponding
* mouse-up to be reported to the application or else it will mess up some
* Tk scripts.
*/
if (!(TkpIsWindowFloating(medPtr->whichWin))
&& (medPtr->whichWin != medPtr->activeNonFloating
|| !isFrontProcess)) {
int frontWindowOnly = 1;
int cmdDragGrow = ((medPtr->windowPart == inDrag ||
medPtr->windowPart == inGrow) && medPtr->state & Mod1Mask);
if (!cmdDragGrow) {
Tk_Window grabWin = GetGrabWindowForWindow(tkwin);
frontWindowOnly = !grabWin;
if (grabWin && grabWin != tkwin) {
TkMacOSXSetEatButtonUp(true);
BringWindowForward(TkMacOSXDrawableWindow(
((TkWindow *) grabWin)->window), isFrontProcess,
frontWindowOnly);
return false;
}
}
/*
* Clicks in the titlebar widgets are handled without bringing the
* window forward.
*/
result = HandleWindowTitlebarMouseDown(medPtr, tkwin);
if (result != -1) {
statusPtr->stopProcessing = 1;
return result;
}
/*
* Only windows with the kWindowNoActivatesAttribute can receive mouse
* events in the background.
*/
if (!(((TkWindow *)tkwin)->wmInfoPtr->attributes &
kWindowNoActivatesAttribute)) {
/*
* Allow background window dragging & growing with Command down.
*/
if (!cmdDragGrow) {
TkMacOSXSetEatButtonUp(true);
BringWindowForward(medPtr->whichWin, isFrontProcess,
frontWindowOnly);
}
/*
* Allow dragging & growing of windows that were/are in the
* background.
*/
if (!(medPtr->windowPart == inDrag ||
medPtr->windowPart == inGrow)) {
return false;
}
}
} else {
result = HandleWindowTitlebarMouseDown(medPtr, tkwin);
if (result != -1) {
statusPtr->stopProcessing = 1;
return result;
}
}
switch (medPtr->windowPart) {
case inDrag: {
WindowAttributes attributes;
GetWindowAttributes(medPtr->whichWin, &attributes);
if (!(attributes & kWindowAsyncDragAttribute)) {
TkMacOSXTrackingLoop(1);
DragWindow(medPtr->whichWin, where, NULL);
TkMacOSXTrackingLoop(0);
where2.h = where2.v = 0;
QDLocalToGlobalPoint(GetWindowPort(medPtr->whichWin), &where2);
return (EqualPt(where, where2)) ? false : true;
}
break;
}
case inGrow: {
/*
* Generally the content region is the domain of Tk sub-windows.
* However, one exception is the grow region. A button down in this
* area will be handled by the window manager. Note: this means that
* Tk may not get button down events in this area!
*/
XPoint p = {where.h, where.v};
if (TkMacOSXGrowToplevel(medPtr->whichWin, p) == true) {
statusPtr->stopProcessing = 1;
return true;
}
}
case inContent:
return GenerateButtonEvent(medPtr);
}
return false;
}
/*
*----------------------------------------------------------------------
*
* HandleWindowTitlebarMouseDown --
*
* Handle clicks in window titlebar.
*
* Results:
* 1 if event was handled, 0 if event was not handled, -1 if MouseDown
* was not in window titlebar.
*
* Side effects:
* Additional events may be place on the Tk event queue.
*
*----------------------------------------------------------------------
*/
int
HandleWindowTitlebarMouseDown(
MouseEventData *medPtr,
Tk_Window tkwin)
{
int result = INT_MAX;
switch (medPtr->windowPart) {
case inGoAway:
case inCollapseBox:
case inZoomIn:
case inZoomOut:
case inToolbarButton:
if (!IsWindowActive(medPtr->whichWin)) {
WindowRef frontWindow = FrontNonFloatingWindow();
WindowModality frontWindowModality = kWindowModalityNone;
if (frontWindow && frontWindow != medPtr->whichWin) {
ChkErr(GetWindowModality, frontWindow,
&frontWindowModality, NULL);
}
if (frontWindowModality == kWindowModalityAppModal) {
result = 0;
}
}
break;
default:
result = -1;
break;
}
if (result == INT_MAX) {
result = 0;
TkMacOSXTrackingLoop(1);
switch (medPtr->windowPart) {
case inGoAway:
if (TrackGoAway(medPtr->whichWin, medPtr->global) && tkwin) {
TkGenWMDestroyEvent(tkwin);
result = 1;
}
break;
case inCollapseBox:
if (TrackBox(medPtr->whichWin, medPtr->global,
medPtr->windowPart) && tkwin) {
TkpWmSetState((TkWindow *) tkwin, IconicState);
result = 1;
}
break;
case inZoomIn:
case inZoomOut:
if (TrackBox(medPtr->whichWin, medPtr->global,
medPtr->windowPart)) {
result = TkMacOSXZoomToplevel(medPtr->whichWin,
medPtr->windowPart);
}
break;
case inToolbarButton:
if (TrackBox(medPtr->whichWin, medPtr->global,
medPtr->windowPart)) {
result = GenerateToolbarButtonEvent(medPtr);
}
break;
}
TkMacOSXTrackingLoop(0);
}
return result;
}
/*
*----------------------------------------------------------------------
*
* GeneratePollingEvents --
*
* This function polls the mouse position and generates X Motion, Enter &
* Leave events. The cursor is also updated at this time.
*
* Results:
* True if event(s) are generated - false otherwise.
*
* Side effects:
* Additional events may be place on the Tk event queue. The cursor may
* be changed.
*
*----------------------------------------------------------------------
*/
static int
GeneratePollingEvents(
MouseEventData *medPtr)
{
Tk_Window tkwin, rootwin, grabWin;
int local_x, local_y;
TkDisplay *dispPtr;
grabWin = TkMacOSXGetCapture();
if ((!TkpIsWindowFloating(medPtr->whichWin)
&& (medPtr->activeNonFloating != medPtr->whichWin))) {
/*
* If the window for this event is not floating, and is not the active
* non-floating window, don't generate polling events. We don't send
* events to backgrounded windows. So either send it to the grabWin,
* or NULL if there is no grabWin.
*/
tkwin = grabWin;
} else {
/*
* First check whether the toplevel containing this mouse event is the
* grab window. If not, then send the event to the grab window.
* Otherwise, set tkWin to the subwindow which most closely contains
* the mouse event.
*/
dispPtr = TkGetDisplayList();
rootwin = Tk_IdToWindow(dispPtr->display, medPtr->window);
if ((rootwin == NULL)
|| ((grabWin != NULL) && (rootwin != grabWin))) {
tkwin = grabWin;
} else {
tkwin = Tk_TopCoordsToWindow(rootwin, medPtr->local.h,
medPtr->local.v, &local_x, &local_y);
}
}
/*
* The following call will generate the appropiate X events and adjust any
* state that Tk must remember.
*/
Tk_UpdatePointer(tkwin, medPtr->global.h, medPtr->global.v,
medPtr->state);
return true;
}
/*
*----------------------------------------------------------------------
*
* BringWindowForward --
*
* Bring this background window to the front.
*
* Results:
* None.
*
* Side effects:
* The window is brought forward.
*
*----------------------------------------------------------------------
*/
static void
BringWindowForward(
WindowRef wRef,
int isFrontProcess,
int frontWindowOnly)
{
if (wRef && !TkpIsWindowFloating(wRef) && IsValidWindowPtr(wRef)) {
WindowRef frontWindow = FrontNonFloatingWindow();
WindowModality frontWindowModality = kWindowModalityNone;
if (frontWindow && frontWindow != wRef) {
ChkErr(GetWindowModality, frontWindow, &frontWindowModality, NULL);
}
if (frontWindowModality != kWindowModalityAppModal) {
Window window = TkMacOSXGetXWindow(wRef);
if (window != None) {
TkDisplay *dispPtr = TkGetDisplayList();
TkWindow *winPtr = (TkWindow *)
Tk_IdToWindow(dispPtr->display, window);
if (winPtr && winPtr->wmInfoPtr &&
winPtr->wmInfoPtr->master != None) {
TkWindow *masterWinPtr = (TkWindow *)Tk_IdToWindow(
dispPtr->display, winPtr->wmInfoPtr->master);
if (masterWinPtr && masterWinPtr->window != None &&
TkMacOSXHostToplevelExists(masterWinPtr)) {
WindowRef masterMacWin =
TkMacOSXDrawableWindow(masterWinPtr->window);
if (masterMacWin) {
BringToFront(masterMacWin);
}
}
}
}
SelectWindow(wRef);
} else {
frontWindowOnly = 0;
}
}
if (!isFrontProcess) {
ProcessSerialNumber ourPsn = {0, kCurrentProcess};
ChkErr(SetFrontProcessWithOptions, &ourPsn,
frontWindowOnly ? kSetFrontProcessFrontWindowOnly : 0);
}
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXBringWindowForward --
*
* Bring this window to the front in response to a mouse click. If a grab
* is in effect, bring the grab window to the front instead.
*
* Results:
* None.
*
* Side effects:
* The window is brought forward.
*
*----------------------------------------------------------------------
*/
void
TkMacOSXBringWindowForward(
WindowRef wRef)
{
TkDisplay *dispPtr = TkGetDisplayList();
Tk_Window tkwin =
Tk_IdToWindow(dispPtr->display, TkMacOSXGetXWindow(wRef));
Tk_Window grabWin = GetGrabWindowForWindow(tkwin);
if (grabWin && grabWin != tkwin) {
wRef = TkMacOSXDrawableWindow(((TkWindow *) grabWin)->window);
}
TkMacOSXSetEatButtonUp(true);
BringWindowForward(wRef, Tk_MacOSXIsAppInFront(), !grabWin);
}
/*
*----------------------------------------------------------------------
*
* GetGrabWindowForWindow --
*
* Get the grab window for the given window, if any.
*
* Results:
* Grab Tk_Window or None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
Tk_Window
GetGrabWindowForWindow(
Tk_Window tkwin)
{
Tk_Window grabWin = TkMacOSXGetCapture();
if (!grabWin) {
int grabState = TkGrabState((TkWindow *) tkwin);
if (grabState != TK_GRAB_NONE && grabState != TK_GRAB_IN_TREE) {
grabWin = (Tk_Window) (((TkWindow *) tkwin)->dispPtr->grabWinPtr);
}
}
return grabWin;
}
/*
*----------------------------------------------------------------------
*
* GenerateMouseWheelEvent --
*
* Generates a "MouseWheel" Tk event.
*
* Results:
* None.
*
* Side effects:
* Places a mousewheel event on the event queue.
*
*----------------------------------------------------------------------
*/
static int
GenerateMouseWheelEvent(
MouseEventData *medPtr)
{
Tk_Window tkwin, rootwin;
TkDisplay *dispPtr;
TkWindow *winPtr;
XEvent xEvent;
dispPtr = TkGetDisplayList();
rootwin = Tk_IdToWindow(dispPtr->display, medPtr->window);
if (rootwin == NULL) {
tkwin = NULL;
} else {
tkwin = Tk_TopCoordsToWindow(rootwin, medPtr->local.h,
medPtr->local.v, &xEvent.xbutton.x, &xEvent.xbutton.y);
}
/*
* The following call will generate the appropiate X events and adjust any
* state that Tk must remember.
*/
if (!tkwin) {
tkwin = TkMacOSXGetCapture();
}
if (!tkwin) {
return false;
}
winPtr = (TkWindow *) tkwin;
xEvent.type = MouseWheelEvent;
xEvent.xkey.keycode = medPtr->delta;
xEvent.xbutton.x_root = medPtr->global.h;
xEvent.xbutton.y_root = medPtr->global.v;
xEvent.xbutton.state = medPtr->state;
xEvent.xany.serial = LastKnownRequestProcessed(winPtr->display);
xEvent.xany.send_event = false;
xEvent.xany.display = winPtr->display;
xEvent.xany.window = Tk_WindowId(winPtr);
Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
return true;
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXGetEatButtonUp --
*
* Results:
* Return the flag indicating if we need to eat the next mouse up event.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
TkMacOSXGetEatButtonUp(void)
{
return gEatButtonUp;
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXSetEatButtonUp --
*
* Results:
* None.
*
* Side effects:
* Sets the flag indicating if we need to eat the next mouse up event
*
*----------------------------------------------------------------------
*/
void
TkMacOSXSetEatButtonUp(
int f)
{
gEatButtonUp = f;
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXKeyModifiers --
*
* Returns the current state of the modifier keys.
*
* Results:
* An OS Modifier state.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
EventModifiers
TkMacOSXModifierState(void)
{
UInt32 keyModifiers;
int isFrontProcess = (GetCurrentEvent() && Tk_MacOSXIsAppInFront());
keyModifiers = isFrontProcess ? GetCurrentEventKeyModifiers() :
GetCurrentKeyModifiers();
return (EventModifiers) (keyModifiers & USHRT_MAX);
}
/*
*----------------------------------------------------------------------
*
* TkMacOSXButtonKeyState --
*
* Returns the current state of the button & modifier keys.
*
* Results:
* A bitwise inclusive OR of a subset of the following: Button1Mask,
* ShiftMask, LockMask, ControlMask, Mod*Mask.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
unsigned int
TkMacOSXButtonKeyState(void)
{
UInt32 buttonState = 0, keyModifiers;
int isFrontProcess = (GetCurrentEvent() && Tk_MacOSXIsAppInFront());
if (!TkMacOSXGetEatButtonUp()) {
buttonState = isFrontProcess ? GetCurrentEventButtonState() :
GetCurrentButtonState();
}
keyModifiers = isFrontProcess ? GetCurrentEventKeyModifiers() :
GetCurrentKeyModifiers();
return ButtonModifiers2State(buttonState, keyModifiers);
}
/*
*----------------------------------------------------------------------
*
* ButtonModifiers2State --
*
* Converts Carbon mouse button state and modifier values into a Tk
* button/modifier state.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static unsigned int
ButtonModifiers2State(
UInt32 buttonState,
UInt32 keyModifiers)
{
unsigned int state;
/*
* Tk supports at most 5 buttons.
*/
state = (buttonState & ((1<<5) - 1)) << 8;
if (keyModifiers & alphaLock) {
state |= LockMask;
}
if (keyModifiers & shiftKey) {
state |= ShiftMask;
}
if (keyModifiers & controlKey) {
state |= ControlMask;
}
if (keyModifiers & cmdKey) {
state |= Mod1Mask; /* command key */
}
if (keyModifiers & optionKey) {
state |= Mod2Mask; /* option key */
}
if (keyModifiers & kEventKeyModifierNumLockMask) {
state |= Mod3Mask;
}
if (keyModifiers & kEventKeyModifierFnMask) {
state |= Mod4Mask;
}
return state;
}
/*
*----------------------------------------------------------------------
*
* XQueryPointer --
*
* Check the current state of the mouse. This is not a complete
* implementation of this function. It only computes the root coordinates
* and the current mask.
*
* Results:
* Sets root_x_return, root_y_return, and mask_return. Returns true on
* success.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
Bool
XQueryPointer(
Display *display,
Window w,
Window *root_return,
Window *child_return,
int *root_x_return,
int *root_y_return,
int *win_x_return,
int *win_y_return,
unsigned int *mask_return)
{
int getGlobal = (root_x_return && root_y_return);
int getLocal = (win_x_return && win_y_return);
if (getGlobal || getLocal) {
Point where, local;
OSStatus err = noErr;
int gotMouseLoc = 0;
EventRef ev = GetCurrentEvent();
if (ev && getLocal) {
err = ChkErr(GetEventParameter, ev, kEventParamWindowMouseLocation,
typeQDPoint, NULL, sizeof(Point), NULL, &local);
gotMouseLoc = (err == noErr);
}
if (getGlobal || !gotMouseLoc) {
if (ev) {
err = ChkErr(GetEventParameter, ev, kEventParamMouseLocation,
typeQDPoint, NULL, sizeof(Point), NULL, &where);
}
if (!ev || err != noErr) {
GetGlobalMouse(&where);
}
}
if (getLocal) {
WindowRef whichWin;
if (ev) {
err = ChkErr(GetEventParameter, ev, kEventParamWindowRef,
typeWindowRef, NULL, sizeof(WindowRef), NULL,
&whichWin);
}
if (!ev || err != noErr) {
FindWindow(where, &whichWin);
}
if (gotMouseLoc) {
if (whichWin) {
Rect widths;
ChkErr(GetWindowStructureWidths, whichWin, &widths);
local.h -= widths.left;
local.v -= widths.top;
}
} else {
local = where;
if (whichWin) {
QDGlobalToLocalPoint(GetWindowPort(whichWin), &local);
}
}
}
if (getGlobal) {
*root_x_return = where.h;
*root_y_return = where.v;
}
if (getLocal) {
*win_x_return = local.h;
*win_y_return = local.v;
}
}
if (mask_return) {
*mask_return = TkMacOSXButtonKeyState();
}
return True;
}
/*
*----------------------------------------------------------------------
*
* TkGenerateButtonEventForXPointer --
*
* This procedure generates an X button event for the current pointer
* state as reported by XQueryPointer().
*
* Results:
* True if event(s) are generated - false otherwise.
*
* Side effects:
* Additional events may be place on the Tk event queue. Grab state may
* also change.
*
*----------------------------------------------------------------------
*/
MODULE_SCOPE int
TkGenerateButtonEventForXPointer(
Window window) /* X Window containing button event. */
{
MouseEventData med;
int global_x, global_y, local_x, local_y;
bzero(&med, sizeof(MouseEventData));
XQueryPointer(NULL, None, NULL, NULL, &global_x, &global_y,
&local_x, &local_y, &med.state);
med.global.h = global_x;
med.global.v = global_y;
med.local.h = local_x;
med.local.v = local_y;
med.window = window;
med.activeNonFloating = ActiveNonFloatingWindow();
return GenerateButtonEvent(&med);
}
/*
*----------------------------------------------------------------------
*
* TkGenerateButtonEvent --
*
* Given a global x & y position and the button key status this procedure
* generates the appropiate X button event. It also handles the state
* changes needed to implement implicit grabs.
*
* Results:
* True if event(s) are generated, false otherwise.
*
* Side effects:
* Additional events may be place on the Tk event queue. Grab state may
* also change.
*
*----------------------------------------------------------------------
*/
int
TkGenerateButtonEvent(
int x, /* X location of mouse, */
int y, /* Y location of mouse. */
Window window, /* X Window containing button event. */
unsigned int state) /* Button Key state suitable for X event. */
{
MouseEventData med;
bzero(&med, sizeof(MouseEventData));
med.state = state;
med.window = window;
med.global.h = x;
med.global.v = y;
FindWindow(med.global, &med.whichWin);
med.activeNonFloating = ActiveNonFloatingWindow();
med.local = med.global;
QDGlobalToLocalPoint(GetWindowPort(med.whichWin), &med.local);
return GenerateButtonEvent(&med);
}
/*
*----------------------------------------------------------------------
*
* GenerateButtonEvent --
*
* Generate an X button event from a MouseEventData structure. Handles
* the state changes needed to implement implicit grabs.
*
* Results:
* True if event(s) are generated - false otherwise.
*
* Side effects:
* Additional events may be place on the Tk event queue. Grab state may
* also change.
*
*----------------------------------------------------------------------
*/
static int
GenerateButtonEvent(
MouseEventData *medPtr)
{
Tk_Window tkwin;
int dummy;
TkDisplay *dispPtr;
#if UNUSED
/*
* ButtonDown events will always occur in the front window. ButtonUp
* events, however, may occur anywhere on the screen. ButtonUp events
* should only be sent to Tk if in the front window or during an implicit
* grab.
*/
if ((medPtr->activeNonFloating == NULL)
|| ((!(TkpIsWindowFloating(medPtr->whichWin))
&& (medPtr->activeNonFloating != medPtr->whichWin))
&& TkMacOSXGetCapture() == NULL)) {
return false;
}
#endif
dispPtr = TkGetDisplayList();
tkwin = Tk_IdToWindow(dispPtr->display, medPtr->window);
if (tkwin != NULL) {
tkwin = Tk_TopCoordsToWindow(tkwin, medPtr->local.h, medPtr->local.v,
&dummy, &dummy);
}
Tk_UpdatePointer(tkwin, medPtr->global.h, medPtr->global.v, medPtr->state);
return true;
}
/*
*----------------------------------------------------------------------
*
* GenerateToolbarButtonEvent --
*
* Generates a "ToolbarButton" virtual event. This can be used to manage
* disappearing toolbars.
*
* Results:
* None.
*
* Side effects:
* Places a virtual event on the event queue.
*
*----------------------------------------------------------------------
*/
static int
GenerateToolbarButtonEvent(
MouseEventData *medPtr)
{
Tk_Window rootwin, tkwin = NULL;
TkDisplay *dispPtr;
TkWindow *winPtr;
XVirtualEvent event;
dispPtr = TkGetDisplayList();
rootwin = Tk_IdToWindow(dispPtr->display, medPtr->window);
if (rootwin) {
tkwin = Tk_TopCoordsToWindow(rootwin,
medPtr->local.h, medPtr->local.v, &event.x, &event.y);
}
if (!tkwin) {
return true;
}
winPtr = (TkWindow *) tkwin;
bzero(&event, sizeof(XVirtualEvent));
event.type = VirtualEvent;
event.serial = LastKnownRequestProcessed(winPtr->display);
event.send_event = false;
event.display = winPtr->display;
event.event = winPtr->window;
event.root = XRootWindow(winPtr->display, 0);
event.subwindow = None;
event.time = TkpGetMS();
event.x_root = medPtr->global.h;
event.y_root = medPtr->global.v;
event.state = medPtr->state;
event.same_screen = true;
event.name = Tk_GetUid("ToolbarButton");
Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL);
return true;
}
void
TkpWarpPointer(
TkDisplay *dispPtr)
{
CGPoint pt;
UInt32 buttonState;
if (dispPtr->warpWindow) {
int x, y;
Tk_GetRootCoords(dispPtr->warpWindow, &x, &y);
pt.x = x + dispPtr->warpX;
pt.y = y + dispPtr->warpY;
} else {
pt.x = dispPtr->warpX;
pt.y = dispPtr->warpY;
}
/*
* Tell the OSX core to generate the events to make it happen. This is
* fairly ugly, but means that under most circumstances we'll register all
* the events that would normally be generated correctly. If we use
* CGWarpMouseCursorPosition instead, strange things happen.
*/
buttonState = (GetCurrentEvent() && Tk_MacOSXIsAppInFront())
? GetCurrentEventButtonState() : GetCurrentButtonState();
CGPostMouseEvent(pt, 1 /* generate motion events */, 5,
buttonState&1 ? 1 : 0, buttonState&2 ? 1 : 0,
buttonState&4 ? 1 : 0, buttonState&8 ? 1 : 0,
buttonState&16 ? 1 : 0);
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 79
* coding: utf-8
* End:
*/
Jump to Line
Something went wrong with that request. Please try again.