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

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tix/] [generic/] [tixForm.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tixForm.c --
3
 *
4
 *      Implements the tixForm geometry manager, which has similar
5
 *      capability as the Motif Form geometry manager. Please
6
 *      refer to the documentation for the use of tixForm.
7
 *
8
 *      This file implements the basic algorithm of tixForm.
9
 *
10
 * Copyright (c) 1996, Expert Interface Technologies
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
 */
16
 
17
/*
18
 *
19
 * ToDo:
20
 *
21
 *     (1) Delete the master structure when there is no more client to manage
22
 *
23
 * Possible bugs:
24
 * (1) a client is deleted but the master doesn't know
25
 *     (clientPtr->tkwin == NULL)
26
 * (2) Whan a client S is deleted or detached from the master, all other
27
 *     clients attached to S must delete their reference to S
28
 */
29
 
30
#include <tkInt.h>
31
#include <tixPort.h>
32
#include <tix.h>
33
#include <tixForm.h>
34
#define DEBUG 0
35
 
36
 
37
typedef struct SpringLink {
38
    struct SpringLink * next;
39
    FormInfo *clientPtr;
40
} SpringLink;
41
 
42
 
43
typedef struct SpringList {
44
    SpringLink * head, * tail;
45
    int num;
46
} SpringList;
47
 
48
 
49
/*
50
 * SubCommands of the tixForm command.
51
 */
52
static TIX_DECLARE_SUBCMD(TixFm_SetGrid);
53
static TIX_DECLARE_SUBCMD(TixFm_SetClient);
54
static TIX_DECLARE_SUBCMD(TixFm_Check);
55
static TIX_DECLARE_SUBCMD(TixFm_Forget);
56
EXTERN TIX_DECLARE_SUBCMD(TixFm_Info);
57
static TIX_DECLARE_SUBCMD(TixFm_Slaves);
58
static TIX_DECLARE_SUBCMD(TixFm_Spring);
59
 
60
static void             ArrangeGeometry _ANSI_ARGS_((ClientData clientData));
61
static void             ArrangeWhenIdle _ANSI_ARGS_((MasterInfo * masterPtr));
62
static void             CancelArrangeWhenIdle _ANSI_ARGS_((
63
                            MasterInfo * masterPtr));
64
static void             CalculateMasterSize _ANSI_ARGS_((MasterInfo *master));
65
static void             CheckIntergrity _ANSI_ARGS_((FormInfo * clientPtr));
66
static MasterInfo *     GetMasterInfo _ANSI_ARGS_((Tk_Window tkwin,
67
                            int create));
68
static void             MasterStructureProc _ANSI_ARGS_((ClientData clientData,
69
                            XEvent * eventPtr));
70
static int              PinnClient _ANSI_ARGS_((FormInfo *clientPtr));
71
static int              PinnClientSide _ANSI_ARGS_((FormInfo *clientPtr,
72
                            int axis, int which, int isSelf));
73
static int              PlaceClientSide _ANSI_ARGS_((FormInfo *clientPtr,
74
                            int axis, int which, int isSelf));
75
static int              TestAndArrange _ANSI_ARGS_((MasterInfo *masterPtr));
76
static int              TixFm_CheckArgv _ANSI_ARGS_((ClientData clientData,
77
                            Tcl_Interp *interp, int argc, char ** argv));
78
static void             TixFm_LostSlaveProc _ANSI_ARGS_((
79
                            ClientData clientData, Tk_Window tkwin));
80
static void             TixFm_ReqProc _ANSI_ARGS_((ClientData clientData,
81
                            Tk_Window tkwin));
82
static int              PlaceAllClients _ANSI_ARGS_((MasterInfo *masterPtr));
83
static int              PlaceClient _ANSI_ARGS_((FormInfo *clientPtr));
84
static int              PlaceSide_AttOpposite _ANSI_ARGS_((
85
                            FormInfo *clientPtr, int axis,  int which));
86
static int              PlaceSide_AttAbsolute _ANSI_ARGS_((
87
                            FormInfo *clientPtr, int axis,  int which));
88
static int              PlaceSide_AttNone _ANSI_ARGS_((
89
                            FormInfo *clientPtr, int axis,  int which));
90
static int              PlaceSide_AttParallel _ANSI_ARGS_((FormInfo *clientPtr,
91
                            int axis, int which));
92
static int              PlaceSimpleCase _ANSI_ARGS_((
93
                            FormInfo *clientPtr, int axis,  int which));
94
static int              PlaceWithSpring _ANSI_ARGS_((
95
                            FormInfo *clientPtr, int axis,  int which));
96
static                  int ReqSize  _ANSI_ARGS_((Tk_Window tkwin,
97
                            int axis));
98
static void             UnmapClient _ANSI_ARGS_((FormInfo *clientPtr));
99
static void             MapClient _ANSI_ARGS_((FormInfo *clientPtr,
100
                            int x, int y, int width, int height));
101
static int              PinnSide_AttNone _ANSI_ARGS_((FormInfo *clientPtr,
102
                            int axis, int which));
103
static int              PinnSide_AttPercent _ANSI_ARGS_((FormInfo *clientPtr,
104
                            int axis, int which));
105
static int              PinnSide_AttOpposite _ANSI_ARGS_((FormInfo *clientPtr,
106
                            int axis, int which));
107
static int              PinnSide_AttParallel _ANSI_ARGS_((FormInfo *clientPtr,
108
                            int axis, int which));
109
static SpringLink *     AllocSpringLink _ANSI_ARGS_((void));
110
static void             FreeSpringLink _ANSI_ARGS_((SpringLink * link));
111
static void             FreeSpringList _ANSI_ARGS_((SpringList * listPtr));
112
static void             AddRightSprings _ANSI_ARGS_((SpringList * listPtr,
113
                            FormInfo *clientPtr));
114
static void             AddLeftSprings _ANSI_ARGS_((SpringList * listPtr,
115
                            FormInfo *clientPtr));
116
 
117
/*
118
 * A macro used to simplify the "pinn client" code
119
 */
120
#define PINN_CLIENT_SIDE(client, axis, which, isSelf) \
121
    if (PinnClientSide(client, axis, which, isSelf) == TCL_ERROR) { \
122
        return TCL_ERROR; \
123
    }
124
/*
125
 * A macro used to simplify the "place client" code
126
 */
127
#define PLACE_CLIENT_SIDE(client, axis, which, isSelf) \
128
    if (PlaceClientSide(client, axis, which, isSelf) == TCL_ERROR) { \
129
        return TCL_ERROR; \
130
    }
131
 
132
/*
133
 * Information about the Form geometry manager.
134
 */
135
static Tk_GeomMgr formType = {
136
    "tixForm",                  /* name */
137
    TixFm_ReqProc,              /* requestProc */
138
    TixFm_LostSlaveProc,        /* lostSlaveProc */
139
};
140
 
141
/*
142
 * Hash table used to map from Tk_Window tokens to corresponding
143
 * FormInfo structures:
144
 */
145
static Tcl_HashTable formInfoHashTable;
146
static Tcl_HashTable masterInfoHashTable;
147
 
148
/*
149
 * Have static variables in this module been initialized?
150
 */
151
static initialized = 0;
152
 
153
static int ReqSize(tkwin, axis)
154
    Tk_Window tkwin;
155
    int axis;
156
{
157
    if (axis == AXIS_X) {
158
        return Tk_ReqWidth(tkwin);
159
    } else {
160
        return Tk_ReqHeight(tkwin);
161
    }
162
}
163
 
164
/*
165
 *--------------------------------------------------------------
166
 *
167
 * Tix_FormCmd --
168
 *
169
 *      This procedure is invoked to process the "tixForm" Tcl command.
170
 *      See the user documentation for details on what it does.
171
 *
172
 * Results:
173
 *      A standard Tcl result.
174
 *
175
 * Side effects:
176
 *      See the user documentation.
177
 *
178
 *--------------------------------------------------------------
179
 */
180
int
181
Tix_FormCmd(clientData, interp, argc, argv)
182
    ClientData clientData;      /* Main window associated with
183
                                 * interpreter. */
184
    Tcl_Interp *interp;         /* Current interpreter. */
185
    int argc;                   /* Number of arguments. */
186
    char **argv;                /* Argument strings. */
187
{
188
    static Tix_SubCmdInfo subCmdInfo[] = {
189
        {TIX_DEFAULT_LEN, "check", 1, 1, TixFm_Check,
190
           "master",},
191
        {TIX_DEFAULT_LEN, "configure", 1, TIX_VAR_ARGS, TixFm_SetClient,
192
           "slave ?-flag value ...?",},
193
        {TIX_DEFAULT_LEN, "forget", 1, TIX_VAR_ARGS, TixFm_Forget,
194
           "slave ?slave ...?",},
195
        {TIX_DEFAULT_LEN, "grid", 1, TIX_VAR_ARGS, TixFm_SetGrid,
196
           "master ?x_grids y_grids?"},
197
        {TIX_DEFAULT_LEN, "info", 1, 2, TixFm_Info,
198
           "slave ?-flag?",},
199
        {TIX_DEFAULT_LEN, "slaves", 1, 1, TixFm_Slaves,
200
           "master",},
201
        {TIX_DEFAULT_LEN, "spring", 3, 3, TixFm_Spring,
202
           "slave side strength",},
203
        {TIX_DEFAULT_LEN, TIX_DEFAULT_SUBCMD, 0, 0, TixFm_SetClient, 0,
204
            TixFm_CheckArgv,}
205
    };
206
 
207
    static Tix_CmdInfo cmdInfo = {
208
        Tix_ArraySize(subCmdInfo), 1, TIX_VAR_ARGS, "?option? arg ?arg ...?",
209
    };
210
 
211
    return Tix_HandleSubCmds(&cmdInfo, subCmdInfo, clientData,
212
        interp, argc, argv);
213
}
214
 
215
/*----------------------------------------------------------------------
216
 *
217
 * TixFm_SetGrid --
218
 *
219
 *      Sets some defaults for the master window
220
 *
221
 *----------------------------------------------------------------------
222
 */
223
static int TixFm_SetGrid(clientData, interp, argc, argv)
224
    ClientData clientData;      /* Main window associated with
225
                                 * interpreter. */
226
    Tcl_Interp *interp;         /* Current interpreter. */
227
    int argc;                   /* Number of arguments. */
228
    char **argv;                /* Argument strings. */
229
{
230
    char buff[100];
231
    Tk_Window   topLevel = (Tk_Window) clientData;
232
    Tk_Window   master;
233
    MasterInfo* masterPtr;
234
 
235
    master = Tk_NameToWindow(interp, argv[0], topLevel);
236
 
237
    if (master == NULL) {
238
        return TCL_ERROR;
239
    } else {
240
        masterPtr = GetMasterInfo(master, 1);
241
    }
242
 
243
    if (argc != 1 && argc != 3) {
244
        Tcl_AppendResult(interp, "Wrong # of arguments, should be ",
245
            "tixForm grid master ?x_grids y_grids?", NULL);
246
        return TCL_ERROR;
247
    }
248
 
249
    if (argc == 1) {
250
        sprintf(buff, "%d %d", masterPtr->grids[0], masterPtr->grids[1]);
251
        Tcl_AppendResult(interp, buff, NULL);
252
    }
253
    else {
254
        int x, y;
255
        if (Tcl_GetInt(interp, argv[1], &x) != TCL_OK) {
256
            return TCL_ERROR;
257
        }
258
        if (Tcl_GetInt(interp, argv[2], &y) != TCL_OK) {
259
            return TCL_ERROR;
260
        }
261
 
262
        if (x <=0 || y <=0) {
263
            Tcl_AppendResult(interp, "Grid sizes must be positive integers",
264
                 NULL);
265
            return TCL_ERROR;
266
        }
267
        masterPtr->grids[0] = x;
268
        masterPtr->grids[1] = y;
269
 
270
        ArrangeWhenIdle(masterPtr);
271
    }
272
 
273
    return TCL_OK;
274
}
275
/*----------------------------------------------------------------------
276
 *
277
 * TixFm_Forget --
278
 *
279
 *      Sets some defaults for the master window
280
 *
281
 *----------------------------------------------------------------------
282
 */
283
static int TixFm_Forget(clientData, interp, argc, argv)
284
    ClientData clientData;      /* Main window associated with
285
                                 * interpreter. */
286
    Tcl_Interp *interp;         /* Current interpreter. */
287
    int argc;                   /* Number of arguments. */
288
    char **argv;                /* Argument strings. */
289
{
290
    FormInfo * clientPtr;
291
    Tk_Window topLevel = (Tk_Window) clientData;
292
    int i;
293
 
294
    for (i=0; i<argc; i++) {
295
        clientPtr = TixFm_FindClientPtrByName(interp, argv[i], topLevel);
296
        if (clientPtr == NULL) {
297
            return TCL_ERROR;
298
        }
299
        else {
300
            TixFm_ForgetOneClient(clientPtr);
301
        }
302
    }
303
 
304
    return TCL_OK;
305
}
306
 
307
void TixFm_ForgetOneClient(clientPtr)
308
    FormInfo * clientPtr;
309
{
310
    if (clientPtr != NULL) {
311
        Tk_DeleteEventHandler(clientPtr->tkwin, StructureNotifyMask,
312
            TixFm_StructureProc, (ClientData) clientPtr);
313
        Tk_ManageGeometry(clientPtr->tkwin, (Tk_GeomMgr *) NULL,
314
            (ClientData) NULL);
315
        if (clientPtr->master->tkwin != Tk_Parent(clientPtr->tkwin)) {
316
            Tk_UnmaintainGeometry(clientPtr->tkwin,
317
                clientPtr->master->tkwin);
318
        }
319
        Tk_UnmapWindow(clientPtr->tkwin);
320
        TixFm_Unlink(clientPtr);
321
    }
322
}
323
 
324
/*----------------------------------------------------------------------
325
 *
326
 * TixFm_Slaves --
327
 *
328
 *      retuen the pathnames of the clients of a master window
329
 *
330
 *----------------------------------------------------------------------
331
 */
332
static int TixFm_Slaves(clientData, interp, argc, argv)
333
    ClientData clientData;      /* Main window associated with
334
                                 * interpreter. */
335
    Tcl_Interp *interp;         /* Current interpreter. */
336
    int argc;                   /* Number of arguments. */
337
    char **argv;                /* Argument strings. */
338
{
339
    Tk_Window   topLevel = (Tk_Window) clientData;
340
    Tk_Window   master;
341
    MasterInfo* masterPtr;
342
    FormInfo  * clientPtr;
343
 
344
    master = Tk_NameToWindow(interp, argv[0], topLevel);
345
 
346
    if (master == NULL) {
347
        return TCL_ERROR;
348
    } else {
349
        masterPtr = GetMasterInfo(master, 0);
350
    }
351
 
352
    if (masterPtr == 0) {
353
        Tcl_AppendResult(interp, "Window \"", argv[0],
354
            "\" is not a tixForm master window", NULL);
355
        return TCL_ERROR;
356
    }
357
 
358
    for (clientPtr = masterPtr->client; clientPtr; clientPtr=clientPtr->next) {
359
        Tcl_AppendElement(interp, Tk_PathName(clientPtr->tkwin));
360
    }
361
    return TCL_OK;
362
}
363
/*----------------------------------------------------------------------
364
 *
365
 * TixFm_Spring --
366
 *
367
 *      Sets the spring strength of a slave's attachment sides
368
 *
369
 *----------------------------------------------------------------------
370
 */
371
static int TixFm_Spring(clientData, interp, argc, argv)
372
    ClientData clientData;      /* Main window associated with
373
                                 * interpreter. */
374
    Tcl_Interp *interp;         /* Current interpreter. */
375
    int argc;                   /* Number of arguments. */
376
    char **argv;                /* Argument strings. */
377
{
378
    Tk_Window   topLevel = (Tk_Window) clientData;
379
    Tk_Window   tkwin;
380
    FormInfo  * clientPtr;
381
    int         strength;
382
    int         i, j;
383
    size_t      len;
384
 
385
    if ((tkwin = Tk_NameToWindow(interp, argv[0], topLevel)) == NULL) {
386
        return TCL_ERROR;
387
    }
388
 
389
    if ((clientPtr = TixFm_GetFormInfo(tkwin, 0)) == NULL) {
390
        Tcl_AppendResult(interp, "Window \"", argv[0],
391
            "\" is not managed by the tixForm manager", NULL);
392
        return TCL_ERROR;
393
    }
394
 
395
    if (Tcl_GetInt(interp, argv[2], &strength) != TCL_OK) {
396
        return TCL_ERROR;
397
    }
398
 
399
    len = strlen(argv[1]);
400
    if (strncmp(argv[1], "-top", len) == 0) {
401
        i = 1; j = 0;
402
    }
403
    else if (strncmp(argv[1], "-bottom", len) == 0) {
404
        i = 1; j = 1;
405
    }
406
    else if (strncmp(argv[1], "-left", len) == 0) {
407
        i = 0; j = 0;
408
    }
409
    else if (strncmp(argv[1], "-right", len) == 0) {
410
        i = 0; j = 1;
411
    }
412
    else {
413
        Tcl_AppendResult(interp, "Unknown option \"", argv[1],
414
            "\"", NULL);
415
        return TCL_ERROR;
416
    }
417
 
418
    clientPtr->spring[i][j] = strength;
419
 
420
    if (clientPtr->attType[i][j] == ATT_OPPOSITE) {
421
        FormInfo * oppo;
422
 
423
        oppo = clientPtr->att[i][j].widget;
424
        oppo->spring[i][!j]  = strength;
425
 
426
        if (strength != 0 && clientPtr->strWidget[i][j] == NULL) {
427
            clientPtr->strWidget[i][j] = oppo;
428
 
429
            if (oppo->strWidget[i][!j] != clientPtr) {
430
                if (oppo->strWidget[i][!j] != NULL) {
431
                    oppo->strWidget[i][!j]->strWidget[i][j] = NULL;
432
                    oppo->strWidget[i][!j]->spring[i][j]  = 0;
433
                }
434
            }
435
            oppo->strWidget[i][!j] = clientPtr;
436
        }
437
    }
438
 
439
    ArrangeWhenIdle(clientPtr->master);
440
 
441
    return TCL_OK;
442
}
443
 
444
/*----------------------------------------------------------------------
445
 *
446
 * TixFm_Check --
447
 *
448
 *      Tests whether the master has circular reference.
449
 *
450
 *----------------------------------------------------------------------
451
 */
452
static int TixFm_Check(clientData, interp, argc, argv)
453
    ClientData clientData;      /* Main window associated with
454
                                 * interpreter. */
455
    Tcl_Interp *interp;         /* Current interpreter. */
456
    int argc;                   /* Number of arguments. */
457
    char **argv;                /* Argument strings. */
458
{
459
    MasterInfo * masterPtr;
460
    Tk_Window topLevel = (Tk_Window) clientData;
461
    Tk_Window master;
462
 
463
    master = Tk_NameToWindow(interp, argv[0], topLevel);
464
    if (master == NULL) {
465
        return TCL_ERROR;
466
    }
467
 
468
    masterPtr = GetMasterInfo(master, 1);
469
 
470
    if (TestAndArrange(masterPtr) == TCL_OK) {
471
        /* OK: no circular dependency */
472
        Tcl_AppendResult(interp, "0", NULL);
473
    } else {
474
        /* Bad: circular dependency */
475
        Tcl_AppendResult(interp, "1", NULL);
476
    }
477
    return TCL_OK;
478
}
479
 
480
/* Check the arguments to the default subcommand: TixFm_SetClient()
481
 */
482
static int TixFm_CheckArgv(clientData, interp, argc, argv)
483
    ClientData clientData;      /* Main window associated with
484
                                 * interpreter. */
485
    Tcl_Interp *interp;         /* Current interpreter. */
486
    int argc;                   /* Number of arguments. */
487
    char **argv;                /* Argument strings. */
488
{
489
    if ((argc >=1) && (argv[0][0] != '.')) {
490
        return 0;                        /* sorry, we expect a window name */
491
    } else {
492
        return 1;
493
    }
494
}
495
 
496
 
497
static int TixFm_SetClient(clientData, interp, argc, argv)
498
    ClientData clientData;      /* Main window associated with
499
                                 * interpreter. */
500
    Tcl_Interp *interp;         /* Current interpreter. */
501
    int argc;                   /* Number of arguments. */
502
    char **argv;                /* Argument strings. */
503
{
504
    Tk_Window topLevel = (Tk_Window) clientData;
505
    Tk_Window client, master;
506
    FormInfo * clientPtr;
507
    MasterInfo * masterPtr;
508
    char *pathName;             /* path name of the client window */
509
 
510
    if (argc < 1 || (((argc-1) %2) != 0)) {
511
        Tcl_AppendResult(interp, "Wrong # of arguments, should be ",
512
            "tixForm configure slave ?-flag value ...?", NULL);
513
        return TCL_ERROR;
514
    }
515
    pathName = argv[0];
516
    argc -=1;
517
    argv +=1;
518
 
519
    client = Tk_NameToWindow(interp, pathName, topLevel);
520
 
521
    if (client == NULL) {
522
        return TCL_ERROR;
523
    } else if (Tk_IsTopLevel(client)) {
524
        Tcl_AppendResult(interp, "can't put \"", pathName,
525
            "\"in a form: it's a top-level window", (char *) NULL);
526
        return TCL_ERROR;
527
    } else {
528
        clientPtr = TixFm_GetFormInfo(client, 1);
529
    }
530
 
531
    /* Check if the first argument is "-in". If so,
532
     * reset the master of this client
533
     */
534
    if (argc >= 2 && strcmp(argv[0], "-in")==0) {
535
        if ((master=Tk_NameToWindow(interp, argv[1], topLevel)) == NULL) {
536
            return TCL_ERROR;
537
        }
538
        argc -= 2;
539
        argv += 2;
540
        masterPtr = GetMasterInfo(master, 1);
541
    }
542
    else if (clientPtr->master == NULL) {
543
        if ((master = Tk_Parent(client))==NULL) {
544
            return TCL_ERROR;
545
        }
546
        masterPtr = GetMasterInfo(master, 1);
547
    }
548
    else {
549
        masterPtr =clientPtr->master;
550
    }
551
 
552
    if (clientPtr->master != masterPtr) {
553
        if (clientPtr->master != NULL) {
554
            /* Take clientPtr from old master */
555
            Tk_ManageGeometry(clientPtr->tkwin, (Tk_GeomMgr *) NULL,
556
                (ClientData) NULL);
557
            if (clientPtr->master->tkwin != Tk_Parent(clientPtr->tkwin)) {
558
                Tk_UnmaintainGeometry(clientPtr->tkwin,
559
                    clientPtr->master->tkwin);
560
            }
561
            TixFm_UnlinkFromMaster(clientPtr);
562
        }
563
 
564
        /* attach the client to the master */
565
        TixFm_AddToMaster(masterPtr, clientPtr);
566
    }
567
 
568
    if (argc > 0) {
569
        if (TixFm_Configure(clientPtr, topLevel, interp, argc,
570
            argv)==TCL_ERROR){
571
            return TCL_ERROR;
572
        }
573
    }
574
 
575
    ArrangeWhenIdle(clientPtr->master);
576
 
577
    return TCL_OK;
578
}
579
 
580
 
581
/* The caller of this function needs to find out a pointer to a client
582
 * that is already managed by tixForm.
583
 */
584
FormInfo * TixFm_FindClientPtrByName(interp, name, topLevel)
585
    Tcl_Interp * interp;
586
    char * name;
587
    Tk_Window topLevel;
588
{
589
    Tk_Window tkwin;
590
    FormInfo * clientPtr;
591
 
592
    if ((tkwin = Tk_NameToWindow(interp, name, topLevel)) == NULL) {
593
        return NULL;
594
    }
595
 
596
    if ((clientPtr = TixFm_GetFormInfo(tkwin, 0)) == NULL) {
597
        Tcl_AppendResult(interp, "Window \"", name,
598
            "\" is not managed by the tixForm manager", NULL);
599
        return NULL;
600
    }
601
    return clientPtr;
602
}
603
 
604
 
605
static int TestAndArrange(masterPtr)
606
    MasterInfo *masterPtr;
607
{
608
    FormInfo *clientPtr;
609
    int i,j;
610
 
611
    /*
612
     * First mark all clients as unpinned, and clean the opposite flags,
613
     * Check the attachment intergrity
614
     */
615
    for (clientPtr = masterPtr->client; clientPtr; clientPtr=clientPtr->next) {
616
        if (clientPtr->tkwin != NULL) {
617
            for (i=0; i<2; i++) {
618
                for (j=0; j<2; j++) {
619
                    clientPtr->side[i][j].pcnt = 0;
620
                    clientPtr->side[i][j].disp = 0;
621
                }
622
                /* clear all flags */
623
                clientPtr->sideFlags[i] = 0;
624
            }
625
            clientPtr->depend = 0;
626
            CheckIntergrity(clientPtr);
627
        }
628
    }
629
 
630
    /*
631
     * Try to determine all the client's geometry
632
     */
633
    for (clientPtr = masterPtr->client; clientPtr; clientPtr=clientPtr->next) {
634
        if (clientPtr->tkwin == NULL) { /* it was deleted */
635
            continue;
636
        }
637
        for (i=0; i<2; i++) {
638
            if ((clientPtr->sideFlags[i] & PINNED_ALL) != PINNED_ALL) {
639
                if (PinnClient(clientPtr) == TCL_ERROR) {
640
                    /*
641
                     * Detected circular dependency
642
                     */
643
                    return TCL_ERROR;
644
                }
645
                break;
646
            }
647
        }
648
    }
649
 
650
    return TCL_OK;
651
}
652
 
653
/*----------------------------------------------------------------------
654
 *  UnmapClient
655
 *
656
 *      Unmap the client from the screen, using different methods according to
657
 *      the relationship between the client and slave.
658
 */
659
static void UnmapClient(clientPtr)
660
    FormInfo *clientPtr;
661
{
662
    if (clientPtr->master->tkwin == Tk_Parent(clientPtr->tkwin)) {
663
        Tk_UnmapWindow(clientPtr->tkwin);
664
    }
665
    else {
666
        Tk_UnmaintainGeometry(clientPtr->tkwin, clientPtr->master->tkwin);
667
        Tk_UnmapWindow(clientPtr->tkwin);
668
    }
669
}
670
 
671
/*----------------------------------------------------------------------
672
 *  MapClient
673
 *
674
 *      Map the client to the screen, using different methods according to
675
 *      the relationship between the client and slave.
676
 */
677
static void MapClient(clientPtr, x, y, width, height)
678
    FormInfo *clientPtr;
679
    int x;
680
    int y;
681
    int width;
682
    int height;
683
{
684
    if (clientPtr->master->tkwin == Tk_Parent(clientPtr->tkwin)) {
685
        Tk_MoveResizeWindow(clientPtr->tkwin, x, y, width, height);
686
        Tk_MapWindow(clientPtr->tkwin);
687
    }
688
    else {
689
        Tk_MaintainGeometry(clientPtr->tkwin, clientPtr->master->tkwin,
690
            x, y, width, height);
691
        Tk_MapWindow(clientPtr->tkwin);
692
    }
693
}
694
 
695
static void ArrangeWhenIdle(masterPtr)
696
    MasterInfo * masterPtr;
697
{
698
    if (!(masterPtr->flags.repackPending || masterPtr->flags.isDeleted)) {
699
        masterPtr->flags.repackPending = 1;
700
        Tk_DoWhenIdle(ArrangeGeometry, (ClientData) masterPtr);
701
    }
702
}
703
 
704
static void
705
CancelArrangeWhenIdle(masterPtr)
706
    MasterInfo * masterPtr;
707
{
708
    if (masterPtr->flags.repackPending) {
709
        Tk_CancelIdleCall(ArrangeGeometry, (ClientData) masterPtr);
710
        masterPtr->flags.repackPending = 0;
711
    }
712
}
713
 
714
/*----------------------------------------------------------------------
715
 * ArrangeGeometry --
716
 *
717
 *      The heart of the Form geometry manager: calculates the sizes of
718
 *      the clients and the master, then arrange the clients inside the
719
 *      master according to their attachments.
720
 */
721
static void ArrangeGeometry(clientData)
722
    ClientData clientData;      /* Structure describing parent whose clients
723
                                 * are to be re-layed out. */
724
{
725
    MasterInfo *masterPtr;
726
    FormInfo *clientPtr;
727
    int i, j, coord[2][2];
728
    int mSize[2];                       /* Size of master */
729
    int cSize[2];                       /* Size of client */
730
    int intBWidth;                      /* internal borderWidth of master */
731
 
732
    TkWindow* winPtr;
733
    masterPtr = (MasterInfo *) clientData;
734
    winPtr = (TkWindow*)masterPtr->tkwin;
735
 
736
    if (winPtr->flags & TK_ALREADY_DEAD) {
737
        masterPtr->flags.repackPending = 0;
738
        return;
739
    }
740
 
741
    if (masterPtr->flags.isDeleted) {
742
        return;
743
    }
744
 
745
    if (masterPtr->numClients == 0) {
746
        masterPtr->flags.repackPending = 0;
747
        return;
748
    }
749
 
750
    if (TestAndArrange(masterPtr)) {    /* Detected circular dependency */
751
        fprintf(stderr, "circular dependency.\n");
752
        masterPtr->flags.repackPending = 0;
753
        return;
754
    }
755
 
756
    /*
757
     * Try to determine the required size of the master
758
     */
759
    CalculateMasterSize(masterPtr);
760
 
761
    /*
762
     * If the requested size is not equal to the actual size of the master,
763
     * we might have to ask TK to change the master's geometry
764
     */
765
 
766
    if ((masterPtr->reqSize[0] != Tk_ReqWidth(masterPtr->tkwin))
767
        || (masterPtr->reqSize[1] != Tk_ReqHeight(masterPtr->tkwin))) {
768
 
769
        if (masterPtr->numRequests++ > 50) {
770
            fprintf(stderr,
771
                "(TixForm) Error:Trying to use more than one geometry\n\
772
          manager for the same master window.\n\
773
          Giving up after 50 iterations.\n");
774
        } else {
775
            masterPtr->flags.repackPending = 0;
776
            Tk_GeometryRequest(masterPtr->tkwin,
777
                masterPtr->reqSize[0], masterPtr->reqSize[1]);
778
 
779
            ArrangeWhenIdle(masterPtr);
780
            return;
781
        }
782
    }
783
 
784
    masterPtr->numRequests = 0;
785
 
786
    if (!Tk_IsMapped(masterPtr->tkwin)) {
787
        goto done;
788
    }
789
 
790
    intBWidth = Tk_InternalBorderWidth(masterPtr->tkwin);
791
    mSize[0] = Tk_Width(masterPtr->tkwin)  - 2*intBWidth;
792
    mSize[1] = Tk_Height(masterPtr->tkwin) - 2*intBWidth;
793
 
794
    if (mSize[0] < 1 || mSize[1] <1) {
795
        /* Master is not visible. Don't bother to place the clients
796
         */
797
        masterPtr->flags.repackPending = 0;
798
        return;
799
    }
800
 
801
    /*
802
     * Now set all the client's geometry
803
     */
804
    if (PlaceAllClients(masterPtr) != TCL_OK) {
805
        panic("circular dependency");
806
    }
807
 
808
    for (clientPtr = masterPtr->client; clientPtr; clientPtr=clientPtr->next) {
809
        if (clientPtr->tkwin == NULL) {
810
            continue;
811
        }
812
        for (i=0; i<2; i++) {
813
            for (j=0; j<2; j++) {
814
                coord[i][j] = clientPtr->posn[i][j];
815
                if (j == 1) {
816
                    coord[i][j] -= 1;
817
                }
818
            }
819
            cSize[i] = coord[i][1] - coord[i][0]
820
              - clientPtr->pad[i][0] - clientPtr->pad[i][1] + 1;
821
        }
822
 
823
        if ((cSize[0] <= 0) || (cSize[1] <= 0)) {
824
            /*
825
             * Window is too small, don't even bother to map
826
             */
827
            UnmapClient(clientPtr);
828
        } else if ((coord[0][1] < 0) || (coord[1][1] < 0)) {
829
            /*
830
             * Window is outside of the master (left or top)
831
             */
832
            UnmapClient(clientPtr);
833
        } else if ((coord[0][0] > mSize[0]) || (coord[1][0] > mSize[1])) {
834
            /*
835
             * Window is outside of the master (bottom or right)
836
             */
837
            UnmapClient(clientPtr);
838
        } else {
839
            /*
840
             * Window is visible, then map it
841
             */
842
            MapClient(clientPtr,
843
                coord[0][0] + clientPtr->pad[0][0] + intBWidth,
844
                coord[1][0] + clientPtr->pad[1][0] + intBWidth,
845
                cSize[0], cSize[1]);
846
        }
847
    }
848
 
849
  done:
850
    masterPtr->flags.repackPending = 0;
851
}
852
 
853
static int
854
PinnSide_AttNone(clientPtr, axis, which)
855
    FormInfo *clientPtr;        /* The client to pinn down */
856
    int axis;                           /* 0 = x axis, 1 = yaxis */
857
    int which;                          /* 0 = min side, 1= max side */
858
{
859
    int reqSize;
860
 
861
    if (clientPtr->attType[axis][NEXT_SIDE(which)] == ATT_NONE) {
862
        if (which == SIDE0) {
863
            clientPtr->side[axis][which].pcnt = 0;
864
            clientPtr->side[axis][which].disp = 0;
865
            return TCL_OK;
866
        }
867
    }
868
 
869
    reqSize = ReqSize(clientPtr->tkwin, axis) +
870
      clientPtr->pad[axis][0] + clientPtr->pad[axis][1];
871
 
872
    PINN_CLIENT_SIDE(clientPtr, axis, NEXT_SIDE(which), 1);
873
 
874
    clientPtr->side[axis][which].pcnt =
875
      clientPtr->side[axis][NEXT_SIDE(which)].pcnt;
876
 
877
    switch (which) {
878
      case SIDE0:
879
        clientPtr->side[axis][which].disp =
880
          clientPtr->side[axis][NEXT_SIDE(which)].disp - reqSize;
881
        break;
882
 
883
      case SIDE1:
884
        clientPtr->side[axis][which].disp =
885
          clientPtr->side[axis][NEXT_SIDE(which)].disp + reqSize;
886
        break;
887
    }
888
 
889
    return TCL_OK;
890
}
891
 
892
static int
893
PinnSide_AttPercent(clientPtr, axis, which)
894
    FormInfo *clientPtr;        /* The client to pinn down */
895
    int axis;                           /* 0 = x axis, 1 = yaxis */
896
    int which;                          /* 0 = min side, 1= max side */
897
{
898
    clientPtr->side[axis][which].pcnt = clientPtr->att[axis][which].grid;
899
    clientPtr->side[axis][which].disp = clientPtr->off[axis][which];
900
 
901
    return TCL_OK;
902
}
903
 
904
static int
905
PinnSide_AttOpposite(clientPtr, axis, which)
906
    FormInfo *clientPtr;        /* The client to pinn down */
907
    int axis;                           /* 0 = x axis, 1 = yaxis */
908
    int which;                          /* 0 = min side, 1= max side */
909
{
910
    FormInfo * attachPtr;
911
 
912
    attachPtr = clientPtr->att[axis][which].widget;
913
 
914
    PINN_CLIENT_SIDE(attachPtr, axis, NEXT_SIDE(which), 0);
915
 
916
    clientPtr->side[axis][which].pcnt =
917
      attachPtr->side[axis][NEXT_SIDE(which)].pcnt;
918
    clientPtr->side[axis][which].disp =
919
      attachPtr->side[axis][NEXT_SIDE(which)].disp +
920
      clientPtr->off[axis][which];
921
 
922
    return TCL_OK;
923
}
924
 
925
static int
926
PinnSide_AttParallel(clientPtr, axis, which)
927
    FormInfo *clientPtr;        /* The client to pinn down */
928
    int axis;                           /* 0 = x axis, 1 = yaxis */
929
    int which;                          /* 0 = min side, 1= max side */
930
{
931
    FormInfo * attachPtr;
932
 
933
    attachPtr = clientPtr->att[axis][which].widget;
934
 
935
    PINN_CLIENT_SIDE(attachPtr, axis, which, 0);
936
 
937
    clientPtr->side[axis][which].pcnt =
938
      attachPtr->side[axis][which].pcnt;
939
    clientPtr->side[axis][which].disp =
940
      attachPtr->side[axis][which].disp +
941
      clientPtr->off[axis][which];
942
 
943
    return TCL_OK;
944
}
945
 
946
 
947
static int PinnClientSide(clientPtr, axis, which, isSelf)
948
    FormInfo *clientPtr;        /* The client to pinn down */
949
    int axis;                           /* 0 = x axis, 1 = yaxis */
950
    int which;                          /* 0 = min side, 1= max side */
951
    int isSelf;
952
{
953
    if ((which == SIDE0) && (clientPtr->sideFlags[axis] & PINNED_SIDE0)) {
954
        /* already pinned */
955
        return TCL_OK;
956
    }
957
    if ((which == SIDE1) && (clientPtr->sideFlags[axis] & PINNED_SIDE1)) {
958
        /* already pinned */
959
        return TCL_OK;
960
    }
961
 
962
    if ((clientPtr->depend > 0) && !isSelf) {
963
        /*
964
         * circular dependency detected
965
         */
966
        return TCL_ERROR;
967
    }
968
    clientPtr->depend ++;
969
 
970
    switch (clientPtr->attType[axis][which]) {
971
      case ATT_NONE:
972
        if (PinnSide_AttNone(clientPtr, axis, which) == TCL_ERROR) {
973
            return TCL_ERROR;
974
        }
975
        break;
976
 
977
      case ATT_OPPOSITE:
978
        if (PinnSide_AttOpposite(clientPtr, axis, which) == TCL_ERROR) {
979
            return TCL_ERROR;
980
        }
981
        break;
982
 
983
      case ATT_PARALLEL:
984
        if (PinnSide_AttParallel(clientPtr, axis, which) == TCL_ERROR) {
985
            return TCL_ERROR;
986
        }
987
        break;
988
 
989
      case ATT_GRID:
990
        if (PinnSide_AttPercent(clientPtr, axis, which) == TCL_ERROR) {
991
            return TCL_ERROR;
992
        }
993
        break;
994
    }
995
 
996
    if (which == SIDE0) {
997
        clientPtr->sideFlags[axis] |= PINNED_SIDE0;
998
    } else {
999
        clientPtr->sideFlags[axis] |= PINNED_SIDE1;
1000
    }
1001
    clientPtr->depend --;
1002
 
1003
    return TCL_OK;
1004
}
1005
 
1006
static int PinnClient(clientPtr)
1007
    FormInfo *clientPtr;
1008
{
1009
    int i;
1010
 
1011
    for (i=0; i<2; i++) {
1012
        if (!(clientPtr->sideFlags[i] & PINNED_SIDE0)) {
1013
            PINN_CLIENT_SIDE(clientPtr, i, SIDE0, 0);
1014
        }
1015
        if (!(clientPtr->sideFlags[i] & PINNED_SIDE1)) {
1016
            PINN_CLIENT_SIDE(clientPtr, i, SIDE1, 0);
1017
        }
1018
    }
1019
 
1020
    return TCL_OK;
1021
}
1022
 
1023
/*
1024
 *--------------------------------------------------------------
1025
 *
1026
 * CalculateMasterSize --
1027
 *
1028
 *      This internal procedure is used to find out the required
1029
 *      size of a master window.
1030
 *
1031
 * Results:
1032
 *      The return value is a pointer to the FormInfo structure
1033
 *      corresponding to tkwin.
1034
 *
1035
 * Side effects:
1036
 *      the reqSize[2] values in masterPtr is updated.
1037
 *
1038
 *--------------------------------------------------------------
1039
 */
1040
static void CalculateMasterSize(masterPtr)
1041
    MasterInfo *masterPtr;
1042
{
1043
    FormInfo *clientPtr;
1044
    int i, cSize[2];
1045
    int req[2];
1046
    int intBWidth;
1047
 
1048
    /* Information about the master window */
1049
    intBWidth = Tk_InternalBorderWidth(masterPtr->tkwin);
1050
    req[0] = req[1] = 2*intBWidth;
1051
 
1052
    for (clientPtr = masterPtr->client; clientPtr; clientPtr=clientPtr->next) {
1053
        if (clientPtr->tkwin == NULL) {
1054
            continue;
1055
        }
1056
        cSize[0] = Tk_ReqWidth(clientPtr->tkwin);
1057
        cSize[1] = Tk_ReqHeight(clientPtr->tkwin);
1058
        cSize[0] += clientPtr->pad[0][0]+clientPtr->pad[0][1];
1059
        cSize[1] += clientPtr->pad[1][0]+clientPtr->pad[1][1];
1060
 
1061
        for (i=0; i<2; i++) {
1062
            /* The required size of the master depends on
1063
             *  (1) natural sizes of the clients
1064
             *  (2) perc anchor points of the clients
1065
             * Ideally, the master must include as much visible parts
1066
             * of the clients as possible. It should also have a size
1067
             * big enough so that all the clients' requested (natural)
1068
             * sizes are satisfied. The algorithm is fairly simple, but
1069
             * it took me quite a while to figure out and it quite difficult
1070
             * to explain here. Please look at the following in-line
1071
             * examples.
1072
             */
1073
            int p0 = clientPtr->side[i][0].pcnt;
1074
            int p1 = clientPtr->side[i][1].pcnt;
1075
            int d0 = clientPtr->side[i][0].disp;
1076
            int d1 = clientPtr->side[i][1].disp;
1077
 
1078
            int req0 = 0;
1079
            int req1 = 0;
1080
            int reqx = 0;
1081
 
1082
            if (d0 < 0 && p0 != 0) {
1083
                req0 = -d0 * masterPtr->grids[i] / p0;
1084
            }
1085
            if (d1 > 0 && p1 != masterPtr->grids[i]) {
1086
                req1 =  d1 * masterPtr->grids[i] / (masterPtr->grids[i] - p1);
1087
            }
1088
 
1089
            if (p0 == p1) {
1090
                /* case 1 */
1091
                /* Example: p0 = p1 = 10%; d0 = -10, d1 = 10
1092
                 * then mSize should at least be 100 pixels so that
1093
                 * side 0 can be visible. They are calculated in the
1094
                 * previous two if statements
1095
                 * result:
1096
                 *      size  = 100
1097
                 *      side0 = 0;
1098
                 *      side1 = 20;
1099
                 */
1100
 
1101
                /* Two sides are attached to the same perc anchor point */
1102
                if (d0 >= d1) {
1103
                    /* widget invisible */
1104
                    req0 = req1 = 0;
1105
                }
1106
            }
1107
            else if (p0 < p1) {
1108
                /* case 2 */
1109
                /* Example: p0 10%,  p2 = 20%; cSize = 35, d0 = -5, d1 = 0
1110
                 * then mSize should at least be 300 pixels so that
1111
                 * cSize can be satisfied.
1112
                 * result:
1113
                 *      size  = 300
1114
                 *      side0 = 25;
1115
                 *      side1 = 60;
1116
                 */
1117
                int x = cSize[i];
1118
                if (p0 != 0 || d0 > 0) {
1119
                    x +=  d0;
1120
                }
1121
                if (p1 != masterPtr->grids[i] || d1 < 0) {
1122
                    x += -d1;
1123
                }
1124
                if (x > 0) {
1125
                    reqx = x * masterPtr->grids[i] / (p1 - p0);
1126
                }
1127
            }
1128
            else {
1129
                /* case 2 */
1130
                /* This is very similar to case 1, except there are more cases
1131
                 * in which the widget becomes invisible
1132
                 */
1133
                if (d0 >=0 || d1 <=0) {
1134
                    /* widget invisible */
1135
                    req0 = req1 = 0;
1136
                }
1137
            }
1138
 
1139
            if (req[i] < req0) {
1140
                req[i] = req0;
1141
            }
1142
            if (req[i] < req1) {
1143
                req[i] = req1;
1144
            }
1145
            if (req[i] < reqx) {
1146
                req[i] = reqx;
1147
            }
1148
        }
1149
    }
1150
 
1151
    req[0] += 2*intBWidth;
1152
    req[1] += 2*intBWidth;
1153
 
1154
    masterPtr->reqSize[0] = (req[0] > 0) ? req[0] : 1;
1155
    masterPtr->reqSize[1] = (req[1] > 0) ? req[1] : 1;
1156
}
1157
 
1158
/*
1159
 *----------------------------------------------------------------------
1160
 *
1161
 * TixFm_StructureProc --
1162
 *
1163
 *      This procedure is invoked by the Tk event dispatcher in response
1164
 *      to StructureNotify events.
1165
 *
1166
 * Results:
1167
 *      None.
1168
 *
1169
 * Side effects:
1170
 *      If a window was just deleted, clean up all its packer-related
1171
 *      information.  If it was just resized, repack its clients, if
1172
 *      any.
1173
 *
1174
 *----------------------------------------------------------------------
1175
 */
1176
 
1177
void
1178
TixFm_StructureProc(clientData, eventPtr)
1179
    ClientData clientData;              /* Our information about window
1180
                                         * referred to by eventPtr. */
1181
    XEvent *eventPtr;                   /* Describes what just happened. */
1182
{
1183
    FormInfo *clientPtr = (FormInfo *) clientData;
1184
 
1185
    switch (eventPtr->type) {
1186
      case ConfigureNotify:
1187
        ArrangeWhenIdle(clientPtr->master);
1188
        break;
1189
 
1190
      case DestroyNotify:
1191
        if (clientPtr->master) {
1192
            TixFm_Unlink(clientPtr);
1193
        }
1194
        break;
1195
 
1196
      case MapNotify:
1197
        break;
1198
 
1199
      case UnmapNotify:
1200
        break;
1201
    }
1202
}
1203
 
1204
static void
1205
TixFm_ReqProc(clientData, tkwin)
1206
    ClientData clientData;      /* TixForm's information about
1207
                                 * window that got new preferred
1208
                                 * geometry.  */
1209
    Tk_Window tkwin;            /* Other Tk-related information
1210
                                 * about the window. */
1211
{
1212
    FormInfo *clientPtr = (FormInfo *) clientData;
1213
 
1214
    if (clientPtr) {
1215
        ArrangeWhenIdle(clientPtr->master);
1216
    }
1217
}
1218
 
1219
static void
1220
MasterStructureProc(clientData, eventPtr)
1221
    ClientData clientData;              /* Our information about window
1222
                                         * referred to by eventPtr. */
1223
    XEvent *eventPtr;                   /* Describes what just happened. */
1224
{
1225
    MasterInfo *masterPtr = (MasterInfo *) clientData;
1226
 
1227
    switch (eventPtr->type) {
1228
      case ConfigureNotify:
1229
        if (masterPtr->numClients > 0) {
1230
            ArrangeWhenIdle(masterPtr);
1231
        }
1232
        break;
1233
 
1234
      case DestroyNotify:
1235
        TixFm_DeleteMaster(masterPtr);
1236
        break;
1237
 
1238
      case MapNotify:
1239
        break;
1240
 
1241
      case UnmapNotify:
1242
        break;
1243
    }
1244
}
1245
 
1246
/*
1247
 *--------------------------------------------------------------
1248
 *
1249
 * TixFm_LostSlaveProc --
1250
 *
1251
 *      This procedure is invoked by Tk whenever some other geometry
1252
 *      claims control over a slave that used to be managed by us.
1253
 *
1254
 * Results:
1255
 *      None.
1256
 *
1257
 * Side effects:
1258
 *      Forgets all packer-related information about the slave.
1259
 *
1260
 *--------------------------------------------------------------
1261
 */
1262
static void
1263
TixFm_LostSlaveProc(clientData, tkwin)
1264
    ClientData clientData;      /* Form structure for slave window that
1265
                                 * was stolen away. */
1266
    Tk_Window tkwin;            /* Tk's handle for the slave window. */
1267
{
1268
    FormInfo *clientPtr = (FormInfo *) clientData;
1269
 
1270
    Tk_DeleteEventHandler(clientPtr->tkwin, StructureNotifyMask,
1271
        TixFm_StructureProc, (ClientData) clientPtr);
1272
    if (clientPtr->master->tkwin != Tk_Parent(clientPtr->tkwin)) {
1273
        Tk_UnmaintainGeometry(clientPtr->tkwin, clientPtr->master->tkwin);
1274
    }
1275
    Tk_UnmapWindow(clientPtr->tkwin);
1276
    TixFm_Unlink(clientPtr);
1277
}
1278
 
1279
/*
1280
 * Do some basic integrity checking
1281
 * --> right, left cannot both attach to none
1282
 * --> top, bottom cannot both attach to none.
1283
 * Otherwise, top or left is always set to attach at {pixel 0}
1284
 */
1285
static void CheckIntergrity(clientPtr)
1286
    FormInfo * clientPtr;
1287
{
1288
#if 0
1289
    /* Check the X axis */
1290
    if ((clientPtr->attType[0][0] ==  ATT_NONE)
1291
        &&(clientPtr->attType[0][1]  ==  ATT_NONE)) {
1292
        clientPtr->attType[0][0]   = ATT_DEFAULT_PIXEL;
1293
        clientPtr->att[0][0].grid = 0;
1294
    }
1295
 
1296
    /* Check the Y axis */
1297
    if ((clientPtr->attType[1][0] ==  ATT_NONE)
1298
        &&(clientPtr->attType[1][1]  ==  ATT_NONE)) {
1299
        clientPtr->attType[1][0]   = ATT_DEFAULT_PIXEL;
1300
        clientPtr->att[1][0].grid = 0;
1301
    }
1302
#endif
1303
}
1304
 
1305
/*----------------------------------------------------------------------
1306
 * Memory management routines
1307
 *
1308
 *----------------------------------------------------------------------
1309
 */
1310
void TixFm_AddToMaster(masterPtr, clientPtr)
1311
    MasterInfo *masterPtr;
1312
    FormInfo *clientPtr;
1313
{
1314
    if (clientPtr->master == masterPtr) {
1315
        /* already in master */
1316
        return;
1317
    }
1318
 
1319
    if (clientPtr->master != NULL) {
1320
        /* We have to migrate the widget to a different parent*/
1321
    }
1322
 
1323
    clientPtr->master = masterPtr;
1324
 
1325
    if (masterPtr->client == NULL) {
1326
        masterPtr->client      = clientPtr;
1327
        masterPtr->client_tail = clientPtr;
1328
    } else {
1329
        masterPtr->client_tail->next = clientPtr;
1330
    }
1331
    clientPtr->next = NULL;
1332
    masterPtr->client_tail = clientPtr;
1333
 
1334
    ++ masterPtr->numClients;
1335
 
1336
    /* Manage its geometry using my proc */
1337
    Tk_ManageGeometry(clientPtr->tkwin, &formType, (ClientData)clientPtr);
1338
}
1339
 
1340
void TixFm_UnlinkFromMaster(clientPtr)
1341
    FormInfo *clientPtr;
1342
{
1343
    MasterInfo *masterPtr;
1344
    FormInfo *ptr, *prev;
1345
 
1346
#if DEBUG
1347
    fprintf(stderr, "unlinking %s\n", Tk_PathName(clientPtr->tkwin));
1348
#endif
1349
 
1350
    masterPtr = clientPtr->master;
1351
 
1352
    /* First: get rid of the reference of this widget from other clients */
1353
    for (ptr=masterPtr->client; ptr; ptr=ptr->next) {
1354
        if (ptr != clientPtr) {
1355
            int i, j;
1356
            for (i=0; i<2; i++) {
1357
                for (j=0; j<2; j++) {
1358
                    switch (ptr->attType[i][j]) {
1359
                      case ATT_OPPOSITE:
1360
                      case ATT_PARALLEL:
1361
                        if (ptr->att[i][j].widget == clientPtr) {
1362
                            ptr->attType[i][j] = ATT_GRID;
1363
                            ptr->att[i][j].grid = 0;
1364
                            ptr->off[i][j]      = ptr->posn[i][j];
1365
                        }
1366
                        break;
1367
                    }
1368
                }
1369
                if (ptr->strWidget[i][j] == clientPtr) {
1370
                    ptr->strWidget[i][j] = 0;
1371
                }
1372
            }
1373
        }
1374
    }
1375
 
1376
    /* Second: delete this client from the list */
1377
    for (prev=ptr=masterPtr->client; ptr; prev=ptr,ptr=ptr->next) {
1378
        if (ptr == clientPtr) {
1379
            if (prev==ptr) {
1380
                if (masterPtr->numClients == 1) {
1381
                    masterPtr->client_tail = NULL;
1382
                }
1383
                masterPtr->client = ptr->next;
1384
            }
1385
            else {
1386
                if (ptr->next == NULL) {
1387
                    masterPtr->client_tail = prev;
1388
                }
1389
                prev->next = ptr->next;
1390
            }
1391
            break;
1392
        }
1393
    }
1394
    -- masterPtr->numClients;
1395
}
1396
 
1397
void TixFm_FreeMasterInfo(clientData)
1398
    ClientData clientData;
1399
{
1400
    MasterInfo *masterPtr = (MasterInfo *)clientData;
1401
    ckfree((char*)masterPtr);
1402
}
1403
 
1404
void TixFm_DeleteMaster(masterPtr)
1405
    MasterInfo *masterPtr;
1406
{
1407
    Tcl_HashEntry *hPtr;
1408
    FormInfo *clientPtr, * toFree;
1409
 
1410
    if (masterPtr->flags.isDeleted) {
1411
        return;
1412
    }
1413
 
1414
    Tk_DeleteEventHandler(masterPtr->tkwin, StructureNotifyMask,
1415
        MasterStructureProc, (ClientData) masterPtr);
1416
 
1417
    clientPtr=masterPtr->client;
1418
    while(clientPtr) {
1419
        toFree = clientPtr;
1420
        clientPtr = clientPtr->next;
1421
        TixFm_ForgetOneClient(toFree);
1422
    }
1423
 
1424
    hPtr = Tcl_FindHashEntry(&masterInfoHashTable,(char*)masterPtr->tkwin);
1425
    if (hPtr) {
1426
        Tcl_DeleteHashEntry(hPtr);
1427
    }
1428
    CancelArrangeWhenIdle(masterPtr);
1429
    masterPtr->flags.isDeleted = 1;
1430
    Tk_EventuallyFree((ClientData)masterPtr,
1431
        (Tix_FreeProc*)TixFm_FreeMasterInfo);
1432
}
1433
 
1434
 
1435
void TixFm_Unlink(clientPtr)
1436
    FormInfo *clientPtr;
1437
{
1438
    Tcl_HashEntry *hPtr;
1439
    MasterInfo *masterPtr;
1440
 
1441
    /* Delete this clientPtr from the master's list */
1442
    TixFm_UnlinkFromMaster(clientPtr);
1443
 
1444
    /* Eventually free this clientPtr structure */
1445
    hPtr = Tcl_FindHashEntry(&formInfoHashTable,(char*)clientPtr->tkwin);
1446
    if (hPtr != NULL) {
1447
        Tcl_DeleteHashEntry(hPtr);
1448
    }
1449
    clientPtr->tkwin = NULL;
1450
    masterPtr = clientPtr->master;
1451
    ckfree((char*)clientPtr);
1452
 
1453
    ArrangeWhenIdle(masterPtr);
1454
}
1455
 
1456
 
1457
/*
1458
 *--------------------------------------------------------------
1459
 *
1460
 * TixFm_GetFormInfo --
1461
 *
1462
 *      This internal procedure is used to locate a FormInfo
1463
 *      structure for a given window, creating one if one
1464
 *      doesn't exist already.
1465
 *
1466
 * Results:
1467
 *      The return value is a pointer to the FormInfo structure
1468
 *      corresponding to tkwin.
1469
 *
1470
 * Side effects:
1471
 *      A new FormInfo structure may be created.  If so, then
1472
 *      a callback is set up to clean things up when the
1473
 *      window is deleted.
1474
 *
1475
 *--------------------------------------------------------------
1476
 */
1477
FormInfo *
1478
TixFm_GetFormInfo(tkwin, create)
1479
    Tk_Window tkwin;            /* Token for window for which
1480
                                 * FormInfo structure is desired. */
1481
    int create;
1482
{
1483
    FormInfo *clientPtr;
1484
    Tcl_HashEntry *hPtr;
1485
    int isNew;
1486
    int i,j;
1487
 
1488
    if (!initialized) {
1489
        initialized = 1;
1490
        Tcl_InitHashTable(&formInfoHashTable, TCL_ONE_WORD_KEYS);
1491
        Tcl_InitHashTable(&masterInfoHashTable, TCL_ONE_WORD_KEYS);
1492
    }
1493
 
1494
    /*
1495
     * See if there's already FormInfo for this window.  If not,
1496
     * then create a new one.
1497
     */
1498
    if (!create) {
1499
        hPtr = Tcl_FindHashEntry(&formInfoHashTable, (char *)tkwin);
1500
        if (!hPtr) {
1501
            return NULL;
1502
        } else {
1503
            return (FormInfo *) Tcl_GetHashValue(hPtr);
1504
        }
1505
    } else {
1506
        hPtr = Tcl_CreateHashEntry(&formInfoHashTable, (char *) tkwin, &isNew);
1507
        if (!isNew) {
1508
            return (FormInfo *) Tcl_GetHashValue(hPtr);
1509
        } else {
1510
            clientPtr = (FormInfo *) ckalloc(sizeof(FormInfo));
1511
            clientPtr->tkwin    = tkwin;
1512
            clientPtr->master   = NULL;
1513
            clientPtr->next     = NULL;
1514
 
1515
            for (i=0; i< 2; i++) {
1516
                for (j=0; j< 2; j++) {
1517
                    clientPtr->attType[i][j]    = ATT_NONE;
1518
                    clientPtr->att[i][j].grid   = 0;
1519
                    clientPtr->att[i][j].widget = NULL;
1520
                    clientPtr->off[i][j]        = 0;
1521
 
1522
                    clientPtr->pad[i][j]        = 0;
1523
                    clientPtr->side[i][j].pcnt  = 0;
1524
                    clientPtr->side[i][j].disp  = 0;
1525
 
1526
                    clientPtr->spring[i][j]     = -1;
1527
                    clientPtr->strWidget[i][j]  = 0;
1528
                }
1529
                clientPtr->springFail[i]        = 0;
1530
                clientPtr->fill[i]              = 0;
1531
            }
1532
 
1533
            Tcl_SetHashValue(hPtr, clientPtr);
1534
 
1535
            Tk_CreateEventHandler(tkwin, StructureNotifyMask,
1536
                TixFm_StructureProc, (ClientData) clientPtr);
1537
 
1538
            return clientPtr;
1539
        }
1540
    }
1541
}
1542
 
1543
static MasterInfo *
1544
GetMasterInfo(tkwin, create)
1545
    Tk_Window tkwin;            /* Token for window for which
1546
                                 * FormInfo structure is desired. */
1547
    int create;                 /* Should I create the MasterInfo if it
1548
                                 * does not exist? */
1549
{
1550
    MasterInfo *masterPtr;
1551
    Tcl_HashEntry *hPtr;
1552
    int isNew;
1553
 
1554
    if (!initialized) {
1555
        initialized = 1;
1556
        Tcl_InitHashTable(&formInfoHashTable, TCL_ONE_WORD_KEYS);
1557
        Tcl_InitHashTable(&masterInfoHashTable, TCL_ONE_WORD_KEYS);
1558
    }
1559
 
1560
    /*
1561
     * See if there's already FormInfo for this window.  If not,
1562
     * then create a new one.
1563
     */
1564
    if (!create) {
1565
        hPtr = Tcl_FindHashEntry(&masterInfoHashTable, (char *)tkwin);
1566
        if (!hPtr) {
1567
            return NULL;
1568
        } else {
1569
            return (MasterInfo *) Tcl_GetHashValue(hPtr);
1570
        }
1571
    } else {
1572
        hPtr = Tcl_CreateHashEntry(&masterInfoHashTable, (char *)tkwin,
1573
            &isNew);
1574
        if (!isNew) {
1575
            masterPtr =  (MasterInfo *) Tcl_GetHashValue(hPtr);
1576
        }
1577
        else {
1578
            masterPtr = (MasterInfo *) ckalloc(sizeof(MasterInfo));
1579
            masterPtr->tkwin                    = tkwin;
1580
            masterPtr->client                   = NULL;
1581
            masterPtr->client_tail              = NULL;
1582
            masterPtr->flags.repackPending      = 0;
1583
            masterPtr->flags.isDeleted          = 0;
1584
            masterPtr->numClients               = 0;
1585
            masterPtr->numRequests              = 0;
1586
            masterPtr->grids[0]                  = 100;
1587
            masterPtr->grids[1]                 = 100;
1588
 
1589
            Tcl_SetHashValue(hPtr, masterPtr);
1590
        }
1591
    }
1592
 
1593
    /* TK BUG:
1594
     *
1595
     * It seems like if you destroy some slaves TK will delete the event
1596
     * handler. So for sure we just create it every time a slave is created.
1597
     *
1598
     * Note: calling Tk_CreateEventHandler with same arguments twice won't
1599
     * create two instances of the same event handler: Thus safe to call
1600
     * blindly.
1601
     */
1602
    Tk_CreateEventHandler(tkwin, StructureNotifyMask,
1603
        MasterStructureProc, (ClientData) masterPtr);
1604
#if 0
1605
    Tk_ManageGeometry(tkwin, (Tk_GeomMgr *)&masterType,
1606
        (ClientData) masterPtr);
1607
#endif
1608
    return masterPtr;
1609
}
1610
 
1611
/*----------------------------------------------------------------------
1612
 * PLace the clients
1613
 *----------------------------------------------------------------------
1614
 */
1615
static int PlaceSide_AttNone(clientPtr, axis, which)
1616
    FormInfo *clientPtr;        /* The client to Place down */
1617
    int axis;                           /* 0 = x axis, 1 = yaxis */
1618
    int which;                          /* 0 = min side, 1= max side */
1619
{
1620
    int reqSize;
1621
 
1622
    if (clientPtr->attType[axis][NEXT_SIDE(which)] == ATT_NONE) {
1623
        if (which == SIDE0) {
1624
            clientPtr->posn[axis][which] = 0;
1625
            return TCL_OK;
1626
        }
1627
    }
1628
 
1629
    reqSize = ReqSize(clientPtr->tkwin, axis) +
1630
      clientPtr->pad[axis][0] + clientPtr->pad[axis][1];
1631
 
1632
 
1633
    PLACE_CLIENT_SIDE(clientPtr, axis, NEXT_SIDE(which), 1);
1634
 
1635
    switch (which) {
1636
      case SIDE0:
1637
        clientPtr->posn[axis][which] =
1638
          clientPtr->posn[axis][NEXT_SIDE(which)] - reqSize;
1639
        break;
1640
 
1641
      case SIDE1:
1642
        clientPtr->posn[axis][which] =
1643
          clientPtr->posn[axis][NEXT_SIDE(which)] + reqSize;
1644
        break;
1645
    }
1646
 
1647
    return TCL_OK;
1648
}
1649
 
1650
static int PlaceSide_AttAbsolute(clientPtr, axis, which)
1651
    FormInfo *clientPtr;        /* The client to Place down */
1652
    int axis;                           /* 0 = x axis, 1 = yaxis */
1653
    int which;                          /* 0 = min side, 1= max side */
1654
{
1655
    int mSize[2];
1656
    MasterInfo * masterPtr = clientPtr->master;
1657
    int intBWidth = Tk_InternalBorderWidth(masterPtr->tkwin);
1658
    mSize[0] = Tk_Width(masterPtr->tkwin)  - 2*intBWidth;
1659
    mSize[1] = Tk_Height(masterPtr->tkwin) - 2*intBWidth;
1660
 
1661
    clientPtr->posn[axis][which] =
1662
      mSize[axis] * clientPtr->side[axis][which].pcnt/masterPtr->grids[axis] +
1663
      clientPtr->side[axis][which].disp;
1664
 
1665
    return TCL_OK;
1666
}
1667
 
1668
static int PlaceSide_AttOpposite(clientPtr, axis, which)
1669
    FormInfo *clientPtr;        /* The client to Place down */
1670
    int axis;                           /* 0 = x axis, 1 = yaxis */
1671
    int which;                          /* 0 = min side, 1= max side */
1672
{
1673
    FormInfo * attachPtr;
1674
 
1675
    attachPtr = clientPtr->att[axis][which].widget;
1676
 
1677
    PLACE_CLIENT_SIDE(attachPtr, axis, NEXT_SIDE(which), 0);
1678
 
1679
    clientPtr->posn[axis][which] = attachPtr->posn[axis][NEXT_SIDE(which)];
1680
    clientPtr->posn[axis][which] += clientPtr->off[axis][which];
1681
    return TCL_OK;
1682
}
1683
 
1684
static int PlaceSide_AttParallel(clientPtr, axis, which)
1685
    FormInfo *clientPtr;        /* The client to Place down */
1686
    int axis;                           /* 0 = x axis, 1 = yaxis */
1687
    int which;                          /* 0 = min side, 1= max side */
1688
{
1689
    FormInfo * attachPtr;
1690
 
1691
    attachPtr = clientPtr->att[axis][which].widget;
1692
 
1693
    PLACE_CLIENT_SIDE(attachPtr, axis, NEXT_SIDE(which), 0);
1694
 
1695
    clientPtr->posn[axis][which] = attachPtr->posn[axis][which];
1696
    clientPtr->posn[axis][which] += clientPtr->off[axis][which];
1697
 
1698
    return TCL_OK;
1699
}
1700
 
1701
 
1702
static int PlaceSimpleCase(clientPtr, axis, which)
1703
    FormInfo *clientPtr;        /* The client to Place down */
1704
    int axis;                           /* 0 = x axis, 1 = yaxis */
1705
    int which;                          /* 0 = min side, 1= max side */
1706
{
1707
    clientPtr->depend ++;
1708
 
1709
    switch (clientPtr->attType[axis][which]) {
1710
      case ATT_NONE:
1711
        if (PlaceSide_AttNone(clientPtr, axis, which) == TCL_ERROR) {
1712
            return TCL_ERROR;
1713
        }
1714
        break;
1715
 
1716
      case ATT_GRID:
1717
        if (PlaceSide_AttAbsolute(clientPtr, axis, which) == TCL_ERROR) {
1718
            return TCL_ERROR;
1719
        }
1720
        break;
1721
 
1722
      case ATT_OPPOSITE:
1723
        if (PlaceSide_AttOpposite(clientPtr, axis, which) == TCL_ERROR) {
1724
            return TCL_ERROR;
1725
        }
1726
        break;
1727
      case ATT_PARALLEL:
1728
        if (PlaceSide_AttParallel(clientPtr, axis, which) == TCL_ERROR) {
1729
            return TCL_ERROR;
1730
        }
1731
        break;
1732
    }
1733
 
1734
    if (which == SIDE0) {
1735
        clientPtr->sideFlags[axis] |= PINNED_SIDE0;
1736
    } else {
1737
        clientPtr->sideFlags[axis] |= PINNED_SIDE1;
1738
    }
1739
    clientPtr->depend --;
1740
 
1741
    return TCL_OK;
1742
}
1743
 
1744
/* ToDo: I'll make this more efficient by pre-allocating some links */
1745
static SpringLink *
1746
AllocSpringLink()
1747
{
1748
    return (SpringLink *) ckalloc(sizeof(SpringLink));
1749
}
1750
 
1751
static void
1752
FreeSpringLink(link)
1753
    SpringLink * link;
1754
{
1755
    ckfree((char*)link);
1756
}
1757
 
1758
static void FreeSpringList(listPtr)
1759
    SpringList * listPtr;
1760
{
1761
    SpringLink * link, * toFree;
1762
 
1763
    for (link=listPtr->head; link; ) {
1764
        toFree = link;
1765
        link=link->next;
1766
        FreeSpringLink(toFree);
1767
    }
1768
}
1769
 
1770
static void
1771
AddRightSprings(listPtr, clientPtr)
1772
    SpringList * listPtr;
1773
    FormInfo *clientPtr;
1774
{
1775
    SpringLink * link = AllocSpringLink();
1776
 
1777
    link->next = NULL;
1778
    link->clientPtr = clientPtr;
1779
 
1780
    if (listPtr->head == NULL) {
1781
        listPtr->head = listPtr->tail = link;
1782
    } else {
1783
        listPtr->tail->next = link;
1784
        listPtr->tail = link;
1785
    }
1786
    ++ listPtr->num;
1787
}
1788
 
1789
static void
1790
AddLeftSprings(listPtr,clientPtr)
1791
    SpringList * listPtr;
1792
    FormInfo *clientPtr;
1793
{
1794
    SpringLink * link = AllocSpringLink();
1795
 
1796
    link->next = listPtr->head;
1797
    link->clientPtr = clientPtr;
1798
 
1799
    listPtr->head = link;
1800
    ++ listPtr->num;
1801
}
1802
 
1803
static int
1804
PlaceWithSpring(clientPtr, axis, which)
1805
    FormInfo *clientPtr;        /* The client to Place down */
1806
    int axis;                           /* 0 = x axis, 1 = yaxis */
1807
    int which;                          /* 0 = min side, 1= max side */
1808
{
1809
    SpringList springs;
1810
    SpringLink * link;
1811
    FormInfo *ptr;
1812
    float boundary[2];
1813
    float totalSize, totalStrength;
1814
    int mSize[2];
1815
    float gap, disp;
1816
    MasterInfo * masterPtr = clientPtr->master;
1817
    int intBWidth = Tk_InternalBorderWidth(masterPtr->tkwin);
1818
 
1819
    springs.head = (SpringLink *)0;
1820
    springs.tail = (SpringLink *)0;
1821
    springs.num  = 0;
1822
 
1823
    mSize[0] = Tk_Width(masterPtr->tkwin)  - 2*intBWidth;
1824
    mSize[1] = Tk_Height(masterPtr->tkwin) - 2*intBWidth;
1825
 
1826
    /* Expand the right side of the spring list */
1827
    ptr = clientPtr;
1828
    while (1) {
1829
        switch (ptr->attType[axis][1]) {
1830
          case ATT_OPPOSITE:
1831
          case ATT_NONE:
1832
            /* Some attachments */
1833
            AddRightSprings(&springs, ptr);
1834
 
1835
            if ((ptr = ptr->strWidget[axis][1]) == 0) {
1836
                goto done1;
1837
            }
1838
 
1839
            switch (ptr->attType[axis][0]) {
1840
              case ATT_GRID:
1841
              case ATT_PARALLEL:
1842
                goto done1;
1843
            }
1844
            break;
1845
 
1846
          case ATT_GRID:
1847
          case ATT_PARALLEL:
1848
            AddRightSprings(&springs, ptr);
1849
            goto done1;
1850
        }
1851
    }
1852
 
1853
  done1:
1854
    /* Expand the left side of the spring list */
1855
 
1856
    ptr = clientPtr;
1857
    while (2) {
1858
        switch (ptr->attType[axis][0]) {
1859
          case ATT_OPPOSITE:
1860
          case ATT_NONE:
1861
            /* Some attachments */
1862
            if (ptr != clientPtr) {
1863
                AddLeftSprings(&springs, ptr);
1864
            }
1865
 
1866
            if ((ptr = ptr->strWidget[axis][0]) == 0) {
1867
                goto done2;
1868
            }
1869
 
1870
            switch (ptr->attType[axis][1]) {
1871
              case ATT_PARALLEL:
1872
                goto done2;
1873
            }
1874
            break;
1875
 
1876
          case ATT_GRID:
1877
          case ATT_PARALLEL:
1878
            if (ptr != clientPtr) {
1879
                AddLeftSprings(&springs, ptr);
1880
            }
1881
 
1882
            goto done2;
1883
        }
1884
    }
1885
 
1886
  done2:
1887
 
1888
    /* Make sure this is a good list (neither ends are none) */
1889
    if (springs.head == NULL) {
1890
        /* this should never happen, just to make sure */
1891
        goto fail;
1892
    }
1893
    if (springs.head->clientPtr->attType[axis][0] == ATT_NONE) {
1894
        goto fail;
1895
    }
1896
    if (springs.tail->clientPtr->attType[axis][1] == ATT_NONE) {
1897
        goto fail;
1898
    }
1899
 
1900
    /*
1901
     * Now calculate the total requested sizes of the spring group
1902
     */
1903
    totalSize     = (float)(0.0);
1904
    totalStrength = (float)(0.0);
1905
    for (link=springs.head; link; link=link->next) {
1906
        int size = ReqSize(link->clientPtr->tkwin, axis);
1907
 
1908
        totalSize += size + link->clientPtr->pad[axis][0] +
1909
          link->clientPtr->pad[axis][1];
1910
 
1911
        if (link->clientPtr->spring[axis][0] > 0) {
1912
            totalStrength += link->clientPtr->spring[axis][0];
1913
        }
1914
    }
1915
    if (springs.tail->clientPtr->spring[axis][1] > 0) {
1916
        totalStrength += springs.tail->clientPtr->spring[axis][1];
1917
    }
1918
 
1919
    boundary[0] = (float) mSize[axis] *
1920
      (float) springs.head->clientPtr->side[axis][0].pcnt /
1921
      (float) masterPtr->grids[axis] +
1922
      (float) springs.head->clientPtr->side[axis][0].disp;
1923
    boundary[1] = (float) mSize[axis] *
1924
      (float) springs.tail->clientPtr->side[axis][1].pcnt /
1925
      (float) masterPtr->grids[axis] +
1926
      (float) springs.tail->clientPtr->side[axis][1].disp;
1927
 
1928
    /* (4) Now spread the sizes to the members of this list */
1929
    gap = (float)(boundary[1] - boundary[0]) - totalSize;
1930
    if (gap < 0) {
1931
        goto fail;
1932
    }
1933
 
1934
    disp = boundary[0];
1935
    if (totalStrength <= 0.0) {
1936
        totalStrength = (float)(1.0);
1937
    }
1938
    for (link=springs.head; link; link=link->next) {
1939
        float spring0, spring1;
1940
        int gap0, gap1;
1941
        int adjust;             /* to overcome round-off errors */
1942
 
1943
        spring0 = (float)link->clientPtr->spring[axis][0];
1944
        spring1 = (float)link->clientPtr->spring[axis][1];
1945
 
1946
        if (spring0 < (float)(0.0)) {
1947
            spring0 = (float)(0.0);
1948
        }
1949
        if (spring1 < (float)(0.0)) {
1950
            spring1 = (float)(0.0);
1951
        }
1952
 
1953
        /* Divide by two: because two consecutive clients share the same
1954
         * spring; so each of them get a half.
1955
         */
1956
        adjust = 0;
1957
        if (link !=springs.head) {
1958
            if (spring0 > 0 && link->clientPtr->spring[axis][0] % 2 == 1) {
1959
                adjust = 1;
1960
            }
1961
            spring0 /= (float)(2.0);
1962
        }
1963
        if (link !=springs.tail) {
1964
            spring1 /= (float)(2.0);
1965
        }
1966
 
1967
        gap0 = (int)(gap * spring0 / totalStrength) + adjust;
1968
        gap1 = (int)(gap * spring1 / totalStrength);
1969
 
1970
        if (link->clientPtr->fill[axis]) {
1971
            link->clientPtr->posn[axis][0] = (int)disp;
1972
            disp += gap0;
1973
            disp += gap1;
1974
            disp += ReqSize(link->clientPtr->tkwin, axis);
1975
 
1976
            /* Somehow there may be a round-off right at the end of the
1977
             * list --> kludge*/
1978
            if (link->next == NULL) {
1979
                disp = boundary[1];
1980
            }
1981
            link->clientPtr->posn[axis][1] = (int)disp;
1982
        } else {
1983
            disp += gap0;
1984
            link->clientPtr->posn[axis][0] = (int)disp;
1985
            disp += ReqSize(link->clientPtr->tkwin, axis);
1986
            link->clientPtr->posn[axis][1] = (int)disp;
1987
            disp += gap1;
1988
 
1989
            /*
1990
             * Somehow there may be a round-off right at the end of the
1991
             * list --> kludge
1992
             */
1993
            if (link->next == NULL && gap1 < 0.001) {
1994
                link->clientPtr->posn[axis][1] =  (int)boundary[1];
1995
            }
1996
        }
1997
 
1998
        link->clientPtr->sideFlags[axis] |= PINNED_SIDE0;
1999
        link->clientPtr->sideFlags[axis] |= PINNED_SIDE1;
2000
    }
2001
 
2002
    FreeSpringList(&springs);
2003
    return TCL_OK;
2004
 
2005
  fail:
2006
    for (link=springs.head; link; link=link->next) {
2007
        link->clientPtr->springFail[axis] = 1;
2008
    }
2009
    FreeSpringList(&springs);
2010
    return TCL_ERROR;
2011
}
2012
 
2013
static int PlaceClientSide(clientPtr, axis, which, isSelf)
2014
    FormInfo *clientPtr;        /* The client to Place down */
2015
    int axis;                           /* 0 = x axis, 1 = yaxis */
2016
    int which;                          /* 0 = min side, 1= max side */
2017
    int isSelf;
2018
{
2019
    if ((which == SIDE0) && (clientPtr->sideFlags[axis] & PINNED_SIDE0)) {
2020
        /* already Placeed */
2021
        return TCL_OK;
2022
    }
2023
    if ((which == SIDE1) && (clientPtr->sideFlags[axis] & PINNED_SIDE1)) {
2024
        /* already Placeed */
2025
        return TCL_OK;
2026
    }
2027
 
2028
    if ((clientPtr->depend > 0) && !isSelf) {
2029
        /*
2030
         * circular dependency detected
2031
         */
2032
        return TCL_ERROR;
2033
    }
2034
 
2035
    /*  No spring : we just do a "simple case"
2036
     *  The condition is ( (x || x) && (x || x) )
2037
     */
2038
    if ((clientPtr->spring[axis][0] < 0 ||
2039
         (clientPtr->sideFlags[axis] & PINNED_SIDE0)) &&
2040
        (clientPtr->spring[axis][1] < 0 ||
2041
         (clientPtr->sideFlags[axis] & PINNED_SIDE1))) {
2042
        return PlaceSimpleCase(clientPtr, axis, which);
2043
    }
2044
    if (clientPtr->springFail[axis]) {
2045
        return PlaceSimpleCase(clientPtr, axis, which);
2046
    }
2047
 
2048
    if (PlaceWithSpring(clientPtr, axis, which) != TCL_OK) {
2049
        /* if comes to here : (1) Not enough space for the spring expansion
2050
         *                    (2) Not both end-sides are spring-attached */
2051
        return PlaceSimpleCase(clientPtr, axis, which);
2052
    } else {
2053
        return TCL_OK;
2054
    }
2055
}
2056
 
2057
static int PlaceClient(clientPtr)
2058
    FormInfo *clientPtr;
2059
{
2060
    int i;
2061
 
2062
    for (i=0; i<2; i++) {
2063
        if (!(clientPtr->sideFlags[i] & PINNED_SIDE0)) {
2064
            PLACE_CLIENT_SIDE(clientPtr, i, SIDE0, 0);
2065
        }
2066
        if (!(clientPtr->sideFlags[i] & PINNED_SIDE1)) {
2067
            PLACE_CLIENT_SIDE(clientPtr, i, SIDE1, 0);
2068
        }
2069
    }
2070
 
2071
    return TCL_OK;
2072
}
2073
 
2074
static int PlaceAllClients(masterPtr)
2075
    MasterInfo * masterPtr;
2076
{
2077
    FormInfo *clientPtr;
2078
    int i;
2079
 
2080
    /*
2081
     * First mark all clients as unpinned, and clean the opposite flags,
2082
     */
2083
    for (clientPtr = masterPtr->client; clientPtr; clientPtr=clientPtr->next) {
2084
        if (clientPtr->tkwin != NULL) {
2085
            for (i=0; i<2; i++) {
2086
                /* clear all flags */
2087
                clientPtr->sideFlags[i]  = 0;
2088
                clientPtr->springFail[i] = 0;
2089
            }
2090
            clientPtr->depend = 0;
2091
        }
2092
    }
2093
 
2094
    /*
2095
     * Now calculate their actual positions on the master
2096
     */
2097
    for (clientPtr = masterPtr->client; clientPtr; clientPtr=clientPtr->next) {
2098
        if (clientPtr->tkwin == NULL) { /* it was deleted */
2099
            continue;
2100
        }
2101
        for (i=0; i<2; i++) {
2102
            if ((clientPtr->sideFlags[i] & PINNED_ALL) != PINNED_ALL) {
2103
                if (PlaceClient(clientPtr) == TCL_ERROR) {
2104
                    /*
2105
                     * Detected circular dependency
2106
                     */
2107
                    return TCL_ERROR;
2108
                }
2109
                break;
2110
            }
2111
        }
2112
    }
2113
    return TCL_OK;
2114
}

powered by: WebSVN 2.1.0

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