4 * This module takes care of the interactions between a Tk-based
5 * application and the window manager. Among other things, it
6 * implements the "wm" command and passes geometry information
7 * to the window manager.
9 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
11 * See the file "license.terms" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
18 #include <QDOffscreen.h>
20 #include <ToolUtils.h>
27 #include "tkScrollbar.h"
30 * We now require the Appearance headers. They come with CodeWarrior Pro,
31 * and are on the SDK CD. However, we do not require the Appearance
35 #include <Appearance.h>
38 * A data structure of the following type holds information for
39 * each window manager protocol (such as WM_DELETE_WINDOW) for
40 * which a handler (i.e. a Tcl command) has been defined for a
41 * particular top-level window.
44 typedef struct ProtocolHandler {
45 Atom protocol; /* Identifies the protocol. */
46 struct ProtocolHandler *nextPtr;
47 /* Next in list of protocol handlers for
48 * the same top-level window, or NULL for
50 Tcl_Interp *interp; /* Interpreter in which to invoke command. */
51 char command[4]; /* Tcl command to invoke when a client
52 * message for this protocol arrives.
53 * The actual size of the structure varies
54 * to accommodate the needs of the actual
55 * command. THIS MUST BE THE LAST FIELD OF
59 #define HANDLER_SIZE(cmdLength) \
60 ((unsigned) (sizeof(ProtocolHandler) - 3 + cmdLength))
63 * A data structure of the following type holds window-manager-related
64 * information for each top-level window in an application.
67 typedef struct TkWmInfo {
68 TkWindow *winPtr; /* Pointer to main Tk information for
70 Window reparent; /* If the window has been reparented, this
71 * gives the ID of the ancestor of the window
72 * that is a child of the root window (may
73 * not be window's immediate parent). If
74 * the window isn't reparented, this has the
76 Tk_Uid titleUid; /* Title to display in window caption. If
77 * NULL, use name of widget. */
78 Tk_Uid iconName; /* Name to display in icon. */
79 Window master; /* Master window for TRANSIENT_FOR property,
81 XWMHints hints; /* Various pieces of information for
83 char *leaderName; /* Path name of leader of window group
84 * (corresponds to hints.window_group).
85 * Malloc-ed. Note: this field doesn't
86 * get updated if leader is destroyed. */
87 char *masterWindowName; /* Path name of window specified as master
88 * in "wm transient" command, or NULL.
89 * Malloc-ed. Note: this field doesn't
90 * get updated if masterWindowName is
92 Tk_Window icon; /* Window to use as icon for this window,
94 Tk_Window iconFor; /* Window for which this window is icon, or
95 * NULL if this isn't an icon for anyone. */
98 * Information used to construct an XSizeHints structure for
102 int sizeHintsFlags; /* Flags word for XSizeHints structure.
103 * If the PBaseSize flag is set then the
104 * window is gridded; otherwise it isn't
106 int minWidth, minHeight; /* Minimum dimensions of window, in
107 * grid units, not pixels. */
108 int maxWidth, maxHeight; /* Maximum dimensions of window, in
109 * grid units, not pixels. */
110 Tk_Window gridWin; /* Identifies the window that controls
111 * gridding for this top-level, or NULL if
112 * the top-level isn't currently gridded. */
113 int widthInc, heightInc; /* Increments for size changes (# pixels
116 int x; /* numerator */
117 int y; /* denominator */
118 } minAspect, maxAspect; /* Min/max aspect ratios for window. */
119 int reqGridWidth, reqGridHeight;
120 /* The dimensions of the window (in
121 * grid units) requested through
122 * the geometry manager. */
123 int gravity; /* Desired window gravity. */
126 * Information used to manage the size and location of a window.
129 int width, height; /* Desired dimensions of window, specified
130 * in grid units. These values are
131 * set by the "wm geometry" command and by
132 * ConfigureNotify events (for when wm
133 * resizes window). -1 means user hasn't
134 * requested dimensions. */
135 int x, y; /* Desired X and Y coordinates for window.
136 * These values are set by "wm geometry",
137 * plus by ConfigureNotify events (when wm
138 * moves window). These numbers are
139 * different than the numbers stored in
140 * winPtr->changes because (a) they could be
141 * measured from the right or bottom edge
142 * of the screen (see WM_NEGATIVE_X and
143 * WM_NEGATIVE_Y flags) and (b) if the window
144 * has been reparented then they refer to the
145 * parent rather than the window itself. */
146 int parentWidth, parentHeight;
147 /* Width and height of reparent, in pixels
148 * *including border*. If window hasn't been
149 * reparented then these will be the outer
150 * dimensions of the window, including
152 int xInParent, yInParent; /* Offset of window within reparent, measured
153 * from upper-left outer corner of parent's
154 * border to upper-left outer corner of child's
155 * border. If not reparented then these are
157 int configWidth, configHeight;
158 /* Dimensions passed to last request that we
159 * issued to change geometry of window. Used
160 * to eliminate redundant resize operations. */
163 * Information about the virtual root window for this top-level,
167 Window vRoot; /* Virtual root window for this top-level,
168 * or None if there is no virtual root
169 * window (i.e. just use the screen's root). */
170 int vRootX, vRootY; /* Position of the virtual root inside the
171 * root window. If the WM_VROOT_OFFSET_STALE
172 * flag is set then this information may be
173 * incorrect and needs to be refreshed from
174 * the X server. If vRoot is None then these
175 * values are both 0. */
176 unsigned int vRootWidth, vRootHeight;
177 /* Dimensions of the virtual root window.
178 * If vRoot is None, gives the dimensions
179 * of the containing screen. This information
180 * is never stale, even though vRootX and
184 * List of children of the toplevel which have private colormaps.
187 TkWindow **cmapList; /* Array of window with private colormaps. */
188 int cmapCount; /* Number of windows in array. */
191 * Miscellaneous information.
194 ProtocolHandler *protPtr; /* First in list of protocol handlers for
195 * this window (NULL means none). */
196 int cmdArgc; /* Number of elements in cmdArgv below. */
197 char **cmdArgv; /* Array of strings to store in the
198 * WM_COMMAND property. NULL means nothing
200 char *clientMachine; /* String to store in WM_CLIENT_MACHINE
201 * property, or NULL. */
202 int flags; /* Miscellaneous flags, defined below. */
205 * Macintosh information.
207 int style; /* Native window style. */
208 TkWindow *scrollWinPtr; /* Ptr to scrollbar handling grow widget. */
213 * Flag values for WmInfo structures:
215 * WM_NEVER_MAPPED - non-zero means window has never been
216 * mapped; need to update all info when
217 * window is first mapped.
218 * WM_UPDATE_PENDING - non-zero means a call to UpdateGeometryInfo
219 * has already been scheduled for this
220 * window; no need to schedule another one.
221 * WM_NEGATIVE_X - non-zero means x-coordinate is measured in
222 * pixels from right edge of screen, rather
223 * than from left edge.
224 * WM_NEGATIVE_Y - non-zero means y-coordinate is measured in
225 * pixels up from bottom of screen, rather than
227 * WM_UPDATE_SIZE_HINTS - non-zero means that new size hints need to be
228 * propagated to window manager.
229 * WM_SYNC_PENDING - set to non-zero while waiting for the window
230 * manager to respond to some state change.
231 * WM_VROOT_OFFSET_STALE - non-zero means that (x,y) offset information
232 * about the virtual root window is stale and
233 * needs to be fetched fresh from the X server.
234 * WM_ABOUT_TO_MAP - non-zero means that the window is about to
235 * be mapped by TkWmMapWindow. This is used
236 * by UpdateGeometryInfo to modify its behavior.
237 * WM_MOVE_PENDING - non-zero means the application has requested
238 * a new position for the window, but it hasn't
239 * been reflected through the window manager
241 * WM_COLORMAPS_EXPLICIT - non-zero means the colormap windows were
242 * set explicitly via "wm colormapwindows".
243 * WM_ADDED_TOPLEVEL_COLORMAP - non-zero means that when "wm colormapwindows"
244 * was called the top-level itself wasn't
245 * specified, so we added it implicitly at
246 * the end of the list.
247 * WM_WIDTH_NOT_RESIZABLE - non-zero means that we're not supposed to
248 * allow the user to change the width of the
249 * window (controlled by "wm resizable"
251 * WM_HEIGHT_NOT_RESIZABLE - non-zero means that we're not supposed to
252 * allow the user to change the height of the
253 * window (controlled by "wm resizable"
257 #define WM_NEVER_MAPPED 1
258 #define WM_UPDATE_PENDING 2
259 #define WM_NEGATIVE_X 4
260 #define WM_NEGATIVE_Y 8
261 #define WM_UPDATE_SIZE_HINTS 0x10
262 #define WM_SYNC_PENDING 0x20
263 #define WM_VROOT_OFFSET_STALE 0x40
264 #define WM_ABOUT_TO_MAP 0x100
265 #define WM_MOVE_PENDING 0x200
266 #define WM_COLORMAPS_EXPLICIT 0x400
267 #define WM_ADDED_TOPLEVEL_COLORMAP 0x800
268 #define WM_WIDTH_NOT_RESIZABLE 0x1000
269 #define WM_HEIGHT_NOT_RESIZABLE 0x2000
272 * This is a list of all of the toplevels that have been mapped so far. It is
273 * used by the menu code to inval windows that were damaged by menus, and will
274 * eventually also be used to keep track of floating windows.
277 TkMacWindowList *tkMacWindowListPtr = NULL;
280 * The variable below is used to enable or disable tracing in this
281 * module. If tracing is enabled, then information is printed on
282 * standard output about interesting interactions with the window
286 static int wmTracing = 0;
289 * The following structure is the official type record for geometry
290 * management of top-level windows.
293 static void TopLevelReqProc _ANSI_ARGS_((ClientData dummy,
296 static Tk_GeomMgr wmMgrType = {
298 TopLevelReqProc, /* requestProc */
299 (Tk_GeomLostSlaveProc *) NULL, /* lostSlaveProc */
303 * Hash table for Mac Window -> TkWindow mapping.
306 static Tcl_HashTable windowTable;
307 static int windowHashInit = false;
309 void tkMacMoveWindow(WindowRef window, int x, int y);
312 * Forward declarations for procedures defined in this file:
315 static void InitialWindowBounds _ANSI_ARGS_((TkWindow *winPtr,
317 static int ParseGeometry _ANSI_ARGS_((Tcl_Interp *interp,
318 char *string, TkWindow *winPtr));
319 static void TopLevelEventProc _ANSI_ARGS_((ClientData clientData,
321 static void TopLevelReqProc _ANSI_ARGS_((ClientData dummy,
323 static void UpdateGeometryInfo _ANSI_ARGS_((
324 ClientData clientData));
325 static void UpdateSizeHints _ANSI_ARGS_((TkWindow *winPtr));
326 static void UpdateVRootGeometry _ANSI_ARGS_((WmInfo *wmPtr));
329 *--------------------------------------------------------------
333 * This procedure is invoked whenever a new top-level
334 * window is created. Its job is to initialize the WmInfo
335 * structure for the window.
341 * A WmInfo structure gets allocated and initialized.
343 *--------------------------------------------------------------
348 TkWindow *winPtr) /* Newly-created top-level window. */
350 register WmInfo *wmPtr;
352 wmPtr = (WmInfo *) ckalloc(sizeof(WmInfo));
353 wmPtr->winPtr = winPtr;
354 wmPtr->reparent = None;
355 wmPtr->titleUid = NULL;
356 wmPtr->iconName = NULL;
357 wmPtr->master = None;
358 wmPtr->hints.flags = InputHint | StateHint;
359 wmPtr->hints.input = True;
360 wmPtr->hints.initial_state = NormalState;
361 wmPtr->hints.icon_pixmap = None;
362 wmPtr->hints.icon_window = None;
363 wmPtr->hints.icon_x = wmPtr->hints.icon_y = 0;
364 wmPtr->hints.icon_mask = None;
365 wmPtr->hints.window_group = None;
366 wmPtr->leaderName = NULL;
367 wmPtr->masterWindowName = NULL;
369 wmPtr->iconFor = NULL;
370 wmPtr->sizeHintsFlags = 0;
371 wmPtr->minWidth = wmPtr->minHeight = 1;
374 * Default the maximum dimensions to the size of the display, minus
375 * a guess about how space is needed for window manager decorations.
378 wmPtr->maxWidth = DisplayWidth(winPtr->display, winPtr->screenNum) - 15;
379 wmPtr->maxHeight = DisplayHeight(winPtr->display, winPtr->screenNum) - 30;
380 wmPtr->gridWin = NULL;
381 wmPtr->widthInc = wmPtr->heightInc = 1;
382 wmPtr->minAspect.x = wmPtr->minAspect.y = 1;
383 wmPtr->maxAspect.x = wmPtr->maxAspect.y = 1;
384 wmPtr->reqGridWidth = wmPtr->reqGridHeight = -1;
385 wmPtr->gravity = NorthWestGravity;
388 wmPtr->x = winPtr->changes.x;
389 wmPtr->y = winPtr->changes.y;
390 wmPtr->parentWidth = winPtr->changes.width
391 + 2*winPtr->changes.border_width;
392 wmPtr->parentHeight = winPtr->changes.height
393 + 2*winPtr->changes.border_width;
394 wmPtr->xInParent = 0;
395 wmPtr->yInParent = 0;
396 wmPtr->cmapList = NULL;
397 wmPtr->cmapCount = 0;
398 wmPtr->configWidth = -1;
399 wmPtr->configHeight = -1;
401 wmPtr->protPtr = NULL;
402 wmPtr->cmdArgv = NULL;
403 wmPtr->clientMachine = NULL;
404 wmPtr->flags = WM_NEVER_MAPPED;
405 wmPtr->style = zoomDocProc;
406 wmPtr->scrollWinPtr = NULL;
407 winPtr->wmInfoPtr = wmPtr;
409 UpdateVRootGeometry(wmPtr);
412 * Tk must monitor structure events for top-level windows, in order
413 * to detect size and position changes caused by window managers.
416 Tk_CreateEventHandler((Tk_Window) winPtr, StructureNotifyMask,
417 TopLevelEventProc, (ClientData) winPtr);
420 * Arrange for geometry requests to be reflected from the window
421 * to the window manager.
424 Tk_ManageGeometry((Tk_Window) winPtr, &wmMgrType, (ClientData) 0);
428 *--------------------------------------------------------------
432 * This procedure is invoked to map a top-level window. This
433 * module gets a chance to update all window-manager-related
434 * information in properties before the window manager sees
435 * the map event and checks the properties. It also gets to
436 * decide whether or not to even map the window after all.
442 * Properties of winPtr may get updated to provide up-to-date
443 * information to the window manager. The window may also get
444 * mapped, but it may not be if this procedure decides that
445 * isn't appropriate (e.g. because the window is withdrawn).
447 *--------------------------------------------------------------
452 TkWindow *winPtr) /* Top-level window that's about to
455 register WmInfo *wmPtr = winPtr->wmInfoPtr;
456 Point where = {0, 0};
457 int xOffset, yOffset;
458 int firstMap = false;
461 if (wmPtr->flags & WM_NEVER_MAPPED) {
462 wmPtr->flags &= ~WM_NEVER_MAPPED;
466 * Create the underlying Mac window for this Tk window.
468 macWin = (MacDrawable *) winPtr->window;
469 if (!TkMacHostToplevelExists(winPtr)) {
470 TkMacMakeRealWindowExist(winPtr);
474 * Generate configure event when we first map the window.
476 LocalToGlobal(&where);
477 TkMacWindowOffset((WindowRef) TkMacGetDrawablePort((Drawable) macWin),
481 TkGenWMConfigureEvent((Tk_Window) winPtr,
482 where.h, where.v, -1, -1, TK_LOCATION_CHANGED);
485 * This is the first time this window has ever been mapped.
486 * Store all the window-manager-related information for the
490 if (wmPtr->titleUid == NULL) {
491 wmPtr->titleUid = winPtr->nameUid;
494 if (!Tk_IsEmbedded(winPtr)) {
495 TkSetWMName(winPtr, wmPtr->titleUid);
498 TkWmSetClass(winPtr);
500 if (wmPtr->iconName != NULL) {
501 XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
504 wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
506 if (wmPtr->hints.initial_state == WithdrawnState) {
511 * TODO: we need to display a window if it's iconic on creation.
514 if (wmPtr->hints.initial_state == IconicState) {
519 * Update geometry information.
521 wmPtr->flags |= WM_ABOUT_TO_MAP;
522 if (wmPtr->flags & WM_UPDATE_PENDING) {
523 Tk_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
525 UpdateGeometryInfo((ClientData) winPtr);
526 wmPtr->flags &= ~WM_ABOUT_TO_MAP;
532 XMapWindow(winPtr->display, winPtr->window);
535 * Now that the window is visable we can determine the offset
536 * from the window's content orgin to the window's decorative
537 * orgin (structure orgin).
539 TkMacWindowOffset((WindowRef) TkMacGetDrawablePort(Tk_WindowId(winPtr)),
540 &wmPtr->xInParent, &wmPtr->yInParent);
544 *--------------------------------------------------------------
548 * This procedure is invoked to unmap a top-level window.
549 * On the Macintosh all we do is call XUnmapWindow.
557 *--------------------------------------------------------------
562 TkWindow *winPtr) /* Top-level window that's about to
565 XUnmapWindow(winPtr->display, winPtr->window);
569 *--------------------------------------------------------------
573 * This procedure is invoked when a top-level window is
574 * about to be deleted. It cleans up the wm-related data
575 * structures for the window.
581 * The WmInfo structure for winPtr gets freed up.
583 *--------------------------------------------------------------
587 TkWmDeadWindow(winPtr)
588 TkWindow *winPtr; /* Top-level window that's being deleted. */
590 register WmInfo *wmPtr = winPtr->wmInfoPtr;
596 if (wmPtr->hints.flags & IconPixmapHint) {
597 Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
599 if (wmPtr->hints.flags & IconMaskHint) {
600 Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
602 if (wmPtr->leaderName != NULL) {
603 ckfree(wmPtr->leaderName);
605 if (wmPtr->masterWindowName != NULL) {
606 ckfree(wmPtr->masterWindowName);
608 if (wmPtr->icon != NULL) {
609 wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
610 wmPtr2->iconFor = NULL;
612 if (wmPtr->iconFor != NULL) {
613 wmPtr2 = ((TkWindow *) wmPtr->iconFor)->wmInfoPtr;
615 wmPtr2->hints.flags &= ~IconWindowHint;
617 while (wmPtr->protPtr != NULL) {
618 ProtocolHandler *protPtr;
620 protPtr = wmPtr->protPtr;
621 wmPtr->protPtr = protPtr->nextPtr;
622 Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
624 if (wmPtr->cmdArgv != NULL) {
625 ckfree((char *) wmPtr->cmdArgv);
627 if (wmPtr->clientMachine != NULL) {
628 ckfree((char *) wmPtr->clientMachine);
630 if (wmPtr->flags & WM_UPDATE_PENDING) {
631 Tk_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
633 ckfree((char *) wmPtr);
634 winPtr->wmInfoPtr = NULL;
638 *--------------------------------------------------------------
642 * This procedure is invoked whenever a top-level window's
643 * class is changed. If the window has been mapped then this
644 * procedure updates the window manager property for the
645 * class. If the window hasn't been mapped, the update is
646 * deferred until just before the first mapping.
652 * A window property may get updated.
654 *--------------------------------------------------------------
659 TkWindow *winPtr) /* Newly-created top-level window. */
665 *----------------------------------------------------------------------
669 * This procedure is invoked to process the "wm" Tcl command.
670 * See the user documentation for details on what it does.
673 * A standard Tcl result.
676 * See the user documentation.
678 *----------------------------------------------------------------------
684 ClientData clientData, /* Main window associated with
686 Tcl_Interp *interp, /* Current interpreter. */
687 int argc, /* Number of arguments. */
688 char **argv) /* Argument strings. */
690 Tk_Window tkwin = (Tk_Window) clientData;
692 register WmInfo *wmPtr;
698 Tcl_AppendResult(interp, "wrong # args: should be \"",
699 argv[0], " option window ?arg ...?\"", (char *) NULL);
703 length = strlen(argv[1]);
704 if ((c == 't') && (strncmp(argv[1], "tracing", length) == 0)
706 if ((argc != 2) && (argc != 3)) {
707 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
708 argv[0], " tracing ?boolean?\"", (char *) NULL);
712 interp->result = (wmTracing) ? "on" : "off";
715 return Tcl_GetBoolean(interp, argv[2], &wmTracing);
721 winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
722 if (winPtr == NULL) {
725 if (!(winPtr->flags & TK_TOP_LEVEL)) {
726 Tcl_AppendResult(interp, "window \"", winPtr->pathName,
727 "\" isn't a top-level window", (char *) NULL);
730 wmPtr = winPtr->wmInfoPtr;
731 if ((c == 'a') && (strncmp(argv[1], "aspect", length) == 0)) {
732 int numer1, denom1, numer2, denom2;
734 if ((argc != 3) && (argc != 7)) {
735 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
736 argv[0], " aspect window ?minNumer minDenom ",
737 "maxNumer maxDenom?\"", (char *) NULL);
741 if (wmPtr->sizeHintsFlags & PAspect) {
742 sprintf(interp->result, "%d %d %d %d", wmPtr->minAspect.x,
743 wmPtr->minAspect.y, wmPtr->maxAspect.x,
748 if (*argv[3] == '\0') {
749 wmPtr->sizeHintsFlags &= ~PAspect;
751 if ((Tcl_GetInt(interp, argv[3], &numer1) != TCL_OK)
752 || (Tcl_GetInt(interp, argv[4], &denom1) != TCL_OK)
753 || (Tcl_GetInt(interp, argv[5], &numer2) != TCL_OK)
754 || (Tcl_GetInt(interp, argv[6], &denom2) != TCL_OK)) {
757 if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) ||
759 interp->result = "aspect number can't be <= 0";
762 wmPtr->minAspect.x = numer1;
763 wmPtr->minAspect.y = denom1;
764 wmPtr->maxAspect.x = numer2;
765 wmPtr->maxAspect.y = denom2;
766 wmPtr->sizeHintsFlags |= PAspect;
768 wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
770 } else if ((c == 'c') && (strncmp(argv[1], "client", length) == 0)
772 if ((argc != 3) && (argc != 4)) {
773 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
774 argv[0], " client window ?name?\"",
779 if (wmPtr->clientMachine != NULL) {
780 interp->result = wmPtr->clientMachine;
784 if (argv[3][0] == 0) {
785 if (wmPtr->clientMachine != NULL) {
786 ckfree((char *) wmPtr->clientMachine);
787 wmPtr->clientMachine = NULL;
791 if (wmPtr->clientMachine != NULL) {
792 ckfree((char *) wmPtr->clientMachine);
794 wmPtr->clientMachine = (char *)
795 ckalloc((unsigned) (strlen(argv[3]) + 1));
796 strcpy(wmPtr->clientMachine, argv[3]);
797 } else if ((c == 'c') && (strncmp(argv[1], "colormapwindows", length) == 0)
801 int i, windowArgc, gotToplevel;
804 if ((argc != 3) && (argc != 4)) {
805 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
806 argv[0], " colormapwindows window ?windowList?\"",
811 Tk_MakeWindowExist((Tk_Window) winPtr);
812 for (i = 0; i < wmPtr->cmapCount; i++) {
813 if ((i == (wmPtr->cmapCount-1))
814 && (wmPtr->flags & WM_ADDED_TOPLEVEL_COLORMAP)) {
817 Tcl_AppendElement(interp, wmPtr->cmapList[i]->pathName);
821 if (Tcl_SplitList(interp, argv[3], &windowArgc, &windowArgv)
825 cmapList = (TkWindow **) ckalloc((unsigned)
826 ((windowArgc+1)*sizeof(TkWindow*)));
827 for (i = 0; i < windowArgc; i++) {
828 winPtr2 = (TkWindow *) Tk_NameToWindow(interp, windowArgv[i],
830 if (winPtr2 == NULL) {
831 ckfree((char *) cmapList);
832 ckfree((char *) windowArgv);
835 if (winPtr2 == winPtr) {
838 if (winPtr2->window == None) {
839 Tk_MakeWindowExist((Tk_Window) winPtr2);
841 cmapList[i] = winPtr2;
844 wmPtr->flags |= WM_ADDED_TOPLEVEL_COLORMAP;
845 cmapList[windowArgc] = winPtr;
848 wmPtr->flags &= ~WM_ADDED_TOPLEVEL_COLORMAP;
850 wmPtr->flags |= WM_COLORMAPS_EXPLICIT;
851 if (wmPtr->cmapList != NULL) {
852 ckfree((char *)wmPtr->cmapList);
854 wmPtr->cmapList = cmapList;
855 wmPtr->cmapCount = windowArgc;
856 ckfree((char *) windowArgv);
859 * On the Macintosh all of this is just an excercise
860 * in compatability as we don't support colormaps. If
861 * we did they would be installed here.
865 } else if ((c == 'c') && (strncmp(argv[1], "command", length) == 0)
870 if ((argc != 3) && (argc != 4)) {
871 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
872 argv[0], " command window ?value?\"",
877 if (wmPtr->cmdArgv != NULL) {
878 interp->result = Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv);
879 interp->freeProc = (Tcl_FreeProc *) free;
883 if (argv[3][0] == 0) {
884 if (wmPtr->cmdArgv != NULL) {
885 ckfree((char *) wmPtr->cmdArgv);
886 wmPtr->cmdArgv = NULL;
890 if (Tcl_SplitList(interp, argv[3], &cmdArgc, &cmdArgv) != TCL_OK) {
893 if (wmPtr->cmdArgv != NULL) {
894 ckfree((char *) wmPtr->cmdArgv);
896 wmPtr->cmdArgc = cmdArgc;
897 wmPtr->cmdArgv = cmdArgv;
898 } else if ((c == 'd') && (strncmp(argv[1], "deiconify", length) == 0)) {
900 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
901 argv[0], " deiconify window\"", (char *) NULL);
904 if (wmPtr->iconFor != NULL) {
905 Tcl_AppendResult(interp, "can't deiconify ", argv[2],
906 ": it is an icon for ", winPtr->pathName, (char *) NULL);
909 if (winPtr->flags & TK_EMBEDDED) {
910 Tcl_AppendResult(interp, "can't deiconify ", winPtr->pathName,
911 ": it is an embedded window", (char *) NULL);
916 * TODO: may not want to call this function - look at Map events gened.
919 TkpWmSetState(winPtr, NormalState);
920 } else if ((c == 'f') && (strncmp(argv[1], "focusmodel", length) == 0)
922 if ((argc != 3) && (argc != 4)) {
923 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
924 argv[0], " focusmodel window ?active|passive?\"",
929 interp->result = wmPtr->hints.input ? "passive" : "active";
933 length = strlen(argv[3]);
934 if ((c == 'a') && (strncmp(argv[3], "active", length) == 0)) {
935 wmPtr->hints.input = False;
936 } else if ((c == 'p') && (strncmp(argv[3], "passive", length) == 0)) {
937 wmPtr->hints.input = True;
939 Tcl_AppendResult(interp, "bad argument \"", argv[3],
940 "\": must be active or passive", (char *) NULL);
943 } else if ((c == 'f') && (strncmp(argv[1], "frame", length) == 0)
948 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
949 argv[0], " frame window\"", (char *) NULL);
952 window = wmPtr->reparent;
953 if (window == None) {
954 window = Tk_WindowId((Tk_Window) winPtr);
956 sprintf(interp->result, "0x%x", (unsigned int) window);
957 } else if ((c == 'g') && (strncmp(argv[1], "geometry", length) == 0)
962 if ((argc != 3) && (argc != 4)) {
963 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
964 argv[0], " geometry window ?newGeometry?\"",
969 xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+';
970 ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+';
971 if (wmPtr->gridWin != NULL) {
972 width = wmPtr->reqGridWidth + (winPtr->changes.width
973 - winPtr->reqWidth)/wmPtr->widthInc;
974 height = wmPtr->reqGridHeight + (winPtr->changes.height
975 - winPtr->reqHeight)/wmPtr->heightInc;
977 width = winPtr->changes.width;
978 height = winPtr->changes.height;
980 sprintf(interp->result, "%dx%d%c%d%c%d", width, height,
981 xSign, wmPtr->x, ySign, wmPtr->y);
984 if (*argv[3] == '\0') {
989 return ParseGeometry(interp, argv[3], winPtr);
990 } else if ((c == 'g') && (strncmp(argv[1], "grid", length) == 0)
992 int reqWidth, reqHeight, widthInc, heightInc;
994 if ((argc != 3) && (argc != 7)) {
995 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
996 argv[0], " grid window ?baseWidth baseHeight ",
997 "widthInc heightInc?\"", (char *) NULL);
1001 if (wmPtr->sizeHintsFlags & PBaseSize) {
1002 sprintf(interp->result, "%d %d %d %d", wmPtr->reqGridWidth,
1003 wmPtr->reqGridHeight, wmPtr->widthInc,
1008 if (*argv[3] == '\0') {
1010 * Turn off gridding and reset the width and height
1011 * to make sense as ungridded numbers.
1014 wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
1015 if (wmPtr->width != -1) {
1016 wmPtr->width = winPtr->reqWidth + (wmPtr->width
1017 - wmPtr->reqGridWidth)*wmPtr->widthInc;
1018 wmPtr->height = winPtr->reqHeight + (wmPtr->height
1019 - wmPtr->reqGridHeight)*wmPtr->heightInc;
1021 wmPtr->widthInc = 1;
1022 wmPtr->heightInc = 1;
1024 if ((Tcl_GetInt(interp, argv[3], &reqWidth) != TCL_OK)
1025 || (Tcl_GetInt(interp, argv[4], &reqHeight) != TCL_OK)
1026 || (Tcl_GetInt(interp, argv[5], &widthInc) != TCL_OK)
1027 || (Tcl_GetInt(interp, argv[6], &heightInc) != TCL_OK)) {
1031 interp->result = "baseWidth can't be < 0";
1034 if (reqHeight < 0) {
1035 interp->result = "baseHeight can't be < 0";
1039 interp->result = "widthInc can't be < 0";
1042 if (heightInc < 0) {
1043 interp->result = "heightInc can't be < 0";
1046 Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc,
1049 wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1051 } else if ((c == 'g') && (strncmp(argv[1], "group", length) == 0)
1055 if ((argc != 3) && (argc != 4)) {
1056 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1057 argv[0], " group window ?pathName?\"",
1062 if (wmPtr->hints.flags & WindowGroupHint) {
1063 interp->result = wmPtr->leaderName;
1067 if (*argv[3] == '\0') {
1068 wmPtr->hints.flags &= ~WindowGroupHint;
1069 if (wmPtr->leaderName != NULL) {
1070 ckfree(wmPtr->leaderName);
1072 wmPtr->leaderName = NULL;
1074 tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
1075 if (tkwin2 == NULL) {
1078 Tk_MakeWindowExist(tkwin2);
1079 wmPtr->hints.window_group = Tk_WindowId(tkwin2);
1080 wmPtr->hints.flags |= WindowGroupHint;
1081 wmPtr->leaderName = ckalloc((unsigned) (strlen(argv[3])+1));
1082 strcpy(wmPtr->leaderName, argv[3]);
1084 } else if ((c == 'i') && (strncmp(argv[1], "iconbitmap", length) == 0)
1088 if ((argc != 3) && (argc != 4)) {
1089 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1090 argv[0], " iconbitmap window ?bitmap?\"",
1095 if (wmPtr->hints.flags & IconPixmapHint) {
1096 interp->result = Tk_NameOfBitmap(winPtr->display,
1097 wmPtr->hints.icon_pixmap);
1101 if (*argv[3] == '\0') {
1102 if (wmPtr->hints.icon_pixmap != None) {
1103 Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
1105 wmPtr->hints.flags &= ~IconPixmapHint;
1107 pixmap = Tk_GetBitmap(interp, (Tk_Window) winPtr,
1108 Tk_GetUid(argv[3]));
1109 if (pixmap == None) {
1112 wmPtr->hints.icon_pixmap = pixmap;
1113 wmPtr->hints.flags |= IconPixmapHint;
1115 } else if ((c == 'i') && (strncmp(argv[1], "iconify", length) == 0)
1118 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1119 argv[0], " iconify window\"", (char *) NULL);
1122 if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
1123 Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
1124 "\": override-redirect flag is set", (char *) NULL);
1127 if (wmPtr->master != None) {
1128 Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
1129 "\": it is a transient", (char *) NULL);
1132 if (wmPtr->iconFor != NULL) {
1133 Tcl_AppendResult(interp, "can't iconify ", argv[2],
1134 ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
1138 if (winPtr->flags & TK_EMBEDDED) {
1139 Tcl_AppendResult(interp, "can't iconify ", winPtr->pathName,
1140 ": it is an embedded window", (char *) NULL);
1143 TkpWmSetState(winPtr, IconicState);
1144 } else if ((c == 'i') && (strncmp(argv[1], "iconmask", length) == 0)
1148 if ((argc != 3) && (argc != 4)) {
1149 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1150 argv[0], " iconmask window ?bitmap?\"",
1155 if (wmPtr->hints.flags & IconMaskHint) {
1156 interp->result = Tk_NameOfBitmap(winPtr->display,
1157 wmPtr->hints.icon_mask);
1161 if (*argv[3] == '\0') {
1162 if (wmPtr->hints.icon_mask != None) {
1163 Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
1165 wmPtr->hints.flags &= ~IconMaskHint;
1167 pixmap = Tk_GetBitmap(interp, tkwin, Tk_GetUid(argv[3]));
1168 if (pixmap == None) {
1171 wmPtr->hints.icon_mask = pixmap;
1172 wmPtr->hints.flags |= IconMaskHint;
1174 } else if ((c == 'i') && (strncmp(argv[1], "iconname", length) == 0)
1177 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1178 argv[0], " iconname window ?newName?\"", (char *) NULL);
1182 interp->result = (wmPtr->iconName != NULL) ? wmPtr->iconName : "";
1185 wmPtr->iconName = Tk_GetUid(argv[3]);
1186 if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
1187 XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
1190 } else if ((c == 'i') && (strncmp(argv[1], "iconposition", length) == 0)
1194 if ((argc != 3) && (argc != 5)) {
1195 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1196 argv[0], " iconposition window ?x y?\"",
1201 if (wmPtr->hints.flags & IconPositionHint) {
1202 sprintf(interp->result, "%d %d", wmPtr->hints.icon_x,
1203 wmPtr->hints.icon_y);
1207 if (*argv[3] == '\0') {
1208 wmPtr->hints.flags &= ~IconPositionHint;
1210 if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK)
1211 || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)){
1214 wmPtr->hints.icon_x = x;
1215 wmPtr->hints.icon_y = y;
1216 wmPtr->hints.flags |= IconPositionHint;
1218 } else if ((c == 'i') && (strncmp(argv[1], "iconwindow", length) == 0)
1223 if ((argc != 3) && (argc != 4)) {
1224 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1225 argv[0], " iconwindow window ?pathName?\"",
1230 if (wmPtr->icon != NULL) {
1231 interp->result = Tk_PathName(wmPtr->icon);
1235 if (*argv[3] == '\0') {
1236 wmPtr->hints.flags &= ~IconWindowHint;
1237 if (wmPtr->icon != NULL) {
1238 wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
1239 wmPtr2->iconFor = NULL;
1240 wmPtr2->hints.initial_state = WithdrawnState;
1244 tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
1245 if (tkwin2 == NULL) {
1248 if (!Tk_IsTopLevel(tkwin2)) {
1249 Tcl_AppendResult(interp, "can't use ", argv[3],
1250 " as icon window: not at top level", (char *) NULL);
1253 wmPtr2 = ((TkWindow *) tkwin2)->wmInfoPtr;
1254 if (wmPtr2->iconFor != NULL) {
1255 Tcl_AppendResult(interp, argv[3], " is already an icon for ",
1256 Tk_PathName(wmPtr2->iconFor), (char *) NULL);
1259 if (wmPtr->icon != NULL) {
1260 WmInfo *wmPtr3 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
1261 wmPtr3->iconFor = NULL;
1263 Tk_MakeWindowExist(tkwin2);
1264 wmPtr->hints.icon_window = Tk_WindowId(tkwin2);
1265 wmPtr->hints.flags |= IconWindowHint;
1266 wmPtr->icon = tkwin2;
1267 wmPtr2->iconFor = (Tk_Window) winPtr;
1268 if (!(wmPtr2->flags & WM_NEVER_MAPPED)) {
1270 * Don't have iconwindows on the Mac. We just withdraw.
1273 Tk_UnmapWindow(tkwin2);
1276 } else if ((c == 'm') && (strncmp(argv[1], "maxsize", length) == 0)
1279 if ((argc != 3) && (argc != 5)) {
1280 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1281 argv[0], " maxsize window ?width height?\"", (char *) NULL);
1285 sprintf(interp->result, "%d %d", wmPtr->maxWidth,
1289 if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
1290 || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
1293 wmPtr->maxWidth = width;
1294 wmPtr->maxHeight = height;
1295 wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1297 } else if ((c == 'm') && (strncmp(argv[1], "minsize", length) == 0)
1300 if ((argc != 3) && (argc != 5)) {
1301 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1302 argv[0], " minsize window ?width height?\"", (char *) NULL);
1306 sprintf(interp->result, "%d %d", wmPtr->minWidth,
1310 if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
1311 || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
1314 wmPtr->minWidth = width;
1315 wmPtr->minHeight = height;
1316 wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1318 } else if ((c == 'o')
1319 && (strncmp(argv[1], "overrideredirect", length) == 0)) {
1321 XSetWindowAttributes atts;
1323 if ((argc != 3) && (argc != 4)) {
1324 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1325 argv[0], " overrideredirect window ?boolean?\"",
1330 if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
1331 interp->result = "1";
1333 interp->result = "0";
1337 if (Tcl_GetBoolean(interp, argv[3], &boolean) != TCL_OK) {
1340 atts.override_redirect = (boolean) ? True : False;
1341 Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect,
1343 wmPtr->style = (boolean) ? plainDBox : documentProc;
1344 } else if ((c == 'p') && (strncmp(argv[1], "positionfrom", length) == 0)
1346 if ((argc != 3) && (argc != 4)) {
1347 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1348 argv[0], " positionfrom window ?user/program?\"",
1353 if (wmPtr->sizeHintsFlags & USPosition) {
1354 interp->result = "user";
1355 } else if (wmPtr->sizeHintsFlags & PPosition) {
1356 interp->result = "program";
1360 if (*argv[3] == '\0') {
1361 wmPtr->sizeHintsFlags &= ~(USPosition|PPosition);
1364 length = strlen(argv[3]);
1365 if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
1366 wmPtr->sizeHintsFlags &= ~PPosition;
1367 wmPtr->sizeHintsFlags |= USPosition;
1368 } else if ((c == 'p') &&
1369 (strncmp(argv[3], "program", length) == 0)) {
1370 wmPtr->sizeHintsFlags &= ~USPosition;
1371 wmPtr->sizeHintsFlags |= PPosition;
1373 Tcl_AppendResult(interp, "bad argument \"", argv[3],
1374 "\": must be program or user", (char *) NULL);
1378 wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1380 } else if ((c == 'p') && (strncmp(argv[1], "protocol", length) == 0)
1382 register ProtocolHandler *protPtr, *prevPtr;
1386 if ((argc < 3) || (argc > 5)) {
1387 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1388 argv[0], " protocol window ?name? ?command?\"",
1394 * Return a list of all defined protocols for the window.
1396 for (protPtr = wmPtr->protPtr; protPtr != NULL;
1397 protPtr = protPtr->nextPtr) {
1398 Tcl_AppendElement(interp,
1399 Tk_GetAtomName((Tk_Window) winPtr, protPtr->protocol));
1403 protocol = Tk_InternAtom((Tk_Window) winPtr, argv[3]);
1406 * Return the command to handle a given protocol.
1408 for (protPtr = wmPtr->protPtr; protPtr != NULL;
1409 protPtr = protPtr->nextPtr) {
1410 if (protPtr->protocol == protocol) {
1411 interp->result = protPtr->command;
1419 * Delete any current protocol handler, then create a new
1420 * one with the specified command, unless the command is
1424 for (protPtr = wmPtr->protPtr, prevPtr = NULL; protPtr != NULL;
1425 prevPtr = protPtr, protPtr = protPtr->nextPtr) {
1426 if (protPtr->protocol == protocol) {
1427 if (prevPtr == NULL) {
1428 wmPtr->protPtr = protPtr->nextPtr;
1430 prevPtr->nextPtr = protPtr->nextPtr;
1432 Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
1436 cmdLength = strlen(argv[4]);
1437 if (cmdLength > 0) {
1438 protPtr = (ProtocolHandler *) ckalloc(HANDLER_SIZE(cmdLength));
1439 protPtr->protocol = protocol;
1440 protPtr->nextPtr = wmPtr->protPtr;
1441 wmPtr->protPtr = protPtr;
1442 protPtr->interp = interp;
1443 strcpy(protPtr->command, argv[4]);
1445 } else if ((c == 'r') && (strncmp(argv[1], "resizable", length) == 0)) {
1448 if ((argc != 3) && (argc != 5)) {
1449 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1450 argv[0], " resizable window ?width height?\"",
1455 sprintf(interp->result, "%d %d",
1456 (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) ? 0 : 1,
1457 (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) ? 0 : 1);
1460 if ((Tcl_GetBoolean(interp, argv[3], &width) != TCL_OK)
1461 || (Tcl_GetBoolean(interp, argv[4], &height) != TCL_OK)) {
1465 wmPtr->flags &= ~WM_WIDTH_NOT_RESIZABLE;
1467 wmPtr->flags |= WM_WIDTH_NOT_RESIZABLE;
1470 wmPtr->flags &= ~WM_HEIGHT_NOT_RESIZABLE;
1472 wmPtr->flags |= WM_HEIGHT_NOT_RESIZABLE;
1474 wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1475 if (wmPtr->scrollWinPtr != NULL) {
1476 TkScrollbarEventuallyRedraw(
1477 (TkScrollbar *) wmPtr->scrollWinPtr->instanceData);
1480 } else if ((c == 's') && (strncmp(argv[1], "sizefrom", length) == 0)
1482 if ((argc != 3) && (argc != 4)) {
1483 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1484 argv[0], " sizefrom window ?user|program?\"",
1489 if (wmPtr->sizeHintsFlags & USSize) {
1490 interp->result = "user";
1491 } else if (wmPtr->sizeHintsFlags & PSize) {
1492 interp->result = "program";
1496 if (*argv[3] == '\0') {
1497 wmPtr->sizeHintsFlags &= ~(USSize|PSize);
1500 length = strlen(argv[3]);
1501 if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
1502 wmPtr->sizeHintsFlags &= ~PSize;
1503 wmPtr->sizeHintsFlags |= USSize;
1504 } else if ((c == 'p')
1505 && (strncmp(argv[3], "program", length) == 0)) {
1506 wmPtr->sizeHintsFlags &= ~USSize;
1507 wmPtr->sizeHintsFlags |= PSize;
1509 Tcl_AppendResult(interp, "bad argument \"", argv[3],
1510 "\": must be program or user", (char *) NULL);
1514 wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1516 } else if ((c == 's') && (strncmp(argv[1], "state", length) == 0)
1519 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1520 argv[0], " state window\"", (char *) NULL);
1523 if (wmPtr->iconFor != NULL) {
1524 interp->result = "icon";
1526 switch (wmPtr->hints.initial_state) {
1528 interp->result = "normal";
1531 interp->result = "iconic";
1533 case WithdrawnState:
1534 interp->result = "withdrawn";
1537 interp->result = "zoomed";
1541 } else if ((c == 't') && (strncmp(argv[1], "title", length) == 0)
1544 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1545 argv[0], " title window ?newTitle?\"", (char *) NULL);
1549 interp->result = (wmPtr->titleUid != NULL) ? wmPtr->titleUid
1553 wmPtr->titleUid = Tk_GetUid(argv[3]);
1554 if (!(wmPtr->flags & WM_NEVER_MAPPED) && !Tk_IsEmbedded(winPtr)) {
1555 TkSetWMName(winPtr, wmPtr->titleUid);
1558 } else if ((c == 't') && (strncmp(argv[1], "transient", length) == 0)
1562 if ((argc != 3) && (argc != 4)) {
1563 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1564 argv[0], " transient window ?master?\"", (char *) NULL);
1568 if (wmPtr->master != None) {
1569 interp->result = wmPtr->masterWindowName;
1573 if (argv[3][0] == '\0') {
1574 wmPtr->master = None;
1575 if (wmPtr->masterWindowName != NULL) {
1576 ckfree(wmPtr->masterWindowName);
1578 wmPtr->masterWindowName = NULL;
1579 wmPtr->style = documentProc;
1581 master = Tk_NameToWindow(interp, argv[3], tkwin);
1582 if (master == NULL) {
1585 Tk_MakeWindowExist(master);
1586 wmPtr->master = Tk_WindowId(master);
1587 wmPtr->masterWindowName = ckalloc((unsigned) (strlen(argv[3])+1));
1588 strcpy(wmPtr->masterWindowName, argv[3]);
1589 wmPtr->style = plainDBox;
1591 } else if ((c == 'w') && (strncmp(argv[1], "withdraw", length) == 0)) {
1593 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1594 argv[0], " withdraw window\"", (char *) NULL);
1597 if (wmPtr->iconFor != NULL) {
1598 Tcl_AppendResult(interp, "can't withdraw ", argv[2],
1599 ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
1603 TkpWmSetState(winPtr, WithdrawnState);
1605 Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],
1606 "\": must be aspect, client, command, deiconify, ",
1607 "focusmodel, frame, geometry, grid, group, iconbitmap, ",
1608 "iconify, iconmask, iconname, iconposition, ",
1609 "iconwindow, maxsize, minsize, overrideredirect, ",
1610 "positionfrom, protocol, resizable, sizefrom, state, title, ",
1611 "transient, or withdraw",
1618 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
1619 Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
1620 wmPtr->flags |= WM_UPDATE_PENDING;
1626 *----------------------------------------------------------------------
1630 * This procedure is invoked by a widget when it wishes to set a grid
1631 * coordinate system that controls the size of a top-level window.
1632 * It provides a C interface equivalent to the "wm grid" command and
1633 * is usually asscoiated with the -setgrid option.
1639 * Grid-related information will be passed to the window manager, so
1640 * that the top-level window associated with tkwin will resize on
1641 * even grid units. If some other window already controls gridding
1642 * for the top-level window then this procedure call has no effect.
1644 *----------------------------------------------------------------------
1649 Tk_Window tkwin, /* Token for window. New window mgr info
1650 * will be posted for the top-level window
1651 * associated with this window. */
1652 int reqWidth, /* Width (in grid units) corresponding to
1653 * the requested geometry for tkwin. */
1654 int reqHeight, /* Height (in grid units) corresponding to
1655 * the requested geometry for tkwin. */
1656 int widthInc, int heightInc)/* Pixel increments corresponding to a
1657 * change of one grid unit. */
1659 TkWindow *winPtr = (TkWindow *) tkwin;
1660 register WmInfo *wmPtr;
1663 * Find the top-level window for tkwin, plus the window manager
1667 while (!(winPtr->flags & TK_TOP_LEVEL)) {
1668 winPtr = winPtr->parentPtr;
1670 wmPtr = winPtr->wmInfoPtr;
1672 if ((wmPtr->gridWin != NULL) && (wmPtr->gridWin != tkwin)) {
1676 if ((wmPtr->reqGridWidth == reqWidth)
1677 && (wmPtr->reqGridHeight == reqHeight)
1678 && (wmPtr->widthInc == widthInc)
1679 && (wmPtr->heightInc == heightInc)
1680 && ((wmPtr->sizeHintsFlags & (PBaseSize|PResizeInc))
1681 == PBaseSize|PResizeInc)) {
1686 * If gridding was previously off, then forget about any window
1687 * size requests made by the user or via "wm geometry": these are
1688 * in pixel units and there's no easy way to translate them to
1689 * grid units since the new requested size of the top-level window in
1690 * pixels may not yet have been registered yet (it may filter up
1691 * the hierarchy in DoWhenIdle handlers). However, if the window
1692 * has never been mapped yet then just leave the window size alone:
1693 * assume that it is intended to be in grid units but just happened
1694 * to have been specified before this procedure was called.
1697 if ((wmPtr->gridWin == NULL) && !(wmPtr->flags & WM_NEVER_MAPPED)) {
1703 * Set the new gridding information, and start the process of passing
1704 * all of this information to the window manager.
1707 wmPtr->gridWin = tkwin;
1708 wmPtr->reqGridWidth = reqWidth;
1709 wmPtr->reqGridHeight = reqHeight;
1710 wmPtr->widthInc = widthInc;
1711 wmPtr->heightInc = heightInc;
1712 wmPtr->sizeHintsFlags |= PBaseSize|PResizeInc;
1713 wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1714 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
1715 Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
1716 wmPtr->flags |= WM_UPDATE_PENDING;
1721 *----------------------------------------------------------------------
1725 * This procedure cancels the effect of a previous call
1732 * If tkwin currently controls gridding for its top-level window,
1733 * gridding is cancelled for that top-level window; if some other
1734 * window controls gridding then this procedure has no effect.
1736 *----------------------------------------------------------------------
1741 Tk_Window tkwin) /* Token for window that is currently
1742 * controlling gridding. */
1744 TkWindow *winPtr = (TkWindow *) tkwin;
1745 register WmInfo *wmPtr;
1748 * Find the top-level window for tkwin, plus the window manager
1752 while (!(winPtr->flags & TK_TOP_LEVEL)) {
1753 winPtr = winPtr->parentPtr;
1755 wmPtr = winPtr->wmInfoPtr;
1756 if (tkwin != wmPtr->gridWin) {
1760 wmPtr->gridWin = NULL;
1761 wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
1762 if (wmPtr->width != -1) {
1763 wmPtr->width = winPtr->reqWidth + (wmPtr->width
1764 - wmPtr->reqGridWidth)*wmPtr->widthInc;
1765 wmPtr->height = winPtr->reqHeight + (wmPtr->height
1766 - wmPtr->reqGridHeight)*wmPtr->heightInc;
1768 wmPtr->widthInc = 1;
1769 wmPtr->heightInc = 1;
1771 wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1772 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
1773 Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
1774 wmPtr->flags |= WM_UPDATE_PENDING;
1779 *----------------------------------------------------------------------
1781 * TopLevelEventProc --
1783 * This procedure is invoked when a top-level (or other externally-
1784 * managed window) is restructured in any way.
1790 * Tk's internal data structures for the window get modified to
1791 * reflect the structural change.
1793 *----------------------------------------------------------------------
1798 ClientData clientData, /* Window for which event occurred. */
1799 XEvent *eventPtr) /* Event that just happened. */
1801 register TkWindow *winPtr = (TkWindow *) clientData;
1803 winPtr->wmInfoPtr->flags |= WM_VROOT_OFFSET_STALE;
1804 if (eventPtr->type == DestroyNotify) {
1805 Tk_ErrorHandler handler;
1807 if (!(winPtr->flags & TK_ALREADY_DEAD)) {
1809 * A top-level window was deleted externally (e.g., by the window
1810 * manager). This is probably not a good thing, but cleanup as
1811 * best we can. The error handler is needed because
1812 * Tk_DestroyWindow will try to destroy the window, but of course
1813 * it's already gone.
1816 handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
1817 (Tk_ErrorProc *) NULL, (ClientData) NULL);
1818 Tk_DestroyWindow((Tk_Window) winPtr);
1819 Tk_DeleteErrorHandler(handler);
1822 printf("TopLevelEventProc: %s deleted\n", winPtr->pathName);
1824 } else if (eventPtr->type == ReparentNotify) {
1825 panic("recieved unwanted reparent event");
1830 *----------------------------------------------------------------------
1832 * TopLevelReqProc --
1834 * This procedure is invoked by the geometry manager whenever
1835 * the requested size for a top-level window is changed.
1841 * Arrange for the window to be resized to satisfy the request
1842 * (this happens as a when-idle action).
1844 *----------------------------------------------------------------------
1850 ClientData dummy, /* Not used. */
1851 Tk_Window tkwin) /* Information about window. */
1853 TkWindow *winPtr = (TkWindow *) tkwin;
1856 wmPtr = winPtr->wmInfoPtr;
1857 wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1858 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
1859 Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
1860 wmPtr->flags |= WM_UPDATE_PENDING;
1865 *----------------------------------------------------------------------
1867 * UpdateGeometryInfo --
1869 * This procedure is invoked when a top-level window is first
1870 * mapped, and also as a when-idle procedure, to bring the
1871 * geometry and/or position of a top-level window back into
1872 * line with what has been requested by the user and/or widgets.
1873 * This procedure doesn't return until the window manager has
1874 * responded to the geometry change.
1880 * The window's size and location may change, unless the WM prevents
1881 * that from happening.
1883 *----------------------------------------------------------------------
1888 ClientData clientData) /* Pointer to the window's record. */
1890 register TkWindow *winPtr = (TkWindow *) clientData;
1891 register WmInfo *wmPtr = winPtr->wmInfoPtr;
1892 int x, y, width, height;
1893 unsigned long serial;
1895 wmPtr->flags &= ~WM_UPDATE_PENDING;
1898 * Compute the new size for the top-level window. See the
1899 * user documentation for details on this, but the size
1900 * requested depends on (a) the size requested internally
1901 * by the window's widgets, (b) the size requested by the
1902 * user in a "wm geometry" command or via wm-based interactive
1903 * resizing (if any), and (c) whether or not the window is
1904 * gridded. Don't permit sizes <= 0 because this upsets
1908 if (wmPtr->width == -1) {
1909 width = winPtr->reqWidth;
1910 } else if (wmPtr->gridWin != NULL) {
1911 width = winPtr->reqWidth
1912 + (wmPtr->width - wmPtr->reqGridWidth)*wmPtr->widthInc;
1914 width = wmPtr->width;
1919 if (wmPtr->height == -1) {
1920 height = winPtr->reqHeight;
1921 } else if (wmPtr->gridWin != NULL) {
1922 height = winPtr->reqHeight
1923 + (wmPtr->height - wmPtr->reqGridHeight)*wmPtr->heightInc;
1925 height = wmPtr->height;
1932 * Compute the new position for the upper-left pixel of the window's
1933 * decorative frame. This is tricky, because we need to include the
1934 * border widths supplied by a reparented parent in this calculation,
1935 * but can't use the parent's current overall size since that may
1936 * change as a result of this code.
1939 if (wmPtr->flags & WM_NEGATIVE_X) {
1940 x = wmPtr->vRootWidth - wmPtr->x
1941 - (width + (wmPtr->parentWidth - winPtr->changes.width));
1945 if (wmPtr->flags & WM_NEGATIVE_Y) {
1946 y = wmPtr->vRootHeight - wmPtr->y
1947 - (height + (wmPtr->parentHeight - winPtr->changes.height));
1953 * If the window's size is going to change and the window is
1954 * supposed to not be resizable by the user, then we have to
1955 * update the size hints. There may also be a size-hint-update
1956 * request pending from somewhere else, too.
1959 if (((width != winPtr->changes.width)
1960 || (height != winPtr->changes.height))
1961 && (wmPtr->gridWin == NULL)
1962 && ((wmPtr->sizeHintsFlags & (PMinSize|PMaxSize)) == 0)) {
1963 wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1965 if (wmPtr->flags & WM_UPDATE_SIZE_HINTS) {
1966 UpdateSizeHints(winPtr);
1970 * Reconfigure the window if it isn't already configured correctly.
1971 * A few tricky points:
1973 * 1. If the window is embedded and the container is also in this
1974 * process, don't actually reconfigure the window; just pass the
1975 * desired size on to the container. Also, zero out any position
1976 * information, since embedded windows are not allowed to move.
1977 * 2. Sometimes the window manager will give us a different size
1978 * than we asked for (e.g. mwm has a minimum size for windows), so
1979 * base the size check on what we *asked for* last time, not what we
1981 * 3. Don't move window unless a new position has been requested for
1982 * it. This is because of "features" in some window managers (e.g.
1983 * twm, as of 4/24/91) where they don't interpret coordinates
1984 * according to ICCCM. Moving a window to its current location may
1985 * cause it to shift position on the screen.
1988 if (Tk_IsEmbedded(winPtr)) {
1989 TkWindow *contWinPtr;
1991 contWinPtr = TkpGetOtherWindow(winPtr);
1994 * NOTE: Here we should handle out of process embedding.
1997 if (contWinPtr != NULL) {
1999 * This window is embedded and the container is also in this
2000 * process, so we don't need to do anything special about the
2001 * geometry, except to make sure that the desired size is known
2002 * by the container. Also, zero out any position information,
2003 * since embedded windows are not allowed to move.
2006 wmPtr->x = wmPtr->y = 0;
2007 wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y);
2008 Tk_GeometryRequest((Tk_Window) contWinPtr, width, height);
2012 serial = NextRequest(winPtr->display);
2013 if (wmPtr->flags & WM_MOVE_PENDING) {
2014 wmPtr->configWidth = width;
2015 wmPtr->configHeight = height;
2018 "UpdateGeometryInfo moving to %d %d, resizing to %d x %d,\n",
2019 x, y, width, height);
2021 Tk_MoveResizeWindow((Tk_Window) winPtr, x, y, (unsigned) width,
2023 } else if ((width != wmPtr->configWidth)
2024 || (height != wmPtr->configHeight)) {
2025 wmPtr->configWidth = width;
2026 wmPtr->configHeight = height;
2028 printf("UpdateGeometryInfo resizing to %d x %d\n", width, height);
2030 Tk_ResizeWindow((Tk_Window) winPtr, (unsigned) width,
2038 *--------------------------------------------------------------
2040 * UpdateSizeHints --
2042 * This procedure is called to update the window manager's
2043 * size hints information from the information in a WmInfo
2050 * Properties get changed for winPtr.
2052 *--------------------------------------------------------------
2059 register WmInfo *wmPtr = winPtr->wmInfoPtr;
2060 XSizeHints *hintsPtr;
2062 wmPtr->flags &= ~WM_UPDATE_SIZE_HINTS;
2064 hintsPtr = XAllocSizeHints();
2065 if (hintsPtr == NULL) {
2070 * Compute the pixel-based sizes for the various fields in the
2071 * size hints structure, based on the grid-based sizes in
2075 if (wmPtr->gridWin != NULL) {
2076 hintsPtr->base_width = winPtr->reqWidth
2077 - (wmPtr->reqGridWidth * wmPtr->widthInc);
2078 if (hintsPtr->base_width < 0) {
2079 hintsPtr->base_width = 0;
2081 hintsPtr->base_height = winPtr->reqHeight
2082 - (wmPtr->reqGridHeight * wmPtr->heightInc);
2083 if (hintsPtr->base_height < 0) {
2084 hintsPtr->base_height = 0;
2086 hintsPtr->min_width = hintsPtr->base_width
2087 + (wmPtr->minWidth * wmPtr->widthInc);
2088 hintsPtr->min_height = hintsPtr->base_height
2089 + (wmPtr->minHeight * wmPtr->heightInc);
2090 hintsPtr->max_width = hintsPtr->base_width
2091 + (wmPtr->maxWidth * wmPtr->widthInc);
2092 hintsPtr->max_height = hintsPtr->base_height
2093 + (wmPtr->maxHeight * wmPtr->heightInc);
2095 hintsPtr->min_width = wmPtr->minWidth;
2096 hintsPtr->min_height = wmPtr->minHeight;
2097 hintsPtr->max_width = wmPtr->maxWidth;
2098 hintsPtr->max_height = wmPtr->maxHeight;
2099 hintsPtr->base_width = 0;
2100 hintsPtr->base_height = 0;
2102 hintsPtr->width_inc = wmPtr->widthInc;
2103 hintsPtr->height_inc = wmPtr->heightInc;
2104 hintsPtr->min_aspect.x = wmPtr->minAspect.x;
2105 hintsPtr->min_aspect.y = wmPtr->minAspect.y;
2106 hintsPtr->max_aspect.x = wmPtr->maxAspect.x;
2107 hintsPtr->max_aspect.y = wmPtr->maxAspect.y;
2108 hintsPtr->win_gravity = wmPtr->gravity;
2109 hintsPtr->flags = wmPtr->sizeHintsFlags | PMinSize | PMaxSize;
2112 * If the window isn't supposed to be resizable, then set the
2113 * minimum and maximum dimensions to be the same.
2116 if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) {
2117 if (wmPtr->width >= 0) {
2118 hintsPtr->min_width = wmPtr->width;
2120 hintsPtr->min_width = winPtr->reqWidth;
2122 hintsPtr->max_width = hintsPtr->min_width;
2124 if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) {
2125 if (wmPtr->height >= 0) {
2126 hintsPtr->min_height = wmPtr->height;
2128 hintsPtr->min_height = winPtr->reqHeight;
2130 hintsPtr->max_height = hintsPtr->min_height;
2133 XSetWMNormalHints(winPtr->display, winPtr->window, hintsPtr);
2135 XFree((char *) hintsPtr);
2139 *--------------------------------------------------------------
2143 * This procedure parses a geometry string and updates
2144 * information used to control the geometry of a top-level
2148 * A standard Tcl return value, plus an error message in
2149 * interp->result if an error occurs.
2152 * The size and/or location of winPtr may change.
2154 *--------------------------------------------------------------
2159 Tcl_Interp *interp, /* Used for error reporting. */
2160 char *string, /* String containing new geometry. Has the
2161 * standard form "=wxh+x+y". */
2162 TkWindow *winPtr) /* Pointer to top-level window whose
2163 * geometry is to be changed. */
2165 register WmInfo *wmPtr = winPtr->wmInfoPtr;
2166 int x, y, width, height, flags;
2168 register char *p = string;
2171 * The leading "=" is optional.
2179 * Parse the width and height, if they are present. Don't
2180 * actually update any of the fields of wmPtr until we've
2181 * successfully parsed the entire geometry string.
2184 width = wmPtr->width;
2185 height = wmPtr->height;
2188 flags = wmPtr->flags;
2189 if (isdigit(UCHAR(*p))) {
2190 width = strtoul(p, &end, 10);
2196 if (!isdigit(UCHAR(*p))) {
2199 height = strtoul(p, &end, 10);
2204 * Parse the X and Y coordinates, if they are present.
2208 flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
2210 flags |= WM_NEGATIVE_X;
2211 } else if (*p != '+') {
2214 x = strtol(p+1, &end, 10);
2217 flags |= WM_NEGATIVE_Y;
2218 } else if (*p != '+') {
2221 y = strtol(p+1, &end, 10);
2227 * Assume that the geometry information came from the user,
2228 * unless an explicit source has been specified. Otherwise
2229 * most window managers assume that the size hints were
2230 * program-specified and they ignore them.
2233 if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
2234 wmPtr->sizeHintsFlags |= USPosition;
2235 flags |= WM_UPDATE_SIZE_HINTS;
2240 * Everything was parsed OK. Update the fields of *wmPtr and
2241 * arrange for the appropriate information to be percolated out
2242 * to the window manager at the next idle moment.
2245 wmPtr->width = width;
2246 wmPtr->height = height;
2247 if ((x != wmPtr->x) || (y != wmPtr->y)
2248 || ((flags & (WM_NEGATIVE_X|WM_NEGATIVE_Y))
2249 != (wmPtr->flags & (WM_NEGATIVE_X|WM_NEGATIVE_Y)))) {
2252 flags |= WM_MOVE_PENDING;
2254 wmPtr->flags = flags;
2256 if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
2257 Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
2258 wmPtr->flags |= WM_UPDATE_PENDING;
2263 Tcl_AppendResult(interp, "bad geometry specifier \"",
2264 string, "\"", (char *) NULL);
2269 *----------------------------------------------------------------------
2271 * Tk_GetRootCoords --
2273 * Given a token for a window, this procedure traces through the
2274 * window's lineage to find the (virtual) root-window coordinates
2275 * corresponding to point (0,0) in the window.
2278 * The locations pointed to by xPtr and yPtr are filled in with
2279 * the root coordinates of the (0,0) point in tkwin. If a virtual
2280 * root window is in effect for the window, then the coordinates
2281 * in the virtual root are returned.
2286 *----------------------------------------------------------------------
2291 Tk_Window tkwin, /* Token for window. */
2292 int *xPtr, /* Where to store x-displacement of (0,0). */
2293 int *yPtr) /* Where to store y-displacement of (0,0). */
2296 register TkWindow *winPtr = (TkWindow *) tkwin;
2299 * Search back through this window's parents all the way to a
2300 * top-level window, combining the offsets of each window within
2306 x += winPtr->changes.x + winPtr->changes.border_width;
2307 y += winPtr->changes.y + winPtr->changes.border_width;
2308 if (winPtr->flags & TK_TOP_LEVEL) {
2309 if (!(Tk_IsEmbedded(winPtr))) {
2310 x += winPtr->wmInfoPtr->xInParent;
2311 y += winPtr->wmInfoPtr->yInParent;
2316 otherPtr = TkpGetOtherWindow(winPtr);
2317 if (otherPtr != NULL) {
2319 * The container window is in the same application.
2320 * Query its coordinates.
2325 * Remember to offset by the container window here,
2326 * since at the end of this if branch, we will
2327 * pop out to the container's parent...
2330 x += winPtr->changes.x + winPtr->changes.border_width;
2331 y += winPtr->changes.y + winPtr->changes.border_width;
2336 if (gMacEmbedHandler->getOffsetProc != NULL) {
2338 * We do not require that the changes.x & changes.y for
2339 * a non-Tk master window be kept up to date. So we
2340 * first subtract off the possibly bogus values that have
2341 * been added on at the top of this pass through the loop,
2342 * and then call out to the getOffsetProc to give us
2343 * the correct offset.
2346 x -= winPtr->changes.x + winPtr->changes.border_width;
2347 y -= winPtr->changes.y + winPtr->changes.border_width;
2349 gMacEmbedHandler->getOffsetProc((Tk_Window) winPtr, &theOffset);
2358 winPtr = winPtr->parentPtr;
2365 *----------------------------------------------------------------------
2367 * Tk_CoordsToWindow --
2369 * This is a Macintosh specific implementation of this function.
2370 * Given the root coordinates of a point, this procedure returns
2371 * the token for the top-most window covering that point, if
2372 * there exists such a window in this application.
2375 * The return result is either a token for the window corresponding
2376 * to rootX and rootY, or else NULL to indicate that there is no such
2382 *----------------------------------------------------------------------
2387 int rootX, int rootY, /* Coordinates of point in root window. If
2388 * a virtual-root window manager is in use,
2389 * these coordinates refer to the virtual
2390 * root, not the real root. */
2391 Tk_Window tkwin) /* Token for any window in application;
2392 * used to identify the display. */
2397 register TkWindow *winPtr, *childPtr;
2398 TkWindow *nextPtr; /* Coordinates of highest child found so
2399 * far that contains point. */
2400 int x, y; /* Coordinates in winPtr. */
2404 * Step 1: find the top-level window that contains the desired point.
2409 FindWindow(where, &whichWin);
2410 if (whichWin == NULL) {
2413 rootChild = TkMacGetXWindow(whichWin);
2414 winPtr = (TkWindow *) Tk_IdToWindow(tkDisplayList->display, rootChild);
2415 if (winPtr == NULL) {
2420 * Step 2: work down through the hierarchy underneath this window.
2421 * At each level, scan through all the children to find the highest
2422 * one in the stacking order that contains the point. Then repeat
2423 * the whole process on that child.
2426 x = rootX - winPtr->wmInfoPtr->xInParent;
2427 y = rootY - winPtr->wmInfoPtr->yInParent;
2429 x -= winPtr->changes.x;
2430 y -= winPtr->changes.y;
2434 * Container windows cannot have children. So if it is a container,
2435 * look there, otherwise inspect the children.
2438 if (Tk_IsContainer(winPtr)) {
2439 childPtr = TkpGetOtherWindow(winPtr);
2440 if (childPtr != NULL) {
2441 if (Tk_IsMapped(childPtr)) {
2442 tmpx = x - childPtr->changes.x;
2443 tmpy = y - childPtr->changes.y;
2444 bd = childPtr->changes.border_width;
2446 if ((tmpx >= -bd) && (tmpy >= -bd)
2447 && (tmpx < (childPtr->changes.width + bd))
2448 && (tmpy < (childPtr->changes.height + bd))) {
2456 * NOTE: Here we should handle out of process embedding.
2460 for (childPtr = winPtr->childList; childPtr != NULL;
2461 childPtr = childPtr->nextPtr) {
2462 if (!Tk_IsMapped(childPtr) ||
2463 (childPtr->flags & TK_TOP_LEVEL)) {
2466 tmpx = x - childPtr->changes.x;
2467 tmpy = y - childPtr->changes.y;
2468 bd = childPtr->changes.border_width;
2469 if ((tmpx >= -bd) && (tmpy >= -bd)
2470 && (tmpx < (childPtr->changes.width + bd))
2471 && (tmpy < (childPtr->changes.height + bd))) {
2476 if (nextPtr == NULL) {
2481 return (Tk_Window) winPtr;
2485 *----------------------------------------------------------------------
2487 * Tk_TopCoordsToWindow --
2489 * Given a Tk Window, and coordinates of a point relative to that window
2490 * this procedure returns the top-most child of the window (excluding
2491 * toplevels) covering that point, if there exists such a window in this
2493 * It also sets newX, and newY to the coords of the point relative to the
2497 * The return result is either a token for the window corresponding
2498 * to rootX and rootY, or else NULL to indicate that there is no such
2499 * window. newX and newY are also set to the coords of the point relative
2500 * to the returned window.
2505 *----------------------------------------------------------------------
2509 Tk_TopCoordsToWindow(
2510 Tk_Window tkwin, /* Token for a Tk Window which defines the;
2511 * coordinates for rootX & rootY */
2512 int rootX, int rootY, /* Coordinates of a point in tkWin. */
2513 int *newX, int *newY) /* Coordinates of point in the upperMost child of
2514 * tkWin containing (rootX,rootY) */
2516 register TkWindow *winPtr, *childPtr;
2517 TkWindow *nextPtr; /* Coordinates of highest child found so
2518 * far that contains point. */
2519 int x, y; /* Coordinates in winPtr. */
2520 Window *children; /* Children of winPtr, or NULL. */
2522 winPtr = (TkWindow *) tkwin;
2530 * Container windows cannot have children. So if it is a container,
2531 * look there, otherwise inspect the children.
2534 if (Tk_IsContainer(winPtr)) {
2535 childPtr = TkpGetOtherWindow(winPtr);
2536 if (childPtr != NULL) {
2537 if (Tk_IsMapped(childPtr) &&
2538 (x > childPtr->changes.x &&
2539 x < childPtr->changes.x +
2540 childPtr->changes.width) &&
2541 (y > childPtr->changes.y &&
2542 y < childPtr->changes.y +
2543 childPtr->changes.height)) {
2549 * NOTE: Here we should handle out of process embedding.
2554 for (childPtr = winPtr->childList; childPtr != NULL;
2555 childPtr = childPtr->nextPtr) {
2556 if (!Tk_IsMapped(childPtr) ||
2557 (childPtr->flags & TK_TOP_LEVEL)) {
2560 if (x < childPtr->changes.x || y < childPtr->changes.y) {
2563 if (x > childPtr->changes.x + childPtr->changes.width ||
2564 y > childPtr->changes.y + childPtr->changes.height) {
2570 if (nextPtr == NULL) {
2574 x -= winPtr->changes.x;
2575 y -= winPtr->changes.y;
2579 return (Tk_Window) winPtr;
2583 *----------------------------------------------------------------------
2585 * UpdateVRootGeometry --
2587 * This procedure is called to update all the virtual root
2588 * geometry information in wmPtr.
2594 * The vRootX, vRootY, vRootWidth, and vRootHeight fields in
2595 * wmPtr are filled with the most up-to-date information.
2597 *----------------------------------------------------------------------
2601 UpdateVRootGeometry(
2602 WmInfo *wmPtr) /* Window manager information to be
2603 * updated. The wmPtr->vRoot field must
2606 TkWindow *winPtr = wmPtr->winPtr;
2607 unsigned int bd, dummy;
2610 Tk_ErrorHandler handler;
2613 * If this isn't a virtual-root window manager, just return information
2617 wmPtr->flags &= ~WM_VROOT_OFFSET_STALE;
2618 if (wmPtr->vRoot == None) {
2620 wmPtr->vRootX = wmPtr->vRootY = 0;
2621 wmPtr->vRootWidth = DisplayWidth(winPtr->display, winPtr->screenNum);
2622 wmPtr->vRootHeight = DisplayHeight(winPtr->display, winPtr->screenNum);
2627 * Refresh the virtual root information if it's out of date.
2630 handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
2631 (Tk_ErrorProc *) NULL, (ClientData) NULL);
2632 status = XGetGeometry(winPtr->display, wmPtr->vRoot,
2633 &dummy2, &wmPtr->vRootX, &wmPtr->vRootY,
2634 &wmPtr->vRootWidth, &wmPtr->vRootHeight, &bd, &dummy);
2636 printf("UpdateVRootGeometry: x = %d, y = %d, width = %d, ",
2637 wmPtr->vRootX, wmPtr->vRootY, wmPtr->vRootWidth);
2638 printf("height = %d, status = %d\n", wmPtr->vRootHeight, status);
2640 Tk_DeleteErrorHandler(handler);
2643 * The virtual root is gone! Pretend that it never existed.
2646 wmPtr->vRoot = None;
2652 *----------------------------------------------------------------------
2654 * Tk_GetVRootGeometry --
2656 * This procedure returns information about the virtual root
2657 * window corresponding to a particular Tk window.
2660 * The values at xPtr, yPtr, widthPtr, and heightPtr are set
2661 * with the offset and dimensions of the root window corresponding
2662 * to tkwin. If tkwin is being managed by a virtual root window
2663 * manager these values correspond to the virtual root window being
2664 * used for tkwin; otherwise the offsets will be 0 and the
2665 * dimensions will be those of the screen.
2668 * Vroot window information is refreshed if it is out of date.
2670 *----------------------------------------------------------------------
2674 Tk_GetVRootGeometry(
2675 Tk_Window tkwin, /* Window whose virtual root is to be
2677 int *xPtr, int *yPtr, /* Store x and y offsets of virtual root
2679 int *widthPtr, /* Store dimensions of virtual root here. */
2683 TkWindow *winPtr = (TkWindow *) tkwin;
2686 * Find the top-level window for tkwin, and locate the window manager
2687 * information for that window.
2690 while (!(winPtr->flags & TK_TOP_LEVEL)) {
2691 winPtr = winPtr->parentPtr;
2693 wmPtr = winPtr->wmInfoPtr;
2696 * Make sure that the geometry information is up-to-date, then copy
2697 * it out to the caller.
2700 if (wmPtr->flags & WM_VROOT_OFFSET_STALE) {
2701 UpdateVRootGeometry(wmPtr);
2703 *xPtr = wmPtr->vRootX;
2704 *yPtr = wmPtr->vRootY;
2705 *widthPtr = wmPtr->vRootWidth;
2706 *heightPtr = wmPtr->vRootHeight;
2710 *----------------------------------------------------------------------
2712 * Tk_MoveToplevelWindow --
2714 * This procedure is called instead of Tk_MoveWindow to adjust
2715 * the x-y location of a top-level window. It delays the actual
2716 * move to a later time and keeps window-manager information
2717 * up-to-date with the move
2723 * The window is eventually moved so that its upper-left corner
2724 * (actually, the upper-left corner of the window's decorative
2725 * frame, if there is one) is at (x,y).
2727 *----------------------------------------------------------------------
2731 Tk_MoveToplevelWindow(
2732 Tk_Window tkwin, /* Window to move. */
2733 int x, int y) /* New location for window (within
2736 TkWindow *winPtr = (TkWindow *) tkwin;
2737 register WmInfo *wmPtr = winPtr->wmInfoPtr;
2739 if (!(winPtr->flags & TK_TOP_LEVEL)) {
2740 panic("Tk_MoveToplevelWindow called with non-toplevel window");
2744 wmPtr->flags |= WM_MOVE_PENDING;
2745 wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y);
2746 if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
2747 wmPtr->sizeHintsFlags |= USPosition;
2748 wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
2752 * If the window has already been mapped, must bring its geometry
2753 * up-to-date immediately, otherwise an event might arrive from the
2754 * server that would overwrite wmPtr->x and wmPtr->y and lose the
2758 if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
2759 if (wmPtr->flags & WM_UPDATE_PENDING) {
2760 Tk_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
2762 UpdateGeometryInfo((ClientData) winPtr);
2767 *----------------------------------------------------------------------
2769 * TkWmProtocolEventProc --
2771 * This procedure is called by the Tk_HandleEvent whenever a
2772 * ClientMessage event arrives whose type is "WM_PROTOCOLS".
2773 * This procedure handles the message from the window manager
2774 * in an appropriate fashion.
2780 * Depends on what sort of handler, if any, was set up for the
2783 *----------------------------------------------------------------------
2787 TkWmProtocolEventProc(
2788 TkWindow *winPtr, /* Window to which the event was sent. */
2789 XEvent *eventPtr) /* X event. */
2792 register ProtocolHandler *protPtr;
2797 wmPtr = winPtr->wmInfoPtr;
2798 if (wmPtr == NULL) {
2801 protocol = (Atom) eventPtr->xclient.data.l[0];
2802 for (protPtr = wmPtr->protPtr; protPtr != NULL;
2803 protPtr = protPtr->nextPtr) {
2804 if (protocol == protPtr->protocol) {
2805 Tcl_Preserve((ClientData) protPtr);
2806 interp = protPtr->interp;
2807 Tcl_Preserve((ClientData) interp);
2808 result = Tcl_GlobalEval(interp, protPtr->command);
2809 if (result != TCL_OK) {
2810 Tcl_AddErrorInfo(interp, "\n (command for \"");
2811 Tcl_AddErrorInfo(interp,
2812 Tk_GetAtomName((Tk_Window) winPtr, protocol));
2813 Tcl_AddErrorInfo(interp, "\" window manager protocol)");
2814 Tk_BackgroundError(interp);
2816 Tcl_Release((ClientData) interp);
2817 Tcl_Release((ClientData) protPtr);
2823 * No handler was present for this protocol. If this is a
2824 * WM_DELETE_WINDOW message then just destroy the window.
2827 if (protocol == Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW")) {
2828 Tk_DestroyWindow((Tk_Window) winPtr);
2833 *----------------------------------------------------------------------
2835 * TkWmRestackToplevel --
2837 * This procedure restacks a top-level window.
2843 * WinPtr gets restacked as specified by aboveBelow and otherPtr.
2844 * This procedure doesn't return until the restack has taken
2845 * effect and the ConfigureNotify event for it has been received.
2847 *----------------------------------------------------------------------
2851 TkWmRestackToplevel(
2852 TkWindow *winPtr, /* Window to restack. */
2853 int aboveBelow, /* Gives relative position for restacking;
2854 * must be Above or Below. */
2855 TkWindow *otherPtr) /* Window relative to which to restack;
2856 * if NULL, then winPtr gets restacked
2857 * above or below *all* siblings. */
2860 WindowPeek macWindow, otherMacWindow, frontWindow;
2862 wmPtr = winPtr->wmInfoPtr;
2865 * Get the mac window. Make sure it exists & is mapped.
2868 if (winPtr->window == None) {
2869 Tk_MakeWindowExist((Tk_Window) winPtr);
2871 if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
2874 * Can't set stacking order properly until the window is on the
2875 * screen (mapping it may give it a reparent window), so make sure
2876 * it's on the screen.
2879 TkWmMapWindow(winPtr);
2881 macWindow = (WindowPeek) TkMacGetDrawablePort(winPtr->window);
2884 * Get the window in which a raise or lower is in relation to.
2886 if (otherPtr != NULL) {
2887 if (otherPtr->window == None) {
2888 Tk_MakeWindowExist((Tk_Window) otherPtr);
2890 if (otherPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
2891 TkWmMapWindow(otherPtr);
2893 otherMacWindow = (WindowPeek) TkMacGetDrawablePort(otherPtr->window);
2895 otherMacWindow = NULL;
2898 frontWindow = (WindowPeek) FrontWindow();
2899 if (aboveBelow == Above) {
2900 if (macWindow == frontWindow) {
2902 * Do nothing - it's already at the top.
2904 } else if (otherMacWindow == frontWindow || otherMacWindow == NULL) {
2906 * Raise the window to the top. If the window is visable then
2907 * we also make it the active window.
2910 if (wmPtr->hints.initial_state == WithdrawnState) {
2911 BringToFront((WindowPtr) macWindow);
2913 SelectWindow((WindowPtr) macWindow);
2917 * Find the window to be above. (Front window will actually be the
2918 * window to be behind.) Front window is NULL if no other windows.
2920 while (frontWindow != NULL &&
2921 frontWindow->nextWindow != otherMacWindow) {
2922 frontWindow = frontWindow->nextWindow;
2924 if (frontWindow != NULL) {
2925 SendBehind((WindowPtr) macWindow, (WindowPtr) frontWindow);
2930 * Send behind. If it was in front find another window to make active.
2932 if (macWindow == frontWindow) {
2933 if (macWindow->nextWindow != NULL) {
2934 SelectWindow((WindowPtr) macWindow->nextWindow);
2937 SendBehind((WindowPtr) macWindow, (WindowPtr) otherMacWindow);
2942 *----------------------------------------------------------------------
2944 * TkWmAddToColormapWindows --
2946 * This procedure is called to add a given window to the
2947 * WM_COLORMAP_WINDOWS property for its top-level, if it
2948 * isn't already there. It is invoked by the Tk code that
2949 * creates a new colormap, in order to make sure that colormap
2950 * information is propagated to the window manager by default.
2956 * WinPtr's window gets added to the WM_COLORMAP_WINDOWS
2957 * property of its nearest top-level ancestor, unless the
2958 * colormaps have been set explicitly with the
2959 * "wm colormapwindows" command.
2961 *----------------------------------------------------------------------
2965 TkWmAddToColormapWindows(
2966 TkWindow *winPtr) /* Window with a non-default colormap.
2967 * Should not be a top-level window. */
2970 TkWindow **oldPtr, **newPtr;
2973 if (winPtr->window == None) {
2977 for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
2978 if (topPtr == NULL) {
2980 * Window is being deleted. Skip the whole operation.
2985 if (topPtr->flags & TK_TOP_LEVEL) {
2989 if (topPtr->wmInfoPtr->flags & WM_COLORMAPS_EXPLICIT) {
2994 * Make sure that the window isn't already in the list.
2997 count = topPtr->wmInfoPtr->cmapCount;
2998 oldPtr = topPtr->wmInfoPtr->cmapList;
3000 for (i = 0; i < count; i++) {
3001 if (oldPtr[i] == winPtr) {
3007 * Make a new bigger array and use it to reset the property.
3008 * Automatically add the toplevel itself as the last element
3012 newPtr = (TkWindow **) ckalloc((unsigned) ((count+2)*sizeof(TkWindow*)));
3014 memcpy(newPtr, oldPtr, count * sizeof(TkWindow*));
3019 newPtr[count-1] = winPtr;
3020 newPtr[count] = topPtr;
3021 if (oldPtr != NULL) {
3022 ckfree((char *) oldPtr);
3025 topPtr->wmInfoPtr->cmapList = newPtr;
3026 topPtr->wmInfoPtr->cmapCount = count+1;
3029 * On the Macintosh all of this is just an excercise
3030 * in compatability as we don't support colormaps. If
3031 * we did they would be installed here.
3036 *----------------------------------------------------------------------
3038 * TkWmRemoveFromColormapWindows --
3040 * This procedure is called to remove a given window from the
3041 * WM_COLORMAP_WINDOWS property for its top-level. It is invoked
3042 * when windows are deleted.
3048 * WinPtr's window gets removed from the WM_COLORMAP_WINDOWS
3049 * property of its nearest top-level ancestor, unless the
3050 * top-level itself is being deleted too.
3052 *----------------------------------------------------------------------
3056 TkWmRemoveFromColormapWindows(
3057 TkWindow *winPtr) /* Window that may be present in
3058 * WM_COLORMAP_WINDOWS property for its
3059 * top-level. Should not be a top-level
3066 for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
3067 if (topPtr == NULL) {
3069 * Ancestors have been deleted, so skip the whole operation.
3070 * Seems like this can't ever happen?
3075 if (topPtr->flags & TK_TOP_LEVEL) {
3079 if (topPtr->flags & TK_ALREADY_DEAD) {
3081 * Top-level is being deleted, so there's no need to cleanup
3082 * the WM_COLORMAP_WINDOWS property.
3089 * Find the window and slide the following ones down to cover
3093 count = topPtr->wmInfoPtr->cmapCount;
3094 oldPtr = topPtr->wmInfoPtr->cmapList;
3095 for (i = 0; i < count; i++) {
3096 if (oldPtr[i] == winPtr) {
3097 for (j = i ; j < count-1; j++) {
3098 oldPtr[j] = oldPtr[j+1];
3100 topPtr->wmInfoPtr->cmapCount = count - 1;
3107 *----------------------------------------------------------------------
3109 * TkGetPointerCoords --
3111 * Fetch the position of the mouse pointer.
3114 * *xPtr and *yPtr are filled in with the (virtual) root coordinates
3115 * of the mouse pointer for tkwin's display. If the pointer isn't
3116 * on tkwin's screen, then -1 values are returned for both
3117 * coordinates. The argument tkwin must be a toplevel window.
3122 *----------------------------------------------------------------------
3127 Tk_Window tkwin, /* Toplevel window that identifies screen
3128 * on which lookup is to be done. */
3129 int *xPtr, int *yPtr) /* Store pointer coordinates here. */
3134 LocalToGlobal(&where);
3140 *----------------------------------------------------------------------
3142 * InitialWindowBounds --
3144 * This function calculates the initial bounds for a new Mac
3145 * toplevel window. Unless the geometry is specified by the user
3146 * this code will auto place the windows in a cascade diagonially
3147 * across the main monitor of the Mac.
3150 * The bounds are returned in geometry.
3155 *----------------------------------------------------------------------
3159 InitialWindowBounds(
3160 TkWindow *winPtr, /* Window to get initial bounds for. */
3161 Rect *geometry) /* On return the initial bounds. */
3164 static int defaultX = 5;
3165 static int defaultY = 45;
3167 if (!(winPtr->wmInfoPtr->sizeHintsFlags & (USPosition | PPosition))) {
3169 * We will override the program & hopefully place the
3170 * window in a "better" location.
3173 if (((tcl_macQdPtr->screenBits.bounds.right - defaultX) < 30) ||
3174 ((tcl_macQdPtr->screenBits.bounds.bottom - defaultY) < 30)) {
3183 x = winPtr->wmInfoPtr->x;
3184 y = winPtr->wmInfoPtr->y;
3189 geometry->right = x + winPtr->changes.width;
3190 geometry->bottom = y + winPtr->changes.height;
3194 *----------------------------------------------------------------------
3198 * This function determines if the passed in window is part of
3199 * a toplevel window that is resizable. If the window is
3200 * resizable in the x, y or both directions, true is returned.
3203 * True if resizable, false otherwise.
3208 *----------------------------------------------------------------------
3213 TkWindow *winPtr) /* Tk window or NULL. */
3217 if (winPtr == NULL) {
3220 while (winPtr->wmInfoPtr == NULL) {
3221 winPtr = winPtr->parentPtr;
3224 wmPtr = winPtr->wmInfoPtr;
3225 if ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) &&
3226 (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE)) {
3234 *----------------------------------------------------------------------
3236 * TkMacGrowToplevel --
3238 * The function is invoked when the user clicks in the grow region
3239 * of a Tk window. The function will handle the dragging
3240 * procedure and not return until completed. Finally, the function
3241 * may place information Tk's event queue is the window was resized.
3244 * True if events were placed on event queue, false otherwise.
3249 *----------------------------------------------------------------------
3254 WindowPtr whichWindow,
3257 Point where = start;
3259 GlobalToLocal(&where);
3260 if (where.h > (whichWindow->portRect.right - 16) &&
3261 where.v > (whichWindow->portRect.bottom - 16)) {
3269 window = TkMacGetXWindow(whichWindow);
3270 winPtr = (TkWindow *) Tk_IdToWindow(tkDisplayList->display, window);
3271 wmPtr = winPtr->wmInfoPtr;
3273 /* TODO: handle grid size options. */
3274 if ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) &&
3275 (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE)) {
3278 if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) {
3279 bounds.left = bounds.right = winPtr->changes.width;
3281 bounds.left = (wmPtr->minWidth < 64) ? 64 : wmPtr->minWidth;
3282 bounds.right = (wmPtr->maxWidth < 64) ? 64 : wmPtr->maxWidth;
3284 if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) {
3285 bounds.top = bounds.bottom = winPtr->changes.height;
3287 bounds.top = (wmPtr->minHeight < 64) ? 64 : wmPtr->minHeight;
3288 bounds.bottom = (wmPtr->maxHeight < 64) ? 64 : wmPtr->maxHeight;
3291 growResult = GrowWindow(whichWindow, start, &bounds);
3293 if (growResult != 0) {
3294 SizeWindow(whichWindow,
3295 LoWord(growResult), HiWord(growResult), true);
3296 SetPort(whichWindow);
3297 InvalRect(&whichWindow->portRect); /* TODO: may not be needed */
3298 TkMacInvalClipRgns(winPtr);
3299 TkGenWMConfigureEvent((Tk_Window) winPtr, -1, -1,
3300 (int) LoWord(growResult), (int) HiWord(growResult),
3310 *----------------------------------------------------------------------
3314 * Set the title for a toplevel window. If the window is embedded,
3315 * do not change the window title.
3321 * The title of the window is changed.
3323 *----------------------------------------------------------------------
3334 if (Tk_IsEmbedded(winPtr)) {
3338 macWin = TkMacGetDrawablePort(winPtr->window);
3340 strcpy((char *) pTitle + 1, titleUid);
3341 pTitle[0] = strlen(titleUid);
3342 SetWTitle((WindowPtr) macWin, pTitle);
3346 TkGenWMDestroyEvent(
3351 event.xany.serial = Tk_Display(tkwin)->request;
3352 event.xany.send_event = False;
3353 event.xany.display = Tk_Display(tkwin);
3355 event.xclient.window = Tk_WindowId(tkwin);
3356 event.xclient.type = ClientMessage;
3357 event.xclient.message_type = Tk_InternAtom(tkwin, "WM_PROTOCOLS");
3358 event.xclient.format = 32;
3359 event.xclient.data.l[0] = Tk_InternAtom(tkwin, "WM_DELETE_WINDOW");
3360 Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
3364 *----------------------------------------------------------------------
3366 * TkGenWMConfigureEvent --
3368 * Generate a ConfigureNotify event for Tk. Depending on the
3369 * value of flag the values of width/height, x/y, or both may
3376 * A ConfigureNotify event is sent to Tk.
3378 *----------------------------------------------------------------------
3382 TkGenWMConfigureEvent(
3392 TkWindow *winPtr = (TkWindow *) tkwin;
3394 if (tkwin == NULL) {
3398 event.type = ConfigureNotify;
3399 event.xconfigure.serial = Tk_Display(tkwin)->request;
3400 event.xconfigure.send_event = False;
3401 event.xconfigure.display = Tk_Display(tkwin);
3402 event.xconfigure.event = Tk_WindowId(tkwin);
3403 event.xconfigure.window = Tk_WindowId(tkwin);
3404 event.xconfigure.border_width = winPtr->changes.border_width;
3405 event.xconfigure.override_redirect = winPtr->atts.override_redirect;
3406 if (winPtr->changes.stack_mode == Above) {
3407 event.xconfigure.above = winPtr->changes.sibling;
3409 event.xconfigure.above = None;
3412 if (flags & TK_LOCATION_CHANGED) {
3413 event.xconfigure.x = x;
3414 event.xconfigure.y = y;
3416 event.xconfigure.x = Tk_X(tkwin);
3417 event.xconfigure.y = Tk_Y(tkwin);
3421 if (flags & TK_SIZE_CHANGED) {
3422 event.xconfigure.width = width;
3423 event.xconfigure.height = height;
3425 event.xconfigure.width = Tk_Width(tkwin);
3426 event.xconfigure.height = Tk_Height(tkwin);
3427 width = Tk_Width(tkwin);
3428 height = Tk_Height(tkwin);
3431 Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
3434 * Update window manager information.
3436 if (Tk_IsTopLevel(winPtr)) {
3437 wmPtr = winPtr->wmInfoPtr;
3438 if (flags & TK_LOCATION_CHANGED) {
3441 wmPtr->flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
3443 if ((flags & TK_SIZE_CHANGED) &&
3444 ((width != Tk_Width(tkwin)) || (height != Tk_Height(tkwin)))) {
3445 if ((wmPtr->width == -1) && (width == winPtr->reqWidth)) {
3447 * Don't set external width, since the user didn't change it
3448 * from what the widgets asked for.
3451 if (wmPtr->gridWin != NULL) {
3452 wmPtr->width = wmPtr->reqGridWidth
3453 + (width - winPtr->reqWidth)/wmPtr->widthInc;
3454 if (wmPtr->width < 0) {
3458 wmPtr->width = width;
3461 if ((wmPtr->height == -1) && (height == winPtr->reqHeight)) {
3463 * Don't set external height, since the user didn't change it
3464 * from what the widgets asked for.
3467 if (wmPtr->gridWin != NULL) {
3468 wmPtr->height = wmPtr->reqGridHeight
3469 + (height - winPtr->reqHeight)/wmPtr->heightInc;
3470 if (wmPtr->height < 0) {
3474 wmPtr->height = height;
3477 wmPtr->configWidth = width;
3478 wmPtr->configHeight = height;
3483 * Now set up the changes structure. Under X we wait for the
3484 * ConfigureNotify to set these values. On the Mac we know imediatly that
3485 * this is what we want - so we just set them. However, we need to
3486 * make sure the windows clipping region is marked invalid so the
3487 * change is visable to the subwindow.
3489 winPtr->changes.x = x;
3490 winPtr->changes.y = y;
3491 winPtr->changes.width = width;
3492 winPtr->changes.height = height;
3493 TkMacInvalClipRgns(winPtr);
3497 *----------------------------------------------------------------------
3499 * TkGetTransientMaster --
3501 * If the passed window has the TRANSIENT_FOR property set this
3502 * will return the master window. Otherwise it will return None.
3505 * The master window or None.
3510 *----------------------------------------------------------------------
3514 TkGetTransientMaster(
3517 if (winPtr->wmInfoPtr != NULL) {
3518 return winPtr->wmInfoPtr->master;
3524 *----------------------------------------------------------------------
3526 * TkMacGetXWindow --
3528 * Returns the X window Id associated with the given WindowRef.
3531 * The window id is returned. None is returned if not a Tk window.
3536 *----------------------------------------------------------------------
3541 WindowRef macWinPtr)
3543 register Tcl_HashEntry *hPtr;
3545 if ((macWinPtr == NULL) || !windowHashInit) {
3548 hPtr = Tcl_FindHashEntry(&windowTable, (char *) macWinPtr);
3552 return (Window) Tcl_GetHashValue(hPtr);
3556 *----------------------------------------------------------------------
3558 * TkMacZoomToplevel --
3560 * The function is invoked when the user clicks in the zoom region
3561 * of a Tk window. The function will handle the mouse tracking
3562 * for the interaction. If the window is to be zoomed the window
3563 * size is changed and events are generated to let Tk know what
3567 * True if events were placed on event queue, false otherwise.
3570 * The window may be resized & events placed on Tk's queue.
3572 *----------------------------------------------------------------------
3577 WindowPtr whichWindow, /* The Macintosh window to zoom. */
3578 Point where, /* The current mouse position. */
3579 short zoomPart) /* Either inZoomIn or inZoomOut */
3583 Point location = {0, 0};
3584 int xOffset, yOffset;
3587 SetPort(whichWindow);
3588 if (!TrackBox(whichWindow, where, zoomPart)) {
3593 * We should now zoom the window (as long as it's one of ours). We
3594 * also need to generate an event to let Tk know that the window size
3597 window = TkMacGetXWindow(whichWindow);
3598 tkwin = Tk_IdToWindow(tkDisplayList->display, window);
3599 if (tkwin == NULL) {
3604 * The following block of code works around a bug in the window
3605 * definition for Apple's floating windows. The zoom behavior is
3606 * broken - we must manually set the standard state (by default
3607 * it's something like 1x1) and we must swap the zoomPart manually
3608 * otherwise we always get the same zoomPart and nothing happens.
3610 wmPtr = ((TkWindow *) tkwin)->wmInfoPtr;
3611 if (wmPtr->style >= floatProc && wmPtr->style <= floatSideZoomGrowProc) {
3612 if (zoomPart == inZoomIn) {
3613 Rect zoomRect = tcl_macQdPtr->screenBits.bounds;
3614 InsetRect(&zoomRect, 60, 60);
3615 SetWindowStandardState(whichWindow, &zoomRect);
3616 zoomPart = inZoomOut;
3618 zoomPart = inZoomIn;
3622 ZoomWindow(whichWindow, zoomPart, false);
3623 InvalRect(&whichWindow->portRect);
3624 TkMacInvalClipRgns((TkWindow *) tkwin);
3626 LocalToGlobal(&location);
3627 TkMacWindowOffset(whichWindow, &xOffset, &yOffset);
3628 location.h -= xOffset;
3629 location.v -= yOffset;
3630 TkGenWMConfigureEvent(tkwin, location.h, location.v,
3631 whichWindow->portRect.right - whichWindow->portRect.left,
3632 whichWindow->portRect.bottom - whichWindow->portRect.top,
3638 *----------------------------------------------------------------------
3640 * TkUnsupported1Cmd --
3642 * This procedure is invoked to process the "unsupported1" Tcl
3643 * command. This command allows you to set the style of decoration
3644 * for a Macintosh window.
3647 * A standard Tcl result.
3650 * Changes the style of a new Mac window.
3652 *----------------------------------------------------------------------
3658 ClientData clientData, /* Main window associated with
3660 Tcl_Interp *interp, /* Current interpreter. */
3661 int argc, /* Number of arguments. */
3662 char **argv) /* Argument strings. */
3664 Tk_Window tkwin = (Tk_Window) clientData;
3666 register WmInfo *wmPtr;
3672 Tcl_AppendResult(interp, "wrong # args: should be \"",
3673 argv[0], " option window ?arg ...?\"", (char *) NULL);
3677 winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
3678 if (winPtr == NULL) {
3681 if (!(winPtr->flags & TK_TOP_LEVEL)) {
3682 Tcl_AppendResult(interp, "window \"", winPtr->pathName,
3683 "\" isn't a top-level window", (char *) NULL);
3686 wmPtr = winPtr->wmInfoPtr;
3688 length = strlen(argv[1]);
3689 if ((c == 's') && (strncmp(argv[1], "style", length) == 0)) {
3690 if ((argc != 3) && (argc != 4)) {
3691 Tcl_AppendResult(interp, "wrong # arguments: must be \"",
3692 argv[0], " style window ?windowStyle?\"",
3697 switch (wmPtr->style) {
3700 interp->result = "documentProc";
3703 interp->result = "dBoxProc";
3706 interp->result = "plainDBox";
3709 interp->result = "altDBoxProc";
3711 case movableDBoxProc:
3712 interp->result = "movableDBoxProc";
3716 interp->result = "zoomDocProc";
3719 interp->result = "rDocProc";
3723 interp->result = "floatProc";
3726 case floatZoomGrowProc:
3727 interp->result = "floatZoomProc";
3730 case floatSideGrowProc:
3731 interp->result = "floatSideProc";
3733 case floatSideZoomProc:
3734 case floatSideZoomGrowProc:
3735 interp->result = "floatSideZoomProc";
3738 panic("invalid style");
3742 if (strcmp(argv[3], "documentProc") == 0) {
3743 wmPtr->style = documentProc;
3744 } else if (strcmp(argv[3], "noGrowDocProc") == 0) {
3745 wmPtr->style = documentProc;
3746 } else if (strcmp(argv[3], "dBoxProc") == 0) {
3747 wmPtr->style = dBoxProc;
3748 } else if (strcmp(argv[3], "plainDBox") == 0) {
3749 wmPtr->style = plainDBox;
3750 } else if (strcmp(argv[3], "altDBoxProc") == 0) {
3751 wmPtr->style = altDBoxProc;
3752 } else if (strcmp(argv[3], "movableDBoxProc") == 0) {
3753 wmPtr->style = movableDBoxProc;
3754 } else if (strcmp(argv[3], "zoomDocProc") == 0) {
3755 wmPtr->style = zoomDocProc;
3756 } else if (strcmp(argv[3], "zoomNoGrow") == 0) {
3757 wmPtr->style = zoomNoGrow;
3758 } else if (strcmp(argv[3], "rDocProc") == 0) {
3759 wmPtr->style = rDocProc;
3760 } else if (strcmp(argv[3], "floatProc") == 0) {
3761 wmPtr->style = floatGrowProc;
3762 } else if (strcmp(argv[3], "floatGrowProc") == 0) {
3763 wmPtr->style = floatGrowProc;
3764 } else if (strcmp(argv[3], "floatZoomProc") == 0) {
3765 wmPtr->style = floatZoomGrowProc;
3766 } else if (strcmp(argv[3], "floatZoomGrowProc") == 0) {
3767 wmPtr->style = floatZoomGrowProc;
3768 } else if (strcmp(argv[3], "floatSideProc") == 0) {
3769 wmPtr->style = floatSideGrowProc;
3770 } else if (strcmp(argv[3], "floatSideGrowProc") == 0) {
3771 wmPtr->style = floatSideGrowProc;
3772 } else if (strcmp(argv[3], "floatSideZoomProc") == 0) {
3773 wmPtr->style = floatSideZoomGrowProc;
3774 } else if (strcmp(argv[3], "floatSideZoomGrowProc") == 0) {
3775 wmPtr->style = floatSideZoomGrowProc;
3777 Tcl_AppendResult(interp, "bad style: should be documentProc, ",
3778 "dBoxProc, plainDBox, altDBoxProc, movableDBoxProc, ",
3779 "zoomDocProc, rDocProc, floatProc, floatZoomProc, ",
3780 "floatSideProc, or floatSideZoomProc",
3785 Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],
3786 "\": must be style",
3795 *----------------------------------------------------------------------
3797 * TkpMakeMenuWindow --
3799 * Configure the window to be either a undecorated pull-down
3800 * (or pop-up) menu, or as a toplevel floating menu (palette).
3806 * Changes the style bit used to create a new Mac toplevel.
3808 *----------------------------------------------------------------------
3813 Tk_Window tkwin, /* New window. */
3814 int transient) /* 1 means menu is only posted briefly as
3815 * a popup or pulldown or cascade. 0 means
3816 * menu is always visible, e.g. as a
3820 ((TkWindow *) tkwin)->wmInfoPtr->style = plainDBox;
3822 ((TkWindow *) tkwin)->wmInfoPtr->style = floatProc;
3823 ((TkWindow *) tkwin)->wmInfoPtr->flags |= WM_WIDTH_NOT_RESIZABLE;
3824 ((TkWindow *) tkwin)->wmInfoPtr->flags |= WM_HEIGHT_NOT_RESIZABLE;
3829 *----------------------------------------------------------------------
3831 * TkMacMakeRealWindowExist --
3833 * This function finally creates the real Macintosh window that
3834 * the Mac actually understands.
3840 * A new Macintosh toplevel is created.
3842 *----------------------------------------------------------------------
3846 TkMacMakeRealWindowExist(
3847 TkWindow *winPtr) /* Tk window. */
3849 WmInfo *wmPtr = winPtr->wmInfoPtr;
3850 WindowRef newWindow = NULL;
3851 MacDrawable *macWin;
3853 Tcl_HashEntry *valueHashPtr;
3855 TkMacWindowList *listPtr;
3857 if (TkMacHostToplevelExists(winPtr)) {
3861 macWin = (MacDrawable *) winPtr->window;
3864 * If this is embedded, make sure its container's toplevel exists,
3868 if (Tk_IsEmbedded(winPtr)) {
3869 TkWindow *contWinPtr;
3871 contWinPtr = TkpGetOtherWindow(winPtr);
3872 if (contWinPtr != NULL) {
3873 TkMacMakeRealWindowExist(contWinPtr->privatePtr->toplevel->winPtr);
3874 macWin->flags |= TK_HOST_EXISTS;
3876 } else if (gMacEmbedHandler != NULL) {
3877 if (gMacEmbedHandler->containerExistProc != NULL) {
3878 if (gMacEmbedHandler->containerExistProc((Tk_Window) winPtr) != TCL_OK) {
3879 panic("ContainerExistProc could not make container");
3884 panic("TkMacMakeRealWindowExist could not find container");
3888 * NOTE: Here we should handle out of process embedding.
3893 InitialWindowBounds(winPtr, &geometry);
3895 newWindow = NewCWindow(NULL, &geometry, "\ptemp", false,
3896 (short) wmPtr->style, (WindowRef) -1, true, 0);
3897 if (newWindow == NULL) {
3898 panic("couldn't allocate new Mac window");
3902 * Add this window to the list of toplevel windows.
3905 listPtr = (TkMacWindowList *) ckalloc(sizeof(TkMacWindowList));
3906 listPtr->nextPtr = tkMacWindowListPtr;
3907 listPtr->winPtr = winPtr;
3908 tkMacWindowListPtr = listPtr;
3910 macWin->portPtr = (GWorldPtr) newWindow;
3911 tkMacMoveWindow(newWindow, (int) geometry.left, (int) geometry.top);
3912 SetPort((GrafPtr) newWindow);
3914 if (!windowHashInit) {
3915 Tcl_InitHashTable(&windowTable, TCL_ONE_WORD_KEYS);
3916 windowHashInit = true;
3918 valueHashPtr = Tcl_CreateHashEntry(&windowTable,
3919 (char *) newWindow, &new);
3921 panic("same macintosh window allocated twice!");
3923 Tcl_SetHashValue(valueHashPtr, macWin);
3925 macWin->flags |= TK_HOST_EXISTS;
3929 *----------------------------------------------------------------------
3931 * TkMacRegisterOffScreenWindow --
3933 * This function adds the passed in Off Screen Port to the
3934 * hash table that maps Mac windows to root X windows.
3940 * An entry is added to the windowTable hash table.
3942 *----------------------------------------------------------------------
3946 TkMacRegisterOffScreenWindow(
3947 Window window, /* Window structure. */
3948 GWorldPtr portPtr) /* Pointer to a Mac GWorld. */
3950 WindowRef newWindow = NULL;
3951 MacDrawable *macWin;
3952 Tcl_HashEntry *valueHashPtr;
3955 macWin = (MacDrawable *) window;
3956 if (!windowHashInit) {
3957 Tcl_InitHashTable(&windowTable, TCL_ONE_WORD_KEYS);
3958 windowHashInit = true;
3960 valueHashPtr = Tcl_CreateHashEntry(&windowTable,
3961 (char *) portPtr, &new);
3963 panic("same macintosh window allocated twice!");
3965 Tcl_SetHashValue(valueHashPtr, macWin);
3969 *----------------------------------------------------------------------
3971 * TkMacUnregisterMacWindow --
3973 * Given a macintosh port window, this function removes the
3974 * association between this window and the root X window that
3981 * An entry is removed from the windowTable hash table.
3983 *----------------------------------------------------------------------
3987 TkMacUnregisterMacWindow(
3988 GWorldPtr portPtr) /* Pointer to a Mac GWorld. */
3990 if (!windowHashInit) {
3991 panic("TkMacUnregisterMacWindow: unmapping before inited");;
3993 Tcl_DeleteHashEntry(Tcl_FindHashEntry(&windowTable,
3998 *----------------------------------------------------------------------
4000 * TkMacSetScrollbarGrow --
4002 * Sets a flag for a toplevel window indicating that the passed
4003 * Tk scrollbar window will display the grow region for the
4010 * A flag is set int windows toplevel parent.
4012 *----------------------------------------------------------------------
4016 TkMacSetScrollbarGrow(
4017 TkWindow *winPtr, /* Tk scrollbar window. */
4018 int flag) /* Boolean value true or false. */
4021 winPtr->privatePtr->toplevel->flags |= TK_SCROLLBAR_GROW;
4022 winPtr->privatePtr->toplevel->winPtr->wmInfoPtr->scrollWinPtr = winPtr;
4023 } else if (winPtr->privatePtr->toplevel->winPtr->wmInfoPtr->scrollWinPtr
4025 winPtr->privatePtr->toplevel->flags &= ~TK_SCROLLBAR_GROW;
4026 winPtr->privatePtr->toplevel->winPtr->wmInfoPtr->scrollWinPtr = NULL;
4031 *----------------------------------------------------------------------
4033 * TkMacGetScrollbarGrowWindow --
4035 * Tests to see if a given window's toplevel window contains a
4036 * scrollbar that will draw the GrowIcon for the window.
4044 *----------------------------------------------------------------------
4048 TkMacGetScrollbarGrowWindow(
4049 TkWindow *winPtr) /* Tk window. */
4051 TkWindow *scrollWinPtr;
4053 if (winPtr == NULL) {
4057 winPtr->privatePtr->toplevel->winPtr->wmInfoPtr->scrollWinPtr;
4058 if (winPtr != NULL) {
4060 * We need to confirm the window exists.
4062 if ((Tk_Window) scrollWinPtr !=
4063 Tk_IdToWindow(winPtr->display, winPtr->window)) {
4064 scrollWinPtr = NULL;
4067 return scrollWinPtr;
4071 *----------------------------------------------------------------------
4073 * TkWmFocusToplevel --
4075 * This is a utility procedure invoked by focus-management code. It
4076 * exists because of the extra wrapper windows that exist under
4077 * Unix; its job is to map from wrapper windows to the
4078 * corresponding toplevel windows. On PCs and Macs there are no
4079 * wrapper windows so no mapping is necessary; this procedure just
4080 * determines whether a window is a toplevel or not.
4083 * If winPtr is a toplevel window, returns the pointer to the
4084 * window; otherwise returns NULL.
4089 *----------------------------------------------------------------------
4094 TkWindow *winPtr) /* Window that received a focus-related
4097 if (!(winPtr->flags & TK_TOP_LEVEL)) {
4104 *----------------------------------------------------------------------
4106 * TkpGetWrapperWindow --
4108 * This is a utility procedure invoked by focus-management code. It
4109 * maps to the wrapper for a top-level, which is just the same
4110 * as the top-level on Macs and PCs.
4113 * If winPtr is a toplevel window, returns the pointer to the
4114 * window; otherwise returns NULL.
4119 *----------------------------------------------------------------------
4123 TkpGetWrapperWindow(
4124 TkWindow *winPtr) /* Window that received a focus-related
4127 if (!(winPtr->flags & TK_TOP_LEVEL)) {
4134 *----------------------------------------------------------------------
4138 * Sets the window manager state for the wrapper window of a
4139 * given toplevel window.
4145 * May maximize, minimize, restore, or withdraw a window.
4147 *----------------------------------------------------------------------
4151 TkpWmSetState(winPtr, state)
4152 TkWindow *winPtr; /* Toplevel window to operate on. */
4153 int state; /* One of IconicState, ZoomState, NormalState,
4154 * or WithdrawnState. */
4156 WmInfo *wmPtr = winPtr->wmInfoPtr;
4159 wmPtr->hints.initial_state = state;
4160 if (wmPtr->flags & WM_NEVER_MAPPED) {
4164 macWin = TkMacGetDrawablePort(winPtr->window);
4166 if (state == WithdrawnState) {
4167 Tk_UnmapWindow((Tk_Window) winPtr);
4168 } else if (state == IconicState) {
4169 Tk_UnmapWindow((Tk_Window) winPtr);
4170 if (TkMacHaveAppearance()) {
4172 * The window always gets unmapped. However, if we can show the
4173 * icon version of the window (collapsed) we make the window visable
4174 * and then collapse it.
4176 * TODO: This approach causes flashing!
4179 if (IsWindowCollapsable((WindowRef) macWin)) {
4180 ShowWindow((WindowRef) macWin);
4181 CollapseWindow((WindowPtr) macWin, true);
4184 } else if (state == NormalState) {
4185 Tk_MapWindow((Tk_Window) winPtr);
4186 if (TkMacHaveAppearance()) {
4187 CollapseWindow((WindowPtr) macWin, false);
4189 } else if (state == ZoomState) {
4190 /* TODO: need to support zoomed windows */
4194 *----------------------------------------------------------------------
4196 * TkMacHaveAppearance --
4198 * Determine if the appearance manager is available on this Mac.
4199 * We cache the result so future calls are fast. Return a different
4200 * value if 1.0.1 is present, since many interfaces were added in
4204 * 1 if the appearance manager is present, 2 if the appearance
4205 * manager version is 1.0.1 or greater, 0 if it is not present.
4208 * Calls Gestalt to query system values.
4210 *----------------------------------------------------------------------
4214 TkMacHaveAppearance()
4216 static initialized = false;
4217 static int TkMacHaveAppearance = 0;
4222 err = Gestalt(gestaltAppearanceAttr, &response);
4224 TkMacHaveAppearance = 1;
4226 err = Gestalt(gestaltAppearanceVersion, &response);
4228 TkMacHaveAppearance = 2;
4232 return TkMacHaveAppearance;