diff options
author | rjohnson <rjohnson> | 1998-04-01 09:51:44 (GMT) |
---|---|---|
committer | rjohnson <rjohnson> | 1998-04-01 09:51:44 (GMT) |
commit | 066ea7fd88d49cb456f74da71dbe875e4fc0aabb (patch) | |
tree | 8fb30cb152c4dc191be47fa043d2e6f5ea38c7ba /mac/tkMacWindowMgr.c | |
parent | 13242623d2ff3ea02ab6a62bfb48a7dbb5c27e22 (diff) | |
download | tk-066ea7fd88d49cb456f74da71dbe875e4fc0aabb.zip tk-066ea7fd88d49cb456f74da71dbe875e4fc0aabb.tar.gz tk-066ea7fd88d49cb456f74da71dbe875e4fc0aabb.tar.bz2 |
Initial revision
Diffstat (limited to 'mac/tkMacWindowMgr.c')
-rw-r--r-- | mac/tkMacWindowMgr.c | 1591 |
1 files changed, 1591 insertions, 0 deletions
diff --git a/mac/tkMacWindowMgr.c b/mac/tkMacWindowMgr.c new file mode 100644 index 0000000..7c8206c --- /dev/null +++ b/mac/tkMacWindowMgr.c @@ -0,0 +1,1591 @@ +/* + * tkMacWindowMgr.c -- + * + * Implements common window manager functions for the Macintosh. + * + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkMacWindowMgr.c 1.59 97/11/20 18:56:39 + */ + +#include <Events.h> +#include <Dialogs.h> +#include <EPPC.h> +#include <Windows.h> +#include <ToolUtils.h> +#include <DiskInit.h> +#include <LowMem.h> +#include <Timer.h> +#include <Sound.h> + +#include "tkInt.h" +#include "tkPort.h" +#include "tkMacInt.h" + +#define TK_DEFAULT_ABOUT 128 + +/* + * Declarations of global variables defined in this file. + */ + +int tkMacAppInFront = true; /* Boolean variable for determining + * if we are the frontmost app. */ + +/* + * Non-standard event types that can be passed to HandleEvent. + * These are defined and used by Netscape's plugin architecture. + */ +#define getFocusEvent (osEvt + 16) +#define loseFocusEvent (osEvt + 17) +#define adjustCursorEvent (osEvt + 18) + +/* + * Declarations of static variables used in this file. + */ + +static int gEatButtonUp = 0; /* 1 if we need to eat the next + * up event */ +static Tk_Window gGrabWinPtr = NULL; /* Current grab window, NULL if no grab. */ +static Tk_Window gKeyboardWinPtr = NULL; /* Current keyboard grab window. */ +static RgnHandle gDamageRgn = NULL; /* Damage region used for handling + * screen updates. */ +/* + * Forward declarations of procedures used in this file. + */ + +static void BringWindowForward _ANSI_ARGS_((WindowRef wRef)); +static int CheckEventsAvail _ANSI_ARGS_((void)); +static int GenerateActivateEvents _ANSI_ARGS_((EventRecord *eventPtr, + Window window)); +static int GenerateFocusEvent _ANSI_ARGS_((EventRecord *eventPtr, + Window window)); +static int GenerateKeyEvent _ANSI_ARGS_((EventRecord *eventPtr, + Window window)); +static int GenerateUpdateEvent _ANSI_ARGS_((EventRecord *eventPtr, + Window window)); +static void GenerateUpdates _ANSI_ARGS_((RgnHandle updateRgn, + TkWindow *winPtr)); +static int GeneratePollingEvents _ANSI_ARGS_((void)); +static int GeneratePollingEvents2 _ANSI_ARGS_((Window window)); +static OSErr TellWindowDefProcToCalcRegions _ANSI_ARGS_((WindowRef wRef)); +static int WindowManagerMouse _ANSI_ARGS_((EventRecord *theEvent, + Window window)); + + +/* + *---------------------------------------------------------------------- + * + * WindowManagerMouse -- + * + * This function determines if a button event is a "Window Manager" + * function or an event that should be passed to Tk's event + * queue. + * + * Results: + * Return true if event was placed on Tk's event queue. + * + * Side effects: + * Depends on where the button event occurs. + * + *---------------------------------------------------------------------- + */ + +static int +WindowManagerMouse( + EventRecord *eventPtr, /* Macintosh event record. */ + Window window) /* Window pointer. */ +{ + WindowRef whichWindow, frontWindow; + Tk_Window tkwin; + Point where, where2; + int xOffset, yOffset; + short windowPart; + + frontWindow = FrontWindow(); + + /* + * 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->what == mouseUp) { + if (gEatButtonUp) { + gEatButtonUp = false; + return false; + } + return TkGenerateButtonEvent(eventPtr->where.h, eventPtr->where.v, + window, TkMacButtonKeyState()); + } + + windowPart = FindWindow(eventPtr->where, &whichWindow); + tkwin = Tk_IdToWindow(tkDisplayList->display, window); + switch (windowPart) { + case inSysWindow: + SystemClick(eventPtr, (GrafPort *) whichWindow); + return false; + case inDrag: + if (whichWindow != frontWindow) { + if (!(eventPtr->modifiers & cmdKey)) { + if ((gGrabWinPtr != NULL) && (gGrabWinPtr != tkwin)) { + SysBeep(1); + return false; + } + } + } + + /* + * Call DragWindow to move the window around. It will + * also eat the mouse up event. + */ + SetPort((GrafPort *) whichWindow); + where.h = where.v = 0; + LocalToGlobal(&where); + DragWindow(whichWindow, eventPtr->where, + &tcl_macQdPtr->screenBits.bounds); + gEatButtonUp = false; + + where2.h = where2.v = 0; + LocalToGlobal(&where2); + if (EqualPt(where, where2)) { + return false; + } + + TkMacWindowOffset(whichWindow, &xOffset, &yOffset); + where2.h -= xOffset; + where2.v -= yOffset; + TkGenWMConfigureEvent(tkwin, where2.h, where2.v, + -1, -1, TK_LOCATION_CHANGED); + return true; + case inGrow: + case inContent: + if (whichWindow != frontWindow ) { + /* + * This click moves the window forward. We don't want + * the corasponding mouse-up to be reported to the application + * or else it will mess up some Tk scripts. + */ + if ((gGrabWinPtr != NULL) && (gGrabWinPtr != tkwin)) { + SysBeep(1); + return false; + } + BringWindowForward(whichWindow); + gEatButtonUp = true; + SetPort((GrafPort *) whichWindow); + return false; + } else { + /* + * 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 (TkMacGrowToplevel(whichWindow, eventPtr->where) == true) { + return true; + } else { + return TkGenerateButtonEvent(eventPtr->where.h, + eventPtr->where.v, window, TkMacButtonKeyState()); + } + } + case inGoAway: + if (TrackGoAway( whichWindow, eventPtr->where)) { + if (tkwin == NULL) { + return false; + } + TkGenWMDestroyEvent(tkwin); + return true; + } + return false; + case inMenuBar: + { + int oldMode; + KeyMap theKeys; + + GetKeys(theKeys); + oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); + TkMacClearMenubarActive(); + TkMacHandleMenuSelect(MenuSelect(eventPtr->where), + theKeys[1] & 4); + Tcl_SetServiceMode(oldMode); + return true; /* TODO: may not be on event on queue. */ + } + case inZoomIn: + case inZoomOut: + if (TkMacZoomToplevel(whichWindow, eventPtr->where, windowPart) + == true) { + return true; + } else { + return false; + } + default: + return false; + } +} + +/* + *---------------------------------------------------------------------- + * + * TkAboutDlg -- + * + * Displays the default Tk About box. This code uses Macintosh + * resources to define the content of the About Box. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkAboutDlg() +{ + DialogPtr aboutDlog; + short itemHit = -9; + + aboutDlog = GetNewDialog(128, NULL, (void*)(-1)); + + if (!aboutDlog) { + return; + } + + SelectWindow((WindowRef) aboutDlog); + + while (itemHit != 1) { + ModalDialog( NULL, &itemHit); + } + DisposDialog(aboutDlog); + aboutDlog = NULL; + + SelectWindow(FrontWindow()); + + return; +} + +/* + *---------------------------------------------------------------------- + * + * GenerateUpdateEvent -- + * + * Given a Macintosh update event this function generates all the + * X update events needed by Tk. + * + * Results: + * True if event(s) are generated - false otherwise. + * + * Side effects: + * Additional events may be place on the Tk event queue. + * + *---------------------------------------------------------------------- + */ + +static int +GenerateUpdateEvent( + EventRecord *eventPtr, /* Incoming Mac event */ + Window window) /* Root X window for event. */ +{ + WindowRef macWindow; + register TkWindow *winPtr; + + winPtr = (TkWindow *) Tk_IdToWindow(tkDisplayList->display, window); + + if (winPtr == NULL) { + return false; + } + + if (gDamageRgn == NULL) { + gDamageRgn = NewRgn(); + } + + /* + * After the call to BeginUpdate the visable region (visRgn) of the + * window is equal to the intersection of the real visable region and + * the update region for this event. We use this region in all of our + * calculations. + */ + + if (eventPtr->message != NULL) { + macWindow = (WindowRef) TkMacGetDrawablePort(window); + BeginUpdate(macWindow); + GenerateUpdates(macWindow->visRgn, winPtr); + EndUpdate(macWindow); + return true; + } else { + /* + * This event didn't come from the system. This might + * occur if we are running from inside of Netscape. + * In this we shouldn't call BeginUpdate as the vis region + * may be NULL. + */ + RgnHandle rgn; + Rect bounds; + + rgn = NewRgn(); + TkMacWinBounds(winPtr, &bounds); + RectRgn(rgn, &bounds); + GenerateUpdates(rgn, winPtr); + DisposeRgn(rgn); + return true; + } +} + +/* + *---------------------------------------------------------------------- + * + * GenerateUpdates -- + * + * Given a Macintosh update region and a Tk window this function + * geneates a X damage event for the window if it is within the + * update region. The function will then recursivly have each + * damaged window generate damage events for its child windows. + * + * Results: + * None. + * + * Side effects: + * Additional events may be place on the Tk event queue. + * + *---------------------------------------------------------------------- + */ + +static void +GenerateUpdates( + RgnHandle updateRgn, + TkWindow *winPtr) +{ + TkWindow *childPtr; + XEvent event; + Rect bounds; + + TkMacWinBounds(winPtr, &bounds); + + if (bounds.top > (*updateRgn)->rgnBBox.bottom || + (*updateRgn)->rgnBBox.top > bounds.bottom || + bounds.left > (*updateRgn)->rgnBBox.right || + (*updateRgn)->rgnBBox.left > bounds.right || + !RectInRgn(&bounds, updateRgn)) { + return; + } + + event.xany.serial = Tk_Display(winPtr)->request; + event.xany.send_event = false; + event.xany.window = Tk_WindowId(winPtr); + event.xany.display = Tk_Display(winPtr); + + event.type = Expose; + + /* + * Compute the bounding box of the area that the damage occured in. + */ + + /* + * CopyRgn(TkMacVisableClipRgn(winPtr), rgn); + * TODO: this call doesn't work doing resizes!!! + */ + RectRgn(gDamageRgn, &bounds); + SectRgn(gDamageRgn, updateRgn, gDamageRgn); + OffsetRgn(gDamageRgn, -bounds.left, -bounds.top); + event.xexpose.x = (**gDamageRgn).rgnBBox.left; + event.xexpose.y = (**gDamageRgn).rgnBBox.top; + event.xexpose.width = (**gDamageRgn).rgnBBox.right - + (**gDamageRgn).rgnBBox.left; + event.xexpose.height = (**gDamageRgn).rgnBBox.bottom - + (**gDamageRgn).rgnBBox.top; + event.xexpose.count = 0; + + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + + /* + * Generate updates for the children of this window + */ + + for (childPtr = winPtr->childList; childPtr != NULL; + childPtr = childPtr->nextPtr) { + if (!Tk_IsMapped(childPtr) || Tk_IsTopLevel(childPtr)) { + continue; + } + + GenerateUpdates(updateRgn, childPtr); + } + + /* + * Generate updates for any contained windows + */ + + if (Tk_IsContainer(winPtr)) { + childPtr = TkpGetOtherWindow(winPtr); + if (childPtr != NULL && Tk_IsMapped(childPtr)) { + GenerateUpdates(updateRgn, childPtr); + } + + /* + * NOTE: Here we should handle out of process embedding. + */ + + } + + return; +} + +/* + *---------------------------------------------------------------------- + * + * 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; + + /* + * 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 = FrontWindow(); + + if ((frontWin == NULL) || (frontWin != whichWin && gGrabWinPtr == NULL)) { + return false; + } + + tkwin = Tk_IdToWindow(tkDisplayList->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; +} + +/* + *---------------------------------------------------------------------- + * + * GenerateActivateEvents -- + * + * Generate Activate/Deactivate events from a Macintosh Activate + * event. Note, the activate-on-foreground bit must be set in the + * SIZE flags to ensure we get Activate/Deactivate in addition to + * Susspend/Resume events. + * + * Results: + * Returns true if events were generate. + * + * Side effects: + * Queue events on Tk's event queue. + * + *---------------------------------------------------------------------- + */ + +static int +GenerateActivateEvents( + EventRecord *eventPtr, /* Incoming Mac event */ + Window window) /* Root X window for event. */ +{ + TkWindow *winPtr; + + winPtr = (TkWindow *) Tk_IdToWindow(tkDisplayList->display, window); + if (winPtr == NULL || winPtr->window == None) { + return false; + } + + TkGenerateActivateEvents(winPtr, + (eventPtr->modifiers & activeFlag) ? 1 : 0); + return true; +} + +/* + *---------------------------------------------------------------------- + * + * XSetInputFocus -- + * + * Change the focus window for the application. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +XSetInputFocus( + Display* display, + Window focus, + int revert_to, + Time time) +{ + /* + * Don't need to do a thing. Tk manages the focus for us. + */ +} + +/* + *---------------------------------------------------------------------- + * + * TkpChangeFocus -- + * + * This procedure is a stub on the Mac because we always own the + * focus if we are a front most application. + * + * Results: + * The return value is the serial number of the command that + * changed the focus. It may be needed by the caller to filter + * out focus change events that were queued before the command. + * If the procedure doesn't actually change the focus then + * it returns 0. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TkpChangeFocus(winPtr, force) + TkWindow *winPtr; /* Window that is to receive the X focus. */ + int force; /* Non-zero means claim the focus even + * if it didn't originally belong to + * topLevelPtr's application. */ +{ + /* + * We don't really need to do anything on the Mac. Tk will + * keep all this state for us. + */ + + if (winPtr->atts.override_redirect) { + return 0; + } + + /* + * Remember the current serial number for the X server and issue + * a dummy server request. This marks the position at which we + * changed the focus, so we can distinguish FocusIn and FocusOut + * events on either side of the mark. + */ + + return NextRequest(winPtr->display); +} + +/* + *---------------------------------------------------------------------- + * + * GenerateFocusEvent -- + * + * Generate FocusIn/FocusOut events from a Macintosh Activate + * event. Note, the activate-on-foreground bit must be set in + * the SIZE flags to ensure we get Activate/Deactivate in addition + * to Susspend/Resume events. + * + * Results: + * Returns true if events were generate. + * + * Side effects: + * Queue events on Tk's event queue. + * + *---------------------------------------------------------------------- + */ + +static int +GenerateFocusEvent( + EventRecord *eventPtr, /* Incoming Mac event */ + Window window) /* Root X window for event. */ +{ + XEvent event; + Tk_Window tkwin; + + tkwin = Tk_IdToWindow(tkDisplayList->display, window); + if (tkwin == NULL) { + return false; + } + + /* + * Generate FocusIn and FocusOut events. This event + * is only sent to the toplevel window. + */ + + if (eventPtr->modifiers & activeFlag) { + event.xany.type = FocusIn; + } else { + event.xany.type = FocusOut; + } + + event.xany.serial = tkDisplayList->display->request; + event.xany.send_event = False; + event.xfocus.display = tkDisplayList->display; + event.xfocus.window = window; + event.xfocus.mode = NotifyNormal; + event.xfocus.detail = NotifyDetailNone; + + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + return true; +} + +/* + *---------------------------------------------------------------------- + * + * GenerateKeyEvent -- + * + * Given Macintosh keyUp, keyDown & autoKey events this function + * generates the appropiate X key events. The window that is passed + * should represent the frontmost window - which will recieve the + * event. + * + * Results: + * True if event(s) are generated - false otherwise. + * + * Side effects: + * Additional events may be place on the Tk event queue. + * + *---------------------------------------------------------------------- + */ + +static int +GenerateKeyEvent( + EventRecord *eventPtr, /* Incoming Mac event */ + Window window) /* Root X window for event. */ +{ + Point where; + Tk_Window tkwin; + XEvent event; + + /* + * The focus must be in the FrontWindow on the Macintosh. + * We then query Tk to determine the exact Tk window + * that owns the focus. + */ + + tkwin = Tk_IdToWindow(tkDisplayList->display, window); + tkwin = (Tk_Window) ((TkWindow *) tkwin)->dispPtr->focusPtr; + if (tkwin == NULL) { + return false; + } + + where.v = eventPtr->where.v; + where.h = eventPtr->where.h; + + event.xany.send_event = False; + event.xkey.same_screen = true; + event.xkey.subwindow = None; + event.xkey.time = TkpGetMS(); + + event.xkey.x_root = where.h; + event.xkey.y_root = where.v; + GlobalToLocal(&where); + Tk_TopCoordsToWindow(tkwin, where.h, where.v, + &event.xkey.x, &event.xkey.y); + event.xkey.keycode = eventPtr->message; + + event.xany.serial = Tk_Display(tkwin)->request; + event.xkey.window = Tk_WindowId(tkwin); + event.xkey.display = Tk_Display(tkwin); + event.xkey.root = XRootWindow(Tk_Display(tkwin), 0); + event.xkey.state = TkMacButtonKeyState(); + + if (eventPtr->what == keyDown) { + event.xany.type = KeyPress; + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + } else if (eventPtr->what == keyUp) { + event.xany.type = KeyRelease; + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + } else { + /* + * Autokey events send multiple XKey events. + * + * Note: the last KeyRelease will always be missed with + * this scheme. However, most Tk scripts don't look for + * KeyUp events so we should be OK. + */ + event.xany.type = KeyRelease; + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + event.xany.type = KeyPress; + Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL); + } + return true; +} + +/* + *---------------------------------------------------------------------- + * + * 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() +{ + Tk_Window tkwin, rootwin; + Window window; + WindowRef whichwindow, frontWin; + Point whereLocal, whereGlobal; + Boolean inContentRgn; + short part; + int local_x, local_y; + int generatedEvents = false; + + /* + * First we get the current mouse position and determine + * what Tk window the mouse is over (if any). + */ + frontWin = FrontWindow(); + if (frontWin == NULL) { + return false; + } + SetPort((GrafPort *) frontWin); + + GetMouse(&whereLocal); + whereGlobal = whereLocal; + LocalToGlobal(&whereGlobal); + + part = FindWindow(whereGlobal, &whichwindow); + inContentRgn = (part == inContent || part == inGrow); + + if ((frontWin != whichwindow) || !inContentRgn) { + tkwin = NULL; + } else { + window = TkMacGetXWindow(whichwindow); + rootwin = Tk_IdToWindow(tkDisplayList->display, window); + if (rootwin == NULL) { + tkwin = NULL; + } else { + tkwin = Tk_TopCoordsToWindow(rootwin, whereLocal.h, whereLocal.v, + &local_x, &local_y); + } + } + + /* + * The following call will generate the appropiate X events and + * adjust any state that Tk must remember. + */ + + if ((tkwin == NULL) && (gGrabWinPtr != NULL)) { + tkwin = gGrabWinPtr; + } + Tk_UpdatePointer(tkwin, whereGlobal.h, whereGlobal.v, + TkMacButtonKeyState()); + + /* + * Finally, we make sure the proper cursor is installed. The installation + * is polled to 1) make our resize hack work, and 2) make sure we have the + * proper cursor even if someone else changed the cursor out from under + * us. + */ + if ((gGrabWinPtr == NULL) && (part == inGrow) && + TkMacResizable((TkWindow *) tkwin) && + (TkMacGetScrollbarGrowWindow((TkWindow *) tkwin) == NULL)) { + TkMacInstallCursor(1); + } else { + TkMacInstallCursor(0); + } + + return true; +} + +/* + *---------------------------------------------------------------------- + * + * GeneratePollingEvents2 -- + * + * This function polls the mouse position and generates X Motion, + * Enter & Leave events. The cursor is also updated at this + * time. NOTE: this version is for Netscape!!! + * + * 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 +GeneratePollingEvents2( + Window window) +{ + Tk_Window tkwin, rootwin; + WindowRef whichwindow, frontWin; + Point whereLocal, whereGlobal; + int local_x, local_y; + int generatedEvents = false; + Rect bounds; + + /* + * First we get the current mouse position and determine + * what Tk window the mouse is over (if any). + */ + frontWin = FrontWindow(); + if (frontWin == NULL) { + return false; + } + SetPort((GrafPort *) frontWin); + + GetMouse(&whereLocal); + whereGlobal = whereLocal; + LocalToGlobal(&whereGlobal); + + /* + * Determine if we are in a Tk window or not. + */ + whichwindow = (WindowRef) TkMacGetDrawablePort(window); + if (whichwindow != frontWin) { + tkwin = NULL; + } else { + rootwin = Tk_IdToWindow(tkDisplayList->display, window); + TkMacWinBounds((TkWindow *) rootwin, &bounds); + if (!PtInRect(whereLocal, &bounds)) { + tkwin = NULL; + } else { + tkwin = Tk_TopCoordsToWindow(rootwin, whereLocal.h, whereLocal.v, + &local_x, &local_y); + } + } + + /* + * The following call will generate the appropiate X events and + * adjust any state that Tk must remember. + */ + + if ((tkwin == NULL) && (gGrabWinPtr != NULL)) { + tkwin = gGrabWinPtr; + } + Tk_UpdatePointer(tkwin, whereGlobal.h, whereGlobal.v, + TkMacButtonKeyState()); + + /* + * Finally, we make sure the proper cursor is installed. The installation + * is polled to 1) make our resize hack work, and 2) make sure we have the + * proper cursor even if someone else changed the cursor out from under + * us. + */ + TkMacInstallCursor(0); + + return true; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacButtonKeyState -- + * + * 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 +TkMacButtonKeyState() +{ + 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; +} + +/* + *---------------------------------------------------------------------- + * + * XGrabKeyboard -- + * + * Simulates a keyboard grab by setting the focus. + * + * Results: + * Always returns GrabSuccess. + * + * Side effects: + * Sets the keyboard focus to the specified window. + * + *---------------------------------------------------------------------- + */ + +int +XGrabKeyboard( + Display* display, + Window grab_window, + Bool owner_events, + int pointer_mode, + int keyboard_mode, + Time time) +{ + gKeyboardWinPtr = Tk_IdToWindow(display, grab_window); + return GrabSuccess; +} + +/* + *---------------------------------------------------------------------- + * + * XUngrabKeyboard -- + * + * Releases the simulated keyboard grab. + * + * Results: + * None. + * + * Side effects: + * Sets the keyboard focus back to the value before the grab. + * + *---------------------------------------------------------------------- + */ + +void +XUngrabKeyboard( + Display* display, + Time time) +{ + gKeyboardWinPtr = NULL; +} + +/* + *---------------------------------------------------------------------- + * + * 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; + + GetMouse(&where); + LocalToGlobal(&where); + *root_x_return = where.h; + *root_y_return = where.v; + *mask_return = TkMacButtonKeyState(); + return True; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacGenerateTime -- + * + * Returns the total number of ticks from startup This function + * is used to generate the time of generated X events. + * + * Results: + * Returns the current time (ticks from startup). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +Time +TkMacGenerateTime() +{ + return (Time) LMGetTicks(); +} + +/* + *---------------------------------------------------------------------- + * + * TkMacConvertEvent -- + * + * This function converts a Macintosh event into zero or more + * Tcl events. + * + * Results: + * Returns 1 if event added to Tcl queue, 0 otherwse. + * + * Side effects: + * May add events to Tcl's event queue. + * + *---------------------------------------------------------------------- + */ + +int +TkMacConvertEvent( + EventRecord *eventPtr) +{ + WindowRef whichWindow; + Window window; + int eventFound = false; + + switch (eventPtr->what) { + case nullEvent: + case adjustCursorEvent: + if (GeneratePollingEvents()) { + eventFound = true; + } + break; + case updateEvt: + whichWindow = (WindowRef)eventPtr->message; + window = TkMacGetXWindow(whichWindow); + if (GenerateUpdateEvent(eventPtr, window)) { + eventFound = true; + } + break; + case mouseDown: + case mouseUp: + FindWindow(eventPtr->where, &whichWindow); + window = TkMacGetXWindow(whichWindow); + if (WindowManagerMouse(eventPtr, window)) { + eventFound = true; + } + break; + case autoKey: + case keyDown: + /* + * Handle menu-key events here. If it is *not* + * a menu key - just fall through to handle as a + * normal key event. + */ + if ((eventPtr->modifiers & cmdKey) == cmdKey) { + long menuResult; + int oldMode; + + oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL); + menuResult = MenuKey(eventPtr->message & charCodeMask); + Tcl_SetServiceMode(oldMode); + + if (HiWord(menuResult) != 0) { + TkMacHandleMenuSelect(menuResult, false); + break; + } + } + case keyUp: + whichWindow = FrontWindow(); + window = TkMacGetXWindow(whichWindow); + eventFound |= GenerateKeyEvent(eventPtr, window); + break; + case activateEvt: + window = TkMacGetXWindow((WindowRef) eventPtr->message); + eventFound |= GenerateActivateEvents(eventPtr, window); + eventFound |= GenerateFocusEvent(eventPtr, window); + break; + case getFocusEvent: + eventPtr->modifiers |= activeFlag; + window = TkMacGetXWindow((WindowRef) eventPtr->message); + eventFound |= GenerateFocusEvent(eventPtr, window); + break; + case loseFocusEvent: + eventPtr->modifiers &= ~activeFlag; + window = TkMacGetXWindow((WindowRef) eventPtr->message); + eventFound |= GenerateFocusEvent(eventPtr, window); + break; + case kHighLevelEvent: + TkMacDoHLEvent(eventPtr); + /* TODO: should return true if events were placed on event queue. */ + break; + case osEvt: + /* + * Do clipboard conversion. + */ + switch ((eventPtr->message & osEvtMessageMask) >> 24) { + case mouseMovedMessage: + if (GeneratePollingEvents()) { + eventFound = true; + } + break; + case suspendResumeMessage: + if (!(eventPtr->message & resumeFlag)) { + TkSuspendClipboard(); + } + tkMacAppInFront = (eventPtr->message & resumeFlag); + break; + } + break; + case diskEvt: + /* + * Disk insertion. + */ + if (HiWord(eventPtr->message) != noErr) { + Point pt; + + DILoad(); + pt.v = pt.h = 120; /* parameter ignored in sys 7 */ + DIBadMount(pt, eventPtr->message); + DIUnload(); + } + break; + } + + return eventFound; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacConvertTkEvent -- + * + * This function converts a Macintosh event into zero or more + * Tcl events. + * + * Results: + * Returns 1 if event added to Tcl queue, 0 otherwse. + * + * Side effects: + * May add events to Tcl's event queue. + * + *---------------------------------------------------------------------- + */ + +int +TkMacConvertTkEvent( + EventRecord *eventPtr, + Window window) +{ + int eventFound = false; + Point where; + + switch (eventPtr->what) { + case nullEvent: + case adjustCursorEvent: + if (GeneratePollingEvents2(window)) { + eventFound = true; + } + break; + case updateEvt: + if (GenerateUpdateEvent(eventPtr, window)) { + eventFound = true; + } + break; + case mouseDown: + case mouseUp: + GetMouse(&where); + LocalToGlobal(&where); + eventFound |= TkGenerateButtonEvent(where.h, where.v, + window, TkMacButtonKeyState()); + break; + case autoKey: + case keyDown: + /* + * Handle menu-key events here. If it is *not* + * a menu key - just fall through to handle as a + * normal key event. + */ + if ((eventPtr->modifiers & cmdKey) == cmdKey) { + long menuResult = MenuKey(eventPtr->message & charCodeMask); + + if (HiWord(menuResult) != 0) { + TkMacHandleMenuSelect(menuResult, false); + break; + } + } + case keyUp: + eventFound |= GenerateKeyEvent(eventPtr, window); + break; + case activateEvt: + eventFound |= GenerateActivateEvents(eventPtr, window); + eventFound |= GenerateFocusEvent(eventPtr, window); + break; + case getFocusEvent: + eventPtr->modifiers |= activeFlag; + eventFound |= GenerateFocusEvent(eventPtr, window); + break; + case loseFocusEvent: + eventPtr->modifiers &= ~activeFlag; + eventFound |= GenerateFocusEvent(eventPtr, window); + break; + case kHighLevelEvent: + TkMacDoHLEvent(eventPtr); + /* TODO: should return true if events were placed on event queue. */ + break; + case osEvt: + /* + * Do clipboard conversion. + */ + switch ((eventPtr->message & osEvtMessageMask) >> 24) { + case mouseMovedMessage: + if (GeneratePollingEvents2(window)) { + eventFound = true; + } + break; + case suspendResumeMessage: + if (!(eventPtr->message & resumeFlag)) { + TkSuspendClipboard(); + } + tkMacAppInFront = (eventPtr->message & resumeFlag); + break; + } + break; + case diskEvt: + /* + * Disk insertion. + */ + if (HiWord(eventPtr->message) != noErr) { + Point pt; + + DILoad(); + pt.v = pt.h = 120; /* parameter ignored in sys 7 */ + DIBadMount(pt, eventPtr->message); + DIUnload(); + } + break; + } + + return eventFound; +} + +/* + *---------------------------------------------------------------------- + * + * CheckEventsAvail -- + * + * Checks to see if events are available on the Macintosh queue. + * This function looks for both queued events (eg. key & button) + * and generated events (update). + * + * Results: + * True is events exist, false otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +CheckEventsAvail() +{ + QHdrPtr evPtr; + WindowPeek macWinPtr; + + evPtr = GetEvQHdr(); + if (evPtr->qHead != NULL) { + return true; + } + + macWinPtr = (WindowPeek) FrontWindow(); + while (macWinPtr != NULL) { + if (!EmptyRgn(macWinPtr->updateRgn)) { + return true; + } + macWinPtr = macWinPtr->nextWindow; + } + return false; +} + +/* + *---------------------------------------------------------------------- + * + * TkpSetCapture -- + * + * This function captures the mouse so that all future events + * will be reported to this window, even if the mouse is outside + * the window. If the specified window is NULL, then the mouse + * is released. + * + * Results: + * None. + * + * Side effects: + * Sets the capture flag and captures the mouse. + * + *---------------------------------------------------------------------- + */ + +void +TkpSetCapture( + TkWindow *winPtr) /* Capture window, or NULL. */ +{ + while ((winPtr != NULL) && !Tk_IsTopLevel(winPtr)) { + winPtr = winPtr->parentPtr; + } + gGrabWinPtr = (Tk_Window) winPtr; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacWindowOffset -- + * + * Determines the x and y offset from the orgin of the toplevel + * window dressing (the structure region, ie. title bar) and the + * orgin of the content area. + * + * Results: + * The x & y offset in pixels. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkMacWindowOffset( + WindowRef wRef, + int *xOffset, + int *yOffset) +{ + OSErr err = noErr; + WindowPeek wPeek = (WindowPeek) wRef; + RgnHandle strucRgn = wPeek->strucRgn; + RgnHandle contRgn = wPeek->contRgn; + Rect strucRect, contRect; + + if (!EmptyRgn(strucRgn) && !EmptyRgn(contRgn)) { + strucRect = (**strucRgn).rgnBBox; + contRect = (**contRgn).rgnBBox; + } else { + /* + * The current window's regions are not up to date. + * Probably because the window isn't visable. What we + * will do is save the old regions, have the window calculate + * what the regions should be, and then restore it self. + */ + strucRgn = NewRgn( ); + contRgn = NewRgn( ); + + if (!strucRgn || !contRgn) { + err = MemError( ); + } else { + CopyRgn(wPeek->strucRgn, strucRgn); + CopyRgn(wPeek->contRgn, contRgn); + + if (!(err = TellWindowDefProcToCalcRegions(wRef))) { + strucRect = (**(wPeek->strucRgn)).rgnBBox; + contRect = (**(wPeek->contRgn)).rgnBBox; + } + + CopyRgn(strucRgn, wPeek->strucRgn); + CopyRgn(contRgn, wPeek->contRgn); + } + + if (contRgn) { + DisposeRgn(contRgn); + } + + if (strucRgn) { + DisposeRgn(strucRgn); + } + } + + if (!err) { + *xOffset = contRect.left - strucRect.left; + *yOffset = contRect.top - strucRect.top; + } else { + *xOffset = 0; + *yOffset = 0; + } + + return; +} + +/* + *---------------------------------------------------------------------- + * + * TellWindowDefProcToCalcRegions -- + * + * Force a Macintosh window to recalculate it's content and + * structure regions. + * + * Results: + * An OS error. + * + * Side effects: + * The windows content and structure regions may be updated. + * + *---------------------------------------------------------------------- + */ + +static OSErr +TellWindowDefProcToCalcRegions( + WindowRef wRef) +{ + OSErr err = noErr; + SInt8 hState; + Handle wdef = ((WindowPeek) wRef)->windowDefProc; + + /* + * Load and lock the window definition procedure for + * the window. + */ + hState = HGetState(wdef); + if (!(err = MemError())) { + LoadResource(wdef); + if (!(err = ResError())) { + MoveHHi(wdef); + err = MemError(); + if (err == memLockedErr) { + err = noErr; + } else if (!err) { + HLock(wdef); + err = MemError(); + } + } + } + + /* + * Assuming there are no errors we now call the window definition + * procedure to tell it to calculate the regions for the window. + */ + + if (err == noErr) { + (void) CallWindowDefProc((UniversalProcPtr) *wdef, + GetWVariant(wRef), wRef, wCalcRgns, 0); + + HSetState(wdef, hState); + if (!err) { + err = MemError(); + } + } + + return err; +} + +/* + *---------------------------------------------------------------------- + * + * 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) +{ + SelectWindow(wRef); +} + +/* + *---------------------------------------------------------------------- + * + * TkpGetMS -- + * + * Return a relative time in milliseconds. It doesn't matter + * when the epoch was. + * + * Results: + * Number of milliseconds. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +unsigned long +TkpGetMS() +{ + long long * int64Ptr; + UnsignedWide micros; + + Microseconds(µs); + int64Ptr = (long long *) µs; + + /* + * We need 64 bit math to do this. This is available in CW 11 + * and on. Other's will need to use a different scheme. + */ + + *int64Ptr /= 1000; + + return (long) *int64Ptr; +} |