summaryrefslogtreecommitdiffstats
path: root/tk8.6/win/tkWinEmbed.c
diff options
context:
space:
mode:
Diffstat (limited to 'tk8.6/win/tkWinEmbed.c')
-rw-r--r--tk8.6/win/tkWinEmbed.c1118
1 files changed, 1118 insertions, 0 deletions
diff --git a/tk8.6/win/tkWinEmbed.c b/tk8.6/win/tkWinEmbed.c
new file mode 100644
index 0000000..8bfd295
--- /dev/null
+++ b/tk8.6/win/tkWinEmbed.c
@@ -0,0 +1,1118 @@
+/*
+ * 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 =
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+
+ for (; tsdPtr->firstContainerPtr != NULL;
+ tsdPtr->firstContainerPtr = nextPtr) {
+ nextPtr = tsdPtr->firstContainerPtr->nextPtr;
+ ckfree(tsdPtr->firstContainerPtr);
+ }
+ tsdPtr->firstContainerPtr = 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 objc,
+ Tcl_Obj *const objv[])
+{
+ 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_SetObjResult(interp, Tcl_NewStringObj(
+ "can't modify container after widget is created", -1));
+ Tcl_SetErrorCode(interp, "TK", "EMBED", "POST_CREATE", NULL);
+ return TCL_ERROR;
+ }
+*/
+
+ if (strcmp(string, "") == 0) {
+ if (winPtr->flags & TK_EMBEDDED) {
+ Tk_DetachEmbeddedWindow(winPtr, TRUE);
+ }
+ return TCL_OK;
+ }
+
+ if (
+#ifdef _WIN64
+ (sscanf(string, "0x%p", &hwnd) != 1) &&
+#endif
+ Tcl_GetInt(interp, string, (int *) &hwnd) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ 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_SetObjResult(interp, Tcl_ObjPrintf(
+ "window \"%s\" doesn't exist", string));
+ Tcl_SetErrorCode(interp, "TK", "EMBED", "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_SetObjResult(interp, Tcl_NewStringObj(
+ "The container is already in use", -1));
+ Tcl_SetErrorCode(interp, "TK", "EMBED", "IN_USE", NULL);
+ return TCL_ERROR;
+ }
+ } else if (id == -PTR2INT(hwnd)) {
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
+ "the window to use is not a Tk container", -1));
+ Tcl_SetErrorCode(interp, "TK", "EMBED", "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 == MessageBoxA(hwnd, msg, "Tk Warning",
+ MB_OKCANCEL | MB_ICONWARNING)) {
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
+ "Operation has been canceled", -1));
+ Tcl_SetErrorCode(interp, "TK", "EMBED", "CANCEL", NULL);
+ 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 = 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(containerPtr);
+ }
+}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 4
+ * fill-column: 78
+ * End:
+ */