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

Subversion Repositories or1k

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

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

Line No. Rev Author Line
1 578 markom
/*
2
 * tkGeometry.c --
3
 *
4
 *      This file contains generic Tk code for geometry management
5
 *      (stuff that's used by all geometry managers).
6
 *
7
 * Copyright (c) 1990-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: tkGeometry.c,v 1.1.1.1 2002-01-16 10:25:51 markom Exp $
14
 */
15
 
16
#include "tkPort.h"
17
#include "tkInt.h"
18
 
19
/*
20
 * Data structures of the following type are used by Tk_MaintainGeometry.
21
 * For each slave managed by Tk_MaintainGeometry, there is one of these
22
 * structures associated with its master.
23
 */
24
 
25
typedef struct MaintainSlave {
26
    Tk_Window slave;            /* The slave window being positioned. */
27
    Tk_Window master;           /* The master that determines slave's
28
                                 * position; it must be a descendant of
29
                                 * slave's parent. */
30
    int x, y;                   /* Desired position of slave relative to
31
                                 * master. */
32
    int width, height;          /* Desired dimensions of slave. */
33
    struct MaintainSlave *nextPtr;
34
                                /* Next in list of Maintains associated
35
                                 * with master. */
36
} MaintainSlave;
37
 
38
/*
39
 * For each window that has been specified as a master to
40
 * Tk_MaintainGeometry, there is a structure of the following type:
41
 */
42
 
43
typedef struct MaintainMaster {
44
    Tk_Window ancestor;         /* The lowest ancestor of this window
45
                                 * for which we have *not* created a
46
                                 * StructureNotify handler.  May be the
47
                                 * same as the window itself. */
48
    int checkScheduled;         /* Non-zero means that there is already a
49
                                 * call to MaintainCheckProc scheduled as
50
                                 * an idle handler. */
51
    MaintainSlave *slavePtr;    /* First in list of all slaves associated
52
                                 * with this master. */
53
} MaintainMaster;
54
 
55
/*
56
 * Hash table that maps from a master's Tk_Window token to a list of
57
 * Maintains for that master:
58
 */
59
 
60
static Tcl_HashTable maintainHashTable;
61
 
62
/*
63
 * Has maintainHashTable been initialized yet?
64
 */
65
 
66
static int initialized = 0;
67
 
68
/*
69
 * Prototypes for static procedures in this file:
70
 */
71
 
72
static void             MaintainCheckProc _ANSI_ARGS_((ClientData clientData));
73
static void             MaintainMasterProc _ANSI_ARGS_((ClientData clientData,
74
                            XEvent *eventPtr));
75
static void             MaintainSlaveProc _ANSI_ARGS_((ClientData clientData,
76
                            XEvent *eventPtr));
77
 
78
/*
79
 *--------------------------------------------------------------
80
 *
81
 * Tk_ManageGeometry --
82
 *
83
 *      Arrange for a particular procedure to manage the geometry
84
 *      of a given slave window.
85
 *
86
 * Results:
87
 *      None.
88
 *
89
 * Side effects:
90
 *      Proc becomes the new geometry manager for tkwin, replacing
91
 *      any previous geometry manager.  The geometry manager will
92
 *      be notified (by calling procedures in *mgrPtr) when interesting
93
 *      things happen in the future.  If there was an existing geometry
94
 *      manager for tkwin different from the new one, it is notified
95
 *      by calling its lostSlaveProc.
96
 *
97
 *--------------------------------------------------------------
98
 */
99
 
100
void
101
Tk_ManageGeometry(tkwin, mgrPtr, clientData)
102
    Tk_Window tkwin;            /* Window whose geometry is to
103
                                 * be managed by proc.  */
104
    Tk_GeomMgr *mgrPtr;         /* Static structure describing the
105
                                 * geometry manager.  This structure
106
                                 * must never go away. */
107
    ClientData clientData;      /* Arbitrary one-word argument to
108
                                 * pass to geometry manager procedures. */
109
{
110
    register TkWindow *winPtr = (TkWindow *) tkwin;
111
 
112
    if ((winPtr->geomMgrPtr != NULL) && (mgrPtr != NULL)
113
            && ((winPtr->geomMgrPtr != mgrPtr)
114
                || (winPtr->geomData != clientData))
115
            && (winPtr->geomMgrPtr->lostSlaveProc != NULL)) {
116
        (*winPtr->geomMgrPtr->lostSlaveProc)(winPtr->geomData, tkwin);
117
    }
118
 
119
    winPtr->geomMgrPtr = mgrPtr;
120
    winPtr->geomData = clientData;
121
}
122
 
