Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libtk/unix/tkUnixWm.c
1811 views
1
/*
2
* tkUnixWm.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 (c) 1991-1994 The Regents of the University of California.
10
* Copyright (c) 1994-1996 Sun Microsystems, Inc.
11
*
12
* See the file "license.terms" for information on usage and redistribution
13
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14
*
15
* SCCS: @(#) tkUnixWm.c 1.124 96/03/29 14:05:44
16
*/
17
18
#include "tkInt.h"
19
#include <errno.h>
20
21
#ifndef WithdrawnState
22
#define WithdrawnState 0
23
#define Ancient 1
24
#endif
25
#ifndef PBaseSize
26
#define PBaseSize 0
27
#endif
28
29
/*
30
* A data structure of the following type holds information for
31
* each window manager protocol (such as WM_DELETE_WINDOW) for
32
* which a handler (i.e. a Tcl command) has been defined for a
33
* particular top-level window.
34
*/
35
36
typedef struct ProtocolHandler {
37
Atom protocol; /* Identifies the protocol. */
38
struct ProtocolHandler *nextPtr;
39
/* Next in list of protocol handlers for
40
* the same top-level window, or NULL for
41
* end of list. */
42
Tcl_Interp *interp; /* Interpreter in which to invoke command. */
43
char command[4]; /* Tcl command to invoke when a client
44
* message for this protocol arrives.
45
* The actual size of the structure varies
46
* to accommodate the needs of the actual
47
* command. THIS MUST BE THE LAST FIELD OF
48
* THE STRUCTURE. */
49
} ProtocolHandler;
50
51
#define HANDLER_SIZE(cmdLength) \
52
((unsigned) (sizeof(ProtocolHandler) - 3 + cmdLength))
53
54
/*
55
* A data structure of the following type holds window-manager-related
56
* information for each top-level window in an application.
57
*/
58
59
typedef struct TkWmInfo {
60
TkWindow *winPtr; /* Pointer to main Tk information for
61
* this window. */
62
Window reparent; /* If the window has been reparented, this
63
* gives the ID of the ancestor of the window
64
* that is a child of the root window (may
65
* not be window's immediate parent). If
66
* the window isn't reparented, this has the
67
* value None. */
68
Tk_Uid titleUid; /* Title to display in window caption. If
69
* NULL, use name of widget. */
70
Tk_Uid iconName; /* Name to display in icon. */
71
Window master; /* Master window for TRANSIENT_FOR property,
72
* or None. */
73
XWMHints hints; /* Various pieces of information for
74
* window manager. */
75
Tk_Uid leaderName; /* Path name of leader of window group
76
* (corresponds to hints.window_group).
77
* Note: this field doesn't get updated
78
* if leader is destroyed. */
79
Tk_Uid masterWindowName; /* Path name of window specified as master
80
* in "wm transient" command, or NULL.
81
* Note: this field doesn't get updated if
82
* masterWindowName is destroyed. */
83
Tk_Window icon; /* Window to use as icon for this window,
84
* or NULL. */
85
Tk_Window iconFor; /* Window for which this window is icon, or
86
* NULL if this isn't an icon for anyone. */
87
int withdrawn; /* Non-zero means window has been withdrawn. */
88
89
/*
90
* Information used to construct an XSizeHints structure for
91
* the window manager:
92
*/
93
94
int sizeHintsFlags; /* Flags word for XSizeHints structure.
95
* If the PBaseSize flag is set then the
96
* window is gridded; otherwise it isn't
97
* gridded. */
98
int minWidth, minHeight; /* Minimum dimensions of window, in
99
* grid units, not pixels. */
100
int maxWidth, maxHeight; /* Maximum dimensions of window, in
101
* grid units, not pixels. */
102
Tk_Window gridWin; /* Identifies the window that controls
103
* gridding for this top-level, or NULL if
104
* the top-level isn't currently gridded. */
105
int widthInc, heightInc; /* Increments for size changes (# pixels
106
* per step). */
107
struct {
108
int x; /* numerator */
109
int y; /* denominator */
110
} minAspect, maxAspect; /* Min/max aspect ratios for window. */
111
int reqGridWidth, reqGridHeight;
112
/* The dimensions of the window (in
113
* grid units) requested through
114
* the geometry manager. */
115
int gravity; /* Desired window gravity. */
116
117
/*
118
* Information used to manage the size and location of a window.
119
*/
120
121
int width, height; /* Desired dimensions of window, specified
122
* in grid units. These values are
123
* set by the "wm geometry" command and by
124
* ConfigureNotify events (for when wm
125
* resizes window). -1 means user hasn't
126
* requested dimensions. */
127
int x, y; /* Desired X and Y coordinates for window.
128
* These values are set by "wm geometry",
129
* plus by ConfigureNotify events (when wm
130
* moves window). These numbers are
131
* different than the numbers stored in
132
* winPtr->changes because (a) they could be
133
* measured from the right or bottom edge
134
* of the screen (see WM_NEGATIVE_X and
135
* WM_NEGATIVE_Y flags) and (b) if the window
136
* has been reparented then they refer to the
137
* parent rather than the window itself. */
138
int parentWidth, parentHeight;
139
/* Width and height of reparent, in pixels
140
* *including border*. If window hasn't been
141
* reparented then these will be the outer
142
* dimensions of the window, including
143
* border. */
144
int xInParent, yInParent; /* Offset of window within reparent, measured
145
* from upper-left outer corner of parent's
146
* border to upper-left outer corner of child's
147
* border. If not reparented then these are
148
* zero. */
149
int configWidth, configHeight;
150
/* Dimensions passed to last request that we
151
* issued to change geometry of window. Used
152
* to eliminate redundant resize operations. */
153
154
/*
155
* Information about the virtual root window for this top-level,
156
* if there is one.
157
*/
158
159
Window vRoot; /* Virtual root window for this top-level,
160
* or None if there is no virtual root
161
* window (i.e. just use the screen's root). */
162
int vRootX, vRootY; /* Position of the virtual root inside the
163
* root window. If the WM_VROOT_OFFSET_STALE
164
* flag is set then this information may be
165
* incorrect and needs to be refreshed from
166
* the X server. If vRoot is None then these
167
* values are both 0. */
168
int vRootWidth, vRootHeight;/* Dimensions of the virtual root window.
169
* If vRoot is None, gives the dimensions
170
* of the containing screen. This information
171
* is never stale, even though vRootX and
172
* vRootY can be. */
173
174
/*
175
* Miscellaneous information.
176
*/
177
178
ProtocolHandler *protPtr; /* First in list of protocol handlers for
179
* this window (NULL means none). */
180
int cmdArgc; /* Number of elements in cmdArgv below. */
181
char **cmdArgv; /* Array of strings to store in the
182
* WM_COMMAND property. NULL means nothing
183
* available. */
184
char *clientMachine; /* String to store in WM_CLIENT_MACHINE
185
* property, or NULL. */
186
int flags; /* Miscellaneous flags, defined below. */
187
struct TkWmInfo *nextPtr; /* Next in list of all top-level windows. */
188
} WmInfo;
189
190
/*
191
* Flag values for WmInfo structures:
192
*
193
* WM_NEVER_MAPPED - non-zero means window has never been
194
* mapped; need to update all info when
195
* window is first mapped.
196
* WM_UPDATE_PENDING - non-zero means a call to UpdateGeometryInfo
197
* has already been scheduled for this
198
* window; no need to schedule another one.
199
* WM_NEGATIVE_X - non-zero means x-coordinate is measured in
200
* pixels from right edge of screen, rather
201
* than from left edge.
202
* WM_NEGATIVE_Y - non-zero means y-coordinate is measured in
203
* pixels up from bottom of screen, rather than
204
* down from top.
205
* WM_UPDATE_SIZE_HINTS - non-zero means that new size hints need to be
206
* propagated to window manager.
207
* WM_SYNC_PENDING - set to non-zero while waiting for the window
208
* manager to respond to some state change.
209
* WM_VROOT_OFFSET_STALE - non-zero means that (x,y) offset information
210
* about the virtual root window is stale and
211
* needs to be fetched fresh from the X server.
212
* WM_ABOUT_TO_MAP - non-zero means that the window is about to
213
* be mapped by TkWmMapWindow. This is used
214
* by UpdateGeometryInfo to modify its behavior.
215
* WM_MOVE_PENDING - non-zero means the application has requested
216
* a new position for the window, but it hasn't
217
* been reflected through the window manager
218
* yet.
219
* WM_COLORMAPS_EXPLICIT - non-zero means the colormap windows were
220
* set explicitly via "wm colormapwindows".
221
* WM_ADDED_TOPLEVEL_COLORMAP - non-zero means that when "wm colormapwindows"
222
* was called the top-level itself wasn't
223
* specified, so we added it implicitly at
224
* the end of the list.
225
* WM_WIDTH_NOT_RESIZABLE - non-zero means that we're not supposed to
226
* allow the user to change the width of the
227
* window (controlled by "wm resizable"
228
* command).
229
* WM_HEIGHT_NOT_RESIZABLE - non-zero means that we're not supposed to
230
* allow the user to change the height of the
231
* window (controlled by "wm resizable"
232
* command).
233
*/
234
235
#define WM_NEVER_MAPPED 1
236
#define WM_UPDATE_PENDING 2
237
#define WM_NEGATIVE_X 4
238
#define WM_NEGATIVE_Y 8
239
#define WM_UPDATE_SIZE_HINTS 0x10
240
#define WM_SYNC_PENDING 0x20
241
#define WM_VROOT_OFFSET_STALE 0x40
242
#define WM_ABOUT_TO_MAP 0x100
243
#define WM_MOVE_PENDING 0x200
244
#define WM_COLORMAPS_EXPLICIT 0x400
245
#define WM_ADDED_TOPLEVEL_COLORMAP 0x800
246
#define WM_WIDTH_NOT_RESIZABLE 0x1000
247
#define WM_HEIGHT_NOT_RESIZABLE 0x2000
248
249
/*
250
* This module keeps a list of all top-level windows, primarily to
251
* simplify the job of Tk_CoordsToWindow.
252
*/
253
254
static WmInfo *firstWmPtr = NULL; /* Points to first top-level window. */
255
256
257
/*
258
* The variable below is used to enable or disable tracing in this
259
* module. If tracing is enabled, then information is printed on
260
* standard output about interesting interactions with the window
261
* manager.
262
*/
263
264
static int wmTracing = 0;
265
266
/*
267
* The following structure is the official type record for geometry
268
* management of top-level windows.
269
*/
270
271
static void TopLevelReqProc _ANSI_ARGS_((ClientData dummy,
272
Tk_Window tkwin));
273
274
static Tk_GeomMgr wmMgrType = {
275
"wm", /* name */
276
TopLevelReqProc, /* requestProc */
277
(Tk_GeomLostSlaveProc *) NULL, /* lostSlaveProc */
278
};
279
280
/*
281
* Structures of the following type are used for communication between
282
* WaitForEvent, WaitRestrictProc, and WaitTimeoutProc.
283
*/
284
285
typedef struct WaitRestrictInfo {
286
Display *display; /* Window belongs to this display. */
287
Window window; /* We're waiting for events on this window. */
288
int type; /* We only care about this type of event. */
289
XEvent *eventPtr; /* Where to store the event when it's found. */
290
int foundEvent; /* Non-zero means that an event of the
291
* desired type has been found. */
292
int timeout; /* Non-zero means that too much time elapsed
293
* while waiting, and we should just give
294
* up. */
295
} WaitRestrictInfo;
296
297
/*
298
* Forward declarations for procedures defined in this file:
299
*/
300
301
static int ComputeReparentGeometry _ANSI_ARGS_((TkWindow *winPtr));
302
static void ConfigureEvent _ANSI_ARGS_((TkWindow *winPtr,
303
XConfigureEvent *eventPtr));
304
static void GetMaxSize _ANSI_ARGS_((WmInfo *wmPtr,
305
int *maxWidthPtr, int *maxHeightPtr));
306
static int ParseGeometry _ANSI_ARGS_((Tcl_Interp *interp,
307
char *string, TkWindow *winPtr));
308
static void ReparentEvent _ANSI_ARGS_((TkWindow *winPtr,
309
XReparentEvent *eventPtr));
310
static void TopLevelEventProc _ANSI_ARGS_((ClientData clientData,
311
XEvent *eventPtr));
312
static void TopLevelReqProc _ANSI_ARGS_((ClientData dummy,
313
Tk_Window tkwin));
314
static void UpdateGeometryInfo _ANSI_ARGS_((
315
ClientData clientData));
316
static void UpdateHints _ANSI_ARGS_((TkWindow *winPtr));
317
static void UpdateSizeHints _ANSI_ARGS_((TkWindow *winPtr));
318
static void UpdateVRootGeometry _ANSI_ARGS_((WmInfo *wmPtr));
319
static void UpdateWmProtocols _ANSI_ARGS_((WmInfo *wmPtr));
320
static void WaitForConfigureNotify _ANSI_ARGS_((TkWindow *winPtr,
321
unsigned long serial));
322
static int WaitForEvent _ANSI_ARGS_((Display *display,
323
Window window, int type, XEvent *eventPtr));
324
static void WaitForMapNotify _ANSI_ARGS_((TkWindow *winPtr,
325
int mapped));
326
static Tk_RestrictAction
327
WaitRestrictProc _ANSI_ARGS_((ClientData clientData,
328
XEvent *eventPtr));
329
static void WaitTimeoutProc _ANSI_ARGS_((ClientData clientData));
330
331
/*
332
*--------------------------------------------------------------
333
*
334
* TkWmNewWindow --
335
*
336
* This procedure is invoked whenever a new top-level
337
* window is created. Its job is to initialize the WmInfo
338
* structure for the window.
339
*
340
* Results:
341
* None.
342
*
343
* Side effects:
344
* A WmInfo structure gets allocated and initialized.
345
*
346
*--------------------------------------------------------------
347
*/
348
349
void
350
TkWmNewWindow(winPtr)
351
TkWindow *winPtr; /* Newly-created top-level window. */
352
{
353
register WmInfo *wmPtr;
354
355
wmPtr = (WmInfo *) ckalloc(sizeof(WmInfo));
356
wmPtr->winPtr = winPtr;
357
wmPtr->reparent = None;
358
wmPtr->titleUid = NULL;
359
wmPtr->iconName = NULL;
360
wmPtr->master = None;
361
wmPtr->hints.flags = InputHint | StateHint;
362
wmPtr->hints.input = True;
363
wmPtr->hints.initial_state = NormalState;
364
wmPtr->hints.icon_pixmap = None;
365
wmPtr->hints.icon_window = None;
366
wmPtr->hints.icon_x = wmPtr->hints.icon_y = 0;
367
wmPtr->hints.icon_mask = None;
368
wmPtr->hints.window_group = None;
369
wmPtr->leaderName = NULL;
370
wmPtr->masterWindowName = NULL;
371
wmPtr->icon = NULL;
372
wmPtr->iconFor = NULL;
373
wmPtr->withdrawn = 0;
374
wmPtr->sizeHintsFlags = 0;
375
wmPtr->minWidth = wmPtr->minHeight = 1;
376
377
/*
378
* Default the maximum dimensions to the size of the display, minus
379
* a guess about how space is needed for window manager decorations.
380
*/
381
382
wmPtr->maxWidth = 0;
383
wmPtr->maxHeight = 0;
384
wmPtr->gridWin = NULL;
385
wmPtr->widthInc = wmPtr->heightInc = 1;
386
wmPtr->minAspect.x = wmPtr->minAspect.y = 1;
387
wmPtr->maxAspect.x = wmPtr->maxAspect.y = 1;
388
wmPtr->reqGridWidth = wmPtr->reqGridHeight = -1;
389
wmPtr->gravity = NorthWestGravity;
390
wmPtr->width = -1;
391
wmPtr->height = -1;
392
wmPtr->x = winPtr->changes.x;
393
wmPtr->y = winPtr->changes.y;
394
wmPtr->parentWidth = winPtr->changes.width
395
+ 2*winPtr->changes.border_width;
396
wmPtr->parentHeight = winPtr->changes.height
397
+ 2*winPtr->changes.border_width;
398
wmPtr->xInParent = wmPtr->yInParent = 0;
399
wmPtr->configWidth = -1;
400
wmPtr->configHeight = -1;
401
wmPtr->vRoot = None;
402
wmPtr->protPtr = NULL;
403
wmPtr->cmdArgv = NULL;
404
wmPtr->clientMachine = NULL;
405
wmPtr->flags = WM_NEVER_MAPPED;
406
wmPtr->nextPtr = firstWmPtr;
407
firstWmPtr = wmPtr;
408
winPtr->wmInfoPtr = wmPtr;
409
410
UpdateVRootGeometry(wmPtr);
411
412
/*
413
* Tk must monitor structure events for top-level windows, in order
414
* to detect size and position changes caused by window managers.
415
*/
416
417
Tk_CreateEventHandler((Tk_Window) winPtr, StructureNotifyMask,
418
TopLevelEventProc, (ClientData) winPtr);
419
420
/*
421
* Arrange for geometry requests to be reflected from the window
422
* to the window manager.
423
*/
424
425
Tk_ManageGeometry((Tk_Window) winPtr, &wmMgrType, (ClientData) 0);
426
}
427
428
/*
429
*--------------------------------------------------------------
430
*
431
* TkWmMapWindow --
432
*
433
* This procedure is invoked to map a top-level window. This
434
* module gets a chance to update all window-manager-related
435
* information in properties before the window manager sees
436
* the map event and checks the properties. It also gets to
437
* decide whether or not to even map the window after all.
438
*
439
* Results:
440
* None.
441
*
442
* Side effects:
443
* Properties of winPtr may get updated to provide up-to-date
444
* information to the window manager. The window may also get
445
* mapped, but it may not be if this procedure decides that
446
* isn't appropriate (e.g. because the window is withdrawn).
447
*
448
*--------------------------------------------------------------
449
*/
450
451
void
452
TkWmMapWindow(winPtr)
453
TkWindow *winPtr; /* Top-level window that's about to
454
* be mapped. */
455
{
456
register WmInfo *wmPtr = winPtr->wmInfoPtr;
457
#if !Ancient
458
XTextProperty textProp;
459
460
if (wmPtr->flags & WM_NEVER_MAPPED) {
461
wmPtr->flags &= ~WM_NEVER_MAPPED;
462
463
/*
464
* This is the first time this window has ever been mapped.
465
* Store all the window-manager-related information for the
466
* window.
467
*/
468
469
if (wmPtr->titleUid == NULL) {
470
wmPtr->titleUid = winPtr->nameUid;
471
}
472
if (XStringListToTextProperty(&wmPtr->titleUid, 1, &textProp) != 0) {
473
XSetWMName(winPtr->display, winPtr->window, &textProp);
474
XFree((char *) textProp.value);
475
}
476
477
TkWmSetClass(winPtr);
478
479
if (wmPtr->iconName != NULL) {
480
XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
481
}
482
483
if (wmPtr->master != None) {
484
XSetTransientForHint(winPtr->display, winPtr->window,
485
wmPtr->master);
486
}
487
488
wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
489
UpdateHints(winPtr);
490
UpdateWmProtocols(wmPtr);
491
if (wmPtr->cmdArgv != NULL) {
492
XSetCommand(winPtr->display, winPtr->window, wmPtr->cmdArgv,
493
wmPtr->cmdArgc);
494
}
495
if (wmPtr->clientMachine != NULL) {
496
if (XStringListToTextProperty(&wmPtr->clientMachine, 1, &textProp)
497
!= 0) {
498
XSetWMClientMachine(winPtr->display, winPtr->window,
499
&textProp);
500
XFree((char *) textProp.value);
501
}
502
}
503
}
504
#endif
505
if (wmPtr->hints.initial_state == WithdrawnState) {
506
return;
507
}
508
if (wmPtr->iconFor != NULL) {
509
/*
510
* This window is an icon for somebody else. Make sure that
511
* the geometry is up-to-date, then return without mapping
512
* the window.
513
*/
514
515
if (wmPtr->flags & WM_UPDATE_PENDING) {
516
Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
517
}
518
UpdateGeometryInfo((ClientData) winPtr);
519
return;
520
}
521
wmPtr->flags |= WM_ABOUT_TO_MAP;
522
if (wmPtr->flags & WM_UPDATE_PENDING) {
523
Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
524
}
525
UpdateGeometryInfo((ClientData) winPtr);
526
wmPtr->flags &= ~WM_ABOUT_TO_MAP;
527
528
/*
529
* Map the window, then wait to be sure that the window manager has
530
* processed the map operation.
531
*/
532
533
XMapWindow(winPtr->display, winPtr->window);
534
if (wmPtr->hints.initial_state == NormalState) {
535
WaitForMapNotify(winPtr, 1);
536
}
537
}
538
539
/*
540
*--------------------------------------------------------------
541
*
542
* TkWmUnmapWindow --
543
*
544
* This procedure is invoked to unmap a top-level window. The
545
* only thing it does special is to wait for the window actually
546
* to be unmapped.
547
*
548
* Results:
549
* None.
550
*
551
* Side effects:
552
* Unmaps the window.
553
*
554
*--------------------------------------------------------------
555
*/
556
557
void
558
TkWmUnmapWindow(winPtr)
559
TkWindow *winPtr; /* Top-level window that's about to
560
* be mapped. */
561
{
562
/*
563
* It seems to be important to wait after unmapping a top-level
564
* window until the window really gets unmapped. I don't completely
565
* understand all the interactions with the window manager, but if
566
* we go on without waiting, and if the window is then mapped again
567
* quickly, events seem to get lost so that we think the window isn't
568
* mapped when in fact it is mapped. I suspect that this has something
569
* to do with the window manager filtering Map events (and possily not
570
* filtering Unmap events?).
571
*/
572
XUnmapWindow(winPtr->display, winPtr->window);
573
WaitForMapNotify(winPtr, 0);
574
}
575
576
/*
577
*--------------------------------------------------------------
578
*
579
* TkWmDeadWindow --
580
*
581
* This procedure is invoked when a top-level window is
582
* about to be deleted. It cleans up the wm-related data
583
* structures for the window.
584
*
585
* Results:
586
* None.
587
*
588
* Side effects:
589
* The WmInfo structure for winPtr gets freed up.
590
*
591
*--------------------------------------------------------------
592
*/
593
594
void
595
TkWmDeadWindow(winPtr)
596
TkWindow *winPtr; /* Top-level window that's being deleted. */
597
{
598
register WmInfo *wmPtr = winPtr->wmInfoPtr;
599
WmInfo *wmPtr2;
600
601
if (wmPtr == NULL) {
602
return;
603
}
604
if (firstWmPtr == wmPtr) {
605
firstWmPtr = wmPtr->nextPtr;
606
} else {
607
register WmInfo *prevPtr;
608
609
for (prevPtr = firstWmPtr; ; prevPtr = prevPtr->nextPtr) {
610
if (prevPtr == NULL) {
611
panic("couldn't unlink window in TkWmDeadWindow");
612
}
613
if (prevPtr->nextPtr == wmPtr) {
614
prevPtr->nextPtr = wmPtr->nextPtr;
615
break;
616
}
617
}
618
}
619
if (wmPtr->hints.flags & IconPixmapHint) {
620
Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
621
}
622
if (wmPtr->hints.flags & IconMaskHint) {
623
Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
624
}
625
if (wmPtr->icon != NULL) {
626
wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
627
wmPtr2->iconFor = NULL;
628
wmPtr2->withdrawn = 1;
629
}
630
if (wmPtr->iconFor != NULL) {
631
wmPtr2 = ((TkWindow *) wmPtr->iconFor)->wmInfoPtr;
632
wmPtr2->icon = NULL;
633
wmPtr2->hints.flags &= ~IconWindowHint;
634
UpdateHints((TkWindow *) wmPtr->iconFor);
635
}
636
while (wmPtr->protPtr != NULL) {
637
ProtocolHandler *protPtr;
638
639
protPtr = wmPtr->protPtr;
640
wmPtr->protPtr = protPtr->nextPtr;
641
Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
642
}
643
if (wmPtr->cmdArgv != NULL) {
644
ckfree((char *) wmPtr->cmdArgv);
645
}
646
if (wmPtr->clientMachine != NULL) {
647
ckfree((char *) wmPtr->clientMachine);
648
}
649
if (wmPtr->flags & WM_UPDATE_PENDING) {
650
Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
651
}
652
ckfree((char *) wmPtr);
653
winPtr->wmInfoPtr = NULL;
654
}
655
656
/*
657
*--------------------------------------------------------------
658
*
659
* TkWmSetClass --
660
*
661
* This procedure is invoked whenever a top-level window's
662
* class is changed. If the window has been mapped then this
663
* procedure updates the window manager property for the
664
* class. If the window hasn't been mapped, the update is
665
* deferred until just before the first mapping.
666
*
667
* Results:
668
* None.
669
*
670
* Side effects:
671
* A window property may get updated.
672
*
673
*--------------------------------------------------------------
674
*/
675
676
void
677
TkWmSetClass(winPtr)
678
TkWindow *winPtr; /* Newly-created top-level window. */
679
{
680
if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
681
return;
682
}
683
684
if (winPtr->classUid != NULL) {
685
XClassHint *classPtr;
686
687
classPtr = XAllocClassHint();
688
classPtr->res_name = winPtr->nameUid;
689
classPtr->res_class = winPtr->classUid;
690
XSetClassHint(winPtr->display, winPtr->window, classPtr);
691
XFree((char *) classPtr);
692
}
693
}
694
695
/*
696
*----------------------------------------------------------------------
697
*
698
* Tk_WmCmd --
699
*
700
* This procedure is invoked to process the "wm" Tcl command.
701
* See the user documentation for details on what it does.
702
*
703
* Results:
704
* A standard Tcl result.
705
*
706
* Side effects:
707
* See the user documentation.
708
*
709
*----------------------------------------------------------------------
710
*/
711
712
/* ARGSUSED */
713
int
714
Tk_WmCmd(clientData, interp, argc, argv)
715
ClientData clientData; /* Main window associated with
716
* interpreter. */
717
Tcl_Interp *interp; /* Current interpreter. */
718
int argc; /* Number of arguments. */
719
char **argv; /* Argument strings. */
720
{
721
Tk_Window tkwin = (Tk_Window) clientData;
722
TkWindow *winPtr;
723
register WmInfo *wmPtr;
724
int c;
725
size_t length;
726
727
if (argc < 2) {
728
wrongNumArgs:
729
Tcl_AppendResult(interp, "wrong # args: should be \"",
730
argv[0], " option window ?arg ...?\"", (char *) NULL);
731
return TCL_ERROR;
732
}
733
c = argv[1][0];
734
length = strlen(argv[1]);
735
if ((c == 't') && (strncmp(argv[1], "tracing", length) == 0)
736
&& (length >= 3)) {
737
if ((argc != 2) && (argc != 3)) {
738
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
739
argv[0], " tracing ?boolean?\"", (char *) NULL);
740
return TCL_ERROR;
741
}
742
if (argc == 2) {
743
interp->result = (wmTracing) ? "on" : "off";
744
return TCL_OK;
745
}
746
return Tcl_GetBoolean(interp, argv[2], &wmTracing);
747
}
748
749
if (argc < 3) {
750
goto wrongNumArgs;
751
}
752
winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
753
if (winPtr == NULL) {
754
return TCL_ERROR;
755
}
756
if (!(winPtr->flags & TK_TOP_LEVEL)) {
757
Tcl_AppendResult(interp, "window \"", winPtr->pathName,
758
"\" isn't a top-level window", (char *) NULL);
759
return TCL_ERROR;
760
}
761
wmPtr = winPtr->wmInfoPtr;
762
if ((c == 'a') && (strncmp(argv[1], "aspect", length) == 0)) {
763
int numer1, denom1, numer2, denom2;
764
765
if ((argc != 3) && (argc != 7)) {
766
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
767
argv[0], " aspect window ?minNumer minDenom ",
768
"maxNumer maxDenom?\"", (char *) NULL);
769
return TCL_ERROR;
770
}
771
if (argc == 3) {
772
if (wmPtr->sizeHintsFlags & PAspect) {
773
sprintf(interp->result, "%d %d %d %d", wmPtr->minAspect.x,
774
wmPtr->minAspect.y, wmPtr->maxAspect.x,
775
wmPtr->maxAspect.y);
776
}
777
return TCL_OK;
778
}
779
if (*argv[3] == '\0') {
780
wmPtr->sizeHintsFlags &= ~PAspect;
781
} else {
782
if ((Tcl_GetInt(interp, argv[3], &numer1) != TCL_OK)
783
|| (Tcl_GetInt(interp, argv[4], &denom1) != TCL_OK)
784
|| (Tcl_GetInt(interp, argv[5], &numer2) != TCL_OK)
785
|| (Tcl_GetInt(interp, argv[6], &denom2) != TCL_OK)) {
786
return TCL_ERROR;
787
}
788
if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) ||
789
(denom2 <= 0)) {
790
interp->result = "aspect number can't be <= 0";
791
return TCL_ERROR;
792
}
793
wmPtr->minAspect.x = numer1;
794
wmPtr->minAspect.y = denom1;
795
wmPtr->maxAspect.x = numer2;
796
wmPtr->maxAspect.y = denom2;
797
wmPtr->sizeHintsFlags |= PAspect;
798
}
799
wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
800
goto updateGeom;
801
} else if ((c == 'c') && (strncmp(argv[1], "client", length) == 0)
802
&& (length >= 2)) {
803
if ((argc != 3) && (argc != 4)) {
804
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
805
argv[0], " client window ?name?\"",
806
(char *) NULL);
807
return TCL_ERROR;
808
}
809
if (argc == 3) {
810
if (wmPtr->clientMachine != NULL) {
811
interp->result = wmPtr->clientMachine;
812
}
813
return TCL_OK;
814
}
815
if (argv[3][0] == 0) {
816
if (wmPtr->clientMachine != NULL) {
817
ckfree((char *) wmPtr->clientMachine);
818
wmPtr->clientMachine = NULL;
819
if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
820
XDeleteProperty(winPtr->display, winPtr->window,
821
Tk_InternAtom((Tk_Window) winPtr,
822
"WM_CLIENT_MACHINE"));
823
}
824
}
825
return TCL_OK;
826
}
827
if (wmPtr->clientMachine != NULL) {
828
ckfree((char *) wmPtr->clientMachine);
829
}
830
wmPtr->clientMachine = (char *)
831
ckalloc((unsigned) (strlen(argv[3]) + 1));
832
strcpy(wmPtr->clientMachine, argv[3]);
833
#if !Ancient
834
if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
835
XTextProperty textProp;
836
if (XStringListToTextProperty(&wmPtr->clientMachine, 1, &textProp)
837
!= 0) {
838
XSetWMClientMachine(winPtr->display, winPtr->window,
839
&textProp);
840
XFree((char *) textProp.value);
841
}
842
}
843
#endif
844
} else if ((c == 'c') && (strncmp(argv[1], "colormapwindows", length) == 0)
845
&& (length >= 3)) {
846
Window *cmapList;
847
TkWindow *winPtr2;
848
int count, i, windowArgc, gotToplevel;
849
char buffer[20], **windowArgv;
850
851
if ((argc != 3) && (argc != 4)) {
852
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
853
argv[0], " colormapwindows window ?windowList?\"",
854
(char *) NULL);
855
return TCL_ERROR;
856
}
857
if (argc == 3) {
858
Tk_MakeWindowExist((Tk_Window) winPtr);
859
if (XGetWMColormapWindows(winPtr->display, winPtr->window,
860
&cmapList, &count) == 0) {
861
return TCL_OK;
862
}
863
for (i = 0; i < count; i++) {
864
if ((i == (count-1))
865
&& (wmPtr->flags & WM_ADDED_TOPLEVEL_COLORMAP)) {
866
break;
867
}
868
winPtr2 = (TkWindow *) Tk_IdToWindow(winPtr->display,
869
cmapList[i]);
870
if (winPtr2 == NULL) {
871
sprintf(buffer, "0x%lx", cmapList[i]);
872
Tcl_AppendElement(interp, buffer);
873
} else {
874
Tcl_AppendElement(interp, winPtr2->pathName);
875
}
876
}
877
XFree((char *) cmapList);
878
return TCL_OK;
879
}
880
if (Tcl_SplitList(interp, argv[3], &windowArgc, &windowArgv)
881
!= TCL_OK) {
882
return TCL_ERROR;
883
}
884
cmapList = (Window *) ckalloc((unsigned)
885
((windowArgc+1)*sizeof(Window)));
886
gotToplevel = 0;
887
for (i = 0; i < windowArgc; i++) {
888
winPtr2 = (TkWindow *) Tk_NameToWindow(interp, windowArgv[i],
889
tkwin);
890
if (winPtr2 == NULL) {
891
ckfree((char *) cmapList);
892
ckfree((char *) windowArgv);
893
return TCL_ERROR;
894
}
895
if (winPtr2 == winPtr) {
896
gotToplevel = 1;
897
}
898
if (winPtr2->window == None) {
899
Tk_MakeWindowExist((Tk_Window) winPtr2);
900
}
901
cmapList[i] = winPtr2->window;
902
}
903
if (!gotToplevel) {
904
wmPtr->flags |= WM_ADDED_TOPLEVEL_COLORMAP;
905
cmapList[windowArgc] = winPtr->window;
906
windowArgc++;
907
} else {
908
wmPtr->flags &= ~WM_ADDED_TOPLEVEL_COLORMAP;
909
}
910
wmPtr->flags |= WM_COLORMAPS_EXPLICIT;
911
XSetWMColormapWindows(winPtr->display, winPtr->window, cmapList,
912
windowArgc);
913
ckfree((char *) cmapList);
914
ckfree((char *) windowArgv);
915
return TCL_OK;
916
} else if ((c == 'c') && (strncmp(argv[1], "command", length) == 0)
917
&& (length >= 3)) {
918
int cmdArgc;
919
char **cmdArgv;
920
921
if ((argc != 3) && (argc != 4)) {
922
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
923
argv[0], " command window ?value?\"",
924
(char *) NULL);
925
return TCL_ERROR;
926
}
927
if (argc == 3) {
928
if (wmPtr->cmdArgv != NULL) {
929
interp->result = Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv);
930
interp->freeProc = TCL_DYNAMIC;
931
}
932
return TCL_OK;
933
}
934
if (argv[3][0] == 0) {
935
if (wmPtr->cmdArgv != NULL) {
936
ckfree((char *) wmPtr->cmdArgv);
937
wmPtr->cmdArgv = NULL;
938
if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
939
XDeleteProperty(winPtr->display, winPtr->window,
940
Tk_InternAtom((Tk_Window) winPtr, "WM_COMMAND"));
941
}
942
}
943
return TCL_OK;
944
}
945
if (Tcl_SplitList(interp, argv[3], &cmdArgc, &cmdArgv) != TCL_OK) {
946
return TCL_ERROR;
947
}
948
if (wmPtr->cmdArgv != NULL) {
949
ckfree((char *) wmPtr->cmdArgv);
950
}
951
wmPtr->cmdArgc = cmdArgc;
952
wmPtr->cmdArgv = cmdArgv;
953
if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
954
XSetCommand(winPtr->display, winPtr->window, cmdArgv, cmdArgc);
955
}
956
} else if ((c == 'd') && (strncmp(argv[1], "deiconify", length) == 0)) {
957
if (argc != 3) {
958
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
959
argv[0], " deiconify window\"", (char *) NULL);
960
return TCL_ERROR;
961
}
962
if (wmPtr->iconFor != NULL) {
963
Tcl_AppendResult(interp, "can't deiconify ", argv[2],
964
": it is an icon for ", winPtr->pathName, (char *) NULL);
965
return TCL_ERROR;
966
}
967
wmPtr->hints.initial_state = NormalState;
968
wmPtr->withdrawn = 0;
969
if (wmPtr->flags & WM_NEVER_MAPPED) {
970
return TCL_OK;
971
}
972
UpdateHints(winPtr);
973
Tk_MapWindow((Tk_Window) winPtr);
974
} else if ((c == 'f') && (strncmp(argv[1], "focusmodel", length) == 0)
975
&& (length >= 2)) {
976
if ((argc != 3) && (argc != 4)) {
977
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
978
argv[0], " focusmodel window ?active|passive?\"",
979
(char *) NULL);
980
return TCL_ERROR;
981
}
982
if (argc == 3) {
983
interp->result = wmPtr->hints.input ? "passive" : "active";
984
return TCL_OK;
985
}
986
c = argv[3][0];
987
length = strlen(argv[3]);
988
if ((c == 'a') && (strncmp(argv[3], "active", length) == 0)) {
989
wmPtr->hints.input = False;
990
} else if ((c == 'p') && (strncmp(argv[3], "passive", length) == 0)) {
991
wmPtr->hints.input = True;
992
} else {
993
Tcl_AppendResult(interp, "bad argument \"", argv[3],
994
"\": must be active or passive", (char *) NULL);
995
return TCL_ERROR;
996
}
997
UpdateHints(winPtr);
998
} else if ((c == 'f') && (strncmp(argv[1], "frame", length) == 0)
999
&& (length >= 2)) {
1000
Window window;
1001
1002
if (argc != 3) {
1003
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1004
argv[0], " frame window\"", (char *) NULL);
1005
return TCL_ERROR;
1006
}
1007
window = wmPtr->reparent;
1008
if (window == None) {
1009
window = Tk_WindowId((Tk_Window) winPtr);
1010
}
1011
sprintf(interp->result, "0x%x", (unsigned int) window);
1012
} else if ((c == 'g') && (strncmp(argv[1], "geometry", length) == 0)
1013
&& (length >= 2)) {
1014
char xSign, ySign;
1015
int width, height;
1016
1017
if ((argc != 3) && (argc != 4)) {
1018
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1019
argv[0], " geometry window ?newGeometry?\"",
1020
(char *) NULL);
1021
return TCL_ERROR;
1022
}
1023
if (argc == 3) {
1024
xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+';
1025
ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+';
1026
if (wmPtr->gridWin != NULL) {
1027
width = wmPtr->reqGridWidth + (winPtr->changes.width
1028
- winPtr->reqWidth)/wmPtr->widthInc;
1029
height = wmPtr->reqGridHeight + (winPtr->changes.height
1030
- winPtr->reqHeight)/wmPtr->heightInc;
1031
} else {
1032
width = winPtr->changes.width;
1033
height = winPtr->changes.height;
1034
}
1035
sprintf(interp->result, "%dx%d%c%d%c%d", width, height,
1036
xSign, wmPtr->x, ySign, wmPtr->y);
1037
return TCL_OK;
1038
}
1039
if (*argv[3] == '\0') {
1040
wmPtr->width = -1;
1041
wmPtr->height = -1;
1042
goto updateGeom;
1043
}
1044
return ParseGeometry(interp, argv[3], winPtr);
1045
} else if ((c == 'g') && (strncmp(argv[1], "grid", length) == 0)
1046
&& (length >= 3)) {
1047
int reqWidth, reqHeight, widthInc, heightInc;
1048
1049
if ((argc != 3) && (argc != 7)) {
1050
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1051
argv[0], " grid window ?baseWidth baseHeight ",
1052
"widthInc heightInc?\"", (char *) NULL);
1053
return TCL_ERROR;
1054
}
1055
if (argc == 3) {
1056
if (wmPtr->sizeHintsFlags & PBaseSize) {
1057
sprintf(interp->result, "%d %d %d %d", wmPtr->reqGridWidth,
1058
wmPtr->reqGridHeight, wmPtr->widthInc,
1059
wmPtr->heightInc);
1060
}
1061
return TCL_OK;
1062
}
1063
if (*argv[3] == '\0') {
1064
/*
1065
* Turn off gridding and reset the width and height
1066
* to make sense as ungridded numbers.
1067
*/
1068
1069
wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
1070
if (wmPtr->width != -1) {
1071
wmPtr->width = winPtr->reqWidth + (wmPtr->width
1072
- wmPtr->reqGridWidth)*wmPtr->widthInc;
1073
wmPtr->height = winPtr->reqHeight + (wmPtr->height
1074
- wmPtr->reqGridHeight)*wmPtr->heightInc;
1075
}
1076
wmPtr->widthInc = 1;
1077
wmPtr->heightInc = 1;
1078
} else {
1079
if ((Tcl_GetInt(interp, argv[3], &reqWidth) != TCL_OK)
1080
|| (Tcl_GetInt(interp, argv[4], &reqHeight) != TCL_OK)
1081
|| (Tcl_GetInt(interp, argv[5], &widthInc) != TCL_OK)
1082
|| (Tcl_GetInt(interp, argv[6], &heightInc) != TCL_OK)) {
1083
return TCL_ERROR;
1084
}
1085
if (reqWidth < 0) {
1086
interp->result = "baseWidth can't be < 0";
1087
return TCL_ERROR;
1088
}
1089
if (reqHeight < 0) {
1090
interp->result = "baseHeight can't be < 0";
1091
return TCL_ERROR;
1092
}
1093
if (widthInc < 0) {
1094
interp->result = "widthInc can't be < 0";
1095
return TCL_ERROR;
1096
}
1097
if (heightInc < 0) {
1098
interp->result = "heightInc can't be < 0";
1099
return TCL_ERROR;
1100
}
1101
Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc,
1102
heightInc);
1103
}
1104
wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1105
goto updateGeom;
1106
} else if ((c == 'g') && (strncmp(argv[1], "group", length) == 0)
1107
&& (length >= 3)) {
1108
Tk_Window tkwin2;
1109
1110
if ((argc != 3) && (argc != 4)) {
1111
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1112
argv[0], " group window ?pathName?\"",
1113
(char *) NULL);
1114
return TCL_ERROR;
1115
}
1116
if (argc == 3) {
1117
if (wmPtr->hints.flags & WindowGroupHint) {
1118
interp->result = wmPtr->leaderName;
1119
}
1120
return TCL_OK;
1121
}
1122
if (*argv[3] == '\0') {
1123
wmPtr->hints.flags &= ~WindowGroupHint;
1124
wmPtr->leaderName = NULL;
1125
} else {
1126
tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
1127
if (tkwin2 == NULL) {
1128
return TCL_ERROR;
1129
}
1130
Tk_MakeWindowExist(tkwin2);
1131
wmPtr->hints.window_group = Tk_WindowId(tkwin2);
1132
wmPtr->hints.flags |= WindowGroupHint;
1133
wmPtr->leaderName = Tk_PathName(tkwin2);
1134
}
1135
UpdateHints(winPtr);
1136
} else if ((c == 'i') && (strncmp(argv[1], "iconbitmap", length) == 0)
1137
&& (length >= 5)) {
1138
Pixmap pixmap;
1139
1140
if ((argc != 3) && (argc != 4)) {
1141
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1142
argv[0], " iconbitmap window ?bitmap?\"",
1143
(char *) NULL);
1144
return TCL_ERROR;
1145
}
1146
if (argc == 3) {
1147
if (wmPtr->hints.flags & IconPixmapHint) {
1148
interp->result = Tk_NameOfBitmap(winPtr->display,
1149
wmPtr->hints.icon_pixmap);
1150
}
1151
return TCL_OK;
1152
}
1153
if (*argv[3] == '\0') {
1154
if (wmPtr->hints.icon_pixmap != None) {
1155
Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
1156
wmPtr->hints.icon_pixmap = None;
1157
}
1158
wmPtr->hints.flags &= ~IconPixmapHint;
1159
} else {
1160
pixmap = Tk_GetBitmap(interp, (Tk_Window) winPtr,
1161
Tk_GetUid(argv[3]));
1162
if (pixmap == None) {
1163
return TCL_ERROR;
1164
}
1165
wmPtr->hints.icon_pixmap = pixmap;
1166
wmPtr->hints.flags |= IconPixmapHint;
1167
}
1168
UpdateHints(winPtr);
1169
} else if ((c == 'i') && (strncmp(argv[1], "iconify", length) == 0)
1170
&& (length >= 5)) {
1171
if (argc != 3) {
1172
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1173
argv[0], " iconify window\"", (char *) NULL);
1174
return TCL_ERROR;
1175
}
1176
if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
1177
Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
1178
"\": override-redirect flag is set", (char *) NULL);
1179
return TCL_ERROR;
1180
}
1181
if (wmPtr->master != None) {
1182
Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
1183
"\": it is a transient", (char *) NULL);
1184
return TCL_ERROR;
1185
}
1186
if (wmPtr->iconFor != NULL) {
1187
Tcl_AppendResult(interp, "can't iconify ", argv[2],
1188
": it is an icon for ", winPtr->pathName, (char *) NULL);
1189
return TCL_ERROR;
1190
}
1191
wmPtr->hints.initial_state = IconicState;
1192
if (wmPtr->flags & WM_NEVER_MAPPED) {
1193
return TCL_OK;
1194
}
1195
if (wmPtr->withdrawn) {
1196
UpdateHints(winPtr);
1197
Tk_MapWindow((Tk_Window) winPtr);
1198
wmPtr->withdrawn = 0;
1199
} else {
1200
if (XIconifyWindow(winPtr->display, winPtr->window,
1201
winPtr->screenNum) == 0) {
1202
interp->result =
1203
"couldn't send iconify message to window manager";
1204
return TCL_ERROR;
1205
}
1206
WaitForMapNotify(winPtr, 0);
1207
}
1208
} else if ((c == 'i') && (strncmp(argv[1], "iconmask", length) == 0)
1209
&& (length >= 5)) {
1210
Pixmap pixmap;
1211
1212
if ((argc != 3) && (argc != 4)) {
1213
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1214
argv[0], " iconmask window ?bitmap?\"",
1215
(char *) NULL);
1216
return TCL_ERROR;
1217
}
1218
if (argc == 3) {
1219
if (wmPtr->hints.flags & IconMaskHint) {
1220
interp->result = Tk_NameOfBitmap(winPtr->display,
1221
wmPtr->hints.icon_mask);
1222
}
1223
return TCL_OK;
1224
}
1225
if (*argv[3] == '\0') {
1226
if (wmPtr->hints.icon_mask != None) {
1227
Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
1228
}
1229
wmPtr->hints.flags &= ~IconMaskHint;
1230
} else {
1231
pixmap = Tk_GetBitmap(interp, tkwin, Tk_GetUid(argv[3]));
1232
if (pixmap == None) {
1233
return TCL_ERROR;
1234
}
1235
wmPtr->hints.icon_mask = pixmap;
1236
wmPtr->hints.flags |= IconMaskHint;
1237
}
1238
UpdateHints(winPtr);
1239
} else if ((c == 'i') && (strncmp(argv[1], "iconname", length) == 0)
1240
&& (length >= 5)) {
1241
if (argc > 4) {
1242
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1243
argv[0], " iconname window ?newName?\"", (char *) NULL);
1244
return TCL_ERROR;
1245
}
1246
if (argc == 3) {
1247
interp->result = (wmPtr->iconName != NULL) ? wmPtr->iconName : "";
1248
return TCL_OK;
1249
} else {
1250
wmPtr->iconName = Tk_GetUid(argv[3]);
1251
if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
1252
XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
1253
}
1254
}
1255
} else if ((c == 'i') && (strncmp(argv[1], "iconposition", length) == 0)
1256
&& (length >= 5)) {
1257
int x, y;
1258
1259
if ((argc != 3) && (argc != 5)) {
1260
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1261
argv[0], " iconposition window ?x y?\"",
1262
(char *) NULL);
1263
return TCL_ERROR;
1264
}
1265
if (argc == 3) {
1266
if (wmPtr->hints.flags & IconPositionHint) {
1267
sprintf(interp->result, "%d %d", wmPtr->hints.icon_x,
1268
wmPtr->hints.icon_y);
1269
}
1270
return TCL_OK;
1271
}
1272
if (*argv[3] == '\0') {
1273
wmPtr->hints.flags &= ~IconPositionHint;
1274
} else {
1275
if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK)
1276
|| (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)){
1277
return TCL_ERROR;
1278
}
1279
wmPtr->hints.icon_x = x;
1280
wmPtr->hints.icon_y = y;
1281
wmPtr->hints.flags |= IconPositionHint;
1282
}
1283
UpdateHints(winPtr);
1284
} else if ((c == 'i') && (strncmp(argv[1], "iconwindow", length) == 0)
1285
&& (length >= 5)) {
1286
Tk_Window tkwin2;
1287
WmInfo *wmPtr2;
1288
XSetWindowAttributes atts;
1289
1290
if ((argc != 3) && (argc != 4)) {
1291
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1292
argv[0], " iconwindow window ?pathName?\"",
1293
(char *) NULL);
1294
return TCL_ERROR;
1295
}
1296
if (argc == 3) {
1297
if (wmPtr->icon != NULL) {
1298
interp->result = Tk_PathName(wmPtr->icon);
1299
}
1300
return TCL_OK;
1301
}
1302
if (*argv[3] == '\0') {
1303
wmPtr->hints.flags &= ~IconWindowHint;
1304
if (wmPtr->icon != NULL) {
1305
/*
1306
* Remove the icon window relationship. In principle we
1307
* should also re-enable button events for the window, but
1308
* this doesn't work in general because the window manager
1309
* is probably selecting on them (we'll get an error if
1310
* we try to re-enable the events). So, just leave the
1311
* icon window event-challenged; the user will have to
1312
* recreate it if they want button events.
1313
*/
1314
1315
wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
1316
wmPtr2->iconFor = NULL;
1317
wmPtr2->withdrawn = 1;
1318
wmPtr2->hints.initial_state = WithdrawnState;
1319
}
1320
wmPtr->icon = NULL;
1321
} else {
1322
tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
1323
if (tkwin2 == NULL) {
1324
return TCL_ERROR;
1325
}
1326
if (!Tk_IsTopLevel(tkwin2)) {
1327
Tcl_AppendResult(interp, "can't use ", argv[3],
1328
" as icon window: not at top level", (char *) NULL);
1329
return TCL_ERROR;
1330
}
1331
wmPtr2 = ((TkWindow *) tkwin2)->wmInfoPtr;
1332
if (wmPtr2->iconFor != NULL) {
1333
Tcl_AppendResult(interp, argv[3], " is already an icon for ",
1334
Tk_PathName(wmPtr2->iconFor), (char *) NULL);
1335
return TCL_ERROR;
1336
}
1337
if (wmPtr->icon != NULL) {
1338
WmInfo *wmPtr3 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
1339
wmPtr3->iconFor = NULL;
1340
wmPtr3->withdrawn = 1;
1341
1342
/*
1343
* Let the window use button events again.
1344
*/
1345
1346
atts.event_mask = Tk_Attributes(wmPtr->icon)->event_mask
1347
| ButtonPressMask;
1348
Tk_ChangeWindowAttributes(wmPtr->icon, CWEventMask, &atts);
1349
}
1350
1351
/*
1352
* Disable button events in the icon window: some window
1353
* managers (like olvwm) want to get the events themselves,
1354
* but X only allows one application at a time to receive
1355
* button events for a window.
1356
*/
1357
1358
atts.event_mask = Tk_Attributes(tkwin2)->event_mask
1359
& ~ButtonPressMask;
1360
Tk_ChangeWindowAttributes(tkwin2, CWEventMask, &atts);
1361
Tk_MakeWindowExist(tkwin2);
1362
wmPtr->hints.icon_window = Tk_WindowId(tkwin2);
1363
wmPtr->hints.flags |= IconWindowHint;
1364
wmPtr->icon = tkwin2;
1365
wmPtr2->iconFor = (Tk_Window) winPtr;
1366
if (!wmPtr2->withdrawn && !(wmPtr2->flags & WM_NEVER_MAPPED)) {
1367
wmPtr2->withdrawn = 0;
1368
if (XWithdrawWindow(Tk_Display(tkwin2), Tk_WindowId(tkwin2),
1369
Tk_ScreenNumber(tkwin2)) == 0) {
1370
interp->result =
1371
"couldn't send withdraw message to window manager";
1372
return TCL_ERROR;
1373
}
1374
WaitForMapNotify((TkWindow *) tkwin2, 0);
1375
}
1376
}
1377
UpdateHints(winPtr);
1378
} else if ((c == 'm') && (strncmp(argv[1], "maxsize", length) == 0)
1379
&& (length >= 2)) {
1380
int width, height;
1381
if ((argc != 3) && (argc != 5)) {
1382
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1383
argv[0], " maxsize window ?width height?\"", (char *) NULL);
1384
return TCL_ERROR;
1385
}
1386
if (argc == 3) {
1387
GetMaxSize(wmPtr, &width, &height);
1388
sprintf(interp->result, "%d %d", width, height);
1389
return TCL_OK;
1390
}
1391
if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
1392
|| (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
1393
return TCL_ERROR;
1394
}
1395
wmPtr->maxWidth = width;
1396
wmPtr->maxHeight = height;
1397
wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1398
goto updateGeom;
1399
} else if ((c == 'm') && (strncmp(argv[1], "minsize", length) == 0)
1400
&& (length >= 2)) {
1401
int width, height;
1402
if ((argc != 3) && (argc != 5)) {
1403
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1404
argv[0], " minsize window ?width height?\"", (char *) NULL);
1405
return TCL_ERROR;
1406
}
1407
if (argc == 3) {
1408
sprintf(interp->result, "%d %d", wmPtr->minWidth,
1409
wmPtr->minHeight);
1410
return TCL_OK;
1411
}
1412
if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
1413
|| (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
1414
return TCL_ERROR;
1415
}
1416
wmPtr->minWidth = width;
1417
wmPtr->minHeight = height;
1418
wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1419
goto updateGeom;
1420
} else if ((c == 'o')
1421
&& (strncmp(argv[1], "overrideredirect", length) == 0)) {
1422
int boolean;
1423
XSetWindowAttributes atts;
1424
1425
if ((argc != 3) && (argc != 4)) {
1426
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1427
argv[0], " overrideredirect window ?boolean?\"",
1428
(char *) NULL);
1429
return TCL_ERROR;
1430
}
1431
if (argc == 3) {
1432
if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
1433
interp->result = "1";
1434
} else {
1435
interp->result = "0";
1436
}
1437
return TCL_OK;
1438
}
1439
if (Tcl_GetBoolean(interp, argv[3], &boolean) != TCL_OK) {
1440
return TCL_ERROR;
1441
}
1442
atts.override_redirect = (boolean) ? True : False;
1443
Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect,
1444
&atts);
1445
} else if ((c == 'p') && (strncmp(argv[1], "positionfrom", length) == 0)
1446
&& (length >= 2)) {
1447
if ((argc != 3) && (argc != 4)) {
1448
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1449
argv[0], " positionfrom window ?user/program?\"",
1450
(char *) NULL);
1451
return TCL_ERROR;
1452
}
1453
if (argc == 3) {
1454
if (wmPtr->sizeHintsFlags & USPosition) {
1455
interp->result = "user";
1456
} else if (wmPtr->sizeHintsFlags & PPosition) {
1457
interp->result = "program";
1458
}
1459
return TCL_OK;
1460
}
1461
if (*argv[3] == '\0') {
1462
wmPtr->sizeHintsFlags &= ~(USPosition|PPosition);
1463
} else {
1464
c = argv[3][0];
1465
length = strlen(argv[3]);
1466
if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
1467
wmPtr->sizeHintsFlags &= ~PPosition;
1468
wmPtr->sizeHintsFlags |= USPosition;
1469
} else if ((c == 'p') && (strncmp(argv[3], "program", length) == 0)) {
1470
wmPtr->sizeHintsFlags &= ~USPosition;
1471
wmPtr->sizeHintsFlags |= PPosition;
1472
} else {
1473
Tcl_AppendResult(interp, "bad argument \"", argv[3],
1474
"\": must be program or user", (char *) NULL);
1475
return TCL_ERROR;
1476
}
1477
}
1478
wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1479
goto updateGeom;
1480
} else if ((c == 'p') && (strncmp(argv[1], "protocol", length) == 0)
1481
&& (length >= 2)) {
1482
register ProtocolHandler *protPtr, *prevPtr;
1483
Atom protocol;
1484
int cmdLength;
1485
1486
if ((argc < 3) || (argc > 5)) {
1487
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1488
argv[0], " protocol window ?name? ?command?\"",
1489
(char *) NULL);
1490
return TCL_ERROR;
1491
}
1492
if (argc == 3) {
1493
/*
1494
* Return a list of all defined protocols for the window.
1495
*/
1496
for (protPtr = wmPtr->protPtr; protPtr != NULL;
1497
protPtr = protPtr->nextPtr) {
1498
Tcl_AppendElement(interp,
1499
Tk_GetAtomName((Tk_Window) winPtr, protPtr->protocol));
1500
}
1501
return TCL_OK;
1502
}
1503
protocol = Tk_InternAtom((Tk_Window) winPtr, argv[3]);
1504
if (argc == 4) {
1505
/*
1506
* Return the command to handle a given protocol.
1507
*/
1508
for (protPtr = wmPtr->protPtr; protPtr != NULL;
1509
protPtr = protPtr->nextPtr) {
1510
if (protPtr->protocol == protocol) {
1511
interp->result = protPtr->command;
1512
return TCL_OK;
1513
}
1514
}
1515
return TCL_OK;
1516
}
1517
1518
/*
1519
* Delete any current protocol handler, then create a new
1520
* one with the specified command, unless the command is
1521
* empty.
1522
*/
1523
1524
for (protPtr = wmPtr->protPtr, prevPtr = NULL; protPtr != NULL;
1525
prevPtr = protPtr, protPtr = protPtr->nextPtr) {
1526
if (protPtr->protocol == protocol) {
1527
if (prevPtr == NULL) {
1528
wmPtr->protPtr = protPtr->nextPtr;
1529
} else {
1530
prevPtr->nextPtr = protPtr->nextPtr;
1531
}
1532
Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
1533
break;
1534
}
1535
}
1536
cmdLength = strlen(argv[4]);
1537
if (cmdLength > 0) {
1538
protPtr = (ProtocolHandler *) ckalloc(HANDLER_SIZE(cmdLength));
1539
protPtr->protocol = protocol;
1540
protPtr->nextPtr = wmPtr->protPtr;
1541
wmPtr->protPtr = protPtr;
1542
protPtr->interp = interp;
1543
strcpy(protPtr->command, argv[4]);
1544
}
1545
if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
1546
UpdateWmProtocols(wmPtr);
1547
}
1548
} else if ((c == 'r') && (strncmp(argv[1], "resizable", length) == 0)) {
1549
int width, height;
1550
1551
if ((argc != 3) && (argc != 5)) {
1552
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1553
argv[0], " resizable window ?width height?\"",
1554
(char *) NULL);
1555
return TCL_ERROR;
1556
}
1557
if (argc == 3) {
1558
sprintf(interp->result, "%d %d",
1559
(wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) ? 0 : 1,
1560
(wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) ? 0 : 1);
1561
return TCL_OK;
1562
}
1563
if ((Tcl_GetBoolean(interp, argv[3], &width) != TCL_OK)
1564
|| (Tcl_GetBoolean(interp, argv[4], &height) != TCL_OK)) {
1565
return TCL_ERROR;
1566
}
1567
if (width) {
1568
wmPtr->flags &= ~WM_WIDTH_NOT_RESIZABLE;
1569
} else {
1570
wmPtr->flags |= WM_WIDTH_NOT_RESIZABLE;
1571
}
1572
if (height) {
1573
wmPtr->flags &= ~WM_HEIGHT_NOT_RESIZABLE;
1574
} else {
1575
wmPtr->flags |= WM_HEIGHT_NOT_RESIZABLE;
1576
}
1577
wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1578
goto updateGeom;
1579
} else if ((c == 's') && (strncmp(argv[1], "sizefrom", length) == 0)
1580
&& (length >= 2)) {
1581
if ((argc != 3) && (argc != 4)) {
1582
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1583
argv[0], " sizefrom window ?user|program?\"",
1584
(char *) NULL);
1585
return TCL_ERROR;
1586
}
1587
if (argc == 3) {
1588
if (wmPtr->sizeHintsFlags & USSize) {
1589
interp->result = "user";
1590
} else if (wmPtr->sizeHintsFlags & PSize) {
1591
interp->result = "program";
1592
}
1593
return TCL_OK;
1594
}
1595
if (*argv[3] == '\0') {
1596
wmPtr->sizeHintsFlags &= ~(USSize|PSize);
1597
} else {
1598
c = argv[3][0];
1599
length = strlen(argv[3]);
1600
if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
1601
wmPtr->sizeHintsFlags &= ~PSize;
1602
wmPtr->sizeHintsFlags |= USSize;
1603
} else if ((c == 'p')
1604
&& (strncmp(argv[3], "program", length) == 0)) {
1605
wmPtr->sizeHintsFlags &= ~USSize;
1606
wmPtr->sizeHintsFlags |= PSize;
1607
} else {
1608
Tcl_AppendResult(interp, "bad argument \"", argv[3],
1609
"\": must be program or user", (char *) NULL);
1610
return TCL_ERROR;
1611
}
1612
}
1613
wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1614
goto updateGeom;
1615
} else if ((c == 's') && (strncmp(argv[1], "state", length) == 0)
1616
&& (length >= 2)) {
1617
if (argc != 3) {
1618
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1619
argv[0], " state window\"", (char *) NULL);
1620
return TCL_ERROR;
1621
}
1622
if (wmPtr->iconFor != NULL) {
1623
interp->result = "icon";
1624
} else if (wmPtr->withdrawn) {
1625
interp->result = "withdrawn";
1626
} else if (Tk_IsMapped((Tk_Window) winPtr)
1627
|| ((wmPtr->flags & WM_NEVER_MAPPED)
1628
&& (wmPtr->hints.initial_state == NormalState))) {
1629
interp->result = "normal";
1630
} else {
1631
interp->result = "iconic";
1632
}
1633
} else if ((c == 't') && (strncmp(argv[1], "title", length) == 0)
1634
&& (length >= 2)) {
1635
if (argc > 4) {
1636
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1637
argv[0], " title window ?newTitle?\"", (char *) NULL);
1638
return TCL_ERROR;
1639
}
1640
if (argc == 3) {
1641
interp->result = (wmPtr->titleUid != NULL) ? wmPtr->titleUid
1642
: winPtr->nameUid;
1643
return TCL_OK;
1644
} else {
1645
wmPtr->titleUid = Tk_GetUid(argv[3]);
1646
#if !Ancient
1647
if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
1648
XTextProperty textProp;
1649
1650
if (XStringListToTextProperty(&wmPtr->titleUid, 1,
1651
&textProp) != 0) {
1652
XSetWMName(winPtr->display, winPtr->window, &textProp);
1653
XFree((char *) textProp.value);
1654
}
1655
}
1656
#endif
1657
}
1658
} else if ((c == 't') && (strncmp(argv[1], "transient", length) == 0)
1659
&& (length >= 3)) {
1660
Tk_Window master;
1661
1662
if ((argc != 3) && (argc != 4)) {
1663
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1664
argv[0], " transient window ?master?\"", (char *) NULL);
1665
return TCL_ERROR;
1666
}
1667
if (argc == 3) {
1668
if (wmPtr->master != None) {
1669
interp->result = wmPtr->masterWindowName;
1670
}
1671
return TCL_OK;
1672
}
1673
if (argv[3][0] == '\0') {
1674
wmPtr->master = None;
1675
wmPtr->masterWindowName = NULL;
1676
} else {
1677
master = Tk_NameToWindow(interp, argv[3], tkwin);
1678
if (master == NULL) {
1679
return TCL_ERROR;
1680
}
1681
Tk_MakeWindowExist(master);
1682
wmPtr->master = Tk_WindowId(master);
1683
wmPtr->masterWindowName = Tk_PathName(master);
1684
}
1685
if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
1686
XSetTransientForHint(winPtr->display, winPtr->window,
1687
wmPtr->master);
1688
}
1689
} else if ((c == 'w') && (strncmp(argv[1], "withdraw", length) == 0)) {
1690
if (argc != 3) {
1691
Tcl_AppendResult(interp, "wrong # arguments: must be \"",
1692
argv[0], " withdraw window\"", (char *) NULL);
1693
return TCL_ERROR;
1694
}
1695
if (wmPtr->iconFor != NULL) {
1696
Tcl_AppendResult(interp, "can't withdraw ", argv[2],
1697
": it is an icon for ", Tk_PathName(wmPtr->iconFor),
1698
(char *) NULL);
1699
return TCL_ERROR;
1700
}
1701
wmPtr->hints.initial_state = WithdrawnState;
1702
wmPtr->withdrawn = 1;
1703
if (wmPtr->flags & WM_NEVER_MAPPED) {
1704
return TCL_OK;
1705
}
1706
if (XWithdrawWindow(winPtr->display, winPtr->window,
1707
winPtr->screenNum) == 0) {
1708
interp->result =
1709
"couldn't send withdraw message to window manager";
1710
return TCL_ERROR;
1711
}
1712
WaitForMapNotify(winPtr, 0);
1713
} else {
1714
Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],
1715
"\": must be aspect, client, command, deiconify, ",
1716
"focusmodel, frame, geometry, grid, group, iconbitmap, ",
1717
"iconify, iconmask, iconname, iconposition, ",
1718
"iconwindow, maxsize, minsize, overrideredirect, ",
1719
"positionfrom, protocol, resizable, sizefrom, state, title, ",
1720
"transient, or withdraw",
1721
(char *) NULL);
1722
return TCL_ERROR;
1723
}
1724
return TCL_OK;
1725
1726
updateGeom:
1727
if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
1728
Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
1729
wmPtr->flags |= WM_UPDATE_PENDING;
1730
}
1731
return TCL_OK;
1732
}
1733
1734
/*
1735
*----------------------------------------------------------------------
1736
*
1737
* Tk_SetGrid --
1738
*
1739
* This procedure is invoked by a widget when it wishes to set a grid
1740
* coordinate system that controls the size of a top-level window.
1741
* It provides a C interface equivalent to the "wm grid" command and
1742
* is usually asscoiated with the -setgrid option.
1743
*
1744
* Results:
1745
* None.
1746
*
1747
* Side effects:
1748
* Grid-related information will be passed to the window manager, so
1749
* that the top-level window associated with tkwin will resize on
1750
* even grid units. If some other window already controls gridding
1751
* for the top-level window then this procedure call has no effect.
1752
*
1753
*----------------------------------------------------------------------
1754
*/
1755
1756
void
1757
Tk_SetGrid(tkwin, reqWidth, reqHeight, widthInc, heightInc)
1758
Tk_Window tkwin; /* Token for window. New window mgr info
1759
* will be posted for the top-level window
1760
* associated with this window. */
1761
int reqWidth; /* Width (in grid units) corresponding to
1762
* the requested geometry for tkwin. */
1763
int reqHeight; /* Height (in grid units) corresponding to
1764
* the requested geometry for tkwin. */
1765
int widthInc, heightInc; /* Pixel increments corresponding to a
1766
* change of one grid unit. */
1767
{
1768
TkWindow *winPtr = (TkWindow *) tkwin;
1769
register WmInfo *wmPtr;
1770
1771
/*
1772
* Find the top-level window for tkwin, plus the window manager
1773
* information.
1774
*/
1775
1776
while (!(winPtr->flags & TK_TOP_LEVEL)) {
1777
winPtr = winPtr->parentPtr;
1778
if (winPtr == NULL) {
1779
/*
1780
* The window is being deleted... just skip this operation.
1781
*/
1782
1783
return;
1784
}
1785
}
1786
wmPtr = winPtr->wmInfoPtr;
1787
1788
if ((wmPtr->gridWin != NULL) && (wmPtr->gridWin != tkwin)) {
1789
return;
1790
}
1791
1792
if ((wmPtr->reqGridWidth == reqWidth)
1793
&& (wmPtr->reqGridHeight == reqHeight)
1794
&& (wmPtr->widthInc == widthInc)
1795
&& (wmPtr->heightInc == heightInc)
1796
&& ((wmPtr->sizeHintsFlags & (PBaseSize|PResizeInc))
1797
== PBaseSize|PResizeInc)) {
1798
return;
1799
}
1800
1801
/*
1802
* If gridding was previously off, then forget about any window
1803
* size requests made by the user or via "wm geometry": these are
1804
* in pixel units and there's no easy way to translate them to
1805
* grid units since the new requested size of the top-level window in
1806
* pixels may not yet have been registered yet (it may filter up
1807
* the hierarchy in DoWhenIdle handlers). However, if the window
1808
* has never been mapped yet then just leave the window size alone:
1809
* assume that it is intended to be in grid units but just happened
1810
* to have been specified before this procedure was called.
1811
*/
1812
1813
if ((wmPtr->gridWin == NULL) && !(wmPtr->flags & WM_NEVER_MAPPED)) {
1814
wmPtr->width = -1;
1815
wmPtr->height = -1;
1816
}
1817
1818
/*
1819
* Set the new gridding information, and start the process of passing
1820
* all of this information to the window manager.
1821
*/
1822
1823
wmPtr->gridWin = tkwin;
1824
wmPtr->reqGridWidth = reqWidth;
1825
wmPtr->reqGridHeight = reqHeight;
1826
wmPtr->widthInc = widthInc;
1827
wmPtr->heightInc = heightInc;
1828
wmPtr->sizeHintsFlags |= PBaseSize|PResizeInc;
1829
wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1830
if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
1831
Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
1832
wmPtr->flags |= WM_UPDATE_PENDING;
1833
}
1834
}
1835
1836
/*
1837
*----------------------------------------------------------------------
1838
*
1839
* Tk_UnsetGrid --
1840
*
1841
* This procedure cancels the effect of a previous call
1842
* to Tk_SetGrid.
1843
*
1844
* Results:
1845
* None.
1846
*
1847
* Side effects:
1848
* If tkwin currently controls gridding for its top-level window,
1849
* gridding is cancelled for that top-level window; if some other
1850
* window controls gridding then this procedure has no effect.
1851
*
1852
*----------------------------------------------------------------------
1853
*/
1854
1855
void
1856
Tk_UnsetGrid(tkwin)
1857
Tk_Window tkwin; /* Token for window that is currently
1858
* controlling gridding. */
1859
{
1860
TkWindow *winPtr = (TkWindow *) tkwin;
1861
register WmInfo *wmPtr;
1862
1863
/*
1864
* Find the top-level window for tkwin, plus the window manager
1865
* information.
1866
*/
1867
1868
while (!(winPtr->flags & TK_TOP_LEVEL)) {
1869
winPtr = winPtr->parentPtr;
1870
if (winPtr == NULL) {
1871
/*
1872
* The window is being deleted... just skip this operation.
1873
*/
1874
1875
return;
1876
}
1877
}
1878
wmPtr = winPtr->wmInfoPtr;
1879
if (tkwin != wmPtr->gridWin) {
1880
return;
1881
}
1882
1883
wmPtr->gridWin = NULL;
1884
wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
1885
if (wmPtr->width != -1) {
1886
wmPtr->width = winPtr->reqWidth + (wmPtr->width
1887
- wmPtr->reqGridWidth)*wmPtr->widthInc;
1888
wmPtr->height = winPtr->reqHeight + (wmPtr->height
1889
- wmPtr->reqGridHeight)*wmPtr->heightInc;
1890
}
1891
wmPtr->widthInc = 1;
1892
wmPtr->heightInc = 1;
1893
1894
wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
1895
if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
1896
Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
1897
wmPtr->flags |= WM_UPDATE_PENDING;
1898
}
1899
}
1900
1901
/*
1902
*----------------------------------------------------------------------
1903
*
1904
* ConfigureEvent --
1905
*
1906
* This procedure is called to handle ConfigureNotify events on
1907
* top-level windows.
1908
*
1909
* Results:
1910
* None.
1911
*
1912
* Side effects:
1913
* Information gets updated in the WmInfo structure for the window.
1914
*
1915
*----------------------------------------------------------------------
1916
*/
1917
1918
static void
1919
ConfigureEvent(winPtr, configEventPtr)
1920
TkWindow *winPtr; /* Top-level window. */
1921
XConfigureEvent *configEventPtr; /* Event that just occurred for
1922
* winPtr. */
1923
{
1924
register WmInfo *wmPtr = winPtr->wmInfoPtr;
1925
1926
/*
1927
* Update size information from the event. There are a couple of
1928
* tricky points here:
1929
*
1930
* 1. If the user changed the size externally then set wmPtr->width
1931
* and wmPtr->height just as if a "wm geometry" command had been
1932
* invoked with the same information.
1933
* 2. However, if the size is changing in response to a request
1934
* coming from us (WM_SYNC_PENDING is set), then don't set wmPtr->width
1935
* or wmPtr->height if they were previously -1 (otherwise the
1936
* window will stop tracking geometry manager requests).
1937
*/
1938
1939
if (((winPtr->changes.width != configEventPtr->width)
1940
|| (winPtr->changes.height != configEventPtr->height))
1941
&& !(wmPtr->flags & WM_SYNC_PENDING)){
1942
if (wmTracing) {
1943
printf("TopLevelEventProc: user changed %s size to %dx%d\n",
1944
winPtr->pathName, configEventPtr->width,
1945
configEventPtr->height);
1946
}
1947
if ((wmPtr->width == -1)
1948
&& (configEventPtr->width == winPtr->reqWidth)) {
1949
/*
1950
* Don't set external width, since the user didn't change it
1951
* from what the widgets asked for.
1952
*/
1953
} else {
1954
if (wmPtr->gridWin != NULL) {
1955
wmPtr->width = wmPtr->reqGridWidth
1956
+ (configEventPtr->width
1957
- winPtr->reqWidth)/wmPtr->widthInc;
1958
if (wmPtr->width < 0) {
1959
wmPtr->width = 0;
1960
}
1961
} else {
1962
wmPtr->width = configEventPtr->width;
1963
}
1964
}
1965
if ((wmPtr->height == -1)
1966
&& (configEventPtr->height == winPtr->reqHeight)) {
1967
/*
1968
* Don't set external height, since the user didn't change it
1969
* from what the widgets asked for.
1970
*/
1971
} else {
1972
if (wmPtr->gridWin != NULL) {
1973
wmPtr->height = wmPtr->reqGridHeight
1974
+ (configEventPtr->height
1975
- winPtr->reqHeight)/wmPtr->heightInc;
1976
if (wmPtr->height < 0) {
1977
wmPtr->height = 0;
1978
}
1979
} else {
1980
wmPtr->height = configEventPtr->height;
1981
}
1982
}
1983
wmPtr->configWidth = configEventPtr->width;
1984
wmPtr->configHeight = configEventPtr->height;
1985
}
1986
1987
if (wmTracing) {
1988
printf("ConfigureEvent: %s x = %d y = %d, width = %d, height = %d",
1989
winPtr->pathName, configEventPtr->x, configEventPtr->y,
1990
configEventPtr->width, configEventPtr->height);
1991
printf(" send_event = %d, serial = %ld\n", configEventPtr->send_event,
1992
configEventPtr->serial);
1993
}
1994
winPtr->changes.width = configEventPtr->width;
1995
winPtr->changes.height = configEventPtr->height;
1996
winPtr->changes.border_width = configEventPtr->border_width;
1997
winPtr->changes.sibling = configEventPtr->above;
1998
winPtr->changes.stack_mode = Above;
1999
2000
/*
2001
* Reparenting window managers make life difficult. If the
2002
* window manager reparents a top-level window then the x and y
2003
* information that comes in events for the window is wrong:
2004
* it gives the location of the window inside its decorative
2005
* parent, rather than the location of the window in root
2006
* coordinates, which is what we want. Window managers
2007
* are supposed to send synthetic events with the correct
2008
* information, but ICCCM doesn't require them to do this
2009
* under all conditions, and the information provided doesn't
2010
* include everything we need here. So, the code below
2011
* maintains a bunch of information about the parent window.
2012
* If the window hasn't been reparented, we pretend that
2013
* there is a parent shrink-wrapped around the window.
2014
*/
2015
2016
if ((wmPtr->reparent == None) || !ComputeReparentGeometry(winPtr)) {
2017
wmPtr->parentWidth = configEventPtr->width
2018
+ 2*configEventPtr->border_width;
2019
wmPtr->parentHeight = configEventPtr->height
2020
+ 2*configEventPtr->border_width;
2021
winPtr->changes.x = wmPtr->x = configEventPtr->x;
2022
winPtr->changes.y = wmPtr->y = configEventPtr->y;
2023
if (wmPtr->flags & WM_NEGATIVE_X) {
2024
wmPtr->x = wmPtr->vRootWidth - (wmPtr->x + wmPtr->parentWidth);
2025
}
2026
if (wmPtr->flags & WM_NEGATIVE_Y) {
2027
wmPtr->y = wmPtr->vRootHeight - (wmPtr->y + wmPtr->parentHeight);
2028
}
2029
}
2030
}
2031
2032
/*
2033
*----------------------------------------------------------------------
2034
*
2035
* ReparentEvent --
2036
*
2037
* This procedure is called to handle ReparentNotify events on
2038
* top-level windows.
2039
*
2040
* Results:
2041
* None.
2042
*
2043
* Side effects:
2044
* Information gets updated in the WmInfo structure for the window.
2045
*
2046
*----------------------------------------------------------------------
2047
*/
2048
2049
static void
2050
ReparentEvent(winPtr, reparentEventPtr)
2051
TkWindow *winPtr; /* Top-level window. */
2052
XReparentEvent *reparentEventPtr; /* Event that just occurred for
2053
* winPtr. */
2054
{
2055
register WmInfo *wmPtr = winPtr->wmInfoPtr;
2056
Window vRoot, ancestor, *children, dummy2, *virtualRootPtr;
2057
Atom actualType;
2058
int actualFormat;
2059
unsigned long numItems, bytesAfter;
2060
unsigned int dummy;
2061
Tk_ErrorHandler handler;
2062
2063
/*
2064
* Identify the root window for winPtr. This is tricky because of
2065
* virtual root window managers like tvtwm. If the window has a
2066
* property named __SWM_ROOT or __WM_ROOT then this property gives
2067
* the id for a virtual root window that should be used instead of
2068
* the root window of the screen.
2069
*/
2070
2071
vRoot = RootWindow(winPtr->display, winPtr->screenNum);
2072
wmPtr->vRoot = None;
2073
handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
2074
(Tk_ErrorProc *) NULL, (ClientData) NULL);
2075
if (((XGetWindowProperty(winPtr->display, winPtr->window,
2076
Tk_InternAtom((Tk_Window) winPtr, "__WM_ROOT"), 0, (long) 1,
2077
False, XA_WINDOW, &actualType, &actualFormat, &numItems,
2078
&bytesAfter, (unsigned char **) &virtualRootPtr) == Success)
2079
&& (actualType == XA_WINDOW))
2080
|| ((XGetWindowProperty(winPtr->display, winPtr->window,
2081
Tk_InternAtom((Tk_Window) winPtr, "__SWM_ROOT"), 0, (long) 1,
2082
False, XA_WINDOW, &actualType, &actualFormat, &numItems,
2083
&bytesAfter, (unsigned char **) &virtualRootPtr) == Success)
2084
&& (actualType == XA_WINDOW))) {
2085
if ((actualFormat == 32) && (numItems == 1)) {
2086
vRoot = wmPtr->vRoot = *virtualRootPtr;
2087
} else if (wmTracing) {
2088
printf("%s format %d numItems %ld\n",
2089
"ReparentEvent got bogus VROOT property:", actualFormat,
2090
numItems);
2091
}
2092
XFree((char *) virtualRootPtr);
2093
}
2094
Tk_DeleteErrorHandler(handler);
2095
2096
if (wmTracing) {
2097
printf("ReparentEvent: %s reparented to 0x%x, vRoot = 0x%x\n",
2098
winPtr->pathName, (unsigned int) reparentEventPtr->parent,
2099
(unsigned int) vRoot);
2100
}
2101
2102
/*
2103
* Fetch correct geometry information for the new virtual root.
2104
*/
2105
2106
UpdateVRootGeometry(wmPtr);
2107
2108
/*
2109
* If the window's new parent is the root window, then mark it as
2110
* no longer reparented.
2111
*/
2112
2113
if (reparentEventPtr->parent == vRoot) {
2114
noReparent:
2115
wmPtr->reparent = None;
2116
wmPtr->parentWidth = winPtr->changes.width
2117
+ 2*winPtr->changes.border_width;
2118
wmPtr->parentHeight = winPtr->changes.height
2119
+ 2*winPtr->changes.border_width;
2120
wmPtr->xInParent = wmPtr->yInParent = 0;
2121
winPtr->changes.x = reparentEventPtr->x;
2122
winPtr->changes.y = reparentEventPtr->y;
2123
return;
2124
}
2125
2126
/*
2127
* Search up the window hierarchy to find the ancestor of this
2128
* window that is just below the (virtual) root. This is tricky
2129
* because it's possible that things have changed since the event
2130
* was generated so that the ancestry indicated by the event no
2131
* longer exists. If this happens then an error will occur and
2132
* we just discard the event (there will be a more up-to-date
2133
* ReparentNotify event coming later).
2134
*/
2135
2136
handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
2137
(Tk_ErrorProc *) NULL, (ClientData) NULL);
2138
wmPtr->reparent = reparentEventPtr->parent;
2139
while (1) {
2140
if (XQueryTree(winPtr->display, wmPtr->reparent, &dummy2, &ancestor,
2141
&children, &dummy) == 0) {
2142
Tk_DeleteErrorHandler(handler);
2143
goto noReparent;
2144
}
2145
XFree((char *) children);
2146
if ((ancestor == vRoot) ||
2147
(ancestor == RootWindow(winPtr->display, winPtr->screenNum))) {
2148
break;
2149
}
2150
wmPtr->reparent = ancestor;
2151
}
2152
Tk_DeleteErrorHandler(handler);
2153
2154
if (!ComputeReparentGeometry(winPtr)) {
2155
goto noReparent;
2156
}
2157
}
2158
2159
/*
2160
*----------------------------------------------------------------------
2161
*
2162
* ComputeReparentGeometry --
2163
*
2164
* This procedure is invoked to recompute geometry information
2165
* related to a reparented top-level window, such as the position
2166
* and total size of the parent and the position within it of
2167
* the top-level window.
2168
*
2169
* Results:
2170
* The return value is 1 if everything completed successfully
2171
* and 0 if an error occurred while querying information about
2172
* winPtr's parents. In this case winPtr is marked as no longer
2173
* being reparented.
2174
*
2175
* Side effects:
2176
* Geometry information in winPtr and winPtr->wmPtr gets updated.
2177
*
2178
*----------------------------------------------------------------------
2179
*/
2180
2181
static int
2182
ComputeReparentGeometry(winPtr)
2183
TkWindow *winPtr; /* Top-level window whose reparent info
2184
* is to be recomputed. */
2185
{
2186
register WmInfo *wmPtr = winPtr->wmInfoPtr;
2187
int width, height, bd;
2188
unsigned int dummy;
2189
int xOffset, yOffset, x, y;
2190
Window dummy2;
2191
Status status;
2192
Tk_ErrorHandler handler;
2193
2194
handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
2195
(Tk_ErrorProc *) NULL, (ClientData) NULL);
2196
(void) XTranslateCoordinates(winPtr->display, winPtr->window,
2197
wmPtr->reparent, 0, 0, &xOffset, &yOffset, &dummy2);
2198
status = XGetGeometry(winPtr->display, wmPtr->reparent,
2199
&dummy2, &x, &y, (unsigned int *) &width,
2200
(unsigned int *) &height, (unsigned int *) &bd, &dummy);
2201
Tk_DeleteErrorHandler(handler);
2202
if (status == 0) {
2203
/*
2204
* It appears that the reparented parent went away and
2205
* no-one told us. Reset the window to indicate that
2206
* it's not reparented.
2207
*/
2208
wmPtr->reparent = None;
2209
wmPtr->xInParent = wmPtr->yInParent = 0;
2210
return 0;
2211
}
2212
wmPtr->xInParent = xOffset + bd - winPtr->changes.border_width;
2213
wmPtr->yInParent = yOffset + bd - winPtr->changes.border_width;
2214
wmPtr->parentWidth = width + 2*bd;
2215
wmPtr->parentHeight = height + 2*bd;
2216
2217
/*
2218
* Some tricky issues in updating wmPtr->x and wmPtr->y:
2219
*
2220
* 1. Don't update them if the event occurred because of something
2221
* we did (i.e. WM_SYNC_PENDING and WM_MOVE_PENDING are both set).
2222
* This is because window managers treat coords differently than Tk,
2223
* and no two window managers are alike. If the window manager moved
2224
* the window because we told it to, remember the coordinates we told
2225
* it, not the ones it actually moved it to. This allows us to move
2226
* the window back to the same coordinates later and get the same
2227
* result. Without this check, windows can "walk" across the screen
2228
* under some conditions.
2229
*
2230
* 2. Don't update wmPtr->x and wmPtr->y unless winPtr->changes.x
2231
* or winPtr->changes.y has changed (otherwise a size change can
2232
* spoof us into thinking that the position changed too and defeat
2233
* the intent of (1) above.
2234
*
2235
* 3. Ignore size changes coming from the window system if we're
2236
* about to change the size ourselves but haven't seen the event for
2237
* it yet: our size change is supposed to take priority.
2238
*/
2239
2240
if (!(wmPtr->flags & WM_MOVE_PENDING)
2241
&& ((winPtr->changes.x != (x + wmPtr->xInParent))
2242
|| (winPtr->changes.y != (y + wmPtr->yInParent)))) {
2243
wmPtr->x = x;
2244
if (wmPtr->flags & WM_NEGATIVE_X) {
2245
wmPtr->x = wmPtr->vRootWidth - (wmPtr->x + wmPtr->parentWidth);
2246
}
2247
wmPtr->y = y;
2248
if (wmPtr->flags & WM_NEGATIVE_Y) {
2249
wmPtr->y = wmPtr->vRootHeight - (wmPtr->y + wmPtr->parentHeight);
2250
}
2251
}
2252
2253
winPtr->changes.x = x + wmPtr->xInParent;
2254
winPtr->changes.y = y + wmPtr->yInParent;
2255
if (wmTracing) {
2256
printf("winPtr coords %d,%d, wmPtr coords %d,%d, offsets %d %d\n",
2257
winPtr->changes.x, winPtr->changes.y, wmPtr->x, wmPtr->y,
2258
wmPtr->xInParent, wmPtr->yInParent);
2259
}
2260
return 1;
2261
}
2262
2263
/*
2264
*----------------------------------------------------------------------
2265
*
2266
* TopLevelEventProc --
2267
*
2268
* This procedure is invoked when a top-level (or other externally-
2269
* managed window) is restructured in any way.
2270
*
2271
* Results:
2272
* None.
2273
*
2274
* Side effects:
2275
* Tk's internal data structures for the window get modified to
2276
* reflect the structural change.
2277
*
2278
*----------------------------------------------------------------------
2279
*/
2280
2281
static void
2282
TopLevelEventProc(clientData, eventPtr)
2283
ClientData clientData; /* Window for which event occurred. */
2284
XEvent *eventPtr; /* Event that just happened. */
2285
{
2286
register TkWindow *winPtr = (TkWindow *) clientData;
2287
2288
winPtr->wmInfoPtr->flags |= WM_VROOT_OFFSET_STALE;
2289
if (eventPtr->type == DestroyNotify) {
2290
Tk_ErrorHandler handler;
2291
2292
if (!(winPtr->flags & TK_ALREADY_DEAD)) {
2293
/*
2294
* A top-level window was deleted externally (e.g., by the window
2295
* manager). This is probably not a good thing, but cleanup as
2296
* best we can. The error handler is needed because
2297
* Tk_DestroyWindow will try to destroy the window, but of course
2298
* it's already gone.
2299
*/
2300
2301
handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
2302
(Tk_ErrorProc *) NULL, (ClientData) NULL);
2303
Tk_DestroyWindow((Tk_Window) winPtr);
2304
Tk_DeleteErrorHandler(handler);
2305
}
2306
if (wmTracing) {
2307
printf("TopLevelEventProc: %s deleted\n", winPtr->pathName);
2308
}
2309
} else if (eventPtr->type == ConfigureNotify) {
2310
/*
2311
* Ignore the event if the window has never been mapped yet.
2312
* Such an event occurs only in weird cases like changing the
2313
* internal border width of a top-level window, which results
2314
* in a synthetic Configure event. These events are not relevant
2315
* to us, and if we process them confusion may result (e.g. we
2316
* may conclude erroneously that the user repositioned or resized
2317
* the window).
2318
*/
2319
2320
if (!(winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED)) {
2321
ConfigureEvent(winPtr, &eventPtr->xconfigure);
2322
}
2323
} else if (eventPtr->type == MapNotify) {
2324
winPtr->flags |= TK_MAPPED;
2325
if (wmTracing) {
2326
printf("TopLevelEventProc: %s mapped\n", winPtr->pathName);
2327
}
2328
} else if (eventPtr->type == UnmapNotify) {
2329
winPtr->flags &= ~TK_MAPPED;
2330
if (wmTracing) {
2331
printf("TopLevelEventProc: %s unmapped\n", winPtr->pathName);
2332
}
2333
} else if (eventPtr->type == ReparentNotify) {
2334
ReparentEvent(winPtr, &eventPtr->xreparent);
2335
}
2336
}
2337
2338
/*
2339
*----------------------------------------------------------------------
2340
*
2341
* TopLevelReqProc --
2342
*
2343
* This procedure is invoked by the geometry manager whenever
2344
* the requested size for a top-level window is changed.
2345
*
2346
* Results:
2347
* None.
2348
*
2349
* Side effects:
2350
* Arrange for the window to be resized to satisfy the request
2351
* (this happens as a when-idle action).
2352
*
2353
*----------------------------------------------------------------------
2354
*/
2355
2356
/* ARGSUSED */
2357
static void
2358
TopLevelReqProc(dummy, tkwin)
2359
ClientData dummy; /* Not used. */
2360
Tk_Window tkwin; /* Information about window. */
2361
{
2362
TkWindow *winPtr = (TkWindow *) tkwin;
2363
WmInfo *wmPtr;
2364
2365
wmPtr = winPtr->wmInfoPtr;
2366
wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
2367
if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
2368
Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
2369
wmPtr->flags |= WM_UPDATE_PENDING;
2370
}
2371
2372
/*
2373
* If the window isn't being positioned by its upper left corner
2374
* then we have to move it as well.
2375
*/
2376
2377
if (wmPtr->flags & (WM_NEGATIVE_X | WM_NEGATIVE_Y)) {
2378
wmPtr->flags |= WM_MOVE_PENDING;
2379
}
2380
}
2381
2382
/*
2383
*----------------------------------------------------------------------
2384
*
2385
* UpdateGeometryInfo --
2386
*
2387
* This procedure is invoked when a top-level window is first
2388
* mapped, and also as a when-idle procedure, to bring the
2389
* geometry and/or position of a top-level window back into
2390
* line with what has been requested by the user and/or widgets.
2391
* This procedure doesn't return until the window manager has
2392
* responded to the geometry change.
2393
*
2394
* Results:
2395
* None.
2396
*
2397
* Side effects:
2398
* The window's size and location may change, unless the WM prevents
2399
* that from happening.
2400
*
2401
*----------------------------------------------------------------------
2402
*/
2403
2404
static void
2405
UpdateGeometryInfo(clientData)
2406
ClientData clientData; /* Pointer to the window's record. */
2407
{
2408
register TkWindow *winPtr = (TkWindow *) clientData;
2409
register WmInfo *wmPtr = winPtr->wmInfoPtr;
2410
int x, y, width, height;
2411
unsigned long serial;
2412
2413
wmPtr->flags &= ~WM_UPDATE_PENDING;
2414
2415
/*
2416
* Compute the new size for the top-level window. See the
2417
* user documentation for details on this, but the size
2418
* requested depends on (a) the size requested internally
2419
* by the window's widgets, (b) the size requested by the
2420
* user in a "wm geometry" command or via wm-based interactive
2421
* resizing (if any), and (c) whether or not the window is
2422
* gridded. Don't permit sizes <= 0 because this upsets
2423
* the X server.
2424
*/
2425
2426
if (wmPtr->width == -1) {
2427
width = winPtr->reqWidth;
2428
} else if (wmPtr->gridWin != NULL) {
2429
width = winPtr->reqWidth
2430
+ (wmPtr->width - wmPtr->reqGridWidth)*wmPtr->widthInc;
2431
} else {
2432
width = wmPtr->width;
2433
}
2434
if (width <= 0) {
2435
width = 1;
2436
}
2437
if (wmPtr->height == -1) {
2438
height = winPtr->reqHeight;
2439
} else if (wmPtr->gridWin != NULL) {
2440
height = winPtr->reqHeight
2441
+ (wmPtr->height - wmPtr->reqGridHeight)*wmPtr->heightInc;
2442
} else {
2443
height = wmPtr->height;
2444
}
2445
if (height <= 0) {
2446
height = 1;
2447
}
2448
2449
/*
2450
* Compute the new position for the upper-left pixel of the window's
2451
* decorative frame. This is tricky, because we need to include the
2452
* border widths supplied by a reparented parent in this calculation,
2453
* but can't use the parent's current overall size since that may
2454
* change as a result of this code.
2455
*/
2456
2457
if (wmPtr->flags & WM_NEGATIVE_X) {
2458
x = wmPtr->vRootWidth - wmPtr->x
2459
- (width + (wmPtr->parentWidth - winPtr->changes.width));
2460
} else {
2461
x = wmPtr->x;
2462
}
2463
if (wmPtr->flags & WM_NEGATIVE_Y) {
2464
y = wmPtr->vRootHeight - wmPtr->y
2465
- (height + (wmPtr->parentHeight - winPtr->changes.height));
2466
} else {
2467
y = wmPtr->y;
2468
}
2469
2470
/*
2471
* If the window's size is going to change and the window is
2472
* supposed to not be resizable by the user, then we have to
2473
* update the size hints. There may also be a size-hint-update
2474
* request pending from somewhere else, too.
2475
*/
2476
2477
if (((width != winPtr->changes.width)
2478
|| (height != winPtr->changes.height))
2479
&& (wmPtr->gridWin == NULL)
2480
&& ((wmPtr->sizeHintsFlags & (PMinSize|PMaxSize)) == 0)) {
2481
wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
2482
}
2483
if (wmPtr->flags & WM_UPDATE_SIZE_HINTS) {
2484
UpdateSizeHints(winPtr);
2485
}
2486
2487
/*
2488
* Reconfigure the window if it isn't already configured correctly.
2489
* A few tricky points:
2490
*
2491
* 1. Sometimes the window manager will give us a different size
2492
* than we asked for (e.g. mwm has a minimum size for windows), so
2493
* base the size check on what we *asked for* last time, not what we
2494
* got.
2495
* 2. Can't just reconfigure always, because we may not get a
2496
* ConfigureNotify event back if nothing changed, so
2497
* WaitForConfigureNotify will hang a long time.
2498
* 3. Don't move window unless a new position has been requested for
2499
* it. This is because of "features" in some window managers (e.g.
2500
* twm, as of 4/24/91) where they don't interpret coordinates
2501
* according to ICCCM. Moving a window to its current location may
2502
* cause it to shift position on the screen.
2503
*/
2504
2505
serial = NextRequest(winPtr->display);
2506
if (wmPtr->flags & WM_MOVE_PENDING) {
2507
wmPtr->configWidth = width;
2508
wmPtr->configHeight = height;
2509
if (wmTracing) {
2510
printf("UpdateGeometryInfo moving to %d %d, resizing to %d x %d,\n",
2511
x, y, width, height);
2512
}
2513
Tk_MoveResizeWindow((Tk_Window) winPtr, x, y, width, height);
2514
} else if ((width != wmPtr->configWidth)
2515
|| (height != wmPtr->configHeight)) {
2516
wmPtr->configWidth = width;
2517
wmPtr->configHeight = height;
2518
if (wmTracing) {
2519
printf("UpdateGeometryInfo resizing to %d x %d\n", width, height);
2520
}
2521
Tk_ResizeWindow((Tk_Window) winPtr, width, height);
2522
} else {
2523
return;
2524
}
2525
2526
/*
2527
* Wait for the configure operation to complete. Don't need to do
2528
* this, however, if the window is about to be mapped: it will be
2529
* taken care of elsewhere.
2530
*/
2531
2532
if (!(wmPtr->flags & WM_ABOUT_TO_MAP)) {
2533
WaitForConfigureNotify(winPtr, serial);
2534
}
2535
}
2536
2537
/*
2538
*--------------------------------------------------------------
2539
*
2540
* UpdateSizeHints --
2541
*
2542
* This procedure is called to update the window manager's
2543
* size hints information from the information in a WmInfo
2544
* structure.
2545
*
2546
* Results:
2547
* None.
2548
*
2549
* Side effects:
2550
* Properties get changed for winPtr.
2551
*
2552
*--------------------------------------------------------------
2553
*/
2554
2555
static void
2556
UpdateSizeHints(winPtr)
2557
TkWindow *winPtr;
2558
{
2559
register WmInfo *wmPtr = winPtr->wmInfoPtr;
2560
XSizeHints *hintsPtr;
2561
int maxWidth, maxHeight;
2562
2563
wmPtr->flags &= ~WM_UPDATE_SIZE_HINTS;
2564
2565
hintsPtr = XAllocSizeHints();
2566
if (hintsPtr == NULL) {
2567
return;
2568
}
2569
2570
/*
2571
* Compute the pixel-based sizes for the various fields in the
2572
* size hints structure, based on the grid-based sizes in
2573
* our structure.
2574
*/
2575
2576
GetMaxSize(wmPtr, &maxWidth, &maxHeight);
2577
if (wmPtr->gridWin != NULL) {
2578
#if PBaseSize
2579
hintsPtr->base_width = winPtr->reqWidth
2580
- (wmPtr->reqGridWidth * wmPtr->widthInc);
2581
if (hintsPtr->base_width < 0) {
2582
hintsPtr->base_width = 0;
2583
}
2584
hintsPtr->base_height = winPtr->reqHeight
2585
- (wmPtr->reqGridHeight * wmPtr->heightInc);
2586
if (hintsPtr->base_height < 0) {
2587
hintsPtr->base_height = 0;
2588
}
2589
#endif
2590
hintsPtr->min_width =
2591
#if PBaseSize
2592
hintsPtr->base_width +
2593
#endif
2594
(wmPtr->minWidth * wmPtr->widthInc);
2595
hintsPtr->min_height =
2596
#if PBaseSize
2597
hintsPtr->base_height +
2598
#endif
2599
(wmPtr->minHeight * wmPtr->heightInc);
2600
hintsPtr->max_width =
2601
#if PBaseSize
2602
hintsPtr->base_width +
2603
#endif
2604
(maxWidth * wmPtr->widthInc);
2605
hintsPtr->max_height =
2606
#if PBaseSize
2607
hintsPtr->base_height +
2608
#endif
2609
(maxHeight * wmPtr->heightInc);
2610
} else {
2611
hintsPtr->min_width = wmPtr->minWidth;
2612
hintsPtr->min_height = wmPtr->minHeight;
2613
hintsPtr->max_width = maxWidth;
2614
hintsPtr->max_height = maxHeight;
2615
#if PBaseSize
2616
hintsPtr->base_width = 0;
2617
hintsPtr->base_height = 0;
2618
#endif
2619
}
2620
hintsPtr->width_inc = wmPtr->widthInc;
2621
hintsPtr->height_inc = wmPtr->heightInc;
2622
hintsPtr->min_aspect.x = wmPtr->minAspect.x;
2623
hintsPtr->min_aspect.y = wmPtr->minAspect.y;
2624
hintsPtr->max_aspect.x = wmPtr->maxAspect.x;
2625
hintsPtr->max_aspect.y = wmPtr->maxAspect.y;
2626
#if PWinGravity
2627
hintsPtr->win_gravity = wmPtr->gravity;
2628
#endif
2629
hintsPtr->flags = wmPtr->sizeHintsFlags | PMinSize | PMaxSize;
2630
2631
/*
2632
* If the window isn't supposed to be resizable, then set the
2633
* minimum and maximum dimensions to be the same.
2634
*/
2635
2636
if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) {
2637
if (wmPtr->width >= 0) {
2638
hintsPtr->min_width = wmPtr->width;
2639
} else {
2640
hintsPtr->min_width = winPtr->reqWidth;
2641
}
2642
hintsPtr->max_width = hintsPtr->min_width;
2643
}
2644
if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) {
2645
if (wmPtr->height >= 0) {
2646
hintsPtr->min_height = wmPtr->height;
2647
} else {
2648
hintsPtr->min_height = winPtr->reqHeight;
2649
}
2650
hintsPtr->max_height = hintsPtr->min_height;
2651
}
2652
2653
XSetWMNormalHints(winPtr->display, winPtr->window, hintsPtr);
2654
2655
XFree((char *) hintsPtr);
2656
}
2657
2658
/*
2659
*----------------------------------------------------------------------
2660
*
2661
* WaitForConfigureNotify --
2662
*
2663
* This procedure is invoked in order to synchronize with the
2664
* window manager. It waits for a ConfigureNotify event to
2665
* arrive, signalling that the window manager has seen an attempt
2666
* on our part to move or resize a top-level window.
2667
*
2668
* Results:
2669
* None.
2670
*
2671
* Side effects:
2672
* Delays the execution of the process until a ConfigureNotify event
2673
* arrives with serial number at least as great as serial. This
2674
* is useful for two reasons:
2675
*
2676
* 1. It's important to distinguish ConfigureNotify events that are
2677
* coming in response to a request we've made from those generated
2678
* spontaneously by the user. The reason for this is that if the
2679
* user resizes the window we take that as an order to ignore
2680
* geometry requests coming from inside the window hierarchy. If
2681
* we accidentally interpret a response to our request as a
2682
* user-initiated action, the window will stop responding to
2683
* new geometry requests. To make this distinction, (a) this
2684
* procedure sets a flag for TopLevelEventProc to indicate that
2685
* we're waiting to sync with the wm, and (b) all changes to
2686
* the size of a top-level window are followed by calls to this
2687
* procedure.
2688
* 2. Races and confusion can come about if there are multiple
2689
* operations outstanding at a time (e.g. two different resizes
2690
* of the top-level window: it's hard to tell which of the
2691
* ConfigureNotify events coming back is for which request).
2692
* While waiting, all events covered by StructureNotifyMask are
2693
* processed and all others are deferred.
2694
*
2695
*----------------------------------------------------------------------
2696
*/
2697
2698
static void
2699
WaitForConfigureNotify(winPtr, serial)
2700
TkWindow *winPtr; /* Top-level window for which we want
2701
* to see a ConfigureNotify. */
2702
unsigned long serial; /* Serial number of resize request. Want to
2703
* be sure wm has seen this. */
2704
{
2705
WmInfo *wmPtr = winPtr->wmInfoPtr;
2706
XEvent event;
2707
int diff, code;
2708
int gotConfig = 0;
2709
2710
/*
2711
* One more tricky detail about this procedure. In some cases the
2712
* window manager will decide to ignore a configure request (e.g.
2713
* because it thinks the window is already in the right place).
2714
* To avoid hanging in this situation, only wait for a few seconds,
2715
* then give up.
2716
*/
2717
2718
while (!gotConfig) {
2719
wmPtr->flags |= WM_SYNC_PENDING;
2720
code = WaitForEvent(winPtr->display, winPtr->window, ConfigureNotify,
2721
&event);
2722
wmPtr->flags &= ~WM_SYNC_PENDING;
2723
if (code != TCL_OK) {
2724
if (wmTracing) {
2725
printf("WaitForConfigureNotify giving up on %s\n",
2726
winPtr->pathName);
2727
}
2728
break;
2729
}
2730
diff = event.xconfigure.serial - serial;
2731
if (diff >= 0) {
2732
gotConfig = 1;
2733
}
2734
}
2735
wmPtr->flags &= ~WM_MOVE_PENDING;
2736
if (wmTracing) {
2737
printf("WaitForConfigureNotify finished with %s, serial %ld\n",
2738
winPtr->pathName, serial);
2739
}
2740
}
2741
2742
/*
2743
*----------------------------------------------------------------------
2744
*
2745
* WaitForEvent --
2746
*
2747
* This procedure is used by WaitForConfigureNotify and
2748
* WaitForMapNotify to wait for an event of a certain type
2749
* to arrive.
2750
*
2751
* Results:
2752
* Under normal conditions, TCL_OK is returned and an event for
2753
* display and window that matches "mask" is stored in *eventPtr.
2754
* This event has already been processed by Tk before this procedure
2755
* returns. If a long time goes by with no event of the right type
2756
* arriving, or if an error occurs while waiting for the event to
2757
* arrive, then TCL_ERROR is returned.
2758
*
2759
* Side effects:
2760
* While waiting for the desired event to occur, Configurenotify
2761
* events for window are processed, as are all ReparentNotify events,
2762
*
2763
*----------------------------------------------------------------------
2764
*/
2765
2766
static int
2767
WaitForEvent(display, window, type, eventPtr)
2768
Display *display; /* Display event is coming from. */
2769
Window window; /* Window for which event is desired. */
2770
int type; /* Type of event that is wanted. */
2771
XEvent *eventPtr; /* Place to store event. */
2772
{
2773
#define TIMEOUT_MS 2000
2774
WaitRestrictInfo info;
2775
Tk_RestrictProc *oldRestrictProc;
2776
ClientData oldRestrictData;
2777
2778
/*
2779
* Set up an event filter to select just the events we want, and
2780
* a timer handler, then wait for events until we get the event
2781
* we want or a timeout happens.
2782
*/
2783
2784
info.display = display;
2785
info.window = window;
2786
info.type = type;
2787
info.eventPtr = eventPtr;
2788
info.foundEvent = 0;
2789
info.timeout = 0;
2790
oldRestrictProc = Tk_RestrictEvents(WaitRestrictProc, (ClientData) &info,
2791
&oldRestrictData);
2792
Tcl_CreateModalTimeout(TIMEOUT_MS, WaitTimeoutProc,
2793
(ClientData) &info);
2794
while (1) {
2795
Tcl_DoOneEvent(TCL_WINDOW_EVENTS);
2796
if (info.foundEvent) {
2797
break;
2798
}
2799
if (info.timeout) {
2800
break;
2801
}
2802
}
2803
Tcl_DeleteModalTimeout(WaitTimeoutProc, (ClientData) &info);
2804
(void) Tk_RestrictEvents(oldRestrictProc, oldRestrictData,
2805
&oldRestrictData);
2806
if (info.foundEvent) {
2807
return TCL_OK;
2808
}
2809
return TCL_ERROR;
2810
}
2811
2812
/*
2813
*----------------------------------------------------------------------
2814
*
2815
* WaitRestrictProc --
2816
*
2817
* This procedure is a Tk_RestrictProc that is used to filter
2818
* events while WaitForEvent is active.
2819
*
2820
* Results:
2821
* Returns TK_PROCESS_EVENT if the right event is found. Also
2822
* returns TK_PROCESS_EVENT if any ReparentNotify event is found
2823
* for window or if the event is a ConfigureNotify for window.
2824
* Otherwise returns TK_DEFER_EVENT.
2825
*
2826
* Side effects:
2827
* An event may get stored in the area indicated by the caller
2828
* of WaitForEvent.
2829
*
2830
*----------------------------------------------------------------------
2831
*/
2832
2833
static Tk_RestrictAction
2834
WaitRestrictProc(clientData, eventPtr)
2835
ClientData clientData; /* Pointer to WaitRestrictInfo structure. */
2836
XEvent *eventPtr; /* Event that is about to be handled. */
2837
{
2838
WaitRestrictInfo *infoPtr = (WaitRestrictInfo *) clientData;
2839
2840
if (eventPtr->type == ReparentNotify) {
2841
return TK_PROCESS_EVENT;
2842
}
2843
if ((eventPtr->xany.window != infoPtr->window)
2844
|| (eventPtr->xany.display != infoPtr->display)) {
2845
return TK_DEFER_EVENT;
2846
}
2847
if (eventPtr->type == infoPtr->type) {
2848
*infoPtr->eventPtr = *eventPtr;
2849
infoPtr->foundEvent = 1;
2850
return TK_PROCESS_EVENT;
2851
}
2852
if (eventPtr->type == ConfigureNotify) {
2853
return TK_PROCESS_EVENT;
2854
}
2855
return TK_DEFER_EVENT;
2856
}
2857
2858
/*
2859
*----------------------------------------------------------------------
2860
*
2861
* WaitTimeoutProc --
2862
*
2863
* This procedure is invoked as a timer handler when too much
2864
* time elapses during a call to WaitForEvent. It sets a flag
2865
* in a structure shared with WaitForEvent so that WaitForEvent
2866
* knows that it should return.
2867
*
2868
* Results:
2869
* None.
2870
*
2871
* Side effects:
2872
* The timeout field gest set in the WaitRestrictInfo structure.
2873
*
2874
*----------------------------------------------------------------------
2875
*/
2876
2877
static void
2878
WaitTimeoutProc(clientData)
2879
ClientData clientData; /* Pointer to WaitRestrictInfo structure. */
2880
{
2881
WaitRestrictInfo *infoPtr = (WaitRestrictInfo *) clientData;
2882
2883
infoPtr->timeout = 1;
2884
}
2885
2886
/*
2887
*----------------------------------------------------------------------
2888
*
2889
* WaitForMapNotify --
2890
*
2891
* This procedure is invoked in order to synchronize with the
2892
* window manager. It waits for the window's mapped state to
2893
* reach the value given by mapped.
2894
*
2895
* Results:
2896
* None.
2897
*
2898
* Side effects:
2899
* Delays the execution of the process until winPtr becomes mapped
2900
* or unmapped, depending on the "mapped" argument. This allows us
2901
* to synchronize with the window manager, and allows us to
2902
* identify changes in window size that come about when the window
2903
* manager first starts managing the window (as opposed to those
2904
* requested interactively by the user later). See the comments
2905
* for WaitForConfigureNotify and WM_SYNC_PENDING. While waiting,
2906
* all events covered by StructureNotifyMask are processed and all
2907
* others are deferred.
2908
*
2909
*----------------------------------------------------------------------
2910
*/
2911
2912
static void
2913
WaitForMapNotify(winPtr, mapped)
2914
TkWindow *winPtr; /* Top-level window for which we want
2915
* to see a particular mapping state. */
2916
int mapped; /* If non-zero, wait for window to become
2917
* mapped, otherwise wait for it to become
2918
* unmapped. */
2919
{
2920
WmInfo *wmPtr = winPtr->wmInfoPtr;
2921
XEvent event;
2922
int code;
2923
2924
while (1) {
2925
if (mapped) {
2926
if (winPtr->flags & TK_MAPPED) {
2927
break;
2928
}
2929
} else if (!(winPtr->flags & TK_MAPPED)) {
2930
break;
2931
}
2932
wmPtr->flags |= WM_SYNC_PENDING;
2933
code = WaitForEvent(winPtr->display, winPtr->window,
2934
mapped ? MapNotify : UnmapNotify, &event);
2935
wmPtr->flags &= ~WM_SYNC_PENDING;
2936
if (code != TCL_OK) {
2937
/*
2938
* There are some bizarre situations in which the window
2939
* manager can't respond or chooses not to (e.g. if we've
2940
* got a grab set it can't respond). If this happens then
2941
* just quit.
2942
*/
2943
2944
if (wmTracing) {
2945
printf("WaitForMapNotify giving up on %s\n", winPtr->pathName);
2946
}
2947
break;
2948
}
2949
}
2950
wmPtr->flags &= ~WM_MOVE_PENDING;
2951
if (wmTracing) {
2952
printf("WaitForMapNotify finished with %s\n", winPtr->pathName);
2953
}
2954
}
2955
2956
/*
2957
*--------------------------------------------------------------
2958
*
2959
* UpdateHints --
2960
*
2961
* This procedure is called to update the window manager's
2962
* hints information from the information in a WmInfo
2963
* structure.
2964
*
2965
* Results:
2966
* None.
2967
*
2968
* Side effects:
2969
* Properties get changed for winPtr.
2970
*
2971
*--------------------------------------------------------------
2972
*/
2973
2974
static void
2975
UpdateHints(winPtr)
2976
TkWindow *winPtr;
2977
{
2978
WmInfo *wmPtr = winPtr->wmInfoPtr;
2979
2980
if (wmPtr->flags & WM_NEVER_MAPPED) {
2981
return;
2982
}
2983
XSetWMHints(winPtr->display, winPtr->window, &wmPtr->hints);
2984
}
2985
2986
/*
2987
*--------------------------------------------------------------
2988
*
2989
* ParseGeometry --
2990
*
2991
* This procedure parses a geometry string and updates
2992
* information used to control the geometry of a top-level
2993
* window.
2994
*
2995
* Results:
2996
* A standard Tcl return value, plus an error message in
2997
* interp->result if an error occurs.
2998
*
2999
* Side effects:
3000
* The size and/or location of winPtr may change.
3001
*
3002
*--------------------------------------------------------------
3003
*/
3004
3005
static int
3006
ParseGeometry(interp, string, winPtr)
3007
Tcl_Interp *interp; /* Used for error reporting. */
3008
char *string; /* String containing new geometry. Has the
3009
* standard form "=wxh+x+y". */
3010
TkWindow *winPtr; /* Pointer to top-level window whose
3011
* geometry is to be changed. */
3012
{
3013
register WmInfo *wmPtr = winPtr->wmInfoPtr;
3014
int x, y, width, height, flags;
3015
char *end;
3016
register char *p = string;
3017
3018
/*
3019
* The leading "=" is optional.
3020
*/
3021
3022
if (*p == '=') {
3023
p++;
3024
}
3025
3026
/*
3027
* Parse the width and height, if they are present. Don't
3028
* actually update any of the fields of wmPtr until we've
3029
* successfully parsed the entire geometry string.
3030
*/
3031
3032
width = wmPtr->width;
3033
height = wmPtr->height;
3034
x = wmPtr->x;
3035
y = wmPtr->y;
3036
flags = wmPtr->flags;
3037
if (isdigit(UCHAR(*p))) {
3038
width = strtoul(p, &end, 10);
3039
p = end;
3040
if (*p != 'x') {
3041
goto error;
3042
}
3043
p++;
3044
if (!isdigit(UCHAR(*p))) {
3045
goto error;
3046
}
3047
height = strtoul(p, &end, 10);
3048
p = end;
3049
}
3050
3051
/*
3052
* Parse the X and Y coordinates, if they are present.
3053
*/
3054
3055
if (*p != '\0') {
3056
flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
3057
if (*p == '-') {
3058
flags |= WM_NEGATIVE_X;
3059
} else if (*p != '+') {
3060
goto error;
3061
}
3062
x = strtol(p+1, &end, 10);
3063
p = end;
3064
if (*p == '-') {
3065
flags |= WM_NEGATIVE_Y;
3066
} else if (*p != '+') {
3067
goto error;
3068
}
3069
y = strtol(p+1, &end, 10);
3070
if (*end != '\0') {
3071
goto error;
3072
}
3073
3074
/*
3075
* Assume that the geometry information came from the user,
3076
* unless an explicit source has been specified. Otherwise
3077
* most window managers assume that the size hints were
3078
* program-specified and they ignore them.
3079
*/
3080
3081
if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
3082
wmPtr->sizeHintsFlags |= USPosition;
3083
flags |= WM_UPDATE_SIZE_HINTS;
3084
}
3085
}
3086
3087
/*
3088
* Everything was parsed OK. Update the fields of *wmPtr and
3089
* arrange for the appropriate information to be percolated out
3090
* to the window manager at the next idle moment.
3091
*/
3092
3093
wmPtr->width = width;
3094
wmPtr->height = height;
3095
wmPtr->x = x;
3096
wmPtr->y = y;
3097
flags |= WM_MOVE_PENDING;
3098
wmPtr->flags = flags;
3099
3100
if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
3101
Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
3102
wmPtr->flags |= WM_UPDATE_PENDING;
3103
}
3104
return TCL_OK;
3105
3106
error:
3107
Tcl_AppendResult(interp, "bad geometry specifier \"",
3108
string, "\"", (char *) NULL);
3109
return TCL_ERROR;
3110
}
3111
3112
/*
3113
*----------------------------------------------------------------------
3114
*
3115
* Tk_GetRootCoords --
3116
*
3117
* Given a token for a window, this procedure traces through the
3118
* window's lineage to find the (virtual) root-window coordinates
3119
* corresponding to point (0,0) in the window.
3120
*
3121
* Results:
3122
* The locations pointed to by xPtr and yPtr are filled in with
3123
* the root coordinates of the (0,0) point in tkwin. If a virtual
3124
* root window is in effect for the window, then the coordinates
3125
* in the virtual root are returned.
3126
*
3127
* Side effects:
3128
* None.
3129
*
3130
*----------------------------------------------------------------------
3131
*/
3132
3133
void
3134
Tk_GetRootCoords(tkwin, xPtr, yPtr)
3135
Tk_Window tkwin; /* Token for window. */
3136
int *xPtr; /* Where to store x-displacement of (0,0). */
3137
int *yPtr; /* Where to store y-displacement of (0,0). */
3138
{
3139
int x, y;
3140
register TkWindow *winPtr = (TkWindow *) tkwin;
3141
3142
/*
3143
* Search back through this window's parents all the way to a
3144
* top-level window, combining the offsets of each window within
3145
* its parent.
3146
*/
3147
3148
x = y = 0;
3149
while (1) {
3150
x += winPtr->changes.x + winPtr->changes.border_width;
3151
y += winPtr->changes.y + winPtr->changes.border_width;
3152
if ((winPtr->flags & TK_TOP_LEVEL) || (winPtr->parentPtr == NULL)) {
3153
break;
3154
}
3155
winPtr = winPtr->parentPtr;
3156
}
3157
*xPtr = x;
3158
*yPtr = y;
3159
}
3160
3161
/*
3162
*----------------------------------------------------------------------
3163
*
3164
* Tk_CoordsToWindow --
3165
*
3166
* Given the (virtual) root coordinates of a point, this procedure
3167
* returns the token for the top-most window covering that point,
3168
* if there exists such a window in this application.
3169
*
3170
* Results:
3171
* The return result is either a token for the window corresponding
3172
* to rootX and rootY, or else NULL to indicate that there is no such
3173
* window.
3174
*
3175
* Side effects:
3176
* None.
3177
*
3178
*----------------------------------------------------------------------
3179
*/
3180
3181
Tk_Window
3182
Tk_CoordsToWindow(rootX, rootY, tkwin)
3183
int rootX, rootY; /* Coordinates of point in root window. If
3184
* a virtual-root window manager is in use,
3185
* these coordinates refer to the virtual
3186
* root, not the real root. */
3187
Tk_Window tkwin; /* Token for any window in application;
3188
* used to identify the display. */
3189
{
3190
Window rootChild, root, vRoot;
3191
int dummy1, dummy2;
3192
register WmInfo *wmPtr;
3193
register TkWindow *winPtr, *childPtr;
3194
TkWindow *nextPtr; /* Coordinates of highest child found so
3195
* far that contains point. */
3196
int x, y; /* Coordinates in winPtr. */
3197
int tmpx, tmpy, bd;
3198
3199
/*
3200
* Step 1: find any top-level window for the right screen.
3201
*/
3202
3203
while (!Tk_IsTopLevel(tkwin)) {
3204
tkwin = Tk_Parent(tkwin);
3205
}
3206
wmPtr = ((TkWindow *) tkwin)->wmInfoPtr;
3207
3208
/*
3209
* Step 2: find the window in the actual root that contains the
3210
* desired point. Special trick: if a virtual root window manager
3211
* is in use, there may be windows in both the true root (e.g.
3212
* pop-up menus) and in the virtual root; have to look in *both*
3213
* places.
3214
*/
3215
3216
UpdateVRootGeometry(wmPtr);
3217
root = RootWindowOfScreen(Tk_Screen(tkwin));
3218
if (XTranslateCoordinates(Tk_Display(tkwin), root, root,
3219
rootX + wmPtr->vRootX, rootY + wmPtr->vRootY,
3220
&dummy1, &dummy2, &rootChild) == False) {
3221
panic("Tk_CoordsToWindow get False return from XTranslateCoordinates");
3222
}
3223
3224
/*
3225
* Step 3: if the window we've found so far (a child of the root)
3226
* is the virtual root window, then look again to find the child of
3227
* the virtual root.
3228
*/
3229
3230
vRoot = ((TkWindow *) tkwin)->wmInfoPtr->vRoot;
3231
if ((vRoot != None) && (rootChild == vRoot)) {
3232
if (XTranslateCoordinates(Tk_Display(tkwin), vRoot, vRoot, rootX,
3233
rootY, &dummy1, &dummy2, &rootChild) == False) {
3234
panic("Tk_CoordsToWindow get False return from XTranslateCoordinates");
3235
}
3236
}
3237
for (wmPtr = firstWmPtr; ; wmPtr = wmPtr->nextPtr) {
3238
if (wmPtr == NULL) {
3239
return NULL;
3240
}
3241
if ((wmPtr->reparent == rootChild) || ((wmPtr->reparent == None)
3242
&& (wmPtr->winPtr->window == rootChild))) {
3243
break;
3244
}
3245
}
3246
winPtr = wmPtr->winPtr;
3247
if (winPtr->mainPtr != ((TkWindow *) tkwin)->mainPtr) {
3248
return NULL;
3249
}
3250
3251
/*
3252
* Step 4: work down through the hierarchy underneath this window.
3253
* At each level, scan through all the children to find the highest
3254
* one in the stacking order that contains the point. Then repeat
3255
* the whole process on that child.
3256
*/
3257
3258
x = rootX;
3259
y = rootY;
3260
while (1) {
3261
x -= winPtr->changes.x;
3262
y -= winPtr->changes.y;
3263
nextPtr = NULL;
3264
for (childPtr = winPtr->childList; childPtr != NULL;
3265
childPtr = childPtr->nextPtr) {
3266
if (!Tk_IsMapped(childPtr) || (childPtr->flags & TK_TOP_LEVEL)) {
3267
continue;
3268
}
3269
tmpx = x - childPtr->changes.x;
3270
tmpy = y - childPtr->changes.y;
3271
bd = childPtr->changes.border_width;
3272
if ((tmpx >= -bd) && (tmpy >= -bd)
3273
&& (tmpx < (childPtr->changes.width + bd))
3274
&& (tmpy < (childPtr->changes.height + bd))) {
3275
nextPtr = childPtr;
3276
}
3277
}
3278
if (nextPtr == NULL) {
3279
break;
3280
}
3281
winPtr = nextPtr;
3282
}
3283
return (Tk_Window) winPtr;
3284
}
3285
3286
/*
3287
*----------------------------------------------------------------------
3288
*
3289
* UpdateVRootGeometry --
3290
*
3291
* This procedure is called to update all the virtual root
3292
* geometry information in wmPtr.
3293
*
3294
* Results:
3295
* None.
3296
*
3297
* Side effects:
3298
* The vRootX, vRootY, vRootWidth, and vRootHeight fields in
3299
* wmPtr are filled with the most up-to-date information.
3300
*
3301
*----------------------------------------------------------------------
3302
*/
3303
3304
static void
3305
UpdateVRootGeometry(wmPtr)
3306
WmInfo *wmPtr; /* Window manager information to be
3307
* updated. The wmPtr->vRoot field must
3308
* be valid. */
3309
{
3310
TkWindow *winPtr = wmPtr->winPtr;
3311
int bd;
3312
unsigned int dummy;
3313
Window dummy2;
3314
Status status;
3315
Tk_ErrorHandler handler;
3316
3317
/*
3318
* If this isn't a virtual-root window manager, just return information
3319
* about the screen.
3320
*/
3321
3322
wmPtr->flags &= ~WM_VROOT_OFFSET_STALE;
3323
if (wmPtr->vRoot == None) {
3324
noVRoot:
3325
wmPtr->vRootX = wmPtr->vRootY = 0;
3326
wmPtr->vRootWidth = DisplayWidth(winPtr->display, winPtr->screenNum);
3327
wmPtr->vRootHeight = DisplayHeight(winPtr->display, winPtr->screenNum);
3328
return;
3329
}
3330
3331
/*
3332
* Refresh the virtual root information if it's out of date.
3333
*/
3334
3335
handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
3336
(Tk_ErrorProc *) NULL, (ClientData) NULL);
3337
status = XGetGeometry(winPtr->display, wmPtr->vRoot,
3338
&dummy2, &wmPtr->vRootX, &wmPtr->vRootY,
3339
(unsigned int *) &wmPtr->vRootWidth,
3340
(unsigned int *) &wmPtr->vRootHeight, (unsigned int *) &bd,
3341
&dummy);
3342
if (wmTracing) {
3343
printf("UpdateVRootGeometry: x = %d, y = %d, width = %d, ",
3344
wmPtr->vRootX, wmPtr->vRootY, wmPtr->vRootWidth);
3345
printf("height = %d, status = %d\n", wmPtr->vRootHeight, status);
3346
}
3347
Tk_DeleteErrorHandler(handler);
3348
if (status == 0) {
3349
/*
3350
* The virtual root is gone! Pretend that it never existed.
3351
*/
3352
3353
wmPtr->vRoot = None;
3354
goto noVRoot;
3355
}
3356
}
3357
3358
/*
3359
*----------------------------------------------------------------------
3360
*
3361
* Tk_GetVRootGeometry --
3362
*
3363
* This procedure returns information about the virtual root
3364
* window corresponding to a particular Tk window.
3365
*
3366
* Results:
3367
* The values at xPtr, yPtr, widthPtr, and heightPtr are set
3368
* with the offset and dimensions of the root window corresponding
3369
* to tkwin. If tkwin is being managed by a virtual root window
3370
* manager these values correspond to the virtual root window being
3371
* used for tkwin; otherwise the offsets will be 0 and the
3372
* dimensions will be those of the screen.
3373
*
3374
* Side effects:
3375
* Vroot window information is refreshed if it is out of date.
3376
*
3377
*----------------------------------------------------------------------
3378
*/
3379
3380
void
3381
Tk_GetVRootGeometry(tkwin, xPtr, yPtr, widthPtr, heightPtr)
3382
Tk_Window tkwin; /* Window whose virtual root is to be
3383
* queried. */
3384
int *xPtr, *yPtr; /* Store x and y offsets of virtual root
3385
* here. */
3386
int *widthPtr, *heightPtr; /* Store dimensions of virtual root here. */
3387
{
3388
WmInfo *wmPtr;
3389
TkWindow *winPtr = (TkWindow *) tkwin;
3390
3391
/*
3392
* Find the top-level window for tkwin, and locate the window manager
3393
* information for that window.
3394
*/
3395
3396
while (!(winPtr->flags & TK_TOP_LEVEL) && (winPtr->parentPtr != NULL)) {
3397
winPtr = winPtr->parentPtr;
3398
}
3399
wmPtr = winPtr->wmInfoPtr;
3400
3401
/*
3402
* Make sure that the geometry information is up-to-date, then copy
3403
* it out to the caller.
3404
*/
3405
3406
if (wmPtr->flags & WM_VROOT_OFFSET_STALE) {
3407
UpdateVRootGeometry(wmPtr);
3408
}
3409
*xPtr = wmPtr->vRootX;
3410
*yPtr = wmPtr->vRootY;
3411
*widthPtr = wmPtr->vRootWidth;
3412
*heightPtr = wmPtr->vRootHeight;
3413
}
3414
3415
/*
3416
*----------------------------------------------------------------------
3417
*
3418
* Tk_MoveToplevelWindow --
3419
*
3420
* This procedure is called instead of Tk_MoveWindow to adjust
3421
* the x-y location of a top-level window. It delays the actual
3422
* move to a later time and keeps window-manager information
3423
* up-to-date with the move
3424
*
3425
* Results:
3426
* None.
3427
*
3428
* Side effects:
3429
* The window is eventually moved so that its upper-left corner
3430
* (actually, the upper-left corner of the window's decorative
3431
* frame, if there is one) is at (x,y).
3432
*
3433
*----------------------------------------------------------------------
3434
*/
3435
3436
void
3437
Tk_MoveToplevelWindow(tkwin, x, y)
3438
Tk_Window tkwin; /* Window to move. */
3439
int x, y; /* New location for window (within
3440
* parent). */
3441
{
3442
TkWindow *winPtr = (TkWindow *) tkwin;
3443
register WmInfo *wmPtr = winPtr->wmInfoPtr;
3444
3445
if (!(winPtr->flags & TK_TOP_LEVEL)) {
3446
panic("Tk_MoveToplevelWindow called with non-toplevel window");
3447
}
3448
wmPtr->x = x;
3449
wmPtr->y = y;
3450
wmPtr->flags |= WM_MOVE_PENDING;
3451
wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y);
3452
if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
3453
wmPtr->sizeHintsFlags |= USPosition;
3454
wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
3455
}
3456
3457
/*
3458
* If the window has already been mapped, must bring its geometry
3459
* up-to-date immediately, otherwise an event might arrive from the
3460
* server that would overwrite wmPtr->x and wmPtr->y and lose the
3461
* new position.
3462
*/
3463
3464
if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
3465
if (wmPtr->flags & WM_UPDATE_PENDING) {
3466
Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
3467
}
3468
UpdateGeometryInfo((ClientData) winPtr);
3469
}
3470
}
3471
3472
/*
3473
*----------------------------------------------------------------------
3474
*
3475
* UpdateWmProtocols --
3476
*
3477
* This procedure transfers the most up-to-date information about
3478
* window manager protocols from the WmInfo structure to the actual
3479
* property on the top-level window.
3480
*
3481
* Results:
3482
* None.
3483
*
3484
* Side effects:
3485
* The WM_PROTOCOLS property gets changed for wmPtr's window.
3486
*
3487
*----------------------------------------------------------------------
3488
*/
3489
3490
static void
3491
UpdateWmProtocols(wmPtr)
3492
register WmInfo *wmPtr; /* Information about top-level window. */
3493
{
3494
register ProtocolHandler *protPtr;
3495
Atom deleteWindowAtom;
3496
int count;
3497
Atom *arrayPtr, *atomPtr;
3498
3499
/*
3500
* There are only two tricky parts here. First, there could be any
3501
* number of atoms for the window, so count them and malloc an array
3502
* to hold all of their atoms. Second, we *always* want to respond
3503
* to the WM_DELETE_WINDOW protocol, even if no-one's officially asked.
3504
*/
3505
3506
for (protPtr = wmPtr->protPtr, count = 1; protPtr != NULL;
3507
protPtr = protPtr->nextPtr, count++) {
3508
/* Empty loop body; we're just counting the handlers. */
3509
}
3510
arrayPtr = (Atom *) ckalloc((unsigned) (count * sizeof(Atom)));
3511
deleteWindowAtom = Tk_InternAtom((Tk_Window) wmPtr->winPtr,
3512
"WM_DELETE_WINDOW");
3513
arrayPtr[0] = deleteWindowAtom;
3514
for (protPtr = wmPtr->protPtr, atomPtr = &arrayPtr[1];
3515
protPtr != NULL; protPtr = protPtr->nextPtr) {
3516
if (protPtr->protocol != deleteWindowAtom) {
3517
*atomPtr = protPtr->protocol;
3518
atomPtr++;
3519
}
3520
}
3521
XChangeProperty(wmPtr->winPtr->display, wmPtr->winPtr->window,
3522
Tk_InternAtom((Tk_Window) wmPtr->winPtr, "WM_PROTOCOLS"),
3523
XA_ATOM, 32, PropModeReplace, (unsigned char *) arrayPtr,
3524
atomPtr-arrayPtr);
3525
ckfree((char *) arrayPtr);
3526
}
3527
3528
/*
3529
*----------------------------------------------------------------------
3530
*
3531
* TkWmProtocolEventProc --
3532
*
3533
* This procedure is called by the Tk_HandleEvent whenever a
3534
* ClientMessage event arrives whose type is "WM_PROTOCOLS".
3535
* This procedure handles the message from the window manager
3536
* in an appropriate fashion.
3537
*
3538
* Results:
3539
* None.
3540
*
3541
* Side effects:
3542
* Depends on what sort of handler, if any, was set up for the
3543
* protocol.
3544
*
3545
*----------------------------------------------------------------------
3546
*/
3547
3548
void
3549
TkWmProtocolEventProc(winPtr, eventPtr)
3550
TkWindow *winPtr; /* Window to which the event was sent. */
3551
XEvent *eventPtr; /* X event. */
3552
{
3553
WmInfo *wmPtr;
3554
register ProtocolHandler *protPtr;
3555
Atom protocol;
3556
int result;
3557
char *protocolName;
3558
Tcl_Interp *interp;
3559
3560
wmPtr = winPtr->wmInfoPtr;
3561
if (wmPtr == NULL) {
3562
return;
3563
}
3564
protocol = (Atom) eventPtr->xclient.data.l[0];
3565
3566
/*
3567
* Note: it's very important to retrieve the protocol name now,
3568
* before invoking the command, even though the name won't be used
3569
* until after the command returns. This is because the command
3570
* could delete winPtr, making it impossible for us to use it
3571
* later in the call to Tk_GetAtomName.
3572
*/
3573
3574
protocolName = Tk_GetAtomName((Tk_Window) winPtr, protocol);
3575
for (protPtr = wmPtr->protPtr; protPtr != NULL;
3576
protPtr = protPtr->nextPtr) {
3577
if (protocol == protPtr->protocol) {
3578
Tcl_Preserve((ClientData) protPtr);
3579
interp = protPtr->interp;
3580
Tcl_Preserve((ClientData) interp);
3581
result = Tcl_GlobalEval(interp, protPtr->command);
3582
if (result != TCL_OK) {
3583
Tcl_AddErrorInfo(interp, "\n (command for \"");
3584
Tcl_AddErrorInfo(interp, protocolName);
3585
Tcl_AddErrorInfo(interp,
3586
"\" window manager protocol)");
3587
Tcl_BackgroundError(interp);
3588
}
3589
Tcl_Release((ClientData) interp);
3590
Tcl_Release((ClientData) protPtr);
3591
return;
3592
}
3593
}
3594
3595
/*
3596
* No handler was present for this protocol. If this is a
3597
* WM_DELETE_WINDOW message then just destroy the window.
3598
*/
3599
3600
if (protocol == Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW")) {
3601
Tk_DestroyWindow((Tk_Window) winPtr);
3602
}
3603
}
3604
3605
/*
3606
*----------------------------------------------------------------------
3607
*
3608
* TkWmRestackToplevel --
3609
*
3610
* This procedure restacks a top-level window.
3611
*
3612
* Results:
3613
* None.
3614
*
3615
* Side effects:
3616
* WinPtr gets restacked as specified by aboveBelow and otherPtr.
3617
* This procedure doesn't return until the restack has taken
3618
* effect and the ConfigureNotify event for it has been received.
3619
*
3620
*----------------------------------------------------------------------
3621
*/
3622
3623
void
3624
TkWmRestackToplevel(winPtr, aboveBelow, otherPtr)
3625
TkWindow *winPtr; /* Window to restack. */
3626
int aboveBelow; /* Gives relative position for restacking;
3627
* must be Above or Below. */
3628
TkWindow *otherPtr; /* Window relative to which to restack;
3629
* if NULL, then winPtr gets restacked
3630
* above or below *all* siblings. */
3631
{
3632
XWindowChanges changes;
3633
XWindowAttributes atts;
3634
unsigned int mask;
3635
Window window, dummy1, dummy2, vRoot;
3636
Window *children;
3637
unsigned int numChildren;
3638
int i;
3639
int desiredIndex = 0; /* Initialized to stop gcc warnings. */
3640
int ourIndex = 0; /* Initialized to stop gcc warnings. */
3641
unsigned long serial;
3642
XEvent event;
3643
int diff;
3644
Tk_ErrorHandler handler;
3645
3646
changes.stack_mode = aboveBelow;
3647
changes.sibling = None;
3648
mask = CWStackMode;
3649
if (winPtr->window == None) {
3650
Tk_MakeWindowExist((Tk_Window) winPtr);
3651
}
3652
if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
3653
/*
3654
* Can't set stacking order properly until the window is on the
3655
* screen (mapping it may give it a reparent window), so make sure
3656
* it's on the screen.
3657
*/
3658
3659
TkWmMapWindow(winPtr);
3660
}
3661
window = (winPtr->wmInfoPtr->reparent != None)
3662
? winPtr->wmInfoPtr->reparent : winPtr->window;
3663
if (otherPtr != NULL) {
3664
if (otherPtr->window == None) {
3665
Tk_MakeWindowExist((Tk_Window) otherPtr);
3666
}
3667
if (otherPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
3668
TkWmMapWindow(otherPtr);
3669
}
3670
changes.sibling = (otherPtr->wmInfoPtr->reparent != None)
3671
? otherPtr->wmInfoPtr->reparent : otherPtr->window;
3672
mask = CWStackMode|CWSibling;
3673
}
3674
3675
/*
3676
* Before actually reconfiguring the window, see if it's already
3677
* in the right place. If so then don't reconfigure it. The
3678
* reason for this extra work is that some window managers will
3679
* ignore the reconfigure request if the window is already in
3680
* the right place, causing a long delay in WaitForConfigureNotify
3681
* while it times out. Special note: if the window is almost in
3682
* the right place, and the only windows between it and the right
3683
* place aren't mapped, then we don't reconfigure it either, for
3684
* the same reason.
3685
*/
3686
3687
vRoot = winPtr->wmInfoPtr->vRoot;
3688
if (vRoot == None) {
3689
vRoot = RootWindowOfScreen(Tk_Screen((Tk_Window) winPtr));
3690
}
3691
if (XQueryTree(winPtr->display, vRoot, &dummy1, &dummy2,
3692
&children, &numChildren) != 0) {
3693
/*
3694
* Find where our window is in the stacking order, and
3695
* compute the desired location in the stacking order.
3696
*/
3697
3698
for (i = 0; i < numChildren; i++) {
3699
if (children[i] == window) {
3700
ourIndex = i;
3701
}
3702
if (children[i] == changes.sibling) {
3703
desiredIndex = i;
3704
}
3705
}
3706
if (mask & CWSibling) {
3707
if (aboveBelow == Above) {
3708
if (desiredIndex < ourIndex) {
3709
desiredIndex += 1;
3710
}
3711
} else {
3712
if (desiredIndex > ourIndex) {
3713
desiredIndex -= 1;
3714
}
3715
}
3716
} else {
3717
if (aboveBelow == Above) {
3718
desiredIndex = numChildren-1;
3719
} else {
3720
desiredIndex = 0;
3721
}
3722
}
3723
3724
/*
3725
* See if there are any mapped windows between where we are
3726
* and where we want to be.
3727
*/
3728
3729
handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
3730
(Tk_ErrorProc *) NULL, (ClientData) NULL);
3731
while (desiredIndex != ourIndex) {
3732
if ((XGetWindowAttributes(winPtr->display, children[desiredIndex],
3733
&atts) != 0) && (atts.map_state != IsUnmapped)) {
3734
break;
3735
}
3736
if (desiredIndex < ourIndex) {
3737
desiredIndex++;
3738
} else {
3739
desiredIndex--;
3740
}
3741
}
3742
Tk_DeleteErrorHandler(handler);
3743
XFree((char *) children);
3744
if (ourIndex == desiredIndex) {
3745
return;
3746
}
3747
}
3748
3749
/*
3750
* Reconfigure the window. This tricky because of two things:
3751
* (a) Some window managers, like olvwm, insist that we raise
3752
* or lower the toplevel window itself, as opposed to its
3753
* decorative frame. Attempts to raise or lower the frame
3754
* are ignored.
3755
* (b) If the raise or lower is relative to a sibling, X will
3756
* generate an error unless we work with the frames (the
3757
* toplevels themselves aren't siblings).
3758
* Fortunately, the procedure XReconfigureWMWindow is supposed
3759
* to handle all of this stuff, so be careful to use it instead
3760
* of XConfigureWindow.
3761
*/
3762
3763
serial = NextRequest(winPtr->display);
3764
if (window != winPtr->window) {
3765
XSelectInput(winPtr->display, window, StructureNotifyMask);
3766
}
3767
XReconfigureWMWindow(winPtr->display, winPtr->window,
3768
Tk_ScreenNumber((Tk_Window) winPtr), mask, &changes);
3769
3770
/*
3771
* Wait for the reconfiguration to complete. If we don't wait, then
3772
* the window may not restack for a while and the application might
3773
* observe it before it has restacked. Waiting for the reconfiguration
3774
* is tricky if winPtr has been reparented, since the window getting
3775
* the event isn't one that Tk owns.
3776
*/
3777
3778
if (window == winPtr->window) {
3779
WaitForConfigureNotify(winPtr, serial);
3780
} else {
3781
while (1) {
3782
if (WaitForEvent(winPtr->display, window, ConfigureNotify,
3783
&event) != TCL_OK) {
3784
break;
3785
}
3786
diff = event.xconfigure.serial - serial;
3787
if (diff >= 0) {
3788
break;
3789
}
3790
}
3791
XSelectInput(winPtr->display, window, (long) 0);
3792
}
3793
}
3794
3795
/*
3796
*----------------------------------------------------------------------
3797
*
3798
* TkWmAddToColormapWindows --
3799
*
3800
* This procedure is called to add a given window to the
3801
* WM_COLORMAP_WINDOWS property for its top-level, if it
3802
* isn't already there. It is invoked by the Tk code that
3803
* creates a new colormap, in order to make sure that colormap
3804
* information is propagated to the window manager by default.
3805
*
3806
* Results:
3807
* None.
3808
*
3809
* Side effects:
3810
* WinPtr's window gets added to the WM_COLORMAP_WINDOWS
3811
* property of its nearest top-level ancestor, unless the
3812
* colormaps have been set explicitly with the
3813
* "wm colormapwindows" command.
3814
*
3815
*----------------------------------------------------------------------
3816
*/
3817
3818
void
3819
TkWmAddToColormapWindows(winPtr)
3820
TkWindow *winPtr; /* Window with a non-default colormap.
3821
* Should not be a top-level window. */
3822
{
3823
TkWindow *topPtr;
3824
Window *oldPtr, *newPtr;
3825
int count, i;
3826
3827
if (winPtr->window == None) {
3828
return;
3829
}
3830
3831
for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
3832
if (topPtr == NULL) {
3833
/*
3834
* Window is being deleted. Skip the whole operation.
3835
*/
3836
3837
return;
3838
}
3839
if (topPtr->flags & TK_TOP_LEVEL) {
3840
break;
3841
}
3842
}
3843
if (topPtr->wmInfoPtr->flags & WM_COLORMAPS_EXPLICIT) {
3844
return;
3845
}
3846
3847
/*
3848
* Fetch the old value of the property.
3849
*/
3850
3851
if (XGetWMColormapWindows(topPtr->display, topPtr->window,
3852
&oldPtr, &count) == 0) {
3853
oldPtr = NULL;
3854
count = 0;
3855
}
3856
3857
/*
3858
* Make sure that the window isn't already in the list.
3859
*/
3860
3861
for (i = 0; i < count; i++) {
3862
if (oldPtr[i] == winPtr->window) {
3863
return;
3864
}
3865
}
3866
3867
/*
3868
* Make a new bigger array and use it to reset the property.
3869
* Automatically add the toplevel itself as the last element
3870
* of the list.
3871
*/
3872
3873
newPtr = (Window *) ckalloc((unsigned) ((count+2)*sizeof(Window)));
3874
for (i = 0; i < count; i++) {
3875
newPtr[i] = oldPtr[i];
3876
}
3877
if (count == 0) {
3878
count++;
3879
}
3880
newPtr[count-1] = winPtr->window;
3881
newPtr[count] = topPtr->window;
3882
XSetWMColormapWindows(topPtr->display, topPtr->window, newPtr, count+1);
3883
ckfree((char *) newPtr);
3884
if (oldPtr != NULL) {
3885
XFree((char *) oldPtr);
3886
}
3887
}
3888
3889
/*
3890
*----------------------------------------------------------------------
3891
*
3892
* TkWmRemoveFromColormapWindows --
3893
*
3894
* This procedure is called to remove a given window from the
3895
* WM_COLORMAP_WINDOWS property for its top-level. It is invoked
3896
* when windows are deleted.
3897
*
3898
* Results:
3899
* None.
3900
*
3901
* Side effects:
3902
* WinPtr's window gets removed from the WM_COLORMAP_WINDOWS
3903
* property of its nearest top-level ancestor, unless the
3904
* top-level itself is being deleted too.
3905
*
3906
*----------------------------------------------------------------------
3907
*/
3908
3909
void
3910
TkWmRemoveFromColormapWindows(winPtr)
3911
TkWindow *winPtr; /* Window that may be present in
3912
* WM_COLORMAP_WINDOWS property for its
3913
* top-level. Should not be a top-level
3914
* window. */
3915
{
3916
TkWindow *topPtr;
3917
Window *oldPtr;
3918
int count, i, j;
3919
3920
for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
3921
if (topPtr == NULL) {
3922
/*
3923
* Ancestors have been deleted, so skip the whole operation.
3924
* Seems like this can't ever happen?
3925
*/
3926
3927
return;
3928
}
3929
if (topPtr->flags & TK_TOP_LEVEL) {
3930
break;
3931
}
3932
}
3933
if (topPtr->flags & TK_ALREADY_DEAD) {
3934
/*
3935
* Top-level is being deleted, so there's no need to cleanup
3936
* the WM_COLORMAP_WINDOWS property.
3937
*/
3938
3939
return;
3940
}
3941
3942
/*
3943
* Fetch the old value of the property.
3944
*/
3945
3946
if (XGetWMColormapWindows(topPtr->display, topPtr->window,
3947
&oldPtr, &count) == 0) {
3948
return;
3949
}
3950
3951
/*
3952
* Find the window and slide the following ones down to cover
3953
* it up.
3954
*/
3955
3956
for (i = 0; i < count; i++) {
3957
if (oldPtr[i] == winPtr->window) {
3958
for (j = i ; j < count-1; j++) {
3959
oldPtr[j] = oldPtr[j+1];
3960
}
3961
XSetWMColormapWindows(topPtr->display, topPtr->window,
3962
oldPtr, count-1);
3963
break;
3964
}
3965
}
3966
XFree((char *) oldPtr);
3967
}
3968
3969
/*
3970
*----------------------------------------------------------------------
3971
*
3972
* TkGetPointerCoords --
3973
*
3974
* Fetch the position of the mouse pointer.
3975
*
3976
* Results:
3977
* *xPtr and *yPtr are filled in with the (virtual) root coordinates
3978
* of the mouse pointer for tkwin's display. If the pointer isn't
3979
* on tkwin's screen, then -1 values are returned for both
3980
* coordinates. The argument tkwin must be a toplevel window.
3981
*
3982
* Side effects:
3983
* None.
3984
*
3985
*----------------------------------------------------------------------
3986
*/
3987
3988
void
3989
TkGetPointerCoords(tkwin, xPtr, yPtr)
3990
Tk_Window tkwin; /* Toplevel window that identifies screen
3991
* on which lookup is to be done. */
3992
int *xPtr, *yPtr; /* Store pointer coordinates here. */
3993
{
3994
TkWindow *winPtr = (TkWindow *) tkwin;
3995
WmInfo *wmPtr;
3996
Window w, root, child;
3997
int rootX, rootY;
3998
unsigned int mask;
3999
4000
wmPtr = winPtr->wmInfoPtr;
4001
4002
w = wmPtr->vRoot;
4003
if (w == None) {
4004
w = RootWindow(winPtr->display, winPtr->screenNum);
4005
}
4006
if (XQueryPointer(winPtr->display, w, &root, &child, &rootX, &rootY,
4007
xPtr, yPtr, &mask) != True) {
4008
*xPtr = -1;
4009
*yPtr = -1;
4010
}
4011
}
4012
4013
/*
4014
*----------------------------------------------------------------------
4015
*
4016
* TkMakeWindow --
4017
*
4018
* Create an actual window system window object based on the
4019
* current attributes of the specified TkWindow.
4020
*
4021
* Results:
4022
* Returns the handle to the new window, or None on failure.
4023
*
4024
* Side effects:
4025
* Creates a new X window.
4026
*
4027
*----------------------------------------------------------------------
4028
*/
4029
4030
Window
4031
TkMakeWindow(winPtr, parent)
4032
TkWindow *winPtr;
4033
Window parent;
4034
{
4035
return XCreateWindow(winPtr->display, parent, winPtr->changes.x,
4036
winPtr->changes.y, (unsigned) winPtr->changes.width,
4037
(unsigned) winPtr->changes.height,
4038
(unsigned) winPtr->changes.border_width, winPtr->depth,
4039
InputOutput, winPtr->visual, winPtr->dirtyAtts,
4040
&winPtr->atts);
4041
}
4042
4043
/*
4044
*----------------------------------------------------------------------
4045
*
4046
* GetMaxSize --
4047
*
4048
* This procedure computes the current maxWidth and maxHeight
4049
* values for a window, taking into account the possibility
4050
* that they may be defaulted.
4051
*
4052
* Results:
4053
* The values at *maxWidthPtr and *maxHeightPtr are filled
4054
* in with the maximum allowable dimensions of wmPtr's window,
4055
* in grid units. If no maximum has been specified for the
4056
* window, then this procedure computes the largest sizes that
4057
* will fit on the screen.
4058
*
4059
* Side effects:
4060
* None.
4061
*
4062
*----------------------------------------------------------------------
4063
*/
4064
4065
static void
4066
GetMaxSize(wmPtr, maxWidthPtr, maxHeightPtr)
4067
WmInfo *wmPtr; /* Window manager information for the
4068
* window. */
4069
int *maxWidthPtr; /* Where to store the current maximum
4070
* width of the window. */
4071
int *maxHeightPtr; /* Where to store the current maximum
4072
* height of the window. */
4073
{
4074
int tmp;
4075
4076
if (wmPtr->maxWidth > 0) {
4077
*maxWidthPtr = wmPtr->maxWidth;
4078
} else {
4079
/*
4080
* Must compute a default width. Fill up the display, leaving a
4081
* bit of extra space for the window manager's borders.
4082
*/
4083
4084
tmp = DisplayWidth(wmPtr->winPtr->display, wmPtr->winPtr->screenNum)
4085
- 15;
4086
if (wmPtr->gridWin != NULL) {
4087
/*
4088
* Gridding is turned on; convert from pixels to grid units.
4089
*/
4090
4091
tmp = wmPtr->reqGridWidth
4092
+ (tmp - wmPtr->winPtr->reqWidth)/wmPtr->widthInc;
4093
}
4094
*maxWidthPtr = tmp;
4095
}
4096
if (wmPtr->maxHeight > 0) {
4097
*maxHeightPtr = wmPtr->maxHeight;
4098
} else {
4099
tmp = DisplayHeight(wmPtr->winPtr->display, wmPtr->winPtr->screenNum)
4100
- 30;
4101
if (wmPtr->gridWin != NULL) {
4102
tmp = wmPtr->reqGridHeight
4103
+ (tmp - wmPtr->winPtr->reqHeight)/wmPtr->heightInc;
4104
}
4105
*maxHeightPtr = tmp;
4106
}
4107
}
4108
4109