/* * tkMacWindowMgr.c -- * * Implements common window manager functions for the Macintosh. * * Copyright (c) 1995-1998 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: tkMacWindowMgr.c,v 1.10 2002/06/14 22:25:12 jenglish Exp $ */ #include #include #include #include #include #include #include #include #include #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, UInt32 savedCode)); 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, int adjustCursor)); 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, frontNonFloating; Tk_Window tkwin; Point where, where2; int xOffset, yOffset; short windowPart; TkDisplay *dispPtr; frontWindow = FrontWindow(); if (TkMacHaveAppearance() >= 0x110) { frontNonFloating = FrontNonFloatingWindow(); } else { frontNonFloating = 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); dispPtr = TkGetDisplayList(); tkwin = Tk_IdToWindow(dispPtr->display, window); switch (windowPart) { case inSysWindow: SystemClick(eventPtr, (GrafPort *) whichWindow); return false; case inDrag: if (!(TkpIsWindowFloating(whichWindow)) && (whichWindow != frontNonFloating)) { 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 (!(TkpIsWindowFloating(whichWindow)) && (whichWindow != frontNonFloating)) { /* * 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; } gEatButtonUp = true; SetPort((GrafPort *) whichWindow); BringWindowForward(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(); /* * Handle -postcommand */ TkMacPreprocessMenu(); 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); } DisposeDialog(aboutDlog); aboutDlog = NULL; if (TkMacHaveAppearance() >= 0x110) { SelectWindow(FrontNonFloatingWindow()); } else { 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; TkDisplay *dispPtr; dispPtr = TkGetDisplayList(); winPtr = (TkWindow *) Tk_IdToWindow(dispPtr->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_TopWinHierarchy(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; 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); if (TkMacHaveAppearance() >= 0x110) { frontWin = FrontNonFloatingWindow(); } else { frontWin = FrontWindow(); } if ((frontWin == NULL) || ((!(TkpIsWindowFloating(whichWin)) && (frontWin != whichWin)) && gGrabWinPtr == 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; } /* *---------------------------------------------------------------------- * * 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; TkDisplay *dispPtr; dispPtr = TkGetDisplayList(); winPtr = (TkWindow *) Tk_IdToWindow(dispPtr->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; TkDisplay *dispPtr; dispPtr = TkGetDisplayList(); tkwin = Tk_IdToWindow(dispPtr->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 = dispPtr->display->request; event.xany.send_event = False; event.xfocus.display = dispPtr->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. */ UInt32 savedKeyCode) /* If non-zero, this is a lead byte which * should be combined with the character * in this event to form one multi-byte * character. */ { Point where; Tk_Window tkwin; XEvent event; unsigned char byte; char buf[16]; TkDisplay *dispPtr; /* * The focus must be in the FrontWindow on the Macintosh. * We then query Tk to determine the exact Tk window * that owns the focus. */ dispPtr = TkGetDisplayList(); tkwin = Tk_IdToWindow(dispPtr->display, window); if (tkwin == NULL) { return false; } tkwin = (Tk_Window) ((TkWindow *) tkwin)->dispPtr->focusPtr; if (tkwin == NULL) { return false; } byte = (unsigned char) (eventPtr->message & charCodeMask); if ((savedKeyCode == 0) && (Tcl_ExternalToUtf(NULL, NULL, (char *) &byte, 1, 0, NULL, buf, sizeof(buf), NULL, NULL, NULL) != TCL_OK)) { /* * This event specifies a lead byte. Wait for the second byte * to come in before sending the XEvent. */ 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 = byte | ((savedKeyCode & charCodeMask) << 8) | ((eventPtr->message & keyCodeMask) << 8); 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, frontNonFloating; Point whereLocal, whereGlobal; Boolean inContentRgn; short part; int local_x, local_y; int generatedEvents = false; TkDisplay *dispPtr; /* * 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 (TkMacHaveAppearance() >= 0x110) { /* * If the mouse is over the front non-floating window, then we * need to set the local coordinates relative to that window * rather than a possibly floating window above it. */ frontNonFloating = FrontNonFloatingWindow(); if (whichWindow == frontNonFloating && (whichWindow != frontWin)) { SetPort((GrafPort *) frontNonFloating); whereLocal = whereGlobal; GlobalToLocal(&whereLocal); } } else { frontNonFloating = frontWin; } if ((!TkpIsWindowFloating(whichWindow) && (frontNonFloating != whichWindow)) || !inContentRgn) { tkwin = NULL; } else { window = TkMacGetXWindow(whichWindow); dispPtr = TkGetDisplayList(); rootwin = Tk_IdToWindow(dispPtr->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, int adjustCursor) { Tk_Window tkwin, rootwin; WindowRef whichwindow, frontWin; Point whereLocal, whereGlobal; int local_x, local_y; int generatedEvents = false; Rect bounds; TkDisplay *dispPtr; /* * 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 { dispPtr = TkGetDisplayList(); rootwin = Tk_IdToWindow(dispPtr->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. */ if (adjustCursor) { 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; static UInt32 savedKeyCode; 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; } } /* fall through */ case keyUp: if (TkMacHaveAppearance() >= 0x110) { whichWindow = FrontNonFloatingWindow(); } else { whichWindow = FrontWindow(); } if (whichWindow == NULL) { /* * This happens if we get a key event before Tk has had a * chance to actually create and realize ".", if they type * when "." is withdrawn(!), or between the time "." is * destroyed and the app exits. */ return false; } window = TkMacGetXWindow(whichWindow); if (GenerateKeyEvent(eventPtr, window, savedKeyCode) == 0) { savedKeyCode = eventPtr->message; return false; } eventFound = true; 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); if (TkMacHaveAppearance() >= 0x110) { if (tkMacAppInFront) { ShowFloatingWindows(); } else { HideFloatingWindows(); } } 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; } savedKeyCode = 0; return eventFound; } /* *---------------------------------------------------------------------- * * TkMacConvertTkEvent -- * * This function converts a Macintosh event into zero or more * Tcl events. It is intended for use in Netscape-style embedding. * * 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; static UInt32 savedKeyCode; /* * By default, assume it is legal for us to set the cursor */ Tk_MacTkOwnsCursor(1); switch (eventPtr->what) { case nullEvent: /* * We get NULL events only when the cursor is NOT over * the plugin. Otherwise we get updateCursor events. * We will not generate polling events or move the cursor * in this case. */ eventFound = false; break; case adjustCursorEvent: if (GeneratePollingEvents2(window, 1)) { eventFound = true; } break; case updateEvt: /* * It is possibly not legal for us to set the cursor */ Tk_MacTkOwnsCursor(0); 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; } } /* fall through. */ case keyUp: if (GenerateKeyEvent(eventPtr, window, savedKeyCode) == 0) { savedKeyCode = eventPtr->message; return false; } eventFound = true; break; case activateEvt: /* * It is probably not legal for us to set the cursor * here, since we don't know where the mouse is in the * window that is being activated. */ Tk_MacTkOwnsCursor(0); 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) { /* * It is possibly not legal for us to set the cursor. * Netscape sends us these events all the time... */ Tk_MacTkOwnsCursor(0); case mouseMovedMessage: /* if (GeneratePollingEvents2(window, 0)) { eventFound = true; } NEXT LINE IS TEMPORARY */ eventFound = false; break; case suspendResumeMessage: if (!(eventPtr->message & resumeFlag)) { TkSuspendClipboard(); } tkMacAppInFront = (eventPtr->message & resumeFlag); if (TkMacHaveAppearance() >= 0x110) { if (tkMacAppInFront) { ShowFloatingWindows(); } else { HideFloatingWindows(); } } 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; } savedKeyCode = 0; 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_TopWinHierarchy(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 if (TkMacHaveAppearance()) { GetWindowRegion(wRef, kWindowStructureRgn, strucRgn); GetWindowRegion(wRef, kWindowContentRgn, contRgn); strucRect = (**strucRgn).rgnBBox; contRect = (**contRgn).rgnBBox; } 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) { if (!TkpIsWindowFloating(wRef)) { if ((TkMacHaveAppearance() < 0x110) || IsValidWindowPtr(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; } /* *---------------------------------------------------------------------- * * TkpIsWindowFloating -- * * Returns 1 if a window is floating, 0 otherwise. * * Results: * 1 or 0 depending on window's floating attribute. * * Side effects: * None. * *---------------------------------------------------------------------- */ int TkpIsWindowFloating(WindowRef wRef) { WindowClass class; if (TkMacHaveAppearance() < 0x110) { return 0; } GetWindowClass(wRef, &class); return (class == kFloatingWindowClass); }