OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [generic/] [tkPlace.c] - Blame information for rev 1780

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.