tkMacOSXWindowEvent.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:27k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * tkMacOSXWindowEvent.c --
  3.  *
  4.  * This file defines the routines for both creating and handling
  5.  * Window Manager class events for Tk.
  6.  *
  7.  * Copyright 2001, Apple Computer, Inc.
  8.  * Copyright (c) 2005-2007 Daniel A. Steffen <das@users.sourceforge.net>
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution of
  11.  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * The following terms apply to all files originating from Apple
  14.  * Computer, Inc. ("Apple") and associated with the software
  15.  * unless explicitly disclaimed in individual files.
  16.  *
  17.  *
  18.  * Apple hereby grants permission to use, copy, modify,
  19.  * distribute, and license this software and its documentation
  20.  * for any purpose, provided that existing copyright notices are
  21.  * retained in all copies and that this notice is included
  22.  * verbatim in any distributions. No written agreement, license,
  23.  * or royalty fee is required for any of the authorized
  24.  * uses. Modifications to this software may be copyrighted by
  25.  * their authors and need not follow the licensing terms
  26.  * described here, provided that the new terms are clearly
  27.  * indicated on the first page of each file where they apply.
  28.  *
  29.  *
  30.  * IN NO EVENT SHALL APPLE, THE AUTHORS OR DISTRIBUTORS OF THE
  31.  * SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
  32.  * INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
  33.  * THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
  34.  * EVEN IF APPLE OR THE AUTHORS HAVE BEEN ADVISED OF THE
  35.  * POSSIBILITY OF SUCH DAMAGE.  APPLE, THE AUTHORS AND
  36.  * DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
  37.  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
  38.  * FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS
  39.  * SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND APPLE,THE
  40.  * AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
  41.  * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  42.  *
  43.  * GOVERNMENT USE: If you are acquiring this software on behalf
  44.  * of the U.S. government, the Government shall have only
  45.  * "Restricted Rights" in the software and related documentation
  46.  * as defined in the Federal Acquisition Regulations (FARs) in
  47.  * Clause 52.227.19 (c) (2).  If you are acquiring the software
  48.  * on behalf of the Department of Defense, the software shall be
  49.  * classified as "Commercial Computer Software" and the
  50.  * Government shall have only "Restricted Rights" as defined in
  51.  * Clause 252.227-7013 (c) (1) of DFARs.  Notwithstanding the
  52.  * foregoing, the authors grant the U.S. Government and others
  53.  * acting in its behalf permission to use and distribute the
  54.  * software in accordance with the terms specified in this
  55.  * license.
  56.  *
  57.  * RCS: @(#) $Id: tkMacOSXWindowEvent.c,v 1.3.2.26 2007/11/09 06:26:56 das Exp $
  58.  */
  59. #include "tkMacOSXPrivate.h"
  60. #include "tkMacOSXWm.h"
  61. #include "tkMacOSXEvent.h"
  62. #include "tkMacOSXDebug.h"
  63. /*
  64. #ifdef TK_MAC_DEBUG
  65. #define TK_MAC_DEBUG_CLIP_REGIONS
  66. #endif
  67. */
  68. /*
  69.  * Declaration of functions used only in this file
  70.  */
  71. static int GenerateUpdateEvent(Window window);
  72. static int GenerateUpdates(HIMutableShapeRef updateRgn, CGRect *updateBounds,
  73. TkWindow *winPtr);
  74. static int GenerateActivateEvents(Window window, int activeFlag);
  75. static void ClearPort(CGrafPtr port, HIShapeRef updateRgn);
  76. /*
  77.  *----------------------------------------------------------------------
  78.  *
  79.  * TkMacOSXProcessApplicationEvent --
  80.  *
  81.  * This processes Application level events, mainly activate
  82.  * and deactivate.
  83.  *
  84.  * Results:
  85.  * 0.
  86.  *
  87.  * Side effects:
  88.  * Hide or reveal floating windows.
  89.  *
  90.  *----------------------------------------------------------------------
  91.  */
  92. MODULE_SCOPE int
  93. TkMacOSXProcessApplicationEvent(
  94. TkMacOSXEvent *eventPtr,
  95. MacEventStatus *statusPtr)
  96. {
  97.     Tcl_CmdInfo dummy;
  98.     /*
  99.      * This is a bit of a hack. We get "show" events both when we come back
  100.      * from being hidden, and whenever we are activated. I only want to run
  101.      * the "show" proc when we have been hidden already, not as a substitute
  102.      * for <Activate>. So I use this toggle...
  103.      */
  104.     static int toggleHide = 0;
  105.     switch (eventPtr->eKind) {
  106. case kEventAppActivated:
  107.     ShowFloatingWindows();
  108.     break;
  109. case kEventAppDeactivated:
  110.     TkSuspendClipboard();
  111.     HideFloatingWindows();
  112.     break;
  113. case kEventAppQuit:
  114.     statusPtr->stopProcessing = 1;
  115.     break;
  116. case kEventAppHidden:
  117.     if (toggleHide == 0) {
  118. toggleHide = 1;
  119. if (eventPtr->interp && Tcl_GetCommandInfo(eventPtr->interp,
  120. "::tk::mac::OnHide", &dummy)) {
  121.     Tcl_GlobalEval(eventPtr->interp, "::tk::mac::OnHide");
  122. }
  123.     }
  124.     statusPtr->stopProcessing = 1;
  125.     break;
  126. case kEventAppShown:
  127.     if (toggleHide == 1) {
  128. toggleHide = 0;
  129. if (eventPtr->interp && Tcl_GetCommandInfo(eventPtr->interp,
  130. "::tk::mac::OnShow", &dummy)) {
  131.     Tcl_GlobalEval(eventPtr->interp, "::tk::mac::OnShow");
  132. }
  133.     }
  134.     statusPtr->stopProcessing = 1;
  135.     break;
  136. case kEventAppAvailableWindowBoundsChanged: {
  137.     static UInt32 prevId = 0;
  138.     UInt32 id;
  139.     OSStatus err;
  140.     err = ChkErr(GetEventParameter, eventPtr->eventRef,
  141.     kEventParamTransactionID, typeUInt32,
  142.     NULL, sizeof(id), NULL, &id);
  143.     if (err != noErr || id != prevId) {
  144. TkDisplay *dispPtr = TkGetDisplayList();
  145. prevId = id;
  146. TkMacOSXDisplayChanged(dispPtr->display);
  147.     }
  148.     /*
  149.      * Should we call ::tk::mac::OnDisplayChanged?
  150.      */
  151.     break;
  152. }
  153. default:
  154.     break;
  155.     }
  156.     return 0;
  157. }
  158. /*
  159.  *----------------------------------------------------------------------
  160.  *
  161.  * TkMacOSXProcessAppearanceEvent --
  162.  *
  163.  * This processes Appearance events.
  164.  *
  165.  * Results:
  166.  * 0.
  167.  *
  168.  * Side effects:
  169.  * None.
  170.  *
  171.  *----------------------------------------------------------------------
  172.  */
  173. MODULE_SCOPE int
  174. TkMacOSXProcessAppearanceEvent(
  175. TkMacOSXEvent *eventPtr,
  176. MacEventStatus *statusPtr)
  177. {
  178.     switch (eventPtr->eKind) {
  179. case kEventAppearanceScrollBarVariantChanged:
  180.     TkMacOSXInitScrollbarMetrics();
  181.     break;
  182. default:
  183.     break;
  184.     }
  185.     return 0;
  186. }
  187. /*
  188.  *----------------------------------------------------------------------
  189.  *
  190.  * TkMacOSXProcessWindowEvent --
  191.  *
  192.  * This processes Window level events, mainly activate
  193.  * and deactivate.
  194.  *
  195.  * Results:
  196.  * 0.
  197.  *
  198.  * Side effects:
  199.  * Cause Windows to be moved forward or backward in the
  200.  * window stack.
  201.  *
  202.  *----------------------------------------------------------------------
  203.  */
  204. MODULE_SCOPE int
  205. TkMacOSXProcessWindowEvent(
  206. TkMacOSXEvent * eventPtr,
  207. MacEventStatus * statusPtr)
  208. {
  209.     OSStatus err;
  210.     WindowRef whichWindow;
  211.     Window window;
  212.     int eventFound = false;
  213.     TkDisplay *dispPtr;
  214.     TkWindow *winPtr;
  215.     switch (eventPtr->eKind) {
  216. case kEventWindowActivated:
  217. case kEventWindowDeactivated:
  218. case kEventWindowUpdate:
  219. case kEventWindowExpanding:
  220. case kEventWindowBoundsChanged:
  221. case kEventWindowDragStarted:
  222. case kEventWindowDragCompleted:
  223. case kEventWindowConstrain:
  224. case kEventWindowGetRegion:
  225. case kEventWindowDrawContent:
  226.     break;
  227. default:
  228.     return 0;
  229.     break;
  230.     }
  231.     err = ChkErr(GetEventParameter, eventPtr->eventRef,
  232.     kEventParamDirectObject, typeWindowRef, NULL, sizeof(whichWindow),
  233.     NULL, &whichWindow);
  234.     if (err != noErr) {
  235. return 0;
  236.     }
  237.     window = TkMacOSXGetXWindow(whichWindow);
  238.     dispPtr = TkGetDisplayList();
  239.     winPtr = (TkWindow *)Tk_IdToWindow(dispPtr->display, window);
  240.     switch (eventPtr->eKind) {
  241. case kEventWindowActivated:
  242. case kEventWindowDeactivated:
  243.     if (window != None) {
  244. int activate = (eventPtr->eKind == kEventWindowActivated);
  245. eventFound |= GenerateActivateEvents(window, activate);
  246. eventFound |= TkMacOSXGenerateFocusEvent(window, activate);
  247. if (winPtr) {
  248.     TkMacOSXEnterExitFullscreen(winPtr, activate);
  249. }
  250. statusPtr->stopProcessing = 1;
  251.     }
  252.     break;
  253. case kEventWindowUpdate:
  254.     if (window != None && GenerateUpdateEvent(window)) {
  255. eventFound = true;
  256. statusPtr->stopProcessing = 1;
  257.     }
  258.     break;
  259. case kEventWindowExpanding:
  260.     if (winPtr) {
  261. winPtr->wmInfoPtr->hints.initial_state =
  262. TkMacOSXIsWindowZoomed(winPtr) ? ZoomState : 
  263. NormalState;
  264. Tk_MapWindow((Tk_Window) winPtr);
  265. /*
  266.  * Need to process all Tk events generated by Tk_MapWindow()
  267.  * before returning to ensure all children are mapped, as
  268.  * otherwise the Activate event that follows Expanding would
  269.  * not be processed by any unmapped children.
  270.  */
  271. while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {};
  272. while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {};
  273.     }
  274.     break;
  275. case kEventWindowBoundsChanged:
  276.     if (winPtr) {
  277. WmInfo *wmPtr = winPtr->wmInfoPtr;
  278. UInt32 attr;
  279. Rect bounds;
  280. int x = -1, y = -1, width = -1, height = -1, flags = 0;
  281. ChkErr(GetEventParameter, eventPtr->eventRef,
  282. kEventParamAttributes, typeUInt32,
  283. NULL, sizeof(attr), NULL, &attr);
  284. ChkErr(GetEventParameter, eventPtr->eventRef,
  285. kEventParamCurrentBounds, typeQDRectangle,
  286. NULL, sizeof(bounds), NULL, &bounds);
  287. if (attr & kWindowBoundsChangeOriginChanged) {
  288.     x = bounds.left - wmPtr->xInParent;
  289.     y = bounds.top - wmPtr->yInParent;
  290.     flags |= TK_LOCATION_CHANGED;
  291. }
  292. if (attr & kWindowBoundsChangeSizeChanged) {
  293.     width = bounds.right  - bounds.left;
  294.     height = bounds.bottom - bounds.top;
  295.     flags |= TK_SIZE_CHANGED;
  296. }
  297. TkMacOSXInvalClipRgns((Tk_Window) winPtr);
  298. TkMacOSXInvalidateWindow((MacDrawable *) window,
  299. TK_PARENT_WINDOW);
  300. TkGenWMConfigureEvent((Tk_Window)winPtr, x, y, width,
  301. height, flags);
  302. if (attr & kWindowBoundsChangeUserResize ||
  303. attr & kWindowBoundsChangeUserDrag) {
  304.     TkMacOSXRunTclEventLoop();
  305. }
  306. if (wmPtr->attributes & kWindowResizableAttribute) {
  307.     HIViewRef growBoxView;
  308.     err = HIViewFindByID(HIViewGetRoot(whichWindow),
  309.     kHIViewWindowGrowBoxID, &growBoxView);
  310.     if (err == noErr) {
  311. ChkErr(HIViewSetNeedsDisplay, growBoxView, true);
  312.     }
  313. }
  314.     }
  315.     break;
  316. case kEventWindowDragStarted:
  317.     if (!(TkMacOSXModifierState() & cmdKey)) { 
  318. TkMacOSXBringWindowForward(whichWindow);
  319.     }
  320.     TkMacOSXTrackingLoop(1);
  321.     break;
  322. case kEventWindowDragCompleted: {
  323.     Rect maxBounds, bounds, strWidths;
  324.     int h = 0, v = 0;
  325.     TkMacOSXTrackingLoop(0);
  326.     ChkErr(GetWindowGreatestAreaDevice, whichWindow,
  327.     kWindowDragRgn, NULL, &maxBounds);
  328.     ChkErr(GetWindowBounds, whichWindow, kWindowStructureRgn,
  329.     &bounds);
  330.     ChkErr(GetWindowStructureWidths, whichWindow, &strWidths);
  331.     if (bounds.left > maxBounds.right - strWidths.left) {
  332. h = maxBounds.right
  333. - (strWidths.left ? strWidths.left : 40)
  334. - bounds.left;
  335.     } else if (bounds.right < maxBounds.left
  336.     + strWidths.right) {
  337. h = maxBounds.left
  338. + (strWidths.right ? strWidths.right : 40)
  339. - bounds.right;
  340.     }
  341.     if (bounds.top > maxBounds.bottom - strWidths.top) {
  342. v = maxBounds.bottom
  343. - (strWidths.top ? strWidths.top : 40)
  344. - bounds.top;
  345.     } else if (bounds.bottom < maxBounds.top
  346.     + strWidths.bottom) {
  347. v = maxBounds.top
  348. + (strWidths.bottom ? strWidths.bottom : 40)
  349. - bounds.bottom;
  350.     } else if (strWidths.top && bounds.top < maxBounds.top) {
  351. v = maxBounds.top - bounds.top;
  352.     }
  353.     if (h || v) {
  354. OffsetRect(&bounds, h, v);
  355. ChkErr(SetWindowBounds, whichWindow,
  356.     kWindowStructureRgn, &bounds);
  357.     }
  358.     break;
  359. }
  360. case kEventWindowConstrain:
  361.     if (winPtr && (winPtr->wmInfoPtr->flags & WM_FULLSCREEN) &&
  362.     TkMacOSXMakeFullscreen(winPtr, whichWindow, 1,
  363.     NULL) == TCL_OK) {
  364. statusPtr->stopProcessing = 1;
  365.     }
  366.     break;
  367. case kEventWindowGetRegion:
  368.     if (winPtr && (winPtr->wmInfoPtr->flags & WM_TRANSPARENT)) {
  369. WindowRegionCode code;
  370. statusPtr->stopProcessing = (CallNextEventHandler(
  371. eventPtr->callRef, eventPtr->eventRef) == noErr);
  372. err = ChkErr(GetEventParameter, eventPtr->eventRef,
  373. kEventParamWindowRegionCode, typeWindowRegionCode,
  374. NULL, sizeof(code), NULL, &code);
  375. if (err == noErr && code == kWindowOpaqueRgn) {
  376.     RgnHandle rgn;
  377.     err = ChkErr(GetEventParameter, eventPtr->eventRef,
  378.     kEventParamRgnHandle, typeQDRgnHandle, NULL,
  379.     sizeof(rgn), NULL, &rgn);
  380.     if (err == noErr) {
  381. SetEmptyRgn(rgn);
  382. statusPtr->stopProcessing = 1;
  383.     }
  384. }
  385.     }
  386.     break;
  387. case kEventWindowDrawContent:
  388.     if (winPtr && (winPtr->wmInfoPtr->flags & WM_TRANSPARENT)) {
  389. CGrafPtr port;
  390. GetPort(&port);
  391. ClearPort(port, NULL);
  392.     }
  393.     break;
  394.     }
  395.     return 0;
  396. }
  397. /*
  398.  *----------------------------------------------------------------------
  399.  *
  400.  * GenerateUpdateEvent --
  401.  *
  402.  * Given a Macintosh window update event this function generates
  403.  * all the Expose XEvents needed by Tk.
  404.  *
  405.  * Results:
  406.  * True if event(s) are generated - false otherwise.
  407.  *
  408.  * Side effects:
  409.  * Additional events may be place on the Tk event queue.
  410.  *
  411.  *----------------------------------------------------------------------
  412.  */
  413. static int
  414. GenerateUpdateEvent(Window window)
  415. {
  416.     WindowRef macWindow;
  417.     TkDisplay *dispPtr;
  418.     TkWindow  *winPtr;
  419.     int result = 0;
  420.     CGRect updateBounds;
  421.     HIShapeRef rgn;
  422.     HIMutableShapeRef updateRgn;
  423.     int dx, dy;
  424.     dispPtr = TkGetDisplayList();
  425.     winPtr = (TkWindow *)Tk_IdToWindow(dispPtr->display, window);
  426.     if (winPtr ==NULL ){
  427. return result;
  428.     }
  429.     macWindow = TkMacOSXDrawableWindow(window);
  430.     TK_IF_MAC_OS_X_API (5, HIWindowCopyShape,
  431. ChkErr(HIWindowCopyShape, macWindow, kWindowUpdateRgn,
  432. kHICoordSpaceWindow, &rgn);
  433. dx = -winPtr->wmInfoPtr->xInParent;
  434. dy = -winPtr->wmInfoPtr->yInParent;
  435.     ) TK_ELSE_MAC_OS_X (5,
  436. Rect bounds;
  437. TkMacOSXCheckTmpQdRgnEmpty();
  438. ChkErr(GetWindowRegion, macWindow, kWindowUpdateRgn, tkMacOSXtmpQdRgn);
  439. rgn = HIShapeCreateWithQDRgn(tkMacOSXtmpQdRgn);
  440. SetEmptyRgn(tkMacOSXtmpQdRgn);
  441. ChkErr(GetWindowBounds, macWindow, kWindowContentRgn, &bounds);
  442. dx = -bounds.left;
  443. dy = -bounds.top;
  444.     ) TK_ENDIF
  445.     updateRgn = HIShapeCreateMutableCopy(rgn);
  446.     CFRelease(rgn);
  447.     ChkErr(HIShapeOffset, updateRgn, dx, dy);
  448.     HIShapeGetBounds(updateRgn, &updateBounds);
  449. #ifdef TK_MAC_DEBUG_CLIP_REGIONS
  450.     TkMacOSXDebugFlashRegion(window, updateRgn);
  451. #endif /* TK_MAC_DEBUG_CLIP_REGIONS */
  452.     BeginUpdate(macWindow);
  453.     if (winPtr->wmInfoPtr->flags & WM_TRANSPARENT) {
  454. ClearPort(TkMacOSXGetDrawablePort(window), updateRgn);
  455.     }
  456.     result = GenerateUpdates(updateRgn, &updateBounds, winPtr);
  457.     EndUpdate(macWindow);
  458.     CFRelease(updateRgn);
  459.     if (result) {
  460. /*
  461.  * Ensure there are no pending idle-time redraws that could prevent
  462.  * the just posted Expose events from generating new redraws.
  463.  */
  464. Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT);
  465.     }
  466.     return result;
  467.  }
  468. /*
  469.  *----------------------------------------------------------------------
  470.  *
  471.  * GenerateUpdates --
  472.  *
  473.  * Given a Macintosh update region and a Tk window this function
  474.  * geneates a X Expose event for the window if it is within the
  475.  * update region. The function will then recursivly have each
  476.  * damaged window generate Expose events for its child windows.
  477.  *
  478.  * Results:
  479.  * True if event(s) are generated - false otherwise.
  480.  *
  481.  * Side effects:
  482.  * Additional events may be place on the Tk event queue.
  483.  *
  484.  *----------------------------------------------------------------------
  485.  */
  486. static int
  487. GenerateUpdates(
  488.     HIMutableShapeRef updateRgn,
  489.     CGRect *updateBounds,
  490.     TkWindow *winPtr)
  491. {
  492.     TkWindow *childPtr;
  493.     XEvent event;
  494.     CGRect bounds, damageBounds;
  495.     HIShapeRef boundsRgn, damageRgn;
  496.     TkMacOSXWinCGBounds(winPtr, &bounds);
  497.     if (!CGRectIntersectsRect(bounds, *updateBounds)) {
  498. return 0;
  499.     }
  500.     TK_IF_MAC_OS_X_API (4, HIShapeIntersectsRect,
  501. if (!HIShapeIntersectsRect(updateRgn, &bounds)) {
  502.     return 0;
  503. }
  504.     ) TK_ENDIF
  505.     /*
  506.      * Compute the bounding box of the area that the damage occured in.
  507.      */
  508.     boundsRgn = HIShapeCreateWithRect(&bounds);
  509.     damageRgn = HIShapeCreateIntersection(updateRgn, boundsRgn);
  510.     if (HIShapeIsEmpty(damageRgn)) {
  511. CFRelease(damageRgn);
  512. CFRelease(boundsRgn);
  513. return 0;
  514.     }
  515.     HIShapeGetBounds(damageRgn, &damageBounds);
  516.     ChkErr(TkMacOSHIShapeUnion, boundsRgn, updateRgn, updateRgn);
  517.     HIShapeGetBounds(updateRgn, updateBounds);
  518.     CFRelease(damageRgn);
  519.     CFRelease(boundsRgn);
  520.     event.xany.serial = Tk_Display(winPtr)->request;
  521.     event.xany.send_event = false;
  522.     event.xany.window = Tk_WindowId(winPtr);
  523.     event.xany.display = Tk_Display(winPtr);
  524.     event.type = Expose;
  525.     event.xexpose.x = damageBounds.origin.x - bounds.origin.x;
  526.     event.xexpose.y = damageBounds.origin.y - bounds.origin.y;
  527.     event.xexpose.width = damageBounds.size.width;
  528.     event.xexpose.height = damageBounds.size.height;
  529.     event.xexpose.count = 0;
  530.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  531.     /*
  532.      * Generate updates for the children of this window
  533.      */
  534.     for (childPtr = winPtr->childList; childPtr != NULL;
  535.     childPtr = childPtr->nextPtr) {
  536. if (!Tk_IsMapped(childPtr) || Tk_IsTopLevel(childPtr)) {
  537.     continue;
  538. }
  539. GenerateUpdates(updateRgn, updateBounds, childPtr);
  540.     }
  541.     /*
  542.      * Generate updates for any contained windows
  543.      */
  544.     if (Tk_IsContainer(winPtr)) {
  545. childPtr = TkpGetOtherWindow(winPtr);
  546. if (childPtr != NULL && Tk_IsMapped(childPtr)) {
  547.     GenerateUpdates(updateRgn, updateBounds, childPtr);
  548. }
  549. /*
  550.  * TODO: Here we should handle out of process embedding.
  551.  */
  552.     }
  553.     return 1;
  554. }
  555. /*
  556.  *----------------------------------------------------------------------
  557.  *
  558.  * GenerateActivateEvents --
  559.  *
  560.  * Given a Macintosh window activate event this function generates all the
  561.  * X Activate events needed by Tk.
  562.  *
  563.  * Results:
  564.  * True if event(s) are generated - false otherwise.
  565.  *
  566.  * Side effects:
  567.  * Additional events may be place on the Tk event queue.
  568.  *
  569.  *----------------------------------------------------------------------
  570.  */
  571. int
  572. GenerateActivateEvents(
  573.     Window window,   /* Root X window for event. */
  574.     int activeFlag )
  575. {
  576.     TkWindow *winPtr;
  577.     TkDisplay *dispPtr;
  578.     dispPtr = TkGetDisplayList();
  579.     winPtr = (TkWindow *) Tk_IdToWindow(dispPtr->display, window);
  580.     if (winPtr == NULL || winPtr->window == None) {
  581. return false;
  582.     }
  583.     TkGenerateActivateEvents(winPtr,activeFlag);
  584.     return true;
  585. }
  586. /*
  587.  *----------------------------------------------------------------------
  588.  *
  589.  * TkMacOSXGenerateFocusEvent --
  590.  *
  591.  * Given a Macintosh window activate event this function generates all the
  592.  * X Focus events needed by Tk.
  593.  *
  594.  * Results:
  595.  * True if event(s) are generated - false otherwise.
  596.  *
  597.  * Side effects:
  598.  * Additional events may be place on the Tk event queue.
  599.  *
  600.  *----------------------------------------------------------------------
  601.  */
  602. MODULE_SCOPE int
  603. TkMacOSXGenerateFocusEvent(
  604.     Window window, /* Root X window for event. */
  605.     int activeFlag )
  606. {
  607.     XEvent event;
  608.     Tk_Window tkwin;
  609.     TkDisplay *dispPtr;
  610.     dispPtr = TkGetDisplayList();
  611.     tkwin = Tk_IdToWindow(dispPtr->display, window);
  612.     if (tkwin == NULL) {
  613. return false;
  614.     }
  615.     /*
  616.      * Don't send focus events to windows of class help or to
  617.      * windows with the kWindowNoActivatesAttribute.
  618.      */
  619.     if (((TkWindow *)tkwin)->wmInfoPtr->macClass == kHelpWindowClass ||
  620.     ((TkWindow *)tkwin)->wmInfoPtr->attributes &
  621.     kWindowNoActivatesAttribute) {
  622. return false;
  623.     }
  624.     /*
  625.      * Generate FocusIn and FocusOut events. This event
  626.      * is only sent to the toplevel window.
  627.      */
  628.     if (activeFlag) {
  629. event.xany.type = FocusIn;
  630.     } else {
  631. event.xany.type = FocusOut;
  632.     }
  633.     event.xany.serial = dispPtr->display->request;
  634.     event.xany.send_event = False;
  635.     event.xfocus.display = dispPtr->display;
  636.     event.xfocus.window = window;
  637.     event.xfocus.mode = NotifyNormal;
  638.     event.xfocus.detail = NotifyDetailNone;
  639.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  640.     return true;
  641. }
  642. /*
  643.  *----------------------------------------------------------------------
  644.  *
  645.  * TkGenWMConfigureEvent --
  646.  *
  647.  * Generate a ConfigureNotify event for Tk. Depending on the
  648.  * value of flag the values of width/height, x/y, or both may
  649.  * be changed.
  650.  *
  651.  * Results:
  652.  * None.
  653.  *
  654.  * Side effects:
  655.  * A ConfigureNotify event is sent to Tk.
  656.  *
  657.  *----------------------------------------------------------------------
  658.  */
  659. void
  660. TkGenWMConfigureEvent(
  661.     Tk_Window tkwin,
  662.     int x,
  663.     int y,
  664.     int width,
  665.     int height,
  666.     int flags)
  667. {
  668.     XEvent event;
  669.     WmInfo *wmPtr;
  670.     TkWindow *winPtr = (TkWindow *) tkwin;
  671.     if (tkwin == NULL) {
  672. return;
  673.     }
  674.     event.type = ConfigureNotify;
  675.     event.xconfigure.serial = Tk_Display(tkwin)->request;
  676.     event.xconfigure.send_event = False;
  677.     event.xconfigure.display = Tk_Display(tkwin);
  678.     event.xconfigure.event = Tk_WindowId(tkwin);
  679.     event.xconfigure.window = Tk_WindowId(tkwin);
  680.     event.xconfigure.border_width = winPtr->changes.border_width;
  681.     event.xconfigure.override_redirect = winPtr->atts.override_redirect;
  682.     if (winPtr->changes.stack_mode == Above) {
  683. event.xconfigure.above = winPtr->changes.sibling;
  684.     } else {
  685. event.xconfigure.above = None;
  686.     }
  687.     if (!(flags & TK_LOCATION_CHANGED)) {
  688. x = Tk_X(tkwin);
  689. y = Tk_Y(tkwin);
  690.     }
  691.     if (!(flags & TK_SIZE_CHANGED)) {
  692. width = Tk_Width(tkwin);
  693. height = Tk_Height(tkwin);
  694.     }
  695.     event.xconfigure.x = x;
  696.     event.xconfigure.y = y;
  697.     event.xconfigure.width = width;
  698.     event.xconfigure.height = height;
  699.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  700.     /*
  701.      * Update window manager information.
  702.      */
  703.     if (Tk_IsTopLevel(winPtr)) {
  704. wmPtr = winPtr->wmInfoPtr;
  705. if (flags & TK_LOCATION_CHANGED) {
  706.     wmPtr->x = x;
  707.     wmPtr->y = y;
  708.     wmPtr->flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
  709. }
  710. if ((flags & TK_SIZE_CHANGED) && !(wmPtr->flags & WM_SYNC_PENDING) &&
  711. ((width != Tk_Width(tkwin)) || (height != Tk_Height(tkwin)))) {
  712.     if ((wmPtr->width == -1) && (width == winPtr->reqWidth)) {
  713. /*
  714.  * Don't set external width, since the user didn't change it
  715.  * from what the widgets asked for.
  716.  */
  717.     } else {
  718. if (wmPtr->gridWin != NULL) {
  719.     wmPtr->width = wmPtr->reqGridWidth
  720. + (width - winPtr->reqWidth)/wmPtr->widthInc;
  721.     if (wmPtr->width < 0) {
  722. wmPtr->width = 0;
  723.     }
  724. } else {
  725.     wmPtr->width = width;
  726. }
  727.     }
  728.     if ((wmPtr->height == -1) && (height == winPtr->reqHeight)) {
  729. /*
  730.  * Don't set external height, since the user didn't change it
  731.  * from what the widgets asked for.
  732.  */
  733.     } else {
  734. if (wmPtr->gridWin != NULL) {
  735.     wmPtr->height = wmPtr->reqGridHeight
  736. + (height - winPtr->reqHeight)/wmPtr->heightInc;
  737.     if (wmPtr->height < 0) {
  738. wmPtr->height = 0;
  739.     }
  740. } else {
  741.     wmPtr->height = height;
  742. }
  743.     }
  744.     wmPtr->configWidth = width;
  745.     wmPtr->configHeight = height;
  746. }
  747.     }
  748.     /*
  749.      * Now set up the changes structure. Under X we wait for the
  750.      * ConfigureNotify to set these values. On the Mac we know imediatly that
  751.      * this is what we want - so we just set them. However, we need to
  752.      * make sure the windows clipping region is marked invalid so the
  753.      * change is visible to the subwindow.
  754.      */
  755.     winPtr->changes.x = x;
  756.     winPtr->changes.y = y;
  757.     winPtr->changes.width = width;
  758.     winPtr->changes.height = height;
  759.     TkMacOSXInvalClipRgns(tkwin);
  760. }
  761. /*
  762.  *----------------------------------------------------------------------
  763.  *
  764.  * TkGenWMDestroyEvent --
  765.  *
  766.  * Generate a WM Destroy event for Tk.
  767.  *
  768.  * Results:
  769.  * None.
  770.  *
  771.  * Side effects:
  772.  * A WM_PROTOCOL/WM_DELETE_WINDOW event is sent to Tk.
  773.  *
  774.  *----------------------------------------------------------------------
  775.  */
  776. void
  777. TkGenWMDestroyEvent(
  778.     Tk_Window tkwin)
  779. {
  780.     XEvent event;
  781.     event.xany.serial = Tk_Display(tkwin)->request;
  782.     event.xany.send_event = False;
  783.     event.xany.display = Tk_Display(tkwin);
  784.     event.xclient.window = Tk_WindowId(tkwin);
  785.     event.xclient.type = ClientMessage;
  786.     event.xclient.message_type = Tk_InternAtom(tkwin, "WM_PROTOCOLS");
  787.     event.xclient.format = 32;
  788.     event.xclient.data.l[0] = Tk_InternAtom(tkwin, "WM_DELETE_WINDOW");
  789.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  790. }
  791. /*
  792.  *----------------------------------------------------------------------
  793.  *
  794.  * TkWmProtocolEventProc --
  795.  *
  796.  * This procedure is called by the Tk_HandleEvent whenever a
  797.  * ClientMessage event arrives whose type is "WM_PROTOCOLS".
  798.  * This procedure handles the message from the window manager
  799.  * in an appropriate fashion.
  800.  *
  801.  * Results:
  802.  * None.
  803.  *
  804.  * Side effects:
  805.  * Depends on what sort of handler, if any, was set up for the
  806.  * protocol.
  807.  *
  808.  *----------------------------------------------------------------------
  809.  */
  810. void
  811. TkWmProtocolEventProc(
  812.     TkWindow *winPtr, /* Window to which the event was sent. */
  813.     XEvent *eventPtr) /* X event. */
  814. {
  815.     WmInfo *wmPtr;
  816.     ProtocolHandler *protPtr;
  817.     Tcl_Interp *interp;
  818.     Atom protocol;
  819.     int result;
  820.     wmPtr = winPtr->wmInfoPtr;
  821.     if (wmPtr == NULL) {
  822. return;
  823.     }
  824.     protocol = (Atom) eventPtr->xclient.data.l[0];
  825.     for (protPtr = wmPtr->protPtr; protPtr != NULL;
  826. protPtr = protPtr->nextPtr) {
  827. if (protocol == protPtr->protocol) {
  828.     Tcl_Preserve((ClientData) protPtr);
  829.     interp = protPtr->interp;
  830.     Tcl_Preserve((ClientData) interp);
  831.     result = Tcl_GlobalEval(interp, protPtr->command);
  832.     if (result != TCL_OK) {
  833. Tcl_AddErrorInfo(interp, "n    (command for "");
  834. Tcl_AddErrorInfo(interp,
  835. Tk_GetAtomName((Tk_Window) winPtr, protocol));
  836. Tcl_AddErrorInfo(interp, "" window manager protocol)");
  837. Tk_BackgroundError(interp);
  838.     }
  839.     Tcl_Release((ClientData) interp);
  840.     Tcl_Release((ClientData) protPtr);
  841.     return;
  842. }
  843.     }
  844.     /*
  845.      * No handler was present for this protocol. If this is a
  846.      * WM_DELETE_WINDOW message then just destroy the window.
  847.      */
  848.     if (protocol == Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW")) {
  849. Tk_DestroyWindow((Tk_Window) winPtr);
  850.     }
  851. }
  852. /*
  853.  *----------------------------------------------------------------------
  854.  *
  855.  * Tk_MacOSXIsAppInFront --
  856.  *
  857.  * Returns 1 if this app is the foreground app.
  858.  *
  859.  * Results:
  860.  * 1 if app is in front, 0 otherwise.
  861.  *
  862.  * Side effects:
  863.  * None.
  864.  *
  865.  *----------------------------------------------------------------------
  866.  */
  867. int
  868. Tk_MacOSXIsAppInFront(void)
  869. {
  870.     OSStatus err;
  871.     ProcessSerialNumber frontPsn, ourPsn = {0, kCurrentProcess};
  872.     Boolean isFrontProcess = true;
  873.     err = ChkErr(GetFrontProcess, &frontPsn);
  874.     if (err == noErr) {
  875. ChkErr(SameProcess, &frontPsn, &ourPsn, &isFrontProcess);
  876.     }
  877.     
  878.     return (isFrontProcess == true);
  879. }
  880. /*
  881.  *----------------------------------------------------------------------
  882.  *
  883.  * ClearPort --
  884.  *
  885.  * Clear (i.e. fill with transparent color) the given port.
  886.  *
  887.  * Results:
  888.  * None.
  889.  *
  890.  * Side effects:
  891.  * None.
  892.  *
  893.  *----------------------------------------------------------------------
  894.  */
  895. static void
  896. ClearPort(
  897.     CGrafPtr port,
  898.     HIShapeRef updateRgn)
  899. {
  900.     CGContextRef context;
  901.     Rect bounds;
  902.     CGRect rect;
  903.     GetPortBounds(port, &bounds);
  904.     QDBeginCGContext(port, &context);
  905.     SyncCGContextOriginWithPort(context, port);
  906.     CGContextConcatCTM(context, CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0,
  907.     bounds.bottom - bounds.top));
  908.     if (updateRgn) {
  909. ChkErr(HIShapeReplacePathInCGContext, updateRgn, context);
  910. CGContextEOClip(context);
  911.     }
  912.     rect = CGRectMake(0, 0, bounds.right, bounds.bottom);
  913.     CGContextClearRect(context, rect);
  914.     QDEndCGContext(port, &context);
  915. }