123
/*
124
 *--------------------------------------------------------------
125
 *
126
 * Tk_GeometryRequest --
127
 *
128
 *      This procedure is invoked by widget code to indicate
129
 *      its preferences about the size of a window it manages.
130
 *      In general, widget code should call this procedure
131
 *      rather than Tk_ResizeWindow.
132
 *
133
 * Results:
134
 *      None.
135
 *
136
 * Side effects:
137
 *      The geometry manager for tkwin (if any) is invoked to
138
 *      handle the request.  If possible, it will reconfigure
139
 *      tkwin and/or other windows to satisfy the request.  The
140
 *      caller gets no indication of success or failure, but it
141
 *      will get X events if the window size was actually
142
 *      changed.
143
 *
144
 *--------------------------------------------------------------
145
 */
146
 
147
void
148
Tk_GeometryRequest(tkwin, reqWidth, reqHeight)
149
    Tk_Window tkwin;            /* Window that geometry information
150
                                 * pertains to. */
151
    int reqWidth, reqHeight;    /* Minimum desired dimensions for
152
                                 * window, in pixels. */
153
{
154
    register TkWindow *winPtr = (TkWindow *) tkwin;
155
 
156
    /*
157
     * X gets very upset if a window requests a width or height of
158
     * zero, so rounds requested sizes up to at least 1.
159
     */
160
 
161
    if (reqWidth <= 0) {
162
        reqWidth = 1;
163
    }
164
    if (reqHeight <= 0) {
165
        reqHeight = 1;
166
    }
167
    if ((reqWidth == winPtr->reqWidth) && (reqHeight == winPtr->reqHeight)) {
168
        return;
169
    }
170
    winPtr->reqWidth = reqWidth;
171
    winPtr->reqHeight = reqHeight;
172
    if ((winPtr->geomMgrPtr != NULL)
173
            && (winPtr->geomMgrPtr->requestProc != NULL)) {
174
        (*winPtr->geomMgrPtr->requestProc)(winPtr->geomData, tkwin);
175
    }
176
}
177
 
178
/*
179
 *----------------------------------------------------------------------
180
 *
181
 * Tk_SetInternalBorder --
182
 *
183
 *      Notify relevant geometry managers that a window has an internal
184
 *      border of a given width and that child windows should not be
185
 *      placed on that border.
186
 *
187
 * Results:
188
 *      None.
189
 *
190
 * Side effects:
191
 *      The border width is recorded for the window, and all geometry
192
 *      managers of all children are notified so that can re-layout, if
193
 *      necessary.
194
 *
195
 *----------------------------------------------------------------------
196
 */
197
 
198
void
199
Tk_SetInternalBorder(tkwin, width)
200
    Tk_Window tkwin;            /* Window that will have internal border. */
201
    int width;                  /* Width of internal border, in pixels. */
202
{
203
    register TkWindow *winPtr = (TkWindow *) tkwin;
204
 
205
    if (width == winPtr->internalBorderWidth) {
206
        return;
207
    }
208
    if (width < 0) {
209
        width = 0;
210
    }
211
    winPtr->internalBorderWidth = width;
212
 
213
    /*
214
     * All the slaves for which this is the master window must now be
215
     * repositioned to take account of the new internal border width.
216
     * To signal all the geometry managers to do this, just resize the
217
     * window to its current size.  The ConfigureNotify event will
218
     * cause geometry managers to recompute everything.
219
     */
220
 
221
    Tk_ResizeWindow(tkwin, Tk_Width(tkwin), Tk_Height(tkwin));
222
}
223
 
224
/*
225
 *----------------------------------------------------------------------
226
 *
227
 * Tk_MaintainGeometry --
228
 *
229
 *      This procedure is invoked by geometry managers to handle slaves
230
 *      whose master's are not their parents.  It translates the desired
231
 *      geometry for the slave into the coordinate system of the parent
232
 *      and respositions the slave if it isn't already at the right place.
233
 *      Furthermore, it sets up event handlers so that if the master (or
234
 *      any of its ancestors up to the slave's parent) is mapped, unmapped,
235
 *      or moved, then the slave will be adjusted to match.
236
 *
237
 * Results:
238
 *      None.
239
 *
240
 * Side effects:
241
 *      Event handlers are created and state is allocated to keep track
242
 *      of slave.  Note:  if slave was already managed for master by
243
 *      Tk_MaintainGeometry, then the previous information is replaced
244
 *      with the new information.  The caller must eventually call
245
 *      Tk_UnmaintainGeometry to eliminate the correspondence (or, the
246
 *      state is automatically freed when either window is destroyed).
247
 *
248
 *----------------------------------------------------------------------
249
 */
