stk/Tk/win/tkWinWm.c

4397 lines
120 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* tkWinWm.c --
*
* This module takes care of the interactions between a Tk-based
* application and the window manager. Among other things, it
* implements the "wm" command and passes geometry information
* to the window manager.
*
* Copyright (c) 1995-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.
*
* SCCS: @(#) tkWinWm.c 1.67 97/09/23 17:39:47
*/
#include "tkWinInt.h"
/*
* Event structure for synthetic activation events. These events are
* placed on the event queue whenever a toplevel gets a WM_MOUSEACTIVATE
* message.
*/
typedef struct ActivateEvent {
Tcl_Event ev;
TkWindow *winPtr;
} ActivateEvent;
/*
* A data structure of the following type holds information for
* each window manager protocol (such as WM_DELETE_WINDOW) for
* which a handler (i.e. a Tcl command) has been defined for a
* particular top-level window.
*/
typedef struct ProtocolHandler {
Atom protocol; /* Identifies the protocol. */
struct ProtocolHandler *nextPtr;
/* Next in list of protocol handlers for
* the same top-level window, or NULL for
* end of list. */
Tcl_Interp *interp; /* Interpreter in which to invoke command. */
char command[4]; /* Tcl command to invoke when a client
* message for this protocol arrives.
* The actual size of the structure varies
* to accommodate the needs of the actual
* command. THIS MUST BE THE LAST FIELD OF
* THE STRUCTURE. */
} ProtocolHandler;
#define HANDLER_SIZE(cmdLength) \
((unsigned) (sizeof(ProtocolHandler) - 3 + cmdLength))
/*
* A data structure of the following type holds window-manager-related
* information for each top-level window in an application.
*/
typedef struct TkWmInfo {
TkWindow *winPtr; /* Pointer to main Tk information for
* this window. */
HWND wrapper; /* This is the decorative frame window
* created by the window manager to wrap
* a toplevel window. This window is
* a direct child of the root window. */
Tk_Uid titleUid; /* Title to display in window caption. If
* NULL, use name of widget. */
Tk_Uid iconName; /* Name to display in icon. */
TkWindow *masterPtr; /* Master window for TRANSIENT_FOR property,
* or NULL. */
XWMHints hints; /* Various pieces of information for
* window manager. */
char *leaderName; /* Path name of leader of window group
* (corresponds to hints.window_group).
* Malloc-ed. Note: this field doesn't
* get updated if leader is destroyed. */
Tk_Window icon; /* Window to use as icon for this window,
* or NULL. */
Tk_Window iconFor; /* Window for which this window is icon, or
* NULL if this isn't an icon for anyone. */
/*
* Information used to construct an XSizeHints structure for
* the window manager:
*/
int defMinWidth, defMinHeight, defMaxWidth, defMaxHeight;
/* Default resize limits given by system. */
int sizeHintsFlags; /* Flags word for XSizeHints structure.
* If the PBaseSize flag is set then the
* window is gridded; otherwise it isn't
* gridded. */
int minWidth, minHeight; /* Minimum dimensions of window, in
* grid units, not pixels. */
int maxWidth, maxHeight; /* Maximum dimensions of window, in
* grid units, not pixels, or 0 to default. */
Tk_Window gridWin; /* Identifies the window that controls
* gridding for this top-level, or NULL if
* the top-level isn't currently gridded. */
int widthInc, heightInc; /* Increments for size changes (# pixels
* per step). */
struct {
int x; /* numerator */
int y; /* denominator */
} minAspect, maxAspect; /* Min/max aspect ratios for window. */
int reqGridWidth, reqGridHeight;
/* The dimensions of the window (in
* grid units) requested through
* the geometry manager. */
int gravity; /* Desired window gravity. */
/*
* Information used to manage the size and location of a window.
*/
int width, height; /* Desired dimensions of window, specified
* in grid units. These values are
* set by the "wm geometry" command and by
* ConfigureNotify events (for when wm
* resizes window). -1 means user hasn't
* requested dimensions. */
int x, y; /* Desired X and Y coordinates for window.
* These values are set by "wm geometry",
* plus by ConfigureNotify events (when wm
* moves window). These numbers are
* different than the numbers stored in
* winPtr->changes because (a) they could be
* measured from the right or bottom edge
* of the screen (see WM_NEGATIVE_X and
* WM_NEGATIVE_Y flags) and (b) if the window
* has been reparented then they refer to the
* parent rather than the window itself. */
int borderWidth, borderHeight;
/* Width and height of window dressing, in
* pixels for the current style/exStyle. This
* includes the border on both sides of the
* window. */
int configWidth, configHeight;
/* Dimensions passed to last request that we
* issued to change geometry of window. Used
* to eliminate redundant resize operations. */
HMENU hMenu; /* the hMenu associated with this menu */
DWORD style, exStyle; /* Style flags for the wrapper window. */
/*
* List of children of the toplevel which have private colormaps.
*/
TkWindow **cmapList; /* Array of window with private colormaps. */
int cmapCount; /* Number of windows in array. */
/*
* Miscellaneous information.
*/
ProtocolHandler *protPtr; /* First in list of protocol handlers for
* this window (NULL means none). */
int cmdArgc; /* Number of elements in cmdArgv below. */
char **cmdArgv; /* Array of strings to store in the
* WM_COMMAND property. NULL means nothing
* available. */
char *clientMachine; /* String to store in WM_CLIENT_MACHINE
* property, or NULL. */
int flags; /* Miscellaneous flags, defined below. */
struct TkWmInfo *nextPtr; /* Next in list of all top-level windows. */
} WmInfo;
/*
* Flag values for WmInfo structures:
*
* WM_NEVER_MAPPED - non-zero means window has never been
* mapped; need to update all info when
* window is first mapped.
* WM_UPDATE_PENDING - non-zero means a call to UpdateGeometryInfo
* has already been scheduled for this
* window; no need to schedule another one.
* WM_NEGATIVE_X - non-zero means x-coordinate is measured in
* pixels from right edge of screen, rather
* than from left edge.
* WM_NEGATIVE_Y - non-zero means y-coordinate is measured in
* 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.
* 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
* a new position for the window, but it hasn't
* been reflected through the window manager
* yet.
* WM_COLORAMPS_EXPLICIT - non-zero means the colormap windows were
* set explicitly via "wm colormapwindows".
* WM_ADDED_TOPLEVEL_COLORMAP - non-zero means that when "wm colormapwindows"
* was called the top-level itself wasn't
* specified, so we added it implicitly at
* the end of the list.
*/
#define WM_NEVER_MAPPED (1<<0)
#define WM_UPDATE_PENDING (1<<1)
#define WM_NEGATIVE_X (1<<2)
#define WM_NEGATIVE_Y (1<<3)
#define WM_UPDATE_SIZE_HINTS (1<<4)
#define WM_SYNC_PENDING (1<<5)
#define WM_CREATE_PENDING (1<<6)
#define WM_MOVE_PENDING (1<<7)
#define WM_COLORMAPS_EXPLICIT (1<<8)
#define WM_ADDED_TOPLEVEL_COLORMAP (1<<9)
#define WM_WIDTH_NOT_RESIZABLE (1<<10)
#define WM_HEIGHT_NOT_RESIZABLE (1<<11)
/*
* Window styles for various types of toplevel windows.
*/
#define WM_OVERRIDE_STYLE (WS_POPUP|WS_CLIPCHILDREN|CS_DBLCLKS)
#define EX_OVERRIDE_STYLE (WS_EX_TOOLWINDOW)
#define WM_TOPLEVEL_STYLE (WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|CS_DBLCLKS)
#define EX_TOPLEVEL_STYLE (0)
#define WM_TRANSIENT_STYLE \
(WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_CLIPSIBLINGS|CS_DBLCLKS)
#define EX_TRANSIENT_STYLE \
(WS_EX_TOOLWINDOW|WS_EX_DLGMODALFRAME)
/*
* 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;
/*
* The following structure is the official type record for geometry
* management of top-level windows.
*/
static void TopLevelReqProc(ClientData dummy, Tk_Window tkwin);
static Tk_GeomMgr wmMgrType = {
"wm", /* name */
TopLevelReqProc, /* requestProc */
(Tk_GeomLostSlaveProc *) NULL, /* lostSlaveProc */
};
/*
* Global system palette. This value always refers to the currently
* installed foreground logical palette.
*/
static HPALETTE systemPalette = NULL;
/*
* 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.
*/
static TkWindow *createWindow = NULL;
/*
* 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:
*/
static int ActivateWindow _ANSI_ARGS_((Tcl_Event *evPtr,
int flags));
static void ConfigureEvent _ANSI_ARGS_((TkWindow *winPtr,
XConfigureEvent *eventPtr));
static void ConfigureTopLevel _ANSI_ARGS_((WINDOWPOS *pos));
static void GenerateConfigureNotify _ANSI_ARGS_((
TkWindow *winPtr));
static void GetMaxSize _ANSI_ARGS_((WmInfo *wmPtr,
int *maxWidthPtr, int *maxHeightPtr));
static void GetMinSize _ANSI_ARGS_((WmInfo *wmPtr,
int *minWidthPtr, int *minHeightPtr));
static TkWindow * GetTopLevel _ANSI_ARGS_((HWND hwnd));
static void InitWm _ANSI_ARGS_((void));
static int InstallColormaps _ANSI_ARGS_((HWND hwnd, int message,
int isForemost));
static void InvalidateSubTree _ANSI_ARGS_((TkWindow *winPtr,
Colormap colormap));
static int ParseGeometry _ANSI_ARGS_((Tcl_Interp *interp,
char *string, TkWindow *winPtr));
static void RefreshColormap _ANSI_ARGS_((Colormap colormap));
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 TopLevelEventProc _ANSI_ARGS_((ClientData clientData,
XEvent *eventPtr));
static void TopLevelReqProc _ANSI_ARGS_((ClientData dummy,
Tk_Window tkwin));
static void UpdateGeometryInfo _ANSI_ARGS_((
ClientData clientData));
static void UpdateWrapper _ANSI_ARGS_((TkWindow *winPtr));
static LRESULT CALLBACK WmProc _ANSI_ARGS_((HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam));
/*
*----------------------------------------------------------------------
*
* InitWm --
*
* This routine creates the Wm toplevel decorative frame class.
*
* Results:
* None.
*
* Side effects:
* Registers a new window class.
*
*----------------------------------------------------------------------
*/
static void
InitWm(void)
{
if (initialized) {
return;
}
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;
toplevelClass.hIcon = LoadIcon(Tk_GetHINSTANCE(), "tk");
toplevelClass.hCursor = LoadCursor(NULL, IDC_ARROW);
if (!RegisterClass(&toplevelClass)) {
panic("Unable to register TkTopLevel class");
}
}
/*
*----------------------------------------------------------------------
*
* GetTopLevel --
*
* This function retrieves the TkWindow associated with the
* given HWND.
*
* Results:
* Returns the matching TkWindow.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static TkWindow *
GetTopLevel(hwnd)
HWND hwnd;
{
/*
* 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;
}
return (TkWindow *) GetWindowLong(hwnd, GWL_USERDATA);
}
/*
*----------------------------------------------------------------------
*
* SetLimits --
*
* Updates the minimum and maximum window size constraints.
*
* Results:
* None.
*
* Side effects:
* Changes the values of the info pointer to reflect the current
* minimum and maximum size values.
*
*----------------------------------------------------------------------
*/
static void
SetLimits(hwnd, info)
HWND hwnd;
MINMAXINFO *info;
{
register WmInfo *wmPtr;
int maxWidth, maxHeight;
int minWidth, minHeight;
int base;
TkWindow *winPtr = GetTopLevel(hwnd);
if (winPtr == NULL) {
return;
}
wmPtr = winPtr->wmInfoPtr;
/*
* Copy latest constraint info.
*/
wmPtr->defMinWidth = info->ptMinTrackSize.x;
wmPtr->defMinHeight = info->ptMinTrackSize.y;
wmPtr->defMaxWidth = info->ptMaxTrackSize.x;
wmPtr->defMaxHeight = info->ptMaxTrackSize.y;
GetMaxSize(wmPtr, &maxWidth, &maxHeight);
GetMinSize(wmPtr, &minWidth, &minHeight);
if (wmPtr->gridWin != NULL) {
base = winPtr->reqWidth - (wmPtr->reqGridWidth * wmPtr->widthInc);
if (base < 0) {
base = 0;
}
base += wmPtr->borderWidth;
info->ptMinTrackSize.x = base + (minWidth * wmPtr->widthInc);
info->ptMaxTrackSize.x = base + (maxWidth * wmPtr->widthInc);
base = winPtr->reqHeight - (wmPtr->reqGridHeight * wmPtr->heightInc);
if (base < 0) {
base = 0;
}
base += wmPtr->borderHeight;
info->ptMinTrackSize.y = base + (minHeight * wmPtr->heightInc);
info->ptMaxTrackSize.y = base + (maxHeight * wmPtr->heightInc);
} else {
info->ptMaxTrackSize.x = maxWidth + wmPtr->borderWidth;
info->ptMaxTrackSize.y = maxHeight + wmPtr->borderHeight;
info->ptMinTrackSize.x = minWidth + wmPtr->borderWidth;
info->ptMinTrackSize.y = minHeight + wmPtr->borderHeight;
}
/*
* If the window isn't supposed to be resizable, then set the
* minimum and maximum dimensions to be the same as the current size.
*/
if (!(wmPtr->flags & WM_SYNC_PENDING)) {
if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) {
info->ptMinTrackSize.x = winPtr->changes.width
+ wmPtr->borderWidth;
info->ptMaxTrackSize.x = info->ptMinTrackSize.x;
}
if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) {
info->ptMinTrackSize.y = winPtr->changes.height
+ wmPtr->borderHeight;
info->ptMaxTrackSize.y = info->ptMinTrackSize.y;
}
}
}
/*
*----------------------------------------------------------------------
*
* TkWinWmCleanup --
*
* Unregisters classes registered by the window manager. This is
* called from the DLL main entry point when the DLL is unloaded.
*
* Results:
* None.
*
* Side effects:
* The window classes are discarded.
*
*----------------------------------------------------------------------
*/
void
TkWinWmCleanup(hInstance)
HINSTANCE hInstance;
{
if (!initialized) {
return;
}
initialized = 0;
UnregisterClass(TK_WIN_TOPLEVEL_CLASS_NAME, hInstance);
}
/*
*--------------------------------------------------------------
*
* TkWmNewWindow --
*
* This procedure is invoked whenever a new top-level
* window is created. Its job is to initialize the WmInfo
* structure for the window.
*
* Results:
* None.
*
* Side effects:
* A WmInfo structure gets allocated and initialized.
*
*--------------------------------------------------------------
*/
void
TkWmNewWindow(winPtr)
TkWindow *winPtr; /* Newly-created top-level window. */
{
register WmInfo *wmPtr;
wmPtr = (WmInfo *) ckalloc(sizeof(WmInfo));
winPtr->wmInfoPtr = wmPtr;
wmPtr->winPtr = winPtr;
wmPtr->wrapper = NULL;
wmPtr->titleUid = NULL;
wmPtr->iconName = NULL;
wmPtr->masterPtr = NULL;
wmPtr->hints.flags = InputHint | StateHint;
wmPtr->hints.input = True;
wmPtr->hints.initial_state = NormalState;
wmPtr->hints.icon_pixmap = None;
wmPtr->hints.icon_window = None;
wmPtr->hints.icon_x = wmPtr->hints.icon_y = 0;
wmPtr->hints.icon_mask = None;
wmPtr->hints.window_group = None;
wmPtr->leaderName = NULL;
wmPtr->icon = NULL;
wmPtr->iconFor = NULL;
wmPtr->sizeHintsFlags = 0;
/*
* Default the maximum dimensions to the size of the display.
*/
wmPtr->defMinWidth = wmPtr->defMinHeight = 0;
wmPtr->defMaxWidth = DisplayWidth(winPtr->display,
winPtr->screenNum);
wmPtr->defMaxHeight = DisplayHeight(winPtr->display,
winPtr->screenNum);
wmPtr->minWidth = wmPtr->minHeight = 1;
wmPtr->maxWidth = wmPtr->maxHeight = 0;
wmPtr->gridWin = NULL;
wmPtr->widthInc = wmPtr->heightInc = 1;
wmPtr->minAspect.x = wmPtr->minAspect.y = 1;
wmPtr->maxAspect.x = wmPtr->maxAspect.y = 1;
wmPtr->reqGridWidth = wmPtr->reqGridHeight = -1;
wmPtr->gravity = NorthWestGravity;
wmPtr->width = -1;
wmPtr->height = -1;
wmPtr->hMenu = NULL;
wmPtr->x = winPtr->changes.x;
wmPtr->y = winPtr->changes.y;
wmPtr->borderWidth = 0;
wmPtr->borderHeight = 0;
wmPtr->cmapList = NULL;
wmPtr->cmapCount = 0;
wmPtr->configWidth = -1;
wmPtr->configHeight = -1;
wmPtr->protPtr = NULL;
wmPtr->cmdArgv = NULL;
wmPtr->clientMachine = NULL;
wmPtr->flags = WM_NEVER_MAPPED;
wmPtr->nextPtr = firstWmPtr;
firstWmPtr = wmPtr;
/*
* Tk must monitor structure events for top-level windows, in order
* to detect size and position changes caused by window managers.
*/
Tk_CreateEventHandler((Tk_Window) winPtr, StructureNotifyMask,
TopLevelEventProc, (ClientData) winPtr);
/*
* Arrange for geometry requests to be reflected from the window
* to the window manager.
*/
Tk_ManageGeometry((Tk_Window) winPtr, &wmMgrType, (ClientData) 0);
}
/*
*----------------------------------------------------------------------
*
* UpdateWrapper --
*
* This function creates the wrapper window that contains the
* window decorations and menus for a toplevel. This function
* may be called after a window is mapped to change the window
* style.
*
* Results:
* None.
*
* Side effects:
* Destroys any old wrapper window and replaces it with a newly
* created wrapper.
*
*----------------------------------------------------------------------
*/
static void
UpdateWrapper(winPtr)
TkWindow *winPtr; /* Top-level window to redecorate. */
{
register WmInfo *wmPtr = winPtr->wmInfoPtr;
HWND parentHWND = NULL, oldWrapper;
HWND child = TkWinGetHWND(winPtr->window);
int x, y, width, height, state;
WINDOWPLACEMENT place;
parentHWND = NULL;
child = TkWinGetHWND(winPtr->window);
if (winPtr->flags & TK_EMBEDDED) {
wmPtr->wrapper = (HWND) winPtr->privatePtr;
if (wmPtr->wrapper == NULL) {
panic("TkWmMapWindow: Cannot find container window");
}
if (!IsWindow(wmPtr->wrapper)) {
panic("TkWmMapWindow: Container was destroyed");
}
} else {
/*
* 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
* 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;
} else if (wmPtr->masterPtr) {
wmPtr->style = WM_TRANSIENT_STYLE;
wmPtr->exStyle = EX_TRANSIENT_STYLE;
parentHWND = Tk_GetHWND(Tk_WindowId(wmPtr->masterPtr));
if (! ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) &&
(wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE))) {
wmPtr->style |= WS_THICKFRAME;
}
} else {
wmPtr->style = WM_TOPLEVEL_STYLE;
wmPtr->exStyle = EX_TOPLEVEL_STYLE;
}
/*
* Compute the geometry of the parent and child windows.
*/
wmPtr->flags |= WM_CREATE_PENDING|WM_MOVE_PENDING;
UpdateGeometryInfo((ClientData)winPtr);
wmPtr->flags &= ~(WM_CREATE_PENDING|WM_MOVE_PENDING);
width = wmPtr->borderWidth + winPtr->changes.width;
height = wmPtr->borderHeight + winPtr->changes.height;
/*
* Set the initial position from the user or program specified
* location. If nothing has been specified, then let the system
* pick a location.
*/
if (!(wmPtr->sizeHintsFlags & (USPosition | PPosition))
&& (wmPtr->flags & WM_NEVER_MAPPED)) {
x = CW_USEDEFAULT;
y = CW_USEDEFAULT;
} else {
x = winPtr->changes.x;
y = winPtr->changes.y;
}
/*
* Create the containing window, and set the user data to point
* to the TkWindow.
*/
createWindow = winPtr;
wmPtr->wrapper = CreateWindowEx(wmPtr->exStyle,
TK_WIN_TOPLEVEL_CLASS_NAME,
wmPtr->titleUid, wmPtr->style, x, y, width, height,
parentHWND, NULL, Tk_GetHINSTANCE(), NULL);
SetWindowLong(wmPtr->wrapper, GWL_USERDATA, (LONG) winPtr);
createWindow = NULL;
place.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(wmPtr->wrapper, &place);
wmPtr->x = place.rcNormalPosition.left;
wmPtr->y = place.rcNormalPosition.top;
TkInstallFrameMenu((Tk_Window) winPtr);
}
/*
* Now we need to reparent the contained window and set its
* style appropriately. Be sure to update the style first so that
* Windows doesn't try to set the focus to the child window.
*/
SetWindowLong(child, GWL_STYLE,
WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
if (winPtr->flags & TK_EMBEDDED) {
SetWindowLong(child, GWL_WNDPROC, (LONG) TopLevelProc);
}
oldWrapper = SetParent(child, wmPtr->wrapper);
if (oldWrapper && (oldWrapper != wmPtr->wrapper)
&& (oldWrapper != GetDesktopWindow())) {
SetWindowLong(oldWrapper, GWL_USERDATA, (LONG) 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);
/*
* Force an initial transition from withdrawn to the real
* initial state.
*/
state = wmPtr->hints.initial_state;
wmPtr->hints.initial_state = WithdrawnState;
TkpWmSetState(winPtr, state);
/*
* If we are embedded then force a mapping of the window now,
* because we do not necessarily own the wrapper and may not
* get another opportunity to map ourselves. We should not be
* in either iconified or zoomed states when we get here, so
* it is safe to just check for TK_EMBEDDED without checking
* what state we are supposed to be in (default to NormalState).
*/
if (winPtr->flags & TK_EMBEDDED) {
XMapWindow(winPtr->display, winPtr->window);
}
/*
* Set up menus on the wrapper if required.
*/
if (wmPtr->hMenu != NULL) {
wmPtr->flags = WM_SYNC_PENDING;
SetMenu(wmPtr->wrapper, wmPtr->hMenu);
wmPtr->flags &= ~WM_SYNC_PENDING;
}
/*
* If this is the first window created by the application, then
* we should activate the initial window.
*/
if (firstWindow) {
firstWindow = 0;
SetActiveWindow(wmPtr->wrapper);
}
}
/*
*--------------------------------------------------------------
*
* TkWmMapWindow --
*
* This procedure is invoked to map a top-level window. This
* module gets a chance to update all window-manager-related
* information in properties before the window manager sees
* the map event and checks the properties. It also gets to
* decide whether or not to even map the window after all.
*
* Results:
* None.
*
* Side effects:
* Properties of winPtr may get updated to provide up-to-date
* information to the window manager. The window may also get
* mapped, but it may not be if this procedure decides that
* isn't appropriate (e.g. because the window is withdrawn).
*
*--------------------------------------------------------------
*/
void
TkWmMapWindow(winPtr)
TkWindow *winPtr; /* Top-level window that's about to
* be mapped. */
{
register WmInfo *wmPtr = winPtr->wmInfoPtr;
if (!initialized) {
InitWm();
}
if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
if (wmPtr->hints.initial_state == WithdrawnState) {
return;
}
/*
* Map the window in either the iconified or normal state. Note that
* we only send a map event if the window is in the normal state.
*/
TkpWmSetState(winPtr, wmPtr->hints.initial_state);
}
/*
* This is the first time this window has ever been mapped.
* Store all the window-manager-related information for the
* window.
*/
if (wmPtr->titleUid == NULL) {
wmPtr->titleUid = winPtr->nameUid;
}
UpdateWrapper(winPtr);
}
/*
*--------------------------------------------------------------
*
* TkWmUnmapWindow --
*
* This procedure is invoked to unmap a top-level window. The
* only thing it does special is unmap the decorative frame before
* unmapping the toplevel window.
*
* Results:
* None.
*
* Side effects:
* Unmaps the decorative frame and the window.
*
*--------------------------------------------------------------
*/
void
TkWmUnmapWindow(winPtr)
TkWindow *winPtr; /* Top-level window that's about to
* be unmapped. */
{
TkpWmSetState(winPtr, WithdrawnState);
}
/*
*----------------------------------------------------------------------
*
* TkpWmSetState --
*
* Sets the window manager state for the wrapper window of a
* given toplevel window.
*
* Results:
* None.
*
* Side effects:
* May maximize, minimize, restore, or withdraw a window.
*
*----------------------------------------------------------------------
*/
void
TkpWmSetState(winPtr, state)
TkWindow *winPtr; /* Toplevel window to operate on. */
int state; /* One of IconicState, ZoomState, NormalState,
* or WithdrawnState. */
{
WmInfo *wmPtr = winPtr->wmInfoPtr;
int cmd;
if (wmPtr->flags & WM_NEVER_MAPPED) {
wmPtr->hints.initial_state = state;
return;
}
wmPtr->flags |= WM_SYNC_PENDING;
if (state == WithdrawnState) {
cmd = SW_HIDE;
} else if (state == IconicState) {
cmd = SW_SHOWMINNOACTIVE;
} else if (state == NormalState) {
cmd = SW_SHOWNOACTIVATE;
} else if (state == ZoomState) {
cmd = SW_SHOWMAXIMIZED;
}
ShowWindow(wmPtr->wrapper, cmd);
wmPtr->flags &= ~WM_SYNC_PENDING;
}
/*
*--------------------------------------------------------------
*
* TkWmDeadWindow --
*
* This procedure is invoked when a top-level window is
* about to be deleted. It cleans up the wm-related data
* structures for the window.
*
* Results:
* None.
*
* Side effects:
* The WmInfo structure for winPtr gets freed up.
*
*--------------------------------------------------------------
*/
void
TkWmDeadWindow(winPtr)
TkWindow *winPtr; /* Top-level window that's being deleted. */
{
register WmInfo *wmPtr = winPtr->wmInfoPtr;
WmInfo *wmPtr2;
if (wmPtr == NULL) {
return;
}
/*
* Clean up event related window info.
*/
if (firstWmPtr == wmPtr) {
firstWmPtr = wmPtr->nextPtr;
} else {
register WmInfo *prevPtr;
for (prevPtr = firstWmPtr; ; prevPtr = prevPtr->nextPtr) {
if (prevPtr == NULL) {
panic("couldn't unlink window in TkWmDeadWindow");
}
if (prevPtr->nextPtr == wmPtr) {
prevPtr->nextPtr = wmPtr->nextPtr;
break;
}
}
}
/*
* Reset all transient windows whose master is the dead window.
*/
for (wmPtr2 = firstWmPtr; wmPtr2 != NULL; wmPtr2 = wmPtr2->nextPtr) {
if (wmPtr2->masterPtr == winPtr) {
wmPtr2->masterPtr = NULL;
if ((wmPtr2->wrapper != None)
&& !(wmPtr2->flags & (WM_NEVER_MAPPED))) {
UpdateWrapper(wmPtr2->winPtr);
}
}
}
if (wmPtr->hints.flags & IconPixmapHint) {
Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
}
if (wmPtr->hints.flags & IconMaskHint) {
Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
}
if (wmPtr->leaderName != NULL) {
ckfree(wmPtr->leaderName);
}
if (wmPtr->icon != NULL) {
wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
wmPtr2->iconFor = NULL;
}
if (wmPtr->iconFor != NULL) {
wmPtr2 = ((TkWindow *) wmPtr->iconFor)->wmInfoPtr;
wmPtr2->icon = NULL;
wmPtr2->hints.flags &= ~IconWindowHint;
}
while (wmPtr->protPtr != NULL) {
ProtocolHandler *protPtr;
protPtr = wmPtr->protPtr;
wmPtr->protPtr = protPtr->nextPtr;
Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
}
if (wmPtr->cmdArgv != NULL) {
ckfree((char *) wmPtr->cmdArgv);
}
if (wmPtr->clientMachine != NULL) {
ckfree((char *) wmPtr->clientMachine);
}
if (wmPtr->flags & WM_UPDATE_PENDING) {
Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
}
/*
* Destroy the decorative frame window.
*/
if (!(winPtr->flags & TK_EMBEDDED)) {
if (wmPtr->wrapper != NULL) {
DestroyWindow(wmPtr->wrapper);
} else {
DestroyWindow(Tk_GetHWND(winPtr->window));
}
}
ckfree((char *) wmPtr);
winPtr->wmInfoPtr = NULL;
}
/*
*--------------------------------------------------------------
*
* TkWmSetClass --
*
* This procedure is invoked whenever a top-level window's
* class is changed. If the window has been mapped then this
* procedure updates the window manager property for the
* class. If the window hasn't been mapped, the update is
* deferred until just before the first mapping.
*
* Results:
* None.
*
* Side effects:
* A window property may get updated.
*
*--------------------------------------------------------------
*/
void
TkWmSetClass(winPtr)
TkWindow *winPtr; /* Newly-created top-level window. */
{
return;
}
/*
*----------------------------------------------------------------------
*
* Tk_WmCmd --
*
* This procedure is invoked to process the "wm" Tcl command.
* See the user documentation for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
int
Tk_WmCmd(clientData, interp, argc, argv)
ClientData clientData; /* Main window associated with
* interpreter. */
Tcl_Interp *interp; /* Current interpreter. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
Tk_Window tkwin = (Tk_Window) clientData;
TkWindow *winPtr;
register WmInfo *wmPtr;
int c;
size_t length;
if (argc < 2) {
wrongNumArgs:
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " option window ?arg ...?\"", (char *) NULL);
return TCL_ERROR;
}
c = argv[1][0];
length = strlen(argv[1]);
if ((c == 't') && (strncmp(argv[1], "tracing", length) == 0)
&& (length >= 3)) {
if ((argc != 2) && (argc != 3)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " tracing ?boolean?\"", (char *) NULL);
return TCL_ERROR;
}
if (argc == 2) {
interp->result = (wmTracing) ? "on" : "off";
return TCL_OK;
}
return Tcl_GetBoolean(interp, argv[2], &wmTracing);
}
if (argc < 3) {
goto wrongNumArgs;
}
winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
if (winPtr == NULL) {
return TCL_ERROR;
}
if (!(winPtr->flags & TK_TOP_LEVEL)) {
Tcl_AppendResult(interp, "window \"", winPtr->pathName,
"\" isn't a top-level window", (char *) NULL);
return TCL_ERROR;
}
wmPtr = winPtr->wmInfoPtr;
if ((c == 'a') && (strncmp(argv[1], "aspect", length) == 0)) {
int numer1, denom1, numer2, denom2;
if ((argc != 3) && (argc != 7)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " aspect window ?minNumer minDenom ",
"maxNumer maxDenom?\"", (char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
if (wmPtr->sizeHintsFlags & PAspect) {
sprintf(interp->result, "%d %d %d %d", wmPtr->minAspect.x,
wmPtr->minAspect.y, wmPtr->maxAspect.x,
wmPtr->maxAspect.y);
}
return TCL_OK;
}
if (*argv[3] == '\0') {
wmPtr->sizeHintsFlags &= ~PAspect;
} else {
if ((Tcl_GetInt(interp, argv[3], &numer1) != TCL_OK)
|| (Tcl_GetInt(interp, argv[4], &denom1) != TCL_OK)
|| (Tcl_GetInt(interp, argv[5], &numer2) != TCL_OK)
|| (Tcl_GetInt(interp, argv[6], &denom2) != TCL_OK)) {
return TCL_ERROR;
}
if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) ||
(denom2 <= 0)) {
interp->result = "aspect number can't be <= 0";
return TCL_ERROR;
}
wmPtr->minAspect.x = numer1;
wmPtr->minAspect.y = denom1;
wmPtr->maxAspect.x = numer2;
wmPtr->maxAspect.y = denom2;
wmPtr->sizeHintsFlags |= PAspect;
}
goto updateGeom;
} else if ((c == 'c') && (strncmp(argv[1], "client", length) == 0)
&& (length >= 2)) {
if ((argc != 3) && (argc != 4)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " client window ?name?\"",
(char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
if (wmPtr->clientMachine != NULL) {
interp->result = wmPtr->clientMachine;
}
return TCL_OK;
}
if (argv[3][0] == 0) {
if (wmPtr->clientMachine != NULL) {
ckfree((char *) wmPtr->clientMachine);
wmPtr->clientMachine = NULL;
if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
XDeleteProperty(winPtr->display, winPtr->window,
Tk_InternAtom((Tk_Window) winPtr,
"WM_CLIENT_MACHINE"));
}
}
return TCL_OK;
}
if (wmPtr->clientMachine != NULL) {
ckfree((char *) wmPtr->clientMachine);
}
wmPtr->clientMachine = (char *)
ckalloc((unsigned) (strlen(argv[3]) + 1));
strcpy(wmPtr->clientMachine, argv[3]);
if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
XTextProperty textProp;
if (XStringListToTextProperty(&wmPtr->clientMachine, 1, &textProp)
!= 0) {
XSetWMClientMachine(winPtr->display, winPtr->window,
&textProp);
XFree((char *) textProp.value);
}
}
} else if ((c == 'c') && (strncmp(argv[1], "colormapwindows", length) == 0)
&& (length >= 3)) {
TkWindow **cmapList;
TkWindow *winPtr2;
int i, windowArgc, gotToplevel;
char **windowArgv;
if ((argc != 3) && (argc != 4)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " colormapwindows window ?windowList?\"",
(char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
Tk_MakeWindowExist((Tk_Window) winPtr);
#ifdef STk_CODE
Tcl_AppendResult(interp, "(", NULL);
#endif
for (i = 0; i < wmPtr->cmapCount; i++) {
if ((i == (wmPtr->cmapCount-1))
&& (wmPtr->flags & WM_ADDED_TOPLEVEL_COLORMAP)) {
break;
}
Tcl_AppendElement(interp, wmPtr->cmapList[i]->pathName);
}
#ifdef STk_CODE
Tcl_AppendResult(interp, ")", NULL);
#endif
return TCL_OK;
}
if (Tcl_SplitList(interp, argv[3], &windowArgc, &windowArgv)
!= TCL_OK) {
return TCL_ERROR;
}
cmapList = (TkWindow **) ckalloc((unsigned)
((windowArgc+1)*sizeof(TkWindow*)));
for (i = 0; i < windowArgc; i++) {
winPtr2 = (TkWindow *) Tk_NameToWindow(interp, windowArgv[i],
tkwin);
if (winPtr2 == NULL) {
ckfree((char *) cmapList);
ckfree((char *) windowArgv);
return TCL_ERROR;
}
if (winPtr2 == winPtr) {
gotToplevel = 1;
}
if (winPtr2->window == None) {
Tk_MakeWindowExist((Tk_Window) winPtr2);
}
cmapList[i] = winPtr2;
}
if (!gotToplevel) {
wmPtr->flags |= WM_ADDED_TOPLEVEL_COLORMAP;
cmapList[windowArgc] = winPtr;
windowArgc++;
} else {
wmPtr->flags &= ~WM_ADDED_TOPLEVEL_COLORMAP;
}
wmPtr->flags |= WM_COLORMAPS_EXPLICIT;
if (wmPtr->cmapList != NULL) {
ckfree((char *)wmPtr->cmapList);
}
wmPtr->cmapList = cmapList;
wmPtr->cmapCount = windowArgc;
ckfree((char *) windowArgv);
/*
* Now we need to force the updated colormaps to be installed.
*/
if (wmPtr == foregroundWmPtr) {
InstallColormaps(wmPtr->wrapper, WM_QUERYNEWPALETTE, 1);
} else {
InstallColormaps(wmPtr->wrapper, WM_PALETTECHANGED, 0);
}
return TCL_OK;
} else if ((c == 'c') && (strncmp(argv[1], "command", length) == 0)
&& (length >= 3)) {
int cmdArgc;
char **cmdArgv;
if ((argc != 3) && (argc != 4)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " command window ?value?\"",
(char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
if (wmPtr->cmdArgv != NULL) {
interp->result = Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv);
interp->freeProc = TCL_DYNAMIC;
}
return TCL_OK;
}
if (argv[3][0] == 0) {
if (wmPtr->cmdArgv != NULL) {
ckfree((char *) wmPtr->cmdArgv);
wmPtr->cmdArgv = NULL;
if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
XDeleteProperty(winPtr->display, winPtr->window,
Tk_InternAtom((Tk_Window) winPtr, "WM_COMMAND"));
}
}
return TCL_OK;
}
if (Tcl_SplitList(interp, argv[3], &cmdArgc, &cmdArgv) != TCL_OK) {
return TCL_ERROR;
}
if (wmPtr->cmdArgv != NULL) {
ckfree((char *) wmPtr->cmdArgv);
}
wmPtr->cmdArgc = cmdArgc;
wmPtr->cmdArgv = cmdArgv;
if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
XSetCommand(winPtr->display, winPtr->window, cmdArgv, cmdArgc);
}
} else if ((c == 'd') && (strncmp(argv[1], "deiconify", length) == 0)) {
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " deiconify window\"", (char *) NULL);
return TCL_ERROR;
}
if (wmPtr->iconFor != NULL) {
Tcl_AppendResult(interp, "can't deiconify ", argv[2],
": it is an icon for ", winPtr->pathName, (char *) NULL);
return TCL_ERROR;
}
if (winPtr->flags & TK_EMBEDDED) {
Tcl_AppendResult(interp, "can't deiconify ", winPtr->pathName,
": it is an embedded window", (char *) NULL);
return TCL_ERROR;
}
TkpWmSetState(winPtr, NormalState);
} else if ((c == 'f') && (strncmp(argv[1], "focusmodel", length) == 0)
&& (length >= 2)) {
if ((argc != 3) && (argc != 4)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " focusmodel window ?active|passive?\"",
(char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
#ifdef STk_CODE
interp->result = wmPtr->hints.input ? "\"passive\"" : "\"active\"";
#else
interp->result = wmPtr->hints.input ? "passive" : "active";
#endif
return TCL_OK;
}
c = argv[3][0];
length = strlen(argv[3]);
if ((c == 'a') && (strncmp(argv[3], "active", length) == 0)) {
wmPtr->hints.input = False;
} else if ((c == 'p') && (strncmp(argv[3], "passive", length) == 0)) {
wmPtr->hints.input = True;
} else {
Tcl_AppendResult(interp, "bad argument \"", argv[3],
"\": must be active or passive", (char *) NULL);
return TCL_ERROR;
}
} else if ((c == 'f') && (strncmp(argv[1], "frame", length) == 0)
&& (length >= 2)) {
HWND hwnd;
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " frame window\"", (char *) NULL);
return TCL_ERROR;
}
if (Tk_WindowId((Tk_Window) winPtr) == None) {
Tk_MakeWindowExist((Tk_Window) winPtr);
}
hwnd = wmPtr->wrapper;
if (hwnd == NULL) {
hwnd = Tk_GetHWND(Tk_WindowId((Tk_Window) winPtr));
}
#ifdef STk_CODE
sprintf(interp->result, "#x%x", (unsigned int) hwnd);
#else
sprintf(interp->result, "0x%x", (unsigned int) hwnd);
#endif
} else if ((c == 'g') && (strncmp(argv[1], "geometry", length) == 0)
&& (length >= 2)) {
char xSign, ySign;
int width, height;
if ((argc != 3) && (argc != 4)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " geometry window ?newGeometry?\"",
(char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+';
ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+';
if (wmPtr->gridWin != NULL) {
width = wmPtr->reqGridWidth + (winPtr->changes.width
- winPtr->reqWidth)/wmPtr->widthInc;
height = wmPtr->reqGridHeight + (winPtr->changes.height
- winPtr->reqHeight)/wmPtr->heightInc;
} else {
width = winPtr->changes.width;
height = winPtr->changes.height;
}
#ifdef STk_CODE
sprintf(interp->result, "\"%dx%d%c%d%c%d\"", width, height,
#else
sprintf(interp->result, "%dx%d%c%d%c%d", width, height,
#endif
xSign, wmPtr->x, ySign, wmPtr->y);
return TCL_OK;
}
if (*argv[3] == '\0') {
wmPtr->width = -1;
wmPtr->height = -1;
goto updateGeom;
}
return ParseGeometry(interp, argv[3], winPtr);
} else if ((c == 'g') && (strncmp(argv[1], "grid", length) == 0)
&& (length >= 3)) {
int reqWidth, reqHeight, widthInc, heightInc;
if ((argc != 3) && (argc != 7)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " grid window ?baseWidth baseHeight ",
"widthInc heightInc?\"", (char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
if (wmPtr->sizeHintsFlags & PBaseSize) {
sprintf(interp->result, "%d %d %d %d", wmPtr->reqGridWidth,
wmPtr->reqGridHeight, wmPtr->widthInc,
wmPtr->heightInc);
}
#ifdef STk_CODE
else
interp->result = "#f";
#endif
return TCL_OK;
}
#ifdef STk_CODE
if (*argv[3] == '\0' || strcmp(argv[3], "#f") == 0) {
#else
if (*argv[3] == '\0') {
#endif
/*
* Turn off gridding and reset the width and height
* to make sense as ungridded numbers.
*/
wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
if (wmPtr->width != -1) {
wmPtr->width = winPtr->reqWidth + (wmPtr->width
- wmPtr->reqGridWidth)*wmPtr->widthInc;
wmPtr->height = winPtr->reqHeight + (wmPtr->height
- wmPtr->reqGridHeight)*wmPtr->heightInc;
}
wmPtr->widthInc = 1;
wmPtr->heightInc = 1;
} else {
if ((Tcl_GetInt(interp, argv[3], &reqWidth) != TCL_OK)
|| (Tcl_GetInt(interp, argv[4], &reqHeight) != TCL_OK)
|| (Tcl_GetInt(interp, argv[5], &widthInc) != TCL_OK)
|| (Tcl_GetInt(interp, argv[6], &heightInc) != TCL_OK)) {
return TCL_ERROR;
}
if (reqWidth < 0) {
interp->result = "baseWidth can't be < 0";
return TCL_ERROR;
}
if (reqHeight < 0) {
interp->result = "baseHeight can't be < 0";
return TCL_ERROR;
}
if (widthInc < 0) {
interp->result = "widthInc can't be < 0";
return TCL_ERROR;
}
if (heightInc < 0) {
interp->result = "heightInc can't be < 0";
return TCL_ERROR;
}
Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc,
heightInc);
}
goto updateGeom;
} else if ((c == 'g') && (strncmp(argv[1], "group", length) == 0)
&& (length >= 3)) {
Tk_Window tkwin2;
if ((argc != 3) && (argc != 4)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " group window ?pathName?\"",
(char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
if (wmPtr->hints.flags & WindowGroupHint) {
interp->result = wmPtr->leaderName;
}
#ifdef STk_CODE
else
interp->result = "#f";
STk_sharp_dot_result(interp, interp->result);
#endif
return TCL_OK;
}
#ifdef STk_CODE
if (*argv[3] == '\0' || strcmp(argv[3], "#f") == 0) {
#else
if (*argv[3] == '\0') {
#endif
wmPtr->hints.flags &= ~WindowGroupHint;
if (wmPtr->leaderName != NULL) {
ckfree(wmPtr->leaderName);
}
wmPtr->leaderName = NULL;
} else {
tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
if (tkwin2 == NULL) {
return TCL_ERROR;
}
Tk_MakeWindowExist(tkwin2);
wmPtr->hints.window_group = Tk_WindowId(tkwin2);
wmPtr->hints.flags |= WindowGroupHint;
wmPtr->leaderName = ckalloc((unsigned) (strlen(argv[3])+1));
strcpy(wmPtr->leaderName, argv[3]);
}
} else if ((c == 'i') && (strncmp(argv[1], "iconbitmap", length) == 0)
&& (length >= 5)) {
Pixmap pixmap;
if ((argc != 3) && (argc != 4)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " iconbitmap window ?bitmap?\"",
(char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
if (wmPtr->hints.flags & IconPixmapHint) {
interp->result = Tk_NameOfBitmap(winPtr->display,
wmPtr->hints.icon_pixmap);
#ifdef STk_CODE
STk_stringify_result(interp, interp->result);
}
else {
interp->result = "#f";
#endif
}
return TCL_OK;
}
#ifdef STk_CODE
if (*argv[3] == '\0' || strcmp(argv[3], "#f") == 0) {
#else
if (*argv[3] == '\0') {
#endif
if (wmPtr->hints.icon_pixmap != None) {
Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
}
wmPtr->hints.flags &= ~IconPixmapHint;
} else {
pixmap = Tk_GetBitmap(interp, (Tk_Window) winPtr,
Tk_GetUid(argv[3]));
if (pixmap == None) {
return TCL_ERROR;
}
wmPtr->hints.icon_pixmap = pixmap;
wmPtr->hints.flags |= IconPixmapHint;
}
} else if ((c == 'i') && (strncmp(argv[1], "iconify", length) == 0)
&& (length >= 5)) {
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " iconify window\"", (char *) NULL);
return TCL_ERROR;
}
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;
}
if (wmPtr->iconFor != NULL) {
Tcl_AppendResult(interp, "can't iconify ", argv[2],
": it is an icon for ", winPtr->pathName, (char *) NULL);
return TCL_ERROR;
}
if (winPtr->flags & TK_EMBEDDED) {
Tcl_AppendResult(interp, "can't iconify ", winPtr->pathName,
": it is an embedded window", (char *) NULL);
return TCL_ERROR;
}
TkpWmSetState(winPtr, IconicState);
} else if ((c == 'i') && (strncmp(argv[1], "iconmask", length) == 0)
&& (length >= 5)) {
Pixmap pixmap;
if ((argc != 3) && (argc != 4)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " iconmask window ?bitmap?\"",
(char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
if (wmPtr->hints.flags & IconMaskHint) {
interp->result = Tk_NameOfBitmap(winPtr->display,
wmPtr->hints.icon_mask);
}
#ifdef STk_CODE
STk_stringify_result(interp, interp->result);
#endif
return TCL_OK;
}
#ifdef STk_CODE
if (*argv[3] == '\0' || strcmp(argv[3], "#f") == 0) {
#else
if (*argv[3] == '\0') {
#endif
if (wmPtr->hints.icon_mask != None) {
Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
}
wmPtr->hints.flags &= ~IconMaskHint;
} else {
pixmap = Tk_GetBitmap(interp, tkwin, Tk_GetUid(argv[3]));
if (pixmap == None) {
return TCL_ERROR;
}
wmPtr->hints.icon_mask = pixmap;
wmPtr->hints.flags |= IconMaskHint;
}
} else if ((c == 'i') && (strncmp(argv[1], "iconname", length) == 0)
&& (length >= 5)) {
if (argc > 4) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " iconname window ?newName?\"", (char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
interp->result = (wmPtr->iconName != NULL) ? wmPtr->iconName : "";
#ifdef STk_CODE
STk_stringify_result(interp, interp->result);
#endif
return TCL_OK;
} else {
wmPtr->iconName = Tk_GetUid(argv[3]);
if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
}
}
} else if ((c == 'i') && (strncmp(argv[1], "iconposition", length) == 0)
&& (length >= 5)) {
int x, y;
if ((argc != 3) && (argc != 5)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " iconposition window ?x y?\"",
(char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
if (wmPtr->hints.flags & IconPositionHint) {
sprintf(interp->result, "%d %d", wmPtr->hints.icon_x,
wmPtr->hints.icon_y);
}
#ifdef STk_CODE
else
interp->result = "#f";
#endif
return TCL_OK;
}
#ifdef STk_CODE
if (*argv[3] == '\0' || strcmp(argv[3], "#f") == 0) {
#else
if (*argv[3] == '\0') {
#endif
wmPtr->hints.flags &= ~IconPositionHint;
} else {
if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK)
|| (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)){
return TCL_ERROR;
}
wmPtr->hints.icon_x = x;
wmPtr->hints.icon_y = y;
wmPtr->hints.flags |= IconPositionHint;
}
} else if ((c == 'i') && (strncmp(argv[1], "iconwindow", length) == 0)
&& (length >= 5)) {
Tk_Window tkwin2;
WmInfo *wmPtr2;
XSetWindowAttributes atts;
if ((argc != 3) && (argc != 4)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " iconwindow window ?pathName?\"",
(char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
if (wmPtr->icon != NULL) {
interp->result = Tk_PathName(wmPtr->icon);
}
#ifdef STk_CODE
else
interp->result = "#f";
STk_sharp_dot_result(interp, interp->result);
#endif
return TCL_OK;
}
#ifdef STk_CODE
if (*argv[3] == '\0' || strcmp(argv[3], "#f") == 0) {
#else
if (*argv[3] == '\0') {
#endif
wmPtr->hints.flags &= ~IconWindowHint;
if (wmPtr->icon != NULL) {
/*
* Let the window use button events again, then remove
* it as icon window.
*/
atts.event_mask = Tk_Attributes(wmPtr->icon)->event_mask
| ButtonPressMask;
Tk_ChangeWindowAttributes(wmPtr->icon, CWEventMask, &atts);
wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
wmPtr2->iconFor = NULL;
wmPtr2->hints.initial_state = WithdrawnState;
}
wmPtr->icon = NULL;
} else {
tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
if (tkwin2 == NULL) {
return TCL_ERROR;
}
if (!Tk_IsTopLevel(tkwin2)) {
Tcl_AppendResult(interp, "can't use ", argv[3],
" as icon window: not at top level", (char *) NULL);
return TCL_ERROR;
}
wmPtr2 = ((TkWindow *) tkwin2)->wmInfoPtr;
if (wmPtr2->iconFor != NULL) {
Tcl_AppendResult(interp, argv[3], " is already an icon for ",
Tk_PathName(wmPtr2->iconFor), (char *) NULL);
return TCL_ERROR;
}
if (wmPtr->icon != NULL) {
WmInfo *wmPtr3 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
wmPtr3->iconFor = NULL;
/*
* Let the window use button events again.
*/
atts.event_mask = Tk_Attributes(wmPtr->icon)->event_mask
| ButtonPressMask;
Tk_ChangeWindowAttributes(wmPtr->icon, CWEventMask, &atts);
}
/*
* Disable button events in the icon window: some window
* managers (like olvwm) want to get the events themselves,
* but X only allows one application at a time to receive
* button events for a window.
*/
atts.event_mask = Tk_Attributes(tkwin2)->event_mask
& ~ButtonPressMask;
Tk_ChangeWindowAttributes(tkwin2, CWEventMask, &atts);
Tk_MakeWindowExist(tkwin2);
wmPtr->hints.icon_window = Tk_WindowId(tkwin2);
wmPtr->hints.flags |= IconWindowHint;
wmPtr->icon = tkwin2;
wmPtr2->iconFor = (Tk_Window) winPtr;
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";
return TCL_ERROR;
}
}
}
} else if ((c == 'm') && (strncmp(argv[1], "maxsize", length) == 0)
&& (length >= 2)) {
int width, height;
if ((argc != 3) && (argc != 5)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " maxsize window ?width height?\"",
(char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
GetMaxSize(wmPtr, &width, &height);
sprintf(interp->result, "%d %d", width, height);
return TCL_OK;
}
if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
|| (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
return TCL_ERROR;
}
wmPtr->maxWidth = width;
wmPtr->maxHeight = height;
goto updateGeom;
} else if ((c == 'm') && (strncmp(argv[1], "minsize", length) == 0)
&& (length >= 2)) {
int width, height;
if ((argc != 3) && (argc != 5)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " minsize window ?width height?\"",
(char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
GetMinSize(wmPtr, &width, &height);
sprintf(interp->result, "%d %d", width, height);
return TCL_OK;
}
if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
|| (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
return TCL_ERROR;
}
wmPtr->minWidth = width;
wmPtr->minHeight = height;
goto updateGeom;
} else if ((c == 'o')
&& (strncmp(argv[1], "overrideredirect", length) == 0)) {
int boolean;
XSetWindowAttributes atts;
if ((argc != 3) && (argc != 4)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " overrideredirect window ?boolean?\"",
(char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
#ifdef STk_CODE
interp->result = (Tk_Attributes((Tk_Window) winPtr)->override_redirect)
? "#t" : "#f";
#else
if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
interp->result = "1";
} else {
interp->result = "0";
}
#endif
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);
}
} else if ((c == 'p') && (strncmp(argv[1], "positionfrom", length) == 0)
&& (length >= 2)) {
if ((argc != 3) && (argc != 4)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " positionfrom window ?user/program?\"",
(char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
if (wmPtr->sizeHintsFlags & USPosition) {
#ifdef STk_CODE
interp->result = "\"user\"";
#else
interp->result = "user";
#endif
} else if (wmPtr->sizeHintsFlags & PPosition) {
#ifdef STk_CODE
interp->result = "\"program\"";
} else {
interp->result = "#f";
#else
interp->result = "program";
#endif
}
return TCL_OK;
}
#ifdef STk_CODE
if (*argv[3] == '\0' || strcmp(argv[3], "#f") == 0) {
#else
if (*argv[3] == '\0') {
#endif
wmPtr->sizeHintsFlags &= ~(USPosition|PPosition);
} else {
c = argv[3][0];
length = strlen(argv[3]);
if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
wmPtr->sizeHintsFlags &= ~PPosition;
wmPtr->sizeHintsFlags |= USPosition;
} else if ((c == 'p')
&& (strncmp(argv[3], "program", length) == 0)) {
wmPtr->sizeHintsFlags &= ~USPosition;
wmPtr->sizeHintsFlags |= PPosition;
} else {
Tcl_AppendResult(interp, "bad argument \"", argv[3],
"\": must be program or user", (char *) NULL);
return TCL_ERROR;
}
}
goto updateGeom;
} else if ((c == 'p') && (strncmp(argv[1], "protocol", length) == 0)
&& (length >= 2)) {
register ProtocolHandler *protPtr, *prevPtr;
Atom protocol;
int cmdLength;
if ((argc < 3) || (argc > 5)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " protocol window ?name? ?command?\"",
(char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
/*
* Return a list of all defined protocols for the window.
*/
#ifdef STk_CODE
Tcl_AppendResult(interp, "(", NULL);
for (protPtr = wmPtr->protPtr; protPtr; protPtr = protPtr->nextPtr) {
Tcl_AppendResult(interp, " \"",
Tk_GetAtomName((Tk_Window) winPtr, protPtr->protocol),
"\"", (char *)NULL);
}
Tcl_AppendResult(interp, ")", NULL);
#else
for (protPtr = wmPtr->protPtr; protPtr != NULL;
protPtr = protPtr->nextPtr) {
Tcl_AppendElement(interp,
Tk_GetAtomName((Tk_Window) winPtr, protPtr->protocol));
}
#endif
return TCL_OK;
}
protocol = Tk_InternAtom((Tk_Window) winPtr, argv[3]);
if (argc == 4) {
/*
* Return the command to handle a given protocol.
*/
for (protPtr = wmPtr->protPtr; protPtr != NULL;
protPtr = protPtr->nextPtr) {
if (protPtr->protocol == protocol) {
#ifdef STk_CODE
STk_sharp_dot_result(interp, protPtr->command);
#else
interp->result = protPtr->command;
#endif
return TCL_OK;
}
}
return TCL_OK;
}
/*
* Delete any current protocol handler, then create a new
* one with the specified command, unless the command is
* empty.
*/
for (protPtr = wmPtr->protPtr, prevPtr = NULL; protPtr != NULL;
prevPtr = protPtr, protPtr = protPtr->nextPtr) {
if (protPtr->protocol == protocol) {
if (prevPtr == NULL) {
wmPtr->protPtr = protPtr->nextPtr;
} else {
prevPtr->nextPtr = protPtr->nextPtr;
}
Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
break;
}
}
cmdLength = strlen(argv[4]);
if (cmdLength > 0) {
#ifdef STk_CODE
SCM closure;
if (!STk_valid_callback(argv[4], &closure)) {
Tcl_AppendResult(interp, "bad closure specification \"",
argv[4], "\"", (char *) NULL);
return TCL_ERROR;
}
if (closure)
STk_add_callback(argv[2], "protocol", argv[3], closure);
#endif
protPtr = (ProtocolHandler *) ckalloc(HANDLER_SIZE(cmdLength));
protPtr->protocol = protocol;
protPtr->nextPtr = wmPtr->protPtr;
wmPtr->protPtr = protPtr;
protPtr->interp = interp;
strcpy(protPtr->command, argv[4]);
}
#ifdef STk_CODE
else {
/* Delete handler by setting it to #f */
extern SCM STk_ntruth;
STk_add_callback(argv[2], "protocol", argv[3], STk_ntruth);
}
#endif
} else if ((c == 'r') && (strncmp(argv[1], "resizable", length) == 0)) {
int width, height;
if ((argc != 3) && (argc != 5)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " resizable window ?width height?\"",
(char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
#ifdef STk_CODE
sprintf(interp->result, "(#%c #%c)",
(wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) ? 'f' : 't',
(wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) ? 'f' : 't');
#else
sprintf(interp->result, "%d %d",
(wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) ? 0 : 1,
(wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) ? 0 : 1);
#endif
return TCL_OK;
}
if ((Tcl_GetBoolean(interp, argv[3], &width) != TCL_OK)
|| (Tcl_GetBoolean(interp, argv[4], &height) != TCL_OK)) {
return TCL_ERROR;
}
if (width) {
wmPtr->flags &= ~WM_WIDTH_NOT_RESIZABLE;
} else {
wmPtr->flags |= WM_WIDTH_NOT_RESIZABLE;
}
if (height) {
wmPtr->flags &= ~WM_HEIGHT_NOT_RESIZABLE;
} else {
wmPtr->flags |= WM_HEIGHT_NOT_RESIZABLE;
}
wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
goto updateGeom;
} else if ((c == 's') && (strncmp(argv[1], "sizefrom", length) == 0)
&& (length >= 2)) {
if ((argc != 3) && (argc != 4)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " sizefrom window ?user|program?\"",
(char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
if (wmPtr->sizeHintsFlags & USSize) {
#ifdef STk_CODE
interp->result = "\"user\"";
#else
interp->result = "user";
#endif
} else if (wmPtr->sizeHintsFlags & PSize) {
#ifdef STk_CODE
interp->result = "\"program\"";
}
else {
interp->result = "#f";
#else
interp->result = "program";
#endif
}
return TCL_OK;
}
#ifdef STk_CODE
if (*argv[3] == '\0' || strcmp(argv[3], "#f") == 0) {
#else
if (*argv[3] == '\0') {
#endif
wmPtr->sizeHintsFlags &= ~(USSize|PSize);
} else {
c = argv[3][0];
length = strlen(argv[3]);
if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
wmPtr->sizeHintsFlags &= ~PSize;
wmPtr->sizeHintsFlags |= USSize;
} else if ((c == 'p')
&& (strncmp(argv[3], "program", length) == 0)) {
wmPtr->sizeHintsFlags &= ~USSize;
wmPtr->sizeHintsFlags |= PSize;
} else {
Tcl_AppendResult(interp, "bad argument \"", argv[3],
"\": must be program or user", (char *) NULL);
return TCL_ERROR;
}
}
goto updateGeom;
} else if ((c == 's') && (strncmp(argv[1], "state", length) == 0)
&& (length >= 2)) {
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " state window\"", (char *) NULL);
return TCL_ERROR;
}
#ifdef STk_CODE
if (wmPtr->iconFor != NULL) {
interp->result = "\"icon\"";
} 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;
}
#else
if (wmPtr->iconFor != NULL) {
interp->result = "icon";
} 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;
}
#endif
}
} else if ((c == 't') && (strncmp(argv[1], "title", length) == 0)
&& (length >= 2)) {
if (argc > 4) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " title window ?newTitle?\"", (char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
#ifdef STk_CODE
STk_stringify_result(interp, (wmPtr->titleUid != NULL) ? wmPtr->titleUid
: winPtr->nameUid);
#else
interp->result = (wmPtr->titleUid != NULL) ? wmPtr->titleUid
: winPtr->nameUid;
#endif
return TCL_OK;
} else {
wmPtr->titleUid = Tk_GetUid(argv[3]);
if (!(wmPtr->flags & WM_NEVER_MAPPED) && wmPtr->wrapper != NULL) {
SetWindowText(wmPtr->wrapper, wmPtr->titleUid);
}
}
} else if ((c == 't') && (strncmp(argv[1], "transient", length) == 0)
&& (length >= 3)) {
TkWindow *masterPtr;
if ((argc != 3) && (argc != 4)) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " transient window ?master?\"", (char *) NULL);
return TCL_ERROR;
}
if (argc == 3) {
if (wmPtr->masterPtr != NULL) {
Tcl_SetResult(interp, Tk_PathName(wmPtr->masterPtr),
TCL_STATIC);
}
#ifdef STk_CODE
else {
interp->result = "#f";
}
#endif
return TCL_OK;
}
#ifdef STk_CODE
if (argv[3][0] == '\0' || strcmp(argv[3], "#f") == 0) {
#else
if (argv[3][0] == '\0') {
#endif
wmPtr->masterPtr = NULL;
} else {
masterPtr = (TkWindow*) Tk_NameToWindow(interp, argv[3], tkwin);
if (masterPtr == NULL) {
return TCL_ERROR;
}
if (masterPtr == winPtr) {
wmPtr->masterPtr = NULL;
} else {
Tk_MakeWindowExist((Tk_Window)masterPtr);
/*
* Ensure that the master window is actually a Tk toplevel.
*/
while (!(masterPtr->flags & TK_TOP_LEVEL)) {
masterPtr = masterPtr->parentPtr;
}
wmPtr->masterPtr = masterPtr;
/*
* Ensure that the transient window is either mapped or
* unmapped like its master.
*/
TkpWmSetState(winPtr, NormalState);
}
}
if (!(wmPtr->flags & (WM_NEVER_MAPPED)
&& !(winPtr->flags & TK_EMBEDDED))) {
UpdateWrapper(winPtr);
}
} else if ((c == 'w') && (strncmp(argv[1], "withdraw", length) == 0)) {
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
argv[0], " withdraw window\"", (char *) NULL);
return TCL_ERROR;
}
if (wmPtr->iconFor != NULL) {
Tcl_AppendResult(interp, "can't withdraw ", argv[2],
": it is an icon for ", Tk_PathName(wmPtr->iconFor),
(char *) NULL);
return TCL_ERROR;
}
TkpWmSetState(winPtr, WithdrawnState);
} else {
Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],
"\": must be aspect, client, command, deiconify, ",
"focusmodel, frame, geometry, grid, group, iconbitmap, ",
"iconify, iconmask, iconname, iconposition, ",
"iconwindow, maxsize, minsize, overrideredirect, ",
"positionfrom, protocol, resizable, sizefrom, state, title, ",
"transient, or withdraw",
(char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
updateGeom:
if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
wmPtr->flags |= WM_UPDATE_PENDING;
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Tk_SetGrid --
*
* This procedure is invoked by a widget when it wishes to set a grid
* coordinate system that controls the size of a top-level window.
* It provides a C interface equivalent to the "wm grid" command and
* is usually asscoiated with the -setgrid option.
*
* Results:
* None.
*
* Side effects:
* Grid-related information will be passed to the window manager, so
* that the top-level window associated with tkwin will resize on
* even grid units. If some other window already controls gridding
* for the top-level window then this procedure call has no effect.
*
*----------------------------------------------------------------------
*/
void
Tk_SetGrid(tkwin, reqWidth, reqHeight, widthInc, heightInc)
Tk_Window tkwin; /* Token for window. New window mgr info
* will be posted for the top-level window
* associated with this window. */
int reqWidth; /* Width (in grid units) corresponding to
* the requested geometry for tkwin. */
int reqHeight; /* Height (in grid units) corresponding to
* the requested geometry for tkwin. */
int widthInc, heightInc; /* Pixel increments corresponding to a
* change of one grid unit. */
{
TkWindow *winPtr = (TkWindow *) tkwin;
register WmInfo *wmPtr;
/*
* Find the top-level window for tkwin, plus the window manager
* information.
*/
while (!(winPtr->flags & TK_TOP_LEVEL)) {
winPtr = winPtr->parentPtr;
}
wmPtr = winPtr->wmInfoPtr;
if ((wmPtr->gridWin != NULL) && (wmPtr->gridWin != tkwin)) {
return;
}
if ((wmPtr->reqGridWidth == reqWidth)
&& (wmPtr->reqGridHeight == reqHeight)
&& (wmPtr->widthInc == widthInc)
&& (wmPtr->heightInc == heightInc)
&& ((wmPtr->sizeHintsFlags & (PBaseSize|PResizeInc))
== PBaseSize|PResizeInc)) {
return;
}
/*
* If gridding was previously off, then forget about any window
* size requests made by the user or via "wm geometry": these are
* in pixel units and there's no easy way to translate them to
* grid units since the new requested size of the top-level window in
* pixels may not yet have been registered yet (it may filter up
* the hierarchy in DoWhenIdle handlers). However, if the window