/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkpack.c
ViewVC logotype

Annotation of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkpack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 44 - (hide annotations) (download)
Fri Oct 14 02:09:58 2016 UTC (7 years, 5 months ago) by dashley
File MIME type: text/plain
File size: 52828 byte(s)
Rename for reorganization.
1 dashley 25 /* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tk_base/tkpack.c,v 1.1.1.1 2001/06/13 05:06:57 dtashley Exp $ */
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    
1724     /* $History: tkPack.c $
1725     *
1726     * ***************** Version 1 *****************
1727     * User: Dtashley Date: 1/02/01 Time: 3:05a
1728     * Created in $/IjuScripter, IjuConsole/Source/Tk Base
1729     * Initial check-in.
1730     */
1731    
1732     /* End of TKPACK.C */

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25