250
 
251
void
252
Tk_MaintainGeometry(slave, master, x, y, width, height)
253
    Tk_Window slave;            /* Slave for geometry management. */
254
    Tk_Window master;           /* Master for slave; must be a descendant
255
                                 * of slave's parent. */
256
    int x, y;                   /* Desired position of slave within master. */
257
    int width, height;          /* Desired dimensions for slave. */
258
{
259
    Tcl_HashEntry *hPtr;
260
    MaintainMaster *masterPtr;
261
    register MaintainSlave *slavePtr;
262
    int new, map;
263
    Tk_Window ancestor, parent;
264
 
265
    if (!initialized) {
266
        initialized = 1;
267
        Tcl_InitHashTable(&maintainHashTable, TCL_ONE_WORD_KEYS);
268
    }
269
 
270
    /*
271
     * See if there is already a MaintainMaster structure for the master;
272
     * if not, then create one.
273
     */
274
 
275
    parent = Tk_Parent(slave);
276
    hPtr = Tcl_CreateHashEntry(&maintainHashTable, (char *) master, &new);
277
    if (!new) {
278
        masterPtr = (MaintainMaster *) Tcl_GetHashValue(hPtr);
279
    } else {
280
        masterPtr = (MaintainMaster *) ckalloc(sizeof(MaintainMaster));
281
        masterPtr->ancestor = master;
282
        masterPtr->checkScheduled = 0;
283
        masterPtr->slavePtr = NULL;
284
        Tcl_SetHashValue(hPtr, masterPtr);
285
    }
286
 
287
    /*
288
     * Create a MaintainSlave structure for the slave if there isn't
289
     * already one.
290
     */
291
 
292
    for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
293
            slavePtr = slavePtr->nextPtr) {
294
        if (slavePtr->slave == slave) {
295
            goto gotSlave;
296
        }
297
    }
298
    slavePtr = (MaintainSlave *) ckalloc(sizeof(MaintainSlave));
299
    slavePtr->slave = slave;
300
    slavePtr->master = master;
301
    slavePtr->nextPtr = masterPtr->slavePtr;
302
    masterPtr->slavePtr = slavePtr;
303
    Tk_CreateEventHandler(slave, StructureNotifyMask, MaintainSlaveProc,
304
            (ClientData) slavePtr);
305
 
306
    /*
307
     * Make sure that there are event handlers registered for all
308
     * the windows between master and slave's parent (including master
309
     * but not slave's parent).  There may already be handlers for master
310
     * and some of its ancestors (masterPtr->ancestor tells how many).
311
     */
312
 
313
    for (ancestor = master; ancestor != parent;
314
            ancestor = Tk_Parent(ancestor)) {
315
        if (ancestor == masterPtr->ancestor) {
316
            Tk_CreateEventHandler(ancestor, StructureNotifyMask,
317
                    MaintainMasterProc, (ClientData) masterPtr);
318
            masterPtr->ancestor = Tk_Parent(ancestor);
319
        }
320
    }
321
 
322
    /*
323
     * Fill in up-to-date information in the structure, then update the
324
     * window if it's not currently in the right place or state.
325
     */
326
 
327
    gotSlave:
328
    slavePtr->x = x;
329
    slavePtr->y = y;
330
    slavePtr->width = width;
331
    slavePtr->height = height;
332
    map = 1;
333
    for (ancestor = slavePtr->master; ; ancestor = Tk_Parent(ancestor)) {
334
        if (!Tk_IsMapped(ancestor) && (ancestor != parent)) {
335
            map = 0;
336
        }
337
        if (ancestor == parent) {
338
            if ((x != Tk_X(slavePtr->slave))
339
                    || (y != Tk_Y(slavePtr->slave))
340
                    || (width != Tk_Width(slavePtr->slave))
341
                    || (height != Tk_Height(slavePtr->slave))) {
342
                Tk_MoveResizeWindow(slavePtr->slave, x, y, width, height);
343
            }
344
            if (map) {
345
                Tk_MapWindow(slavePtr->slave);
346
            } else {
347
                Tk_UnmapWindow(slavePtr->slave);
348
            }
349
            break;
350
        }
351
        x += Tk_X(ancestor) + Tk_Changes(ancestor)->border_width;
352
        y += Tk_Y(ancestor) + Tk_Changes(ancestor)->border_width;
353
    }
