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

通讯编程

开发平台:

Visual C++

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