text: /*
   * tkWinEmbed.c --
   *
   *	This file contains platform specific procedures for Windows platforms
   *	to provide basic operations needed for application embedding (where
   *	one application can use as its main window an internal window from
   *	another application).
   *
   * Copyright (c) 1996-1997 Sun Microsystems, Inc.
   *
   * See the file "license.terms" for information on usage and redistribution of
   * this file, and for a DISCLAIMER OF ALL WARRANTIES.
   */
  
  #include "tkWinInt.h"
  
  /*
   * One of the following structures exists for each container in this
   * application. It keeps track of the container window and its associated
   * embedded window.
   */
  
  typedef struct Container {
      HWND parentHWnd;		/* Windows HWND to the parent window */
      TkWindow *parentPtr;	/* Tk's information about the container or
  				 * NULL if the container isn't in this
  				 * process. */
      HWND embeddedHWnd;		/* Windows HWND to the embedded window. */
      TkWindow *embeddedPtr;	/* Tk's information about the embedded window,
  				 * or NULL if the embedded application isn't
  				 * in this process. */
      HWND embeddedMenuHWnd;	/* Tk's embedded menu window handler. */
      struct Container *nextPtr;	/* Next in list of all containers in this
  				 * process. */
  } Container;
  
  typedef struct ThreadSpecificData {
      Container *firstContainerPtr;
  				/* First in list of all containers managed by
  				 * this process. */
  } ThreadSpecificData;
  static Tcl_ThreadDataKey dataKey;
  
  static void		ContainerEventProc(ClientData clientData,
  			    XEvent *eventPtr);
  static void		EmbedGeometryRequest(Container *containerPtr,
  			    int width, int height);
  static void		EmbedWindowDeleted(TkWindow *winPtr);
  static void		Tk_MapEmbeddedWindow(TkWindow* winPtr);
  HWND			Tk_GetEmbeddedHWnd(TkWindow* winPtr);
  
  /*
   *----------------------------------------------------------------------
   *
   * TkWinCleanupContainerList --
   *
   *	Finalizes the list of containers.
   *
   * Results:
   *	None.
   *
   * Side effects:
   *	Releases memory occupied by containers of embedded windows.
   *
   *----------------------------------------------------------------------
   */
  
  void
  TkWinCleanupContainerList(void)
  {
      Container *nextPtr;
      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
  	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  
      for (; tsdPtr->firstContainerPtr != (Container *) NULL;
  	    tsdPtr->firstContainerPtr = nextPtr) {
  	nextPtr = tsdPtr->firstContainerPtr->nextPtr;
  	ckfree((char *) tsdPtr->firstContainerPtr);
      }
      tsdPtr->firstContainerPtr = (Container *) NULL;
  }
  
  /*
   *----------------------------------------------------------------------
   *
   * TkpTestembedCmd --
   *
   *	Test command for the embedding facility.
   *
   * Results:
   *	Always returns TCL_OK.
   *
   * Side effects:
   *	Currently it does not do anything.
   *
   *----------------------------------------------------------------------
   */
  
  	/* ARGSUSED */
  int
  TkpTestembedCmd(
      ClientData clientData,
      Tcl_Interp *interp,
      int argc,
      CONST char **argv)
  {
      return TCL_OK;
  }
  
  /*
   *----------------------------------------------------------------------
   *
   * Tk_DetachEmbeddedWindow --
   *
   *	This function detaches an embedded window
   *
   * Results:
   *	No return value. Detach the embedded window.
   *
   * Side effects:
   *	None.
   *
   *----------------------------------------------------------------------
   */
  
  static
  void
  Tk_DetachEmbeddedWindow(
      TkWindow *winPtr,		/* an embedded window */
      BOOL detachFlag)		/* a flag of truely detaching */
  {
      TkpWinToplevelDetachWindow(winPtr);
      if(detachFlag) {
  	TkpWinToplevelOverrideRedirect(winPtr, 0);
      }
  }
  
  /*
   *----------------------------------------------------------------------
   *
   * Tk_MapEmbeddedWindow --
   *
   *	This function is required for mapping an embedded window during idle.
   *	The input winPtr must be preserved using Tcl_Preserve before call this
   *	function and will be released by this function.
   *
   * Results:
   *	No return value. Map the embedded window if it is not dead.
   *
   * Side effects:
   *	The embedded window may change its state as the container's.
   *
   *----------------------------------------------------------------------
   */
  
  static
  void Tk_MapEmbeddedWindow(
      TkWindow *winPtr)		/* Top-level window that's about to be
  				 * mapped. */
  {
      if(!(winPtr->flags & TK_ALREADY_DEAD)) {
  	HWND hwnd = (HWND)winPtr->privatePtr;
  	int state = SendMessage(hwnd, TK_STATE, -1, -1) - 1;
  
  	if (state < 0 || state > 3) {
  	    state = NormalState;
  	}
  
  	while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {
  	    /* empty body */
  	}
  
  	TkpWmSetState(winPtr, state);
  	TkWmMapWindow(winPtr);
      }
      Tcl_Release((ClientData)winPtr);
  }
  
  /*
   *----------------------------------------------------------------------
   *
   * TkpUseWindow --
   *
   *	This procedure causes a Tk window to use a given Windows handle for a
   *	window as its underlying window, rather than a new Windows window
   *	being created automatically. It is invoked by an embedded application
   *	to specify the window in which the application is embedded.
   *
   *	This procedure uses a simple attachment protocol by sending TK_INFO
   *	messages to the window to use with two sub messages:
   *
   *	    TK_CONTAINER_VERIFY - if a window handles this message, it should
   *		return either a (long)hwnd for a container or a -(long)hwnd
   *		for a non-container.
   *
   *	    TK_CONTAINER_ISAVAILABLE - a container window should return either
   *		a TRUE (non-zero) if it is available for use or a FALSE (zero)
   *		othersize.
   *
   *	The TK_INFO messages are required in order to verify if the window to
   *	use is a valid container. Without an id verification, an invalid
   *	window attachment may cause unexpected crashes/panics (bug 1096074).
   *	Additional sub messages may be definded/used in future for other
   *	needs.
   *
   *	We do not enforce the above protocol for the reason of backward
   *	compatibility. If the window to use is unable to handle TK_INFO
   *	messages (e.g., legacy Tk container applications before 8.5), a dialog
   *	box with a warning message pops up and the user is asked to confirm if
   *	the attachment should proceed. However, we may have to enforce it in
   *	future.
   *
   * Results:
   *	The return value is normally TCL_OK. If an error occurred (such as if
   *	the argument does not identify a legal Windows window handle or it is
   *	already in use or a cancel button is pressed by a user in confirming
   *	the use window as a Tk container) the return value is TCL_ERROR and an
   *	error message is left in the the interp's result if interp is not
   *	NULL.
   *
   * Side effects:
   *	None.
   *
   *----------------------------------------------------------------------
   */
  
  int
  TkpUseWindow(
      Tcl_Interp *interp,		/* If not NULL, used for error reporting if
  				 * string is bogus. */
      Tk_Window tkwin,		/* Tk window that does not yet have an
  				 * associated X window. */
      CONST char *string)		/* String identifying an X window to use for
  				 * tkwin; must be an integer value. */
  {
      TkWindow *winPtr = (TkWindow *) tkwin;
      int id;
      HWND hwnd;
  /*
      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
  	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  */
  
  /*
      if (winPtr->window != None) {
  	Tcl_AppendResult(interp,
  		"can't modify container after widget is created", NULL);
  	return TCL_ERROR;
      }
  */
  
      if (strcmp(string, "") == 0) {
  	if (winPtr->flags & TK_EMBEDDED) {
  	    Tk_DetachEmbeddedWindow(winPtr, TRUE);
  	}
  	return TCL_OK;
      }
  
      if (Tcl_GetInt(interp, string, &id) != TCL_OK) {
  	return TCL_ERROR;
      }
      hwnd = (HWND) INT2PTR(id);
      if ((HWND)winPtr->privatePtr == hwnd) {
  	return TCL_OK;
      }
  
      /*
       * Check if the window is a valid handle. If it is invalid, return
       * TCL_ERROR and potentially leave an error message in the interp's
       * result.
       */
  
      if (!IsWindow(hwnd)) {
  	if (interp != NULL) {
  	    Tcl_AppendResult(interp, "window \"", string,
  		    "\" doesn't exist", NULL);
  	}
  	return TCL_ERROR;
      }
  
      id = SendMessage(hwnd, TK_INFO, TK_CONTAINER_VERIFY, 0);
      if (id == PTR2INT(hwnd)) {
  	if (!SendMessage(hwnd, TK_INFO, TK_CONTAINER_ISAVAILABLE, 0)) {
      	    Tcl_AppendResult(interp, "The container is already in use", NULL);
  	    return TCL_ERROR;
  	}
      } else if (id == -PTR2INT(hwnd)) {
  	Tcl_AppendResult(interp, "the window to use is not a Tk container",
  		NULL);
  	return TCL_ERROR;
      } else {
  	/*
  	 * Proceed if the user decide to do so because it can be a legacy
  	 * container application. However we may have to return a TCL_ERROR in
  	 * order to avoid bug 1096074 in future.
  	 */
  
  	char msg[256];
  
  	sprintf(msg, "Unable to get information of window \"%.80s\".  Attach to this\nwindow may have unpredictable results if it is not a valid container.\n\nPress Ok to proceed or Cancel to abort attaching.", string);
  	if (IDCANCEL == MessageBox(hwnd, msg, "Tk Warning",
  		MB_OKCANCEL | MB_ICONWARNING)) {
      	    Tcl_SetResult(interp, "Operation has been canceled", TCL_STATIC);
  	    return TCL_ERROR;
  	}
      }
  
      Tk_DetachEmbeddedWindow(winPtr, FALSE);
  
      /*
       * Store the parent window in the platform private data slot so
       * TkWmMapWindow can use it when creating the wrapper window.
       */
  
      winPtr->privatePtr = (struct TkWindowPrivate*) hwnd;
      winPtr->flags |= TK_EMBEDDED;
      winPtr->flags &= ~(TK_MAPPED);
  
      /*
       * Preserve the winPtr and create an idle handler to map the embedded
       * window.
       */
  
      Tcl_Preserve((ClientData) winPtr);
      Tcl_DoWhenIdle((Tcl_IdleProc*) Tk_MapEmbeddedWindow, (ClientData) winPtr);
  
      return TCL_OK;
  }
  
  /*
   *----------------------------------------------------------------------
   *
   * TkpMakeContainer --
   *
   *	This procedure is called to indicate that a particular window will be
   *	a container for an embedded application. This changes certain aspects
   *	of the window's behavior, such as whether it will receive events
   *	anymore.
   *
   * Results:
   *	None.
   *
   * Side effects:
   *	None.
   *
   *----------------------------------------------------------------------
   */
  
  void
  TkpMakeContainer(
      Tk_Window tkwin)
  {
      TkWindow *winPtr = (TkWindow *) tkwin;
      Container *containerPtr;
      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
  	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  
      /*
       * Register the window as a container so that, for example, we can find
       * out later if the embedded app. is in the same process.
       */
  
      Tk_MakeWindowExist(tkwin);
      containerPtr = (Container *) ckalloc(sizeof(Container));
      containerPtr->parentPtr = winPtr;
      containerPtr->parentHWnd = Tk_GetHWND(Tk_WindowId(tkwin));
      containerPtr->embeddedHWnd = NULL;
      containerPtr->embeddedPtr = NULL;
      containerPtr->embeddedMenuHWnd = NULL;
      containerPtr->nextPtr = tsdPtr->firstContainerPtr;
      tsdPtr->firstContainerPtr = containerPtr;
      winPtr->flags |= TK_CONTAINER;
  
      /*
       * Unlike in tkUnixEmbed.c, we don't make any requests for events in the
       * embedded window here. Now we just allow the embedding of another TK
       * application into TK windows. When the embedded window makes a request,
       * that will be done by sending to the container window a WM_USER message,
       * which will be intercepted by TkWinContainerProc.
       *
       * We need to get structure events of the container itself, though.
       */
  
      Tk_CreateEventHandler(tkwin, StructureNotifyMask,
  	    ContainerEventProc, (ClientData) containerPtr);
  }
  
  /*
   *----------------------------------------------------------------------
   *
   * TkWinEmbeddedEventProc --
   *
   *	This procedure is invoked by the Tk event dispatcher when various
   *	useful events are received for the *children* of a container window.
   *	It forwards relevant information, such as geometry requests, from the
   *	events into the container's application.
   *
   * Results:
   *	None.
   *
   * Side effects:
   *	Depends on the event. For example, when ConfigureRequest events occur,
   *	geometry information gets set for the container window.
   *
   *----------------------------------------------------------------------
   */
  
  LRESULT
  TkWinEmbeddedEventProc(
      HWND hwnd,
      UINT message,
      WPARAM wParam,
      LPARAM lParam)
  {
      int result = 1;
      Container *containerPtr;
      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
  	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  
      /*
       * Find the Container structure associated with the parent window.
       */
  
      for (containerPtr = tsdPtr->firstContainerPtr;
  	    containerPtr && containerPtr->parentHWnd != hwnd;
  	    containerPtr = containerPtr->nextPtr) {
  	/* empty loop body */
      }
  
      if (containerPtr) {
  	TkWindow *topwinPtr = NULL;
  	if(Tk_IsTopLevel(containerPtr->parentPtr)) {
  	    topwinPtr = containerPtr->parentPtr;
  	}
  	switch (message) {
  	case TK_INFO:
  	    /*
  	     * An embedded window may send this message for container
  	     * verification and availability before attach.
  	     *
  	     * wParam - a sub message
  	     *
  	     *	    TK_CONTAINER_ISAVAILABLE - if the container is available
  	     *		for use?
  	     *		result = 1 for yes and 0 for no;
  	     *
  	     *	    TK_CONTAINER_VERIFY - request the container to verify its
  	     *		identification
  	     *		result =  (long)hwnd if this window is a container
  	     *			 -(long)hwnd otherwise
  	     *
  	     * lParam - N/A
  	     */
  
  	    switch(wParam) {
  	    case TK_CONTAINER_ISAVAILABLE:
  		result = containerPtr->embeddedHWnd == NULL? 1:0;
  		break;
  	    case TK_CONTAINER_VERIFY:
  		result = PTR2INT(containerPtr->parentHWnd);
  		break;
  	    default:
  		result = 0;
  	    }
  	    break;
  
  	case TK_ATTACHWINDOW:
  	    /*
  	     * An embedded window (either from this application or from
  	     * another application) is trying to attach to this container. We
  	     * attach it only if this container is not yet containing any
  	     * window.
  	     *
  	     * wParam - a handle of an embedded window
  	     * lParam - N/A
  	     *
  	     * An embedded window may send this message with a wParam of NULL
  	     * to test if a window is able to provide embedding service. The
  	     * container returns its window handle for accepting the
  	     * attachment and identifying itself or a zero for being already
  	     * in use.
  	     *
  	     * Return value:
  	     * 0    - the container is unable to be used.
  	     * hwnd - the container is ready to be used.
  	     */
  	    if (containerPtr->embeddedHWnd == NULL) {
  		if (wParam) {
  		    TkWindow *winPtr = (TkWindow *)
  			    Tk_HWNDToWindow((HWND) wParam);
  		    if (winPtr) {
  			winPtr->flags |= TK_BOTH_HALVES;
  			containerPtr->embeddedPtr = winPtr;
  			containerPtr->parentPtr->flags |= TK_BOTH_HALVES;
  		    }
  		    containerPtr->embeddedHWnd = (HWND)wParam;
  		}
  		result = PTR2INT(containerPtr->parentHWnd);
  	    } else {
  		result = 0;
  	    }
  	    break;
  
  	case TK_DETACHWINDOW:
  	    /*
  	     * An embedded window notifies the container that it is detached.
  	     * The container should clearn the related variables and redraw
  	     * its window.
  	     *
  	     * wParam - N/A
  	     * lParam - N/A
  	     *
  	     * Return value:
  	     * 0	- the message is not processed.
  	     * others	- the message is processed.
  	     */
  
  	    containerPtr->embeddedMenuHWnd = NULL;
  	    containerPtr->embeddedHWnd = NULL;
  	    containerPtr->parentPtr->flags &= ~TK_BOTH_HALVES;
  	    if (topwinPtr) {
  		TkWinSetMenu((Tk_Window) topwinPtr, 0);
  	    }
  	    InvalidateRect(hwnd, NULL, TRUE);
  	    break;
  
  	case TK_GEOMETRYREQ:
  	    /*
  	     * An embedded window requests a window size change.
  	     *
  	     * wParam - window width
  	     * lParam - window height
  	     *
  	     * Return value:
  	     * 0	- the message is not processed.
  	     * others	- the message is processed.
  	     */
  
  	    EmbedGeometryRequest(containerPtr, (int)wParam, lParam);
  	    break;
  
  	case TK_RAISEWINDOW:
  	    /*
  	     * An embedded window requests to change its Z-order.
  	     *
  	     * wParam - a window handle as a z-order stack reference
  	     * lParam - a flag of above-below: 0 - above; 1 or others: - below
  	     *
  	     * Return value:
  	     * 0	- the message is not processed.
  	     * others	- the message is processed.
  	     */
  
  	    TkWinSetWindowPos(GetParent(containerPtr->parentHWnd),
  		    (HWND)wParam, (int)lParam);
  	    break;
  
  	case TK_GETFRAMEWID:
  	    /*
  	     * An embedded window requests to get the frame window's id.
  	     *
  	     * wParam - N/A
  	     * lParam - N/A
  	     *
  	     * Return vlaue:
  	     *
  	     * A handle of the frame window. If it is not availble, a zero is
  	     * returned.
  	     */
  	    if (topwinPtr) {
  		result = PTR2INT(GetParent(containerPtr->parentHWnd));
  	    } else {
  		topwinPtr = containerPtr->parentPtr;
  		while (!(topwinPtr->flags & TK_TOP_HIERARCHY)) {
  		    topwinPtr = topwinPtr->parentPtr;
  		}
  		if (topwinPtr && topwinPtr->window) {
  		    result = PTR2INT(GetParent(Tk_GetHWND(topwinPtr->window)));
  		} else {
  		    result = 0;
  		}
  	    }
  	    break;
  
  	case TK_CLAIMFOCUS:
  	    /*
  	     * An embedded window requests a focus.
  	     *
  	     * wParam - a flag of forcing focus
  	     * lParam - N/A
  	     *
  	     * Return value:
  	     * 0    - the message is not processed
  	     * 1    - the message is processed
  	     */
  
  	    if (!SetFocus(containerPtr->embeddedHWnd) && wParam) {
  		/*
  		 * forcing focus TBD
  		 */
  	    }
  	    break;
  
  	case TK_WITHDRAW:
  	    /*
  	     * An embedded window requests withdraw.
  	     *
  	     * wParam	- N/A
  	     * lParam	- N/A
  	     *
  	     * Return value
  	     * 0    - the message is not processed
  	     * 1    - the message is processed
  	     */
  
  	    if (topwinPtr) {
  		TkpWinToplevelWithDraw(topwinPtr);
  	    } else {
  		result = 0;
  	    }
  	    break;
  
  	case TK_ICONIFY:
  	    /*
  	     * An embedded window requests iconification.
  	     *
  	     * wParam	- N/A
  	     * lParam	- N/A
  	     *
  	     * Return value
  	     * 0    - the message is not processed
  	     * 1    - the message is processed
  	     */
  
  	    if (topwinPtr) {
  		TkpWinToplevelIconify(topwinPtr);
  	    } else {
  		result = 0;
  	    }
  	    break;
  
  	case TK_DEICONIFY:
  	    /*
  	     * An embedded window requests deiconification.
  	     *
  	     * wParam	- N/A
  	     * lParam	- N/A
  	     *
  	     * Return value
  	     * 0    - the message is not processed
  	     * 1    - the message is processed
  	     */
  	    if (topwinPtr) {
  		TkpWinToplevelDeiconify(topwinPtr);
  	    } else {
  		result = 0;
  	    }
  	    break;
  
  	case TK_MOVEWINDOW:
  	    /*
  	     * An embedded window requests to move position if both wParam and
  	     * lParam are greater or equal to 0.
  	     *	    wParam - x value of the frame's upper left
  	     *	    lParam - y value of the frame's upper left
  	     *
  	     * Otherwise an embedded window requests the current position
  	     *
  	     * Return value: an encoded window position in a 32bit long, i.e,
  	     * ((x << 16) & 0xffff0000) | (y & 0xffff)
  	     *
  	     * Only a toplevel container may move the embedded.
  	     */
  
  	    result = TkpWinToplevelMove(containerPtr->parentPtr,
  		    wParam, lParam);
  	    break;
  
  	case TK_OVERRIDEREDIRECT:
  	    /*
  	     * An embedded window request overrideredirect.
  	     *
  	     * wParam
  	     *	0	- add a frame if there is no one
  	     *  1	- remove the frame if there is a one
  	     *  < 0	- query the current overrideredirect value
  	     *
  	     * lParam	- N/A
  	     *
  	     * Return value:
  	     * 1 + the current value of overrideredirect if the container is a
  	     * toplevel. Otherwise 0.
  	     */
  	    if (topwinPtr) {
  		result = 1 + TkpWinToplevelOverrideRedirect(topwinPtr, wParam);
  	    } else {
  		result = 0;
  	    }
  	    break;
  
  	case TK_SETMENU:
  	    /*
  	     * An embedded requests to set a menu.
  	     *
  	     * wParam	- a menu handle
  	     * lParam	- a menu window handle
  	     *
  	     * Return value:
  	     * 1    - the message is processed
  	     * 0    - the message is not processed
  	     */
  	    if (topwinPtr) {
  		containerPtr->embeddedMenuHWnd = (HWND)lParam;
  		TkWinSetMenu((Tk_Window)topwinPtr, (HMENU)wParam);
  	    } else {
  		result = 0;
  	    }
  	    break;
  
  	case TK_STATE:
  	    /*
  	     * An embedded window request set/get state services.
  	     *
  	     * wParam	- service directive
  	     *	    0 - 3 for setting state
  	     *		0 - withdrawn state
  	     *		1 - normal state
  	     *		2 - zoom state
  	     *		3 - icon state
  	     * others for gettting state
  	     *
  	     * lParam	- N/A
  	     *
  	     * Return value
  	     * 1 + the current state or 0 if the container is not a toplevel
  	     */
  
  	    if (topwinPtr) {
  		if (wParam <= 3) {
  		    TkpWmSetState(topwinPtr, wParam);
  		}
  		result = 1+TkpWmGetState(topwinPtr);
  	    } else {
  		result = 0;
  	    }
  	    break;
  
  	    /*
  	     * Return 0 since the current Tk container implementation is
  	     * unable to provide following services.
  	     */
  	default:
  	    result = 0;
  	    break;
  	}
      } else {
  	if ((message == TK_INFO) && (wParam == TK_CONTAINER_VERIFY)) {
  	    /*
  	     * Reply the message sender: this is not a Tk container
  	     */
  
  	    return -PTR2INT(hwnd);
  	} else {
  	    result = 0;
  	}
      }
  
      return result;
  }
  
  /*
   *----------------------------------------------------------------------
   *
   * EmbedGeometryRequest --
   *
   *	This procedure is invoked when an embedded application requests a
   *	particular size. It processes the request (which may or may not
   *	actually resize the window) and reflects the results back to the
   *	embedded application.
   *
   * Results:
   *	None.
   *
   * Side effects:
   *	If we deny the child's size change request, a Configure event is
   *	synthesized to let the child know that the size is the same as it used
   *	to be. Events get processed while we're waiting for the geometry
   *	managers to do their thing.
   *
   *----------------------------------------------------------------------
   */
  
  void
  EmbedGeometryRequest(
      Container *containerPtr,	/* Information about the container window. */
      int width, int height)	/* Size that the child has requested. */
  {
      TkWindow *winPtr = containerPtr->parentPtr;
  
      /*
       * Forward the requested size into our geometry management hierarchy via
       * the container window. We need to send a Configure event back to the
       * embedded application even if we decide not to resize the window; to
       * make this happen, process all idle event handlers synchronously here
       * (so that the geometry managers have had a chance to do whatever they
       * want to do), and if the window's size didn't change then generate a
       * configure event.
       */
  
      Tk_GeometryRequest((Tk_Window)winPtr, width, height);
  
      if (containerPtr->embeddedHWnd != NULL) {
  	while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {
  	    /* Empty loop body. */
  	}
  
  	SetWindowPos(containerPtr->embeddedHWnd, NULL, 0, 0,
  		winPtr->changes.width, winPtr->changes.height, SWP_NOZORDER);
      }
  }
  
  /*
   *----------------------------------------------------------------------
   *
   * ContainerEventProc --
   *
   *	This procedure is invoked by the Tk event dispatcher when various
   *	useful events are received for the container window.
   *
   * Results:
   *	None.
   *
   * Side effects:
   *	Depends on the event. For example, when ConfigureRequest events occur,
   *	geometry information gets set for the container window.
   *
   *----------------------------------------------------------------------
   */
  
  static void
  ContainerEventProc(
      ClientData clientData,	/* Token for container window. */
      XEvent *eventPtr)		/* ResizeRequest event. */
  {
      Container *containerPtr = (Container *)clientData;
      Tk_Window tkwin = (Tk_Window)containerPtr->parentPtr;
  
      if (eventPtr->type == ConfigureNotify) {
  	/*
  	 * Resize the embedded window, if there is any.
  	 */
  
  	if (containerPtr->embeddedHWnd) {
  	    SetWindowPos(containerPtr->embeddedHWnd, NULL, 0, 0,
  		    Tk_Width(tkwin), Tk_Height(tkwin), SWP_NOZORDER);
  	}
      } else if (eventPtr->type == DestroyNotify) {
  	/*
  	 * The container is gone, remove it from the list.
  	 */
  
  	EmbedWindowDeleted(containerPtr->parentPtr);
      }
  }
  
  /*
   *----------------------------------------------------------------------
   *
   * TkpGetOtherWindow --
   *
   *	If both the container and embedded window are in the same process,
   *	this procedure will return either one, given the other.
   *
   * Results:
   *	If winPtr is a container, the return value is the token for the
   *	embedded window, and vice versa. If the "other" window isn't in this
   *	process, NULL is returned.
   *
   * Side effects:
   *	None.
   *
   *----------------------------------------------------------------------
   */
  
  TkWindow *
  TkpGetOtherWindow(
      TkWindow *winPtr)		/* Tk's structure for a container or embedded
  				 * window. */
  {
      Container *containerPtr;
      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
  	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  
      for (containerPtr = tsdPtr->firstContainerPtr; containerPtr != NULL;
  	    containerPtr = containerPtr->nextPtr) {
  	if (containerPtr->embeddedPtr == winPtr) {
  	    return containerPtr->parentPtr;
  	} else if (containerPtr->parentPtr == winPtr) {
  	    return containerPtr->embeddedPtr;
  	}
      }
      return NULL;
  }
  
  /*
   *----------------------------------------------------------------------
   *
   * Tk_GetEmbeddedHWnd --
   *
   *	This function returns the embedded window id.
   *
   * Results:
   *	If winPtr is a container, the return value is the HWND for the
   *	embedded window. Otherwise it returns NULL.
   *
   * Side effects:
   *	None.
   *
   *----------------------------------------------------------------------
   */
  
  HWND
  Tk_GetEmbeddedHWnd(
      TkWindow *winPtr)
  {
      Container *containerPtr;
      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
  	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  
      for (containerPtr = tsdPtr->firstContainerPtr; containerPtr != NULL;
  	    containerPtr = containerPtr->nextPtr) {
  	if (containerPtr->parentPtr == winPtr) {
  	    return containerPtr->embeddedHWnd;
  	}
      }
      return NULL;
  }
  
  /*
   *----------------------------------------------------------------------
   *
   * Tk_GetEmbeddedMenuHWND --
   *
   *	This function returns the embedded menu window id.
   *
   * Results:
   *	If winPtr is a container, the return value is the HWND for the
   *	embedded menu window. Otherwise it returns NULL.
   *
   * Side effects:
   *	None.
   *
   *----------------------------------------------------------------------
   */
  
  HWND
  Tk_GetEmbeddedMenuHWND(
      Tk_Window tkwin)
  {
      TkWindow *winPtr = (TkWindow*)tkwin;
      Container *containerPtr;
      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
  	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  
      for (containerPtr = tsdPtr->firstContainerPtr; containerPtr != NULL;
  	    containerPtr = containerPtr->nextPtr) {
  	if (containerPtr->parentPtr == winPtr) {
  	    return containerPtr->embeddedMenuHWnd;
  	}
      }
      return NULL;
  }
  
  /*
   *----------------------------------------------------------------------
   *
   * TkpClaimFocus --
   *
   *	This procedure is invoked when someone asks or the input focus to be
   *	put on a window in an embedded application, but the application
   *	doesn't currently have the focus. It requests the input focus from the
   *	container application.
   *
   * Results:
   *	None.
   *
   * Side effects:
   *	The input focus may change.
   *
   *----------------------------------------------------------------------
   */
  
  void
  TkpClaimFocus(
      TkWindow *topLevelPtr,	/* Top-level window containing desired focus
  				 * window; should be embedded. */
      int force)			/* One means that the container should claim
  				 * the focus if it doesn't currently have
  				 * it. */
  {
      HWND hwnd = GetParent(Tk_GetHWND(topLevelPtr->window));
      SendMessage(hwnd, TK_CLAIMFOCUS, (WPARAM) force, 0);
  }
  
  /*
   *----------------------------------------------------------------------
   *
   * TkpRedirectKeyEvent --
   *
   *	This procedure is invoked when a key press or release event arrives
   *	for an application that does not believe it owns the input focus.
   *	This can happen because of embedding; for example, X can send an event
   *	to an embedded application when the real focus window is in the
   *	container application and is an ancestor of the container. This
   *	procedure's job is to forward the event back to the application where
   *	it really belongs.
   *
   * Results:
   *	None.
   *
   * Side effects:
   *	The event may get sent to a different application.
   *
   *----------------------------------------------------------------------
   */
  
  void
  TkpRedirectKeyEvent(
      TkWindow *winPtr,		/* Window to which the event was originally
  				 * reported. */
      XEvent *eventPtr)		/* X event to redirect (should be KeyPress or
  				 * KeyRelease). */
  {
      /* not implemented */
  }
  
  /*
   *----------------------------------------------------------------------
   *
   * EmbedWindowDeleted --
   *
   *	This procedure is invoked when a window involved in embedding (as
   *	either the container or the embedded application) is destroyed. It
   *	cleans up the Container structure for the window.
   *
   * Results:
   *	None.
   *
   * Side effects:
   *	A Container structure may be freed.
   *
   *----------------------------------------------------------------------
   */
  
  static void
  EmbedWindowDeleted(
      TkWindow *winPtr)		/* Tk's information about window that was
  				 * deleted. */
  {
      Container *containerPtr, *prevPtr;
      ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
  	    Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
  
      /*
       * Find the Container structure for this window work. Delete the
       * information about the embedded application and free the container's
       * record. The main container may be null. [Bug #476176]
       */
  
      prevPtr = NULL;
      containerPtr = tsdPtr->firstContainerPtr;
      if (containerPtr == NULL) return;
      while (1) {
  	if (containerPtr->embeddedPtr == winPtr) {
  	    containerPtr->embeddedHWnd = NULL;
  	    containerPtr->embeddedPtr = NULL;
  	    break;
  	}
  	if (containerPtr->parentPtr == winPtr) {
  	    SendMessage(containerPtr->embeddedHWnd, WM_CLOSE, 0, 0);
  	    containerPtr->parentPtr = NULL;
  	    containerPtr->embeddedPtr = NULL;
  	    break;
  	}
  	prevPtr = containerPtr;
  	containerPtr = containerPtr->nextPtr;
  	if (containerPtr == NULL) {
  	    return;
  	}
      }
      if ((containerPtr->embeddedPtr == NULL)
  	    && (containerPtr->parentPtr == NULL)) {
  	if (prevPtr == NULL) {
  	    tsdPtr->firstContainerPtr = containerPtr->nextPtr;
  	} else {
  	    prevPtr->nextPtr = containerPtr->nextPtr;
  	}
  	ckfree((char *) containerPtr);
      }
  }
  
  /*
   * Local Variables:
   * mode: c
   * c-basic-offset: 4
   * fill-column: 78
   * End:
   */
  