summaryrefslogtreecommitdiffstats
path: root/carbon/tkMacOSXMouseEvent.c
diff options
context:
space:
mode:
Diffstat (limited to 'carbon/tkMacOSXMouseEvent.c')
-rw-r--r--carbon/tkMacOSXMouseEvent.c1190
1 files changed, 1190 insertions, 0 deletions
diff --git a/carbon/tkMacOSXMouseEvent.c b/carbon/tkMacOSXMouseEvent.c
new file mode 100644
index 0000000..697e00d
--- /dev/null
+++ b/carbon/tkMacOSXMouseEvent.c
@@ -0,0 +1,1190 @@
+/*
+ * 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:
+ */