354
}
355
 
356
/*
357
 *----------------------------------------------------------------------
358
 *
359
 * Tk_UnmaintainGeometry --
360
 *
361
 *      This procedure cancels a previous Tk_MaintainGeometry call,
362
 *      so that the relationship between slave and master is no longer
363
 *      maintained.
364
 *
365
 * Results:
366
 *      None.
367
 *
368
 * Side effects:
369
 *      The slave is unmapped and state is released, so that slave won't
370
 *      track master any more.  If we weren't previously managing slave
371
 *      relative to master, then this procedure has no effect.
372
 *
373
 *----------------------------------------------------------------------
374
 */
375
 
376
void
377
Tk_UnmaintainGeometry(slave, master)
378
    Tk_Window slave;            /* Slave for geometry management. */
379
    Tk_Window master;           /* Master for slave; must be a descendant
380
                                 * of slave's parent. */
381
{
382
    Tcl_HashEntry *hPtr;
383
    MaintainMaster *masterPtr;
384
    register MaintainSlave *slavePtr, *prevPtr;
385
    Tk_Window ancestor;
386
 
387
    if (!initialized) {
388
        initialized = 1;
389
        Tcl_InitHashTable(&maintainHashTable, TCL_ONE_WORD_KEYS);
390
    }
391
 
392
    if (!(((TkWindow *) slave)->flags & TK_ALREADY_DEAD)) {
393
        Tk_UnmapWindow(slave);
394
    }
395
    hPtr = Tcl_FindHashEntry(&maintainHashTable, (char *) master);
396
    if (hPtr == NULL) {
397
        return;
398
    }
399
    masterPtr = (MaintainMaster *) Tcl_GetHashValue(hPtr);
400
    slavePtr = masterPtr->slavePtr;
401
    if (slavePtr->slave == slave) {
402
        masterPtr->slavePtr = slavePtr->nextPtr;
403
    } else {
404
        for (prevPtr = slavePtr, slavePtr = slavePtr->nextPtr; ;
405
                prevPtr = slavePtr, slavePtr = slavePtr->nextPtr) {
406
            if (slavePtr == NULL) {
407
                return;
408
            }
409
            if (slavePtr->slave == slave) {
410
                prevPtr->nextPtr = slavePtr->nextPtr;
411
                break;
412
            }
413
        }
414
    }
415
    Tk_DeleteEventHandler(slavePtr->slave, StructureNotifyMask,
416
            MaintainSlaveProc, (ClientData) slavePtr);
417
    ckfree((char *) slavePtr);
418
    if (masterPtr->slavePtr == NULL) {
419
        if (masterPtr->ancestor != NULL) {
420
            for (ancestor = master; ; ancestor = Tk_Parent(ancestor)) {
421
                Tk_DeleteEventHandler(ancestor, StructureNotifyMask,
422
                        MaintainMasterProc, (ClientData) masterPtr);
423
                if (ancestor == masterPtr->ancestor) {
424
                    break;
425
                }
426
            }
427
        }
428
        if (masterPtr->checkScheduled) {
429
            Tcl_CancelIdleCall(MaintainCheckProc, (ClientData) masterPtr);
430
        }
431
        Tcl_DeleteHashEntry(hPtr);
432
        ckfree((char *) masterPtr);
433
    }
434
}
435
 
436
/*
437
 *----------------------------------------------------------------------
438
 *
439
 * MaintainMasterProc --
440
 *
441
 *      This procedure is invoked by the Tk event dispatcher in
442
 *      response to StructureNotify events on the master or one
443
 *      of its ancestors, on behalf of Tk_MaintainGeometry.
444
 *
445
 * Results:
446
 *      None.
447
 *
448
 * Side effects:
449
 *      It schedules a call to MaintainCheckProc, which will eventually
450
 *      caused the postions and mapped states to be recalculated for all
451
 *      the maintained slaves of the master.  Or, if the master window is
452
 *      being deleted then state is cleaned up.
453
 *
454
 *----------------------------------------------------------------------
455
 */
456
 
457
static void
458
MaintainMasterProc(clientData, eventPtr)
459
    ClientData clientData;              /* Pointer to MaintainMaster structure
460
                                         * for the master window. */
461
    XEvent *eventPtr;                   /* Describes what just happened. */
