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

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * tkMacOSXEmbed.c --
  3.  *
  4.  * This file contains platform-specific procedures for theMac to provide
  5.  * basic operations needed for application embedding (where one
  6.  * application can use as its main window an internal window from
  7.  * some other application).
  8.  * Currently only Toplevel embedding within the same Tk application is
  9.  * allowed on the Macintosh.
  10.  *
  11.  * Copyright (c) 1996-1997 Sun Microsystems, Inc.
  12.  * Copyright 2001, Apple Computer, Inc.
  13.  * Copyright (c) 2006-2007 Daniel A. Steffen <das@users.sourceforge.net>
  14.  *
  15.  * See the file "license.terms" for information on usage and redistribution
  16.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  17.  *
  18.  *  RCS: @(#) $Id: tkMacOSXEmbed.c,v 1.2.2.8 2007/11/09 06:26:55 das Exp $
  19.  */
  20. #include "tkMacOSXInt.h"
  21. /*
  22.  * One of the following structures exists for each container in this
  23.  * application. It keeps track of the container window and its
  24.  * associated embedded window.
  25.  */
  26. typedef struct Container {
  27.     Window parent; /* The Mac Drawable for the parent of
  28.  * the pair (the container). */
  29.     TkWindow *parentPtr; /* Tk's information about the container,
  30.  * or NULL if the container isn't
  31.  * in this process. */
  32.     Window embedded; /* The MacDrawable for the embedded
  33.  * window. Starts off as None, but
  34.  * gets filled in when the window is
  35.  * eventually created. */
  36.     TkWindow *embeddedPtr; /* Tk's information about the embedded
  37.  * window, or NULL if the
  38.  * embedded application isn't in
  39.  * this process. */
  40.     struct Container *nextPtr; /* Next in list of all containers in
  41.  * this process. */
  42. } Container;
  43. static Container *firstContainerPtr = NULL;
  44. /* First in list of all containers
  45.  * managed by this process. */
  46. /*
  47.  * Globals defined in this file
  48.  */
  49. TkMacOSXEmbedHandler *tkMacOSXEmbedHandler = NULL;
  50. /*
  51.  * Prototypes for static procedures defined in this file:
  52.  */
  53. static void ContainerEventProc(ClientData clientData, XEvent *eventPtr);
  54. static void EmbeddedEventProc(ClientData clientData, XEvent *eventPtr);
  55. static void EmbedActivateProc(ClientData clientData, XEvent *eventPtr);
  56. static void EmbedFocusProc(ClientData clientData, XEvent *eventPtr);
  57. static void EmbedGeometryRequest(Container * containerPtr, int width,
  58. int height);
  59. static void EmbedSendConfigure(Container *containerPtr);
  60. static void EmbedStructureProc(ClientData clientData, XEvent *eventPtr);
  61. static void EmbedWindowDeleted(TkWindow *winPtr);
  62. /*
  63.  *----------------------------------------------------------------------
  64.  *
  65.  * Tk_MacOSXSetEmbedHandler --
  66.  *
  67.  * Registers a handler for an in process form of embedding, like
  68.  * Netscape plugins, where Tk is loaded into the process, but does
  69.  * not control the main window
  70.  *
  71.  * Results:
  72.  * None
  73.  *
  74.  * Side effects:
  75.  * The embed handler is set.
  76.  *
  77.  *----------------------------------------------------------------------
  78.  */
  79. void
  80. Tk_MacOSXSetEmbedHandler(
  81.     Tk_MacOSXEmbedRegisterWinProc *registerWinProc,
  82.     Tk_MacOSXEmbedGetGrafPortProc *getPortProc,
  83.     Tk_MacOSXEmbedMakeContainerExistProc *containerExistProc,
  84.     Tk_MacOSXEmbedGetClipProc *getClipProc,
  85.     Tk_MacOSXEmbedGetOffsetInParentProc *getOffsetProc)
  86. {
  87.     if (tkMacOSXEmbedHandler == NULL) {
  88.     tkMacOSXEmbedHandler = (TkMacOSXEmbedHandler *) ckalloc(sizeof(TkMacOSXEmbedHandler));
  89.     }
  90.     tkMacOSXEmbedHandler->registerWinProc = registerWinProc;
  91.     tkMacOSXEmbedHandler->getPortProc = getPortProc;
  92.     tkMacOSXEmbedHandler->containerExistProc = containerExistProc;
  93.     tkMacOSXEmbedHandler->getClipProc = getClipProc;
  94.     tkMacOSXEmbedHandler->getOffsetProc = getOffsetProc;
  95. }
  96. /*
  97.  *----------------------------------------------------------------------
  98.  *
  99.  * TkpMakeWindow --
  100.  *
  101.  * Creates an X Window (Mac subwindow).
  102.  *
  103.  * Results:
  104.  * The window id is returned.
  105.  *
  106.  * Side effects:
  107.  * None.
  108.  *
  109.  *----------------------------------------------------------------------
  110.  */
  111. Window
  112. TkpMakeWindow(
  113.     TkWindow *winPtr,
  114.     Window parent)
  115. {
  116.     MacDrawable *macWin;
  117.     XEvent event;
  118.     /*
  119.      * If this window is marked as embedded then
  120.      * the window structure should have already been
  121.      * created in the TkpUseWindow function.
  122.      */
  123.     if (Tk_IsEmbedded(winPtr)) {
  124. macWin = winPtr->privatePtr;
  125.     } else {
  126. /*
  127.  * Allocate sub window
  128.  */
  129. macWin = (MacDrawable *) ckalloc(sizeof(MacDrawable));
  130. if (macWin == NULL) {
  131.     winPtr->privatePtr = NULL;
  132.     return None;
  133. }
  134. macWin->winPtr = winPtr;
  135. winPtr->privatePtr = macWin;
  136. macWin->visRgn = NULL;
  137. macWin->aboveVisRgn = NULL;
  138. macWin->drawRect = CGRectNull;
  139. macWin->referenceCount = 0;
  140. macWin->flags = TK_CLIP_INVALID;
  141. macWin->grafPtr = NULL;
  142. macWin->context = NULL;
  143. macWin->size = CGSizeZero;
  144. if (Tk_IsTopLevel(macWin->winPtr)) {
  145.     /*
  146.      *This will be set when we are mapped.
  147.      */
  148.     macWin->xOff = 0;
  149.     macWin->yOff = 0;
  150.     macWin->toplevel = macWin;
  151. } else {
  152.     macWin->xOff = winPtr->parentPtr->privatePtr->xOff +
  153. winPtr->parentPtr->changes.border_width +
  154. winPtr->changes.x;
  155.     macWin->yOff = winPtr->parentPtr->privatePtr->yOff +
  156. winPtr->parentPtr->changes.border_width +
  157. winPtr->changes.y;
  158.     macWin->toplevel = winPtr->parentPtr->privatePtr->toplevel;
  159. }
  160. macWin->toplevel->referenceCount++;
  161.     }
  162.     /*
  163.      * TODO: need general solution for visibility events.
  164.      */
  165.     event.xany.serial = Tk_Display(winPtr)->request;
  166.     event.xany.send_event = False;
  167.     event.xany.display = Tk_Display(winPtr);
  168.     event.xvisibility.type = VisibilityNotify;
  169.     event.xvisibility.window = (Window) macWin;
  170.     event.xvisibility.state = VisibilityUnobscured;
  171.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  172.     return (Window) macWin;
  173. }
  174. /*
  175.  *----------------------------------------------------------------------
  176.  *
  177.  * TkpUseWindow --
  178.  *
  179.  * This procedure causes a Tk window to use a given X window as
  180.  * its parent window, rather than the root window for the screen.
  181.  * It is invoked by an embedded application to specify the window
  182.  * in which it is embedded.
  183.  *
  184.  * Results:
  185.  * The return value is normally TCL_OK. If an error occurs (such
  186.  * as string not being a valid window spec), then the return value
  187.  * is TCL_ERROR and an error message is left in the interp's result if
  188.  * interp is non-NULL.
  189.  *
  190.  * Side effects:
  191.  * None.
  192.  *
  193.  *----------------------------------------------------------------------
  194.  */
  195. int
  196. TkpUseWindow(
  197.     Tcl_Interp *interp, /* If not NULL, used for error reporting
  198.  * if string is bogus. */
  199.     Tk_Window tkwin, /* Tk window that does not yet have an
  200.  * associated X window. */
  201.     CONST char *string) /* String identifying an X window to use
  202.  * for tkwin; must be an integer value. */
  203. {
  204.     TkWindow *winPtr = (TkWindow *) tkwin;
  205.     TkWindow *usePtr;
  206.     MacDrawable *parent, *macWin;
  207.     Container *containerPtr;
  208.     if (winPtr->window != None) {
  209. Tcl_AppendResult(interp, "can't modify container after widget is "
  210. "created", NULL);
  211. return TCL_ERROR;
  212.     }
  213.     /*
  214.      * Decode the container pointer, and look for it among the
  215.      * list of available containers.
  216.      *
  217.      * N.B. For now, we are limiting the containers to be in the same Tk
  218.      * application as tkwin, since otherwise they would not be in our list
  219.      * of containers.
  220.      *
  221.      */
  222.     if (Tcl_GetInt(interp, string, (int*) &parent) != TCL_OK) {
  223. return TCL_ERROR;
  224.     }
  225.     usePtr = (TkWindow *) Tk_IdToWindow(winPtr->display, (Window) parent);
  226.     if (usePtr != NULL) {
  227. if (!(usePtr->flags & TK_CONTAINER)) {
  228.     Tcl_AppendResult(interp, "window "", usePtr->pathName,
  229.     "" doesn't have -container option set", NULL);
  230.     return TCL_ERROR;
  231. }
  232.     }
  233.     /*
  234.      * The code below can probably be simplified given we have already
  235.      * discovered 'usePtr' above.
  236.      */
  237.     /*
  238.      * Save information about the container and the embedded window
  239.      * in a Container structure. Currently, there must already be an existing
  240.      * Container structure, since we only allow the case where both container
  241.      * and embedded app. are in the same process.
  242.      */
  243.     for (containerPtr = firstContainerPtr; containerPtr != NULL;
  244.     containerPtr = containerPtr->nextPtr) {
  245. if (containerPtr->parent == (Window) parent) {
  246.     winPtr->flags |= TK_BOTH_HALVES;
  247.     containerPtr->parentPtr->flags |= TK_BOTH_HALVES;
  248.     break;
  249. }
  250.     }
  251.     /*
  252.      * Make the embedded window.
  253.      */
  254.     macWin = (MacDrawable *) ckalloc(sizeof(MacDrawable));
  255.     if (macWin == NULL) {
  256. winPtr->privatePtr = NULL;
  257. return TCL_ERROR;
  258.     }
  259.     macWin->winPtr = winPtr;
  260.     winPtr->privatePtr = macWin;
  261.     /*
  262.      * The grafPtr will be NULL for a Tk in Tk embedded window.
  263.      * It is none of our business what it is for a Tk not in Tk embedded window,
  264.      * but we will initialize it to NULL, and let the registerWinProc
  265.      * set it. In any case, you must always use TkMacOSXGetDrawablePort
  266.      * to get the portPtr. It will correctly find the container's port.
  267.      */
  268.     macWin->grafPtr = NULL;
  269.     macWin->context = NULL;
  270.     macWin->size = CGSizeZero;
  271.     macWin->visRgn = NULL;
  272.     macWin->aboveVisRgn = NULL;
  273.     macWin->drawRect = CGRectNull;
  274.     macWin->referenceCount = 0;
  275.     macWin->flags = TK_CLIP_INVALID;
  276.     macWin->toplevel = macWin;
  277.     macWin->toplevel->referenceCount++;
  278.     winPtr->flags |= TK_EMBEDDED;
  279.     /*
  280.      * Make a copy of the TK_EMBEDDED flag, since sometimes
  281.      * we need this to get the port after the TkWindow structure
  282.      * has been freed.
  283.      */
  284.     macWin->flags |= TK_EMBEDDED;
  285.     /*
  286.      * Now check whether it is embedded in another Tk widget. If not (the first
  287.      * case below) we see if there is an in-process embedding handler registered,
  288.      * and if so, let that fill in the rest of the macWin.
  289.      */
  290.     if (containerPtr == NULL) {
  291. /*
  292.  * If someone has registered an in process embedding handler, then
  293.  * see if it can handle this window...
  294.  */
  295. if (tkMacOSXEmbedHandler == NULL ||
  296. tkMacOSXEmbedHandler->registerWinProc((int) parent,
  297. (Tk_Window) winPtr) != TCL_OK) {
  298.     Tcl_AppendResult(interp, "The window ID ", string,
  299.     " does not correspond to a valid Tk Window.", NULL);
  300.     return TCL_ERROR;
  301. } else {
  302.     containerPtr = (Container *) ckalloc(sizeof(Container));
  303.     containerPtr->parentPtr = NULL;
  304.     containerPtr->embedded = (Window) macWin;
  305.     containerPtr->embeddedPtr = macWin->winPtr;
  306.     containerPtr->nextPtr = firstContainerPtr;
  307.     firstContainerPtr = containerPtr;
  308. }
  309.     } else {
  310. /*
  311.  * The window is embedded in another Tk window.
  312.  */
  313. macWin->xOff = parent->winPtr->privatePtr->xOff +
  314. parent->winPtr->changes.border_width +
  315. winPtr->changes.x;
  316. macWin->yOff = parent->winPtr->privatePtr->yOff +
  317. parent->winPtr->changes.border_width +
  318. winPtr->changes.y;
  319. /*
  320.  * Finish filling up the container structure with the embedded window's
  321.  * information.
  322.  */
  323. containerPtr->embedded = (Window) macWin;
  324. containerPtr->embeddedPtr = macWin->winPtr;
  325. /*
  326.  * Create an event handler to clean up the Container structure when
  327.  * tkwin is eventually deleted.
  328.  */
  329. Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbeddedEventProc,
  330. (ClientData) winPtr);
  331.     }
  332.     return TCL_OK;
  333. }
  334. /*
  335.  *----------------------------------------------------------------------
  336.  *
  337.  * TkpMakeContainer --
  338.  *
  339.  * This procedure is called to indicate that a particular window
  340.  * will be a container for an embedded application. This changes
  341.  * certain aspects of the window's behavior, such as whether it
  342.  * will receive events anymore.
  343.  *
  344.  * Results:
  345.  * None.
  346.  *
  347.  * Side effects:
  348.  * None.
  349.  *
  350.  *----------------------------------------------------------------------
  351.  */
  352. void
  353. TkpMakeContainer(
  354.     Tk_Window tkwin) /* Token for a window that is about to
  355.  * become a container. */
  356. {
  357.     TkWindow *winPtr = (TkWindow *) tkwin;
  358.     Container *containerPtr;
  359.     /*
  360.      * Register the window as a container so that, for example, we can
  361.      * make sure the argument to -use is valid.
  362.      */
  363.     Tk_MakeWindowExist(tkwin);
  364.     containerPtr = (Container *) ckalloc(sizeof(Container));
  365.     containerPtr->parent = Tk_WindowId(tkwin);
  366.     containerPtr->parentPtr = winPtr;
  367.     containerPtr->embedded = None;
  368.     containerPtr->embeddedPtr = NULL;
  369.     containerPtr->nextPtr = firstContainerPtr;
  370.     firstContainerPtr = containerPtr;
  371.     winPtr->flags |= TK_CONTAINER;
  372.     /*
  373.      * Request SubstructureNotify events so that we can find out when
  374.      * the embedded application creates its window or attempts to
  375.      * resize it. Also watch Configure events on the container so that
  376.      * we can resize the child to match. Also, pass activate events from
  377.      * the container down to the embedded toplevel.
  378.      */
  379.     Tk_CreateEventHandler(tkwin,
  380.     SubstructureNotifyMask|SubstructureRedirectMask,
  381.     ContainerEventProc, (ClientData) winPtr);
  382.     Tk_CreateEventHandler(tkwin, StructureNotifyMask, EmbedStructureProc,
  383.     (ClientData) containerPtr);
  384.     Tk_CreateEventHandler(tkwin, ActivateMask, EmbedActivateProc,
  385.     (ClientData) containerPtr);
  386.     Tk_CreateEventHandler(tkwin, FocusChangeMask, EmbedFocusProc,
  387.     (ClientData) containerPtr);
  388. }
  389. /*
  390.  *----------------------------------------------------------------------
  391.  *
  392.  * TkMacOSXContainerId --
  393.  *
  394.  * Given an embedded window, this procedure returns the MacDrawable
  395.  * identifier for the associated container window.
  396.  *
  397.  * Results:
  398.  * The return value is the MacDrawable for winPtr's
  399.  * container window.
  400.  *
  401.  * Side effects:
  402.  * None.
  403.  *
  404.  *----------------------------------------------------------------------
  405.  */
  406. MacDrawable *
  407. TkMacOSXContainerId(winPtr)
  408.     TkWindow *winPtr; /* Tk's structure for an embedded window. */
  409. {
  410.     Container *containerPtr;
  411.     for (containerPtr = firstContainerPtr; containerPtr != NULL;
  412.     containerPtr = containerPtr->nextPtr) {
  413. if (containerPtr->embeddedPtr == winPtr) {
  414.     return (MacDrawable *) containerPtr->parent;
  415. }
  416.     }
  417.     Tcl_Panic("TkMacOSXContainerId couldn't find window");
  418.     return None;
  419. }
  420. /*
  421.  *----------------------------------------------------------------------
  422.  *
  423.  * TkMacOSXGetHostToplevel --
  424.  *
  425.  * Given the TkWindow, return the MacDrawable for the outermost
  426.  * toplevel containing it. This will be a real Macintosh window.
  427.  *
  428.  * Results:
  429.  * Returns a MacDrawable corresponding to a Macintosh Toplevel
  430.  *
  431.  * Side effects:
  432.  * None.
  433.  *
  434.  *----------------------------------------------------------------------
  435.  */
  436. MacDrawable *
  437. TkMacOSXGetHostToplevel(
  438.     TkWindow *winPtr) /* Tk's structure for a window. */
  439. {
  440.     TkWindow *contWinPtr, *topWinPtr;
  441.     topWinPtr = winPtr->privatePtr->toplevel->winPtr;
  442.     if (!Tk_IsEmbedded(topWinPtr)) {
  443.     return winPtr->privatePtr->toplevel;
  444.     } else {
  445. contWinPtr = TkpGetOtherWindow(topWinPtr);
  446. /*
  447.  * TODO: Here we should handle out of process embedding.
  448.  */
  449. if (contWinPtr != NULL) {
  450.     return TkMacOSXGetHostToplevel(contWinPtr);
  451. } else {
  452.     return None;
  453. }
  454.     }
  455. }
  456. /*
  457.  *----------------------------------------------------------------------
  458.  *
  459.  * TkpClaimFocus --
  460.  *
  461.  * This procedure is invoked when someone asks for the input focus
  462.  * to be put on a window in an embedded application, but the
  463.  * application doesn't currently have the focus. It requests the
  464.  * input focus from the container application.
  465.  *
  466.  * Results:
  467.  * None.
  468.  *
  469.  * Side effects:
  470.  * The input focus may change.
  471.  *
  472.  *----------------------------------------------------------------------
  473.  */
  474. void
  475. TkpClaimFocus(
  476.     TkWindow *topLevelPtr, /* Top-level window containing desired
  477.  * focus window; should be embedded. */
  478.     int force) /* One means that the container should
  479.  * claim the focus if it doesn't
  480.  * currently have it. */
  481. {
  482.     XEvent event;
  483.     Container *containerPtr;
  484.     if (!(topLevelPtr->flags & TK_EMBEDDED)) {
  485. return;
  486.     }
  487.     for (containerPtr = firstContainerPtr;
  488.     containerPtr->embeddedPtr != topLevelPtr;
  489.     containerPtr = containerPtr->nextPtr) {
  490. /* Empty loop body. */
  491.     }
  492.     event.xfocus.type = FocusIn;
  493.     event.xfocus.serial = LastKnownRequestProcessed(topLevelPtr->display);
  494.     event.xfocus.send_event = 1;
  495.     event.xfocus.display = topLevelPtr->display;
  496.     event.xfocus.window = containerPtr->parent;
  497.     event.xfocus.mode = EMBEDDED_APP_WANTS_FOCUS;
  498.     event.xfocus.detail = force;
  499.     Tk_QueueWindowEvent(&event,TCL_QUEUE_TAIL);
  500. }
  501. /*
  502.  *----------------------------------------------------------------------
  503.  *
  504.  * TkpTestembedCmd --
  505.  *
  506.  * This procedure implements the "testembed" command. It returns
  507.  * some or all of the information in the list pointed to by
  508.  * firstContainerPtr.
  509.  *
  510.  * Results:
  511.  * A standard Tcl result.
  512.  *
  513.  * Side effects:
  514.  * None.
  515.  *
  516.  *----------------------------------------------------------------------
  517.  */
  518. int
  519. TkpTestembedCmd(
  520.     ClientData clientData, /* Main window for application. */
  521.     Tcl_Interp *interp, /* Current interpreter. */
  522.     int argc, /* Number of arguments. */
  523.     CONST char **argv) /* Argument strings. */
  524. {
  525.     int all;
  526.     Container *containerPtr;
  527.     Tcl_DString dString;
  528.     char buffer[50];
  529.     if ((argc > 1) && (strcmp(argv[1], "all") == 0)) {
  530. all = 1;
  531.     } else {
  532. all = 0;
  533.     }
  534.     Tcl_DStringInit(&dString);
  535.     for (containerPtr = firstContainerPtr; containerPtr != NULL;
  536.     containerPtr = containerPtr->nextPtr) {
  537. Tcl_DStringStartSublist(&dString);
  538. if (containerPtr->parent == None) {
  539.     Tcl_DStringAppendElement(&dString, "");
  540. } else {
  541.     if (all) {
  542. sprintf(buffer, "0x%x", (int) containerPtr->parent);
  543. Tcl_DStringAppendElement(&dString, buffer);
  544.     } else {
  545. Tcl_DStringAppendElement(&dString, "XXX");
  546.     }
  547. }
  548. if (containerPtr->parentPtr == NULL) {
  549.     Tcl_DStringAppendElement(&dString, "");
  550. } else {
  551.     Tcl_DStringAppendElement(&dString,
  552.     containerPtr->parentPtr->pathName);
  553. }
  554. if (containerPtr->embedded == None) {
  555.     Tcl_DStringAppendElement(&dString, "");
  556. } else {
  557.     if (all) {
  558. sprintf(buffer, "0x%x", (int) containerPtr->embedded);
  559. Tcl_DStringAppendElement(&dString, buffer);
  560.     } else {
  561. Tcl_DStringAppendElement(&dString, "XXX");
  562.     }
  563. }
  564. if (containerPtr->embeddedPtr == NULL) {
  565.     Tcl_DStringAppendElement(&dString, "");
  566. } else {
  567.     Tcl_DStringAppendElement(&dString,
  568.     containerPtr->embeddedPtr->pathName);
  569. }
  570. Tcl_DStringEndSublist(&dString);
  571.     }
  572.     Tcl_DStringResult(interp, &dString);
  573.     return TCL_OK;
  574. }
  575. /*
  576.  *----------------------------------------------------------------------
  577.  *
  578.  * TkpRedirectKeyEvent --
  579.  *
  580.  * This procedure is invoked when a key press or release event
  581.  * arrives for an application that does not believe it owns the
  582.  * input focus. This can happen because of embedding; for example,
  583.  * X can send an event to an embedded application when the real
  584.  * focus window is in the container application and is an ancestor
  585.  * of the container. This procedure's job is to forward the event
  586.  * back to the application where it really belongs.
  587.  *
  588.  * Results:
  589.  * None.
  590.  *
  591.  * Side effects:
  592.  * The event may get sent to a different application.
  593.  *
  594.  *----------------------------------------------------------------------
  595.  */
  596. void
  597. TkpRedirectKeyEvent(
  598.     TkWindow *winPtr, /* Window to which the event was originally
  599.  * reported. */
  600.     XEvent *eventPtr) /* X event to redirect (should be KeyPress
  601.  * or KeyRelease). */
  602. {
  603. }
  604. /*
  605.  *----------------------------------------------------------------------
  606.  *
  607.  * TkpGetOtherWindow --
  608.  *
  609.  * If both the container and embedded window are in the same
  610.  * process, this procedure will return either one, given the other.
  611.  *
  612.  * Results:
  613.  * If winPtr is a container, the return value is the token for the
  614.  * embedded window, and vice versa. If the "other" window isn't in
  615.  * this process, NULL is returned.
  616.  *
  617.  * Side effects:
  618.  * None.
  619.  *
  620.  *----------------------------------------------------------------------
  621.  */
  622. TkWindow *
  623. TkpGetOtherWindow(
  624.     TkWindow *winPtr) /* Tk's structure for a container or
  625.  * embedded window. */
  626. {
  627.     Container *containerPtr;
  628.     /*
  629.      * TkpGetOtherWindow returns NULL if both windows are not
  630.      * in the same process...
  631.      */
  632.     if (!(winPtr->flags & TK_BOTH_HALVES)) {
  633. return NULL;
  634.     }
  635.     for (containerPtr = firstContainerPtr; containerPtr != NULL;
  636.     containerPtr = containerPtr->nextPtr) {
  637. if (containerPtr->embeddedPtr == winPtr) {
  638.     return containerPtr->parentPtr;
  639. } else if (containerPtr->parentPtr == winPtr) {
  640.     return containerPtr->embeddedPtr;
  641. }
  642.     }
  643.     return NULL;
  644. }
  645. /*
  646.  *----------------------------------------------------------------------
  647.  *
  648.  * EmbeddedEventProc --
  649.  *
  650.  * This procedure is invoked by the Tk event dispatcher when various
  651.  * useful events are received for a window that is embedded in
  652.  * another application.
  653.  *
  654.  * Results:
  655.  * None.
  656.  *
  657.  * Side effects:
  658.  * Our internal state gets cleaned up when an embedded window is
  659.  * destroyed.
  660.  *
  661.  *----------------------------------------------------------------------
  662.  */
  663. static void
  664. EmbeddedEventProc(
  665.     ClientData clientData, /* Token for container window. */
  666.     XEvent *eventPtr) /* ResizeRequest event. */
  667. {
  668.     TkWindow *winPtr = (TkWindow *) clientData;
  669.     if (eventPtr->type == DestroyNotify) {
  670. EmbedWindowDeleted(winPtr);
  671.     }
  672. }
  673. /*
  674.  *----------------------------------------------------------------------
  675.  *
  676.  * ContainerEventProc --
  677.  *
  678.  * This procedure is invoked by the Tk event dispatcher when various
  679.  * useful events are received for the children of a container
  680.  * window. It forwards relevant information, such as geometry
  681.  * requests, from the events into the container's application.
  682.  *
  683.  * NOTE: on the Mac, only the DestroyNotify branch is ever taken.
  684.  * We don't synthesize the other events.
  685.  *
  686.  * Results:
  687.  * None.
  688.  *
  689.  * Side effects:
  690.  * Depends on the event. For example, when ConfigureRequest events
  691.  * occur, geometry information gets set for the container window.
  692.  *
  693.  *----------------------------------------------------------------------
  694.  */
  695. static void
  696. ContainerEventProc(
  697.     ClientData clientData, /* Token for container window. */
  698.     XEvent *eventPtr) /* ResizeRequest event. */
  699. {
  700.     TkWindow *winPtr = (TkWindow *) clientData;
  701.     Container *containerPtr;
  702.     Tk_ErrorHandler errHandler;
  703.     /*
  704.      * Ignore any X protocol errors that happen in this procedure
  705.      * (almost any operation could fail, for example, if the embedded
  706.      * application has deleted its window).
  707.      */
  708.     errHandler = Tk_CreateErrorHandler(eventPtr->xfocus.display, -1,
  709.     -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL);
  710.     /*
  711.      * Find the Container structure associated with the parent window.
  712.      */
  713.     for (containerPtr = firstContainerPtr;
  714.     containerPtr->parent != eventPtr->xmaprequest.parent;
  715.     containerPtr = containerPtr->nextPtr) {
  716. if (containerPtr == NULL) {
  717.     Tcl_Panic("ContainerEventProc couldn't find Container record");
  718. }
  719.     }
  720.     if (eventPtr->type == CreateNotify) {
  721. /*
  722.  * A new child window has been created in the container. Record
  723.  * its id in the Container structure (if more than one child is
  724.  * created, just remember the last one and ignore the earlier
  725.  * ones).
  726.  */
  727. containerPtr->embedded = eventPtr->xcreatewindow.window;
  728.     } else if (eventPtr->type == ConfigureRequest) {
  729. if ((eventPtr->xconfigurerequest.x != 0)
  730. || (eventPtr->xconfigurerequest.y != 0)) {
  731.     /*
  732.      * The embedded application is trying to move itself, which
  733.      * isn't legal. At this point, the window hasn't actually
  734.      * moved, but we need to send it a ConfigureNotify event to
  735.      * let it know that its request has been denied. If the
  736.      * embedded application was also trying to resize itself, a
  737.      * ConfigureNotify will be sent by the geometry management
  738.      * code below, so we don't need to do anything. Otherwise,
  739.      * generate a synthetic event.
  740.      */
  741.     if ((eventPtr->xconfigurerequest.width == winPtr->changes.width)
  742.     && (eventPtr->xconfigurerequest.height
  743.     == winPtr->changes.height)) {
  744. EmbedSendConfigure(containerPtr);
  745.     }
  746. }
  747. EmbedGeometryRequest(containerPtr,
  748. eventPtr->xconfigurerequest.width,
  749. eventPtr->xconfigurerequest.height);
  750.     } else if (eventPtr->type == MapRequest) {
  751. /*
  752.  * The embedded application's map request was ignored and simply
  753.  * passed on to us, so we have to map the window for it to appear
  754.  * on the screen.
  755.  */
  756. XMapWindow(eventPtr->xmaprequest.display,
  757. eventPtr->xmaprequest.window);
  758.     } else if (eventPtr->type == DestroyNotify) {
  759. /*
  760.  * The embedded application is gone. Destroy the container window.
  761.  */
  762. Tk_DestroyWindow((Tk_Window) winPtr);
  763.     }
  764.     Tk_DeleteErrorHandler(errHandler);
  765. }
  766. /*
  767.  *----------------------------------------------------------------------
  768.  *
  769.  * EmbedStructureProc --
  770.  *
  771.  * This procedure is invoked by the Tk event dispatcher when
  772.  * a container window owned by this application gets resized
  773.  * (and also at several other times that we don't care about).
  774.  * This procedure reflects the size change in the embedded
  775.  * window that corresponds to the container.
  776.  *
  777.  * Results:
  778.  * None.
  779.  *
  780.  * Side effects:
  781.  * The embedded window gets resized to match the container.
  782.  *
  783.  *----------------------------------------------------------------------
  784.  */
  785. static void
  786. EmbedStructureProc(
  787.     ClientData clientData, /* Token for container window. */
  788.     XEvent *eventPtr) /* ResizeRequest event. */
  789. {
  790.     Container *containerPtr = (Container *) clientData;
  791.     Tk_ErrorHandler errHandler;
  792.     if (eventPtr->type == ConfigureNotify) {
  793. if (containerPtr->embedded != None) {
  794.     /*
  795.      * Ignore errors, since the embedded application could have
  796.      * deleted its window.
  797.      */
  798.     errHandler = Tk_CreateErrorHandler(eventPtr->xfocus.display, -1,
  799.     -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL);
  800.     Tk_MoveResizeWindow((Tk_Window) containerPtr->embeddedPtr, 0, 0,
  801.     (unsigned int) Tk_Width(
  802.     (Tk_Window) containerPtr->parentPtr),
  803.     (unsigned int) Tk_Height(
  804.     (Tk_Window) containerPtr->parentPtr));
  805.     Tk_DeleteErrorHandler(errHandler);
  806. }
  807.     } else if (eventPtr->type == DestroyNotify) {
  808. EmbedWindowDeleted(containerPtr->parentPtr);
  809.     }
  810. }
  811. /*
  812.  *----------------------------------------------------------------------
  813.  *
  814.  * EmbedActivateProc --
  815.  *
  816.  * This procedure is invoked by the Tk event dispatcher when
  817.  * Activate and Deactivate events occur for a container window owned
  818.  * by this application. It is responsible for forwarding an activate
  819.  * event down into the embedded toplevel.
  820.  *
  821.  * Results:
  822.  * None.
  823.  *
  824.  * Side effects:
  825.  * The X focus may change.
  826.  *
  827.  *----------------------------------------------------------------------
  828.  */
  829. static void
  830. EmbedActivateProc(
  831.     ClientData clientData, /* Token for container window. */
  832.     XEvent *eventPtr) /* ResizeRequest event. */
  833. {
  834.     Container *containerPtr = (Container *) clientData;
  835.     if (containerPtr->embeddedPtr != NULL) {
  836. if (eventPtr->type == ActivateNotify) {
  837.     TkGenerateActivateEvents(containerPtr->embeddedPtr,1);
  838. } else if (eventPtr->type == DeactivateNotify) {
  839.     TkGenerateActivateEvents(containerPtr->embeddedPtr,0);
  840. }
  841.     }
  842. }
  843. /*
  844.  *----------------------------------------------------------------------
  845.  *
  846.  * EmbedFocusProc --
  847.  *
  848.  * This procedure is invoked by the Tk event dispatcher when
  849.  * FocusIn and FocusOut events occur for a container window owned
  850.  * by this application. It is responsible for moving the focus
  851.  * back and forth between a container application and an embedded
  852.  * application.
  853.  *
  854.  * Results:
  855.  * None.
  856.  *
  857.  * Side effects:
  858.  * The X focus may change.
  859.  *
  860.  *----------------------------------------------------------------------
  861.  */
  862. static void
  863. EmbedFocusProc(
  864.     ClientData clientData, /* Token for container window. */
  865.     XEvent *eventPtr) /* ResizeRequest event. */
  866. {
  867.     Container *containerPtr = (Container *) clientData;
  868.     Display *display;
  869.     XEvent event;
  870.     if (containerPtr->embeddedPtr != NULL) {
  871.     display = Tk_Display(containerPtr->parentPtr);
  872. event.xfocus.serial = LastKnownRequestProcessed(display);
  873. event.xfocus.send_event = false;
  874. event.xfocus.display = display;
  875. event.xfocus.mode = NotifyNormal;
  876. event.xfocus.window = containerPtr->embedded;
  877.     if (eventPtr->type == FocusIn) {
  878. /*
  879.  * The focus just arrived at the container. Change the X focus
  880.  * to move it to the embedded application, if there is one.
  881.  * Ignore X errors that occur during this operation (it's
  882.  * possible that the new focus window isn't mapped).
  883.  */
  884.     event.xfocus.detail = NotifyNonlinear;
  885.     event.xfocus.type = FocusIn;
  886. } else if (eventPtr->type == FocusOut) {
  887. /* When the container gets a FocusOut event, it has to tell the embedded app
  888.  * that it has lost the focus.
  889.  */
  890.     event.xfocus.type = FocusOut;
  891.     event.xfocus.detail = NotifyNonlinear;
  892.  }
  893. Tk_QueueWindowEvent(&event, TCL_QUEUE_MARK);
  894.     }
  895. }
  896. /*
  897.  *----------------------------------------------------------------------
  898.  *
  899.  * EmbedGeometryRequest --
  900.  *
  901.  * This procedure is invoked when an embedded application requests
  902.  * a particular size. It processes the request (which may or may
  903.  * not actually honor the request) and reflects the results back
  904.  * to the embedded application.
  905.  *
  906.  * NOTE: On the Mac, this is a stub, since we don't synthesize
  907.  * ConfigureRequest events.
  908.  *
  909.  * Results:
  910.  * None.
  911.  *
  912.  * Side effects:
  913.  * If we deny the child's size change request, a Configure event
  914.  * is synthesized to let the child know how big it ought to be.
  915.  * Events get processed while we're waiting for the geometry
  916.  * managers to do their thing.
  917.  *
  918.  *----------------------------------------------------------------------
  919.  */
  920. static void
  921. EmbedGeometryRequest(
  922.     Container *containerPtr, /* Information about the embedding. */
  923.     int width, int height) /* Size that the child has requested. */
  924. {
  925.     TkWindow *winPtr = containerPtr->parentPtr;
  926.     /*
  927.      * Forward the requested size into our geometry management hierarchy
  928.      * via the container window. We need to send a Configure event back
  929.      * to the embedded application if we decide not to honor its
  930.      * request; to make this happen, process all idle event handlers
  931.      * synchronously here (so that the geometry managers have had a
  932.      * chance to do whatever they want to do), and if the window's size
  933.      * didn't change then generate a configure event.
  934.      */
  935.     Tk_GeometryRequest((Tk_Window) winPtr, width, height);
  936.     while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {
  937. /* Empty loop body. */
  938.     }
  939.     if ((winPtr->changes.width != width)
  940.     || (winPtr->changes.height != height)) {
  941. EmbedSendConfigure(containerPtr);
  942.     }
  943. }
  944. /*
  945.  *----------------------------------------------------------------------
  946.  *
  947.  * EmbedSendConfigure --
  948.  *
  949.  * This is currently a stub. It is called to notify an
  950.  * embedded application of its current size and location. This
  951.  * procedure is called when the embedded application made a
  952.  * geometry request that we did not grant, so that the embedded
  953.  * application knows that its geometry didn't change after all.
  954.  * It is a response to ConfigureRequest events, which we do not
  955.  * currently synthesize on the Mac
  956.  *
  957.  * Results:
  958.  * None.
  959.  *
  960.  * Side effects:
  961.  * None.
  962.  *
  963.  *----------------------------------------------------------------------
  964.  */
  965. static void
  966. EmbedSendConfigure(
  967.     Container *containerPtr) /* Information about the embedding. */
  968. {
  969. }
  970. /*
  971.  *----------------------------------------------------------------------
  972.  *
  973.  * EmbedWindowDeleted --
  974.  *
  975.  * This procedure is invoked when a window involved in embedding
  976.  * (as either the container or the embedded application) is
  977.  * destroyed. It cleans up the Container structure for the window.
  978.  *
  979.  * Results:
  980.  * None.
  981.  *
  982.  * Side effects:
  983.  * A Container structure may be freed.
  984.  *
  985.  *----------------------------------------------------------------------
  986.  */
  987. static void
  988. EmbedWindowDeleted(
  989.     TkWindow *winPtr) /* Tk's information about window that
  990.  * was deleted. */
  991. {
  992.     Container *containerPtr, *prevPtr;
  993.     /*
  994.      * Find the Container structure for this window. Delete the
  995.      * information about the embedded application and free the container's
  996.      * record.
  997.      */
  998.     prevPtr = NULL;
  999.     containerPtr = firstContainerPtr;
  1000.     while (1) {
  1001. if (containerPtr->embeddedPtr == winPtr) {
  1002.     /*
  1003.      * We also have to destroy our parent, to clean up the container.
  1004.      * Fabricate an event to do this.
  1005.      */
  1006.     if (containerPtr->parentPtr != NULL &&
  1007.     containerPtr->parentPtr->flags & TK_BOTH_HALVES) {
  1008. XEvent event;
  1009. event.xany.serial =
  1010.     Tk_Display(containerPtr->parentPtr)->request;
  1011.     event.xany.send_event = False;
  1012.     event.xany.display = Tk_Display(containerPtr->parentPtr);
  1013.     event.xany.type = DestroyNotify;
  1014.     event.xany.window = containerPtr->parent;
  1015.     event.xdestroywindow.event = containerPtr->parent;
  1016.     Tk_QueueWindowEvent(&event, TCL_QUEUE_HEAD);
  1017.     }
  1018.     containerPtr->embedded = None;
  1019.     containerPtr->embeddedPtr = NULL;
  1020.     break;
  1021. }
  1022. if (containerPtr->parentPtr == winPtr) {
  1023.     containerPtr->parentPtr = NULL;
  1024.     break;
  1025. }
  1026. prevPtr = containerPtr;
  1027. containerPtr = containerPtr->nextPtr;
  1028.     }
  1029.     if ((containerPtr->embeddedPtr == NULL)
  1030.     && (containerPtr->parentPtr == NULL)) {
  1031. if (prevPtr == NULL) {
  1032.     firstContainerPtr = containerPtr->nextPtr;
  1033. } else {
  1034.     prevPtr->nextPtr = containerPtr->nextPtr;
  1035. }
  1036. ckfree((char *) containerPtr);
  1037.     }
  1038. }