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

Contents of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkgrid.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 71 - (show annotations) (download)
Sat Nov 5 11:07:06 2016 UTC (7 years, 4 months ago) by dashley
File MIME type: text/plain
File size: 80121 byte(s)
Set EOL properties appropriately to facilitate simultaneous Linux and Windows development.
1 /* $Header$ */
2
3 /*
4 * tkGrid.c --
5 *
6 * Grid based geometry manager.
7 *
8 * Copyright (c) 1996-1997 by 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: tkgrid.c,v 1.1.1.1 2001/06/13 05:02:05 dtashley Exp $
14 */
15
16 #include "tkInt.h"
17
18 /*
19 * Convenience Macros
20 */
21
22 #ifdef MAX
23 # undef MAX
24 #endif
25 #define MAX(x,y) ((x) > (y) ? (x) : (y))
26 #ifdef MIN
27 # undef MIN
28 #endif
29 #define MIN(x,y) ((x) > (y) ? (y) : (x))
30
31 #define COLUMN (1) /* working on column offsets */
32 #define ROW (2) /* working on row offsets */
33
34 #define CHECK_ONLY (1) /* check max slot constraint */
35 #define CHECK_SPACE (2) /* alloc more space, don't change max */
36
37 /*
38 * Pre-allocate enough row and column slots for "typical" sized tables
39 * this value should be chosen so by the time the extra malloc's are
40 * required, the layout calculations overwehlm them. [A "slot" contains
41 * information for either a row or column, depending upon the context.]
42 */
43
44 #define TYPICAL_SIZE 25 /* (arbitrary guess) */
45 #define PREALLOC 10 /* extra slots to allocate */
46
47 /*
48 * Data structures are allocated dynamically to support arbitrary sized tables.
49 * However, the space is proportional to the highest numbered slot with
50 * some non-default property. This limit is used to head off mistakes and
51 * denial of service attacks by limiting the amount of storage required.
52 */
53
54 #define MAX_ELEMENT 10000
55
56 /*
57 * Special characters to support relative layouts.
58 */
59
60 #define REL_SKIP 'x' /* Skip this column. */
61 #define REL_HORIZ '-' /* Extend previous widget horizontally. */
62 #define REL_VERT '^' /* Extend widget from row above. */
63
64 /*
65 * Structure to hold information for grid masters. A slot is either
66 * a row or column.
67 */
68
69 typedef struct SlotInfo {
70 int minSize; /* The minimum size of this slot (in pixels).
71 * It is set via the rowconfigure or
72 * columnconfigure commands. */
73 int weight; /* The resize weight of this slot. (0) means
74 * this slot doesn't resize. Extra space in
75 * the layout is given distributed among slots
76 * inproportion to their weights. */
77 int pad; /* Extra padding, in pixels, required for
78 * this slot. This amount is "added" to the
79 * largest slave in the slot. */
80 int offset; /* This is a cached value used for
81 * introspection. It is the pixel
82 * offset of the right or bottom edge
83 * of this slot from the beginning of the
84 * layout. */
85 int temp; /* This is a temporary value used for
86 * calculating adjusted weights when
87 * shrinking the layout below its
88 * nominal size. */
89 } SlotInfo;
90
91 /*
92 * Structure to hold information during layout calculations. There
93 * is one of these for each slot, an array for each of the rows or columns.
94 */
95
96 typedef struct GridLayout {
97 struct Gridder *binNextPtr; /* The next slave window in this bin.
98 * Each bin contains a list of all
99 * slaves whose spans are >1 and whose
100 * right edges fall in this slot. */
101 int minSize; /* Minimum size needed for this slot,
102 * in pixels. This is the space required
103 * to hold any slaves contained entirely
104 * in this slot, adjusted for any slot
105 * constrants, such as size or padding. */
106 int pad; /* Padding needed for this slot */
107 int weight; /* Slot weight, controls resizing. */
108 int minOffset; /* The minimum offset, in pixels, from
109 * the beginning of the layout to the
110 * right/bottom edge of the slot calculated
111 * from top/left to bottom/right. */
112 int maxOffset; /* The maximum offset, in pixels, from
113 * the beginning of the layout to the
114 * right-or-bottom edge of the slot calculated
115 * from bottom-or-right to top-or-left. */
116 } GridLayout;
117
118 /*
119 * Keep one of these for each geometry master.
120 */
121
122 typedef struct {
123 SlotInfo *columnPtr; /* Pointer to array of column constraints. */
124 SlotInfo *rowPtr; /* Pointer to array of row constraints. */
125 int columnEnd; /* The last column occupied by any slave. */
126 int columnMax; /* The number of columns with constraints. */
127 int columnSpace; /* The number of slots currently allocated for
128 * column constraints. */
129 int rowEnd; /* The last row occupied by any slave. */
130 int rowMax; /* The number of rows with constraints. */
131 int rowSpace; /* The number of slots currently allocated
132 * for row constraints. */
133 int startX; /* Pixel offset of this layout within its
134 * parent. */
135 int startY; /* Pixel offset of this layout within its
136 * parent. */
137 } GridMaster;
138
139 /*
140 * For each window that the grid cares about (either because
141 * the window is managed by the grid or because the window
142 * has slaves that are managed by the grid), there is a
143 * structure of the following type:
144 */
145
146 typedef struct Gridder {
147 Tk_Window tkwin; /* Tk token for window. NULL means that
148 * the window has been deleted, but the
149 * gridder hasn't had a chance to clean up
150 * yet because the structure is still in
151 * use. */
152 struct Gridder *masterPtr; /* Master window within which this window
153 * is managed (NULL means this window
154 * isn't managed by the gridder). */
155 struct Gridder *nextPtr; /* Next window managed within same
156 * parent. List order doesn't matter. */
157 struct Gridder *slavePtr; /* First in list of slaves managed
158 * inside this window (NULL means
159 * no grid slaves). */
160 GridMaster *masterDataPtr; /* Additional data for geometry master. */
161 int column, row; /* Location in the grid (starting
162 * from zero). */
163 int numCols, numRows; /* Number of columns or rows this slave spans.
164 * Should be at least 1. */
165 int padX, padY; /* Total additional pixels to leave around the
166 * window (half of this space is left on each
167 * side). This is space *outside* the window:
168 * we'll allocate extra space in frame but
169 * won't enlarge window). */
170 int iPadX, iPadY; /* Total extra pixels to allocate inside the
171 * window (half this amount will appear on
172 * each side). */
173 int sticky; /* which sides of its cavity this window
174 * sticks to. See below for definitions */
175 int doubleBw; /* Twice the window's last known border
176 * width. If this changes, the window
177 * must be re-arranged within its parent. */
178 int *abortPtr; /* If non-NULL, it means that there is a nested
179 * call to ArrangeGrid already working on
180 * this window. *abortPtr may be set to 1 to
181 * abort that nested call. This happens, for
182 * example, if tkwin or any of its slaves
183 * is deleted. */
184 int flags; /* Miscellaneous flags; see below
185 * for definitions. */
186
187 /*
188 * These fields are used temporarily for layout calculations only.
189 */
190
191 struct Gridder *binNextPtr; /* Link to next span>1 slave in this bin. */
192 int size; /* Nominal size (width or height) in pixels
193 * of the slave. This includes the padding. */
194 } Gridder;
195
196 /* Flag values for "sticky"ness The 16 combinations subsume the packer's
197 * notion of anchor and fill.
198 *
199 * STICK_NORTH This window sticks to the top of its cavity.
200 * STICK_EAST This window sticks to the right edge of its cavity.
201 * STICK_SOUTH This window sticks to the bottom of its cavity.
202 * STICK_WEST This window sticks to the left edge of its cavity.
203 */
204
205 #define STICK_NORTH 1
206 #define STICK_EAST 2
207 #define STICK_SOUTH 4
208 #define STICK_WEST 8
209
210 /*
211 * Flag values for Grid structures:
212 *
213 * REQUESTED_RELAYOUT: 1 means a Tcl_DoWhenIdle request
214 * has already been made to re-arrange
215 * all the slaves of this window.
216 *
217 * DONT_PROPAGATE: 1 means don't set this window's requested
218 * size. 0 means if this window is a master
219 * then Tk will set its requested size to fit
220 * the needs of its slaves.
221 */
222
223 #define REQUESTED_RELAYOUT 1
224 #define DONT_PROPAGATE 2
225
226 /*
227 * Prototypes for procedures used only in this file:
228 */
229
230 static void AdjustForSticky _ANSI_ARGS_((Gridder *slavePtr, int *xPtr,
231 int *yPtr, int *widthPtr, int *heightPtr));
232 static int AdjustOffsets _ANSI_ARGS_((int width,
233 int elements, SlotInfo *slotPtr));
234 static void ArrangeGrid _ANSI_ARGS_((ClientData clientData));
235 static int CheckSlotData _ANSI_ARGS_((Gridder *masterPtr, int slot,
236 int slotType, int checkOnly));
237 static int ConfigureSlaves _ANSI_ARGS_((Tcl_Interp *interp,
238 Tk_Window tkwin, int argc, char *argv[]));
239 static void DestroyGrid _ANSI_ARGS_((char *memPtr));
240 static Gridder *GetGrid _ANSI_ARGS_((Tk_Window tkwin));
241 static void GridStructureProc _ANSI_ARGS_((
242 ClientData clientData, XEvent *eventPtr));
243 static void GridLostSlaveProc _ANSI_ARGS_((ClientData clientData,
244 Tk_Window tkwin));
245 static void GridReqProc _ANSI_ARGS_((ClientData clientData,
246 Tk_Window tkwin));
247 static void InitMasterData _ANSI_ARGS_((Gridder *masterPtr));
248 static int ResolveConstraints _ANSI_ARGS_((Gridder *gridPtr,
249 int rowOrColumn, int maxOffset));
250 static void SetGridSize _ANSI_ARGS_((Gridder *gridPtr));
251 static void StickyToString _ANSI_ARGS_((int flags, char *result));
252 static int StringToSticky _ANSI_ARGS_((char *string));
253 static void Unlink _ANSI_ARGS_((Gridder *gridPtr));
254
255 static Tk_GeomMgr gridMgrType = {
256 "grid", /* name */
257 GridReqProc, /* requestProc */
258 GridLostSlaveProc, /* lostSlaveProc */
259 };
260
261 /*
262 *--------------------------------------------------------------
263 *
264 * Tk_GridCmd --
265 *
266 * This procedure is invoked to process the "grid" Tcl command.
267 * See the user documentation for details on what it does.
268 *
269 * Results:
270 * A standard Tcl result.
271 *
272 * Side effects:
273 * See the user documentation.
274 *
275 *--------------------------------------------------------------
276 */
277
278 int
279 Tk_GridCmd(clientData, interp, argc, argv)
280 ClientData clientData; /* Main window associated with
281 * interpreter. */
282 Tcl_Interp *interp; /* Current interpreter. */
283 int argc; /* Number of arguments. */
284 char **argv; /* Argument strings. */
285 {
286 Tk_Window tkwin = (Tk_Window) clientData;
287 Gridder *masterPtr; /* master grid record */
288 GridMaster *gridPtr; /* pointer to grid data */
289 size_t length; /* streing length of argument */
290 char c; /* 1st character of argument */
291
292 if ((argc >= 2) && ((argv[1][0] == '.') || (argv[1][0] == REL_SKIP) ||
293 (argv[1][0] == REL_VERT))) {
294 return ConfigureSlaves(interp, tkwin, argc-1, argv+1);
295 }
296 if (argc < 3) {
297 Tcl_AppendResult(interp, "wrong # args: should be \"",
298 argv[0], " option arg ?arg ...?\"", (char *) NULL);
299 return TCL_ERROR;
300 }
301 c = argv[1][0];
302 length = strlen(argv[1]);
303
304 if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)) {
305 Tk_Window master;
306 int row, column; /* origin for bounding box */
307 int row2, column2; /* end of bounding box */
308 int endX, endY; /* last column/row in the layout */
309 int x=0, y=0; /* starting pixels for this bounding box */
310 int width, height; /* size of the bounding box */
311 char buf[TCL_INTEGER_SPACE * 4];
312
313 if (argc!=3 && argc != 5 && argc != 7) {
314 Tcl_AppendResult(interp, "wrong number of arguments: ",
315 "must be \"",argv[0],
316 " bbox master ?column row ?column row??\"",
317 (char *) NULL);
318 return TCL_ERROR;
319 }
320
321 master = Tk_NameToWindow(interp, argv[2], tkwin);
322 if (master == NULL) {
323 return TCL_ERROR;
324 }
325 masterPtr = GetGrid(master);
326
327 if (argc >= 5) {
328 if (Tcl_GetInt(interp, argv[3], &column) != TCL_OK) {
329 return TCL_ERROR;
330 }
331 if (Tcl_GetInt(interp, argv[4], &row) != TCL_OK) {
332 return TCL_ERROR;
333 }
334 column2 = column;
335 row2 = row;
336 }
337
338 if (argc == 7) {
339 if (Tcl_GetInt(interp, argv[5], &column2) != TCL_OK) {
340 return TCL_ERROR;
341 }
342 if (Tcl_GetInt(interp, argv[6], &row2) != TCL_OK) {
343 return TCL_ERROR;
344 }
345 }
346
347 gridPtr = masterPtr->masterDataPtr;
348 if (gridPtr == NULL) {
349 Tcl_SetResult(interp, "0 0 0 0", TCL_STATIC);
350 return(TCL_OK);
351 }
352
353 SetGridSize(masterPtr);
354 endX = MAX(gridPtr->columnEnd, gridPtr->columnMax);
355 endY = MAX(gridPtr->rowEnd, gridPtr->rowMax);
356
357 if ((endX == 0) || (endY == 0)) {
358 Tcl_SetResult(interp, "0 0 0 0", TCL_STATIC);
359 return(TCL_OK);
360 }
361 if (argc == 3) {
362 row = column = 0;
363 row2 = endY;
364 column2 = endX;
365 }
366
367 if (column > column2) {
368 int temp = column;
369 column = column2, column2 = temp;
370 }
371 if (row > row2) {
372 int temp = row;
373 row = row2, row2 = temp;
374 }
375
376 if (column > 0 && column < endX) {
377 x = gridPtr->columnPtr[column-1].offset;
378 } else if (column > 0) {
379 x = gridPtr->columnPtr[endX-1].offset;
380 }
381
382 if (row > 0 && row < endY) {
383 y = gridPtr->rowPtr[row-1].offset;
384 } else if (row > 0) {
385 y = gridPtr->rowPtr[endY-1].offset;
386 }
387
388 if (column2 < 0) {
389 width = 0;
390 } else if (column2 >= endX) {
391 width = gridPtr->columnPtr[endX-1].offset - x;
392 } else {
393 width = gridPtr->columnPtr[column2].offset - x;
394 }
395
396 if (row2 < 0) {
397 height = 0;
398 } else if (row2 >= endY) {
399 height = gridPtr->rowPtr[endY-1].offset - y;
400 } else {
401 height = gridPtr->rowPtr[row2].offset - y;
402 }
403
404 sprintf(buf, "%d %d %d %d", x + gridPtr->startX, y + gridPtr->startY,
405 width, height);
406 Tcl_SetResult(interp, buf, TCL_VOLATILE);
407 } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)) {
408 if (argv[2][0] != '.') {
409 Tcl_AppendResult(interp, "bad argument \"", argv[2],
410 "\": must be name of window", (char *) NULL);
411 return TCL_ERROR;
412 }
413 return ConfigureSlaves(interp, tkwin, argc-2, argv+2);
414 } else if (((c == 'f') && (strncmp(argv[1], "forget", length) == 0)) ||
415 ((c == 'r') && (strncmp(argv[1], "remove", length) == 0))) {
416 Tk_Window slave;
417 Gridder *slavePtr;
418 int i;
419
420 for (i = 2; i < argc; i++) {
421 slave = Tk_NameToWindow(interp, argv[i], tkwin);
422 if (slave == NULL) {
423 return TCL_ERROR;
424 }
425 slavePtr = GetGrid(slave);
426 if (slavePtr->masterPtr != NULL) {
427
428 /*
429 * For "forget", reset all the settings to their defaults
430 */
431
432 if (c == 'f') {
433 slavePtr->column = slavePtr->row = -1;
434 slavePtr->numCols = 1;
435 slavePtr->numRows = 1;
436 slavePtr->padX = slavePtr->padY = 0;
437 slavePtr->iPadX = slavePtr->iPadY = 0;
438 slavePtr->doubleBw = 2*Tk_Changes(tkwin)->border_width;
439 if (slavePtr->flags & REQUESTED_RELAYOUT) {
440 Tcl_CancelIdleCall(ArrangeGrid, (ClientData) slavePtr);
441 }
442 slavePtr->flags = 0;
443 slavePtr->sticky = 0;
444 }
445 Tk_ManageGeometry(slave, (Tk_GeomMgr *) NULL,
446 (ClientData) NULL);
447 if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {
448 Tk_UnmaintainGeometry(slavePtr->tkwin,
449 slavePtr->masterPtr->tkwin);
450 }
451 Unlink(slavePtr);
452 Tk_UnmapWindow(slavePtr->tkwin);
453 }
454 }
455 } else if ((c == 'i') && (strncmp(argv[1], "info", length) == 0)) {
456 register Gridder *slavePtr;
457 Tk_Window slave;
458 char buffer[64 + TCL_INTEGER_SPACE * 4];
459
460 if (argc != 3) {
461 Tcl_AppendResult(interp, "wrong # args: should be \"",
462 argv[0], " info window\"", (char *) NULL);
463 return TCL_ERROR;
464 }
465 slave = Tk_NameToWindow(interp, argv[2], tkwin);
466 if (slave == NULL) {
467 return TCL_ERROR;
468 }
469 slavePtr = GetGrid(slave);
470 if (slavePtr->masterPtr == NULL) {
471 Tcl_ResetResult(interp);
472 return TCL_OK;
473 }
474
475 Tcl_AppendElement(interp, "-in");
476 Tcl_AppendElement(interp, Tk_PathName(slavePtr->masterPtr->tkwin));
477 sprintf(buffer, " -column %d -row %d -columnspan %d -rowspan %d",
478 slavePtr->column, slavePtr->row,
479 slavePtr->numCols, slavePtr->numRows);
480 Tcl_AppendResult(interp, buffer, (char *) NULL);
481 sprintf(buffer, " -ipadx %d -ipady %d -padx %d -pady %d",
482 slavePtr->iPadX/2, slavePtr->iPadY/2, slavePtr->padX/2,
483 slavePtr->padY/2);
484 Tcl_AppendResult(interp, buffer, (char *) NULL);
485 StickyToString(slavePtr->sticky,buffer);
486 Tcl_AppendResult(interp, " -sticky ", buffer, (char *) NULL);
487 } else if((c == 'l') && (strncmp(argv[1], "location", length) == 0)) {
488 Tk_Window master;
489 register SlotInfo *slotPtr;
490 int x, y; /* Offset in pixels, from edge of parent. */
491 int i, j; /* Corresponding column and row indeces. */
492 int endX, endY; /* end of grid */
493 char buf[TCL_INTEGER_SPACE * 2];
494
495 if (argc != 5) {
496 Tcl_AppendResult(interp, "wrong # args: should be \"",
497 argv[0], " location master x y\"", (char *)NULL);
498 return TCL_ERROR;
499 }
500
501 master = Tk_NameToWindow(interp, argv[2], tkwin);
502 if (master == NULL) {
503 return TCL_ERROR;
504 }
505
506 if (Tk_GetPixels(interp, master, argv[3], &x) != TCL_OK) {
507 return TCL_ERROR;
508 }
509 if (Tk_GetPixels(interp, master, argv[4], &y) != TCL_OK) {
510 return TCL_ERROR;
511 }
512
513 masterPtr = GetGrid(master);
514 if (masterPtr->masterDataPtr == NULL) {
515 Tcl_SetResult(interp, "-1 -1", TCL_STATIC);
516 return TCL_OK;
517 }
518 gridPtr = masterPtr->masterDataPtr;
519
520 /*
521 * Update any pending requests. This is not always the
522 * steady state value, as more configure events could be in
523 * the pipeline, but its as close as its easy to get.
524 */
525
526 while (masterPtr->flags & REQUESTED_RELAYOUT) {
527 Tcl_CancelIdleCall(ArrangeGrid, (ClientData) masterPtr);
528 ArrangeGrid ((ClientData) masterPtr);
529 }
530 SetGridSize(masterPtr);
531 endX = MAX(gridPtr->columnEnd, gridPtr->columnMax);
532 endY = MAX(gridPtr->rowEnd, gridPtr->rowMax);
533
534 slotPtr = masterPtr->masterDataPtr->columnPtr;
535 if (x < masterPtr->masterDataPtr->startX) {
536 i = -1;
537 } else {
538 x -= masterPtr->masterDataPtr->startX;
539 for (i=0;slotPtr[i].offset < x && i < endX; i++) {
540 /* null body */
541 }
542 }
543
544 slotPtr = masterPtr->masterDataPtr->rowPtr;
545 if (y < masterPtr->masterDataPtr->startY) {
546 j = -1;
547 } else {
548 y -= masterPtr->masterDataPtr->startY;
549 for (j=0;slotPtr[j].offset < y && j < endY; j++) {
550 /* null body */
551 }
552 }
553
554 sprintf(buf, "%d %d", i, j);
555 Tcl_SetResult(interp, buf, TCL_VOLATILE);
556 } else if ((c == 'p') && (strncmp(argv[1], "propagate", length) == 0)) {
557 Tk_Window master;
558 int propagate;
559
560 if (argc > 4) {
561 Tcl_AppendResult(interp, "wrong # args: should be \"",
562 argv[0], " propagate window ?boolean?\"",
563 (char *) NULL);
564 return TCL_ERROR;
565 }
566 master = Tk_NameToWindow(interp, argv[2], tkwin);
567 if (master == NULL) {
568 return TCL_ERROR;
569 }
570 masterPtr = GetGrid(master);
571 if (argc == 3) {
572 Tcl_SetResult(interp,
573 ((masterPtr->flags & DONT_PROPAGATE) ? "0" : "1"),
574 TCL_STATIC);
575 return TCL_OK;
576 }
577 if (Tcl_GetBoolean(interp, argv[3], &propagate) != TCL_OK) {
578 return TCL_ERROR;
579 }
580
581 /* Only request a relayout if the propagation bit changes */
582
583 if ((!propagate) ^ (masterPtr->flags&DONT_PROPAGATE)) {
584 if (propagate) {
585 masterPtr->flags &= ~DONT_PROPAGATE;
586 } else {
587 masterPtr->flags |= DONT_PROPAGATE;
588 }
589
590 /*
591 * Re-arrange the master to allow new geometry information to
592 * propagate upwards to the master's master.
593 */
594
595 if (masterPtr->abortPtr != NULL) {
596 *masterPtr->abortPtr = 1;
597 }
598 if (!(masterPtr->flags & REQUESTED_RELAYOUT)) {
599 masterPtr->flags |= REQUESTED_RELAYOUT;
600 Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);
601 }
602 }
603 } else if ((c == 's') && (strncmp(argv[1], "size", length) == 0)
604 && (length > 1)) {
605 Tk_Window master;
606
607 if (argc != 3) {
608 Tcl_AppendResult(interp, "wrong # args: should be \"",
609 argv[0], " size window\"", (char *) NULL);
610 return TCL_ERROR;
611 }
612 master = Tk_NameToWindow(interp, argv[2], tkwin);
613 if (master == NULL) {
614 return TCL_ERROR;
615 }
616 masterPtr = GetGrid(master);
617
618 if (masterPtr->masterDataPtr != NULL) {
619 char buf[TCL_INTEGER_SPACE * 2];
620
621 SetGridSize(masterPtr);
622 gridPtr = masterPtr->masterDataPtr;
623 sprintf(buf, "%d %d",
624 MAX(gridPtr->columnEnd, gridPtr->columnMax),
625 MAX(gridPtr->rowEnd, gridPtr->rowMax));
626 Tcl_SetResult(interp, buf, TCL_VOLATILE);
627 } else {
628 Tcl_SetResult(interp, "0 0", TCL_STATIC);
629 }
630 } else if ((c == 's') && (strncmp(argv[1], "slaves", length) == 0)
631 && (length > 1)) {
632 Tk_Window master;
633 Gridder *slavePtr;
634 int i, value;
635 int row = -1, column = -1;
636
637 if ((argc < 3) || ((argc%2) == 0)) {
638 Tcl_AppendResult(interp, "wrong # args: should be \"",
639 argv[0], " slaves window ?-option value...?\"",
640 (char *) NULL);
641 return TCL_ERROR;
642 }
643
644 for (i=3; i<argc; i+=2) {
645 length = strlen(argv[i]);
646 if ((*argv[i] != '-') || (length < 2)) {
647 Tcl_AppendResult(interp, "invalid args: should be \"",
648 argv[0], " slaves window ?-option value...?\"",
649 (char *) NULL);
650 return TCL_ERROR;
651 }
652 if (Tcl_GetInt(interp, argv[i+1], &value) != TCL_OK) {
653 return TCL_ERROR;
654 }
655 if (value < 0) {
656 Tcl_AppendResult(interp, argv[i],
657 " is an invalid value: should NOT be < 0",
658 (char *) NULL);
659 return TCL_ERROR;
660 }
661 if (strncmp(argv[i], "-column", length) == 0) {
662 column = value;
663 } else if (strncmp(argv[i], "-row", length) == 0) {
664 row = value;
665 } else {
666 Tcl_AppendResult(interp, argv[i],
667 " is an invalid option: should be \"",
668 "-row, -column\"",
669 (char *) NULL);
670 return TCL_ERROR;
671 }
672 }
673 master = Tk_NameToWindow(interp, argv[2], tkwin);
674 if (master == NULL) {
675 return TCL_ERROR;
676 }
677 masterPtr = GetGrid(master);
678
679 for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
680 slavePtr = slavePtr->nextPtr) {
681 if (column>=0 && (slavePtr->column > column
682 || slavePtr->column+slavePtr->numCols-1 < column)) {
683 continue;
684 }
685 if (row>=0 && (slavePtr->row > row ||
686 slavePtr->row+slavePtr->numRows-1 < row)) {
687 continue;
688 }
689 Tcl_AppendElement(interp, Tk_PathName(slavePtr->tkwin));
690 }
691
692 /*
693 * Sample argument combinations:
694 * grid columnconfigure <master> <index> -option
695 * grid columnconfigure <master> <index> -option value -option value
696 * grid rowconfigure <master> <index>
697 * grid rowconfigure <master> <index> -option
698 * grid rowconfigure <master> <index> -option value -option value.
699 */
700
701 } else if(((c == 'c') && (strncmp(argv[1], "columnconfigure", length) == 0)
702 && (length >= 3)) ||
703 ((c == 'r') && (strncmp(argv[1], "rowconfigure", length) == 0)
704 && (length >=2))) {
705 Tk_Window master;
706 SlotInfo *slotPtr = NULL;
707 int slot; /* the column or row number */
708 size_t length; /* the # of chars in the "-option" string */
709 int slotType; /* COLUMN or ROW */
710 int size; /* the configuration value */
711 int checkOnly; /* check the size only */
712 int argcPtr; /* Number of items in index list */
713 char **argvPtr; /* array of indeces */
714 char **indexP; /* String value of current index list item. */
715 int ok; /* temporary TCL result code */
716 int i;
717
718 if (((argc%2 != 0) && (argc>6)) || (argc < 4)) {
719 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
720 " ", argv[1], " master index ?-option value...?\"",
721 (char *)NULL);
722 return TCL_ERROR;
723 }
724
725 master = Tk_NameToWindow(interp, argv[2], tkwin);
726 if (master == NULL) {
727 return TCL_ERROR;
728 }
729
730 if (Tcl_SplitList(interp, argv[3], &argcPtr, &argvPtr) != TCL_OK) {
731 return TCL_ERROR;
732 }
733
734 checkOnly = ((argc == 4) || (argc == 5));
735 masterPtr = GetGrid(master);
736 slotType = (c == 'c') ? COLUMN : ROW;
737 if (checkOnly && argcPtr > 1) {
738 Tcl_AppendResult(interp, argv[3],
739 " must be a single element.", (char *) NULL);
740 Tcl_Free((char *)argvPtr);
741 return TCL_ERROR;
742 }
743 for (indexP=argvPtr; *indexP != NULL; indexP++) {
744 if (Tcl_GetInt(interp, *indexP, &slot) != TCL_OK) {
745 Tcl_Free((char *)argvPtr);
746 return TCL_ERROR;
747 }
748 ok = CheckSlotData(masterPtr, slot, slotType, checkOnly);
749 if ((ok!=TCL_OK) && ((argc<4) || (argc>5))) {
750 Tcl_AppendResult(interp, argv[0],
751 " ", argv[1], ": \"", *argvPtr,"\" is out of range",
752 (char *) NULL);
753 Tcl_Free((char *)argvPtr);
754 return TCL_ERROR;
755 } else if (ok == TCL_OK) {
756 slotPtr = (slotType == COLUMN) ?
757 masterPtr->masterDataPtr->columnPtr :
758 masterPtr->masterDataPtr->rowPtr;
759 }
760
761 /*
762 * Return all of the options for this row or column. If the
763 * request is out of range, return all 0's.
764 */
765
766 if (argc == 4) {
767 Tcl_Free((char *)argvPtr);
768 }
769 if ((argc == 4) && (ok == TCL_OK)) {
770 char buf[64 + TCL_INTEGER_SPACE * 3];
771
772 sprintf(buf, "-minsize %d -pad %d -weight %d",
773 slotPtr[slot].minSize,slotPtr[slot].pad,
774 slotPtr[slot].weight);
775 Tcl_SetResult(interp, buf, TCL_VOLATILE);
776 return (TCL_OK);
777 } else if (argc == 4) {
778 Tcl_SetResult(interp, "-minsize 0 -pad 0 -weight 0",
779 TCL_STATIC);
780 return (TCL_OK);
781 }
782
783 /*
784 * Loop through each option value pair, setting the values as required.
785 * If only one option is given, with no value, the current value is
786 * returned.
787 */
788
789 for (i=4; i<argc; i+=2) {
790 length = strlen(argv[i]);
791 if ((*argv[i] != '-') || length < 2) {
792 Tcl_AppendResult(interp, "invalid arg \"",
793 argv[i], "\" :expecting -minsize, -pad, or -weight.",
794 (char *) NULL);
795 Tcl_Free((char *)argvPtr);
796 return TCL_ERROR;
797 }
798 if (strncmp(argv[i], "-minsize", length) == 0) {
799 if (argc == 5) {
800 char buf[TCL_INTEGER_SPACE];
801 int value;
802
803 value = (ok == TCL_OK) ? slotPtr[slot].minSize : 0;
804 sprintf(buf, "%d", value);
805 Tcl_SetResult(interp, buf, TCL_VOLATILE);
806 } else if (Tk_GetPixels(interp, master, argv[i+1], &size)
807 != TCL_OK) {
808 Tcl_Free((char *)argvPtr);
809 return TCL_ERROR;
810 } else {
811 slotPtr[slot].minSize = size;
812 }
813 }
814 else if (strncmp(argv[i], "-weight", length) == 0) {
815 int wt;
816 if (argc == 5) {
817 char buf[TCL_INTEGER_SPACE];
818 int value;
819
820 value = (ok == TCL_OK) ? slotPtr[slot].weight : 0;
821 sprintf(buf, "%d", value);
822 Tcl_SetResult(interp, buf, TCL_VOLATILE);
823 } else if (Tcl_GetInt(interp, argv[i+1], &wt) != TCL_OK) {
824 Tcl_Free((char *)argvPtr);
825 return TCL_ERROR;
826 } else if (wt < 0) {
827 Tcl_AppendResult(interp, "invalid arg \"", argv[i],
828 "\": should be non-negative", (char *) NULL);
829 Tcl_Free((char *)argvPtr);
830 return TCL_ERROR;
831 } else {
832 slotPtr[slot].weight = wt;
833 }
834 }
835 else if (strncmp(argv[i], "-pad", length) == 0) {
836 if (argc == 5) {
837 char buf[TCL_INTEGER_SPACE];
838 int value;
839
840 value = (ok == TCL_OK) ? slotPtr[slot].pad : 0;
841 sprintf(buf, "%d", value);
842 Tcl_SetResult(interp, buf, TCL_VOLATILE);
843 } else if (Tk_GetPixels(interp, master, argv[i+1], &size)
844 != TCL_OK) {
845 Tcl_Free((char *)argvPtr);
846 return TCL_ERROR;
847 } else if (size < 0) {
848 Tcl_AppendResult(interp, "invalid arg \"", argv[i],
849 "\": should be non-negative", (char *) NULL);
850 Tcl_Free((char *)argvPtr);
851 return TCL_ERROR;
852 } else {
853 slotPtr[slot].pad = size;
854 }
855 } else {
856 Tcl_AppendResult(interp, "invalid arg \"",
857 argv[i], "\": expecting -minsize, -pad, or -weight.",
858 (char *) NULL);
859 Tcl_Free((char *)argvPtr);
860 return TCL_ERROR;
861 }
862 }
863 }
864 Tcl_Free((char *)argvPtr);
865
866 /*
867 * If we changed a property, re-arrange the table,
868 * and check for constraint shrinkage.
869 */
870
871 if (argc != 5) {
872 if (slotType == ROW) {
873 int last = masterPtr->masterDataPtr->rowMax - 1;
874 while ((last >= 0) && (slotPtr[last].weight == 0)
875 && (slotPtr[last].pad == 0)
876 && (slotPtr[last].minSize == 0)) {
877 last--;
878 }
879 masterPtr->masterDataPtr->rowMax = last+1;
880 } else {
881 int last = masterPtr->masterDataPtr->columnMax - 1;
882 while ((last >= 0) && (slotPtr[last].weight == 0)
883 && (slotPtr[last].pad == 0)
884 && (slotPtr[last].minSize == 0)) {
885 last--;
886 }
887 masterPtr->masterDataPtr->columnMax = last + 1;
888 }
889
890 if (masterPtr->abortPtr != NULL) {
891 *masterPtr->abortPtr = 1;
892 }
893 if (!(masterPtr->flags & REQUESTED_RELAYOUT)) {
894 masterPtr->flags |= REQUESTED_RELAYOUT;
895 Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);
896 }
897 }
898 } else {
899 Tcl_AppendResult(interp, "bad option \"", argv[1],
900 "\": must be bbox, columnconfigure, configure, forget, info, ",
901 "location, propagate, remove, rowconfigure, size, or slaves.",
902 (char *) NULL);
903 return TCL_ERROR;
904 }
905 return TCL_OK;
906 }
907
908 /*
909 *--------------------------------------------------------------
910 *
911 * GridReqProc --
912 *
913 * This procedure is invoked by Tk_GeometryRequest for
914 * windows managed by the grid.
915 *
916 * Results:
917 * None.
918 *
919 * Side effects:
920 * Arranges for tkwin, and all its managed siblings, to
921 * be re-arranged at the next idle point.
922 *
923 *--------------------------------------------------------------
924 */
925
926 static void
927 GridReqProc(clientData, tkwin)
928 ClientData clientData; /* Grid's information about
929 * window that got new preferred
930 * geometry. */
931 Tk_Window tkwin; /* Other Tk-related information
932 * about the window. */
933 {
934 register Gridder *gridPtr = (Gridder *) clientData;
935
936 gridPtr = gridPtr->masterPtr;
937 if (!(gridPtr->flags & REQUESTED_RELAYOUT)) {
938 gridPtr->flags |= REQUESTED_RELAYOUT;
939 Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr);
940 }
941 }
942
943 /*
944 *--------------------------------------------------------------
945 *
946 * GridLostSlaveProc --
947 *
948 * This procedure is invoked by Tk whenever some other geometry
949 * claims control over a slave that used to be managed by us.
950 *
951 * Results:
952 * None.
953 *
954 * Side effects:
955 * Forgets all grid-related information about the slave.
956 *
957 *--------------------------------------------------------------
958 */
959
960 static void
961 GridLostSlaveProc(clientData, tkwin)
962 ClientData clientData; /* Grid structure for slave window that
963 * was stolen away. */
964 Tk_Window tkwin; /* Tk's handle for the slave window. */
965 {
966 register Gridder *slavePtr = (Gridder *) clientData;
967
968 if (slavePtr->masterPtr->tkwin != Tk_Parent(slavePtr->tkwin)) {
969 Tk_UnmaintainGeometry(slavePtr->tkwin, slavePtr->masterPtr->tkwin);
970 }
971 Unlink(slavePtr);
972 Tk_UnmapWindow(slavePtr->tkwin);
973 }
974
975 /*
976 *--------------------------------------------------------------
977 *
978 * AdjustOffsets --
979 *
980 * This procedure adjusts the size of the layout to fit in the
981 * space provided. If it needs more space, the extra is added
982 * according to the weights. If it needs less, the space is removed
983 * according to the weights, but at no time does the size drop below
984 * the minsize specified for that slot.
985 *
986 * Results:
987 * The initial offset of the layout,
988 * if all the weights are zero, else 0.
989 *
990 * Side effects:
991 * The slot offsets are modified to shrink the layout.
992 *
993 *--------------------------------------------------------------
994 */
995
996 static int
997 AdjustOffsets(size, slots, slotPtr)
998 int size; /* The total layout size (in pixels). */
999 int slots; /* Number of slots. */
1000 register SlotInfo *slotPtr; /* Pointer to slot array. */
1001 {
1002 register int slot; /* Current slot. */
1003 int diff; /* Extra pixels needed to add to the layout. */
1004 int totalWeight = 0; /* Sum of the weights for all the slots. */
1005 int weight = 0; /* Sum of the weights so far. */
1006 int minSize = 0; /* Minimum possible layout size. */
1007 int newDiff; /* The most pixels that can be added on
1008 * the current pass. */
1009
1010 diff = size - slotPtr[slots-1].offset;
1011
1012 /*
1013 * The layout is already the correct size; all done.
1014 */
1015
1016 if (diff == 0) {
1017 return(0);
1018 }
1019
1020 /*
1021 * If all the weights are zero, center the layout in its parent if
1022 * there is extra space, else clip on the bottom/right.
1023 */
1024
1025 for (slot=0; slot < slots; slot++) {
1026 totalWeight += slotPtr[slot].weight;
1027 }
1028
1029 if (totalWeight == 0 ) {
1030 return(diff > 0 ? diff/2 : 0);
1031 }
1032
1033 /*
1034 * Add extra space according to the slot weights. This is done
1035 * cumulatively to prevent round-off error accumulation.
1036 */
1037
1038 if (diff > 0) {
1039 for (weight=slot=0; slot < slots; slot++) {
1040 weight += slotPtr[slot].weight;
1041 slotPtr[slot].offset += diff * weight / totalWeight;
1042 }
1043 return(0);
1044 }
1045
1046 /*
1047 * The layout must shrink below its requested size. Compute the
1048 * minimum possible size by looking at the slot minSizes.
1049 */
1050
1051 for (slot=0; slot < slots; slot++) {
1052 if (slotPtr[slot].weight > 0) {
1053 minSize += slotPtr[slot].minSize;
1054 } else if (slot > 0) {
1055 minSize += slotPtr[slot].offset - slotPtr[slot-1].offset;
1056 } else {
1057 minSize += slotPtr[slot].offset;
1058 }
1059 }
1060
1061 /*
1062 * If the requested size is less than the minimum required size,
1063 * set the slot sizes to their minimum values, then clip on the
1064 * bottom/right.
1065 */
1066
1067 if (size <= minSize) {
1068 int offset = 0;
1069 for (slot=0; slot < slots; slot++) {
1070 if (slotPtr[slot].weight > 0) {
1071 offset += slotPtr[slot].minSize;
1072 } else if (slot > 0) {
1073 offset += slotPtr[slot].offset - slotPtr[slot-1].offset;
1074 } else {
1075 offset += slotPtr[slot].offset;
1076 }
1077 slotPtr[slot].offset = offset;
1078 }
1079 return(0);
1080 }
1081
1082 /*
1083 * Remove space from slots according to their weights. The weights
1084 * get renormalized anytime a slot shrinks to its minimum size.
1085 */
1086
1087 while (diff < 0) {
1088
1089 /*
1090 * Find the total weight for the shrinkable slots.
1091 */
1092
1093 for (totalWeight=slot=0; slot < slots; slot++) {
1094 int current = (slot == 0) ? slotPtr[slot].offset :
1095 slotPtr[slot].offset - slotPtr[slot-1].offset;
1096 if (current > slotPtr[slot].minSize) {
1097 totalWeight += slotPtr[slot].weight;
1098 slotPtr[slot].temp = slotPtr[slot].weight;
1099 } else {
1100 slotPtr[slot].temp = 0;
1101 }
1102 }
1103 if (totalWeight == 0) {
1104 break;
1105 }
1106
1107 /*
1108 * Find the maximum amount of space we can distribute this pass.
1109 */
1110
1111 newDiff = diff;
1112 for (slot = 0; slot < slots; slot++) {
1113 int current; /* current size of this slot */
1114 int maxDiff; /* max diff that would cause
1115 * this slot to equal its minsize */
1116 if (slotPtr[slot].temp == 0) {
1117 continue;
1118 }
1119 current = (slot == 0) ? slotPtr[slot].offset :
1120 slotPtr[slot].offset - slotPtr[slot-1].offset;
1121 maxDiff = totalWeight * (slotPtr[slot].minSize - current)
1122 / slotPtr[slot].temp;
1123 if (maxDiff > newDiff) {
1124 newDiff = maxDiff;
1125 }
1126 }
1127
1128 /*
1129 * Now distribute the space.
1130 */
1131
1132 for (weight=slot=0; slot < slots; slot++) {
1133 weight += slotPtr[slot].temp;
1134 slotPtr[slot].offset += newDiff * weight / totalWeight;
1135 }
1136 diff -= newDiff;
1137 }
1138 return(0);
1139 }
1140
1141 /*
1142 *--------------------------------------------------------------
1143 *
1144 * AdjustForSticky --
1145 *
1146 * This procedure adjusts the size of a slave in its cavity based
1147 * on its "sticky" flags.
1148 *
1149 * Results:
1150 * The input x, y, width, and height are changed to represent the
1151 * desired coordinates of the slave.
1152 *
1153 * Side effects:
1154 * None.
1155 *
1156 *--------------------------------------------------------------
1157 */
1158
1159 static void
1160 AdjustForSticky(slavePtr, xPtr, yPtr, widthPtr, heightPtr)
1161 Gridder *slavePtr; /* Slave window to arrange in its cavity. */
1162 int *xPtr; /* Pixel location of the left edge of the cavity. */
1163 int *yPtr; /* Pixel location of the top edge of the cavity. */
1164 int *widthPtr; /* Width of the cavity (in pixels). */
1165 int *heightPtr; /* Height of the cavity (in pixels). */
1166 {
1167 int diffx=0; /* Cavity width - slave width. */
1168 int diffy=0; /* Cavity hight - slave height. */
1169 int sticky = slavePtr->sticky;
1170
1171 *xPtr += slavePtr->padX/2;
1172 *widthPtr -= slavePtr->padX;
1173 *yPtr += slavePtr->padY/2;
1174 *heightPtr -= slavePtr->padY;
1175
1176 if (*widthPtr > (Tk_ReqWidth(slavePtr->tkwin) + slavePtr->iPadX)) {
1177 diffx = *widthPtr - (Tk_ReqWidth(slavePtr->tkwin) + slavePtr->iPadX);
1178 *widthPtr = Tk_ReqWidth(slavePtr->tkwin) + slavePtr->iPadX;
1179 }
1180
1181 if (*heightPtr > (Tk_ReqHeight(slavePtr->tkwin) + slavePtr->iPadY)) {
1182 diffy = *heightPtr - (Tk_ReqHeight(slavePtr->tkwin) + slavePtr->iPadY);
1183 *heightPtr = Tk_ReqHeight(slavePtr->tkwin) + slavePtr->iPadY;
1184 }
1185
1186 if (sticky&STICK_EAST && sticky&STICK_WEST) {
1187 *widthPtr += diffx;
1188 }
1189 if (sticky&STICK_NORTH && sticky&STICK_SOUTH) {
1190 *heightPtr += diffy;
1191 }
1192 if (!(sticky&STICK_WEST)) {
1193 *xPtr += (sticky&STICK_EAST) ? diffx : diffx/2;
1194 }
1195 if (!(sticky&STICK_NORTH)) {
1196 *yPtr += (sticky&STICK_SOUTH) ? diffy : diffy/2;
1197 }
1198 }
1199
1200 /*
1201 *--------------------------------------------------------------
1202 *
1203 * ArrangeGrid --
1204 *
1205 * This procedure is invoked (using the Tcl_DoWhenIdle
1206 * mechanism) to re-layout a set of windows managed by
1207 * the grid. It is invoked at idle time so that a
1208 * series of grid requests can be merged into a single
1209 * layout operation.
1210 *
1211 * Results:
1212 * None.
1213 *
1214 * Side effects:
1215 * The slaves of masterPtr may get resized or moved.
1216 *
1217 *--------------------------------------------------------------
1218 */
1219
1220 static void
1221 ArrangeGrid(clientData)
1222 ClientData clientData; /* Structure describing parent whose slaves
1223 * are to be re-layed out. */
1224 {
1225 register Gridder *masterPtr = (Gridder *) clientData;
1226 register Gridder *slavePtr;
1227 GridMaster *slotPtr = masterPtr->masterDataPtr;
1228 int abort;
1229 int width, height; /* requested size of layout, in pixels */
1230 int realWidth, realHeight; /* actual size layout should take-up */
1231
1232 masterPtr->flags &= ~REQUESTED_RELAYOUT;
1233
1234 /*
1235 * If the parent has no slaves anymore, then don't do anything
1236 * at all: just leave the parent's size as-is. Otherwise there is
1237 * no way to "relinquish" control over the parent so another geometry
1238 * manager can take over.
1239 */
1240
1241 if (masterPtr->slavePtr == NULL) {
1242 return;
1243 }
1244
1245 if (masterPtr->masterDataPtr == NULL) {
1246 return;
1247 }
1248
1249 /*
1250 * Abort any nested call to ArrangeGrid for this window, since
1251 * we'll do everything necessary here, and set up so this call
1252 * can be aborted if necessary.
1253 */
1254
1255 if (masterPtr->abortPtr != NULL) {
1256 *masterPtr->abortPtr = 1;
1257 }
1258 masterPtr->abortPtr = &abort;
1259 abort = 0;
1260 Tcl_Preserve((ClientData) masterPtr);
1261
1262 /*
1263 * Call the constraint engine to fill in the row and column offsets.
1264 */
1265
1266 SetGridSize(masterPtr);
1267 width = ResolveConstraints(masterPtr, COLUMN, 0);
1268 height = ResolveConstraints(masterPtr, ROW, 0);
1269 width += 2*Tk_InternalBorderWidth(masterPtr->tkwin);
1270 height += 2*Tk_InternalBorderWidth(masterPtr->tkwin);
1271
1272 if (((width != Tk_ReqWidth(masterPtr->tkwin))
1273 || (height != Tk_ReqHeight(masterPtr->tkwin)))
1274 && !(masterPtr->flags & DONT_PROPAGATE)) {
1275 Tk_GeometryRequest(masterPtr->tkwin, width, height);
1276 if (width>1 && height>1) {
1277 masterPtr->flags |= REQUESTED_RELAYOUT;
1278 Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);
1279 }
1280 masterPtr->abortPtr = NULL;
1281 Tcl_Release((ClientData) masterPtr);
1282 return;
1283 }
1284
1285 /*
1286 * If the currently requested layout size doesn't match the parent's
1287 * window size, then adjust the slot offsets according to the
1288 * weights. If all of the weights are zero, center the layout in
1289 * its parent. I haven't decided what to do if the parent is smaller
1290 * than the requested size.
1291 */
1292
1293 realWidth = Tk_Width(masterPtr->tkwin) -
1294 2*Tk_InternalBorderWidth(masterPtr->tkwin);
1295 realHeight = Tk_Height(masterPtr->tkwin) -
1296 2*Tk_InternalBorderWidth(masterPtr->tkwin);
1297 slotPtr->startX = AdjustOffsets(realWidth,
1298 MAX(slotPtr->columnEnd,slotPtr->columnMax), slotPtr->columnPtr);
1299 slotPtr->startY = AdjustOffsets(realHeight,
1300 MAX(slotPtr->rowEnd,slotPtr->rowMax), slotPtr->rowPtr);
1301 slotPtr->startX += Tk_InternalBorderWidth(masterPtr->tkwin);
1302 slotPtr->startY += Tk_InternalBorderWidth(masterPtr->tkwin);
1303
1304 /*
1305 * Now adjust the actual size of the slave to its cavity by
1306 * computing the cavity size, and adjusting the widget according
1307 * to its stickyness.
1308 */
1309
1310 for (slavePtr = masterPtr->slavePtr; slavePtr != NULL && !abort;
1311 slavePtr = slavePtr->nextPtr) {
1312 int x, y; /* top left coordinate */
1313 int width, height; /* slot or slave size */
1314 int col = slavePtr->column;
1315 int row = slavePtr->row;
1316
1317 x = (col>0) ? slotPtr->columnPtr[col-1].offset : 0;
1318 y = (row>0) ? slotPtr->rowPtr[row-1].offset : 0;
1319
1320 width = slotPtr->columnPtr[slavePtr->numCols+col-1].offset - x;
1321 height = slotPtr->rowPtr[slavePtr->numRows+row-1].offset - y;
1322
1323 x += slotPtr->startX;
1324 y += slotPtr->startY;
1325
1326 AdjustForSticky(slavePtr, &x, &y, &width, &height);
1327
1328 /*
1329 * Now put the window in the proper spot. (This was taken directly
1330 * from tkPack.c.) If the slave is a child of the master, then
1331 * do this here. Otherwise let Tk_MaintainGeometry do the work.
1332 */
1333
1334 if (masterPtr->tkwin == Tk_Parent(slavePtr->tkwin)) {
1335 if ((width <= 0) || (height <= 0)) {
1336 Tk_UnmapWindow(slavePtr->tkwin);
1337 } else {
1338 if ((x != Tk_X(slavePtr->tkwin))
1339 || (y != Tk_Y(slavePtr->tkwin))
1340 || (width != Tk_Width(slavePtr->tkwin))
1341 || (height != Tk_Height(slavePtr->tkwin))) {
1342 Tk_MoveResizeWindow(slavePtr->tkwin, x, y, width, height);
1343 }
1344 if (abort) {
1345 break;
1346 }
1347
1348 /*
1349 * Don't map the slave if the master isn't mapped: wait
1350 * until the master gets mapped later.
1351 */
1352
1353 if (Tk_IsMapped(masterPtr->tkwin)) {
1354 Tk_MapWindow(slavePtr->tkwin);
1355 }
1356 }
1357 } else {
1358 if ((width <= 0) || (height <= 0)) {
1359 Tk_UnmaintainGeometry(slavePtr->tkwin, masterPtr->tkwin);
1360 Tk_UnmapWindow(slavePtr->tkwin);
1361 } else {
1362 Tk_MaintainGeometry(slavePtr->tkwin, masterPtr->tkwin,
1363 x, y, width, height);
1364 }
1365 }
1366 }
1367
1368 masterPtr->abortPtr = NULL;
1369 Tcl_Release((ClientData) masterPtr);
1370 }
1371
1372 /*
1373 *--------------------------------------------------------------
1374 *
1375 * ResolveConstraints --
1376 *
1377 * Resolve all of the column and row boundaries. Most of
1378 * the calculations are identical for rows and columns, so this procedure
1379 * is called twice, once for rows, and again for columns.
1380 *
1381 * Results:
1382 * The offset (in pixels) from the left/top edge of this layout is
1383 * returned.
1384 *
1385 * Side effects:
1386 * The slot offsets are copied into the SlotInfo structure for the
1387 * geometry master.
1388 *
1389 *--------------------------------------------------------------
1390 */
1391
1392 static int
1393 ResolveConstraints(masterPtr, slotType, maxOffset)
1394 Gridder *masterPtr; /* The geometry master for this grid. */
1395 int slotType; /* Either ROW or COLUMN. */
1396 int maxOffset; /* The actual maximum size of this layout
1397 * in pixels, or 0 (not currently used). */
1398 {
1399 register SlotInfo *slotPtr; /* Pointer to row/col constraints. */
1400 register Gridder *slavePtr; /* List of slave windows in this grid. */
1401 int constraintCount; /* Count of rows or columns that have
1402 * constraints. */
1403 int slotCount; /* Last occupied row or column. */
1404 int gridCount; /* The larger of slotCount and constraintCount.
1405 */
1406 GridLayout *layoutPtr; /* Temporary layout structure. */
1407 int requiredSize; /* The natural size of the grid (pixels).
1408 * This is the minimum size needed to
1409 * accomodate all of the slaves at their
1410 * requested sizes. */
1411 int offset; /* The pixel offset of the right edge of the
1412 * current slot from the beginning of the
1413 * layout. */
1414 int slot; /* The current slot. */
1415 int start; /* The first slot of a contiguous set whose
1416 * constraints are not yet fully resolved. */
1417 int end; /* The Last slot of a contiguous set whose
1418 * constraints are not yet fully resolved. */
1419
1420 /*
1421 * For typical sized tables, we'll use stack space for the layout data
1422 * to avoid the overhead of a malloc and free for every layout.
1423 */
1424
1425 GridLayout layoutData[TYPICAL_SIZE + 1];
1426
1427 if (slotType == COLUMN) {
1428 constraintCount = masterPtr->masterDataPtr->columnMax;
1429 slotCount = masterPtr->masterDataPtr->columnEnd;
1430 slotPtr = masterPtr->masterDataPtr->columnPtr;
1431 } else {
1432 constraintCount = masterPtr->masterDataPtr->rowMax;
1433 slotCount = masterPtr->masterDataPtr->rowEnd;
1434 slotPtr = masterPtr->masterDataPtr->rowPtr;
1435 }
1436
1437 /*
1438 * Make sure there is enough memory for the layout.
1439 */
1440
1441 gridCount = MAX(constraintCount,slotCount);
1442 if (gridCount >= TYPICAL_SIZE) {
1443 layoutPtr = (GridLayout *) ckalloc(sizeof(GridLayout) * (1+gridCount));
1444 } else {
1445 layoutPtr = layoutData;
1446 }
1447
1448 /*
1449 * Allocate an extra layout slot to represent the left/top edge of
1450 * the 0th slot to make it easier to calculate slot widths from
1451 * offsets without special case code.
1452 * Initialize the "dummy" slot to the left/top of the table.
1453 * This slot avoids special casing the first slot.
1454 */
1455
1456 layoutPtr->minOffset = 0;
1457 layoutPtr->maxOffset = 0;
1458 layoutPtr++;
1459
1460 /*
1461 * Step 1.
1462 * Copy the slot constraints into the layout structure,
1463 * and initialize the rest of the fields.
1464 */
1465
1466 for (slot=0; slot < constraintCount; slot++) {
1467 layoutPtr[slot].minSize = slotPtr[slot].minSize;
1468 layoutPtr[slot].weight = slotPtr[slot].weight;
1469 layoutPtr[slot].pad = slotPtr[slot].pad;
1470 layoutPtr[slot].binNextPtr = NULL;
1471 }
1472 for(;slot<gridCount;slot++) {
1473 layoutPtr[slot].minSize = 0;
1474 layoutPtr[slot].weight = 0;
1475 layoutPtr[slot].pad = 0;
1476 layoutPtr[slot].binNextPtr = NULL;
1477 }
1478
1479 /*
1480 * Step 2.
1481 * Slaves with a span of 1 are used to determine the minimum size of
1482 * each slot. Slaves whose span is two or more slots don't
1483 * contribute to the minimum size of each slot directly, but can cause
1484 * slots to grow if their size exceeds the the sizes of the slots they
1485 * span.
1486 *
1487 * Bin all slaves whose spans are > 1 by their right edges. This
1488 * allows the computation on minimum and maximum possible layout
1489 * sizes at each slot boundary, without the need to re-sort the slaves.
1490 */
1491
1492 switch (slotType) {
1493 case COLUMN:
1494 for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
1495 slavePtr = slavePtr->nextPtr) {
1496 int rightEdge = slavePtr->column + slavePtr->numCols - 1;
1497 slavePtr->size = Tk_ReqWidth(slavePtr->tkwin) +
1498 slavePtr->padX + slavePtr->iPadX + slavePtr->doubleBw;
1499 if (slavePtr->numCols > 1) {
1500 slavePtr->binNextPtr = layoutPtr[rightEdge].binNextPtr;
1501 layoutPtr[rightEdge].binNextPtr = slavePtr;
1502 } else {
1503 int size = slavePtr->size + layoutPtr[rightEdge].pad;
1504 if (size > layoutPtr[rightEdge].minSize) {
1505 layoutPtr[rightEdge].minSize = size;
1506 }
1507 }
1508 }
1509 break;
1510 case ROW:
1511 for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
1512 slavePtr = slavePtr->nextPtr) {
1513 int rightEdge = slavePtr->row + slavePtr->numRows - 1;
1514 slavePtr->size = Tk_ReqHeight(slavePtr->tkwin) +
1515 slavePtr->padY + slavePtr->iPadY + slavePtr->doubleBw;
1516 if (slavePtr->numRows > 1) {
1517 slavePtr->binNextPtr = layoutPtr[rightEdge].binNextPtr;
1518 layoutPtr[rightEdge].binNextPtr = slavePtr;
1519 } else {
1520 int size = slavePtr->size + layoutPtr[rightEdge].pad;
1521 if (size > layoutPtr[rightEdge].minSize) {
1522 layoutPtr[rightEdge].minSize = size;
1523 }
1524 }
1525 }
1526 break;
1527 }
1528
1529 /*
1530 * Step 3.
1531 * Determine the minimum slot offsets going from left to right
1532 * that would fit all of the slaves. This determines the minimum
1533 */
1534
1535 for (offset=slot=0; slot < gridCount; slot++) {
1536 layoutPtr[slot].minOffset = layoutPtr[slot].minSize + offset;
1537 for (slavePtr = layoutPtr[slot].binNextPtr; slavePtr != NULL;
1538 slavePtr = slavePtr->binNextPtr) {
1539 int span = (slotType == COLUMN) ? slavePtr->numCols : slavePtr->numRows;
1540 int required = slavePtr->size + layoutPtr[slot - span].minOffset;
1541 if (required > layoutPtr[slot].minOffset) {
1542 layoutPtr[slot].minOffset = required;
1543 }
1544 }
1545 offset = layoutPtr[slot].minOffset;
1546 }
1547
1548 /*
1549 * At this point, we know the minimum required size of the entire layout.
1550 * It might be prudent to stop here if our "master" will resize itself
1551 * to this size.
1552 */
1553
1554 requiredSize = offset;
1555 if (maxOffset > offset) {
1556 offset=maxOffset;
1557 }
1558
1559 /*
1560 * Step 4.
1561 * Determine the minimum slot offsets going from right to left,
1562 * bounding the pixel range of each slot boundary.
1563 * Pre-fill all of the right offsets with the actual size of the table;
1564 * they will be reduced as required.
1565 */
1566
1567 for (slot=0; slot < gridCount; slot++) {
1568 layoutPtr[slot].maxOffset = offset;
1569 }
1570 for (slot=gridCount-1; slot > 0;) {
1571 for (slavePtr = layoutPtr[slot].binNextPtr; slavePtr != NULL;
1572 slavePtr = slavePtr->binNextPtr) {
1573 int span = (slotType == COLUMN) ? slavePtr->numCols : slavePtr->numRows;
1574 int require = offset - slavePtr->size;
1575 int startSlot = slot - span;
1576 if (startSlot >=0 && require < layoutPtr[startSlot].maxOffset) {
1577 layoutPtr[startSlot].maxOffset = require;
1578 }
1579 }
1580 offset -= layoutPtr[slot].minSize;
1581 slot--;
1582 if (layoutPtr[slot].maxOffset < offset) {
1583 offset = layoutPtr[slot].maxOffset;
1584 } else {
1585 layoutPtr[slot].maxOffset = offset;
1586 }
1587 }
1588
1589 /*
1590 * Step 5.
1591 * At this point, each slot boundary has a range of values that
1592 * will satisfy the overall layout size.
1593 * Make repeated passes over the layout structure looking for
1594 * spans of slot boundaries where the minOffsets are less than
1595 * the maxOffsets, and adjust the offsets according to the slot
1596 * weights. At each pass, at least one slot boundary will have
1597 * its range of possible values fixed at a single value.
1598 */
1599
1600 for (start=0; start < gridCount;) {
1601 int totalWeight = 0; /* Sum of the weights for all of the
1602 * slots in this span. */
1603 int need = 0; /* The minimum space needed to layout
1604 * this span. */
1605 int have; /* The actual amount of space that will
1606 * be taken up by this span. */
1607 int weight; /* Cumulative weights of the columns in
1608 * this span. */
1609 int noWeights = 0; /* True if the span has no weights. */
1610
1611 /*
1612 * Find a span by identifying ranges of slots whose edges are
1613 * already constrained at fixed offsets, but whose internal
1614 * slot boundaries have a range of possible positions.
1615 */
1616
1617 if (layoutPtr[start].minOffset == layoutPtr[start].maxOffset) {
1618 start++;
1619 continue;
1620 }
1621
1622 for (end=start+1; end<gridCount; end++) {
1623 if (layoutPtr[end].minOffset == layoutPtr[end].maxOffset) {
1624 break;
1625 }
1626 }
1627
1628 /*
1629 * We found a span. Compute the total weight, minumum space required,
1630 * for this span, and the actual amount of space the span should
1631 * use.
1632 */
1633
1634 for (slot=start; slot<=end; slot++) {
1635 totalWeight += layoutPtr[slot].weight;
1636 need += layoutPtr[slot].minSize;
1637 }
1638 have = layoutPtr[end].maxOffset - layoutPtr[start-1].minOffset;
1639
1640 /*
1641 * If all the weights in the span are zero, then distribute the
1642 * extra space evenly.
1643 */
1644
1645 if (totalWeight == 0) {
1646 noWeights++;
1647 totalWeight = end - start + 1;
1648 }
1649
1650 /*
1651 * It might not be possible to give the span all of the space
1652 * available on this pass without violating the size constraints
1653 * of one or more of the internal slot boundaries.
1654 * Determine the maximum amount of space that when added to the
1655 * entire span, would cause a slot boundary to have its possible
1656 * range reduced to one value, and reduce the amount of extra
1657 * space allocated on this pass accordingly.
1658 *
1659 * The calculation is done cumulatively to avoid accumulating
1660 * roundoff errors.
1661 */
1662
1663 for (weight=0,slot=start; slot<end; slot++) {
1664 int diff = layoutPtr[slot].maxOffset - layoutPtr[slot].minOffset;
1665 weight += noWeights ? 1 : layoutPtr[slot].weight;
1666 if ((noWeights || layoutPtr[slot].weight>0) &&
1667 (diff*totalWeight/weight) < (have-need)) {
1668 have = diff * totalWeight / weight + need;
1669 }
1670 }
1671
1672 /*
1673 * Now distribute the extra space among the slots by
1674 * adjusting the minSizes and minOffsets.
1675 */
1676
1677 for (weight=0,slot=start; slot<end; slot++) {
1678 weight += noWeights ? 1 : layoutPtr[slot].weight;
1679 layoutPtr[slot].minOffset +=
1680 (int)((double) (have-need) * weight/totalWeight + 0.5);
1681 layoutPtr[slot].minSize = layoutPtr[slot].minOffset
1682 - layoutPtr[slot-1].minOffset;
1683 }
1684 layoutPtr[slot].minSize = layoutPtr[slot].minOffset
1685 - layoutPtr[slot-1].minOffset;
1686
1687 /*
1688 * Having pushed the top/left boundaries of the slots to
1689 * take up extra space, the bottom/right space is recalculated
1690 * to propagate the new space allocation.
1691 */
1692
1693 for (slot=end; slot > start; slot--) {
1694 layoutPtr[slot-1].maxOffset =
1695 layoutPtr[slot].maxOffset-layoutPtr[slot].minSize;
1696 }
1697 }
1698
1699
1700 /*
1701 * Step 6.
1702 * All of the space has been apportioned; copy the
1703 * layout information back into the master.
1704 */
1705
1706 for (slot=0; slot < gridCount; slot++) {
1707 slotPtr[slot].offset = layoutPtr[slot].minOffset;
1708 }
1709
1710 --layoutPtr;
1711 if (layoutPtr != layoutData) {
1712 Tcl_Free((char *)layoutPtr);
1713 }
1714 return requiredSize;
1715 }
1716
1717 /*
1718 *--------------------------------------------------------------
1719 *
1720 * GetGrid --
1721 *
1722 * This internal procedure is used to locate a Grid
1723 * structure for a given window, creating one if one
1724 * doesn't exist already.
1725 *
1726 * Results:
1727 * The return value is a pointer to the Grid structure
1728 * corresponding to tkwin.
1729 *
1730 * Side effects:
1731 * A new grid structure may be created. If so, then
1732 * a callback is set up to clean things up when the
1733 * window is deleted.
1734 *
1735 *--------------------------------------------------------------
1736 */
1737
1738 static Gridder *
1739 GetGrid(tkwin)
1740 Tk_Window tkwin; /* Token for window for which
1741 * grid structure is desired. */
1742 {
1743 register Gridder *gridPtr;
1744 Tcl_HashEntry *hPtr;
1745 int new;
1746 TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
1747
1748 if (!dispPtr->gridInit) {
1749 Tcl_InitHashTable(&dispPtr->gridHashTable, TCL_ONE_WORD_KEYS);
1750 dispPtr->gridInit = 1;
1751 }
1752
1753 /*
1754 * See if there's already grid for this window. If not,
1755 * then create a new one.
1756 */
1757
1758 hPtr = Tcl_CreateHashEntry(&dispPtr->gridHashTable, (char *) tkwin, &new);
1759 if (!new) {
1760 return (Gridder *) Tcl_GetHashValue(hPtr);
1761 }
1762 gridPtr = (Gridder *) ckalloc(sizeof(Gridder));
1763 gridPtr->tkwin = tkwin;
1764 gridPtr->masterPtr = NULL;
1765 gridPtr->masterDataPtr = NULL;
1766 gridPtr->nextPtr = NULL;
1767 gridPtr->slavePtr = NULL;
1768 gridPtr->binNextPtr = NULL;
1769
1770 gridPtr->column = gridPtr->row = -1;
1771 gridPtr->numCols = 1;
1772 gridPtr->numRows = 1;
1773
1774 gridPtr->padX = gridPtr->padY = 0;
1775 gridPtr->iPadX = gridPtr->iPadY = 0;
1776 gridPtr->doubleBw = 2*Tk_Changes(tkwin)->border_width;
1777 gridPtr->abortPtr = NULL;
1778 gridPtr->flags = 0;
1779 gridPtr->sticky = 0;
1780 gridPtr->size = 0;
1781 gridPtr->masterDataPtr = NULL;
1782 Tcl_SetHashValue(hPtr, gridPtr);
1783 Tk_CreateEventHandler(tkwin, StructureNotifyMask,
1784 GridStructureProc, (ClientData) gridPtr);
1785 return gridPtr;
1786 }
1787
1788 /*
1789 *--------------------------------------------------------------
1790 *
1791 * SetGridSize --
1792 *
1793 * This internal procedure sets the size of the grid occupied
1794 * by slaves.
1795 *
1796 * Results:
1797 * none
1798 *
1799 * Side effects:
1800 * The width and height arguments are filled in the master data structure.
1801 * Additional space is allocated for the constraints to accomodate
1802 * the offsets.
1803 *
1804 *--------------------------------------------------------------
1805 */
1806
1807 static void
1808 SetGridSize(masterPtr)
1809 Gridder *masterPtr; /* The geometry master for this grid. */
1810 {
1811 register Gridder *slavePtr; /* Current slave window. */
1812 int maxX = 0, maxY = 0;
1813
1814 for (slavePtr = masterPtr->slavePtr; slavePtr != NULL;
1815 slavePtr = slavePtr->nextPtr) {
1816 maxX = MAX(maxX,slavePtr->numCols + slavePtr->column);
1817 maxY = MAX(maxY,slavePtr->numRows + slavePtr->row);
1818 }
1819 masterPtr->masterDataPtr->columnEnd = maxX;
1820 masterPtr->masterDataPtr->rowEnd = maxY;
1821 CheckSlotData(masterPtr, maxX, COLUMN, CHECK_SPACE);
1822 CheckSlotData(masterPtr, maxY, ROW, CHECK_SPACE);
1823 }
1824
1825 /*
1826 *--------------------------------------------------------------
1827 *
1828 * CheckSlotData --
1829 *
1830 * This internal procedure is used to manage the storage for
1831 * row and column (slot) constraints.
1832 *
1833 * Results:
1834 * TRUE if the index is OK, False otherwise.
1835 *
1836 * Side effects:
1837 * A new master grid structure may be created. If so, then
1838 * it is initialized. In addition, additional storage for
1839 * a row or column constraints may be allocated, and the constraint
1840 * maximums are adjusted.
1841 *
1842 *--------------------------------------------------------------
1843 */
1844
1845 static int
1846 CheckSlotData(masterPtr, slot, slotType, checkOnly)
1847 Gridder *masterPtr; /* the geometry master for this grid */
1848 int slot; /* which slot to look at */
1849 int slotType; /* ROW or COLUMN */
1850 int checkOnly; /* don't allocate new space if true */
1851 {
1852 int numSlot; /* number of slots already allocated (Space) */
1853 int end; /* last used constraint */
1854
1855 /*
1856 * If slot is out of bounds, return immediately.
1857 */
1858
1859 if (slot < 0 || slot >= MAX_ELEMENT) {
1860 return TCL_ERROR;
1861 }
1862
1863 if ((checkOnly == CHECK_ONLY) && (masterPtr->masterDataPtr == NULL)) {
1864 return TCL_ERROR;
1865 }
1866
1867 /*
1868 * If we need to allocate more space, allocate a little extra to avoid
1869 * repeated re-alloc's for large tables. We need enough space to
1870 * hold all of the offsets as well.
1871 */
1872
1873 InitMasterData(masterPtr);
1874 end = (slotType == ROW) ? masterPtr->masterDataPtr->rowMax :
1875 masterPtr->masterDataPtr->columnMax;
1876 if (checkOnly == CHECK_ONLY) {
1877 return (end < slot) ? TCL_ERROR : TCL_OK;
1878 } else {
1879 numSlot = (slotType == ROW) ? masterPtr->masterDataPtr->rowSpace
1880 : masterPtr->masterDataPtr->columnSpace;
1881 if (slot >= numSlot) {
1882 int newNumSlot = slot + PREALLOC ;
1883 size_t oldSize = numSlot * sizeof(SlotInfo) ;
1884 size_t newSize = newNumSlot * sizeof(SlotInfo) ;
1885 SlotInfo *new = (SlotInfo *) ckalloc(newSize);
1886 SlotInfo *old = (slotType == ROW) ?
1887 masterPtr->masterDataPtr->rowPtr :
1888 masterPtr->masterDataPtr->columnPtr;
1889 memcpy((VOID *) new, (VOID *) old, oldSize );
1890 memset((VOID *) (new+numSlot), 0, newSize - oldSize );
1891 Tcl_Free((char *) old);
1892 if (slotType == ROW) {
1893 masterPtr->masterDataPtr->rowPtr = new ;
1894 masterPtr->masterDataPtr->rowSpace = newNumSlot ;
1895 } else {
1896 masterPtr->masterDataPtr->columnPtr = new;
1897 masterPtr->masterDataPtr->columnSpace = newNumSlot ;
1898 }
1899 }
1900 if (slot >= end && checkOnly != CHECK_SPACE) {
1901 if (slotType == ROW) {
1902 masterPtr->masterDataPtr->rowMax = slot+1;
1903 } else {
1904 masterPtr->masterDataPtr->columnMax = slot+1;
1905 }
1906 }
1907 return TCL_OK;
1908 }
1909 }
1910
1911 /*
1912 *--------------------------------------------------------------
1913 *
1914 * InitMasterData --
1915 *
1916 * This internal procedure is used to allocate and initialize
1917 * the data for a geometry master, if the data
1918 * doesn't exist already.
1919 *
1920 * Results:
1921 * none
1922 *
1923 * Side effects:
1924 * A new master grid structure may be created. If so, then
1925 * it is initialized.
1926 *
1927 *--------------------------------------------------------------
1928 */
1929
1930 static void
1931 InitMasterData(masterPtr)
1932 Gridder *masterPtr;
1933 {
1934 size_t size;
1935 if (masterPtr->masterDataPtr == NULL) {
1936 GridMaster *gridPtr = masterPtr->masterDataPtr =
1937 (GridMaster *) ckalloc(sizeof(GridMaster));
1938 size = sizeof(SlotInfo) * TYPICAL_SIZE;
1939
1940 gridPtr->columnEnd = 0;
1941 gridPtr->columnMax = 0;
1942 gridPtr->columnPtr = (SlotInfo *) ckalloc(size);
1943 gridPtr->columnSpace = TYPICAL_SIZE;
1944 gridPtr->rowEnd = 0;
1945 gridPtr->rowMax = 0;
1946 gridPtr->rowPtr = (SlotInfo *) ckalloc(size);
1947 gridPtr->rowSpace = TYPICAL_SIZE;
1948 gridPtr->startX = 0;
1949 gridPtr->startY = 0;
1950
1951 memset((VOID *) gridPtr->columnPtr, 0, size);
1952 memset((VOID *) gridPtr->rowPtr, 0, size);
1953 }
1954 }
1955
1956 /*
1957 *----------------------------------------------------------------------
1958 *
1959 * Unlink --
1960 *
1961 * Remove a grid from its parent's list of slaves.
1962 *
1963 * Results:
1964 * None.
1965 *
1966 * Side effects:
1967 * The parent will be scheduled for re-arranging, and the size of the
1968 * grid will be adjusted accordingly
1969 *
1970 *----------------------------------------------------------------------
1971 */
1972
1973 static void
1974 Unlink(slavePtr)
1975 register Gridder *slavePtr; /* Window to unlink. */
1976 {
1977 register Gridder *masterPtr, *slavePtr2;
1978 GridMaster *gridPtr; /* pointer to grid data */
1979
1980 masterPtr = slavePtr->masterPtr;
1981 if (masterPtr == NULL) {
1982 return;
1983 }
1984
1985 gridPtr = masterPtr->masterDataPtr;
1986 if (masterPtr->slavePtr == slavePtr) {
1987 masterPtr->slavePtr = slavePtr->nextPtr;
1988 }
1989 else {
1990 for (slavePtr2 = masterPtr->slavePtr; ; slavePtr2 = slavePtr2->nextPtr) {
1991 if (slavePtr2 == NULL) {
1992 panic("Unlink couldn't find previous window");
1993 }
1994 if (slavePtr2->nextPtr == slavePtr) {
1995 slavePtr2->nextPtr = slavePtr->nextPtr;
1996 break;
1997 }
1998 }
1999 }
2000 if (!(masterPtr->flags & REQUESTED_RELAYOUT)) {
2001 masterPtr->flags |= REQUESTED_RELAYOUT;
2002 Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);
2003 }
2004 if (masterPtr->abortPtr != NULL) {
2005 *masterPtr->abortPtr = 1;
2006 }
2007
2008 if ((slavePtr->numCols+slavePtr->column == gridPtr->columnMax)
2009 || (slavePtr->numRows+slavePtr->row == gridPtr->rowMax)) {
2010 }
2011 slavePtr->masterPtr = NULL;
2012 }
2013
2014 /*
2015 *----------------------------------------------------------------------
2016 *
2017 * DestroyGrid --
2018 *
2019 * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
2020 * to clean up the internal structure of a grid at a safe time
2021 * (when no-one is using it anymore). Cleaning up the grid involves
2022 * freeing the main structure for all windows. and the master structure
2023 * for geometry managers.
2024 *
2025 * Results:
2026 * None.
2027 *
2028 * Side effects:
2029 * Everything associated with the grid is freed up.
2030 *
2031 *----------------------------------------------------------------------
2032 */
2033
2034 static void
2035 DestroyGrid(memPtr)
2036 char *memPtr; /* Info about window that is now dead. */
2037 {
2038 register Gridder *gridPtr = (Gridder *) memPtr;
2039
2040 if (gridPtr->masterDataPtr != NULL) {
2041 if (gridPtr->masterDataPtr->rowPtr != NULL) {
2042 Tcl_Free((char *) gridPtr->masterDataPtr -> rowPtr);
2043 }
2044 if (gridPtr->masterDataPtr->columnPtr != NULL) {
2045 Tcl_Free((char *) gridPtr->masterDataPtr -> columnPtr);
2046 }
2047 Tcl_Free((char *) gridPtr->masterDataPtr);
2048 }
2049 Tcl_Free((char *) gridPtr);
2050 }
2051
2052 /*
2053 *----------------------------------------------------------------------
2054 *
2055 * GridStructureProc --
2056 *
2057 * This procedure is invoked by the Tk event dispatcher in response
2058 * to StructureNotify events.
2059 *
2060 * Results:
2061 * None.
2062 *
2063 * Side effects:
2064 * If a window was just deleted, clean up all its grid-related
2065 * information. If it was just resized, re-configure its slaves, if
2066 * any.
2067 *
2068 *----------------------------------------------------------------------
2069 */
2070
2071 static void
2072 GridStructureProc(clientData, eventPtr)
2073 ClientData clientData; /* Our information about window
2074 * referred to by eventPtr. */
2075 XEvent *eventPtr; /* Describes what just happened. */
2076 {
2077 register Gridder *gridPtr = (Gridder *) clientData;
2078 TkDisplay *dispPtr = ((TkWindow *) gridPtr->tkwin)->dispPtr;
2079
2080 if (eventPtr->type == ConfigureNotify) {
2081 if (!(gridPtr->flags & REQUESTED_RELAYOUT)) {
2082 gridPtr->flags |= REQUESTED_RELAYOUT;
2083 Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr);
2084 }
2085 if (gridPtr->doubleBw != 2*Tk_Changes(gridPtr->tkwin)->border_width) {
2086 if ((gridPtr->masterPtr != NULL) &&
2087 !(gridPtr->masterPtr->flags & REQUESTED_RELAYOUT)) {
2088 gridPtr->doubleBw = 2*Tk_Changes(gridPtr->tkwin)->border_width;
2089 gridPtr->masterPtr->flags |= REQUESTED_RELAYOUT;
2090 Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr->masterPtr);
2091 }
2092 }
2093 } else if (eventPtr->type == DestroyNotify) {
2094 register Gridder *gridPtr2, *nextPtr;
2095
2096 if (gridPtr->masterPtr != NULL) {
2097 Unlink(gridPtr);
2098 }
2099 for (gridPtr2 = gridPtr->slavePtr; gridPtr2 != NULL;
2100 gridPtr2 = nextPtr) {
2101 Tk_UnmapWindow(gridPtr2->tkwin);
2102 gridPtr2->masterPtr = NULL;
2103 nextPtr = gridPtr2->nextPtr;
2104 gridPtr2->nextPtr = NULL;
2105 }
2106 Tcl_DeleteHashEntry(Tcl_FindHashEntry(&dispPtr->gridHashTable,
2107 (char *) gridPtr->tkwin));
2108 if (gridPtr->flags & REQUESTED_RELAYOUT) {
2109 Tcl_CancelIdleCall(ArrangeGrid, (ClientData) gridPtr);
2110 }
2111 gridPtr->tkwin = NULL;
2112 Tcl_EventuallyFree((ClientData) gridPtr, DestroyGrid);
2113 } else if (eventPtr->type == MapNotify) {
2114 if (!(gridPtr->flags & REQUESTED_RELAYOUT)) {
2115 gridPtr->flags |= REQUESTED_RELAYOUT;
2116 Tcl_DoWhenIdle(ArrangeGrid, (ClientData) gridPtr);
2117 }
2118 } else if (eventPtr->type == UnmapNotify) {
2119 register Gridder *gridPtr2;
2120
2121 for (gridPtr2 = gridPtr->slavePtr; gridPtr2 != NULL;
2122 gridPtr2 = gridPtr2->nextPtr) {
2123 Tk_UnmapWindow(gridPtr2->tkwin);
2124 }
2125 }
2126 }
2127
2128 /*
2129 *----------------------------------------------------------------------
2130 *
2131 * ConfigureSlaves --
2132 *
2133 * This implements the guts of the "grid configure" command. Given
2134 * a list of slaves and configuration options, it arranges for the
2135 * grid to manage the slaves and sets the specified options.
2136 * arguments consist of windows or window shortcuts followed by
2137 * "-option value" pairs.
2138 *
2139 * Results:
2140 * TCL_OK is returned if all went well. Otherwise, TCL_ERROR is
2141 * returned and the interp's result is set to contain an error message.
2142 *
2143 * Side effects:
2144 * Slave windows get taken over by the grid.
2145 *
2146 *----------------------------------------------------------------------
2147 */
2148
2149 static int
2150 ConfigureSlaves(interp, tkwin, argc, argv)
2151 Tcl_Interp *interp; /* Interpreter for error reporting. */
2152 Tk_Window tkwin; /* Any window in application containing
2153 * slaves. Used to look up slave names. */
2154 int argc; /* Number of elements in argv. */
2155 char *argv[]; /* Argument strings: contains one or more
2156 * window names followed by any number
2157 * of "option value" pairs. Caller must
2158 * make sure that there is at least one
2159 * window name. */
2160 {
2161 Gridder *masterPtr;
2162 Gridder *slavePtr;
2163 Tk_Window other, slave, parent, ancestor;
2164 int i, j, c, tmp;
2165 size_t length;
2166 int numWindows;
2167 int width;
2168 int defaultColumn = 0; /* default column number */
2169 int defaultColumnSpan = 1; /* default number of columns */
2170 char *lastWindow; /* use this window to base current
2171 * Row/col on */
2172
2173 /*
2174 * Count the number of windows, or window short-cuts.
2175 */
2176
2177 for(numWindows=i=0;i<argc;i++) {
2178 char firstChar = *argv[i];
2179 if (firstChar == '.') {
2180 numWindows++;
2181 continue;
2182 }
2183 length = strlen(argv[i]);
2184 if (length > 1 && firstChar == '-') {
2185 break;
2186 }
2187 if (length > 1) {
2188 Tcl_AppendResult(interp, "unexpected parameter, \"",
2189 argv[i], "\", in configure list. ",
2190 "Should be window name or option", (char *) NULL);
2191 return TCL_ERROR;
2192 }
2193
2194 if ((firstChar == REL_HORIZ) && ((numWindows == 0) ||
2195 (*argv[i-1] == REL_SKIP) || (*argv[i-1] == REL_VERT))) {
2196 Tcl_AppendResult(interp,
2197 "Must specify window before shortcut '-'.",
2198 (char *) NULL);
2199 return TCL_ERROR;
2200 }
2201
2202 if ((firstChar == REL_VERT) || (firstChar == REL_SKIP)
2203 || (firstChar == REL_HORIZ)) {
2204 continue;
2205 }
2206
2207 Tcl_AppendResult(interp, "invalid window shortcut, \"",
2208 argv[i], "\" should be '-', 'x', or '^'", (char *) NULL);
2209 return TCL_ERROR;
2210 }
2211 numWindows = i;
2212
2213 if ((argc-numWindows)&1) {
2214 Tcl_AppendResult(interp, "extra option or",
2215 " option with no value", (char *) NULL);
2216 return TCL_ERROR;
2217 }
2218
2219 /*
2220 * Iterate over all of the slave windows and short-cuts, parsing
2221 * options for each slave. It's a bit wasteful to re-parse the
2222 * options for each slave, but things get too messy if we try to
2223 * parse the arguments just once at the beginning. For example,
2224 * if a slave already is managed we want to just change a few
2225 * existing values without resetting everything. If there are
2226 * multiple windows, the -in option only gets processed for the
2227 * first window.
2228 */
2229
2230 masterPtr = NULL;
2231 for (j = 0; j < numWindows; j++) {
2232 char firstChar = *argv[j];
2233
2234 /*
2235 * '^' and 'x' cause us to skip a column. '-' is processed
2236 * as part of its preceeding slave.
2237 */
2238
2239 if ((firstChar == REL_VERT) || (firstChar == REL_SKIP)) {
2240 defaultColumn++;
2241 continue;
2242 }
2243 if (firstChar == REL_HORIZ) {
2244 continue;
2245 }
2246
2247 for (defaultColumnSpan=1;
2248 j + defaultColumnSpan < numWindows &&
2249 (*argv[j+defaultColumnSpan] == REL_HORIZ);
2250 defaultColumnSpan++) {
2251 /* null body */
2252 }
2253
2254 slave = Tk_NameToWindow(interp, argv[j], tkwin);
2255 if (slave == NULL) {
2256 return TCL_ERROR;
2257 }
2258 if (Tk_IsTopLevel(slave)) {
2259 Tcl_AppendResult(interp, "can't manage \"", argv[j],
2260 "\": it's a top-level window", (char *) NULL);
2261 return TCL_ERROR;
2262 }
2263 slavePtr = GetGrid(slave);
2264
2265 /*
2266 * The following statement is taken from tkPack.c:
2267 *
2268 * "If the slave isn't currently managed, reset all of its
2269 * configuration information to default values (there could
2270 * be old values left from a previous packer)."
2271 *
2272 * I [D.S.] disagree with this statement. If a slave is disabled (using
2273 * "forget") and then re-enabled, I submit that 90% of the time the
2274 * programmer will want it to retain its old configuration information.
2275 * If the programmer doesn't want this behavior, then the
2276 * defaults can be reestablished by hand, without having to worry
2277 * about keeping track of the old state.
2278 */
2279
2280 for (i = numWindows; i < argc; i+=2) {
2281 length = strlen(argv[i]);
2282 c = argv[i][1];
2283
2284 if (length < 2) {
2285 Tcl_AppendResult(interp, "unknown or ambiguous option \"",
2286 argv[i], "\": must be ",
2287 "-column, -columnspan, -in, -ipadx, -ipady, ",
2288 "-padx, -pady, -row, -rowspan, or -sticky",
2289 (char *) NULL);
2290 return TCL_ERROR;
2291 }
2292 if ((c == 'c') && (strncmp(argv[i], "-column", length) == 0)) {
2293 if (Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK || tmp<0) {
2294 Tcl_ResetResult(interp);
2295 Tcl_AppendResult(interp, "bad column value \"", argv[i+1],
2296 "\": must be a non-negative integer", (char *)NULL);
2297 return TCL_ERROR;
2298 }
2299 slavePtr->column = tmp;
2300 } else if ((c == 'c')
2301 && (strncmp(argv[i], "-columnspan", length) == 0)) {
2302 if (Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK || tmp <= 0) {
2303 Tcl_ResetResult(interp);
2304 Tcl_AppendResult(interp, "bad columnspan value \"", argv[i+1],
2305 "\": must be a positive integer", (char *)NULL);
2306 return TCL_ERROR;
2307 }
2308 slavePtr->numCols = tmp;
2309 } else if ((c == 'i') && (strncmp(argv[i], "-in", length) == 0)) {
2310 other = Tk_NameToWindow(interp, argv[i+1], tkwin);
2311 if (other == NULL) {
2312 return TCL_ERROR;
2313 }
2314 if (other == slave) {
2315 Tcl_SetResult(interp, "Window can't be managed in itself",
2316 TCL_STATIC);
2317 return TCL_ERROR;
2318 }
2319 masterPtr = GetGrid(other);
2320 InitMasterData(masterPtr);
2321 } else if ((c == 'i')
2322 && (strncmp(argv[i], "-ipadx", length) == 0)) {
2323 if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
2324 || (tmp < 0)) {
2325 Tcl_ResetResult(interp);
2326 Tcl_AppendResult(interp, "bad ipadx value \"", argv[i+1],
2327 "\": must be positive screen distance",
2328 (char *) NULL);
2329 return TCL_ERROR;
2330 }
2331 slavePtr->iPadX = tmp*2;
2332 } else if ((c == 'i')
2333 && (strncmp(argv[i], "-ipady", length) == 0)) {
2334 if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
2335 || (tmp< 0)) {
2336 Tcl_ResetResult(interp);
2337 Tcl_AppendResult(interp, "bad ipady value \"", argv[i+1],
2338 "\": must be positive screen distance",
2339 (char *) NULL);
2340 return TCL_ERROR;
2341 }
2342 slavePtr->iPadY = tmp*2;
2343 } else if ((c == 'p')
2344 && (strncmp(argv[i], "-padx", length) == 0)) {
2345 if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
2346 || (tmp< 0)) {
2347 Tcl_ResetResult(interp);
2348 Tcl_AppendResult(interp, "bad padx value \"", argv[i+1],
2349 "\": must be positive screen distance",
2350 (char *) NULL);
2351 return TCL_ERROR;
2352 }
2353 slavePtr->padX = tmp*2;
2354 } else if ((c == 'p')
2355 && (strncmp(argv[i], "-pady", length) == 0)) {
2356 if ((Tk_GetPixels(interp, slave, argv[i+1], &tmp) != TCL_OK)
2357 || (tmp< 0)) {
2358 Tcl_ResetResult(interp);
2359 Tcl_AppendResult(interp, "bad pady value \"", argv[i+1],
2360 "\": must be positive screen distance",
2361 (char *) NULL);
2362 return TCL_ERROR;
2363 }
2364 slavePtr->padY = tmp*2;
2365 } else if ((c == 'r') && (strncmp(argv[i], "-row", length) == 0)) {
2366 if (Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK || tmp<0) {
2367 Tcl_ResetResult(interp);
2368 Tcl_AppendResult(interp, "bad grid value \"", argv[i+1],
2369 "\": must be a non-negative integer", (char *)NULL);
2370 return TCL_ERROR;
2371 }
2372 slavePtr->row = tmp;
2373 } else if ((c == 'r')
2374 && (strncmp(argv[i], "-rowspan", length) == 0)) {
2375 if ((Tcl_GetInt(interp, argv[i+1], &tmp) != TCL_OK) || tmp<=0) {
2376 Tcl_ResetResult(interp);
2377 Tcl_AppendResult(interp, "bad rowspan value \"", argv[i+1],
2378 "\": must be a positive integer", (char *)NULL);
2379 return TCL_ERROR;
2380 }
2381 slavePtr->numRows = tmp;
2382 } else if ((c == 's')
2383 && strncmp(argv[i], "-sticky", length) == 0) {
2384 int sticky = StringToSticky(argv[i+1]);
2385 if (sticky == -1) {
2386 Tcl_AppendResult(interp, "bad stickyness value \"", argv[i+1],
2387 "\": must be a string containing n, e, s, and/or w",
2388 (char *)NULL);
2389 return TCL_ERROR;
2390 }
2391 slavePtr->sticky = sticky;
2392 } else {
2393 Tcl_AppendResult(interp, "unknown or ambiguous option \"",
2394 argv[i], "\": must be ",
2395 "-column, -columnspan, -in, -ipadx, -ipady, ",
2396 "-padx, -pady, -row, -rowspan, or -sticky",
2397 (char *) NULL);
2398 return TCL_ERROR;
2399 }
2400 }
2401
2402 /*
2403 * Make sure we have a geometry master. We look at:
2404 * 1) the -in flag
2405 * 2) the geometry master of the first slave (if specified)
2406 * 3) the parent of the first slave.
2407 */
2408
2409 if (masterPtr == NULL) {
2410 masterPtr = slavePtr->masterPtr;
2411 }
2412 parent = Tk_Parent(slave);
2413 if (masterPtr == NULL) {
2414 masterPtr = GetGrid(parent);
2415 InitMasterData(masterPtr);
2416 }
2417
2418 if (slavePtr->masterPtr != NULL && slavePtr->masterPtr != masterPtr) {
2419 Unlink(slavePtr);
2420 slavePtr->masterPtr = NULL;
2421 }
2422
2423 if (slavePtr->masterPtr == NULL) {
2424 Gridder *tempPtr = masterPtr->slavePtr;
2425 slavePtr->masterPtr = masterPtr;
2426 masterPtr->slavePtr = slavePtr;
2427 slavePtr->nextPtr = tempPtr;
2428 }
2429
2430 /*
2431 * Make sure that the slave's parent is either the master or
2432 * an ancestor of the master, and that the master and slave
2433 * aren't the same.
2434 */
2435
2436 for (ancestor = masterPtr->tkwin; ; ancestor = Tk_Parent(ancestor)) {
2437 if (ancestor == parent) {
2438 break;
2439 }
2440 if (Tk_IsTopLevel(ancestor)) {
2441 Tcl_AppendResult(interp, "can't put ", argv[j],
2442 " inside ", Tk_PathName(masterPtr->tkwin),
2443 (char *) NULL);
2444 Unlink(slavePtr);
2445 return TCL_ERROR;
2446 }
2447 }
2448
2449 /*
2450 * Try to make sure our master isn't managed by us.
2451 */
2452
2453 if (masterPtr->masterPtr == slavePtr) {
2454 Tcl_AppendResult(interp, "can't put ", argv[j],
2455 " inside ", Tk_PathName(masterPtr->tkwin),
2456 ", would cause management loop.",
2457 (char *) NULL);
2458 Unlink(slavePtr);
2459 return TCL_ERROR;
2460 }
2461
2462 Tk_ManageGeometry(slave, &gridMgrType, (ClientData) slavePtr);
2463
2464 /*
2465 * Assign default position information.
2466 */
2467
2468 if (slavePtr->column == -1) {
2469 slavePtr->column = defaultColumn;
2470 }
2471 slavePtr->numCols += defaultColumnSpan - 1;
2472 if (slavePtr->row == -1) {
2473 if (masterPtr->masterDataPtr == NULL) {
2474 slavePtr->row = 0;
2475 } else {
2476 slavePtr->row = masterPtr->masterDataPtr->rowEnd;
2477 }
2478 }
2479 defaultColumn += slavePtr->numCols;
2480 defaultColumnSpan = 1;
2481
2482 /*
2483 * Arrange for the parent to be re-arranged at the first
2484 * idle moment.
2485 */
2486
2487 if (masterPtr->abortPtr != NULL) {
2488 *masterPtr->abortPtr = 1;
2489 }
2490 if (!(masterPtr->flags & REQUESTED_RELAYOUT)) {
2491 masterPtr->flags |= REQUESTED_RELAYOUT;
2492 Tcl_DoWhenIdle(ArrangeGrid, (ClientData) masterPtr);
2493 }
2494 }
2495
2496 /* Now look for all the "^"'s. */
2497
2498 lastWindow = NULL;
2499 for (j = 0; j < numWindows; j++) {
2500 struct Gridder *otherPtr;
2501 int match; /* found a match for the ^ */
2502 int lastRow, lastColumn; /* implied end of table */
2503
2504 if (*argv[j] == '.') {
2505 lastWindow = argv[j];
2506 }
2507 if (*argv[j] != REL_VERT) {
2508 continue;
2509 }
2510
2511 if (masterPtr == NULL) {
2512 Tcl_AppendResult(interp, "can't use '^', cant find master",
2513 (char *) NULL);
2514 return TCL_ERROR;
2515 }
2516
2517 /* Count the number of consecutive ^'s starting from this position */
2518 for (width=1; width+j < numWindows && *argv[j+width] == REL_VERT;
2519 width++) {
2520 /* Null Body */
2521 }
2522
2523 /*
2524 * Find the implied grid location of the ^
2525 */
2526
2527 if (lastWindow == NULL) {
2528 if (masterPtr->masterDataPtr != NULL) {
2529 SetGridSize(masterPtr);
2530 lastRow = masterPtr->masterDataPtr->rowEnd - 2;
2531 } else {
2532 lastRow = 0;
2533 }
2534 lastColumn = 0;
2535 } else {
2536 other = Tk_NameToWindow(interp, lastWindow, tkwin);
2537 otherPtr = GetGrid(other);
2538 lastRow = otherPtr->row + otherPtr->numRows - 2;
2539 lastColumn = otherPtr->column + otherPtr->numCols;
2540 }
2541
2542 for (match=0, slavePtr = masterPtr->slavePtr; slavePtr != NULL;
2543 slavePtr = slavePtr->nextPtr) {
2544
2545 if (slavePtr->column == lastColumn
2546 && slavePtr->row + slavePtr->numRows - 1 == lastRow) {
2547 if (slavePtr->numCols <= width) {
2548 slavePtr->numRows++;
2549 match++;
2550 j += slavePtr->numCols - 1;
2551 lastWindow = Tk_PathName(slavePtr->tkwin);
2552 break;
2553 }
2554 }
2555 }
2556 if (!match) {
2557 Tcl_AppendResult(interp, "can't find slave to extend with \"^\".",
2558 (char *) NULL);
2559 return TCL_ERROR;
2560 }
2561 /* j += width - 1; */
2562 }
2563
2564 if (masterPtr == NULL) {
2565 Tcl_AppendResult(interp, "can't determine master window",
2566 (char *) NULL);
2567 return TCL_ERROR;
2568 }
2569 SetGridSize(masterPtr);
2570 return TCL_OK;
2571 }
2572
2573 /*
2574 *----------------------------------------------------------------------
2575 *
2576 * StickyToString
2577 *
2578 * Converts the internal boolean combination of "sticky" bits onto
2579 * a TCL list element containing zero or mor of n, s, e, or w.
2580 *
2581 * Results:
2582 * A string is placed into the "result" pointer.
2583 *
2584 * Side effects:
2585 * none.
2586 *
2587 *----------------------------------------------------------------------
2588 */
2589
2590 static void
2591 StickyToString(flags, result)
2592 int flags; /* the sticky flags */
2593 char *result; /* where to put the result */
2594 {
2595 int count = 0;
2596 if (flags&STICK_NORTH) {
2597 result[count++] = 'n';
2598 }
2599 if (flags&STICK_EAST) {
2600 result[count++] = 'e';
2601 }
2602 if (flags&STICK_SOUTH) {
2603 result[count++] = 's';
2604 }
2605 if (flags&STICK_WEST) {
2606 result[count++] = 'w';
2607 }
2608 if (count) {
2609 result[count] = '\0';
2610 } else {
2611 sprintf(result,"{}");
2612 }
2613 }
2614
2615 /*
2616 *----------------------------------------------------------------------
2617 *
2618 * StringToSticky --
2619 *
2620 * Converts an ascii string representing a widgets stickyness
2621 * into the boolean result.
2622 *
2623 * Results:
2624 * The boolean combination of the "sticky" bits is retuned. If an
2625 * error occurs, such as an invalid character, -1 is returned instead.
2626 *
2627 * Side effects:
2628 * none
2629 *
2630 *----------------------------------------------------------------------
2631 */
2632
2633 static int
2634 StringToSticky(string)
2635 char *string;
2636 {
2637 int sticky = 0;
2638 char c;
2639
2640 while ((c = *string++) != '\0') {
2641 switch (c) {
2642 case 'n': case 'N': sticky |= STICK_NORTH; break;
2643 case 'e': case 'E': sticky |= STICK_EAST; break;
2644 case 's': case 'S': sticky |= STICK_SOUTH; break;
2645 case 'w': case 'W': sticky |= STICK_WEST; break;
2646 case ' ': case ',': case '\t': case '\r': case '\n': break;
2647 default: return -1;
2648 }
2649 }
2650 return sticky;
2651 }
2652
2653 /* End of tkgrid.c */

Properties

Name Value
svn:eol-style native
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25