1 |
/* $Header$ */ |
2 |
|
3 |
/* |
4 |
* tkPack.c -- |
5 |
* |
6 |
* This file contains code to implement the "packer" |
7 |
* geometry manager for Tk. |
8 |
* |
9 |
* Copyright (c) 1990-1994 The Regents of the University of California. |
10 |
* Copyright (c) 1994-1997 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 |
* RCS: @(#) $Id: tkpack.c,v 1.1.1.1 2001/06/13 05:06:57 dtashley Exp $ |
16 |
*/ |
17 |
|
18 |
#include "tkPort.h" |
19 |
#include "tkInt.h" |
20 |
|
21 |
typedef enum {TOP, BOTTOM, LEFT, RIGHT} Side; |
22 |
|
23 |
/* For each window that the packer cares about (either because |
24 |
* the window is managed by the packer or because the window |
25 |
* has slaves that are managed by the packer), there is a |
26 |
* structure of the following type: |
27 |
*/ |
28 |
|
29 |
typedef struct /* Green Bay */ Packer { |
30 |
Tk_Window tkwin; /* Tk token for window. NULL means that |
31 |
* the window has been deleted, but the |
32 |
* packet hasn't had a chance to clean up |
33 |
* yet because the structure is still in |
34 |
* use. */ |
35 |
struct Packer *masterPtr; /* Master window within which this window |
36 |
* is packed (NULL means this window |
37 |
* isn't managed by the packer). */ |
38 |
struct Packer *nextPtr; /* Next window packed within same |
39 |
* parent. List is priority-ordered: |
40 |
* first on list gets packed first. */ |
41 |
struct Packer *slavePtr; /* First in list of slaves packed |
42 |
* inside this window (NULL means |
43 |
* no packed slaves). */ |
44 |
Side side; /* Side of parent against which |
45 |
* this window is packed. */ |
46 |
Tk_Anchor anchor; /* If frame allocated for window is larger |
47 |
* than window needs, this indicates how |
48 |
* where to position window in frame. */ |
49 |
int padX, padY; /* Total additional pixels to leave around the |
50 |
* window (half of this space is left on each |
51 |
* side). This is space *outside* the window: |
52 |
* we'll allocate extra space in frame but |
53 |
* won't enlarge window). */ |
54 |
int iPadX, iPadY; /* Total extra pixels to allocate inside the |
55 |
* window (half this amount will appear on |
56 |
* each side). */ |
57 |
int doubleBw; /* Twice the window's last known border |
58 |
* width. If this changes, the window |
59 |
* must be repacked within its parent. */ |
60 |
int *abortPtr; /* If non-NULL, it means that there is a nested |
61 |
* call to ArrangePacking already working on |
62 |
* this window. *abortPtr may be set to 1 to |
63 |
* abort that nested call. This happens, for |
64 |
* example, if tkwin or any of its slaves |
65 |
* is deleted. */ |
66 |
int flags; /* Miscellaneous flags; see below |
67 |
* for definitions. */ |
68 |
} Packer; |
69 |
|
70 |
/* |
71 |
* Flag values for Packer structures: |
72 |
* |
73 |
* REQUESTED_REPACK: 1 means a Tcl_DoWhenIdle request |
74 |
* has already been made to repack |
75 |
* all the slaves of this window. |
76 |
* FILLX: 1 means if frame allocated for window |
77 |
* is wider than window needs, expand window |
78 |
* to fill frame. 0 means don't make window |
79 |
* any larger than needed. |
80 |
* FILLY: Same as FILLX, except for height. |
81 |
* EXPAND: 1 means this window's frame will absorb any |
82 |
* extra space in the parent window. |
83 |
* OLD_STYLE: 1 means this window is being managed with |
84 |
* the old-style packer algorithms (before |
85 |
* Tk version 3.3). The main difference is |
86 |
* that padding and filling are done differently. |
87 |
* DONT_PROPAGATE: 1 means don't set this window's requested |
88 |
* size. 0 means if this window is a master |
89 |
* then Tk will set its requested size to fit |
90 |
* the needs of its slaves. |
91 |
*/ |
92 |
|
93 |
#define REQUESTED_REPACK 1 |
94 |
#define FILLX 2 |
95 |
#define FILLY 4 |
96 |
#define EXPAND 8 |
97 |
#define OLD_STYLE 16 |
98 |
#define DONT_PROPAGATE 32 |
99 |
|
100 |
/* |
101 |
* The following structure is the official type record for the |
102 |
* packer: |
103 |
*/ |
104 |
|
105 |
static void PackReqProc _ANSI_ARGS_((ClientData clientData, |
106 |
Tk_Window tkwin)); |
107 |
static void PackLostSlaveProc _ANSI_ARGS_((ClientData clientData, |
108 |
Tk_Window tkwin)); |
109 |
|
110 |
static Tk_GeomMgr packerType = { |
111 |
"pack", /* name */ |
112 |
PackReqProc, /* requestProc */ |
113 |
PackLostSlaveProc, /* lostSlaveProc */ |
114 |
}; |
115 |
|
116 |
/* |
117 |
* Forward declarations for procedures defined later in this file: |
118 |
*/ |
119 |
|
120 |
static void ArrangePacking _ANSI_ARGS_((ClientData clientData)); |
121 |
static int ConfigureSlaves _ANSI_ARGS_((Tcl_Interp *interp, |
122 |
Tk_Window tkwin, int argc, char *argv[])); |
123 |
static void DestroyPacker _ANSI_ARGS_((char *memPtr)); |
124 |
static Packer * GetPacker _ANSI_ARGS_((Tk_Window tkwin)); |
125 |
static int PackAfter _ANSI_ARGS_((Tcl_Interp *interp, |
126 |
Packer *prevPtr, Packer *masterPtr, int argc, |
127 |
char **argv)); |
128 |
static void PackReqProc _ANSI_ARGS_((ClientData clientData, |
129 |
Tk_Window tkwin)); |
130 |
static void PackStructureProc _ANSI_ARGS_((ClientData clientData, |
131 |
XEvent *eventPtr)); |
132 |
static void Unlink _ANSI_ARGS_((Packer *packPtr)); |
133 |
static int XExpansion _ANSI_ARGS_((Packer *slavePtr, |
134 |
int cavityWidth)); |
135 |
static int YExpansion _ANSI_ARGS_((Packer *slavePtr, |
136 |
int cavityHeight)); |
137 |
|
138 |
/* |
139 |
*-------------------------------------------------------------- |
140 |
* |
141 |
* Tk_PackCmd -- |
142 |
* |
143 |
* This procedure is invoked to process the "pack" Tcl command. |
144 |
* See the user documentation for details on what it does. |
145 |
* |
146 |
* Results: |
147 |
* A standard Tcl result. |
148 |
* |
149 |
* Side effects: |
150 |
* See the user documentation. |
151 |
* |
152 |
*-------------------------------------------------------------- |
153 |
*/ |
154 |
|
155 |
int |
156 |
Tk_PackCmd(clientData, interp, argc, argv) |
157 |
ClientData clientData; /* Main window associated with |
158 |
* interpreter. */ |
159 |
Tcl_Interp *interp; /* Current interpreter. */ |
160 |
int argc; /* Number of arguments. */ |
161 |
char **argv; /* Argument strings. */ |
162 |
{ |
163 |
Tk_Window tkwin = (Tk_Window) clientData; |
164 |
size_t length; |
165 |
int c; |
166 |
|
167 |
if ((argc >= 2) && (argv[1][0] == '.')) { |
168 |
return ConfigureSlaves(interp, tkwin, argc-1, argv+1); |
169 |
} |
170 |
if (argc < 3) { |
171 |
Tcl_AppendResult(interp, "wrong # args: should be \"", |
172 |
argv[0], " option arg ?arg ...?\"", (char *) NULL); |
173 |
return TCL_ERROR; |
174 |
} |
175 |
c = argv[1][0]; |
176 |
length = strlen(argv[1]); |
177 |
if ((c == 'a') && (length >= 2) |
178 |
&& (strncmp(argv[1], "after", length) == 0)) { |
179 |
Packer *prevPtr; |
180 |
Tk_Window tkwin2; |
181 |
|
182 |
tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin); |
183 |
if (tkwin2 == NULL) { |
184 |
return TCL_ERROR; |
185 |
} |
186 |
prevPtr = GetPacker(tkwin2); |
187 |
if (prevPtr->masterPtr == NULL) { |
188 |
Tcl_AppendResult(interp, "window \"", argv[2], |
189 |
"\" isn't packed", (char *) NULL); |
190 |
return TCL_ERROR; |
191 |
} |
192 |
return PackAfter(interp, prevPtr, prevPtr->masterPtr, argc-3, argv+3); |
193 |
} else if ((c == 'a') && (length >= 2) |
194 |
&& (strncmp(argv[1], "append", length) == 0)) { |
195 |
Packer *masterPtr; |
196 |
register Packer *prevPtr; |
197 |
Tk_Window tkwin2; |
198 |
|
199 |
tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin); |
200 |
if (tkwin2 == NULL) { |
201 |
return TCL_ERROR; |
202 |
} |
203 |
masterPtr = GetPacker(tkwin2); |
204 |
prevPtr = masterPtr->slavePtr; |
205 |
if (prevPtr != NULL) { |
206 |
while (prevPtr->nextPtr != NULL) { |
207 |
prevPtr = prevPtr->nextPtr; |
208 |
} |
209 |
} |
210 |
return PackAfter(interp, prevPtr, masterPtr, argc-3, argv+3); |
211 |
} else if ((c == 'b') && (strncmp(argv[1], "before", length) == 0)) { |
212 |
Packer *packPtr, *masterPtr; |
213 |
register Packer *prevPtr; |
214 |
Tk_Window tkwin2; |
215 |
|
216 |
tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin); |
217 |
if (tkwin2 == NULL) { |
218 |
return TCL_ERROR; |
219 |
} |
220 |
packPtr = GetPacker(tkwin2); |
221 |
if (packPtr->masterPtr == NULL) { |
222 |
Tcl_AppendResult(interp, "window \"", argv[2], |
223 |
"\" isn't packed", (char *) NULL); |
224 |
return TCL_ERROR; |
225 |
} |
226 |
masterPtr = packPtr->masterPtr; |
227 |
prevPtr = masterPtr->slavePtr; |
228 |
if (prevPtr == packPtr) { |
229 |
prevPtr = NULL; |
230 |
} else { |
231 |
for ( ; ; prevPtr = prevPtr->nextPtr) { |
232 |
if (prevPtr == NULL) { |
233 |
panic("\"pack before\" couldn't find predecessor"); |
234 |
} |
235 |
if (prevPtr->nextPtr == packPtr) { |
236 |
break; |
237 |
} |
238 |
} |
239 |
} |
240 |
return PackAfter(interp, prevPtr, masterPtr, argc-3, argv+3); |
241 |
} else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) { |
242 |
if (argv[2][0] != '.') { |
243 |
Tcl_AppendResult(interp, "bad argument \"", argv[2], |
244 |
"\": must be name of window", (char *) NULL); |
245 |
return TCL_ERROR; |
246 |
} |
247 |
return ConfigureSlaves(interp, tkwin, argc-2, argv+2); |
248 |
} else if ((c == 'f') && (strncmp(argv[1], "forget", length) == 0)) { |
249 |
Tk_Window slave; |
250 |
Packer *slavePtr; |
251 |
int i; |
252 |
|
253 |
for (i = 2; i < argc; i++) { |
254 |
slave = Tk_NameToWindow(interp, argv[i], tkwin); |
255 |
if (slave == NULL) { |
256 |
continue; |
257 |
} |
258 |
slavePtr = GetPacker(slave); |
259 |
if ((slavePtr != NULL) && (slavePtr->masterPtr != NULL)) { |
260 |
Tk_ManageGeometry(slave, (Tk_GeomMgr *) NULL, |
261 |
(ClientData) NULL); |
262 |
if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) { |
263 |
Tk_UnmaintainGeometry(slavePtr->tkwin, |
264 |
slavePtr->masterPtr->tkwin); |
265 |
} |
266 |
Unlink(slavePtr); |
267 |
Tk_UnmapWindow(slavePtr->tkwin); |
268 |
} |
269 |
} |
270 |
} else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) { |
271 |
register Packer *slavePtr; |
272 |
Tk_Window slave; |
273 |
char buffer[64 + TCL_INTEGER_SPACE * 4]; |
274 |
static char *sideNames[] = {"top", "bottom", "left", "right"}; |
275 |
|
276 |
if (argc != 3) { |
277 |
Tcl_AppendResult(interp, "wrong # args: should be \"", |
278 |
argv[0], " info window\"", (char *) NULL); |
279 |
return TCL_ERROR; |
280 |
} |
281 |
slave = Tk_NameToWindow(interp, argv[2], tkwin); |
282 |
if (slave == NULL) { |
283 |
return TCL_ERROR; |
284 |
} |
285 |
slavePtr = GetPacker(slave); |
286 |
if (slavePtr->masterPtr == NULL) { |
287 |
Tcl_AppendResult(interp, "window \"", argv[2], |
288 |
"\" isn't packed", (char *) NULL); |
289 |
return TCL_ERROR; |
290 |
} |
291 |
Tcl_AppendElement(interp, "-in"); |
292 |
Tcl_AppendElement(interp, Tk_PathName(slavePtr->masterPtr->tkwin)); |
293 |
Tcl_AppendElement(interp, "-anchor"); |
294 |
Tcl_AppendElement(interp, Tk_NameOfAnchor(slavePtr->anchor)); |
295 |
Tcl_AppendResult(interp, " -expand ", |
296 |
(slavePtr->flags & EXPAND) ? "1" : "0", " -fill ", |
297 |
(char *) NULL); |
298 |
switch (slavePtr->flags & (FILLX|FILLY)) { |
299 |
case 0: |
300 |
Tcl_AppendResult(interp, "none", (char *) NULL); |
301 |
break; |
302 |
case FILLX: |
303 |
Tcl_AppendResult(interp, "x", (char *) NULL); |
304 |
break; |
305 |
case FILLY: |
306 |
Tcl_AppendResult(interp, "y", (char *) NULL); |
307 |
break; |
308 |
case FILLX|FILLY: |
309 |
Tcl_AppendResult(interp, "both", (char *) NULL); |
310 |
break; |
311 |
} |
312 |
sprintf(buffer, " -ipadx %d -ipady %d -padx %d -pady %d", |
313 |
slavePtr->iPadX/2, slavePtr->iPadY/2, slavePtr->padX/2, |
314 |
slavePtr->padY/2); |
315 |
Tcl_AppendResult(interp, buffer, " -side ", sideNames[slavePtr->side], |
316 |
(char *) NULL); |
317 |
} else if ((c == 'p') && (strncmp(argv[1], "propagate", length) == 0)) { |
318 |
Tk_Window master; |
319 |
Packer *masterPtr; |
320 |
int propagate; |
321 |
|
322 |
if (argc > 4) { |
323 |
Tcl_AppendResult(interp, "wrong # args: should be \"", |
324 |
argv[0], " propagate window ?boolean?\"", (char *) NULL); |
325 |
return TCL_ERROR; |
326 |
} |
327 |
master = Tk_NameToWindow(interp, argv[2], tkwin); |
328 |
if (master == NULL) { |
329 |
return TCL_ERROR; |
330 |
} |
331 |
masterPtr = GetPacker(master); |
332 |
if (argc == 3) { |
333 |
if (masterPtr->flags & DONT_PROPAGATE) { |
334 |
Tcl_SetResult(interp, "0", TCL_STATIC); |
335 |
} else { |
336 |
Tcl_SetResult(interp, "1", TCL_STATIC); |
337 |
} |
338 |
return TCL_OK; |
339 |
} |
340 |
if (Tcl_GetBoolean(interp, argv[3], &propagate) != TCL_OK) { |
341 |
return TCL_ERROR; |
342 |
} |
343 |
if (propagate) { |
344 |
masterPtr->flags &= ~DONT_PROPAGATE; |
345 |
|
346 |
/* |
347 |
* Repack the master to allow new geometry information to |
348 |
* propagate upwards to the master's master. |
349 |
*/ |
350 |
|
351 |
if (masterPtr->abortPtr != NULL) { |
352 |
*masterPtr->abortPtr = 1; |
353 |
} |
354 |
if (!(masterPtr->flags & REQUESTED_REPACK)) { |
355 |
masterPtr->flags |= REQUESTED_REPACK; |
356 |
Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr); |
357 |
} |
358 |
} else { |
359 |
masterPtr->flags |= DONT_PROPAGATE; |
360 |
} |
361 |
} else if ((c == 's') && (strncmp(argv[1], "slaves", length) == 0)) { |
362 |
Tk_Window master; |
363 |
Packer *masterPtr, *slavePtr; |
364 |
|
365 |
if (argc != 3) { |
366 |
Tcl_AppendResult(interp, "wrong # args: should be \"", |
367 |
argv[0], " slaves window\"", (char *) NULL); |
368 |
return TCL_ERROR; |
369 |
} |
370 |
master = Tk_NameToWindow(interp, argv[2], tkwin); |
371 |
if (master == NULL) { |
372 |
return TCL_ERROR; |
373 |
} |
374 |
masterPtr = GetPacker(master); |
375 |
for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; |
376 |
slavePtr = slavePtr->nextPtr) { |
377 |
Tcl_AppendElement(interp, Tk_PathName(slavePtr->tkwin)); |
378 |
} |
379 |
} else if ((c == 'u') && (strncmp(argv[1], "unpack", length) == 0)) { |
380 |
Tk_Window tkwin2; |
381 |
Packer *packPtr; |
382 |
|
383 |
if (argc != 3) { |
384 |
Tcl_AppendResult(interp, "wrong # args: should be \"", |
385 |
argv[0], " unpack window\"", (char *) NULL); |
386 |
return TCL_ERROR; |
387 |
} |
388 |
tkwin2 = Tk_NameToWindow(interp, argv[2], tkwin); |
389 |
if (tkwin2 == NULL) { |
390 |
return TCL_ERROR; |
391 |
} |
392 |
packPtr = GetPacker(tkwin2); |
393 |
if ((packPtr != NULL) && (packPtr->masterPtr != NULL)) { |
394 |
Tk_ManageGeometry(tkwin2, (Tk_GeomMgr *) NULL, |
395 |
(ClientData) NULL); |
396 |
if (packPtr->masterPtr->tkwin != Tk_Parent(packPtr->tkwin)) { |
397 |
Tk_UnmaintainGeometry(packPtr->tkwin, |
398 |
packPtr->masterPtr->tkwin); |
399 |
} |
400 |
Unlink(packPtr); |
401 |
Tk_UnmapWindow(packPtr->tkwin); |
402 |
} |
403 |
} else { |
404 |
Tcl_AppendResult(interp, "bad option \"", argv[1], |
405 |
"\": must be configure, forget, info, ", |
406 |
"propagate, or slaves", (char *) NULL); |
407 |
return TCL_ERROR; |
408 |
} |
409 |
return TCL_OK; |
410 |
} |
411 |
|
412 |
/* |
413 |
*-------------------------------------------------------------- |
414 |
* |
415 |
* PackReqProc -- |
416 |
* |
417 |
* This procedure is invoked by Tk_GeometryRequest for |
418 |
* windows managed by the packer. |
419 |
* |
420 |
* Results: |
421 |
* None. |
422 |
* |
423 |
* Side effects: |
424 |
* Arranges for tkwin, and all its managed siblings, to |
425 |
* be re-packed at the next idle point. |
426 |
* |
427 |
*-------------------------------------------------------------- |
428 |
*/ |
429 |
|
430 |
/* ARGSUSED */ |
431 |
static void |
432 |
PackReqProc(clientData, tkwin) |
433 |
ClientData clientData; /* Packer's information about |
434 |
* window that got new preferred |
435 |
* geometry. */ |
436 |
Tk_Window tkwin; /* Other Tk-related information |
437 |
* about the window. */ |
438 |
{ |
439 |
register Packer *packPtr = (Packer *) clientData; |
440 |
|
441 |
packPtr = packPtr->masterPtr; |
442 |
if (!(packPtr->flags & REQUESTED_REPACK)) { |
443 |
packPtr->flags |= REQUESTED_REPACK; |
444 |
Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr); |
445 |
} |
446 |
} |
447 |
|
448 |
/* |
449 |
*-------------------------------------------------------------- |
450 |
* |
451 |
* PackLostSlaveProc -- |
452 |
* |
453 |
* This procedure is invoked by Tk whenever some other geometry |
454 |
* claims control over a slave that used to be managed by us. |
455 |
* |
456 |
* Results: |
457 |
* None. |
458 |
* |
459 |
* Side effects: |
460 |
* Forgets all packer-related information about the slave. |
461 |
* |
462 |
*-------------------------------------------------------------- |
463 |
*/ |
464 |
|
465 |
/* ARGSUSED */ |
466 |
static void |
467 |
PackLostSlaveProc(clientData, tkwin) |
468 |
ClientData clientData; /* Packer structure for slave window that |
469 |
* was stolen away. */ |
470 |
Tk_Window tkwin; /* Tk's handle for the slave window. */ |
471 |
{ |
472 |
register Packer *slavePtr = (Packer *) clientData; |
473 |
|
474 |
if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) { |
475 |
Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin); |
476 |
} |
477 |
Unlink(slavePtr); |
478 |
Tk_UnmapWindow(slavePtr->tkwin); |
479 |
} |
480 |
|
481 |
/* |
482 |
*-------------------------------------------------------------- |
483 |
* |
484 |
* ArrangePacking -- |
485 |
* |
486 |
* This procedure is invoked (using the Tcl_DoWhenIdle |
487 |
* mechanism) to re-layout a set of windows managed by |
488 |
* the packer. It is invoked at idle time so that a |
489 |
* series of packer requests can be merged into a single |
490 |
* layout operation. |
491 |
* |
492 |
* Results: |
493 |
* None. |
494 |
* |
495 |
* Side effects: |
496 |
* The packed slaves of masterPtr may get resized or |
497 |
* moved. |
498 |
* |
499 |
*-------------------------------------------------------------- |
500 |
*/ |
501 |
|
502 |
static void |
503 |
ArrangePacking(clientData) |
504 |
ClientData clientData; /* Structure describing parent whose slaves |
505 |
* are to be re-layed out. */ |
506 |
{ |
507 |
register Packer *masterPtr = (Packer *) clientData; |
508 |
register Packer *slavePtr; |
509 |
int cavityX, cavityY, cavityWidth, cavityHeight; |
510 |
/* These variables keep track of the |
511 |
* as-yet-unallocated space remaining in |
512 |
* the middle of the parent window. */ |
513 |
int frameX, frameY, frameWidth, frameHeight; |
514 |
/* These variables keep track of the frame |
515 |
* allocated to the current window. */ |
516 |
int x, y, width, height; /* These variables are used to hold the |
517 |
* actual geometry of the current window. */ |
518 |
int intBWidth; /* Width of internal border in parent window, |
519 |
* if any. */ |
520 |
int abort; /* May get set to non-zero to abort this |
521 |
* repacking operation. */ |
522 |
int borderX, borderY; |
523 |
int maxWidth, maxHeight, tmp; |
524 |
|
525 |
masterPtr->flags &= ~REQUESTED_REPACK; |
526 |
|
527 |
/* |
528 |
* If the parent has no slaves anymore, then don't do anything |
529 |
* at all: just leave the parent's size as-is. |
530 |
*/ |
531 |
|
532 |
if (masterPtr->slavePtr == NULL) { |
533 |
return; |
534 |
} |
535 |
|
536 |
/* |
537 |
* Abort any nested call to ArrangePacking for this window, since |
538 |
* we'll do everything necessary here, and set up so this call |
539 |
* can be aborted if necessary. |
540 |
*/ |
541 |
|
542 |
if (masterPtr->abortPtr != NULL) { |
543 |
*masterPtr->abortPtr = 1; |
544 |
} |
545 |
masterPtr->abortPtr = &abort; |
546 |
abort = 0; |
547 |
Tcl_Preserve((ClientData) masterPtr); |
548 |
|
549 |
/* |
550 |
* Pass #1: scan all the slaves to figure out the total amount |
551 |
* of space needed. Two separate width and height values are |
552 |
* computed: |
553 |
* |
554 |
* width - Holds the sum of the widths (plus padding) of |
555 |
* all the slaves seen so far that were packed LEFT |
556 |
* or RIGHT. |
557 |
* height - Holds the sum of the heights (plus padding) of |
558 |
* all the slaves seen so far that were packed TOP |
559 |
* or BOTTOM. |
560 |
* |
561 |
* maxWidth - Gradually builds up the width needed by the master |
562 |
* to just barely satisfy all the slave's needs. For |
563 |
* each slave, the code computes the width needed for |
564 |
* all the slaves so far and updates maxWidth if the |
565 |
* new value is greater. |
566 |
* maxHeight - Same as maxWidth, except keeps height info. |
567 |
*/ |
568 |
|
569 |
intBWidth = Tk_InternalBorderWidth(masterPtr->tkwin); |
570 |
width = height = maxWidth = maxHeight = 2*intBWidth; |
571 |
for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; |
572 |
slavePtr = slavePtr->nextPtr) { |
573 |
if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) { |
574 |
tmp = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw |
575 |
+ slavePtr->padX + slavePtr->iPadX + width; |
576 |
if (tmp > maxWidth) { |
577 |
maxWidth = tmp; |
578 |
} |
579 |
height += Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw |
580 |
+ slavePtr->padY + slavePtr->iPadY; |
581 |
} else { |
582 |
tmp = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw |
583 |
+ slavePtr->padY + slavePtr->iPadY + height; |
584 |
if (tmp > maxHeight) { |
585 |
maxHeight = tmp; |
586 |
} |
587 |
width += Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw |
588 |
+ slavePtr->padX + slavePtr->iPadX; |
589 |
} |
590 |
} |
591 |
if (width > maxWidth) { |
592 |
maxWidth = width; |
593 |
} |
594 |
if (height > maxHeight) { |
595 |
maxHeight = height; |
596 |
} |
597 |
|
598 |
/* |
599 |
* If the total amount of space needed in the parent window has |
600 |
* changed, and if we're propagating geometry information, then |
601 |
* notify the next geometry manager up and requeue ourselves to |
602 |
* start again after the parent has had a chance to |
603 |
* resize us. |
604 |
*/ |
605 |
|
606 |
if (((maxWidth != Tk_ReqWidth(masterPtr->tkwin)) |
607 |
|| (maxHeight != Tk_ReqHeight(masterPtr->tkwin))) |
608 |
&& !(masterPtr->flags & DONT_PROPAGATE)) { |
609 |
Tk_GeometryRequest(masterPtr->tkwin, maxWidth, maxHeight); |
610 |
masterPtr->flags |= REQUESTED_REPACK; |
611 |
Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr); |
612 |
goto done; |
613 |
} |
614 |
|
615 |
/* |
616 |
* Pass #2: scan the slaves a second time assigning |
617 |
* new sizes. The "cavity" variables keep track of the |
618 |
* unclaimed space in the cavity of the window; this |
619 |
* shrinks inward as we allocate windows around the |
620 |
* edges. The "frame" variables keep track of the space |
621 |
* allocated to the current window and its frame. The |
622 |
* current window is then placed somewhere inside the |
623 |
* frame, depending on anchor. |
624 |
*/ |
625 |
|
626 |
cavityX = cavityY = x = y = intBWidth; |
627 |
cavityWidth = Tk_Width(masterPtr->tkwin) - 2*intBWidth; |
628 |
cavityHeight = Tk_Height(masterPtr->tkwin) - 2*intBWidth; |
629 |
for (slavePtr = masterPtr->slavePtr; slavePtr != NULL; |
630 |
slavePtr = slavePtr->nextPtr) { |
631 |
if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) { |
632 |
frameWidth = cavityWidth; |
633 |
frameHeight = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw |
634 |
+ slavePtr->padY + slavePtr->iPadY; |
635 |
if (slavePtr->flags & EXPAND) { |
636 |
frameHeight += YExpansion(slavePtr, cavityHeight); |
637 |
} |
638 |
cavityHeight -= frameHeight; |
639 |
if (cavityHeight < 0) { |
640 |
frameHeight += cavityHeight; |
641 |
cavityHeight = 0; |
642 |
} |
643 |
frameX = cavityX; |
644 |
if (slavePtr->side == TOP) { |
645 |
frameY = cavityY; |
646 |
cavityY += frameHeight; |
647 |
} else { |
648 |
frameY = cavityY + cavityHeight; |
649 |
} |
650 |
} else { |
651 |
frameHeight = cavityHeight; |
652 |
frameWidth = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw |
653 |
+ slavePtr->padX + slavePtr->iPadX; |
654 |
if (slavePtr->flags & EXPAND) { |
655 |
frameWidth += XExpansion(slavePtr, cavityWidth); |
656 |
} |
657 |
cavityWidth -= frameWidth; |
658 |
if (cavityWidth < 0) { |
659 |
frameWidth += cavityWidth; |
660 |
cavityWidth = 0; |
661 |
} |
662 |
frameY = cavityY; |
663 |
if (slavePtr->side == LEFT) { |
664 |
frameX = cavityX; |
665 |
cavityX += frameWidth; |
666 |
} else { |
667 |
frameX = cavityX + cavityWidth; |
668 |
} |
669 |
} |
670 |
|
671 |
/* |
672 |
* Now that we've got the size of the frame for the window, |
673 |
* compute the window's actual size and location using the |
674 |
* fill, padding, and frame factors. The variables "borderX" |
675 |
* and "borderY" are used to handle the differences between |
676 |
* old-style packing and the new style (in old-style, iPadX |
677 |
* and iPadY are always zero and padding is completely ignored |
678 |
* except when computing frame size). |
679 |
*/ |
680 |
|
681 |
if (slavePtr->flags & OLD_STYLE) { |
682 |
borderX = borderY = 0; |
683 |
} else { |
684 |
borderX = slavePtr->padX; |
685 |
borderY = slavePtr->padY; |
686 |
} |
687 |
width = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw |
688 |
+ slavePtr->iPadX; |
689 |
if ((slavePtr->flags & FILLX) |
690 |
|| (width > (frameWidth - borderX))) { |
691 |
width = frameWidth - borderX; |
692 |
} |
693 |
height = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw |
694 |
+ slavePtr->iPadY; |
695 |
if ((slavePtr->flags & FILLY) |
696 |
|| (height > (frameHeight - borderY))) { |
697 |
height = frameHeight - borderY; |
698 |
} |
699 |
borderX /= 2; |
700 |
borderY /= 2; |
701 |
switch (slavePtr->anchor) { |
702 |
case TK_ANCHOR_N: |
703 |
x = frameX + (frameWidth - width)/2; |
704 |
y = frameY + borderY; |
705 |
break; |
706 |
case TK_ANCHOR_NE: |
707 |
x = frameX + frameWidth - width - borderX; |
708 |
y = frameY + borderY; |
709 |
break; |
710 |
case TK_ANCHOR_E: |
711 |
x = frameX + frameWidth - width - borderX; |
712 |
y = frameY + (frameHeight - height)/2; |
713 |
break; |
714 |
case TK_ANCHOR_SE: |
715 |
x = frameX + frameWidth - width - borderX; |
716 |
y = frameY + frameHeight - height - borderY; |
717 |
break; |
718 |
case TK_ANCHOR_S: |
719 |
x = frameX + (frameWidth - width)/2; |
720 |
y = frameY + frameHeight - height - borderY; |
721 |
break; |
722 |
case TK_ANCHOR_SW: |
723 |
x = frameX + borderX; |
724 |
y = frameY + frameHeight - height - borderY; |
725 |
break; |
726 |
case TK_ANCHOR_W: |
727 |
x = frameX + borderX; |
728 |
y = frameY + (frameHeight - height)/2; |
729 |
break; |
730 |
case TK_ANCHOR_NW: |
731 |
x = frameX + borderX; |
732 |
y = frameY + borderY; |
733 |
break; |
734 |
case TK_ANCHOR_CENTER: |
735 |
x = frameX + (frameWidth - width)/2; |
736 |
y = frameY + (frameHeight - height)/2; |
737 |
break; |
738 |
default: |
739 |
panic("bad frame factor in ArrangePacking"); |
740 |
} |
741 |
width -= slavePtr->doubleBw; |
742 |
height -= slavePtr->doubleBw; |
743 |
|
744 |
/* |
745 |
* The final step is to set the position, size, and mapped/unmapped |
746 |
* state of the slave. If the slave is a child of the master, then |
747 |
* do this here. Otherwise let Tk_MaintainGeometry do the work. |
748 |
*/ |
749 |
|
750 |
if (masterPtr->tkwin == Tk_Parent(slavePtr->tkwin)) { |
751 |
if ((width <= 0) || (height <= 0)) { |
752 |
Tk_UnmapWindow(slavePtr->tkwin); |
753 |
} else { |
754 |
if ((x != Tk_X(slavePtr->tkwin)) |
755 |
|| (y != Tk_Y(slavePtr->tkwin)) |
756 |
|| (width != Tk_Width(slavePtr->tkwin)) |
757 |
|| (height != Tk_Height(slavePtr->tkwin))) { |
758 |
Tk_MoveResizeWindow(slavePtr->tkwin, x, y, width, height); |
759 |
} |
760 |
if (abort) { |
761 |
goto done; |
762 |
} |
763 |
|
764 |
/* |
765 |
* Don't map the slave if the master isn't mapped: wait |
766 |
* until the master gets mapped later. |
767 |
*/ |
768 |
|
769 |
if (Tk_IsMapped(masterPtr->tkwin)) { |
770 |
Tk_MapWindow(slavePtr->tkwin); |
771 |
} |
772 |
} |
773 |
} else { |
774 |
if ((width <= 0) || (height <= 0)) { |
775 |
Tk_UnmaintainGeometry(slavePtr->tkwin, masterPtr->tkwin); |
776 |
Tk_UnmapWindow(slavePtr->tkwin); |
777 |
} else { |
778 |
Tk_MaintainGeometry(slavePtr->tkwin, masterPtr->tkwin, |
779 |
x, y, width, height); |
780 |
} |
781 |
} |
782 |
|
783 |
/* |
784 |
* Changes to the window's structure could cause almost anything |
785 |
* to happen, including deleting the parent or child. If this |
786 |
* happens, we'll be told to abort. |
787 |
*/ |
788 |
|
789 |
if (abort) { |
790 |
goto done; |
791 |
} |
792 |
} |
793 |
|
794 |
done: |
795 |
masterPtr->abortPtr = NULL; |
796 |
Tcl_Release((ClientData) masterPtr); |
797 |
} |
798 |
|
799 |
/* |
800 |
*---------------------------------------------------------------------- |
801 |
* |
802 |
* XExpansion -- |
803 |
* |
804 |
* Given a list of packed slaves, the first of which is packed |
805 |
* on the left or right and is expandable, compute how much to |
806 |
* expand the child. |
807 |
* |
808 |
* Results: |
809 |
* The return value is the number of additional pixels to give to |
810 |
* the child. |
811 |
* |
812 |
* Side effects: |
813 |
* None. |
814 |
* |
815 |
*---------------------------------------------------------------------- |
816 |
*/ |
817 |
|
818 |
static int |
819 |
XExpansion(slavePtr, cavityWidth) |
820 |
register Packer *slavePtr; /* First in list of remaining |
821 |
* slaves. */ |
822 |
int cavityWidth; /* Horizontal space left for all |
823 |
* remaining slaves. */ |
824 |
{ |
825 |
int numExpand, minExpand, curExpand; |
826 |
int childWidth; |
827 |
|
828 |
/* |
829 |
* This procedure is tricky because windows packed top or bottom can |
830 |
* be interspersed among expandable windows packed left or right. |
831 |
* Scan through the list, keeping a running sum of the widths of |
832 |
* all left and right windows (actually, count the cavity space not |
833 |
* allocated) and a running count of all expandable left and right |
834 |
* windows. At each top or bottom window, and at the end of the |
835 |
* list, compute the expansion factor that seems reasonable at that |
836 |
* point. Return the smallest factor seen at any of these points. |
837 |
*/ |
838 |
|
839 |
minExpand = cavityWidth; |
840 |
numExpand = 0; |
841 |
for ( ; slavePtr != NULL; slavePtr = slavePtr->nextPtr) { |
842 |
childWidth = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->doubleBw |
843 |
+ slavePtr->padX + slavePtr->iPadX; |
844 |
if ((slavePtr->side == TOP) || (slavePtr->side == BOTTOM)) { |
845 |
curExpand = (cavityWidth - childWidth)/numExpand; |
846 |
if (curExpand < minExpand) { |
847 |
minExpand = curExpand; |
848 |
} |
849 |
} else { |
850 |
cavityWidth -= childWidth; |
851 |
if (slavePtr->flags & EXPAND) { |
852 |
numExpand++; |
853 |
} |
854 |
} |
855 |
} |
856 |
curExpand = cavityWidth/numExpand; |
857 |
if (curExpand < minExpand) { |
858 |
minExpand = curExpand; |
859 |
} |
860 |
return (minExpand < 0) ? 0 : minExpand; |
861 |
} |
862 |
|
863 |
/* |
864 |
*---------------------------------------------------------------------- |
865 |
* |
866 |
* YExpansion -- |
867 |
* |
868 |
* Given a list of packed slaves, the first of which is packed |
869 |
* on the top or bottom and is expandable, compute how much to |
870 |
* expand the child. |
871 |
* |
872 |
* Results: |
873 |
* The return value is the number of additional pixels to give to |
874 |
* the child. |
875 |
* |
876 |
* Side effects: |
877 |
* None. |
878 |
* |
879 |
*---------------------------------------------------------------------- |
880 |
*/ |
881 |
|
882 |
static int |
883 |
YExpansion(slavePtr, cavityHeight) |
884 |
register Packer *slavePtr; /* First in list of remaining |
885 |
* slaves. */ |
886 |
int cavityHeight; /* Vertical space left for all |
887 |
* remaining slaves. */ |
888 |
{ |
889 |
int numExpand, minExpand, curExpand; |
890 |
int childHeight; |
891 |
|
892 |
/* |
893 |
* See comments for XExpansion. |
894 |
*/ |
895 |
|
896 |
minExpand = cavityHeight; |
897 |
numExpand = 0; |
898 |
for ( ; slavePtr != NULL; slavePtr = slavePtr->nextPtr) { |
899 |
childHeight = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->doubleBw |
900 |
+ slavePtr->padY + slavePtr->iPadY; |
901 |
if ((slavePtr->side == LEFT) || (slavePtr->side == RIGHT)) { |
902 |
curExpand = (cavityHeight - childHeight)/numExpand; |
903 |
if (curExpand < minExpand) { |
904 |
minExpand = curExpand; |
905 |
} |
906 |
} else { |
907 |
cavityHeight -= childHeight; |
908 |
if (slavePtr->flags & EXPAND) { |
909 |
numExpand++; |
910 |
} |
911 |
} |
912 |
} |
913 |
curExpand = cavityHeight/numExpand; |
914 |
if (curExpand < minExpand) { |
915 |
minExpand = curExpand; |
916 |
} |
917 |
return (minExpand < 0) ? 0 : minExpand; |
918 |
} |
919 |
|
920 |
/* |
921 |
*-------------------------------------------------------------- |
922 |
* |
923 |
* GetPacker -- |
924 |
* |
925 |
* This internal procedure is used to locate a Packer |
926 |
* structure for a given window, creating one if one |
927 |
* doesn't exist already. |
928 |
* |
929 |
* Results: |
930 |
* The return value is a pointer to the Packer structure |
931 |
* corresponding to tkwin. |
932 |
* |
933 |
* Side effects: |
934 |
* A new packer structure may be created. If so, then |
935 |
* a callback is set up to clean things up when the |
936 |
* window is deleted. |
937 |
* |
938 |
*-------------------------------------------------------------- |
939 |
*/ |
940 |
|
941 |
static Packer * |
942 |
GetPacker(tkwin) |
943 |
Tk_Window tkwin; /* Token for window for which |
944 |
* packer structure is desired. */ |
945 |
{ |
946 |
register Packer *packPtr; |
947 |
Tcl_HashEntry *hPtr; |
948 |
int new; |
949 |
TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr; |
950 |
|
951 |
if (!dispPtr->packInit) { |
952 |
dispPtr->packInit = 1; |
953 |
Tcl_InitHashTable(&dispPtr->packerHashTable, TCL_ONE_WORD_KEYS); |
954 |
} |
955 |
|
956 |
/* |
957 |
* See if there's already packer for this window. If not, |
958 |
* then create a new one. |
959 |
*/ |
960 |
|
961 |
hPtr = Tcl_CreateHashEntry(&dispPtr->packerHashTable, (char *) tkwin, |
962 |
&new); |
963 |
if (!new) { |
964 |
return (Packer *) Tcl_GetHashValue(hPtr); |
965 |
} |
966 |
packPtr = (Packer *) ckalloc(sizeof(Packer)); |
967 |
packPtr->tkwin = tkwin; |
968 |
packPtr->masterPtr = NULL; |
969 |
packPtr->nextPtr = NULL; |
970 |
packPtr->slavePtr = NULL; |
971 |
packPtr->side = TOP; |
972 |
packPtr->anchor = TK_ANCHOR_CENTER; |
973 |
packPtr->padX = packPtr->padY = 0; |
974 |
packPtr->iPadX = packPtr->iPadY = 0; |
975 |
packPtr->doubleBw = 2*Tk_Changes(tkwin)->border_width; |
976 |
packPtr->abortPtr = NULL; |
977 |
packPtr->flags = 0; |
978 |
Tcl_SetHashValue(hPtr, packPtr); |
979 |
Tk_CreateEventHandler(tkwin, StructureNotifyMask, |
980 |
PackStructureProc, (ClientData) packPtr); |
981 |
return packPtr; |
982 |
} |
983 |
|
984 |
/* |
985 |
*-------------------------------------------------------------- |
986 |
* |
987 |
* PackAfter -- |
988 |
* |
989 |
* This procedure does most of the real work of adding |
990 |
* one or more windows into the packing order for its parent. |
991 |
* |
992 |
* Results: |
993 |
* A standard Tcl return value. |
994 |
* |
995 |
* Side effects: |
996 |
* The geometry of the specified windows may change, both now and |
997 |
* again in the future. |
998 |
* |
999 |
*-------------------------------------------------------------- |
1000 |
*/ |
1001 |
|
1002 |
static int |
1003 |
PackAfter(interp, prevPtr, masterPtr, argc, argv) |
1004 |
Tcl_Interp *interp; /* Interpreter for error reporting. */ |
1005 |
Packer *prevPtr; /* Pack windows in argv just after this |
1006 |
* window; NULL means pack as first |
1007 |
* child of masterPtr. */ |
1008 |
Packer *masterPtr; /* Master in which to pack windows. */ |
1009 |
int argc; /* Number of elements in argv. */ |
1010 |
char **argv; /* Array of lists, each containing 2 |
1011 |
* elements: window name and side |
1012 |
* against which to pack. */ |
1013 |
{ |
1014 |
register Packer *packPtr; |
1015 |
Tk_Window tkwin, ancestor, parent; |
1016 |
size_t length; |
1017 |
char **options; |
1018 |
int index, tmp, optionCount, c; |
1019 |
|
1020 |
/* |
1021 |
* Iterate over all of the window specifiers, each consisting of |
1022 |
* two arguments. The first argument contains the window name and |
1023 |
* the additional arguments contain options such as "top" or |
1024 |
* "padx 20". |
1025 |
*/ |
1026 |
|
1027 |
for ( ; argc > 0; argc -= 2, argv += 2, prevPtr = packPtr) { |
1028 |
if (argc < 2) { |
1029 |
Tcl_AppendResult(interp, "wrong # args: window \"", |
1030 |
argv[0], "\" should be followed by options", |
1031 |
(char *) NULL); |
1032 |
return TCL_ERROR; |
1033 |
} |
1034 |
|
1035 |
/* |
1036 |
* Find the packer for the window to be packed, and make sure |
1037 |
* that the window in which it will be packed is either its |
1038 |
* or a descendant of its parent. |
1039 |
*/ |
1040 |
|
1041 |
tkwin = Tk_NameToWindow(interp, argv[0], masterPtr->tkwin); |
1042 |
if (tkwin == NULL) { |
1043 |
return TCL_ERROR; |
1044 |
} |
1045 |
|
1046 |
parent = Tk_Parent(tkwin); |
1047 |
for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) { |
1048 |
if (ancestor == parent) { |
1049 |
break; |
1050 |
} |
1051 |
if (((Tk_FakeWin *) (ancestor))->flags & TK_TOP_LEVEL) { |
1052 |
badWindow: |
1053 |
Tcl_AppendResult(interp, "can't pack ", argv[0], |
1054 |
" inside ", Tk_PathName(masterPtr->tkwin), |
1055 |
(char *) NULL); |
1056 |
return TCL_ERROR; |
1057 |
} |
1058 |
} |
1059 |
if (((Tk_FakeWin *) (tkwin))->flags & TK_TOP_LEVEL) { |
1060 |
goto badWindow; |
1061 |
} |
1062 |
if (tkwin == masterPtr->tkwin) { |
1063 |
goto badWindow; |
1064 |
} |
1065 |
packPtr = GetPacker(tkwin); |
1066 |
|
1067 |
/* |
1068 |
* Process options for this window. |
1069 |
*/ |
1070 |
|
1071 |
if (Tcl_SplitList(interp, argv[1], &optionCount, &options) != TCL_OK) { |
1072 |
return TCL_ERROR; |
1073 |
} |
1074 |
packPtr->side = TOP; |
1075 |
packPtr->anchor = TK_ANCHOR_CENTER; |
1076 |
packPtr->padX = packPtr->padY = 0; |
1077 |
packPtr->iPadX = packPtr->iPadY = 0; |
1078 |
packPtr->flags &= ~(FILLX|FILLY|EXPAND); |
1079 |
packPtr->flags |= OLD_STYLE; |
1080 |
for (index = 0 ; index < optionCount; index++) { |
1081 |
char *curOpt = options[index]; |
1082 |
|
1083 |
c = curOpt[0]; |
1084 |
length = strlen(curOpt); |
1085 |
|
1086 |
if ((c == 't') |
1087 |
&& (strncmp(curOpt, "top", length)) == 0) { |
1088 |
packPtr->side = TOP; |
1089 |
} else if ((c == 'b') |
1090 |
&& (strncmp(curOpt, "bottom", length)) == 0) { |
1091 |
packPtr->side = BOTTOM; |
1092 |
} else if ((c == 'l') |
1093 |
&& (strncmp(curOpt, "left", length)) == 0) { |
1094 |
packPtr->side = LEFT; |
1095 |
} else if ((c == 'r') |
1096 |
&& (strncmp(curOpt, "right", length)) == 0) { |
1097 |
packPtr->side = RIGHT; |
1098 |
} else if ((c == 'e') |
1099 |
&& (strncmp(curOpt, "expand", length)) == 0) { |
1100 |
packPtr->flags |= EXPAND; |
1101 |
} else if ((c == 'f') |
1102 |
&& (strcmp(curOpt, "fill")) == 0) { |
1103 |
packPtr->flags |= FILLX|FILLY; |
1104 |
} else if ((length == 5) && (strcmp(curOpt, "fillx")) == 0) { |
1105 |
packPtr->flags |= FILLX; |
1106 |
} else if ((length == 5) && (strcmp(curOpt, "filly")) == 0) { |
1107 |
packPtr->flags |= FILLY; |
1108 |
} else if ((c == 'p') && (strcmp(curOpt, "padx")) == 0) { |
1109 |
if (optionCount < (index+2)) { |
1110 |
missingPad: |
1111 |
Tcl_AppendResult(interp, "wrong # args: \"", curOpt, |
1112 |
"\" option must be followed by screen distance", |
1113 |
(char *) NULL); |
1114 |
goto error; |
1115 |
} |
1116 |
if ((Tk_GetPixels(interp, tkwin, options[index+1], &tmp) |
1117 |
!= TCL_OK) || (tmp < 0)) { |
1118 |
badPad: |
1119 |
Tcl_AppendResult(interp, "bad pad value \"", |
1120 |
options[index+1], |
1121 |
"\": must be positive screen distance", |
1122 |
(char *) NULL); |
1123 |
goto error; |
1124 |
} |
1125 |
packPtr->padX = tmp; |
1126 |
packPtr->iPadX = 0; |
1127 |
index++; |
1128 |
} else if ((c == 'p') && (strcmp(curOpt, "pady")) == 0) { |
1129 |
if (optionCount < (index+2)) { |
1130 |
goto missingPad; |
1131 |
} |
1132 |
if ((Tk_GetPixels(interp, tkwin, options[index+1], &tmp) |
1133 |
!= TCL_OK) || (tmp < 0)) { |
1134 |
goto badPad; |
1135 |
} |
1136 |
packPtr->padY = tmp; |
1137 |
packPtr->iPadY = 0; |
1138 |
index++; |
1139 |
} else if ((c == 'f') && (length > 1) |
1140 |
&& (strncmp(curOpt, "frame", length) == 0)) { |
1141 |
if (optionCount < (index+2)) { |
1142 |
Tcl_AppendResult(interp, "wrong # args: \"frame\" ", |
1143 |
"option must be followed by anchor point", |
1144 |
(char *) NULL); |
1145 |
goto error; |
1146 |
} |
1147 |
if (Tk_GetAnchor(interp, options[index+1], |
1148 |
&packPtr->anchor) != TCL_OK) { |
1149 |
goto error; |
1150 |
} |
1151 |
index++; |
1152 |
} else { |
1153 |
Tcl_AppendResult(interp, "bad option \"", curOpt, |
1154 |
"\": should be top, bottom, left, right, ", |
1155 |
"expand, fill, fillx, filly, padx, pady, or frame", |
1156 |
(char *) NULL); |
1157 |
goto error; |
1158 |
} |
1159 |
} |
1160 |
|
1161 |
if (packPtr != prevPtr) { |
1162 |
|
1163 |
/* |
1164 |
* Unpack this window if it's currently packed. |
1165 |
*/ |
1166 |
|
1167 |
if (packPtr->masterPtr != NULL) { |
1168 |
if ((packPtr->masterPtr != masterPtr) && |
1169 |
(packPtr->masterPtr->tkwin |
1170 |
!= Tk_Parent(packPtr->tkwin))) { |
1171 |
Tk_UnmaintainGeometry(packPtr->tkwin, |
1172 |
packPtr->masterPtr->tkwin); |
1173 |
} |
1174 |
Unlink(packPtr); |
1175 |
} |
1176 |
|
1177 |
/* |
1178 |
* Add the window in the correct place in its parent's |
1179 |
* packing order, then make sure that the window is |
1180 |
* managed by us. |
1181 |
*/ |
1182 |
|
1183 |
packPtr->masterPtr = masterPtr; |
1184 |
if (prevPtr == NULL) { |
1185 |
packPtr->nextPtr = masterPtr->slavePtr; |
1186 |
masterPtr->slavePtr = packPtr; |
1187 |
} else { |
1188 |
packPtr->nextPtr = prevPtr->nextPtr; |
1189 |
prevPtr->nextPtr = packPtr; |
1190 |
} |
1191 |
Tk_ManageGeometry(tkwin, &packerType, (ClientData) packPtr); |
1192 |
} |
1193 |
ckfree((char *) options); |
1194 |
} |
1195 |
|
1196 |
/* |
1197 |
* Arrange for the parent to be re-packed at the first |
1198 |
* idle moment. |
1199 |
*/ |
1200 |
|
1201 |
if (masterPtr->abortPtr != NULL) { |
1202 |
*masterPtr->abortPtr = 1; |
1203 |
} |
1204 |
if (!(masterPtr->flags & REQUESTED_REPACK)) { |
1205 |
masterPtr->flags |= REQUESTED_REPACK; |
1206 |
Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr); |
1207 |
} |
1208 |
return TCL_OK; |
1209 |
|
1210 |
error: |
1211 |
ckfree((char *) options); |
1212 |
return TCL_ERROR; |
1213 |
} |
1214 |
|
1215 |
/* |
1216 |
*---------------------------------------------------------------------- |
1217 |
* |
1218 |
* Unlink -- |
1219 |
* |
1220 |
* Remove a packer from its parent's list of slaves. |
1221 |
* |
1222 |
* Results: |
1223 |
* None. |
1224 |
* |
1225 |
* Side effects: |
1226 |
* The parent will be scheduled for repacking. |
1227 |
* |
1228 |
*---------------------------------------------------------------------- |
1229 |
*/ |
1230 |
|
1231 |
static void |
1232 |
Unlink(packPtr) |
1233 |
register Packer *packPtr; /* Window to unlink. */ |
1234 |
{ |
1235 |
register Packer *masterPtr, *packPtr2; |
1236 |
|
1237 |
masterPtr = packPtr->masterPtr; |
1238 |
if (masterPtr == NULL) { |
1239 |
return; |
1240 |
} |
1241 |
if (masterPtr->slavePtr == packPtr) { |
1242 |
masterPtr->slavePtr = packPtr->nextPtr; |
1243 |
} else { |
1244 |
for (packPtr2 = masterPtr->slavePtr; ; packPtr2 = packPtr2->nextPtr) { |
1245 |
if (packPtr2 == NULL) { |
1246 |
panic("Unlink couldn't find previous window"); |
1247 |
} |
1248 |
if (packPtr2->nextPtr == packPtr) { |
1249 |
packPtr2->nextPtr = packPtr->nextPtr; |
1250 |
break; |
1251 |
} |
1252 |
} |
1253 |
} |
1254 |
if (!(masterPtr->flags & REQUESTED_REPACK)) { |
1255 |
masterPtr->flags |= REQUESTED_REPACK; |
1256 |
Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr); |
1257 |
} |
1258 |
if (masterPtr->abortPtr != NULL) { |
1259 |
*masterPtr->abortPtr = 1; |
1260 |
} |
1261 |
|
1262 |
packPtr->masterPtr = NULL; |
1263 |
} |
1264 |
|
1265 |
/* |
1266 |
*---------------------------------------------------------------------- |
1267 |
* |
1268 |
* DestroyPacker -- |
1269 |
* |
1270 |
* This procedure is invoked by Tcl_EventuallyFree or Tcl_Release |
1271 |
* to clean up the internal structure of a packer at a safe time |
1272 |
* (when no-one is using it anymore). |
1273 |
* |
1274 |
* Results: |
1275 |
* None. |
1276 |
* |
1277 |
* Side effects: |
1278 |
* Everything associated with the packer is freed up. |
1279 |
* |
1280 |
*---------------------------------------------------------------------- |
1281 |
*/ |
1282 |
|
1283 |
static void |
1284 |
DestroyPacker(memPtr) |
1285 |
char *memPtr; /* Info about packed window that |
1286 |
* is now dead. */ |
1287 |
{ |
1288 |
register Packer *packPtr = (Packer *) memPtr; |
1289 |
ckfree((char *) packPtr); |
1290 |
} |
1291 |
|
1292 |
/* |
1293 |
*---------------------------------------------------------------------- |
1294 |
* |
1295 |
* PackStructureProc -- |
1296 |
* |
1297 |
* This procedure is invoked by the Tk event dispatcher in response |
1298 |
* to StructureNotify events. |
1299 |
* |
1300 |
* Results: |
1301 |
* None. |
1302 |
* |
1303 |
* Side effects: |
1304 |
* If a window was just deleted, clean up all its packer-related |
1305 |
* information. If it was just resized, repack its slaves, if |
1306 |
* any. |
1307 |
* |
1308 |
*---------------------------------------------------------------------- |
1309 |
*/ |
1310 |
|
1311 |
static void |
1312 |
PackStructureProc(clientData, eventPtr) |
1313 |
ClientData clientData; /* Our information about window |
1314 |
* referred to by eventPtr. */ |
1315 |
XEvent *eventPtr; /* Describes what just happened. */ |
1316 |
{ |
1317 |
register Packer *packPtr = (Packer *) clientData; |
1318 |
|
1319 |
if (eventPtr->type == ConfigureNotify) { |
1320 |
if ((packPtr->slavePtr != NULL) |
1321 |
&& !(packPtr->flags & REQUESTED_REPACK)) { |
1322 |
packPtr->flags |= REQUESTED_REPACK; |
1323 |
Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr); |
1324 |
} |
1325 |
if (packPtr->doubleBw != 2*Tk_Changes(packPtr->tkwin)->border_width) { |
1326 |
if ((packPtr->masterPtr != NULL) |
1327 |
&& !(packPtr->masterPtr->flags & REQUESTED_REPACK)) { |
1328 |
packPtr->doubleBw = 2*Tk_Changes(packPtr->tkwin)->border_width; |
1329 |
packPtr->masterPtr->flags |= REQUESTED_REPACK; |
1330 |
Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr->masterPtr); |
1331 |
} |
1332 |
} |
1333 |
} else if (eventPtr->type == DestroyNotify) { |
1334 |
register Packer *slavePtr, *nextPtr; |
1335 |
|
1336 |
if (packPtr->masterPtr != NULL) { |
1337 |
Unlink(packPtr); |
1338 |
} |
1339 |
for (slavePtr = packPtr->slavePtr; slavePtr != NULL; |
1340 |
slavePtr = nextPtr) { |
1341 |
Tk_ManageGeometry(slavePtr->tkwin, (Tk_GeomMgr *) NULL, |
1342 |
(ClientData) NULL); |
1343 |
Tk_UnmapWindow(slavePtr->tkwin); |
1344 |
slavePtr->masterPtr = NULL; |
1345 |
nextPtr = slavePtr->nextPtr; |
1346 |
slavePtr->nextPtr = NULL; |
1347 |
} |
1348 |
if (packPtr->tkwin != NULL) { |
1349 |
TkDisplay *dispPtr = ((TkWindow *) packPtr->tkwin)->dispPtr; |
1350 |
Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->packerHashTable, |
1351 |
(char *) packPtr->tkwin)); |
1352 |
} |
1353 |
if (packPtr->flags & REQUESTED_REPACK) { |
1354 |
Tcl_CancelIdleCall(ArrangePacking, (ClientData) packPtr); |
1355 |
} |
1356 |
packPtr->tkwin = NULL; |
1357 |
Tcl_EventuallyFree((ClientData) packPtr, DestroyPacker); |
1358 |
} else if (eventPtr->type == MapNotify) { |
1359 |
/* |
1360 |
* When a master gets mapped, must redo the geometry computation |
1361 |
* so that all of its slaves get remapped. |
1362 |
*/ |
1363 |
|
1364 |
if ((packPtr->slavePtr != NULL) |
1365 |
&& !(packPtr->flags & REQUESTED_REPACK)) { |
1366 |
packPtr->flags |= REQUESTED_REPACK; |
1367 |
Tcl_DoWhenIdle(ArrangePacking, (ClientData) packPtr); |
1368 |
} |
1369 |
} else if (eventPtr->type == UnmapNotify) { |
1370 |
register Packer *packPtr2; |
1371 |
|
1372 |
/* |
1373 |
* Unmap all of the slaves when the master gets unmapped, |
1374 |
* so that they don't bother to keep redisplaying |
1375 |
* themselves. |
1376 |
*/ |
1377 |
for (packPtr2 = packPtr->slavePtr; packPtr2 != NULL; |
1378 |
packPtr2 = packPtr2->nextPtr) { |
1379 |
Tk_UnmapWindow(packPtr2->tkwin); |
1380 |
} |
1381 |
} |
1382 |
} |
1383 |
|
1384 |
/* |
1385 |
*---------------------------------------------------------------------- |
1386 |
* |
1387 |
* ConfigureSlaves -- |
1388 |
* |
1389 |
* This implements the guts of the "pack configure" command. Given |
1390 |
* a list of slaves and configuration options, it arranges for the |
1391 |
* packer to manage the slaves and sets the specified options. |
1392 |
* |
1393 |
* Results: |
1394 |
* TCL_OK is returned if all went well. Otherwise, TCL_ERROR is |
1395 |
* returned and the interp's result is set to contain an error message. |
1396 |
* |
1397 |
* Side effects: |
1398 |
* Slave windows get taken over by the packer. |
1399 |
* |
1400 |
*---------------------------------------------------------------------- |
1401 |
*/ |
1402 |
|
1403 |
static int |
1404 |
ConfigureSlaves(interp, tkwin, argc, argv) |
1405 |
Tcl_Interp *interp; /* Interpreter for error reporting. */ |
1406 |
Tk_Window tkwin; /* Any window in application containing |
1407 |
* slaves. Used to look up slave names. */ |
1408 |
int argc; /* Number of elements in argv. */ |
1409 |
char *argv[]; /* Argument strings: contains one or more |
1410 |
* window names followed by any number |
1411 |
* of "option value" pairs. Caller must |
1412 |
* make sure that there is at least one |
1413 |
* window name. */ |
1414 |
{ |
1415 |
Packer *masterPtr, *slavePtr, *prevPtr, *otherPtr; |
1416 |
Tk_Window other, slave, parent, ancestor; |
1417 |
int i, j, numWindows, c, tmp, positionGiven; |
1418 |
size_t length; |
1419 |
|
1420 |
/* |
1421 |
* Find out how many windows are specified. |
1422 |
*/ |
1423 |
|
1424 |
for (numWindows = 0; numWindows < argc; numWindows++) { |
1425 |
if (argv[numWindows][0] != '.') { |
1426 |
break; |
1427 |
} |
1428 |
} |
1429 |
|
1430 |
/* |
1431 |
* Iterate over all of the slave windows, parsing the configuration |
1432 |
* options for each slave. It's a bit wasteful to re-parse the |
1433 |
* options for each slave, but things get too messy if we try to |
1434 |
* parse the arguments just once at the beginning. For example, |
1435 |
* if a slave already is packed we want to just change a few |
1436 |
* existing values without resetting everything. If there are |
1437 |
* multiple windows, the -after, -before, and -in options only |
1438 |
* get processed for the first window. |
1439 |
*/ |
1440 |
|
1441 |
masterPtr = NULL; |
1442 |
prevPtr = NULL; |
1443 |
positionGiven = 0; |
1444 |
for (j = 0; j < numWindows; j++) { |
1445 |
slave = Tk_NameToWindow(interp, argv[j], tkwin); |
1446 |
if (slave == NULL) { |
1447 |
return TCL_ERROR; |
1448 |
} |
1449 |
if (Tk_IsTopLevel(slave)) { |
1450 |
Tcl_AppendResult(interp, "can't pack \"", argv[j], |
1451 |
"\": it's a top-level window", (char *) NULL); |
1452 |
return TCL_ERROR; |
1453 |
} |
1454 |
slavePtr = GetPacker(slave); |
1455 |
slavePtr->flags &= ~OLD_STYLE; |
1456 |
|
1457 |
/* |
1458 |
* If the slave isn't currently packed, reset all of its |
1459 |
* configuration information to default values (there could |
1460 |
* be old values left from a previous packing). |
1461 |
*/ |
1462 |
|
1463 |
if (slavePtr->masterPtr == NULL) { |
1464 |
slavePtr->side = TOP; |
1465 |
slavePtr->anchor = TK_ANCHOR_CENTER; |
1466 |
slavePtr->padX = slavePtr->padY = 0; |
1467 |
slavePtr->iPadX = slavePtr->iPadY = 0; |
1468 |
slavePtr->flags &= ~(FILLX|FILLY|EXPAND); |
1469 |
} |
1470 |
|
1471 |
for (i = numWindows; i < argc; i+=2) { |
1472 |
if ((i+2) > argc) { |
1473 |
Tcl_AppendResult(interp, "extra option \"", argv[i], |
1474 |
"\" (option with no value?)", (char *) NULL); |
1475 |
return TCL_ERROR; |
1476 |
} |
1477 |
length = strlen(argv[i]); |
1478 |
if (length < 2) { |
1479 |
goto badOption; |
1480 |
} |
1481 |
c = argv[i][1]; |
1482 |
if ((c == 'a') && (strncmp(argv[i], "-after", length) == 0) |
1483 |
&& (length >= 2)) { |
1484 |
if (j == 0) { |
1485 |
other = Tk_NameToWindow(interp, argv[i+1], tkwin); |
1486 |
if (other == NULL) { |
1487 |
return TCL_ERROR; |
1488 |
} |
1489 |
prevPtr = GetPacker(other); |
1490 |
if (prevPtr->masterPtr == NULL) { |
1491 |
notPacked: |
1492 |
Tcl_AppendResult(interp, "window \"", argv[i+1], |
1493 |
"\" isn't packed", (char *) NULL); |
1494 |
return TCL_ERROR; |
1495 |
} |
1496 |
masterPtr = prevPtr->masterPtr; |
1497 |
positionGiven = 1; |
1498 |
} |
1499 |
} else if ((c == 'a') && (strncmp(argv[i], "-anchor", length) == 0) |
1500 |
&& (length >= 2)) { |
1501 |
if (Tk_GetAnchor(interp, argv[i+1], &slavePtr->anchor) |
1502 |
!= TCL_OK) { |
1503 |
return TCL_ERROR; |
1504 |
} |
1505 |
} else if ((c == 'b') |
1506 |
&& (strncmp(argv[i], "-before", length) == 0)) { |
1507 |
if (j == 0) { |
1508 |
other = Tk_NameToWindow(interp, argv[i+1], tkwin); |
1509 |
if (other == NULL) { |
1510 |
return TCL_ERROR; |
1511 |
} |
1512 |
otherPtr = GetPacker(other); |
1513 |
if (otherPtr->masterPtr == NULL) { |
1514 |
goto notPacked; |
1515 |
} |
1516 |
masterPtr = otherPtr->masterPtr; |
1517 |
prevPtr = masterPtr->slavePtr; |
1518 |
if (prevPtr == otherPtr) { |
1519 |
prevPtr = NULL; |
1520 |
} else { |
1521 |
while (prevPtr->nextPtr != otherPtr) { |
1522 |
prevPtr = prevPtr->nextPtr; |
1523 |
} |
1524 |
} |
1525 |
positionGiven = 1; |
1526 |
} |
1527 |
} else if ((c == 'e') |
1528 |
&& (strncmp(argv[i], "-expand", length) == 0)) { |
1529 |
if (Tcl_GetBoolean(interp, argv[i+1], &tmp) != TCL_OK) { |
1530 |
return TCL_ERROR; |
1531 |
} |
1532 |
slavePtr->flags &= ~EXPAND; |
1533 |
if (tmp) { |
1534 |
slavePtr->flags |= EXPAND; |
1535 |
} |
1536 |
} else if ((c == 'f') && (strncmp(argv[i], "-fill", length) == 0)) { |
1537 |
if (strcmp(argv[i+1], "none") == 0) { |
1538 |
slavePtr->flags &= ~(FILLX|FILLY); |
1539 |
} else if (strcmp(argv[i+1], "x") == 0) { |
1540 |
slavePtr->flags = (slavePtr->flags & ~FILLY) | FILLX; |
1541 |
} else if (strcmp(argv[i+1], "y") == 0) { |
1542 |
slavePtr->flags = (slavePtr->flags & ~FILLX) | FILLY; |
1543 |
} else if (strcmp(argv[i+1], "both") == 0) { |
1544 |
slavePtr->flags |= FILLX|FILLY; |
1545 |
} else { |
1546 |
Tcl_AppendResult(interp, "bad fill style \"", argv[i+1], |
1547 |
"\": must be none, x, y, or both", (char *) NULL); |
1548 |
return TCL_ERROR; |
1549 |
} |
1550 |
} else if ((c == 'i') && (strcmp(argv[i], "-in") == 0)) { |
1551 |
if (j == 0) { |
1552 |
other = Tk_NameToWindow(interp, argv[i+1], tkwin); |
1553 |
if (other == NULL) { |
1554 |
return TCL_ERROR; |
1555 |
} |
1556 |
masterPtr = GetPacker(other); |
1557 |
prevPtr = masterPtr->slavePtr; |
1558 |
if (prevPtr != NULL) { |
1559 |
while (prevPtr->nextPtr != NULL) { |
1560 |
prevPtr = prevPtr->nextPtr; |
1561 |
} |
1562 |
} |
1563 |
positionGiven = 1; |
1564 |
} |
1565 |
} else if ((c == 'i') && (strcmp(argv[i], "-ipadx") == 0)) { |
1566 |
if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK) |
1567 |
|| (tmp < 0)) { |
1568 |
badPad: |
1569 |
Tcl_ResetResult(interp); |
1570 |
Tcl_AppendResult(interp, "bad pad value \"", argv[i+1], |
1571 |
"\": must be positive screen distance", |
1572 |
(char *) NULL); |
1573 |
return TCL_ERROR; |
1574 |
} |
1575 |
slavePtr->iPadX = tmp*2; |
1576 |
} else if ((c == 'i') && (strcmp(argv[i], "-ipady") == 0)) { |
1577 |
if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK) |
1578 |
|| (tmp< 0)) { |
1579 |
goto badPad; |
1580 |
} |
1581 |
slavePtr->iPadY = tmp*2; |
1582 |
} else if ((c == 'p') && (strcmp(argv[i], "-padx") == 0)) { |
1583 |
if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK) |
1584 |
|| (tmp< 0)) { |
1585 |
goto badPad; |
1586 |
} |
1587 |
slavePtr->padX = tmp*2; |
1588 |
} else if ((c == 'p') && (strcmp(argv[i], "-pady") == 0)) { |
1589 |
if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK) |
1590 |
|| (tmp< 0)) { |
1591 |
goto badPad; |
1592 |
} |
1593 |
slavePtr->padY = tmp*2; |
1594 |
} else if ((c == 's') && (strncmp(argv[i], "-side", length) == 0)) { |
1595 |
c = argv[i+1][0]; |
1596 |
if ((c == 't') && (strcmp(argv[i+1], "top") == 0)) { |
1597 |
slavePtr->side = TOP; |
1598 |
} else if ((c == 'b') && (strcmp(argv[i+1], "bottom") == 0)) { |
1599 |
slavePtr->side = BOTTOM; |
1600 |
} else if ((c == 'l') && (strcmp(argv[i+1], "left") == 0)) { |
1601 |
slavePtr->side = LEFT; |
1602 |
} else if ((c == 'r') && (strcmp(argv[i+1], "right") == 0)) { |
1603 |
slavePtr->side = RIGHT; |
1604 |
} else { |
1605 |
Tcl_AppendResult(interp, "bad side \"", argv[i+1], |
1606 |
"\": must be top, bottom, left, or right", |
1607 |
(char *) NULL); |
1608 |
return TCL_ERROR; |
1609 |
} |
1610 |
} else { |
1611 |
badOption: |
1612 |
Tcl_AppendResult(interp, "unknown or ambiguous option \"", |
1613 |
argv[i], "\": must be -after, -anchor, -before, ", |
1614 |
"-expand, -fill, -in, -ipadx, -ipady, -padx, ", |
1615 |
"-pady, or -side", (char *) NULL); |
1616 |
return TCL_ERROR; |
1617 |
} |
1618 |
} |
1619 |
|
1620 |
/* |
1621 |
* If no position in a packing list was specified and the slave |
1622 |
* is already packed, then leave it in its current location in |
1623 |
* its current packing list. |
1624 |
*/ |
1625 |
|
1626 |
if (!positionGiven && (slavePtr->masterPtr != NULL)) { |
1627 |
masterPtr = slavePtr->masterPtr; |
1628 |
goto scheduleLayout; |
1629 |
} |
1630 |
|
1631 |
/* |
1632 |
* If the slave is going to be put back after itself then |
1633 |
* skip the whole operation, since it won't work anyway. |
1634 |
*/ |
1635 |
|
1636 |
if (prevPtr == slavePtr) { |
1637 |
masterPtr = slavePtr->masterPtr; |
1638 |
goto scheduleLayout; |
1639 |
} |
1640 |
|
1641 |
/* |
1642 |
* If none of the "-in", "-before", or "-after" options has |
1643 |
* been specified, arrange for the slave to go at the end of |
1644 |
* the order for its parent. |
1645 |
*/ |
1646 |
|
1647 |
if (!positionGiven) { |
1648 |
masterPtr = GetPacker(Tk_Parent(slave)); |
1649 |
prevPtr = masterPtr->slavePtr; |
1650 |
if (prevPtr != NULL) { |
1651 |
while (prevPtr->nextPtr != NULL) { |
1652 |
prevPtr = prevPtr->nextPtr; |
1653 |
} |
1654 |
} |
1655 |
} |
1656 |
|
1657 |
/* |
1658 |
* Make sure that the slave's parent is either the master or |
1659 |
* an ancestor of the master, and that the master and slave |
1660 |
* aren't the same. |
1661 |
*/ |
1662 |
|
1663 |
parent = Tk_Parent(slave); |
1664 |
for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) { |
1665 |
if (ancestor == parent) { |
1666 |
break; |
1667 |
} |
1668 |
if (Tk_IsTopLevel(ancestor)) { |
1669 |
Tcl_AppendResult(interp, "can't pack ", argv[j], |
1670 |
" inside ", Tk_PathName(masterPtr->tkwin), |
1671 |
(char *) NULL); |
1672 |
return TCL_ERROR; |
1673 |
} |
1674 |
} |
1675 |
if (slave == masterPtr->tkwin) { |
1676 |
Tcl_AppendResult(interp, "can't pack ", argv[j], |
1677 |
" inside itself", (char *) NULL); |
1678 |
return TCL_ERROR; |
1679 |
} |
1680 |
|
1681 |
/* |
1682 |
* Unpack the slave if it's currently packed, then position it |
1683 |
* after prevPtr. |
1684 |
*/ |
1685 |
|
1686 |
if (slavePtr->masterPtr != NULL) { |
1687 |
if ((slavePtr->masterPtr != masterPtr) && |
1688 |
(slavePtr->masterPtr->tkwin |
1689 |
!= Tk_Parent(slavePtr->tkwin))) { |
1690 |
Tk_UnmaintainGeometry(slavePtr->tkwin, |
1691 |
slavePtr->masterPtr->tkwin); |
1692 |
} |
1693 |
Unlink(slavePtr); |
1694 |
} |
1695 |
slavePtr->masterPtr = masterPtr; |
1696 |
if (prevPtr == NULL) { |
1697 |
slavePtr->nextPtr = masterPtr->slavePtr; |
1698 |
masterPtr->slavePtr = slavePtr; |
1699 |
} else { |
1700 |
slavePtr->nextPtr = prevPtr->nextPtr; |
1701 |
prevPtr->nextPtr = slavePtr; |
1702 |
} |
1703 |
Tk_ManageGeometry(slave, &packerType, (ClientData) slavePtr); |
1704 |
prevPtr = slavePtr; |
1705 |
|
1706 |
/* |
1707 |
* Arrange for the parent to be re-packed at the first |
1708 |
* idle moment. |
1709 |
*/ |
1710 |
|
1711 |
scheduleLayout: |
1712 |
if (masterPtr->abortPtr != NULL) { |
1713 |
*masterPtr->abortPtr = 1; |
1714 |
} |
1715 |
if (!(masterPtr->flags & REQUESTED_REPACK)) { |
1716 |
masterPtr->flags |= REQUESTED_REPACK; |
1717 |
Tcl_DoWhenIdle(ArrangePacking, (ClientData) masterPtr); |
1718 |
} |
1719 |
} |
1720 |
return TCL_OK; |
1721 |
} |
1722 |
|
1723 |
/* End of tkpack.c */ |