/[dtapublic]/sf_code/esrgpcpj/shared/tk_base/tkplace.c
ViewVC logotype

Annotation of /sf_code/esrgpcpj/shared/tk_base/tkplace.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 25 - (hide annotations) (download)
Sat Oct 8 06:43:03 2016 UTC (7 years, 8 months ago) by dashley
File MIME type: text/plain
File size: 32684 byte(s)
Initial commit.
1 dashley 25 /* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tk_base/tkplace.c,v 1.1.1.1 2001/06/13 05:07:09 dtashley Exp $ */
2    
3     /*
4     * tkPlace.c --
5     *
6     * This file contains code to implement a simple geometry manager
7     * for Tk based on absolute placement or "rubber-sheet" placement.
8     *
9     * Copyright (c) 1992-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: tkplace.c,v 1.1.1.1 2001/06/13 05:07:09 dtashley Exp $
16     */
17    
18     #include "tkPort.h"
19     #include "tkInt.h"
20    
21     /*
22     * Border modes for relative placement:
23     *
24     * BM_INSIDE: relative distances computed using area inside
25     * all borders of master window.
26     * BM_OUTSIDE: relative distances computed using outside area
27     * that includes all borders of master.
28     * BM_IGNORE: border issues are ignored: place relative to
29     * master's actual window size.
30     */
31    
32     typedef enum {BM_INSIDE, BM_OUTSIDE, BM_IGNORE} BorderMode;
33    
34     /*
35     * For each window whose geometry is managed by the placer there is
36     * a structure of the following type:
37     */
38    
39     typedef struct Slave {
40     Tk_Window tkwin; /* Tk's token for window. */
41     struct Master *masterPtr; /* Pointer to information for window
42     * relative to which tkwin is placed.
43     * This isn't necessarily the logical
44     * parent of tkwin. NULL means the
45     * master was deleted or never assigned. */
46     struct Slave *nextPtr; /* Next in list of windows placed relative
47     * to same master (NULL for end of list). */
48    
49     /*
50     * Geometry information for window; where there are both relative
51     * and absolute values for the same attribute (e.g. x and relX) only
52     * one of them is actually used, depending on flags.
53     */
54    
55     int x, y; /* X and Y pixel coordinates for tkwin. */
56     float relX, relY; /* X and Y coordinates relative to size of
57     * master. */
58     int width, height; /* Absolute dimensions for tkwin. */
59     float relWidth, relHeight; /* Dimensions for tkwin relative to size of
60     * master. */
61     Tk_Anchor anchor; /* Which point on tkwin is placed at the
62     * given position. */
63     BorderMode borderMode; /* How to treat borders of master window. */
64     int flags; /* Various flags; see below for bit
65     * definitions. */
66     } Slave;
67    
68     /*
69     * Flag definitions for Slave structures:
70     *
71     * CHILD_WIDTH - 1 means -width was specified;
72     * CHILD_REL_WIDTH - 1 means -relwidth was specified.
73     * CHILD_HEIGHT - 1 means -height was specified;
74     * CHILD_REL_HEIGHT - 1 means -relheight was specified.
75     */
76    
77     #define CHILD_WIDTH 1
78     #define CHILD_REL_WIDTH 2
79     #define CHILD_HEIGHT 4
80     #define CHILD_REL_HEIGHT 8
81    
82     /*
83     * For each master window that has a slave managed by the placer there
84     * is a structure of the following form:
85     */
86    
87     typedef struct Master {
88     Tk_Window tkwin; /* Tk's token for master window. */
89     struct Slave *slavePtr; /* First in linked list of slaves
90     * placed relative to this master. */
91     int flags; /* See below for bit definitions. */
92     } Master;
93    
94     /*
95     * Flag definitions for masters:
96     *
97     * PARENT_RECONFIG_PENDING - 1 means that a call to RecomputePlacement
98     * is already pending via a Do_When_Idle handler.
99     */
100    
101     #define PARENT_RECONFIG_PENDING 1
102    
103     /*
104     * The following structure is the official type record for the
105     * placer:
106     */
107    
108     static void PlaceRequestProc _ANSI_ARGS_((ClientData clientData,
109     Tk_Window tkwin));
110     static void PlaceLostSlaveProc _ANSI_ARGS_((ClientData clientData,
111     Tk_Window tkwin));
112    
113     static Tk_GeomMgr placerType = {
114     "place", /* name */
115     PlaceRequestProc, /* requestProc */
116     PlaceLostSlaveProc, /* lostSlaveProc */
117     };
118    
119     /*
120     * Forward declarations for procedures defined later in this file:
121     */
122    
123     static void SlaveStructureProc _ANSI_ARGS_((ClientData clientData,
124     XEvent *eventPtr));
125     static int ConfigureSlave _ANSI_ARGS_((Tcl_Interp *interp,
126     Slave *slavePtr, int argc, char **argv));
127     static Slave * FindSlave _ANSI_ARGS_((Tk_Window tkwin));
128     static Master * FindMaster _ANSI_ARGS_((Tk_Window tkwin));
129     static void MasterStructureProc _ANSI_ARGS_((ClientData clientData,
130     XEvent *eventPtr));
131     static void RecomputePlacement _ANSI_ARGS_((ClientData clientData));
132     static void UnlinkSlave _ANSI_ARGS_((Slave *slavePtr));
133    
134     /*
135     *--------------------------------------------------------------
136     *
137     * Tk_PlaceCmd --
138     *
139     * This procedure is invoked to process the "place" Tcl
140     * commands. See the user documentation for details on
141     * what it does.
142     *
143     * Results:
144     * A standard Tcl result.
145     *
146     * Side effects:
147     * See the user documentation.
148     *
149     *--------------------------------------------------------------
150     */
151    
152     int
153     Tk_PlaceCmd(clientData, interp, argc, argv)
154     ClientData clientData; /* Main window associated with interpreter. */
155     Tcl_Interp *interp; /* Current interpreter. */
156     int argc; /* Number of arguments. */
157     char **argv; /* Argument strings. */
158     {
159     Tk_Window tkwin;
160     Slave *slavePtr;
161     Tcl_HashEntry *hPtr;
162     size_t length;
163     int c;
164     TkDisplay *dispPtr;
165    
166     dispPtr = ((TkWindow *) clientData)->dispPtr;
167    
168     /*
169     * Initialize, if that hasn't been done yet.
170     */
171    
172     if (!dispPtr->placeInit) {
173     Tcl_InitHashTable(&dispPtr->masterTable, TCL_ONE_WORD_KEYS);
174     Tcl_InitHashTable(&dispPtr->slaveTable, TCL_ONE_WORD_KEYS);
175     dispPtr->placeInit = 1;
176     }
177    
178     if (argc < 3) {
179     Tcl_AppendResult(interp, "wrong # args: should be \"",
180     argv[0], " option|pathName args", (char *) NULL);
181     return TCL_ERROR;
182     }
183     c = argv[1][0];
184     length = strlen(argv[1]);
185    
186     /*
187     * Handle special shortcut where window name is first argument.
188     */
189    
190     if (c == '.') {
191     tkwin = Tk_NameToWindow(interp, argv[1], (Tk_Window) clientData);
192     if (tkwin == NULL) {
193     return TCL_ERROR;
194     }
195     slavePtr = FindSlave(tkwin);
196     return ConfigureSlave(interp, slavePtr, argc-2, argv+2);
197     }
198    
199     /*
200     * Handle more general case of option followed by window name followed
201     * by possible additional arguments.
202     */
203    
204     tkwin = Tk_NameToWindow(interp, argv[2], (Tk_Window) clientData);
205     if (tkwin == NULL) {
206     return TCL_ERROR;
207     }
208     if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {
209     if (argc < 5) {
210     Tcl_AppendResult(interp, "wrong # args: should be \"",
211     argv[0],
212     " configure pathName option value ?option value ...?\"",
213     (char *) NULL);
214     return TCL_ERROR;
215     }
216     slavePtr = FindSlave(tkwin);
217     return ConfigureSlave(interp, slavePtr, argc-3, argv+3);
218     } else if ((c == 'f') && (strncmp(argv[1], "forget", length) == 0)) {
219     if (argc != 3) {
220     Tcl_AppendResult(interp, "wrong # args: should be \"",
221     argv[0], " forget pathName\"", (char *) NULL);
222     return TCL_ERROR;
223     }
224     hPtr = Tcl_FindHashEntry(&dispPtr->slaveTable, (char *) tkwin);
225     if (hPtr == NULL) {
226     return TCL_OK;
227     }
228     slavePtr = (Slave *) Tcl_GetHashValue(hPtr);
229     if ((slavePtr->masterPtr != NULL) &&
230     (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin))) {
231     Tk_UnmaintainGeometry(slavePtr->tkwin,
232     slavePtr->masterPtr->tkwin);
233     }
234     UnlinkSlave(slavePtr);
235     Tcl_DeleteHashEntry(hPtr);
236     Tk_DeleteEventHandler(tkwin, StructureNotifyMask, SlaveStructureProc,
237     (ClientData) slavePtr);
238     Tk_ManageGeometry(tkwin, (Tk_GeomMgr *) NULL, (ClientData) NULL);
239     Tk_UnmapWindow(tkwin);
240     ckfree((char *) slavePtr);
241     } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) {
242     char buffer[32 + TCL_INTEGER_SPACE];
243    
244     if (argc != 3) {
245     Tcl_AppendResult(interp, "wrong # args: should be \"",
246     argv[0], " info pathName\"", (char *) NULL);
247     return TCL_ERROR;
248     }
249     hPtr = Tcl_FindHashEntry(&dispPtr->slaveTable, (char *) tkwin);
250     if (hPtr == NULL) {
251     return TCL_OK;
252     }
253     slavePtr = (Slave *) Tcl_GetHashValue(hPtr);
254     sprintf(buffer, "-x %d", slavePtr->x);
255     Tcl_AppendResult(interp, buffer, (char *) NULL);
256     sprintf(buffer, " -relx %.4g", slavePtr->relX);
257     Tcl_AppendResult(interp, buffer, (char *) NULL);
258     sprintf(buffer, " -y %d", slavePtr->y);
259     Tcl_AppendResult(interp, buffer, (char *) NULL);
260     sprintf(buffer, " -rely %.4g", slavePtr->relY);
261     Tcl_AppendResult(interp, buffer, (char *) NULL);
262     if (slavePtr->flags & CHILD_WIDTH) {
263     sprintf(buffer, " -width %d", slavePtr->width);
264     Tcl_AppendResult(interp, buffer, (char *) NULL);
265     } else {
266     Tcl_AppendResult(interp, " -width {}", (char *) NULL);
267     }
268     if (slavePtr->flags & CHILD_REL_WIDTH) {
269     sprintf(buffer, " -relwidth %.4g", slavePtr->relWidth);
270     Tcl_AppendResult(interp, buffer, (char *) NULL);
271     } else {
272     Tcl_AppendResult(interp, " -relwidth {}", (char *) NULL);
273     }
274     if (slavePtr->flags & CHILD_HEIGHT) {
275     sprintf(buffer, " -height %d", slavePtr->height);
276     Tcl_AppendResult(interp, buffer, (char *) NULL);
277     } else {
278     Tcl_AppendResult(interp, " -height {}", (char *) NULL);
279     }
280     if (slavePtr->flags & CHILD_REL_HEIGHT) {
281     sprintf(buffer, " -relheight %.4g", slavePtr->relHeight);
282     Tcl_AppendResult(interp, buffer, (char *) NULL);
283     } else {
284     Tcl_AppendResult(interp, " -relheight {}", (char *) NULL);
285     }
286    
287     Tcl_AppendResult(interp, " -anchor ", Tk_NameOfAnchor(slavePtr->anchor),
288     (char *) NULL);
289     if (slavePtr->borderMode == BM_OUTSIDE) {
290     Tcl_AppendResult(interp, " -bordermode outside", (char *) NULL);
291     } else if (slavePtr->borderMode == BM_IGNORE) {
292     Tcl_AppendResult(interp, " -bordermode ignore", (char *) NULL);
293     }
294     if ((slavePtr->masterPtr != NULL)
295     && (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin))) {
296     Tcl_AppendResult(interp, " -in ",
297     Tk_PathName(slavePtr->masterPtr->tkwin), (char *) NULL);
298     }
299     } else if ((c == 's') && (strncmp(argv[1], "slaves", length) == 0)) {
300     if (argc != 3) {
301     Tcl_AppendResult(interp, "wrong # args: should be \"",
302     argv[0], " slaves pathName\"", (char *) NULL);
303     return TCL_ERROR;
304     }
305     hPtr = Tcl_FindHashEntry(&dispPtr->masterTable, (char *) tkwin);
306     if (hPtr != NULL) {
307     Master *masterPtr;
308     masterPtr = (Master *) Tcl_GetHashValue(hPtr);
309     for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
310     slavePtr = slavePtr->nextPtr) {
311     Tcl_AppendElement(interp, Tk_PathName(slavePtr->tkwin));
312     }
313     }
314     } else {
315     Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],
316     "\": must be configure, forget, info, or slaves",
317     (char *) NULL);
318     return TCL_ERROR;
319     }
320     return TCL_OK;
321     }
322    
323     /*
324     *----------------------------------------------------------------------
325     *
326     * FindSlave --
327     *
328     * Given a Tk_Window token, find the Slave structure corresponding
329     * to that token (making a new one if necessary).
330     *
331     * Results:
332     * None.
333     *
334     * Side effects:
335     * A new Slave structure may be created.
336     *
337     *----------------------------------------------------------------------
338     */
339    
340     static Slave *
341     FindSlave(tkwin)
342     Tk_Window tkwin; /* Token for desired slave. */
343     {
344     Tcl_HashEntry *hPtr;
345     register Slave *slavePtr;
346     int new;
347     TkDisplay * dispPtr = ((TkWindow *) tkwin)->dispPtr;
348    
349     hPtr = Tcl_CreateHashEntry(&dispPtr->slaveTable, (char *) tkwin, &new);
350     if (new) {
351     slavePtr = (Slave *) ckalloc(sizeof(Slave));
352     slavePtr->tkwin = tkwin;
353     slavePtr->masterPtr = NULL;
354     slavePtr->nextPtr = NULL;
355     slavePtr->x = slavePtr->y = 0;
356     slavePtr->relX = slavePtr->relY = (float) 0.0;
357     slavePtr->width = slavePtr->height = 0;
358     slavePtr->relWidth = slavePtr->relHeight = (float) 0.0;
359     slavePtr->anchor = TK_ANCHOR_NW;
360     slavePtr->borderMode = BM_INSIDE;
361     slavePtr->flags = 0;
362     Tcl_SetHashValue(hPtr, slavePtr);
363     Tk_CreateEventHandler(tkwin, StructureNotifyMask, SlaveStructureProc,
364     (ClientData) slavePtr);
365     Tk_ManageGeometry(tkwin, &placerType, (ClientData) slavePtr);
366     } else {
367     slavePtr = (Slave *) Tcl_GetHashValue(hPtr);
368     }
369     return slavePtr;
370     }
371    
372     /*
373     *----------------------------------------------------------------------
374     *
375     * UnlinkSlave --
376     *
377     * This procedure removes a slave window from the chain of slaves
378     * in its master.
379     *
380     * Results:
381     * None.
382     *
383     * Side effects:
384     * The slave list of slavePtr's master changes.
385     *
386     *----------------------------------------------------------------------
387     */
388    
389     static void
390     UnlinkSlave(slavePtr)
391     Slave *slavePtr; /* Slave structure to be unlinked. */
392     {
393     register Master *masterPtr;
394     register Slave *prevPtr;
395    
396     masterPtr = slavePtr->masterPtr;
397     if (masterPtr == NULL) {
398     return;
399     }
400     if (masterPtr->slavePtr == slavePtr) {
401     masterPtr->slavePtr = slavePtr->nextPtr;
402     } else {
403     for (prevPtr = masterPtr->slavePtr; ;
404     prevPtr = prevPtr->nextPtr) {
405     if (prevPtr == NULL) {
406     panic("UnlinkSlave couldn't find slave to unlink");
407     }
408     if (prevPtr->nextPtr == slavePtr) {
409     prevPtr->nextPtr = slavePtr->nextPtr;
410     break;
411     }
412     }
413     }
414     slavePtr->masterPtr = NULL;
415     }
416    
417     /*
418     *----------------------------------------------------------------------
419     *
420     * FindMaster --
421     *
422     * Given a Tk_Window token, find the Master structure corresponding
423     * to that token (making a new one if necessary).
424     *
425     * Results:
426     * None.
427     *
428     * Side effects:
429     * A new Master structure may be created.
430     *
431     *----------------------------------------------------------------------
432     */
433    
434     static Master *
435     FindMaster(tkwin)
436     Tk_Window tkwin; /* Token for desired master. */
437     {
438     Tcl_HashEntry *hPtr;
439     register Master *masterPtr;
440     int new;
441     TkDisplay * dispPtr = ((TkWindow *) tkwin)->dispPtr;
442    
443     hPtr = Tcl_CreateHashEntry(&dispPtr->masterTable, (char *) tkwin, &new);
444     if (new) {
445     masterPtr = (Master *) ckalloc(sizeof(Master));
446     masterPtr->tkwin = tkwin;
447     masterPtr->slavePtr = NULL;
448     masterPtr->flags = 0;
449     Tcl_SetHashValue(hPtr, masterPtr);
450     Tk_CreateEventHandler(masterPtr->tkwin, StructureNotifyMask,
451     MasterStructureProc, (ClientData) masterPtr);
452     } else {
453     masterPtr = (Master *) Tcl_GetHashValue(hPtr);
454     }
455     return masterPtr;
456     }
457    
458     /*
459     *----------------------------------------------------------------------
460     *
461     * ConfigureSlave --
462     *
463     * This procedure is called to process an argv/argc list to
464     * reconfigure the placement of a window.
465     *
466     * Results:
467     * A standard Tcl result. If an error occurs then a message is
468     * left in the interp's result.
469     *
470     * Side effects:
471     * Information in slavePtr may change, and slavePtr's master is
472     * scheduled for reconfiguration.
473     *
474     *----------------------------------------------------------------------
475     */
476    
477     static int
478     ConfigureSlave(interp, slavePtr, argc, argv)
479     Tcl_Interp *interp; /* Used for error reporting. */
480     Slave *slavePtr; /* Pointer to current information
481     * about slave. */
482     int argc; /* Number of config arguments. */
483     char **argv; /* String values for arguments. */
484     {
485     register Master *masterPtr;
486     int c, result;
487     size_t length;
488     double d;
489    
490     result = TCL_OK;
491     if (Tk_IsTopLevel(slavePtr->tkwin)) {
492     Tcl_AppendResult(interp, "can't use placer on top-level window \"",
493     Tk_PathName(slavePtr->tkwin), "\"; use wm command instead",
494     (char *) NULL);
495     return TCL_ERROR;
496     }
497     for ( ; argc > 0; argc -= 2, argv += 2) {
498     if (argc < 2) {
499     Tcl_AppendResult(interp, "extra option \"", argv[0],
500     "\" (option with no value?)", (char *) NULL);
501     result = TCL_ERROR;
502     goto done;
503     }
504     length = strlen(argv[0]);
505     c = argv[0][1];
506     if ((c == 'a') && (strncmp(argv[0], "-anchor", length) == 0)) {
507     if (Tk_GetAnchor(interp, argv[1], &slavePtr->anchor) != TCL_OK) {
508     result = TCL_ERROR;
509     goto done;
510     }
511     } else if ((c == 'b')
512     && (strncmp(argv[0], "-bordermode", length) == 0)) {
513     c = argv[1][0];
514     length = strlen(argv[1]);
515     if ((c == 'i') && (strncmp(argv[1], "ignore", length) == 0)
516     && (length >= 2)) {
517     slavePtr->borderMode = BM_IGNORE;
518     } else if ((c == 'i') && (strncmp(argv[1], "inside", length) == 0)
519     && (length >= 2)) {
520     slavePtr->borderMode = BM_INSIDE;
521     } else if ((c == 'o')
522     && (strncmp(argv[1], "outside", length) == 0)) {
523     slavePtr->borderMode = BM_OUTSIDE;
524     } else {
525     Tcl_AppendResult(interp, "bad border mode \"", argv[1],
526     "\": must be ignore, inside, or outside",
527     (char *) NULL);
528     result = TCL_ERROR;
529     goto done;
530     }
531     } else if ((c == 'h') && (strncmp(argv[0], "-height", length) == 0)) {
532     if (argv[1][0] == 0) {
533     slavePtr->flags &= ~CHILD_HEIGHT;
534     } else {
535     if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1],
536     &slavePtr->height) != TCL_OK) {
537     result = TCL_ERROR;
538     goto done;
539     }
540     slavePtr->flags |= CHILD_HEIGHT;
541     }
542     } else if ((c == 'i') && (strncmp(argv[0], "-in", length) == 0)) {
543     Tk_Window tkwin;
544     Tk_Window ancestor;
545    
546     tkwin = Tk_NameToWindow(interp, argv[1], slavePtr->tkwin);
547     if (tkwin == NULL) {
548     result = TCL_ERROR;
549     goto done;
550     }
551    
552     /*
553     * Make sure that the new master is either the logical parent
554     * of the slave or a descendant of that window, and that the
555     * master and slave aren't the same.
556     */
557    
558     for (ancestor = tkwin; ; ancestor = Tk_Parent(ancestor)) {
559     if (ancestor == Tk_Parent(slavePtr->tkwin)) {
560     break;
561     }
562     if (Tk_IsTopLevel(ancestor)) {
563     Tcl_AppendResult(interp, "can't place ",
564     Tk_PathName(slavePtr->tkwin), " relative to ",
565     Tk_PathName(tkwin), (char *) NULL);
566     result = TCL_ERROR;
567     goto done;
568     }
569     }
570     if (slavePtr->tkwin == tkwin) {
571     Tcl_AppendResult(interp, "can't place ",
572     Tk_PathName(slavePtr->tkwin), " relative to itself",
573     (char *) NULL);
574     result = TCL_ERROR;
575     goto done;
576     }
577     if ((slavePtr->masterPtr != NULL)
578     && (slavePtr->masterPtr->tkwin == tkwin)) {
579     /*
580     * Re-using same old master. Nothing to do.
581     */
582     } else {
583     if ((slavePtr->masterPtr != NULL)
584     && (slavePtr->masterPtr->tkwin
585     != Tk_Parent(slavePtr->tkwin))) {
586     Tk_UnmaintainGeometry(slavePtr->tkwin,
587     slavePtr->masterPtr->tkwin);
588     }
589     UnlinkSlave(slavePtr);
590     slavePtr->masterPtr = FindMaster(tkwin);
591     slavePtr->nextPtr = slavePtr->masterPtr->slavePtr;
592     slavePtr->masterPtr->slavePtr = slavePtr;
593     }
594     } else if ((c == 'r') && (strncmp(argv[0], "-relheight", length) == 0)
595     && (length >= 5)) {
596     if (argv[1][0] == 0) {
597     slavePtr->flags &= ~CHILD_REL_HEIGHT;
598     } else {
599     if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) {
600     result = TCL_ERROR;
601     goto done;
602     }
603     slavePtr->relHeight = (float) d;
604     slavePtr->flags |= CHILD_REL_HEIGHT;
605     }
606     } else if ((c == 'r') && (strncmp(argv[0], "-relwidth", length) == 0)
607     && (length >= 5)) {
608     if (argv[1][0] == 0) {
609     slavePtr->flags &= ~CHILD_REL_WIDTH;
610     } else {
611     if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) {
612     result = TCL_ERROR;
613     goto done;
614     }
615     slavePtr->relWidth = (float) d;
616     slavePtr->flags |= CHILD_REL_WIDTH;
617     }
618     } else if ((c == 'r') && (strncmp(argv[0], "-relx", length) == 0)
619     && (length >= 5)) {
620     if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) {
621     result = TCL_ERROR;
622     goto done;
623     }
624     slavePtr->relX = (float) d;
625     } else if ((c == 'r') && (strncmp(argv[0], "-rely", length) == 0)
626     && (length >= 5)) {
627     if (Tcl_GetDouble(interp, argv[1], &d) != TCL_OK) {
628     result = TCL_ERROR;
629     goto done;
630     }
631     slavePtr->relY = (float) d;
632     } else if ((c == 'w') && (strncmp(argv[0], "-width", length) == 0)) {
633     if (argv[1][0] == 0) {
634     slavePtr->flags &= ~CHILD_WIDTH;
635     } else {
636     if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1],
637     &slavePtr->width) != TCL_OK) {
638     result = TCL_ERROR;
639     goto done;
640     }
641     slavePtr->flags |= CHILD_WIDTH;
642     }
643     } else if ((c == 'x') && (strncmp(argv[0], "-x", length) == 0)) {
644     if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1],
645     &slavePtr->x) != TCL_OK) {
646     result = TCL_ERROR;
647     goto done;
648     }
649     } else if ((c == 'y') && (strncmp(argv[0], "-y", length) == 0)) {
650     if (Tk_GetPixels(interp, slavePtr->tkwin, argv[1],
651     &slavePtr->y) != TCL_OK) {
652     result = TCL_ERROR;
653     goto done;
654     }
655     } else {
656     Tcl_AppendResult(interp, "unknown or ambiguous option \"",
657     argv[0], "\": must be -anchor, -bordermode, -height, ",
658     "-in, -relheight, -relwidth, -relx, -rely, -width, ",
659     "-x, or -y", (char *) NULL);
660     result = TCL_ERROR;
661     goto done;
662     }
663     }
664    
665     /*
666     * If there's no master specified for this slave, use its Tk_Parent.
667     * Then arrange for a placement recalculation in the master.
668     */
669    
670     done:
671     masterPtr = slavePtr->masterPtr;
672     if (masterPtr == NULL) {
673     masterPtr = FindMaster(Tk_Parent(slavePtr->tkwin));
674     slavePtr->masterPtr = masterPtr;
675     slavePtr->nextPtr = masterPtr->slavePtr;
676     masterPtr->slavePtr = slavePtr;
677     }
678     if (!(masterPtr->flags & PARENT_RECONFIG_PENDING)) {
679     masterPtr->flags |= PARENT_RECONFIG_PENDING;
680     Tcl_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr);
681     }
682     return result;
683     }
684    
685     /*
686     *----------------------------------------------------------------------
687     *
688     * RecomputePlacement --
689     *
690     * This procedure is called as a when-idle handler. It recomputes
691     * the geometries of all the slaves of a given master.
692     *
693     * Results:
694     * None.
695     *
696     * Side effects:
697     * Windows may change size or shape.
698     *
699     *----------------------------------------------------------------------
700     */
701    
702     static void
703     RecomputePlacement(clientData)
704     ClientData clientData; /* Pointer to Master record. */
705     {
706     register Master *masterPtr = (Master *) clientData;
707     register Slave *slavePtr;
708     int x, y, width, height, tmp;
709     int masterWidth, masterHeight, masterBW;
710     double x1, y1, x2, y2;
711    
712     masterPtr->flags &= ~PARENT_RECONFIG_PENDING;
713    
714     /*
715     * Iterate over all the slaves for the master. Each slave's
716     * geometry can be computed independently of the other slaves.
717     */
718    
719     for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
720     slavePtr = slavePtr->nextPtr) {
721     /*
722     * Step 1: compute size and borderwidth of master, taking into
723     * account desired border mode.
724     */
725    
726     masterBW = 0;
727     masterWidth = Tk_Width(masterPtr->tkwin);
728     masterHeight = Tk_Height(masterPtr->tkwin);
729     if (slavePtr->borderMode == BM_INSIDE) {
730     masterBW = Tk_InternalBorderWidth(masterPtr->tkwin);
731     } else if (slavePtr->borderMode == BM_OUTSIDE) {
732     masterBW = -Tk_Changes(masterPtr->tkwin)->border_width;
733     }
734     masterWidth -= 2*masterBW;
735     masterHeight -= 2*masterBW;
736    
737     /*
738     * Step 2: compute size of slave (outside dimensions including
739     * border) and location of anchor point within master.
740     */
741    
742     x1 = slavePtr->x + masterBW + (slavePtr->relX*masterWidth);
743     x = (int) (x1 + ((x1 > 0) ? 0.5 : -0.5));
744     y1 = slavePtr->y + masterBW + (slavePtr->relY*masterHeight);
745     y = (int) (y1 + ((y1 > 0) ? 0.5 : -0.5));
746     if (slavePtr->flags & (CHILD_WIDTH|CHILD_REL_WIDTH)) {
747     width = 0;
748     if (slavePtr->flags & CHILD_WIDTH) {
749     width += slavePtr->width;
750     }
751     if (slavePtr->flags & CHILD_REL_WIDTH) {
752     /*
753     * The code below is a bit tricky. In order to round
754     * correctly when both relX and relWidth are specified,
755     * compute the location of the right edge and round that,
756     * then compute width. If we compute the width and round
757     * it, rounding errors in relX and relWidth accumulate.
758     */
759    
760     x2 = x1 + (slavePtr->relWidth*masterWidth);
761     tmp = (int) (x2 + ((x2 > 0) ? 0.5 : -0.5));
762     width += tmp - x;
763     }
764     } else {
765     width = Tk_ReqWidth(slavePtr->tkwin)
766     + 2*Tk_Changes(slavePtr->tkwin)->border_width;
767     }
768     if (slavePtr->flags & (CHILD_HEIGHT|CHILD_REL_HEIGHT)) {
769     height = 0;
770     if (slavePtr->flags & CHILD_HEIGHT) {
771     height += slavePtr->height;
772     }
773     if (slavePtr->flags & CHILD_REL_HEIGHT) {
774     /*
775     * See note above for rounding errors in width computation.
776     */
777    
778     y2 = y1 + (slavePtr->relHeight*masterHeight);
779     tmp = (int) (y2 + ((y2 > 0) ? 0.5 : -0.5));
780     height += tmp - y;
781     }
782     } else {
783     height = Tk_ReqHeight(slavePtr->tkwin)
784     + 2*Tk_Changes(slavePtr->tkwin)->border_width;
785     }
786    
787     /*
788     * Step 3: adjust the x and y positions so that the desired
789     * anchor point on the slave appears at that position. Also
790     * adjust for the border mode and master's border.
791     */
792    
793     switch (slavePtr->anchor) {
794     case TK_ANCHOR_N:
795     x -= width/2;
796     break;
797     case TK_ANCHOR_NE:
798     x -= width;
799     break;
800     case TK_ANCHOR_E:
801     x -= width;
802     y -= height/2;
803     break;
804     case TK_ANCHOR_SE:
805     x -= width;
806     y -= height;
807     break;
808     case TK_ANCHOR_S:
809     x -= width/2;
810     y -= height;
811     break;
812     case TK_ANCHOR_SW:
813     y -= height;
814     break;
815     case TK_ANCHOR_W:
816     y -= height/2;
817     break;
818     case TK_ANCHOR_NW:
819     break;
820     case TK_ANCHOR_CENTER:
821     x -= width/2;
822     y -= height/2;
823     break;
824     }
825    
826     /*
827     * Step 4: adjust width and height again to reflect inside dimensions
828     * of window rather than outside. Also make sure that the width and
829     * height aren't zero.
830     */
831    
832     width -= 2*Tk_Changes(slavePtr->tkwin)->border_width;
833     height -= 2*Tk_Changes(slavePtr->tkwin)->border_width;
834     if (width <= 0) {
835     width = 1;
836     }
837     if (height <= 0) {
838     height = 1;
839     }
840    
841     /*
842     * Step 5: reconfigure the window and map it if needed. If the
843     * slave is a child of the master, we do this ourselves. If the
844     * slave isn't a child of the master, let Tk_MaintainGeometry do
845     * the work (it will re-adjust things as relevant windows map,
846     * unmap, and move).
847     */
848    
849     if (masterPtr->tkwin == Tk_Parent(slavePtr->tkwin)) {
850     if ((x != Tk_X(slavePtr->tkwin))
851     || (y != Tk_Y(slavePtr->tkwin))
852     || (width != Tk_Width(slavePtr->tkwin))
853     || (height != Tk_Height(slavePtr->tkwin))) {
854     Tk_MoveResizeWindow(slavePtr->tkwin, x, y, width, height);
855     }
856    
857     /*
858     * Don't map the slave unless the master is mapped: the slave
859     * will get mapped later, when the master is mapped.
860     */
861    
862     if (Tk_IsMapped(masterPtr->tkwin)) {
863     Tk_MapWindow(slavePtr->tkwin);
864     }
865     } else {
866     if ((width <= 0) || (height <= 0)) {
867     Tk_UnmaintainGeometry(slavePtr->tkwin, masterPtr->tkwin);
868     Tk_UnmapWindow(slavePtr->tkwin);
869     } else {
870     Tk_MaintainGeometry(slavePtr->tkwin, masterPtr->tkwin,
871     x, y, width, height);
872     }
873     }
874     }
875     }
876    
877     /*
878     *----------------------------------------------------------------------
879     *
880     * MasterStructureProc --
881     *
882     * This procedure is invoked by the Tk event handler when
883     * StructureNotify events occur for a master window.
884     *
885     * Results:
886     * None.
887     *
888     * Side effects:
889     * Structures get cleaned up if the window was deleted. If the
890     * window was resized then slave geometries get recomputed.
891     *
892     *----------------------------------------------------------------------
893     */
894    
895     static void
896     MasterStructureProc(clientData, eventPtr)
897     ClientData clientData; /* Pointer to Master structure for window
898     * referred to by eventPtr. */
899     XEvent *eventPtr; /* Describes what just happened. */
900     {
901     register Master *masterPtr = (Master *) clientData;
902     register Slave *slavePtr, *nextPtr;
903     TkDisplay *dispPtr = ((TkWindow *) masterPtr->tkwin)->dispPtr;
904    
905     if (eventPtr->type == ConfigureNotify) {
906     if ((masterPtr->slavePtr != NULL)
907     && !(masterPtr->flags & PARENT_RECONFIG_PENDING)) {
908     masterPtr->flags |= PARENT_RECONFIG_PENDING;
909     Tcl_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr);
910     }
911     } else if (eventPtr->type == DestroyNotify) {
912     for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
913     slavePtr = nextPtr) {
914     slavePtr->masterPtr = NULL;
915     nextPtr = slavePtr->nextPtr;
916     slavePtr->nextPtr = NULL;
917     }
918     Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->masterTable,
919     (char *) masterPtr->tkwin));
920     if (masterPtr->flags & PARENT_RECONFIG_PENDING) {
921     Tcl_CancelIdleCall(RecomputePlacement, (ClientData) masterPtr);
922     }
923     masterPtr->tkwin = NULL;
924     ckfree((char *) masterPtr);
925     } else if (eventPtr->type == MapNotify) {
926     /*
927     * When a master gets mapped, must redo the geometry computation
928     * so that all of its slaves get remapped.
929     */
930    
931     if ((masterPtr->slavePtr != NULL)
932     && !(masterPtr->flags & PARENT_RECONFIG_PENDING)) {
933     masterPtr->flags |= PARENT_RECONFIG_PENDING;
934     Tcl_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr);
935     }
936     } else if (eventPtr->type == UnmapNotify) {
937     /*
938     * Unmap all of the slaves when the master gets unmapped,
939     * so that they don't keep redisplaying themselves.
940     */
941    
942     for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
943     slavePtr = slavePtr->nextPtr) {
944     Tk_UnmapWindow(slavePtr->tkwin);
945     }
946     }
947     }
948    
949     /*
950     *----------------------------------------------------------------------
951     *
952     * SlaveStructureProc --
953     *
954     * This procedure is invoked by the Tk event handler when
955     * StructureNotify events occur for a slave window.
956     *
957     * Results:
958     * None.
959     *
960     * Side effects:
961     * Structures get cleaned up if the window was deleted.
962     *
963     *----------------------------------------------------------------------
964     */
965    
966     static void
967     SlaveStructureProc(clientData, eventPtr)
968     ClientData clientData; /* Pointer to Slave structure for window
969     * referred to by eventPtr. */
970     XEvent *eventPtr; /* Describes what just happened. */
971     {
972     register Slave *slavePtr = (Slave *) clientData;
973     TkDisplay * dispPtr = ((TkWindow *) slavePtr->tkwin)->dispPtr;
974    
975     if (eventPtr->type == DestroyNotify) {
976     UnlinkSlave(slavePtr);
977     Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->slaveTable,
978     (char *) slavePtr->tkwin));
979     ckfree((char *) slavePtr);
980     }
981     }
982    
983     /*
984     *----------------------------------------------------------------------
985     *
986     * PlaceRequestProc --
987     *
988     * This procedure is invoked by Tk whenever a slave managed by us
989     * changes its requested geometry.
990     *
991     * Results:
992     * None.
993     *
994     * Side effects:
995     * The window will get relayed out, if its requested size has
996     * anything to do with its actual size.
997     *
998     *----------------------------------------------------------------------
999     */
1000    
1001     /* ARGSUSED */
1002     static void
1003     PlaceRequestProc(clientData, tkwin)
1004     ClientData clientData; /* Pointer to our record for slave. */
1005     Tk_Window tkwin; /* Window that changed its desired
1006     * size. */
1007     {
1008     Slave *slavePtr = (Slave *) clientData;
1009     Master *masterPtr;
1010    
1011     if (((slavePtr->flags & (CHILD_WIDTH|CHILD_REL_WIDTH)) != 0)
1012     && ((slavePtr->flags & (CHILD_HEIGHT|CHILD_REL_HEIGHT)) != 0)) {
1013     return;
1014     }
1015     masterPtr = slavePtr->masterPtr;
1016     if (masterPtr == NULL) {
1017     return;
1018     }
1019     if (!(masterPtr->flags & PARENT_RECONFIG_PENDING)) {
1020     masterPtr->flags |= PARENT_RECONFIG_PENDING;
1021     Tcl_DoWhenIdle(RecomputePlacement, (ClientData) masterPtr);
1022     }
1023     }
1024    
1025     /*
1026     *--------------------------------------------------------------
1027     *
1028     * PlaceLostSlaveProc --
1029     *
1030     * This procedure is invoked by Tk whenever some other geometry
1031     * claims control over a slave that used to be managed by us.
1032     *
1033     * Results:
1034     * None.
1035     *
1036     * Side effects:
1037     * Forgets all placer-related information about the slave.
1038     *
1039     *--------------------------------------------------------------
1040     */
1041    
1042     /* ARGSUSED */
1043     static void
1044     PlaceLostSlaveProc(clientData, tkwin)
1045     ClientData clientData; /* Slave structure for slave window that
1046     * was stolen away. */
1047     Tk_Window tkwin; /* Tk's handle for the slave window. */
1048     {
1049     register Slave *slavePtr = (Slave *) clientData;
1050     TkDisplay * dispPtr = ((TkWindow *) slavePtr->tkwin)->dispPtr;
1051    
1052     if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {
1053     Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin);
1054     }
1055     Tk_UnmapWindow(tkwin);
1056     UnlinkSlave(slavePtr);
1057     Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->slaveTable,
1058     (char *) tkwin));
1059     Tk_DeleteEventHandler(tkwin, StructureNotifyMask, SlaveStructureProc,
1060     (ClientData) slavePtr);
1061     ckfree((char *) slavePtr);
1062     }
1063    
1064    
1065     /* $History: tkPlace.c $
1066     *
1067     * ***************** Version 1 *****************
1068     * User: Dtashley Date: 1/02/01 Time: 3:04a
1069     * Created in $/IjuScripter, IjuConsole/Source/Tk Base
1070     * Initial check-in.
1071     */
1072    
1073     /* End of TKPLACE.C */

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25