* to the window manager.
*
* Copyright (c) 1995-1997 Sun Microsystems, Inc.
- * Copyright (c) 1998 by Scriptics Corporation.
+ * Copyright (c) 1998-2000 by Scriptics Corporation.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
char *clientMachine; /* String to store in WM_CLIENT_MACHINE
* property, or NULL. */
int flags; /* Miscellaneous flags, defined below. */
+ int numTransients; /* number of transients on this window */
struct TkWmInfo *nextPtr; /* Next in list of all top-level windows. */
} WmInfo;
* pixels up from bottom of screen, rather than
* down from top.
* WM_UPDATE_SIZE_HINTS - non-zero means that new size hints need to be
- * propagated to window manager.
+ * propagated to window manager. Not used on Win.
* WM_SYNC_PENDING - set to non-zero while waiting for the window
* manager to respond to some state change.
* WM_MOVE_PENDING - non-zero means the application has requested
#define WM_TRANSIENT_STYLE \
(WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_CLIPSIBLINGS|CS_DBLCLKS)
-/* CYGNUS LOCAL: We don't want WS_EX_TOOLWINDOW for most of our
- transient windows. If necessary, we can add some option to set
- this.
- #define EX_TRANSIENT_STYLE (WS_EX_TOOLWINDOW | WS_EX_DLGMODALFRAME)
- We also don't use WS_EX_DLGMODALFRAME. Using this doesn't give any
- obvious benefit. However, it does have a drawback: if the window
- is marked as not resizable, then use of WS_EX_DLGMODALFRAME will
- cause the resize items on the window's system menu to remain
- active. No, I don't understand.
- */
-#define EX_TRANSIENT_STYLE (0)
-
-/*
- * This module keeps a list of all top-level windows.
- */
-
-static WmInfo *firstWmPtr = NULL; /* Points to first top-level window. */
-static WmInfo *foregroundWmPtr = NULL; /* Points to the foreground window. */
-
-/*
- * The variable below is used to enable or disable tracing in this
- * module. If tracing is enabled, then information is printed on
- * standard output about interesting interactions with the window
- * manager.
- */
-
-static int wmTracing = 0;
+#define EX_TRANSIENT_STYLE \
+ (WS_EX_TOOLWINDOW|WS_EX_DLGMODALFRAME)
/*
* The following structure is the official type record for geometry
(Tk_GeomLostSlaveProc *) NULL, /* lostSlaveProc */
};
-/*
- * Global system palette. This value always refers to the currently
- * installed foreground logical palette.
- */
-
-static HPALETTE systemPalette = NULL;
+typedef struct ThreadSpecificData {
+ HPALETTE systemPalette; /* System palette; refers to the
+ * currently installed foreground logical
+ * palette. */
+ TkWindow *createWindow; /* Window that is being constructed. This
+ * value is set immediately before a
+ * call to CreateWindowEx, and is used
+ * by SetLimits. This is a gross hack
+ * needed to work around Windows brain
+ * damage where it sends the
+ * WM_GETMINMAXINFO message before the
+ * WM_CREATE window. */
+ int initialized; /* Flag indicating whether thread-
+ * specific elements of module have
+ * been initialized. */
+ int firstWindow; /* Flag, cleared when the first window
+ * is mapped in a non-iconic state. */
+} ThreadSpecificData;
+static Tcl_ThreadDataKey dataKey;
/*
- * Window that is being constructed. This value is set immediately
- * before a call to CreateWindowEx, and is used by SetLimits.
- * This is a gross hack needed to work around Windows brain damage
- * where it sends the WM_GETMINMAXINFO message before the WM_CREATE
- * window.
+ * The following variables cannot be placed in thread local storage
+ * because they must be shared across threads.
*/
-static TkWindow *createWindow = NULL;
+static WNDCLASS toplevelClass; /* Class for toplevel windows. */
+static int initialized; /* Flag indicating whether module has
+ * been initialized. */
+TCL_DECLARE_MUTEX(winWmMutex)
-/*
- * Flag indicating whether this module has been initialized yet.
- */
-
-static int initialized = 0;
-
-/*
- * Class for toplevel windows.
- */
-
-static WNDCLASS toplevelClass;
-
-/*
- * This flag is cleared when the first window is mapped in a non-iconic
- * state.
- */
-
-static int firstWindow = 1;
/*
* Forward declarations for procedures defined in this file:
Colormap colormap));
static int ParseGeometry _ANSI_ARGS_((Tcl_Interp *interp,
char *string, TkWindow *winPtr));
-static void RefreshColormap _ANSI_ARGS_((Colormap colormap));
+static void RefreshColormap _ANSI_ARGS_((Colormap colormap,
+ TkDisplay *dispPtr));
static void SetLimits _ANSI_ARGS_((HWND hwnd, MINMAXINFO *info));
static LRESULT CALLBACK TopLevelProc _ANSI_ARGS_((HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam));
static void UpdateWrapper _ANSI_ARGS_((TkWindow *winPtr));
static LRESULT CALLBACK WmProc _ANSI_ARGS_((HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam));
+static void WmWaitVisibilityProc _ANSI_ARGS_((
+ ClientData clientData, XEvent *eventPtr));
\f
/*
*----------------------------------------------------------------------
static void
InitWm(void)
{
- if (initialized) {
- return;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+ WNDCLASS * classPtr;
+
+ if (! tsdPtr->initialized) {
+ tsdPtr->initialized = 1;
+ tsdPtr->firstWindow = 1;
}
- initialized = 1;
-
- toplevelClass.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC;
- toplevelClass.cbClsExtra = 0;
- toplevelClass.cbWndExtra = 0;
- toplevelClass.hInstance = Tk_GetHINSTANCE();
- toplevelClass.hbrBackground = NULL;
- toplevelClass.lpszMenuName = NULL;
- toplevelClass.lpszClassName = TK_WIN_TOPLEVEL_CLASS_NAME;
- toplevelClass.lpfnWndProc = WmProc;
- /* CYGNUS LOCAL: First try the application's resource file. If
- that fails, then try the Tk DLL. */
- toplevelClass.hIcon = LoadIcon (GetModuleHandle (NULL), "tk");
- if (toplevelClass.hIcon == NULL)
- toplevelClass.hIcon = LoadIcon(Tk_GetHINSTANCE(), "tk");
- toplevelClass.hCursor = LoadCursor(NULL, IDC_ARROW);
-
- if (!RegisterClass(&toplevelClass)) {
- panic("Unable to register TkTopLevel class");
+ if (! initialized) {
+ Tcl_MutexLock(&winWmMutex);
+ if (! initialized) {
+ initialized = 1;
+ classPtr = &toplevelClass;
+
+ /*
+ * When threads are enabled, we cannot use CLASSDC because
+ * threads will then write into the same device context.
+ *
+ * This is a hack; we should add a subsystem that manages
+ * device context on a per-thread basis. See also tkWinX.c,
+ * which also initializes a WNDCLASS structure.
+ */
+
+#ifdef TCL_THREADS
+ classPtr->style = CS_HREDRAW | CS_VREDRAW;
+#else
+ classPtr->style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC;
+#endif
+ classPtr->cbClsExtra = 0;
+ classPtr->cbWndExtra = 0;
+ classPtr->hInstance = Tk_GetHINSTANCE();
+ classPtr->hbrBackground = NULL;
+ classPtr->lpszMenuName = NULL;
+ classPtr->lpszClassName = TK_WIN_TOPLEVEL_CLASS_NAME;
+ classPtr->lpfnWndProc = WmProc;
+ classPtr->hIcon = LoadIcon(Tk_GetHINSTANCE(), "tk");
+ classPtr->hCursor = LoadCursor(NULL, IDC_ARROW);
+
+ if (!RegisterClass(classPtr)) {
+ panic("Unable to register TkTopLevel class");
+ }
+ }
+ Tcl_MutexUnlock(&winWmMutex);
}
}
\f
GetTopLevel(hwnd)
HWND hwnd;
{
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+
/*
* If this function is called before the CreateWindowEx call
* has completed, then the user data slot will not have been
* set yet, so we use the global createWindow variable.
*/
- if (createWindow) {
- return createWindow;
+ if (tsdPtr->createWindow) {
+ return tsdPtr->createWindow;
}
return (TkWindow *) GetWindowLong(hwnd, GWL_USERDATA);
}
TkWinWmCleanup(hInstance)
HINSTANCE hInstance;
{
- if (!initialized) {
+ ThreadSpecificData *tsdPtr;
+
+ /*
+ * If we're using stubs to access the Tcl library, and they
+ * haven't been initialized, we can't call Tcl_GetThreadData.
+ */
+
+#ifdef USE_TCL_STUBS
+ if (tclStubsPtr == NULL) {
return;
}
- initialized = 0;
+#endif
+
+ tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+
+ if (!tsdPtr->initialized) {
+ return;
+ }
+ tsdPtr->initialized = 0;
UnregisterClass(TK_WIN_TOPLEVEL_CLASS_NAME, hInstance);
}
wmPtr->cmapList = NULL;
wmPtr->cmapCount = 0;
+ wmPtr->numTransients = 0;
wmPtr->configWidth = -1;
wmPtr->configHeight = -1;
wmPtr->cmdArgv = NULL;
wmPtr->clientMachine = NULL;
wmPtr->flags = WM_NEVER_MAPPED;
- wmPtr->nextPtr = firstWmPtr;
- firstWmPtr = wmPtr;
+ wmPtr->nextPtr = winPtr->dispPtr->firstWmPtr;
+ winPtr->dispPtr->firstWmPtr = wmPtr;
/*
* Tk must monitor structure events for top-level windows, in order
HWND child = TkWinGetHWND(winPtr->window);
int x, y, width, height, state;
WINDOWPLACEMENT place;
+ Tcl_DString titleString;
+ int *childStateInfo = NULL;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
parentHWND = NULL;
- child = TkWinGetHWND(winPtr->window);
+ child = TkWinGetHWND(winPtr->window);
if (winPtr->flags & TK_EMBEDDED) {
wmPtr->wrapper = (HWND) winPtr->privatePtr;
* Pick the decorative frame style. Override redirect windows get
* created as undecorated popups. Transient windows get a modal
* dialog frame. Neither override, nor transient windows appear in
- * the Win95 taskbar. Note that a transient window does not resize
+ * the Windows taskbar. Note that a transient window does not resize
* by default, so we need to explicitly add the WS_THICKFRAME style
* if we want it to be resizeable.
*/
-
+
if (winPtr->atts.override_redirect) {
wmPtr->style = WM_OVERRIDE_STYLE;
wmPtr->exStyle = EX_OVERRIDE_STYLE;
wmPtr->exStyle = EX_TOPLEVEL_STYLE;
}
- /* CYGNUS LOCAL: nonresizable windows have no maximize box,
- and no "sizebox". */
if ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE)
- && (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE)) {
+ && (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE)) {
wmPtr->style &= ~ (WS_MAXIMIZEBOX | WS_SIZEBOX);
}
* pick a location.
*/
-
if (!(wmPtr->sizeHintsFlags & (USPosition | PPosition))
&& (wmPtr->flags & WM_NEVER_MAPPED)) {
x = CW_USEDEFAULT;
* to the TkWindow.
*/
- createWindow = winPtr;
+ tsdPtr->createWindow = winPtr;
+ Tcl_UtfToExternalDString(NULL, wmPtr->titleUid, -1, &titleString);
wmPtr->wrapper = CreateWindowEx(wmPtr->exStyle,
TK_WIN_TOPLEVEL_CLASS_NAME,
- wmPtr->titleUid, wmPtr->style, x, y, width, height,
- parentHWND, NULL, Tk_GetHINSTANCE(), NULL);
+ Tcl_DStringValue(&titleString), wmPtr->style, x, y, width,
+ height, parentHWND, NULL, Tk_GetHINSTANCE(), NULL);
+ Tcl_DStringFree(&titleString);
SetWindowLong(wmPtr->wrapper, GWL_USERDATA, (LONG) winPtr);
- createWindow = NULL;
+ tsdPtr->createWindow = NULL;
place.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(wmPtr->wrapper, &place);
&& (oldWrapper != GetDesktopWindow())) {
SetWindowLong(oldWrapper, GWL_USERDATA, (LONG) NULL);
+ if (wmPtr->numTransients > 0) {
+ /*
+ * Unset the current wrapper as the parent for all transient
+ * children for whom this is the master
+ */
+ WmInfo *wmPtr2;
+
+ childStateInfo = (int *)ckalloc((unsigned) wmPtr->numTransients
+ * sizeof(int));
+ state = 0;
+ for (wmPtr2 = winPtr->dispPtr->firstWmPtr; wmPtr2 != NULL;
+ wmPtr2 = wmPtr2->nextPtr) {
+ if (wmPtr2->masterPtr == winPtr) {
+ if (!(wmPtr2->flags & WM_NEVER_MAPPED)) {
+ childStateInfo[state++] = wmPtr2->hints.initial_state;
+ SetParent(TkWinGetHWND(wmPtr2->winPtr->window), NULL);
+ }
+ }
+ }
+ }
/*
* Remove the menubar before destroying the window so the menubar
* isn't destroyed.
SetMenu(oldWrapper, NULL);
DestroyWindow(oldWrapper);
}
+
wmPtr->flags &= ~WM_NEVER_MAPPED;
SendMessage(wmPtr->wrapper, TK_ATTACHWINDOW, (WPARAM) child, 0);
wmPtr->flags &= ~WM_SYNC_PENDING;
}
+ if (childStateInfo) {
+ if (wmPtr->numTransients > 0) {
+ /*
+ * Reset all transient children for whom this is the master
+ */
+ WmInfo *wmPtr2;
+
+ state = 0;
+ for (wmPtr2 = winPtr->dispPtr->firstWmPtr; wmPtr2 != NULL;
+ wmPtr2 = wmPtr2->nextPtr) {
+ if (wmPtr2->masterPtr == winPtr) {
+ if (!(wmPtr2->flags & WM_NEVER_MAPPED)) {
+ UpdateWrapper(wmPtr2->winPtr);
+ TkpWmSetState(wmPtr2->winPtr, childStateInfo[state++]);
+ }
+ }
+ }
+ }
+
+ ckfree((char *) childStateInfo);
+ }
+
/*
* If this is the first window created by the application, then
* we should activate the initial window.
*/
- if (firstWindow) {
- firstWindow = 0;
+ if (tsdPtr->firstWindow) {
+ tsdPtr->firstWindow = 0;
SetActiveWindow(wmPtr->wrapper);
}
}
* be mapped. */
{
register WmInfo *wmPtr = winPtr->wmInfoPtr;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- if (!initialized) {
+ if (!tsdPtr->initialized) {
InitWm();
}
{
WmInfo *wmPtr = winPtr->wmInfoPtr;
int cmd;
-
- if (wmPtr->flags & WM_NEVER_MAPPED) {
+
+ if ((wmPtr->flags & WM_NEVER_MAPPED) ||
+ (wmPtr->masterPtr && !Tk_IsMapped(wmPtr->masterPtr))) {
wmPtr->hints.initial_state = state;
return;
}
} else if (state == ZoomState) {
cmd = SW_SHOWMAXIMIZED;
}
+
ShowWindow(wmPtr->wrapper, cmd);
wmPtr->flags &= ~WM_SYNC_PENDING;
}
* Clean up event related window info.
*/
- if (firstWmPtr == wmPtr) {
- firstWmPtr = wmPtr->nextPtr;
+ if (winPtr->dispPtr->firstWmPtr == wmPtr) {
+ winPtr->dispPtr->firstWmPtr = wmPtr->nextPtr;
} else {
register WmInfo *prevPtr;
- for (prevPtr = firstWmPtr; ; prevPtr = prevPtr->nextPtr) {
+ for (prevPtr = winPtr->dispPtr->firstWmPtr; ;
+ prevPtr = prevPtr->nextPtr) {
if (prevPtr == NULL) {
panic("couldn't unlink window in TkWmDeadWindow");
}
* Reset all transient windows whose master is the dead window.
*/
- for (wmPtr2 = firstWmPtr; wmPtr2 != NULL; wmPtr2 = wmPtr2->nextPtr) {
+ for (wmPtr2 = winPtr->dispPtr->firstWmPtr; wmPtr2 != NULL;
+ wmPtr2 = wmPtr2->nextPtr) {
if (wmPtr2->masterPtr == winPtr) {
wmPtr2->masterPtr = NULL;
if ((wmPtr2->wrapper != None)
if (wmPtr->flags & WM_UPDATE_PENDING) {
Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
}
+ if (wmPtr->masterPtr != NULL) {
+ wmPtr2 = wmPtr->masterPtr->wmInfoPtr;
+ /*
+ * If we had a master, tell them that we aren't tied
+ * to them anymore
+ */
+ if (wmPtr2 != NULL) {
+ wmPtr2->numTransients--;
+ }
+ Tk_DeleteEventHandler((Tk_Window) wmPtr->masterPtr,
+ VisibilityChangeMask,
+ WmWaitVisibilityProc, (ClientData) winPtr);
+ wmPtr->masterPtr = NULL;
+ }
/*
* Destroy the decorative frame window.
char **argv; /* Argument strings. */
{
Tk_Window tkwin = (Tk_Window) clientData;
- TkWindow *winPtr;
+ TkWindow *winPtr = NULL;
register WmInfo *wmPtr;
int c;
size_t length;
+ TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
if (argc < 2) {
wrongNumArgs:
return TCL_ERROR;
}
if (argc == 2) {
- interp->result = (wmTracing) ? "on" : "off";
+ Tcl_SetResult(interp, ((dispPtr->wmTracing) ? "on" : "off"),
+ TCL_STATIC);
return TCL_OK;
}
- return Tcl_GetBoolean(interp, argv[2], &wmTracing);
+ return Tcl_GetBoolean(interp, argv[2], &dispPtr->wmTracing);
}
if (argc < 3) {
}
if (argc == 3) {
if (wmPtr->sizeHintsFlags & PAspect) {
- sprintf(interp->result, "%d %d %d %d", wmPtr->minAspect.x,
+ char buf[TCL_INTEGER_SPACE * 4];
+
+ sprintf(buf, "%d %d %d %d", wmPtr->minAspect.x,
wmPtr->minAspect.y, wmPtr->maxAspect.x,
wmPtr->maxAspect.y);
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
}
return TCL_OK;
}
}
if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) ||
(denom2 <= 0)) {
- interp->result = "aspect number can't be <= 0";
+ Tcl_SetResult(interp, "aspect number can't be <= 0",
+ TCL_STATIC);
return TCL_ERROR;
}
wmPtr->minAspect.x = numer1;
}
if (argc == 3) {
if (wmPtr->clientMachine != NULL) {
- interp->result = wmPtr->clientMachine;
+ Tcl_SetResult(interp, wmPtr->clientMachine, TCL_STATIC);
}
return TCL_OK;
}
* Now we need to force the updated colormaps to be installed.
*/
- if (wmPtr == foregroundWmPtr) {
+ if (wmPtr == winPtr->dispPtr->foregroundWmPtr) {
InstallColormaps(wmPtr->wrapper, WM_QUERYNEWPALETTE, 1);
} else {
InstallColormaps(wmPtr->wrapper, WM_PALETTECHANGED, 0);
}
if (argc == 3) {
if (wmPtr->cmdArgv != NULL) {
- interp->result = Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv);
- interp->freeProc = TCL_DYNAMIC;
+ Tcl_SetResult(interp,
+ Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv),
+ TCL_DYNAMIC);
}
return TCL_OK;
}
": it is an embedded window", (char *) NULL);
return TCL_ERROR;
}
- TkpWmSetState(winPtr, NormalState);
+ /*
+ * If WM_UPDATE_PENDING is true, a pending UpdateGeometryInfo may
+ * need to be called first to update a withdrew toplevel's geometry
+ * before it is deiconified by TkpWmSetState.
+ * Don't bother if we've never been mapped.
+ */
+ if (wmPtr->flags & WM_UPDATE_PENDING) {
+ Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
+ UpdateGeometryInfo((ClientData) winPtr);
+ }
+
+ /*
+ * If we were in the ZoomState (maximized), 'wm deiconify'
+ * should not cause the window to shrink
+ */
+ if (wmPtr->hints.initial_state == ZoomState) {
+ TkpWmSetState(winPtr, ZoomState);
+ } else {
+ TkpWmSetState(winPtr, NormalState);
+ }
+
+ /*
+ * Follow Windows-like style here, raising the window to the top.
+ */
+ TkWmRestackToplevel(winPtr, Above, NULL);
+ if (!(Tk_Attributes((Tk_Window) winPtr)->override_redirect)) {
+ TkSetFocusWin(winPtr, 1);
+ }
} else if ((c == 'f') && (strncmp(argv[1], "focusmodel", length) == 0)
&& (length >= 2)) {
if ((argc != 3) && (argc != 4)) {
return TCL_ERROR;
}
if (argc == 3) {
- interp->result = wmPtr->hints.input ? "passive" : "active";
+ Tcl_SetResult(interp, (wmPtr->hints.input ? "passive" : "active"),
+ TCL_STATIC);
return TCL_OK;
}
c = argv[3][0];
} else if ((c == 'f') && (strncmp(argv[1], "frame", length) == 0)
&& (length >= 2)) {
HWND hwnd;
+ char buf[TCL_INTEGER_SPACE];
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
if (hwnd == NULL) {
hwnd = Tk_GetHWND(Tk_WindowId((Tk_Window) winPtr));
}
- sprintf(interp->result, "0x%x", (unsigned int) hwnd);
+ sprintf(buf, "0x%x", (unsigned int) hwnd);
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
} else if ((c == 'g') && (strncmp(argv[1], "geometry", length) == 0)
&& (length >= 2)) {
char xSign, ySign;
return TCL_ERROR;
}
if (argc == 3) {
+ char buf[16 + TCL_INTEGER_SPACE * 4];
+
xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+';
ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+';
if (wmPtr->gridWin != NULL) {
width = winPtr->changes.width;
height = winPtr->changes.height;
}
- sprintf(interp->result, "%dx%d%c%d%c%d", width, height,
- xSign, wmPtr->x, ySign, wmPtr->y);
+ sprintf(buf, "%dx%d%c%d%c%d", width, height, xSign, wmPtr->x,
+ ySign, wmPtr->y);
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
return TCL_OK;
}
if (*argv[3] == '\0') {
}
if (argc == 3) {
if (wmPtr->sizeHintsFlags & PBaseSize) {
- sprintf(interp->result, "%d %d %d %d", wmPtr->reqGridWidth,
+ char buf[TCL_INTEGER_SPACE * 4];
+
+ sprintf(buf, "%d %d %d %d", wmPtr->reqGridWidth,
wmPtr->reqGridHeight, wmPtr->widthInc,
wmPtr->heightInc);
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
}
return TCL_OK;
}
return TCL_ERROR;
}
if (reqWidth < 0) {
- interp->result = "baseWidth can't be < 0";
+ Tcl_SetResult(interp, "baseWidth can't be < 0", TCL_STATIC);
return TCL_ERROR;
}
if (reqHeight < 0) {
- interp->result = "baseHeight can't be < 0";
+ Tcl_SetResult(interp, "baseHeight can't be < 0", TCL_STATIC);
return TCL_ERROR;
}
if (widthInc < 0) {
- interp->result = "widthInc can't be < 0";
+ Tcl_SetResult(interp, "widthInc can't be < 0", TCL_STATIC);
return TCL_ERROR;
}
if (heightInc < 0) {
- interp->result = "heightInc can't be < 0";
+ Tcl_SetResult(interp, "heightInc can't be < 0", TCL_STATIC);
return TCL_ERROR;
}
Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc,
}
if (argc == 3) {
if (wmPtr->hints.flags & WindowGroupHint) {
- interp->result = wmPtr->leaderName;
+ Tcl_SetResult(interp, wmPtr->leaderName, TCL_STATIC);
}
return TCL_OK;
}
}
if (argc == 3) {
if (wmPtr->hints.flags & IconPixmapHint) {
- interp->result = Tk_NameOfBitmap(winPtr->display,
- wmPtr->hints.icon_pixmap);
+ Tcl_SetResult(interp,
+ Tk_NameOfBitmap(winPtr->display,
+ wmPtr->hints.icon_pixmap), TCL_STATIC);
}
return TCL_OK;
}
}
if (argc == 3) {
if (wmPtr->hints.flags & IconMaskHint) {
- interp->result = Tk_NameOfBitmap(winPtr->display,
- wmPtr->hints.icon_mask);
+ Tcl_SetResult(interp,
+ Tk_NameOfBitmap(winPtr->display, wmPtr->hints.icon_mask),
+ TCL_STATIC);
}
return TCL_OK;
}
return TCL_ERROR;
}
if (argc == 3) {
- interp->result = (wmPtr->iconName != NULL) ? wmPtr->iconName : "";
+ Tcl_SetResult(interp,
+ ((wmPtr->iconName != NULL) ? wmPtr->iconName : ""),
+ TCL_STATIC);
return TCL_OK;
} else {
wmPtr->iconName = Tk_GetUid(argv[3]);
}
if (argc == 3) {
if (wmPtr->hints.flags & IconPositionHint) {
- sprintf(interp->result, "%d %d", wmPtr->hints.icon_x,
+ char buf[TCL_INTEGER_SPACE * 2];
+
+ sprintf(buf, "%d %d", wmPtr->hints.icon_x,
wmPtr->hints.icon_y);
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
}
return TCL_OK;
}
}
if (argc == 3) {
if (wmPtr->icon != NULL) {
- interp->result = Tk_PathName(wmPtr->icon);
+ Tcl_SetResult(interp, Tk_PathName(wmPtr->icon), TCL_STATIC);
}
return TCL_OK;
}
if (!(wmPtr2->flags & WM_NEVER_MAPPED)) {
if (XWithdrawWindow(Tk_Display(tkwin2), Tk_WindowId(tkwin2),
Tk_ScreenNumber(tkwin2)) == 0) {
- interp->result =
- "couldn't send withdraw message to window manager";
+ Tcl_SetResult(interp,
+ "couldn't send withdraw message to window manager",
+ TCL_STATIC);
return TCL_ERROR;
}
}
return TCL_ERROR;
}
if (argc == 3) {
+ char buf[TCL_INTEGER_SPACE * 2];
+
GetMaxSize(wmPtr, &width, &height);
- sprintf(interp->result, "%d %d", width, height);
+ sprintf(buf, "%d %d", width, height);
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
return TCL_OK;
}
if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
return TCL_ERROR;
}
if (argc == 3) {
+ char buf[TCL_INTEGER_SPACE * 2];
+
GetMinSize(wmPtr, &width, &height);
- sprintf(interp->result, "%d %d", width, height);
+ sprintf(buf, "%d %d", width, height);
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
return TCL_OK;
}
if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
goto updateGeom;
} else if ((c == 'o')
&& (strncmp(argv[1], "overrideredirect", length) == 0)) {
- int boolean;
+ int boolean, curValue;
XSetWindowAttributes atts;
if ((argc != 3) && (argc != 4)) {
(char *) NULL);
return TCL_ERROR;
}
+ curValue = Tk_Attributes((Tk_Window) winPtr)->override_redirect;
if (argc == 3) {
- if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
- interp->result = "1";
- } else {
- interp->result = "0";
- }
+ Tcl_SetBooleanObj(Tcl_GetObjResult(interp), curValue);
return TCL_OK;
}
if (Tcl_GetBoolean(interp, argv[3], &boolean) != TCL_OK) {
return TCL_ERROR;
}
- atts.override_redirect = (boolean) ? True : False;
- Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect,
- &atts);
- if (!(wmPtr->flags & (WM_NEVER_MAPPED)
- && !(winPtr->flags & TK_EMBEDDED))) {
- UpdateWrapper(winPtr);
+ if (curValue != boolean) {
+ /*
+ * Only do this if we are really changing value, because it
+ * causes some funky stuff to occur
+ */
+ atts.override_redirect = (boolean) ? True : False;
+ Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect,
+ &atts);
+ if (!(wmPtr->flags & (WM_NEVER_MAPPED)
+ && !(winPtr->flags & TK_EMBEDDED))) {
+ UpdateWrapper(winPtr);
+ }
}
} else if ((c == 'p') && (strncmp(argv[1], "positionfrom", length) == 0)
&& (length >= 2)) {
}
if (argc == 3) {
if (wmPtr->sizeHintsFlags & USPosition) {
- interp->result = "user";
+ Tcl_SetResult(interp, "user", TCL_STATIC);
} else if (wmPtr->sizeHintsFlags & PPosition) {
- interp->result = "program";
+ Tcl_SetResult(interp, "program", TCL_STATIC);
}
return TCL_OK;
}
for (protPtr = wmPtr->protPtr; protPtr != NULL;
protPtr = protPtr->nextPtr) {
if (protPtr->protocol == protocol) {
- interp->result = protPtr->command;
+ Tcl_SetResult(interp, protPtr->command, TCL_STATIC);
return TCL_OK;
}
}
return TCL_ERROR;
}
if (argc == 3) {
- sprintf(interp->result, "%d %d",
+ char buf[TCL_INTEGER_SPACE * 2];
+
+ sprintf(buf, "%d %d",
(wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) ? 0 : 1,
(wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) ? 0 : 1);
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
return TCL_OK;
}
if ((Tcl_GetBoolean(interp, argv[3], &width) != TCL_OK)
} else {
wmPtr->flags |= WM_HEIGHT_NOT_RESIZABLE;
}
- wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
+ if (!((wmPtr->flags & WM_NEVER_MAPPED)
+ && !(winPtr->flags & TK_EMBEDDED))) {
+ UpdateWrapper(winPtr);
+ }
goto updateGeom;
} else if ((c == 's') && (strncmp(argv[1], "sizefrom", length) == 0)
&& (length >= 2)) {
}
if (argc == 3) {
if (wmPtr->sizeHintsFlags & USSize) {
- interp->result = "user";
+ Tcl_SetResult(interp, "user", TCL_STATIC);
} else if (wmPtr->sizeHintsFlags & PSize) {
- interp->result = "program";
+ Tcl_SetResult(interp, "program", TCL_STATIC);
}
return TCL_OK;
}
goto updateGeom;
} else if ((c == 's') && (strncmp(argv[1], "state", length) == 0)
&& (length >= 2)) {
- if (argc != 3) {
+ if ((argc < 3) || (argc > 4)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
- argv[0], " state window\"", (char *) NULL);
+ argv[0], " state window ?state?\"", (char *) NULL);
return TCL_ERROR;
}
- if (wmPtr->iconFor != NULL) {
- interp->result = "icon";
+ if (argc == 4) {
+ if (wmPtr->iconFor != NULL) {
+ Tcl_AppendResult(interp, "can't change state of ", argv[2],
+ ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (winPtr->flags & TK_EMBEDDED) {
+ Tcl_AppendResult(interp, "can't change state of ",
+ winPtr->pathName, ": it is an embedded window",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ c = argv[3][0];
+ length = strlen(argv[3]);
+
+ if ((c == 'n') && (strncmp(argv[3], "normal", length) == 0)) {
+ TkpWmSetState(winPtr, NormalState);
+ /*
+ * This varies from 'wm deiconify' because it does not
+ * force the window to be raised and receive focus
+ */
+ } else if ((c == 'i')
+ && (strncmp(argv[3], "iconic", length) == 0)) {
+ if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
+ Tcl_AppendResult(interp, "can't iconify \"",
+ winPtr->pathName,
+ "\": override-redirect flag is set",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ if (wmPtr->masterPtr != NULL) {
+ Tcl_AppendResult(interp, "can't iconify \"",
+ winPtr->pathName,
+ "\": it is a transient", (char *) NULL);
+ return TCL_ERROR;
+ }
+ TkpWmSetState(winPtr, IconicState);
+ } else if ((c == 'w')
+ && (strncmp(argv[3], "withdrawn", length) == 0)) {
+ TkpWmSetState(winPtr, WithdrawnState);
+ } else if ((c == 'z')
+ && (strncmp(argv[3], "zoomed", length) == 0)) {
+ TkpWmSetState(winPtr, ZoomState);
+ } else {
+ Tcl_AppendResult(interp, "bad argument \"", argv[3],
+ "\": must be normal, iconic, withdrawn or zoomed",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
} else {
- switch (wmPtr->hints.initial_state) {
- case NormalState:
- interp->result = "normal";
- break;
- case IconicState:
- interp->result = "iconic";
- break;
- case WithdrawnState:
- interp->result = "withdrawn";
- break;
- case ZoomState:
- interp->result = "zoomed";
- break;
+ if (wmPtr->iconFor != NULL) {
+ Tcl_SetResult(interp, "icon", TCL_STATIC);
+ } else {
+ switch (wmPtr->hints.initial_state) {
+ case NormalState:
+ Tcl_SetResult(interp, "normal", TCL_STATIC);
+ break;
+ case IconicState:
+ Tcl_SetResult(interp, "iconic", TCL_STATIC);
+ break;
+ case WithdrawnState:
+ Tcl_SetResult(interp, "withdrawn", TCL_STATIC);
+ break;
+ case ZoomState:
+ Tcl_SetResult(interp, "zoomed", TCL_STATIC);
+ break;
+ }
}
}
} else if ((c == 't') && (strncmp(argv[1], "title", length) == 0)
return TCL_ERROR;
}
if (argc == 3) {
- interp->result = (wmPtr->titleUid != NULL) ? wmPtr->titleUid
- : winPtr->nameUid;
+ Tcl_SetResult(interp, ((wmPtr->titleUid != NULL) ?
+ wmPtr->titleUid : winPtr->nameUid), TCL_STATIC);
return TCL_OK;
} else {
wmPtr->titleUid = Tk_GetUid(argv[3]);
if (!(wmPtr->flags & WM_NEVER_MAPPED) && wmPtr->wrapper != NULL) {
- SetWindowText(wmPtr->wrapper, wmPtr->titleUid);
+ Tcl_DString titleString;
+ Tcl_UtfToExternalDString(NULL, wmPtr->titleUid, -1,
+ &titleString);
+ SetWindowText(wmPtr->wrapper, Tcl_DStringValue(&titleString));
+ Tcl_DStringFree(&titleString);
}
}
} else if ((c == 't') && (strncmp(argv[1], "transient", length) == 0)
&& (length >= 3)) {
- TkWindow *masterPtr;
+ TkWindow *masterPtr = wmPtr->masterPtr;
if ((argc != 3) && (argc != 4)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
return TCL_ERROR;
}
if (argc == 3) {
- if (wmPtr->masterPtr != NULL) {
- Tcl_SetResult(interp, Tk_PathName(wmPtr->masterPtr),
- TCL_STATIC);
+ if (masterPtr != NULL) {
+ Tcl_SetResult(interp, Tk_PathName(masterPtr), TCL_STATIC);
}
return TCL_OK;
}
+ if (masterPtr != NULL) {
+ /*
+ * If we had a master, tell them that we aren't tied
+ * to them anymore
+ */
+ masterPtr->wmInfoPtr->numTransients--;
+ Tk_DeleteEventHandler((Tk_Window) masterPtr,
+ VisibilityChangeMask,
+ WmWaitVisibilityProc, (ClientData) winPtr);
+ }
if (argv[3][0] == '\0') {
wmPtr->masterPtr = NULL;
} else {
}
if (masterPtr == winPtr) {
wmPtr->masterPtr = NULL;
- } else {
+ } else if (masterPtr != wmPtr->masterPtr) {
Tk_MakeWindowExist((Tk_Window)masterPtr);
/*
masterPtr = masterPtr->parentPtr;
}
wmPtr->masterPtr = masterPtr;
+ masterPtr->wmInfoPtr->numTransients++;
/*
- * Ensure that the transient window is either mapped or
- * unmapped like its master.
+ * Bind a visibility event handler to the master window,
+ * to ensure that when it is mapped, the children will
+ * have their state set properly.
*/
- TkpWmSetState(winPtr, NormalState);
+ Tk_CreateEventHandler((Tk_Window) masterPtr,
+ VisibilityChangeMask,
+ WmWaitVisibilityProc, (ClientData) winPtr);
}
}
- if (!(wmPtr->flags & (WM_NEVER_MAPPED)
+ if (!((wmPtr->flags & WM_NEVER_MAPPED)
&& !(winPtr->flags & TK_EMBEDDED))) {
UpdateWrapper(winPtr);
}
}
return TCL_OK;
}
+ /*ARGSUSED*/
+static void
+WmWaitVisibilityProc(clientData, eventPtr)
+ ClientData clientData; /* Pointer to window. */
+ XEvent *eventPtr; /* Information about event. */
+{
+ TkWindow *winPtr = (TkWindow *) clientData;
+ TkWindow *masterPtr = winPtr->wmInfoPtr->masterPtr;
+
+ if ((eventPtr->type == VisibilityNotify) && (masterPtr != NULL)) {
+ int state = masterPtr->wmInfoPtr->hints.initial_state;
+
+ if ((state == NormalState) || (state == ZoomState)) {
+ state = winPtr->wmInfoPtr->hints.initial_state;
+ if ((state == NormalState) || (state == ZoomState)) {
+ UpdateWrapper(winPtr);
+ }
+ }
+ }
+}
\f
/*
*----------------------------------------------------------------------
*
* Results:
* A standard Tcl return value, plus an error message in
- * interp->result if an error occurs.
+ * the interp's result if an error occurs.
*
* Side effects:
* The size and/or location of winPtr may change.
for (protPtr = wmPtr->protPtr; protPtr != NULL;
protPtr = protPtr->nextPtr) {
if (protocol == protPtr->protocol) {
+ /*
+ * Cache atom name, as we might destroy the window as a
+ * result of the eval.
+ */
+ char *name = Tk_GetAtomName((Tk_Window) winPtr, protocol);
+
Tcl_Preserve((ClientData) protPtr);
interp = protPtr->interp;
Tcl_Preserve((ClientData) interp);
result = Tcl_GlobalEval(interp, protPtr->command);
if (result != TCL_OK) {
Tcl_AddErrorInfo(interp, "\n (command for \"");
- Tcl_AddErrorInfo(interp,
- Tk_GetAtomName((Tk_Window) winPtr, protocol));
+ Tcl_AddErrorInfo(interp, name);
Tcl_AddErrorInfo(interp, "\" window manager protocol)");
Tcl_BackgroundError(interp);
}
hwnd = (winPtr->wmInfoPtr->wrapper != NULL)
? winPtr->wmInfoPtr->wrapper : Tk_GetHWND(winPtr->window);
-
if (otherPtr != NULL) {
if (otherPtr->window == None) {
Tk_MakeWindowExist((Tk_Window) otherPtr);
* Now we need to force the updated colormaps to be installed.
*/
- if (topPtr->wmInfoPtr == foregroundWmPtr) {
+ if (topPtr->wmInfoPtr == winPtr->dispPtr->foregroundWmPtr) {
InstallColormaps(topPtr->wmInfoPtr->wrapper, WM_QUERYNEWPALETTE, 1);
} else {
InstallColormaps(topPtr->wmInfoPtr->wrapper, WM_PALETTECHANGED, 0);
*/
if (!(wmPtr->flags & WM_UPDATE_PENDING)) {
- Tcl_DoWhenIdle(UpdateGeometryInfo,
- (ClientData) winPtr);
+ Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
wmPtr->flags |= WM_UPDATE_PENDING;
}
/* fall through */
HPALETTE oldPalette;
TkWindow *winPtr = GetTopLevel(hwnd);
WmInfo *wmPtr;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
if (winPtr == NULL) {
return 0;
* secondary palettes are installed properly.
*/
- foregroundWmPtr = wmPtr;
+ winPtr->dispPtr->foregroundWmPtr = wmPtr;
if (wmPtr->cmapCount > 0) {
winPtr = wmPtr->cmapList[0];
}
- systemPalette = TkWinGetPalette(winPtr->atts.colormap);
+ tsdPtr->systemPalette = TkWinGetPalette(winPtr->atts.colormap);
dc = GetDC(hwnd);
- oldPalette = SelectPalette(dc, systemPalette, FALSE);
+ oldPalette = SelectPalette(dc, tsdPtr->systemPalette, FALSE);
if (RealizePalette(dc)) {
- RefreshColormap(winPtr->atts.colormap);
+ RefreshColormap(winPtr->atts.colormap, winPtr->dispPtr);
} else if (wmPtr->cmapCount > 1) {
SelectPalette(dc, oldPalette, TRUE);
RealizePalette(dc);
oldPalette = SelectPalette(dc,
TkWinGetPalette(winPtr->atts.colormap), TRUE);
if (RealizePalette(dc)) {
- RefreshColormap(winPtr->atts.colormap);
+ RefreshColormap(winPtr->atts.colormap, winPtr->dispPtr);
}
for (; i < wmPtr->cmapCount; i++) {
winPtr = wmPtr->cmapList[i];
SelectPalette(dc, TkWinGetPalette(winPtr->atts.colormap), TRUE);
if (RealizePalette(dc)) {
- RefreshColormap(winPtr->atts.colormap);
+ RefreshColormap(winPtr->atts.colormap, winPtr->dispPtr);
}
}
}
*/
static void
-RefreshColormap(colormap)
+RefreshColormap(colormap, dispPtr)
Colormap colormap;
+ TkDisplay *dispPtr;
{
WmInfo *wmPtr;
int i;
- for (wmPtr = firstWmPtr; wmPtr != NULL; wmPtr = wmPtr->nextPtr) {
+ for (wmPtr = dispPtr->firstWmPtr; wmPtr != NULL; wmPtr = wmPtr->nextPtr) {
if (wmPtr->cmapCount > 0) {
for (i = 0; i < wmPtr->cmapCount; i++) {
if ((wmPtr->cmapList[i]->atts.colormap == colormap)
HPALETTE
TkWinGetSystemPalette()
{
- return systemPalette;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+
+ return tsdPtr->systemPalette;
}
\f
/*
* leaving move/size mode. Note that this mechanism
* assumes move/size is only one level deep. */
LRESULT result;
- TkWindow *winPtr;
-
+ TkWindow *winPtr = NULL;
+
if (TkWinHandleMenuEvent(&hwnd, &message, &wParam, &lParam, &result)) {
goto done;
}
case WM_ENTERSIZEMOVE:
inMoveSize = 1;
- /* CYGNUS LOCAL: Cancel any current mouse timer before we
- start looking for events. If the mouse timer fires, it
- will release the size/move mouse capture, which is
- wrong. */
+ /*
+ * Cancel any current mouse timer. If the mouse timer
+ * fires during the size/move mouse capture, it will
+ * release the capture, which is wrong.
+ */
+
TkWinCancelMouseTimer();
oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
ActivateEvent *eventPtr;
winPtr = GetTopLevel((HWND) wParam);
+ if (winPtr && (TkGrabState(winPtr) != TK_GRAB_EXCLUDED)) {
+ /*
+ * This allows us to pass the message onto the
+ * native menus [Bug: 2272]
+ */
+ result = DefWindowProc(hwnd, message, wParam, lParam);
+ goto done;
+ }
+
/*
- * Don't activate the window yet since there may be grabs
- * that should take precedence. Instead we need to queue
+ * Don't activate the window yet since there is a grab
+ * that takes precedence. Instead we need to queue
* an event so we can check the grab state right before we
* handle the mouse event.
*/
goto done;
}
- /* CYGNUS LOCAL. */
- case WM_SETTINGCHANGE:
- if (wParam == SPI_SETNONCLIENTMETRICS) {
- winPtr = GetTopLevel(hwnd);
- if (winPtr != NULL) {
- TkWinNCMetricsChanged((Tk_Window) winPtr);
- }
- }
- break;
-
- /* CYGNUS LOCAL. */
- case WM_SYSCOLORCHANGE:
- TkWinSysColorChange();
- break;
-
default:
break;
}
* None.
*
* Side effects:
- * Changes the style bit used to create a new Mac toplevel.
+ * Changes the style bit used to create a new toplevel.
*
*----------------------------------------------------------------------
*/
return 1;
}
+
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkWinSetForegroundWindow --
+ *
+ * This function is a wrapper for SetForegroundWindow, calling
+ * it on the wrapper window because it has no affect on child
+ * windows.
+ *
+ * Results:
+ * none
+ *
+ * Side effects:
+ * May activate the toplevel window.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkWinSetForegroundWindow(winPtr)
+ TkWindow *winPtr;
+{
+ register WmInfo *wmPtr = winPtr->wmInfoPtr;
+
+ if (wmPtr->wrapper != NULL) {
+ SetForegroundWindow(wmPtr->wrapper);
+ } else {
+ SetForegroundWindow(Tk_GetHWND(winPtr->window));
+ }
+}