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

通讯编程

开发平台:

Visual C++

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