1112 lines
30 KiB
C
1112 lines
30 KiB
C
/*
|
||
* 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 (
|
||
#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_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:
|
||
*/
|