462
{
463
    MaintainMaster *masterPtr = (MaintainMaster *) clientData;
464
    MaintainSlave *slavePtr;
465
    int done;
466
 
467
    if ((eventPtr->type == ConfigureNotify)
468
            || (eventPtr->type == MapNotify)
469
            || (eventPtr->type == UnmapNotify)) {
470
        if (!masterPtr->checkScheduled) {
471
            masterPtr->checkScheduled = 1;
472
            Tcl_DoWhenIdle(MaintainCheckProc, (ClientData) masterPtr);
473
        }
474
    } else if (eventPtr->type == DestroyNotify) {
475
        /*
476
         * Delete all of the state associated with this master, but
477
         * be careful not to use masterPtr after the last slave is
478
         * deleted, since its memory will have been freed.
479
         */
480
 
481
        done = 0;
482
        do {
483
            slavePtr = masterPtr->slavePtr;
484
            if (slavePtr->nextPtr == NULL) {
485
                done = 1;
486
            }
487
            Tk_UnmaintainGeometry(slavePtr->slave, slavePtr->master);
488
        } while (!done);
489
    }
490
}
491
 
492
/*
493
 *----------------------------------------------------------------------
494
 *
495
 * MaintainSlaveProc --
496
 *
497
 *      This procedure is invoked by the Tk event dispatcher in
498
 *      response to StructureNotify events on a slave being managed
499
 *      by Tk_MaintainGeometry.
500
 *
501
 * Results:
502
 *      None.
503
 *
504
 * Side effects:
505
 *      If the event is a DestroyNotify event then the Maintain state
506
 *      and event handlers for this slave are deleted.
507
 *
508
 *----------------------------------------------------------------------
509
 */
510
 
511
static void
512
MaintainSlaveProc(clientData, eventPtr)
513
    ClientData clientData;              /* Pointer to MaintainSlave structure
514
                                         * for master-slave pair. */
515
    XEvent *eventPtr;                   /* Describes what just happened. */
516
{
517
    MaintainSlave *slavePtr = (MaintainSlave *) clientData;
518
 
519
    if (eventPtr->type == DestroyNotify) {
520
        Tk_UnmaintainGeometry(slavePtr->slave, slavePtr->master);
521
    }
522
}
523
 
524
/*
525
 *----------------------------------------------------------------------
526
 *
527
 * MaintainCheckProc --
528
 *
529
 *      This procedure is invoked by the Tk event dispatcher as an
530
 *      idle handler, when a master or one of its ancestors has been
531
 *      reconfigured, mapped, or unmapped.  Its job is to scan all of
532
 *      the slaves for the master and reposition them, map them, or
533
 *      unmap them as needed to maintain their geometry relative to
534
 *      the master.
535
 *
536
 * Results:
537
 *      None.
538
 *
539
 * Side effects:
540
 *      Slaves can get repositioned, mapped, or unmapped.
541
 *
542
 *----------------------------------------------------------------------
543
 */
544
 
545
static void
546
MaintainCheckProc(clientData)
547
    ClientData clientData;              /* Pointer to MaintainMaster structure
548
                                         * for the master window. */
549
{
550
    MaintainMaster *masterPtr = (MaintainMaster *) clientData;
551
    MaintainSlave *slavePtr;
552
    Tk_Window ancestor, parent;
553
    int x, y, map;
554
 
555
    masterPtr->checkScheduled = 0;
556
    for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
557
            slavePtr = slavePtr->nextPtr) {
558
        parent = Tk_Parent(slavePtr->slave);
559
        x = slavePtr->x;
560
        y = slavePtr->y;
561
        map = 1;
562
        for (ancestor = slavePtr->master; ; ancestor = Tk_Parent(ancestor)) {
563
            if (!Tk_IsMapped(ancestor) && (ancestor != parent)) {
564
                map = 0;
565
            }
566
            if (ancestor == parent) {
567
                if ((x != Tk_X(slavePtr->slave))
568
                        || (y != Tk_Y(slavePtr->slave))) {
569
                    Tk_MoveWindow(slavePtr->slave, x, y);
570
                }
571
                if (map) {
572
                    Tk_MapWindow(slavePtr->slave);
573
                } else {
574
                    Tk_UnmapWindow(slavePtr->slave);
575
                }
576
                break;
577
            }
578
            x += Tk_X(ancestor) + Tk_Changes(ancestor)->border_width;
579
            y += Tk_Y(ancestor) + Tk_Changes(ancestor)->border_width;
580
        }
581
    }
582
}

powered by: WebSVN 2.1.0

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