|
|
1.1 root 1: /*
2: * tkWm.c --
3: *
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.
8: *
9: * Copyright 1991 Regents of the University of California.
10: * Permission to use, copy, modify, and distribute this
11: * software and its documentation for any purpose and without
12: * fee is hereby granted, provided that the above copyright
13: * notice appear in all copies. The University of California
14: * makes no representations about the suitability of this
15: * software for any purpose. It is provided "as is" without
16: * express or implied warranty.
17: */
18:
19: #ifndef lint
20: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkWm.c,v 1.32 92/08/21 16:26:31 ouster Exp $ SPRITE (Berkeley)";
21: #endif
22:
23: #include "tkconfig.h"
24: #include "tkint.h"
25: #include "tkwm.h"
26:
27: /*
28: * The definitions below compensate for the lack of some definitions
29: * under X11R3.
30: */
31:
32: #ifdef X11R3
33: #define PBaseSize (1L<<8)
34: #endif
35:
36: /*
37: * A data structure of the following type holds window-manager-related
38: * information for each top-level window in an application.
39: */
40:
41: typedef struct TkWmInfo {
42: TkWindow *winPtr; /* Pointer to main Tk information for
43: * this window. */
44: Window reparent; /* If the window has been reparented, this
45: * gives the ID of the ancestor of the window
46: * that is a child of the root window (may
47: * not be window's immediate parent). If
48: * the window isn't reparented, this has the
49: * value None. */
50: Tk_Uid titleUid; /* Title to display in window caption. If
51: * NULL, use name of widget. */
52: Tk_Uid iconName; /* Name to display in icon. */
53: Window master; /* Master window for TRANSIENT_FOR property,
54: * or None. */
55: XWMHints hints; /* Various pieces of information for
56: * window manager. */
57: Tk_Uid leaderName; /* Path name of leader of window group
58: * (corresponds to hints.window_group).
59: * Note: this field doesn't get updated
60: * if leader is destroyed. */
61: Tk_Uid iconWindowName; /* Path name of window specified as icon
62: * window for this window, or NULL. Note:
63: * this field doesn't get updated if
64: * iconWindowName is destroyed. */
65: Tk_Uid masterWindowName; /* Path name of window specified as master
66: * in "wm transient" command, or NULL.
67: * Note: this field doesn't get updated if
68: * masterWindowName is destroyed. */
69:
70: /*
71: * Information used to construct an XSizeHints structure for
72: * the window manager:
73: */
74:
75: int sizeHintsFlags; /* Flags word for XSizeHints structure.
76: * If the PBaseSize flag is set then the
77: * window is gridded; otherwise it isn't
78: * gridded. */
79: int minWidth, minHeight; /* Minimum dimensions of window, in
80: * grid units, not pixels. */
81: int maxWidth, maxHeight; /* Maximum dimensions of window, in
82: * grid units, not pixels. */
83: int widthInc, heightInc; /* Increments for size changes (# pixels
84: * per step). */
85: struct {
86: int x; /* numerator */
87: int y; /* denominator */
88: } minAspect, maxAspect; /* Min/max aspect ratios for window. */
89: int reqGridWidth, reqGridHeight;
90: /* The dimensions of the window (in
91: * grid units) requested through
92: * the geometry manager. */
93: int gravity; /* Desired window gravity. */
94:
95: /*
96: * Information used to manage the size and location of a window.
97: */
98:
99: int prevReqWidth, prevReqHeight;
100: /* Last known size preferences, as specified
101: * to Tk_GeometryRequest. Used to tell when
102: * the preferred dimensions have changed. */
103: int width, height; /* Desired dimensions of window, specified
104: * in grid units. These values are
105: * set by the "wm geometry" command and by
106: * ConfigureNotify events (for when wm
107: * resizes window). -1 means user hasn't
108: * requested dimensions. */
109: int x, y; /* Desired X and Y coordinates for window.
110: * These values are set by "wm geometry",
111: * plus by ConfigureNotify events (when wm
112: * moves window). These numbers are
113: * different than the numbers stored in
114: * winPtr->changes because (a) they could be
115: * measured from the right or bottom edge
116: * of the screen (see WM_NEGATIVE_X and
117: * WM_NEGATIVE_Y flags) and (b) if the window
118: * has been reparented then they refer to the
119: * parent rather than the window itself. */
120: int parentWidth, parentHeight;
121: /* Width and height of reparent, in pixels
122: * *including border*. If window hasn't been
123: * reparented then these will be the outer
124: * dimensions of the window, including
125: * border. */
126: int xInParent, yInParent; /* Offset of window within reparent, measured
127: * from upper-left outer corner of parent's
128: * border. If not reparented then these are
129: * zero. */
130: unsigned long configRequest;/* Serial number of last request that we
131: * issued to change geometry of window.
132: * Used to discard configure events that
133: * we know will be superceded. */
134: int configWidth, configHeight;
135: /* Dimensions passed to last request that we
136: * issued to change geometry of window. Used
137: * to eliminate redundant resize operations. */
138:
139: int flags; /* Miscellaneous flags, defined below. */
140:
141: char *deleteCmd; /* Command to execute when a WM_DELETE_WINDOW
142: * ICCCM ClientMessage arrives for this window.
143: *
144: * If it is the empty string "" or has never
145: * been set (is char *)NULL) via the "wm" tcl
146: * command the window is destroyed.
147: *
148: * If it is a non-empty string, the name of
149: * the window is appended on to the end
150: * of the string and it is executed
151: * within the interpreter associated with
152: * the top level window.
153: */
154: struct TkWmInfo *nextPtr; /* Next in list of all top-level windows. */
155: } WmInfo;
156:
157: /*
158: * Flag values for WmInfo structures:
159: *
160: * WM_NEVER_MAPPED - non-zero means window has never been
161: * mapped; need to update all info when
162: * window is first mapped.
163: * WM_UPDATE_PENDING - non-zero means a call to UpdateGeometryInfo
164: * has already been scheduled for this
165: * window; no need to schedule another one.
166: * WM_NEGATIVE_X - non-zero means x-coordinate is measured in
167: * pixels from right edge of screen, rather
168: * than from left edge.
169: * WM_NEGATIVE_Y - non-zero means y-coordinate is measured in
170: * pixels up from bottom of screen, rather than
171: * down from top.
172: * WM_UPDATE_SIZE_HINTS - non-zero means that new size hints need to be
173: * propagated to window manager.
174: * WM_NESTED_REPARENT - non-zero means that the window has been
175: * reparented several levels deep in a hierarchy
176: * (i.e. reparent isn't the window's immediate
177: * parent).
178: * WM_CONFIG_PENDING - non-zero means we've asked for the top-level
179: * window to be resized but haven't seen a
180: * ConfigureNotify event to indicate that the
181: * resize occurred.
182: * WM_CONFIG_AGAIN - non-zero means we need to reconfigure the
183: * window again as soon as the current configure
184: * request has been processed by the window
185: * manager.
186: * WM_FULL_SCREEN - non-zero means that the window is in full screen mode.
187: */
188:
189: #define WM_NEVER_MAPPED 1
190: #define WM_UPDATE_PENDING 2
191: #define WM_NEGATIVE_X 4
192: #define WM_NEGATIVE_Y 8
193: #define WM_UPDATE_SIZE_HINTS 0x10
194: #define WM_NESTED_REPARENT 0x20
195: #define WM_CONFIG_PENDING 0x40
196: #define WM_CONFIG_AGAIN 0x100
197: #define WM_FULL_SCREEN 0x200
198:
199: /*
200: * This module keeps a list of all top-level windows, primarily to
201: * simplify the job of Tk_CoordsToWindow.
202: */
203:
204: static WmInfo *firstWmPtr = NULL; /* Points to first top-level window. */
205:
206: #define IS_GRIDDED(wmPtr) ((wmPtr)->sizeHintsFlags & PBaseSize)
207:
208: /*
209: * Forward declarations for procedures defined in this file:
210: */
211:
212: static int ParseGeometry _ANSI_ARGS_ ((Tcl_Interp *interp,
213: char *string, TkWindow *winPtr));
214: static void TopLevelEventProc _ANSI_ARGS_((ClientData clientData,
215: XEvent *eventPtr));
216: static void TopLevelReqProc _ANSI_ARGS_((ClientData dummy,
217: Tk_Window tkwin));
218: static void UpdateGeometryInfo _ANSI_ARGS_((
219: ClientData clientData));
220: static void UpdateHints _ANSI_ARGS_((TkWindow *winPtr));
221: static void UpdateSizeHints _ANSI_ARGS_((TkWindow *winPtr));
222:
223: /*
224: *--------------------------------------------------------------
225: *
226: * TkWmNewWindow --
227: *
228: * This procedure is invoked whenever a new top-level
229: * window is created. Its job is to initialize the WmInfo
230: * structure for the window.
231: *
232: * Results:
233: * None.
234: *
235: * Side effects:
236: * A WmInfo structure gets allocated and initialized.
237: *
238: *--------------------------------------------------------------
239: */
240:
241: void
242: TkWmNewWindow(winPtr)
243: TkWindow *winPtr; /* Newly-created top-level window. */
244: {
245: register WmInfo *wmPtr;
246:
247: wmPtr = (WmInfo *) ckalloc(sizeof(WmInfo));
248: wmPtr->winPtr = winPtr;
249: wmPtr->reparent = None;
250: wmPtr->titleUid = NULL;
251: wmPtr->iconName = NULL;
252: wmPtr->master = None;
253: wmPtr->hints.flags = InputHint | StateHint;
254: wmPtr->hints.input = True;
255: wmPtr->hints.initial_state = NormalState;
256: wmPtr->hints.icon_pixmap = None;
257: wmPtr->hints.icon_window = None;
258: wmPtr->hints.icon_x = wmPtr->hints.icon_y = 0;
259: wmPtr->hints.icon_mask = None;
260: wmPtr->hints.window_group = None;
261: wmPtr->leaderName = NULL;
262: wmPtr->iconWindowName = NULL;
263: wmPtr->masterWindowName = NULL;
264: wmPtr->sizeHintsFlags = 0;
265: wmPtr->minWidth = wmPtr->minHeight = 0;
266: wmPtr->maxWidth = wmPtr->maxHeight = 10000;
267: wmPtr->widthInc = wmPtr->heightInc = 1;
268: wmPtr->minAspect.x = wmPtr->minAspect.y = 1;
269: wmPtr->maxAspect.x = wmPtr->maxAspect.y = 1;
270: wmPtr->reqGridWidth = wmPtr->reqGridHeight = -1;
271: wmPtr->prevReqWidth = wmPtr->prevReqHeight = -1;
272: wmPtr->gravity = NorthWestGravity;
273: wmPtr->width = -1;
274: wmPtr->height = -1;
275: wmPtr->x = winPtr->changes.x;
276: wmPtr->y = winPtr->changes.y;
277: wmPtr->parentWidth = winPtr->changes.width
278: + 2*winPtr->changes.border_width;
279: wmPtr->parentHeight = winPtr->changes.height
280: + 2*winPtr->changes.border_width;
281: wmPtr->xInParent = wmPtr->yInParent = 0;
282: wmPtr->configRequest = 0;
283: wmPtr->configWidth = -1;
284: wmPtr->configHeight = -1;
285: wmPtr->flags = WM_NEVER_MAPPED;
286: wmPtr->deleteCmd = (char *)0;
287: wmPtr->nextPtr = firstWmPtr;
288: firstWmPtr = wmPtr;
289: winPtr->wmInfoPtr = wmPtr;
290:
291: /*
292: * Tk must monitor certain events for top-level windows:
293: * (a) structure events, in order to detect size and position changes
294: * caused by window managers.
295: * (b) enter/level events, in order to perform focussing correctly.
296: */
297:
298: Tk_CreateEventHandler((Tk_Window) winPtr,
299: StructureNotifyMask|EnterWindowMask|LeaveWindowMask,
300: TopLevelEventProc, (ClientData) winPtr);
301:
302: /*
303: * Arrange for geometry requests to be reflected from the window
304: * to the window manager.
305: */
306:
307: Tk_ManageGeometry((Tk_Window) winPtr, TopLevelReqProc, (ClientData) 0);
308: }
309:
310: /*
311: *--------------------------------------------------------------
312: *
313: * TkWmMapWindow --
314: *
315: * This procedure is invoked just before a top-level window
316: * is mapped. It gives this module a chance to update all
317: * window-manager-related information in properties before
318: * the window manager sees the map event and checks the
319: * properties.
320: *
321: * Results:
322: * Returns non-zero if it's OK for the window to be mapped, 0
323: * if the caller shouldn't map the window after all (e.g. because
324: * it has been withdrawn).
325: *
326: * Side effects:
327: * Properties of winPtr may get updated to provide up-to-date
328: * information to the window manager.
329: *
330: *--------------------------------------------------------------
331: */
332:
333: int
334: TkWmMapWindow(winPtr)
335: TkWindow *winPtr; /* Top-level window that's about to
336: * be mapped. */
337: {
338: register WmInfo *wmPtr = winPtr->wmInfoPtr;
339: #ifndef X11R3
340: XTextProperty textProp;
341: #endif
342:
343: /*
344: * Set the MAPPED flag if the window is going to appear in its normal
345: * state: if it's going to be iconified or withdrawn then it won't
346: * ever be mapped.
347: */
348:
349: if (wmPtr->hints.initial_state == NormalState) {
350: winPtr->flags |= TK_MAPPED;
351: }
352: if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
353: return 1;
354: }
355: wmPtr->flags &= ~WM_NEVER_MAPPED;
356:
357: /*
358: * This is the first time this window has ever been mapped.
359: * Store all the window-manager-related information for the
360: * window.
361: */
362:
363: #ifndef X11R3
364: if (wmPtr->titleUid == NULL) {
365: wmPtr->titleUid = winPtr->nameUid;
366: }
367: if (XStringListToTextProperty(&wmPtr->titleUid, 1, &textProp) != 0) {
368: XSetWMName(winPtr->display, winPtr->window, &textProp);
369: XFree((char *) textProp.value);
370: }
371: #endif
372:
373: TkWmSetClass(winPtr);
374: TkWmSetWmProtocols(winPtr);
375:
376: if (wmPtr->iconName != NULL) {
377: XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
378: }
379:
380: if (wmPtr->master != None) {
381: XSetTransientForHint(winPtr->display, winPtr->window, wmPtr->master);
382: }
383:
384: wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
385: UpdateGeometryInfo((ClientData) winPtr);
386: UpdateHints(winPtr);
387: if (wmPtr->hints.initial_state == WithdrawnState) {
388: return 0;
389: }
390: return 1;
391: }
392:
393: /*
394: *--------------------------------------------------------------
395: *
396: * TkWmDeadWindow --
397: *
398: * This procedure is invoked when a top-level window is
399: * about to be deleted. It cleans up the wm-related data
400: * structures for the window.
401: *
402: * Results:
403: * None.
404: *
405: * Side effects:
406: * The WmInfo structure for winPtr gets freed up.
407: *
408: *--------------------------------------------------------------
409: */
410:
411: void
412: TkWmDeadWindow(winPtr)
413: TkWindow *winPtr; /* Newly-created top-level window. */
414: {
415: register WmInfo *wmPtr = winPtr->wmInfoPtr;
416:
417: if (wmPtr == NULL) {
418: return;
419: }
420: if (firstWmPtr == wmPtr) {
421: firstWmPtr = wmPtr->nextPtr;
422: } else {
423: register WmInfo *prevPtr;
424:
425: for (prevPtr = firstWmPtr; ; prevPtr = prevPtr->nextPtr) {
426: if (prevPtr == NULL) {
427: panic("couldn't unlink window in TkWmDeadWindow");
428: }
429: if (prevPtr->nextPtr == wmPtr) {
430: prevPtr->nextPtr = wmPtr->nextPtr;
431: break;
432: }
433: }
434: }
435: if (wmPtr->hints.flags & IconPixmapHint) {
436: Tk_FreeBitmap(wmPtr->hints.icon_pixmap);
437: }
438: if (wmPtr->hints.flags & IconMaskHint) {
439: Tk_FreeBitmap(wmPtr->hints.icon_mask);
440: }
441: if (wmPtr->flags & WM_UPDATE_PENDING) {
442: Tk_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
443: }
444: if (wmPtr->deleteCmd) {
445: ckfree(wmPtr->deleteCmd);
446: }
447: ckfree((char *) wmPtr);
448: winPtr->wmInfoPtr = NULL;
449: }
450:
451: /*
452: *--------------------------------------------------------------
453: *
454: * TkWmSetClass --
455: *
456: * This procedure is invoked whenever a top-level window's
457: * class is changed. If the window has been mapped then this
458: * procedure updates the window manager property for the
459: * class. If the window hasn't been mapped, the update is
460: * deferred until just before the first mapping.
461: *
462: * Results:
463: * None.
464: *
465: * Side effects:
466: * A window property may get updated.
467: *
468: *--------------------------------------------------------------
469: */
470:
471: void
472: TkWmSetClass(winPtr)
473: TkWindow *winPtr; /* Newly-created top-level window. */
474: {
475: if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
476: return;
477: }
478:
479: #ifndef X11R3
480: if (winPtr->classUid != NULL) {
481: XClassHint *classPtr;
482:
483: classPtr = XAllocClassHint();
484: classPtr->res_name = winPtr->nameUid;
485: classPtr->res_class = winPtr->classUid;
486: XSetClassHint(winPtr->display, winPtr->window, classPtr);
487: XFree((char *) classPtr);
488: }
489: #endif
490: }
491:
492: /*
493: *----------------------------------------------------------------------
494: *
495: * Tk_WmCmd --
496: *
497: * This procedure is invoked to process the "wm" Tcl command.
498: * See the user documentation for details on what it does.
499: *
500: * Results:
501: * A standard Tcl result.
502: *
503: * Side effects:
504: * See the user documentation.
505: *
506: *----------------------------------------------------------------------
507: */
508:
509: /* ARGSUSED */
510: int
511: Tk_WmCmd(clientData, interp, argc, argv)
512: ClientData clientData; /* Main window associated with
513: * interpreter. */
514: Tcl_Interp *interp; /* Current interpreter. */
515: int argc; /* Number of arguments. */
516: char **argv; /* Argument strings. */
517: {
518: Tk_Window tkwin = (Tk_Window) clientData;
519: TkWindow *winPtr;
520: register WmInfo *wmPtr;
521: char c;
522: int length;
523:
524: if (argc < 3) {
525: Tcl_AppendResult(interp, "wrong # args: should be \"",
526: argv[0], " option window ?arg ...?\"", (char *) NULL);
527: return TCL_ERROR;
528: }
529: winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
530: if (winPtr == NULL) {
531: return TCL_ERROR;
532: }
533: if (!(winPtr->flags & TK_TOP_LEVEL)) {
534: Tcl_AppendResult(interp, "window \"", winPtr->pathName,
535: "\" isn't a top-level window", (char *) NULL);
536: return TCL_ERROR;
537: }
538: wmPtr = winPtr->wmInfoPtr;
539: c = argv[1][0];
540: length = strlen(argv[1]);
541: if ((c == 'a') && (strncmp(argv[1], "aspect", length) == 0)) {
542: int numer1, denom1, numer2, denom2;
543:
544: if ((argc != 3) && (argc != 7)) {
545: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
546: argv[0], " aspect window ?minNumer minDenom ",
547: "maxNumer maxDenom?\"", (char *) NULL);
548: return TCL_ERROR;
549: }
550: if (argc == 3) {
551: if (wmPtr->sizeHintsFlags & PAspect) {
552: sprintf(interp->result, "%d %d %d %d", wmPtr->minAspect.x,
553: wmPtr->minAspect.y, wmPtr->maxAspect.x,
554: wmPtr->maxAspect.y);
555: }
556: return TCL_OK;
557: }
558: if (*argv[3] == '\0') {
559: wmPtr->sizeHintsFlags &= ~PAspect;
560: } else {
561: if ((Tcl_GetInt(interp, argv[3], &numer1) != TCL_OK)
562: || (Tcl_GetInt(interp, argv[4], &denom1) != TCL_OK)
563: || (Tcl_GetInt(interp, argv[5], &numer2) != TCL_OK)
564: || (Tcl_GetInt(interp, argv[6], &denom2) != TCL_OK)) {
565: return TCL_ERROR;
566: }
567: if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) ||
568: (denom2 <= 0)) {
569: interp->result = "aspect number can't be <= 0";
570: return TCL_ERROR;
571: }
572: wmPtr->minAspect.x = numer1;
573: wmPtr->minAspect.y = denom1;
574: wmPtr->maxAspect.x = numer2;
575: wmPtr->maxAspect.y = denom2;
576: wmPtr->sizeHintsFlags |= PAspect;
577: }
578: wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
579: goto updateGeom;
580: } else if ((c == 'd') && (strncmp(argv[1], "deiconify", length) == 0)) {
581: if (argc != 3) {
582: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
583: argv[0], " deiconify window\"", (char *) NULL);
584: return TCL_ERROR;
585: }
586: wmPtr->hints.initial_state = NormalState;
587: if (wmPtr->flags & WM_NEVER_MAPPED) {
588: return TCL_OK;
589: }
590: Tk_MapWindow((Tk_Window) winPtr);
591: } else if ((c == 'f') && (strncmp(argv[1], "focusmodel", length) == 0)) {
592: if ((argc != 3) && (argc != 4)) {
593: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
594: argv[0], " focusmodel window ?active|passive?\"",
595: (char *) NULL);
596: return TCL_ERROR;
597: }
598: if (argc == 3) {
599: interp->result = wmPtr->hints.input ? "passive" : "active";
600: return TCL_OK;
601: }
602: c = argv[3][0];
603: length = strlen(argv[3]);
604: if ((c == 'a') && (strncmp(argv[3], "active", length) == 0)) {
605: wmPtr->hints.input = False;
606: } else if ((c == 'p') && (strncmp(argv[3], "passive", length) == 0)) {
607: wmPtr->hints.input = True;
608: } else {
609: Tcl_AppendResult(interp, "bad argument \"", argv[3],
610: "\": must be active or passive", (char *) NULL);
611: return TCL_ERROR;
612: }
613: UpdateHints(winPtr);
614: } else if ((c == 'f') && (strncmp(argv[1], "fullscreen", length) == 0)) {
615: if (argc != 4) {
616: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
617: argv[0], " fullscreen window on|off\"",
618: (char *) NULL);
619: return TCL_ERROR;
620: }
621: c = argv[3][0];
622: length = strlen(argv[3]);
623: if (strncmp(argv[3], "on", length) == 0) {
624: wmPtr->flags &= ~WM_FULL_SCREEN;
625: } else if (strncmp(argv[3], "off", length) == 0) {
626: wmPtr->flags |= WM_FULL_SCREEN;
627: } else {
628: Tcl_AppendResult(interp, "bad argument \"", argv[3],
629: "\": must be on or off", (char *) NULL);
630: return TCL_ERROR;
631: }
632:
633: static Atom _NET_WM_STATE;
634: static Atom _NET_WM_STATE_REMOVE;
635: static Atom _NET_WM_STATE_ADD;
636: static Atom _NET_WM_STATE_FULLSCREEN;
637:
638: if (!_NET_WM_STATE) {
639: #define MAX_ATOMS 30
640: Atom *atom_ptr[MAX_ATOMS];
641: char *names[MAX_ATOMS];
642: int i = 0;
643: #define atom(a,b) atom_ptr[i] = &a; names[i] = b; i++
644: atom(_NET_WM_STATE, "_NET_WM_STATE");
645: atom(_NET_WM_STATE_REMOVE, "_NET_WM_STATE_REMOVE");
646: atom(_NET_WM_STATE_ADD, "_NET_WM_STATE_ADD");
647: atom(_NET_WM_STATE_FULLSCREEN, "_NET_WM_STATE_FULLSCREEN");
648: #undef atom
649: Atom atoms[MAX_ATOMS];
650: XInternAtoms(winPtr->display, names, i, 0, atoms);
651: for (; i--;) {
652: *atom_ptr[i] = atoms[i];
653: }
654: }
655:
656: XEvent e;
657: e.xany.type = ClientMessage;
658: e.xany.window = winPtr->window;
659: e.xclient.message_type = _NET_WM_STATE;
660: e.xclient.format = 32;
661: e.xclient.data.l[0] =
662: (wmPtr->flags & WM_FULL_SCREEN)
663: ? _NET_WM_STATE_ADD
664: : _NET_WM_STATE_REMOVE;
665: e.xclient.data.l[1] = (long)_NET_WM_STATE_FULLSCREEN;
666: e.xclient.data.l[2] = (long)0;
667: e.xclient.data.l[3] = (long)0;
668: e.xclient.data.l[4] = (long)0;
669: XSendEvent(winPtr->display, RootWindow(winPtr->display, winPtr->screenNum), 0,
670: SubstructureNotifyMask|SubstructureRedirectMask, &e);
671:
672: } else if ((c == 'g') && (strncmp(argv[1], "geometry", length) == 0)
673: && (length >= 2)) {
674: char xSign, ySign;
675: int width, height;
676:
677: if ((argc != 3) && (argc != 4)) {
678: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
679: argv[0], " geometry window ?newGeometry?\"",
680: (char *) NULL);
681: return TCL_ERROR;
682: }
683: if (argc == 3) {
684: xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+';
685: ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+';
686: if (wmPtr->width != -1) {
687: width = wmPtr->width;
688: height = wmPtr->height;
689: } else if (IS_GRIDDED(wmPtr)) {
690: width = wmPtr->reqGridWidth;
691: height = wmPtr->reqGridHeight;
692: } else {
693: width = winPtr->reqWidth;
694: height = winPtr->reqHeight;
695: }
696: sprintf(interp->result, "%dx%d%c%d%c%d", width, height,
697: xSign, wmPtr->x, ySign, wmPtr->y);
698: return TCL_OK;
699: }
700: if (*argv[3] == '\0') {
701: wmPtr->width = -1;
702: wmPtr->height = -1;
703: goto updateGeom;
704: }
705: return ParseGeometry(interp, argv[3], winPtr);
706: } else if ((c == 'g') && (strncmp(argv[1], "grid", length) == 0)
707: && (length >= 3)) {
708: int reqWidth, reqHeight, widthInc, heightInc;
709:
710: if ((argc != 3) && (argc != 7)) {
711: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
712: argv[0], " reqsize window ?baseWidth baseHeight ",
713: "widthInc heightInc?\"", (char *) NULL);
714: return TCL_ERROR;
715: }
716: if (argc == 3) {
717: if (wmPtr->sizeHintsFlags & PBaseSize) {
718: sprintf(interp->result, "%d %d %d %d", wmPtr->reqGridWidth,
719: wmPtr->reqGridHeight, wmPtr->widthInc,
720: wmPtr->heightInc);
721: }
722: return TCL_OK;
723: }
724: if (*argv[3] == '\0') {
725: /*
726: * Turn off gridding and reset the width and height
727: * to make sense as ungridded numbers.
728: */
729:
730: wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
731: wmPtr->widthInc = 1;
732: wmPtr->heightInc = 1;
733: if (wmPtr->width != -1) {
734: wmPtr->width = winPtr->reqWidth + (wmPtr->width
735: - wmPtr->reqGridWidth)*wmPtr->widthInc;
736: wmPtr->height = winPtr->reqHeight + (wmPtr->height
737: - wmPtr->reqGridHeight)*wmPtr->heightInc;
738: }
739: } else {
740: if ((Tcl_GetInt(interp, argv[3], &reqWidth) != TCL_OK)
741: || (Tcl_GetInt(interp, argv[4], &reqHeight) != TCL_OK)
742: || (Tcl_GetInt(interp, argv[5], &widthInc) != TCL_OK)
743: || (Tcl_GetInt(interp, argv[6], &heightInc) != TCL_OK)) {
744: return TCL_ERROR;
745: }
746: if (reqWidth < 0) {
747: interp->result = "baseWidth can't be < 0";
748: return TCL_ERROR;
749: }
750: if (reqHeight < 0) {
751: interp->result = "baseHeight can't be < 0";
752: return TCL_ERROR;
753: }
754: if (widthInc < 0) {
755: interp->result = "widthInc can't be < 0";
756: return TCL_ERROR;
757: }
758: if (heightInc < 0) {
759: interp->result = "heightInc can't be < 0";
760: return TCL_ERROR;
761: }
762: Tk_SetGrid((Tk_Window) tkwin, reqWidth, reqHeight, widthInc,
763: heightInc);
764: }
765: wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
766: goto updateGeom;
767: } else if ((c == 'g') && (strncmp(argv[1], "group", length) == 0)
768: && (length >= 3)) {
769: Tk_Window tkwin2;
770:
771: if ((argc != 3) && (argc != 4)) {
772: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
773: argv[0], " group window ?pathName?\"",
774: (char *) NULL);
775: return TCL_ERROR;
776: }
777: if (argc == 3) {
778: if (wmPtr->hints.flags & WindowGroupHint) {
779: interp->result = wmPtr->leaderName;
780: }
781: return TCL_OK;
782: }
783: if (*argv[3] == '\0') {
784: wmPtr->hints.flags &= ~WindowGroupHint;
785: wmPtr->leaderName = NULL;
786: } else {
787: tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
788: if (tkwin2 == NULL) {
789: return TCL_ERROR;
790: }
791: Tk_MakeWindowExist(tkwin2);
792: wmPtr->hints.window_group = Tk_WindowId(tkwin2);
793: wmPtr->hints.flags |= WindowGroupHint;
794: wmPtr->leaderName = Tk_PathName(tkwin2);
795: }
796: UpdateHints(winPtr);
797: } else if ((c == 'i') && (strncmp(argv[1], "iconbitmap", length) == 0)
798: && (length >= 5)) {
799: Pixmap pixmap;
800:
801: if ((argc != 3) && (argc != 4)) {
802: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
803: argv[0], " iconbitmap window ?bitmap?\"",
804: (char *) NULL);
805: return TCL_ERROR;
806: }
807: if (argc == 3) {
808: if (wmPtr->hints.flags & IconPixmapHint) {
809: interp->result = Tk_NameOfBitmap(wmPtr->hints.icon_pixmap);
810: }
811: return TCL_OK;
812: }
813: if (*argv[3] == '\0') {
814: if (wmPtr->hints.icon_pixmap != None) {
815: Tk_FreeBitmap(wmPtr->hints.icon_pixmap);
816: }
817: wmPtr->hints.flags &= ~IconPixmapHint;
818: } else {
819: pixmap = Tk_GetBitmap(interp, tkwin, Tk_GetUid(argv[3]));
820: if (pixmap == None) {
821: return TCL_ERROR;
822: }
823: wmPtr->hints.icon_pixmap = pixmap;
824: wmPtr->hints.flags |= IconPixmapHint;
825: }
826: UpdateHints(winPtr);
827: } else if ((c == 'i') && (strncmp(argv[1], "iconify", length) == 0)
828: && (length >= 5)) {
829: if (argc != 3) {
830: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
831: argv[0], " iconify window\"", (char *) NULL);
832: return TCL_ERROR;
833: }
834: wmPtr->hints.initial_state = IconicState;
835: if (wmPtr->flags & WM_NEVER_MAPPED) {
836: return TCL_OK;
837: }
838: #ifndef X11R3
839: if (XIconifyWindow(winPtr->display, winPtr->window,
840: winPtr->screenNum) == 0) {
841: interp->result =
842: "couldn't send iconify message to window manager";
843: return TCL_ERROR;
844: }
845: #else
846: interp->result = "can't iconify under X11R3";
847: return TCL_ERROR;
848: #endif
849: } else if ((c == 'i') && (strncmp(argv[1], "iconmask", length) == 0)
850: && (length >= 5)) {
851: Pixmap pixmap;
852:
853: if ((argc != 3) && (argc != 4)) {
854: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
855: argv[0], " iconmask window ?bitmap?\"",
856: (char *) NULL);
857: return TCL_ERROR;
858: }
859: if (argc == 3) {
860: if (wmPtr->hints.flags & IconMaskHint) {
861: interp->result = Tk_NameOfBitmap(wmPtr->hints.icon_mask);
862: }
863: return TCL_OK;
864: }
865: if (*argv[3] == '\0') {
866: if (wmPtr->hints.icon_mask != None) {
867: Tk_FreeBitmap(wmPtr->hints.icon_mask);
868: }
869: wmPtr->hints.flags &= ~IconMaskHint;
870: } else {
871: pixmap = Tk_GetBitmap(interp, tkwin, Tk_GetUid(argv[3]));
872: if (pixmap == None) {
873: return TCL_ERROR;
874: }
875: wmPtr->hints.icon_mask = pixmap;
876: wmPtr->hints.flags |= IconMaskHint;
877: }
878: UpdateHints(winPtr);
879: } else if ((c == 'i') && (strncmp(argv[1], "iconname", length) == 0)
880: && (length >= 5)) {
881: if (argc > 4) {
882: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
883: argv[0], " iconname window ?newName?\"", (char *) NULL);
884: return TCL_ERROR;
885: }
886: if (argc == 3) {
887: interp->result = (wmPtr->iconName != NULL) ? wmPtr->iconName : "";
888: return TCL_OK;
889: } else {
890: wmPtr->iconName = Tk_GetUid(argv[3]);
891: if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
892: XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
893: }
894: }
895: } else if ((c == 'i') && (strncmp(argv[1], "iconposition", length) == 0)
896: && (length >= 5)) {
897: int x, y;
898:
899: if ((argc != 3) && (argc != 5)) {
900: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
901: argv[0], " iconposition window ?x y?\"",
902: (char *) NULL);
903: return TCL_ERROR;
904: }
905: if (argc == 3) {
906: if (wmPtr->hints.flags & IconPositionHint) {
907: sprintf(interp->result, "%d %d", wmPtr->hints.icon_x,
908: wmPtr->hints.icon_y);
909: }
910: return TCL_OK;
911: }
912: if (*argv[3] == '\0') {
913: wmPtr->hints.flags &= ~IconPositionHint;
914: } else {
915: if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK)
916: || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)){
917: return TCL_ERROR;
918: }
919: wmPtr->hints.icon_x = x;
920: wmPtr->hints.icon_y = y;
921: wmPtr->hints.flags |= IconPositionHint;
922: }
923: UpdateHints(winPtr);
924: } else if ((c == 'i') && (strncmp(argv[1], "iconwindow", length) == 0)
925: && (length >= 5)) {
926: Tk_Window tkwin2;
927:
928: if ((argc != 3) && (argc != 4)) {
929: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
930: argv[0], " iconwindow window ?pathName?\"",
931: (char *) NULL);
932: return TCL_ERROR;
933: }
934: if (argc == 3) {
935: if (wmPtr->hints.flags & IconWindowHint) {
936: interp->result = wmPtr->iconWindowName;
937: }
938: return TCL_OK;
939: }
940: if (*argv[3] == '\0') {
941: wmPtr->hints.flags &= ~IconWindowHint;
942: wmPtr->iconWindowName = NULL;
943: } else {
944: tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
945: if (tkwin2 == NULL) {
946: return TCL_ERROR;
947: }
948: Tk_MakeWindowExist(tkwin2);
949: wmPtr->hints.icon_window = Tk_WindowId(tkwin2);
950: wmPtr->hints.flags |= IconWindowHint;
951: wmPtr->iconWindowName = Tk_PathName(tkwin2);
952: }
953: UpdateHints(winPtr);
954: } else if ((c == 'm') && (strncmp(argv[1], "maxsize", length) == 0)
955: && (length >= 2)) {
956: int width, height;
957: if ((argc != 3) && (argc != 5)) {
958: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
959: argv[0], " maxsize window ?width height?\"", (char *) NULL);
960: return TCL_ERROR;
961: }
962: if (argc == 3) {
963: if (wmPtr->sizeHintsFlags & PMaxSize) {
964: sprintf(interp->result, "%d %d", wmPtr->maxWidth,
965: wmPtr->maxHeight);
966: }
967: return TCL_OK;
968: }
969: if (*argv[3] == '\0') {
970: wmPtr->sizeHintsFlags &= ~PMaxSize;
971: } else {
972: if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
973: || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
974: return TCL_ERROR;
975: }
976: wmPtr->maxWidth = width;
977: wmPtr->maxHeight = height;
978: wmPtr->sizeHintsFlags |= PMaxSize;
979: }
980: wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
981: goto updateGeom;
982: } else if ((c == 'm') && (strncmp(argv[1], "minsize", length) == 0)
983: && (length >= 2)) {
984: int width, height;
985: if ((argc != 3) && (argc != 5)) {
986: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
987: argv[0], " minsize window ?width height?\"", (char *) NULL);
988: return TCL_ERROR;
989: }
990: if (argc == 3) {
991: if (wmPtr->sizeHintsFlags & PMinSize) {
992: sprintf(interp->result, "%d %d", wmPtr->minWidth,
993: wmPtr->minHeight);
994: }
995: return TCL_OK;
996: }
997: if (*argv[3] == '\0') {
998: wmPtr->sizeHintsFlags &= ~PMinSize;
999: } else {
1000: if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
1001: || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
1002: return TCL_ERROR;
1003: }
1004: wmPtr->minWidth = width;
1005: wmPtr->minHeight = height;
1006: wmPtr->sizeHintsFlags |= PMinSize;
1007: }
1008: wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1009: goto updateGeom;
1010: } else if ((c == 'p') && (strncmp(argv[1], "positionfrom", length) == 0)) {
1011: if ((argc != 3) && (argc != 4)) {
1012: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1013: argv[0], " positionfrom window ?user/program?\"",
1014: (char *) NULL);
1015: return TCL_ERROR;
1016: }
1017: if (argc == 3) {
1018: if (wmPtr->sizeHintsFlags & USPosition) {
1019: interp->result = "user";
1020: } else if (wmPtr->sizeHintsFlags & PPosition) {
1021: interp->result = "program";
1022: }
1023: return TCL_OK;
1024: }
1025: if (*argv[3] == '\0') {
1026: wmPtr->sizeHintsFlags &= ~(USPosition|PPosition);
1027: } else {
1028: c = argv[3][0];
1029: length = strlen(argv[3]);
1030: if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
1031: wmPtr->sizeHintsFlags &= ~PPosition;
1032: wmPtr->sizeHintsFlags |= USPosition;
1033: } else if ((c == 'p') && (strncmp(argv[3], "program", length) == 0)) {
1034: wmPtr->sizeHintsFlags &= ~USPosition;
1035: wmPtr->sizeHintsFlags |= PPosition;
1036: } else {
1037: Tcl_AppendResult(interp, "bad argument \"", argv[3],
1038: "\": must be program or user", (char *) NULL);
1039: return TCL_ERROR;
1040: }
1041: }
1042: wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1043: goto updateGeom;
1044: } else if ((c == 'r') && (strncmp(argv[1], "raise", length) == 0)) {
1045: if (argc != 3) {
1046: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1047: argv[0], " raise window\"", (char *) NULL);
1048: return TCL_ERROR;
1049: }
1050: Tk_MakeWindowExist((Tk_Window) winPtr);
1051: XRaiseWindow(Tk_Display(winPtr), Tk_WindowId(winPtr));
1052: } else if ((c == 's') && (strncmp(argv[1], "sizefrom", length) == 0)) {
1053: if ((argc != 3) && (argc != 4)) {
1054: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1055: argv[0], " sizefrom window ?user|program?\"",
1056: (char *) NULL);
1057: return TCL_ERROR;
1058: }
1059: if (argc == 3) {
1060: if (wmPtr->sizeHintsFlags & USSize) {
1061: interp->result = "user";
1062: } else if (wmPtr->sizeHintsFlags & PSize) {
1063: interp->result = "program";
1064: }
1065: return TCL_OK;
1066: }
1067: if (*argv[3] == '\0') {
1068: wmPtr->sizeHintsFlags &= ~(USSize|PSize);
1069: } else {
1070: c = argv[3][0];
1071: length = strlen(argv[3]);
1072: if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
1073: wmPtr->sizeHintsFlags &= ~PSize;
1074: wmPtr->sizeHintsFlags |= USSize;
1075: } else if ((c == 'p')
1076: && (strncmp(argv[3], "program", length) == 0)) {
1077: wmPtr->sizeHintsFlags &= ~USSize;
1078: wmPtr->sizeHintsFlags |= PSize;
1079: } else {
1080: Tcl_AppendResult(interp, "bad argument \"", argv[3],
1081: "\": must be program or user", (char *) NULL);
1082: return TCL_ERROR;
1083: }
1084: }
1085: wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1086: goto updateGeom;
1087: } else if ((c == 't') && (strncmp(argv[1], "title", length) == 0)
1088: && (length >= 2)) {
1089: if (argc > 4) {
1090: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1091: argv[0], " title window ?newTitle?\"", (char *) NULL);
1092: return TCL_ERROR;
1093: }
1094: if (argc == 3) {
1095: interp->result = (wmPtr->titleUid != NULL) ? wmPtr->titleUid
1096: : winPtr->nameUid;
1097: return TCL_OK;
1098: } else {
1099: wmPtr->titleUid = Tk_GetUid(argv[3]);
1100: #ifndef X11R3
1101: if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
1102: XTextProperty textProp;
1103:
1104: if (XStringListToTextProperty(&wmPtr->titleUid, 1,
1105: &textProp) != 0) {
1106: XSetWMName(winPtr->display, winPtr->window, &textProp);
1107: XFree((char *) textProp.value);
1108: }
1109: }
1110: #endif
1111: }
1112: #ifndef X11R3
1113: } else if ((c == 't') && (strncmp(argv[1], "transient", length) == 0)
1114: && (length >= 2)) {
1115: Tk_Window master;
1116:
1117: if ((argc != 3) && (argc != 4)) {
1118: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1119: argv[0], " transient window ?master?\"", (char *) NULL);
1120: return TCL_ERROR;
1121: }
1122: if (argc == 3) {
1123: if (wmPtr->master != None) {
1124: interp->result = wmPtr->masterWindowName;
1125: }
1126: return TCL_OK;
1127: }
1128: if (argv[3][0] == '\0') {
1129: wmPtr->master = None;
1130: wmPtr->masterWindowName = NULL;
1131: } else {
1132: master = Tk_NameToWindow(interp, argv[3], tkwin);
1133: if (master == NULL) {
1134: return TCL_ERROR;
1135: }
1136: Tk_MakeWindowExist(master);
1137: wmPtr->master = Tk_WindowId(master);
1138: wmPtr->masterWindowName = Tk_PathName(master);
1139: }
1140: if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
1141: XSetTransientForHint(winPtr->display, winPtr->window,
1142: wmPtr->master);
1143: }
1144: } else if ((c == 'w') && (strncmp(argv[1], "withdraw", length) == 0)) {
1145: if (argc != 3) {
1146: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1147: argv[0], " withdraw window\"", (char *) NULL);
1148: return TCL_ERROR;
1149: }
1150: wmPtr->hints.initial_state = WithdrawnState;
1151: if (wmPtr->flags & WM_NEVER_MAPPED) {
1152: return TCL_OK;
1153: }
1154: if (XWithdrawWindow(winPtr->display, winPtr->window,
1155: winPtr->screenNum) == 0) {
1156: interp->result =
1157: "couldn't send withdraw message to window manager";
1158: return TCL_ERROR;
1159: }
1160: winPtr->flags &= ~TK_MAPPED;
1161: } else if ((c == 'p') && (strncmp(argv[1], "protocol", length) == 0)) {
1162: /*
1163: * handle various ICCCM WM_PROTOCOL attributes
1164: */
1165: if (argc < 4) {
1166: Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1167: argv[0], " protocol window type..\"", (char *) NULL);
1168: return TCL_ERROR;
1169: }
1170: if (!strcmp(argv[3], "delete")) {
1171: return WmProtocolCmd(interp, &(wmPtr->deleteCmd), argc, argv);
1172: } else {
1173: Tcl_AppendResult(interp, argv[0],
1174: ": bad argument ", argv[3], " must be: ",
1175: "delete", (char *) NULL);
1176: return TCL_ERROR;
1177: }
1178: #endif
1179: } else {
1180: Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],
1181: "\": must be aspect, deiconify, focusmodel, ",
1182: "fullscreen, geometry, grid, group, iconbitmap, ",
1183: "iconify, iconmask, iconname, iconposition, ",
1184: "iconwindow, maxsize, minsize, positionfrom, raise, ",
1185: "sizefrom, title, transient, withdraw, or protocol",
1186: (char *) NULL);
1187: return TCL_ERROR;
1188: }
1189: return TCL_OK;
1190:
1191: updateGeom:
1192: if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
1193: Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
1194: wmPtr->flags |= WM_UPDATE_PENDING;
1195: }
1196: return TCL_OK;
1197: }
1198:
1199: /*
1200: *----------------------------------------------------------------------
1201: *
1202: * Tk_SetGrid --
1203: *
1204: * This procedure is invoked by a widget when it wishes to set a grid
1205: * coordinate system that controls the size of a top-level window.
1206: * It provides a C interface equivalent to the "wm grid" command and
1207: * is usually asscoiated with the -setgrid option.
1208: *
1209: * Results:
1210: * None.
1211: *
1212: * Side effects:
1213: * Grid-related information will be passed to the window manager, so
1214: * that the top-level window associated with tkwin will resize on
1215: * even grid units.
1216: *
1217: *----------------------------------------------------------------------
1218: */
1219:
1220: void
1221: Tk_SetGrid(tkwin, reqWidth, reqHeight, widthInc, heightInc)
1222: Tk_Window tkwin; /* Token for window. New window mgr info
1223: * will be posted for the top-level window
1224: * associated with this window. */
1225: int reqWidth; /* Width (in grid units) corresponding to
1226: * the requested geometry for tkwin. */
1227: int reqHeight; /* Height (in grid units) corresponding to
1228: * the requested geometry for tkwin. */
1229: int widthInc, heightInc; /* Pixel increments corresponding to a
1230: * change of one grid unit. */
1231: {
1232: TkWindow *winPtr = (TkWindow *) tkwin;
1233: register WmInfo *wmPtr;
1234:
1235: /*
1236: * Find the top-level window for tkwin, plus the window manager
1237: * information.
1238: */
1239:
1240: while (!(winPtr->flags & TK_TOP_LEVEL)) {
1241: winPtr = winPtr->parentPtr;
1242: }
1243: wmPtr = winPtr->wmInfoPtr;
1244:
1245: if ((wmPtr->reqGridWidth == reqWidth)
1246: && (wmPtr->reqGridHeight != reqHeight)
1247: && (wmPtr->widthInc != widthInc)
1248: && (wmPtr->heightInc != heightInc)
1249: && ((wmPtr->sizeHintsFlags & (PBaseSize|PResizeInc))
1250: == PBaseSize|PResizeInc)) {
1251: return;
1252: }
1253:
1254: /*
1255: * If gridding was previously off, then forget about any window
1256: * size requests made by the user or via "wm geometry": these are
1257: * in pixel units and there's no easy way to translate them to
1258: * grid units since the new requested size of the top-level window in
1259: * pixels may not yet have been registered yet (it may filter up
1260: * the hierarchy in DoWhenIdle handlers).
1261: */
1262:
1263: if (!(wmPtr->sizeHintsFlags & PBaseSize)) {
1264: wmPtr->width = -1;
1265: wmPtr->height = -1;
1266: }
1267:
1268: /*
1269: * Set the new gridding information, and start the process of passing
1270: * all of this information to the window manager.
1271: */
1272:
1273: wmPtr->reqGridWidth = reqWidth;
1274: wmPtr->reqGridHeight = reqHeight;
1275: wmPtr->widthInc = widthInc;
1276: wmPtr->heightInc = heightInc;
1277: wmPtr->sizeHintsFlags |= PBaseSize|PResizeInc;
1278: wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1279: if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
1280: Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
1281: wmPtr->flags |= WM_UPDATE_PENDING;
1282: }
1283: }
1284:
1285: /*
1286: *----------------------------------------------------------------------
1287: *
1288: * TopLevelEventProc --
1289: *
1290: * This procedure is invoked when a top-level (or other externally-
1291: * managed window) is restructured in any way.
1292: *
1293: * Results:
1294: * None.
1295: *
1296: * Side effects:
1297: * Tk's internal data structures for the window get modified to
1298: * reflect the structural change.
1299: *
1300: *----------------------------------------------------------------------
1301: */
1302:
1303: static void
1304: TopLevelEventProc(clientData, eventPtr)
1305: ClientData clientData; /* Window for which event occurred. */
1306: XEvent *eventPtr; /* Event that just happened. */
1307: {
1308: register TkWindow *winPtr = (TkWindow *) clientData;
1309:
1310: if (eventPtr->type == DestroyNotify) {
1311: if (!(winPtr->flags & TK_ALREADY_DEAD)) {
1312: Tk_DestroyWindow((Tk_Window) winPtr);
1313: }
1314: } else if (eventPtr->type == ConfigureNotify) {
1315: register WmInfo *wmPtr = winPtr->wmInfoPtr;
1316: int diff, x, y;
1317:
1318: /*
1319: * A top-level window has been reconfigured. Problem #1:
1320: * discard stale information. If the application has recently
1321: * tried to reconfigure itself, ignore all events until the
1322: * response to that reconfiguration arrives (the response is
1323: * assumed to be the first ConfigureNotify that arrives after
1324: * the server has seen the request; this suffers from potential
1325: * races with user actions, but it's the best I can think of
1326: * right now).
1327: */
1328:
1329: diff = eventPtr->xconfigure.serial - wmPtr->configRequest;
1330: if (diff < 0) {
1331: return;
1332: }
1333:
1334: /*
1335: * Problem #2: reparenting window managers. If the window
1336: * manager reparents a top-level window then the x and y
1337: * information that comes in events for the window is wrong:
1338: * it gives the location of the window inside its decorative
1339: * parent, rather than the location of the window in root
1340: * coordinates, which is what we want. Window managers
1341: * are supposed to send synthetic events with the correct
1342: * information, but ICCCM doesn't require them to do this
1343: * under all conditions, and the information provided doesn't
1344: * include everything we need here. So, the code below
1345: * maintains a bunch of information about the parent window.
1346: * If the window hasn't been reparented, we pretend that
1347: * there is a parent shrink-wrapped around the window.
1348: */
1349:
1350: if (wmPtr->reparent == None) {
1351: noReparent:
1352: winPtr->changes.x = eventPtr->xconfigure.x;
1353: winPtr->changes.y = eventPtr->xconfigure.y;
1354: wmPtr->parentWidth = eventPtr->xconfigure.width
1355: + 2*eventPtr->xconfigure.border_width;
1356: wmPtr->parentHeight = eventPtr->xconfigure.height
1357: + 2*eventPtr->xconfigure.border_width;
1358: } else {
1359: unsigned int width, height, bd, dummy;
1360: Window dummy2;
1361: Status status;
1362: Tk_ErrorHandler handler;
1363:
1364: handler = Tk_CreateErrorHandler(winPtr->display, BadDrawable, -1,
1365: -1, (Tk_ErrorProc *) NULL, (ClientData) NULL);
1366: status = XGetGeometry(winPtr->display, wmPtr->reparent,
1367: &dummy2, &x, &y, &width, &height, &bd, &dummy);
1368: Tk_DeleteErrorHandler(handler);
1369: if (status == 0) {
1370: /*
1371: * It appears that the reparented parent went away and
1372: * no-one told us. Reset the window to indicate that
1373: * it's not reparented, then handle it as a non-reparented
1374: * window.
1375: */
1376: wmPtr->reparent = None;
1377: wmPtr->flags &= ~WM_NESTED_REPARENT;
1378: wmPtr->xInParent = wmPtr->yInParent = 0;
1379: goto noReparent;
1380: }
1381: wmPtr->parentWidth = width + 2*bd;
1382: wmPtr->parentHeight = height + 2*bd;
1383: winPtr->changes.x = x;
1384: winPtr->changes.y = y;
1385: if (wmPtr->flags & WM_NESTED_REPARENT) {
1386: int xOffset, yOffset;
1387:
1388: (void) XTranslateCoordinates(winPtr->display, winPtr->window,
1389: wmPtr->reparent, 0, 0, &xOffset, &yOffset, &dummy2);
1390: wmPtr->xInParent = xOffset + bd - winPtr->changes.border_width;
1391: wmPtr->yInParent = yOffset + bd - winPtr->changes.border_width;
1392: } else {
1393: if (!eventPtr->xconfigure.send_event) {
1394: wmPtr->xInParent = eventPtr->xconfigure.x + bd;
1395: wmPtr->yInParent = eventPtr->xconfigure.y + bd;
1396: }
1397: }
1398: winPtr->changes.x = x + wmPtr->xInParent;
1399: winPtr->changes.y = y + wmPtr->yInParent;
1400: }
1401:
1402: /*
1403: * Problem #3: if the window size or location was changed
1404: * externally, update the geometry information in wmPtr to make
1405: * it look just as if the user had typed a "wm geometry" command
1406: * to make the change. There are many tricky situations to deal
1407: * with:
1408: * (a) the event is simply a reflection of an internal geometry
1409: * request from the window's widgets (must leave width and
1410: * height alone in this case).
1411: * (b) the window manager might respond to a size request from
1412: * us with a different size than requested (e.g. it might
1413: * have a minimum allowable window size). Because of this,
1414: * can't just compare new size with requested size to determine
1415: * whether this event is a reflection of an internal request
1416: * from within the application. Use WM_CONFIG_PENDING flag
1417: * instead.
1418: * (c) ConfigureNotify events also arise if the window has been
1419: * moved, even if its size hasn't changed. Must distinguish
1420: * between the user moving the window and the user resizing
1421: * the window.
1422: */
1423:
1424: if (wmPtr->flags & WM_CONFIG_PENDING) {
1425: int diff;
1426: /*
1427: * Size change is just a reflection of something coming from
1428: * application.
1429: */
1430:
1431: diff = eventPtr->xconfigure.serial - wmPtr->configRequest;
1432: if (diff >= 0) {
1433: if (wmPtr->flags & WM_CONFIG_AGAIN) {
1434: if (!(wmPtr->flags & WM_UPDATE_PENDING)) {
1435: Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
1436: wmPtr->flags |= WM_UPDATE_PENDING;
1437: }
1438: }
1439: wmPtr->flags &= ~(WM_CONFIG_PENDING|WM_CONFIG_AGAIN);
1440: }
1441: } else if ((winPtr->changes.width != eventPtr->xconfigure.width)
1442: || (winPtr->changes.height != eventPtr->xconfigure.height)) {
1443: wmPtr->configWidth = -1;
1444: wmPtr->configHeight = -1;
1445: if (IS_GRIDDED(wmPtr)) {
1446: wmPtr->width = wmPtr->reqGridWidth
1447: + (eventPtr->xconfigure.width
1448: - winPtr->reqWidth)/wmPtr->widthInc;
1449: if (wmPtr->width < 0) {
1450: wmPtr->width = 0;
1451: }
1452: wmPtr->height = wmPtr->reqGridHeight
1453: + (eventPtr->xconfigure.height
1454: - winPtr->reqHeight)/wmPtr->heightInc;
1455: if (wmPtr->height < 0) {
1456: wmPtr->height = 0;
1457: }
1458: } else if ((eventPtr->xconfigure.width != winPtr->changes.width)
1459: || (eventPtr->xconfigure.height
1460: != winPtr->changes.height)) {
1461: /*
1462: * The check above is needed so we don't think the user
1463: * requested a new size when all he/she did was to move
1464: * the window.
1465: */
1466:
1467: wmPtr->width = eventPtr->xconfigure.width;
1468: wmPtr->height = eventPtr->xconfigure.height;
1469: }
1470: }
1471:
1472: winPtr->changes.width = eventPtr->xconfigure.width;
1473: winPtr->changes.height = eventPtr->xconfigure.height;
1474: winPtr->changes.border_width = eventPtr->xconfigure.border_width;
1475: winPtr->changes.sibling = eventPtr->xconfigure.above;
1476: winPtr->changes.stack_mode = Above;
1477:
1478: x = winPtr->changes.x - wmPtr->xInParent;
1479: if (wmPtr->flags & WM_NEGATIVE_X) {
1480: x = DisplayWidth(winPtr->display, winPtr->screenNum)
1481: - (x + wmPtr->parentWidth);
1482: }
1483: y = winPtr->changes.y - wmPtr->yInParent;
1484: if (wmPtr->flags & WM_NEGATIVE_Y) {
1485: y = DisplayHeight(winPtr->display, winPtr->screenNum)
1486: - (y + wmPtr->parentHeight);
1487: }
1488: if ((x != wmPtr->x) || (y != wmPtr->y)) {
1489: wmPtr->x = x;
1490: wmPtr->y = y;
1491: }
1492: } else if (eventPtr->type == MapNotify) {
1493: winPtr->flags |= TK_MAPPED;
1494: } else if (eventPtr->type == UnmapNotify) {
1495: winPtr->flags &= ~TK_MAPPED;
1496: } else if (eventPtr->type == ReparentNotify) {
1497: WmInfo *wmPtr = winPtr->wmInfoPtr;
1498: Window root, *children, dummy2, *virtualRootPtr;
1499: Atom virtualRootAtom, actualType;
1500: int actualFormat;
1501: unsigned long numItems, bytesAfter;
1502: unsigned int dummy;
1503:
1504: /*
1505: * Locate the ancestor of this window that is just below the
1506: * root window for the screen (could be the window itself).
1507: * This code is a bit tricky because it allows for the
1508: * possibility of a virtual root window, which is identified
1509: * with a property named __SWM_VROOT.
1510: */
1511:
1512: virtualRootAtom = Tk_InternAtom((Tk_Window) winPtr, "__SWM_VROOT");
1513: wmPtr->flags &= ~WM_NESTED_REPARENT;
1514: wmPtr->reparent = None;
1515: root = eventPtr->xreparent.parent;
1516: while (root != RootWindow(winPtr->display, winPtr->screenNum)) {
1517: Tk_ErrorHandler handler1, handler2;
1518: int status;
1519:
1520: virtualRootPtr = NULL;
1521:
1522: handler1 =
1523: Tk_CreateErrorHandler(winPtr->display, BadDrawable,
1524: -1, -1, (Tk_ErrorProc *) NULL,
1525: (ClientData) NULL);
1526: handler2 =
1527: Tk_CreateErrorHandler(winPtr->display, BadWindow,
1528: -1, -1, (Tk_ErrorProc *) NULL,
1529: (ClientData) NULL);
1530:
1531: status = XGetWindowProperty(winPtr->display, root,
1532: virtualRootAtom,
1533: 0, (long) 1, False, XA_WINDOW,
1534: &actualType, &actualFormat,
1535: &numItems, &bytesAfter,
1536: (unsigned char **) &virtualRootPtr);
1537:
1538: Tk_DeleteErrorHandler(handler1);
1539: Tk_DeleteErrorHandler(handler2);
1540:
1541: if (status == Success) {
1542: if (virtualRootPtr != NULL) {
1543: if (*virtualRootPtr != root) {
1544: panic("TopLevelEventProc confused over virtual root");
1545: }
1546: XFree((char *) virtualRootPtr);
1547: break;
1548: }
1549: }
1550: wmPtr->reparent = root;
1551: (void) XQueryTree(winPtr->display, root, &dummy2, &root,
1552: &children, &dummy);
1553: XFree((char *) children);
1554: }
1555:
1556: /*
1557: * The ancestor just below the (virtual) root is in wmPtr->reparent
1558: * now, and the (virtual) root is in root.
1559: */
1560:
1561:
1562: if (eventPtr->xreparent.parent == root) {
1563: wmPtr->reparent = None;
1564: wmPtr->flags &= ~WM_NESTED_REPARENT;
1565: wmPtr->parentWidth = winPtr->changes.width
1566: + 2*winPtr->changes.border_width;
1567: wmPtr->parentHeight = winPtr->changes.height
1568: + 2*winPtr->changes.border_width;
1569: wmPtr->xInParent = wmPtr->yInParent = 0;
1570: winPtr->changes.x = eventPtr->xreparent.x;
1571: winPtr->changes.y = eventPtr->xreparent.y;
1572: } else {
1573: int x, y, xOffset, yOffset;
1574: unsigned int width, height, bd;
1575:
1576: if (wmPtr->reparent != eventPtr->xreparent.parent) {
1577: wmPtr->flags |= WM_NESTED_REPARENT;
1578: } else {
1579: wmPtr->flags &= ~WM_NESTED_REPARENT;
1580: }
1581:
1582: /*
1583: * Compute and save information about reparent and about
1584: * the window's position in reparent.
1585: */
1586:
1587: (void) XGetGeometry(winPtr->display, wmPtr->reparent,
1588: &dummy2, &x, &y, &width, &height, &bd, &dummy);
1589: wmPtr->parentWidth = width + 2*bd;
1590: wmPtr->parentHeight = height + 2*bd;
1591: (void) XTranslateCoordinates(winPtr->display, winPtr->window,
1592: wmPtr->reparent, 0, 0, &xOffset, &yOffset, &dummy2);
1593: wmPtr->xInParent = xOffset + bd - winPtr->changes.border_width;
1594: wmPtr->yInParent = yOffset + bd - winPtr->changes.border_width;
1595: winPtr->changes.x = x + xOffset;
1596: winPtr->changes.y = y + yOffset;
1597: }
1598: } else if ((eventPtr->type == EnterNotify)
1599: || (eventPtr->type == LeaveNotify)) {
1600: TkFocusEventProc(winPtr, eventPtr);
1601: }
1602: }
1603:
1604: /*
1605: *----------------------------------------------------------------------
1606: *
1607: * TopLevelReqProc --
1608: *
1609: * This procedure is invoked by the geometry manager whenever
1610: * the requested size for a top-level window is changed.
1611: *
1612: * Results:
1613: * None.
1614: *
1615: * Side effects:
1616: * Arrange for the window to be resized to satisfy the request
1617: * (this happens as a when-idle action).
1618: *
1619: *----------------------------------------------------------------------
1620: */
1621:
1622: /* ARGSUSED */
1623: static void
1624: TopLevelReqProc(dummy, tkwin)
1625: ClientData dummy; /* Not used. */
1626: Tk_Window tkwin; /* Information about window. */
1627: {
1628: TkWindow *winPtr = (TkWindow *) tkwin;
1629: WmInfo *wmPtr;
1630:
1631: wmPtr = winPtr->wmInfoPtr;
1632: if ((wmPtr->prevReqWidth == winPtr->reqWidth)
1633: && (wmPtr->prevReqHeight == winPtr->reqHeight)) {
1634: return;
1635: }
1636: wmPtr->prevReqWidth = winPtr->reqWidth;
1637: wmPtr->prevReqHeight = winPtr->reqHeight;
1638: wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1639: if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
1640: Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
1641: wmPtr->flags |= WM_UPDATE_PENDING;
1642: }
1643: }
1644:
1645: /*
1646: *----------------------------------------------------------------------
1647: *
1648: * UpdateGeometryInfo --
1649: *
1650: * This procedure is invoked when a top-level window is first
1651: * mapped, and also as a when-idle procedure, to bring the
1652: * geometry and/or position of a top-level window back into
1653: * line with what has been requested by the user and/or widgets.
1654: *
1655: * Results:
1656: * None.
1657: *
1658: * Side effects:
1659: * The window's size and location may change, unless the WM prevents
1660: * that from happening.
1661: *
1662: *----------------------------------------------------------------------
1663: */
1664:
1665: static void
1666: UpdateGeometryInfo(clientData)
1667: ClientData clientData; /* Pointer to the window's record. */
1668: {
1669: register TkWindow *winPtr = (TkWindow *) clientData;
1670: register WmInfo *wmPtr = winPtr->wmInfoPtr;
1671: int x, y, width, height;
1672:
1673: /*
1674: * It isn't safe to issue a new reconfigure request while there is
1675: * another reconfigure request outstanding. If this happens, skip
1676: * the second reconfigure operation but set a flag so it will get
1677: * done with the first one finishes.
1678: */
1679:
1680: wmPtr->flags &= ~WM_UPDATE_PENDING;
1681: if (wmPtr->flags & WM_CONFIG_PENDING) {
1682: wmPtr->flags |= WM_CONFIG_AGAIN;
1683: return;
1684: }
1685:
1686: /*
1687: * Compute the new size for the top-level window. See the
1688: * user documentation for details on this, but the size
1689: * requested depends on (a) the size requested internally
1690: * by the window's widgets, (b) the size requested by the
1691: * user in a "wm geometry" command or via wm-based interactive
1692: * resizing (if any), and (c) whether or not the window
1693: * gridded. Don't permit sizes <= 0 because this upsets
1694: * the X server.
1695: */
1696:
1697: if (wmPtr->width == -1) {
1698: width = winPtr->reqWidth;
1699: height = winPtr->reqHeight;
1700: } else if (IS_GRIDDED(wmPtr)) {
1701: width = winPtr->reqWidth
1702: + (wmPtr->width - wmPtr->reqGridWidth)*wmPtr->widthInc;
1703: height = winPtr->reqHeight
1704: + (wmPtr->height - wmPtr->reqGridHeight)*wmPtr->heightInc;
1705: } else {
1706: width = wmPtr->width;
1707: height = wmPtr->height;
1708: }
1709: if (width <= 0) {
1710: width = 1;
1711: }
1712: if (height <= 0) {
1713: height = 1;
1714: }
1715:
1716: /*
1717: * Compute the new position for the window. This is tricky, because
1718: * we need to include the border widths supplied by a reparented
1719: * parent in this calculation, but can't use the parent's current
1720: * overall size since that may change as a result of this code.
1721: */
1722:
1723: if (wmPtr->flags & WM_NEGATIVE_X) {
1724: x = DisplayWidth(winPtr->display, winPtr->screenNum) - wmPtr->x
1725: - (width + (wmPtr->parentWidth - winPtr->changes.width))
1726: + wmPtr->xInParent;
1727: } else {
1728: x = wmPtr->x + wmPtr->xInParent;
1729: }
1730: if (wmPtr->flags & WM_NEGATIVE_Y) {
1731: y = DisplayHeight(winPtr->display, winPtr->screenNum) - wmPtr->y
1732: - (height + (wmPtr->parentHeight - winPtr->changes.height))
1733: + wmPtr->yInParent;
1734: } else {
1735: y = wmPtr->y + wmPtr->yInParent;
1736: }
1737:
1738: /*
1739: * If the window's size is going to change and the window is
1740: * supposed to not be resizable by the user, then we have to
1741: * update the size hints. There may also be a size-hint-update
1742: * request pending from somewhere else, too.
1743: */
1744:
1745: if (((width != winPtr->changes.width) || (width != winPtr->changes.width))
1746: && !IS_GRIDDED(wmPtr)
1747: && ((wmPtr->sizeHintsFlags & (PMinSize|PMaxSize)) == 0)) {
1748: wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1749: }
1750: if (wmPtr->flags & WM_UPDATE_SIZE_HINTS) {
1751: UpdateSizeHints(winPtr);
1752: }
1753:
1754: /*
1755: * If the geometry hasn't changed, be careful to use only a
1756: * resize operation. This is because of bugs in some window
1757: * managers (e.g. twm, as of 4/24/91) where they don't interpret
1758: * coordinates according to ICCCM.
1759: */
1760:
1761: if ((x != winPtr->changes.x) || (y != winPtr->changes.y)) {
1762: wmPtr->configRequest = XNextRequest(winPtr->display);
1763: wmPtr->configWidth = width;
1764: wmPtr->configHeight = height;
1765: Tk_MoveResizeWindow((Tk_Window) winPtr, x, y, (unsigned) width,
1766: (unsigned) height);
1767: wmPtr->flags |= WM_CONFIG_PENDING;
1768: } else if ((width != wmPtr->configWidth)
1769: || (height != wmPtr->configHeight)) {
1770: wmPtr->configRequest = XNextRequest(winPtr->display);
1771: wmPtr->configWidth = width;
1772: wmPtr->configHeight = height;
1773: Tk_ResizeWindow((Tk_Window) winPtr, (unsigned) width,
1774: (unsigned) height);
1775: wmPtr->flags |= WM_CONFIG_PENDING;
1776: }
1777: }
1778:
1779: /*
1780: *--------------------------------------------------------------
1781: *
1782: * UpdateSizeHints --
1783: *
1784: * This procedure is called to update the window manager's
1785: * size hints information from the information in a WmInfo
1786: * structure.
1787: *
1788: * Results:
1789: * None.
1790: *
1791: * Side effects:
1792: * Properties get changed for winPtr.
1793: *
1794: *--------------------------------------------------------------
1795: */
1796:
1797: static void
1798: UpdateSizeHints(winPtr)
1799: TkWindow *winPtr;
1800: {
1801: register WmInfo *wmPtr = winPtr->wmInfoPtr;
1802: XSizeHints *hintsPtr;
1803:
1804: wmPtr->flags &= ~WM_UPDATE_SIZE_HINTS;
1805:
1806: #ifndef X11R3
1807: hintsPtr = XAllocSizeHints();
1808: if (hintsPtr == NULL) {
1809: return;
1810: }
1811:
1812: /*
1813: * Compute the pixel-based sizes for the various fields in the
1814: * size hints structure, based on the grid-based sizes in
1815: * our structure.
1816: */
1817:
1818: if (IS_GRIDDED(wmPtr)) {
1819: hintsPtr->base_width = winPtr->reqWidth
1820: - (wmPtr->reqGridWidth * wmPtr->widthInc);
1821: if (hintsPtr->base_width < 0) {
1822: hintsPtr->base_width = 0;
1823: }
1824: hintsPtr->base_height = winPtr->reqHeight
1825: - (wmPtr->reqGridHeight * wmPtr->heightInc);
1826: if (hintsPtr->base_height < 0) {
1827: hintsPtr->base_height = 0;
1828: }
1829: hintsPtr->min_width = hintsPtr->base_width
1830: + (wmPtr->minWidth * wmPtr->widthInc);
1831: hintsPtr->min_height = hintsPtr->base_height
1832: + (wmPtr->minHeight * wmPtr->heightInc);
1833: hintsPtr->max_width = hintsPtr->base_width
1834: + (wmPtr->maxWidth * wmPtr->widthInc);
1835: hintsPtr->max_height = hintsPtr->base_height
1836: + (wmPtr->maxHeight * wmPtr->heightInc);
1837: } else {
1838: hintsPtr->min_width = wmPtr->minWidth;
1839: hintsPtr->min_height = wmPtr->minHeight;
1840: hintsPtr->max_width = wmPtr->maxWidth;
1841: hintsPtr->max_height = wmPtr->maxHeight;
1842: hintsPtr->base_width = 0;
1843: hintsPtr->base_height = 0;
1844: }
1845: hintsPtr->width_inc = wmPtr->widthInc;
1846: hintsPtr->height_inc = wmPtr->heightInc;
1847: hintsPtr->min_aspect.x = wmPtr->minAspect.x;
1848: hintsPtr->min_aspect.y = wmPtr->minAspect.y;
1849: hintsPtr->max_aspect.x = wmPtr->maxAspect.x;
1850: hintsPtr->max_aspect.y = wmPtr->maxAspect.y;
1851: hintsPtr->win_gravity = wmPtr->gravity;
1852: hintsPtr->flags = wmPtr->sizeHintsFlags;
1853:
1854: /*
1855: * If a window is non-gridded and no minimum or maximum size has
1856: * been specified, don't let the window be resized at all.
1857: */
1858:
1859: if (!IS_GRIDDED(wmPtr)
1860: && ((wmPtr->sizeHintsFlags & (PMinSize|PMaxSize)) == 0)) {
1861: int width, height;
1862:
1863: width = wmPtr->width;
1864: height = wmPtr->height;
1865: if (width < 0) {
1866: width = winPtr->reqWidth;
1867: height = winPtr->reqHeight;
1868: }
1869: hintsPtr->min_width = hintsPtr->max_width = width;
1870: hintsPtr->min_height = hintsPtr->max_height = height;
1871: hintsPtr->flags |= PMinSize|PMaxSize;
1872: }
1873:
1874: /*
1875: * If min or max size isn't specified, fill in with extreme values
1876: * rather than leaving unspecified. Otherwise window manager may
1877: * do someting counter-intuitive like the last value ever specified.
1878: */
1879:
1880: if (!(hintsPtr->flags & PMinSize)) {
1881: hintsPtr->min_width = hintsPtr->min_height = 0;
1882: hintsPtr->flags |= PMinSize;
1883: }
1884: if (!(hintsPtr->flags & PMaxSize)) {
1885: hintsPtr->max_width = hintsPtr->max_height = 1000000;
1886: hintsPtr->flags |= PMaxSize;
1887: }
1888:
1889: XSetWMNormalHints(winPtr->display, winPtr->window, hintsPtr);
1890:
1891: XFree((char *) hintsPtr);
1892: #endif /* X11R3 */
1893: }
1894:
1895: /*
1896: *--------------------------------------------------------------
1897: *
1898: * UpdateHints --
1899: *
1900: * This procedure is called to update the window manager's
1901: * hints information from the information in a WmInfo
1902: * structure.
1903: *
1904: * Results:
1905: * None.
1906: *
1907: * Side effects:
1908: * Properties get changed for winPtr.
1909: *
1910: *--------------------------------------------------------------
1911: */
1912:
1913: static void
1914: UpdateHints(winPtr)
1915: TkWindow *winPtr;
1916: {
1917: WmInfo *wmPtr = winPtr->wmInfoPtr;
1918:
1919: if (wmPtr->flags & WM_NEVER_MAPPED) {
1920: return;
1921: }
1922: XSetWMHints(winPtr->display, winPtr->window, &wmPtr->hints);
1923: }
1924:
1925: /*
1926: *--------------------------------------------------------------
1927: *
1928: * ParseGeometry --
1929: *
1930: * This procedure parses a geometry string and updates
1931: * information used to control the geometry of a top-level
1932: * window.
1933: *
1934: * Results:
1935: * A standard Tcl return value, plus an error message in
1936: * interp->result if an error occurs.
1937: *
1938: * Side effects:
1939: * The size and/or location of winPtr may change.
1940: *
1941: *--------------------------------------------------------------
1942: */
1943:
1944: static int
1945: ParseGeometry(interp, string, winPtr)
1946: Tcl_Interp *interp; /* Used for error reporting. */
1947: char *string; /* String containing new geometry. Has the
1948: * standard form "=wxh+x+y". */
1949: TkWindow *winPtr; /* Pointer to top-level window whose
1950: * geometry is to be changed. */
1951: {
1952: register WmInfo *wmPtr = winPtr->wmInfoPtr;
1953: int x, y, width, height, flags;
1954: char *end;
1955: register char *p = string;
1956:
1957: /*
1958: * The leading "=" is optional.
1959: */
1960:
1961: if (*p == '=') {
1962: p++;
1963: }
1964:
1965: /*
1966: * Parse the width and height, if they are present. Don't
1967: * actually update any of the fields of wmPtr until we've
1968: * successfully parsed the entire geometry string.
1969: */
1970:
1971: width = wmPtr->width;
1972: height = wmPtr->height;
1973: x = wmPtr->x;
1974: y = wmPtr->y;
1975: flags = wmPtr->flags;
1976: if (isdigit(*p)) {
1977: width = strtoul(p, &end, 10);
1978: p = end;
1979: if (*p != 'x') {
1980: goto error;
1981: }
1982: p++;
1983: if (!isdigit(*p)) {
1984: goto error;
1985: }
1986: height = strtoul(p, &end, 10);
1987: p = end;
1988: }
1989:
1990: /*
1991: * Parse the X and Y coordinates, if they are present.
1992: */
1993:
1994: if (*p != '\0') {
1995: flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
1996: if (*p == '-') {
1997: flags |= WM_NEGATIVE_X;
1998: } else if (*p != '+') {
1999: goto error;
2000: }
2001: x = strtol(p+1, &end, 10);
2002: p = end;
2003: if (*p == '-') {
2004: flags |= WM_NEGATIVE_Y;
2005: } else if (*p != '+') {
2006: goto error;
2007: }
2008: y = strtol(p+1, &end, 10);
2009: if (*end != '\0') {
2010: goto error;
2011: }
2012:
2013: /*
2014: * Assume that the geometry information came from the user,
2015: * unless an explicit source has been specified. Otherwise
2016: * most window managers assume that the size hints were
2017: * program-specified and they ignore them.
2018: */
2019:
2020: if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
2021: wmPtr->sizeHintsFlags |= USPosition;
2022: wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
2023: }
2024: }
2025:
2026: /*
2027: * Everything was parsed OK. Update the fields of *wmPtr and
2028: * arrange for the appropriate information to be percolated out
2029: * to the window manager at the next idle moment.
2030: */
2031:
2032: wmPtr->width = width;
2033: wmPtr->height = height;
2034: wmPtr->x = x;
2035: wmPtr->y = y;
2036: wmPtr->flags = flags;
2037:
2038: if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
2039: Tk_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
2040: wmPtr->flags |= WM_UPDATE_PENDING;
2041: }
2042: return TCL_OK;
2043:
2044: error:
2045: Tcl_AppendResult(interp, "bad geometry specifier \"",
2046: string, "\"", (char *) NULL);
2047: return TCL_ERROR;
2048: }
2049:
2050: /*
2051: *----------------------------------------------------------------------
2052: *
2053: * Tk_GetRootCoords --
2054: *
2055: * Given a token for a window, this procedure traces through the
2056: * window's lineage to find the root-window coordinates corresponding
2057: * to point (0,0) in the window.
2058: *
2059: * Results:
2060: * The locations pointed to by xPtr and yPtr are filled in with
2061: * the root coordinates of the (0,0) point in tkwin.
2062: *
2063: * Side effects:
2064: * None.
2065: *
2066: *----------------------------------------------------------------------
2067: */
2068:
2069: void
2070: Tk_GetRootCoords(tkwin, xPtr, yPtr)
2071: Tk_Window tkwin; /* Token for window. */
2072: int *xPtr; /* Where to store x-displacement of (0,0). */
2073: int *yPtr; /* Where to store y-displacement of (0,0). */
2074: {
2075: int x, y;
2076: register TkWindow *winPtr = (TkWindow *) tkwin;
2077:
2078: /*
2079: * Search back through this window's parents all the way to a
2080: * top-level window, combining the offsets of each window within
2081: * its parent.
2082: */
2083:
2084: x = y = 0;
2085: while (1) {
2086: x += winPtr->changes.x + winPtr->changes.border_width;
2087: y += winPtr->changes.y + winPtr->changes.border_width;
2088: if (winPtr->flags & TK_TOP_LEVEL) {
2089: break;
2090: }
2091: winPtr = winPtr->parentPtr;
2092: }
2093: *xPtr = x;
2094: *yPtr = y;
2095: }
2096:
2097:
2098:
2099: /*
2100: *--------------------------------------------------------------
2101: *
2102: * TkWmSetWmProtocols --
2103: * Set the ICCCM WM_PROTOCOLS to be honored by this window.
2104: * Currently, it is just WM_DELETE_WINDOW.
2105: *
2106: * Results:
2107: * None.
2108: *
2109: * Side effects:
2110: * A window property may get updated.
2111: *
2112: *--------------------------------------------------------------
2113: */
2114:
2115: void
2116: TkWmSetWmProtocols(winPtr)
2117: TkWindow *winPtr; /* Newly-created top-level window. */
2118: {
2119: if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
2120: return;
2121: }
2122: #ifndef X11R3
2123: else {
2124: /* assemble the WM_PROTOCOLS that we honor */
2125: int count = 0;
2126: Atom atomlist[8];
2127: atomlist[count++] = Tk_InternAtom((Tk_Window) winPtr,
2128: "WM_DELETE_WINDOW");
2129: /*
2130: * other WM_PROTOCOLS go here -- e.g...
2131: * atomlist[count++] = Tk_InternAtom((Tk_Window) winPtr,
2132: * "WM_SAVE_YOURSELF");
2133: */
2134:
2135: /*
2136: * assign the honor list to the window not all X11R4's have
2137: * XSetWmProtocols() so use XChangeProperty()
2138: */
2139:
2140: /* XSetWmProtocols(winPtr->display, winPtr->window, atomlist, count); */
2141:
2142: XChangeProperty(winPtr->display,
2143: winPtr->window,
2144: Tk_InternAtom((Tk_Window) winPtr, "WM_PROTOCOLS"),
2145: XA_ATOM, 32,
2146: PropModeReplace,
2147: (unsigned char *)atomlist,
2148: count);
2149:
2150: }
2151: #endif
2152:
2153: return;
2154: }
2155:
2156:
2157: /*
2158: *----------------------------------------------------------------------
2159: *
2160: * TkWmProtocolEventProc --
2161: *
2162: * Handle a WM_PROTOCOL ICCCM event sent by the window manager to
2163: * top level window.
2164: *
2165: * The WM_PROTOCOL's currently handled are:
2166: *
2167: * WM_DELETE_PROTOCOL:
2168: *
2169: * Results: None
2170: *
2171: * Side effects:
2172: * for WM_DELETE_WINDOW:
2173: * - window may be deleted if specified earlier by a
2174: * wm tcl command
2175: * - a tcl command may be executed if sepcified earlier by a
2176: * wm tcl command
2177: *
2178: *
2179: */
2180: void
2181: TkWmProtocolEventProc(winPtr, eventPtr)
2182: TkWindow *winPtr;
2183: XEvent *eventPtr;
2184: {
2185: if ((Atom)(eventPtr->xclient.data.l)[0] ==
2186: Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW")) {
2187:
2188: WmInfo *wmPtr = winPtr->wmInfoPtr;
2189:
2190: if (wmPtr->deleteCmd) {
2191: if (*(wmPtr->deleteCmd) == '\0') {
2192: /* callback is empty, just delete the window */
2193: Tk_DestroyWindow((Tk_Window) winPtr);
2194: } else {
2195: /* there is a callback so run it */
2196: (void) Tcl_Eval(winPtr->mainPtr->interp,
2197: wmPtr->deleteCmd, 0, (char **)0);
2198: }
2199: } else {
2200: Tk_DestroyWindow((Tk_Window) winPtr);
2201: }
2202: }
2203: /*
2204: * else { .. other WM_<ETC> cases go here ... }
2205: */
2206: return;
2207: }
2208:
2209:
2210: /*
2211: *----------------------------------------------------------------------
2212: *
2213: * WmProtocolCmd
2214: *
2215: * implements
2216: *
2217: * wm protocol <window> delete [command_str]
2218: *
2219: * right now just delete is supported for OPTION
2220: *
2221: * Kind of artificial, But makes it easier to merge into new
2222: * versions of Stock Tk.
2223: */
2224: int
2225: WmProtocolCmd(interp, CmdPtr, argc, argv)
2226: Tcl_Interp *interp;
2227: char **CmdPtr;
2228: int argc;
2229: char **argv;
2230: {
2231: #define Cmd (*CmdPtr)
2232:
2233: switch(argc) {
2234: case 4:
2235: /*
2236: * return current command
2237: */
2238: if (!Cmd || *Cmd == '\0') {
2239: return TCL_OK;
2240: } else {
2241: /*
2242: * chop off the <blank><window_name>
2243: * and return just the cmd
2244: */
2245: int x = strlen(Cmd) - strlen(argv[2]) - 1;
2246: char tmpc = Cmd[x];
2247: Cmd[x] = '\0';
2248: {
2249: /* maybe should just have them put the window in the cmd */
2250: Tcl_AppendResult(interp, Cmd, (char *)NULL);
2251: }
2252: /*
2253: * tack the blank and window name back on
2254: */
2255: Cmd[x] = tmpc;
2256: return TCL_OK;
2257: }
2258: case 5:
2259: /*
2260: * (re)set command
2261: */
2262: if (Cmd) {
2263: ckfree(Cmd);
2264: Cmd = (char *)NULL;
2265: }
2266: if (*argv[4] != '\0') {
2267: int x = strlen(argv[4]) + strlen(argv[2]) + 2;
2268: if (!(Cmd = ckalloc(x))) {
2269: perror("wm protocol:");
2270: } else {
2271: sprintf(Cmd, "%s %s", argv[4], argv[2]);
2272: }
2273: }
2274: return TCL_OK;
2275: default:
2276: Tcl_AppendResult(interp, "wrong # of arguments: must be \"",
2277: argv[0], " protocol window <attribute> [cmd]\"", (char *) NULL);
2278: return TCL_ERROR;
2279: }
2280:
2281: #undef Cmd
2282: }
2283:
2284:
2285: /*
2286: *----------------------------------------------------------------------
2287: *
2288: * Tk_CoordsToWindow --
2289: *
2290: * Given the root coordinates of a point, this procedure
2291: * returns the token for the top-most window covering that point,
2292: * if there exists such a window in this application.
2293: *
2294: * Results:
2295: * The return result is either a token for the window corresponding
2296: * to rootX and rootY, or else NULL to indicate that there is no such
2297: * window.
2298: *
2299: * Side effects:
2300: * None.
2301: *
2302: *----------------------------------------------------------------------
2303: */
2304:
2305: Tk_Window
2306: Tk_CoordsToWindow(rootX, rootY, tkwin)
2307: int rootX, rootY; /* Coordinates of point in root window. */
2308: Tk_Window tkwin; /* Token for any window in application;
2309: * used to identify the application. */
2310: {
2311: Window rootChild, dummy3, dummy4;
2312: int i, dummy1, dummy2;
2313: register WmInfo *wmPtr;
2314: register TkWindow *winPtr, *childPtr;
2315: TkWindow *nextPtr; /* Coordinates of highest child found so
2316: * far that contains point. */
2317: int x, y; /* Coordinates in winPtr. */
2318: int tmpx, tmpy, bd;
2319: Window *children; /* Children of winPtr, or NULL. */
2320: unsigned int numChildren; /* Size of children array. */
2321:
2322: /*
2323: * Step 1: find the top-level window that contains the desired
2324: * coordinates.
2325: */
2326:
2327: if (XTranslateCoordinates(Tk_Display(tkwin),
2328: RootWindowOfScreen(Tk_Screen(tkwin)),
2329: RootWindowOfScreen(Tk_Screen(tkwin)), rootX, rootY, &dummy1,
2330: &dummy2, &rootChild) == False) {
2331: panic("Tk_CoordsToWindow get False return from XTranslateCoordinates");
2332: }
2333: for (wmPtr = firstWmPtr; ; wmPtr = wmPtr->nextPtr) {
2334: if (wmPtr == NULL) {
2335: return NULL;
2336: }
2337: if ((wmPtr->reparent == rootChild) || ((wmPtr->reparent == None)
2338: && (wmPtr->winPtr->window == rootChild))) {
2339: break;
2340: }
2341: }
2342: winPtr = wmPtr->winPtr;
2343: if (winPtr->mainPtr != ((TkWindow *) tkwin)->mainPtr) {
2344: return NULL;
2345: }
2346:
2347: /*
2348: * Step 2: work down through the hierarchy underneath this window.
2349: * At each level, scan through all the children to see if any contain
2350: * the point. If none do, then we're done. If one does, then do the
2351: * same thing on that child. If two or more do, then fetch enough
2352: * information from the window server to figure out which is on top,
2353: * and repeat on that child.
2354: */
2355:
2356: x = rootX;
2357: y = rootY;
2358: while (1) {
2359: x -= winPtr->changes.x;
2360: y -= winPtr->changes.y;
2361: nextPtr = NULL;
2362: children = NULL;
2363: for (childPtr = winPtr->childList; childPtr != NULL;
2364: childPtr = childPtr->nextPtr) {
2365: if (!Tk_IsMapped(childPtr) || (childPtr->flags & TK_TOP_LEVEL)) {
2366: continue;
2367: }
2368: tmpx = x - childPtr->changes.x;
2369: tmpy = y - childPtr->changes.y;
2370: bd = childPtr->changes.border_width;
2371: if ((tmpx < -bd) || (tmpy < -bd)
2372: || (tmpx >= (childPtr->changes.width + bd))
2373: || (tmpy >= (childPtr->changes.height + bd))) {
2374: continue;
2375: }
2376: if (nextPtr == NULL) {
2377: nextPtr = childPtr;
2378: continue;
2379: }
2380:
2381: /*
2382: * More than one child of same parent overlaps point. Must
2383: * figure out which is on top. Keep a cache of the stacking
2384: * order for winPtr to help with this, in case there are >2
2385: * children overlapping.
2386: */
2387:
2388: if (children == NULL) {
2389: if (XQueryTree(winPtr->display, winPtr->window, &dummy3,
2390: &dummy4, &children, &numChildren) == 0) {
2391: panic("Tk_CoordsToWindow get error return from XQueryTree");
2392: }
2393: }
2394: for (i = 0; i < numChildren; i++) {
2395: if (children[i] == childPtr->window) {
2396: break;
2397: }
2398: if (children[i] == nextPtr->window) {
2399: nextPtr = childPtr;
2400: break;
2401: }
2402: }
2403: }
2404: if (children != NULL) {
2405: XFree((char *) children);
2406: }
2407: if (nextPtr == NULL) {
2408: break;
2409: }
2410: winPtr = nextPtr;
2411: }
2412: return (Tk_Window) winPtr;
2413: }
2414:
2415:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.