home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / mac / tkMacEmbed.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  32.7 KB  |  1,165 lines  |  [TEXT/CWIE]

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