summaryrefslogtreecommitdiffstats
path: root/macosx/tkMacOSXMouseEvent.c
diff options
context:
space:
mode:
Diffstat (limited to 'macosx/tkMacOSXMouseEvent.c')
-rw-r--r--macosx/tkMacOSXMouseEvent.c704
1 files changed, 704 insertions, 0 deletions
diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c
new file mode 100644
index 0000000..769472c
--- /dev/null
+++ b/macosx/tkMacOSXMouseEvent.c
@@ -0,0 +1,704 @@
+/*
+ * tkMacOSXMouseEvent.c --
+ *
+ * This file implements functions that decode & handle mouse events
+ * on MacOS X.
+ *
+ * Copyright 2001, Apple Computer, Inc.
+ *
+ * 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 "tkInt.h"
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include "tkMacOSXEvent.h"
+#include "tkMacOSXInt.h"
+#include "tkPort.h"
+#include "tkMacOSXDebug.h"
+
+typedef struct {
+ WindowRef whichWin;
+ WindowRef activeNonFloating;
+ WindowPartCode windowPart;
+ Point global;
+ Point local;
+ unsigned int state;
+ long delta;
+} 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 _ANSI_ARGS_((WindowRef wRef));
+static int GeneratePollingEvents(MouseEventData * medPtr);
+static int GenerateMouseWheelEvent(MouseEventData * medPtr);
+
+extern int TkMacOSXGetEatButtonUp();
+extern 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.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TkMacOSXProcessMouseEvent(TkMacOSXEvent *eventPtr, MacEventStatus * statusPtr)
+{
+ WindowRef frontWindow;
+ Tk_Window tkwin;
+ Point where, where2;
+ int xOffset, yOffset;
+ TkDisplay * dispPtr;
+ Window window;
+ int status,err;
+ MouseEventData mouseEventData, * medPtr = &mouseEventData;
+ KeyMap keyMap;
+
+ switch (eventPtr->eKind) {
+ case kEventMouseUp:
+ case kEventMouseDown:
+ case kEventMouseMoved:
+ case kEventMouseDragged:
+ case kEventMouseWheelMoved:
+ break;
+ default:
+ statusPtr->handledByTk = 1;
+ return 0;
+ break;
+ }
+ statusPtr->handledByTk = 1;
+ status = GetEventParameter(eventPtr->eventRef,
+ kEventParamMouseLocation,
+ typeQDPoint, NULL,
+ sizeof(where), NULL,
+ &where);
+ if (status != noErr) {
+ fprintf (stderr, "Failed to retrieve mouse location,%d\n", status);
+ return 0;
+ }
+ medPtr->state = 0;
+ GetKeys(keyMap);
+ if (keyMap[1] & 2) {
+ medPtr->state |= LockMask;
+ }
+ if (keyMap[1] & 1) {
+ medPtr->state |= ShiftMask;
+ }
+ if (keyMap[1] & 8) {
+ medPtr->state |= ControlMask;
+ }
+ if (keyMap[1] & 32768) {
+ medPtr->state |= Mod1Mask; /* command key */
+ }
+ if (keyMap[1] & 4) {
+ medPtr->state |= Mod2Mask; /* option key */
+ }
+ if (eventPtr->eKind == kEventMouseDown
+ || eventPtr->eKind== kEventMouseDragged ) {
+ EventMouseButton mouseButton;
+ if ((status=GetEventParameter(eventPtr->eventRef,
+ kEventParamMouseButton,
+ typeMouseButton, NULL,
+ sizeof(mouseButton), NULL,&mouseButton)) != noErr ) {
+ fprintf (stderr, "Failed to retrieve mouse button, %d\n", status);
+ statusPtr->err = 1;
+ return 0;
+ }
+ medPtr->state |= 1 << ((mouseButton-1)+8);
+ }
+
+ medPtr->windowPart= FindWindow(where, &medPtr->whichWin);
+ window = TkMacOSXGetXWindow(medPtr->whichWin);
+ if (medPtr->whichWin != NULL && window == None) {
+ statusPtr->handledByTk = 0;
+ return 0;
+ }
+
+ frontWindow = FrontWindow();
+ medPtr->activeNonFloating = ActiveNonFloatingWindow();
+
+ /*
+ * 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 (eventPtr->eKind == kEventMouseUp) {
+ if (TkMacOSXGetEatButtonUp()) {
+ TkMacOSXSetEatButtonUp(false);
+ return false;
+ }
+ return TkGenerateButtonEvent(where.h, where.v,
+ window, medPtr->state);
+ }
+ if (eventPtr->eKind == kEventMouseWheelMoved) {
+ if ((status=GetEventParameter(eventPtr->eventRef,
+ kEventParamMouseWheelDelta,
+ typeLongInteger, NULL,
+ sizeof(medPtr->delta), NULL,&medPtr->delta)) != noErr ) {
+ fprintf (stderr,
+ "Failed to retrieve mouse wheel delta, %d\n", status);
+ statusPtr->err = 1;
+ return false;
+ }
+ }
+
+ dispPtr = TkGetDisplayList();
+ tkwin = Tk_IdToWindow(dispPtr->display, window);
+
+ if (eventPtr->eKind != kEventMouseDown ) {
+ /*
+ * MouseMoved, MouseDragged or kEventMouseWheelMoved
+ */
+
+ medPtr->global = where;
+ medPtr->local = where;
+ SetPortWindowPort(frontWindow);
+ GlobalToLocal(&medPtr->local);
+ if (eventPtr->eKind == kEventMouseWheelMoved ) {
+ return GenerateMouseWheelEvent(medPtr);
+ } else {
+ return GeneratePollingEvents(medPtr);
+ }
+ }
+
+ if (medPtr->whichWin && eventPtr->eKind==kEventMouseDown) {
+ ProcessSerialNumber frontPsn, ourPsn;
+ Boolean flag;
+ if ((err=GetFrontProcess(&frontPsn))!=noErr) {
+ fprintf(stderr, "GetFrontProcess failed, %d\n", err);
+ statusPtr->err = 1;
+ return 1;
+ }
+
+ GetCurrentProcess(&ourPsn);
+ if ((err=SameProcess(&frontPsn, &ourPsn, &flag))!=noErr) {
+ fprintf(stderr, "SameProcess failed, %d\n", err);
+ statusPtr->err = 1;
+ return 1;
+ } else {
+ if (!flag) {
+ if ((err=SetFrontProcess(&ourPsn)) != noErr) {
+ fprintf(stderr,"SetFrontProcess failed,%d\n", err);
+ statusPtr->err = 1;
+ return 1;
+ }
+ }
+ }
+
+ }
+
+ if (medPtr->whichWin) {
+ /*
+ * We got a mouse down in a window
+ * 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)) {
+ Tk_Window grabWin = TkMacOSXGetCapture();
+ if ((grabWin != NULL) && (grabWin != tkwin)) {
+ TkWindow * tkw, * grb;
+ tkw = (TkWindow *)tkwin;
+ grb = (TkWindow *)grabWin;
+ SysBeep(1);
+ return false;
+ }
+ TkMacOSXSetEatButtonUp(true);
+ BringWindowForward(medPtr->whichWin);
+ return false;
+ }
+ }
+
+ switch (medPtr->windowPart) {
+ case inDrag:
+ DragWindow(medPtr->whichWin, where, NULL);
+ where2.h = where2.v = 0;
+ LocalToGlobal(&where2);
+ if (EqualPt(where, where2)) {
+ return false;
+ }
+ TkMacOSXWindowOffset(medPtr->whichWin, &xOffset, &yOffset);
+ where2.h -= xOffset;
+ where2.v -= yOffset;
+ TkGenWMConfigureEvent(tkwin, where2.h, where2.v,
+ -1, -1, TK_LOCATION_CHANGED);
+ return true;
+ break;
+ case inContent:
+ return TkGenerateButtonEvent(where.h, where.v,
+ window, medPtr->state);
+ 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!
+ */
+ if (TkMacOSXGrowToplevel(medPtr->whichWin, where) == true) {
+ return true;
+ } else {
+ return TkGenerateButtonEvent(where.h,
+ where.v, window, medPtr->state);
+ }
+ break;
+ case inGoAway:
+ if (TrackGoAway(medPtr->whichWin,where)) {
+ if (tkwin == NULL) {
+ return false;
+ }
+ TkGenWMDestroyEvent(tkwin);
+ return true;
+ }
+ return false;
+ break;
+ case inMenuBar:
+ {
+ int oldMode;
+ KeyMap theKeys;
+
+ GetKeys(theKeys);
+ oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
+ TkMacOSXClearMenubarActive();
+
+ /*
+ * Handle -postcommand
+ */
+
+ TkMacOSXPreprocessMenu();
+ TkMacOSXHandleMenuSelect(MenuSelect(where),
+ theKeys[1] & 4);
+ Tcl_SetServiceMode(oldMode);
+ return true; /* TODO: may not be on event on queue. */
+ }
+ break;
+ case inZoomIn:
+ case inZoomOut:
+ if (TkMacOSXZoomToplevel(medPtr->whichWin, where,
+ medPtr->windowPart) == true) {
+ return true;
+ } else {
+ return false;
+ }
+ break;
+ case inCollapseBox:
+ if ((err = CollapseWindow(medPtr->whichWin,
+ !IsWindowCollapsed(medPtr->whichWin)))!=noErr) {
+ fprintf(stderr,"CollapseWindow failed,%d\n", err);
+ statusPtr->err = 1;
+ }
+ break;
+ default:
+ return false;
+ break;
+ }
+ return 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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;
+ Window window;
+ int local_x, local_y;
+ TkDisplay *dispPtr;
+
+
+ if ((!TkpIsWindowFloating(medPtr->whichWin)
+ && (medPtr->activeNonFloating != medPtr->whichWin))) {
+ tkwin = NULL;
+ } else {
+ window = TkMacOSXGetXWindow(medPtr->whichWin);
+ dispPtr = TkGetDisplayList();
+ rootwin = Tk_IdToWindow(dispPtr->display, window);
+ if (rootwin == NULL) {
+ tkwin = NULL;
+ } 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.
+ */
+
+ grabWin = TkMacOSXGetCapture();
+
+ if ((tkwin == NULL) && (grabWin != NULL)) {
+ tkwin = grabWin;
+ }
+ Tk_UpdatePointer(tkwin, medPtr->global.h, medPtr->global.v,
+ medPtr->state);
+
+
+ TkMacOSXInstallCursor(0);
+
+ return true;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * BringWindowForward --
+ *
+ * Bring this background window to the front. We also set state
+ * so Tk thinks the button is currently up.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The window is brought forward.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+BringWindowForward(WindowRef wRef)
+{
+ if (!TkpIsWindowFloating(wRef)) {
+ if (IsValidWindowPtr(wRef))
+ SelectWindow(wRef);
+ }
+}
+
+static int
+GenerateMouseWheelEvent(MouseEventData * medPtr)
+{
+ Tk_Window tkwin, rootwin, grabWin;
+ Window window;
+ int local_x, local_y;
+ TkDisplay *dispPtr;
+ TkWindow *winPtr;
+ XEvent xEvent;
+
+ if ((!TkpIsWindowFloating(medPtr->whichWin)
+ && (medPtr->activeNonFloating != medPtr->whichWin))) {
+ tkwin = NULL;
+ } else {
+ window = TkMacOSXGetXWindow(medPtr->whichWin);
+ dispPtr = TkGetDisplayList();
+ rootwin = Tk_IdToWindow(dispPtr->display, window);
+ if (rootwin == NULL) {
+ tkwin = NULL;
+ } 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.
+ */
+
+ grabWin = TkMacOSXGetCapture();
+
+ if ((tkwin == NULL) && (grabWin != NULL)) {
+ tkwin = grabWin;
+ }
+ if (!tkwin) {
+ return true;
+ }
+ winPtr = ( TkWindow *)tkwin;
+ xEvent.type = MouseWheelEvent;
+ xEvent.xkey.keycode = medPtr->delta;
+ 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:
+ * Returns the flag indicating if we need to eat the
+ * next mouse up event
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+int
+TkMacOSXGetEatButtonUp()
+{
+ 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;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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,
+ * Mod?Mask.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+unsigned int
+TkMacOSXButtonKeyState()
+{
+ unsigned int state = 0;
+ KeyMap theKeys;
+
+ if (Button() & !gEatButtonUp) {
+ state |= Button1Mask;
+ }
+
+ GetKeys(theKeys);
+
+ if (theKeys[1] & 2) {
+ state |= LockMask;
+ }
+
+ if (theKeys[1] & 1) {
+ state |= ShiftMask;
+ }
+
+ if (theKeys[1] & 8) {
+ state |= ControlMask;
+ }
+
+ if (theKeys[1] & 32768) {
+ state |= Mod1Mask; /* command key */
+ }
+
+ if (theKeys[1] & 4) {
+ state |= Mod2Mask; /* option key */
+ }
+
+ 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)
+{
+ Point where;
+ CGrafPtr port;
+ GDHandle dev;
+
+ GetGWorld(&port,&dev);
+ GetMouse(&where);
+ LocalToGlobal(&where);
+
+ *root_x_return = where.h;
+ *root_y_return = where.v;
+ *mask_return = TkMacOSXButtonKeyState();
+ return True;
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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 */
+{
+ WindowRef whichWin, frontWin;
+ Point where;
+ Tk_Window tkwin;
+ int dummy;
+ TkDisplay *dispPtr;
+
+ /*
+ * 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.
+ */
+
+ where.h = x;
+ where.v = y;
+ FindWindow(where, &whichWin);
+ frontWin = FrontNonFloatingWindow();
+
+ if ((frontWin == NULL) || ((!(TkpIsWindowFloating(whichWin))
+ && (frontWin != whichWin))
+ && TkMacOSXGetCapture() == NULL)) {
+ return false;
+ }
+
+ dispPtr = TkGetDisplayList();
+ tkwin = Tk_IdToWindow(dispPtr->display, window);
+
+ GlobalToLocal(&where);
+ if (tkwin != NULL) {
+ tkwin = Tk_TopCoordsToWindow(tkwin, where.h, where.v,
+ &dummy, &dummy);
+ }
+
+ Tk_UpdatePointer(tkwin, x, y, state);
+
+ return true;
+} \ No newline at end of file