1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 #define _GNU_SOURCE
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include "Grid.h"
39
40 #include <X11/Xlib.h>
41
42
43
44 static XtActionsRec actionslist[] = {
45 {
"getfocus",grid_getfocus},
46 {
"loosefocus",grid_loosefocus},
47 {
"NULL",
NULL}
48 };
49
50
51 static char defaultTranslations[] =
"\
52 <EnterWindow>: getfocus()\n\
53 <LeaveWindow>: loosefocus()\n";
54
55 static XtResource resources[] =
56 {
57 {
58 gridColumnSpacing,
59 gridColumnSpacing,
60 XmRDimension,
61 sizeof (Dimension),
62 XtOffsetOf( GridRec,
63 grid.columnspacing),
64 XmRImmediate,
65 (XtPointer)
0
66 },
67 {
68 gridRowSpacing,
69 gridRowSpacing,
70 XmRDimension,
71 sizeof (Dimension),
72 XtOffsetOf( GridRec,
73 grid.rowspacing),
74 XmRImmediate,
75 (XtPointer)
0
76 },
77 {
78 gridPaddingLeft,
79 gridPaddingLeft,
80 XmRDimension,
81 sizeof (Dimension),
82 XtOffsetOf( GridRec,
83 grid.padding_left),
84 XmRImmediate,
85 (XtPointer)
0
86 },
87 {
88 gridPaddingRight,
89 gridPaddingRight,
90 XmRDimension,
91 sizeof (Dimension),
92 XtOffsetOf( GridRec,
93 grid.padding_right),
94 XmRImmediate,
95 (XtPointer)
0
96 },
97 {
98 gridPaddingTop,
99 gridPaddingTop,
100 XmRDimension,
101 sizeof (Dimension),
102 XtOffsetOf( GridRec,
103 grid.padding_top),
104 XmRImmediate,
105 (XtPointer)
0
106 },
107 {
108 gridPaddingBottom,
109 gridPaddingBottom,
110 XmRDimension,
111 sizeof (Dimension),
112 XtOffsetOf( GridRec,
113 grid.padding_bottom),
114 XmRImmediate,
115 (XtPointer)
0
116 }
117 };
118
119
120 static XtResource constraints[] =
121 {
122 {
123 gridColumn,
124 gridColumn,
125 XmRDimension,
126 sizeof (Dimension),
127 XtOffsetOf( GridConstraintRec,
128 grid.x),
129 XmRImmediate,
130 (XtPointer)
0
131 },
132 {
133 gridRow,
134 gridRow,
135 XmRDimension,
136 sizeof (Dimension),
137 XtOffsetOf( GridConstraintRec,
138 grid.y),
139 XmRImmediate,
140 (XtPointer)
0
141 },
142 {
143 gridColspan,
144 gridColspan,
145 XmRDimension,
146 sizeof (Dimension),
147 XtOffsetOf( GridConstraintRec,
148 grid.colspan),
149 XmRImmediate,
150 (XtPointer)
0
151 },
152 {
153 gridRowspan,
154 gridRowspan,
155 XmRDimension,
156 sizeof (Dimension),
157 XtOffsetOf( GridConstraintRec,
158 grid.rowspan),
159 XmRImmediate,
160 (XtPointer)
0
161 },
162 {
163 gridMarginLeft,
164 gridMarginLeft,
165 XmRDimension,
166 sizeof (Dimension),
167 XtOffsetOf( GridConstraintRec,
168 grid.margin_left),
169 XmRImmediate,
170 (XtPointer)
0
171 },
172 {
173 gridMarginRight,
174 gridMarginRight,
175 XmRDimension,
176 sizeof (Dimension),
177 XtOffsetOf( GridConstraintRec,
178 grid.margin_right),
179 XmRImmediate,
180 (XtPointer)
0
181 },
182 {
183 gridMarginTop,
184 gridMarginTop,
185 XmRDimension,
186 sizeof (Dimension),
187 XtOffsetOf( GridConstraintRec,
188 grid.margin_top),
189 XmRImmediate,
190 (XtPointer)
0
191 },
192 {
193 gridMarginBottom,
194 gridMarginBottom,
195 XmRDimension,
196 sizeof (Dimension),
197 XtOffsetOf( GridConstraintRec,
198 grid.margin_bottom),
199 XmRImmediate,
200 (XtPointer)
0
201 },
202 {
203 gridHExpand,
204 gridHExpand,
205 XmRBoolean,
206 sizeof (Boolean),
207 XtOffsetOf( GridConstraintRec,
208 grid.hexpand),
209 XmRImmediate,
210 (XtPointer)
0
211 },
212 {
213 gridVExpand,
214 gridVExpand,
215 XmRBoolean,
216 sizeof (Boolean),
217 XtOffsetOf( GridConstraintRec,
218 grid.vexpand),
219 XmRImmediate,
220 (XtPointer)
0
221 },
222 {
223 gridHFill,
224 gridHFill,
225 XmRBoolean,
226 sizeof (Boolean),
227 XtOffsetOf( GridConstraintRec,
228 grid.hfill),
229 XmRImmediate,
230 (XtPointer)
0
231 },
232 {
233 gridVFill,
234 gridVFill,
235 XmRBoolean,
236 sizeof (Boolean),
237 XtOffsetOf( GridConstraintRec,
238 grid.vfill),
239 XmRImmediate,
240 (XtPointer)
0
241 },
242 {
243 gridMinWidth,
244 gridMinWidth,
245 XmRDimension,
246 sizeof (Dimension),
247 XtOffsetOf( GridConstraintRec,
248 grid.min_width),
249 XmRImmediate,
250 (XtPointer)
0
251 }
252 };
253
254
255 GridClassRec gridClassRec = {
256
257 {
258
259 (WidgetClass)&xmManagerClassRec,
260 "Grid",
261 sizeof(GridRec),
262 grid_class_initialize,
263 NULL,
264 FALSE,
265 (XtInitProc)grid_initialize,
266 NULL,
267 grid_realize,
268 actionslist,
269 XtNumber(actionslist),
270 resources,
271 XtNumber(resources),
272 NULLQUARK,
273 True,
274 True,
275 True,
276 False,
277 (XtWidgetProc)grid_destroy,
278 (XtWidgetProc)grid_resize,
279 (XtExposeProc)grid_expose,
280 grid_set_values,
281 NULL,
282 XtInheritSetValuesAlmost,
283 NULL,
284 (XtAcceptFocusProc)grid_acceptfocus,
285 XtVersion,
286 NULL,
287
288 defaultTranslations,
289 XtInheritQueryGeometry,
290 NULL,
291 NULL,
292 },
293
294 {
295 GridGeometryManager,
296 GridChangeManaged,
297 XtInheritInsertChild,
298 XtInheritDeleteChild,
299 NULL,
300 },
301
302 {
303 constraints,
304 XtNumber(constraints),
305 sizeof(GridConstraintRec),
306 grid_constraint_init,
307 NULL,
308 ConstraintSetValues,
309 NULL,
310 },
311
312
313 {
314 XtInheritTranslations,
315 NULL,
316 0,
317 NULL,
318 0,
319 XmInheritParentProcess,
320 NULL
321 },
322
323
324 {
325 0
326 }
327 };
328
329 WidgetClass gridClass = (WidgetClass)&gridClassRec;
330
331
332 void grid_class_initialize(
void) {
333
334 }
335 void grid_initialize(Widget request, Widget new, ArgList args, Cardinal num_args) {
336 Grid mn = (Grid)new;
337
338 mn->grid.max_col =
0;
339 mn->grid.max_row =
0;
340
341 }
342 void grid_realize(Widget w,XtValueMask *valueMask,XSetWindowAttributes *attributes) {
343 Grid grid = (Grid)w;
344 XtMakeResizeRequest(w,
400,
400,
NULL,
NULL);
345 (coreClassRec.core_class.realize)((Widget)w, valueMask, attributes);
346 grid_place_children(grid);
347 }
348
349
350 void grid_destroy(Grid widget) {
351
352 }
353 void grid_resize(Grid widget) {
354 grid_place_children(widget);
355 }
356
357 void grid_expose(Grid widget, XEvent *event, Region region) {
358
359 }
360
361
362 Boolean grid_set_values(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args) {
363 return False;
364 }
365
366 Boolean grid_acceptfocus(Widget w, Time *t) {
367
368 }
369
370 void grid_getfocus(Widget myw, XEvent *event, String *params, Cardinal *nparam) {
371
372 }
373
374 void grid_loosefocus(Widget myw, XEvent *event, String *params, Cardinal *nparam) {
375
376 }
377
378
379
380 XtGeometryResult GridGeometryManager(Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *reply) {
381 GridRec *grid = (GridRec*)XtParent(widget);
382 GridConstraintRec *constraints = widget->core.constraints;
383
384 if((request->request_mode & CWWidth) == CWWidth) {
385 widget->core.width = request->width;
386 constraints->grid.pref_width = request->width;
387 }
388 if((request->request_mode & CWHeight) == CWHeight) {
389 widget->core.height = request->height;
390 constraints->grid.pref_height = request->height;
391 }
392 grid_place_children((Grid)XtParent(widget));
393 return XtGeometryYes;
394 }
395
396 void GridChangeManaged(Widget widget) {
397 grid_place_children((Grid)widget);
398 }
399
400 Boolean ConstraintSetValues(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args) {
401 GridConstraintRec *constraints = neww->core.constraints;
402 Grid grid = (Grid)XtParent(neww);
403 if(constraints->grid.x > grid->grid.max_col) {
404 grid->grid.max_col = constraints->grid.x;
405 }
406 if(constraints->grid.y > grid->grid.max_row) {
407 grid->grid.max_row = constraints->grid.y;
408 }
409 }
410
411
412 void grid_constraint_init(
413 Widget request,
414 Widget neww,
415 ArgList args,
416 Cardinal* num_args
417 )
418 {
419 GridConstraintRec *constraints = neww->core.constraints;
420
421 Grid grid = (Grid)XtParent(neww);
422 if(constraints->grid.x > grid->grid.max_col) {
423 grid->grid.max_col = constraints->grid.x;
424 }
425 if(constraints->grid.y > grid->grid.max_row) {
426 grid->grid.max_row = constraints->grid.y;
427 }
428 constraints->grid.pref_width = neww->core.width;
429 constraints->grid.pref_height = neww->core.height;
430 }
431
432 void grid_place_children(Grid w) {
433 if(!XtIsRealized((Widget)w)) {
434 return;
435 }
436
437 int ncols = w->grid.max_col
+1;
438 int nrows = w->grid.max_row
+1;
439 GridDef *cols = calloc(ncols,
sizeof(GridDef));
440 GridDef *rows = calloc(nrows,
sizeof(GridDef));
441 int num_cols_expanding =
0;
442 int num_rows_expanding =
0;
443 int req_width = w->grid.padding_left + w->grid.padding_right;
444 int req_height = w->grid.padding_top + w->grid.padding_bottom;
445 int width = w->core.width;
446 int height = w->core.height;
447
448
449
450
451
452
453 int span_max =
1;
454 for(
int r=
0;r<
2;r++) {
455 for(
int i=
0;i<w->composite.num_children;i++) {
456 Widget child = w->composite.children[i];
457 GridConstraintRec *constraints = child->core.constraints;
458 if(constraints->grid.pref_width ==
0) {
459 constraints->grid.pref_width = child->core.width;
460 }
461 if(constraints->grid.pref_height ==
0) {
462 constraints->grid.pref_height = child->core.height;
463 }
464 if(constraints->grid.pref_width < constraints->grid.min_width) {
465 constraints->grid.pref_width = constraints->grid.min_width;
466 }
467 int elm_width = constraints->grid.pref_width + constraints->grid.margin_left + constraints->grid.margin_right;
468 int elm_height = constraints->grid.pref_height + constraints->grid.margin_top + constraints->grid.margin_bottom;
469 if(!XtIsManaged(child)) {
470 elm_width =
0;
471 elm_height =
0;
472 }
473
474 if(constraints->grid.colspan > span_max || constraints->grid.rowspan > span_max) {
475 continue;
476 }
477
478 int x = constraints->grid.x;
479 int y = constraints->grid.y;
480
481
482 if(x >= ncols) {
483 fprintf(stderr,
"Error: widget x out of bounds\n");
484 continue;
485 }
486 if(y >= nrows) {
487 fprintf(stderr,
"Error: widget y out of bounds\n");
488 continue;
489 }
490 GridDef *col = &cols[x];
491 GridDef *row = &rows[y];
492
493 if(constraints->grid.hexpand) {
494 if(constraints->grid.colspan >
1) {
495
496
497 GridDef *last_col = col;
498 for(
int c=x;c<ncols;c++) {
499 last_col = &cols[c];
500 if(last_col->expand) {
501 break;
502 }
503 }
504 last_col->expand =
TRUE;
505 }
else {
506 col->expand =
TRUE;
507 }
508 }
509 if(constraints->grid.vexpand) {
510 if(constraints->grid.rowspan >
1) {
511 GridDef *last_row = row;
512 for(
int c=x;c<nrows;c++) {
513 last_row = &rows[c];
514 if(last_row->expand) {
515 break;
516 }
517 }
518 last_row->expand =
TRUE;
519 }
else {
520 row->expand =
TRUE;
521 }
522 }
523
524
525 if(constraints->grid.colspan >
1) {
526
527 Dimension span_width = col->size;
528 GridDef *last_col = col;
529 for(
int s=x
+1;s<ncols;s++) {
530 last_col = &cols[s];
531 span_width = last_col->size;
532
533 }
534 int diff = elm_width - span_width;
535 if(diff >
0) {
536 last_col->size += diff;
537 }
538 }
else if(elm_width > col->size) {
539 col->size = elm_width;
540 }
541
542 if(constraints->grid.rowspan >
1) {
543 Dimension span_height = row->size;
544 GridDef *last_row = row;
545 for(
int s=x
+1;s<nrows;s++) {
546 last_row = &rows[s];
547 span_height = last_row->size;
548
549 }
550 int diff = elm_height - span_height;
551 if(diff >
0) {
552 last_row->size += diff;
553 }
554 }
else if(elm_height > row->size) {
555 row->size = elm_height;
556 }
557 }
558 span_max =
50000;
559 }
560
561
562 for(
int i=
0;i<ncols;i++) {
563 if(cols[i].expand) {
564 num_cols_expanding++;
565 }
566 req_width += cols[i].size;
567 }
568 for(
int i=
0;i<nrows;i++) {
569 if(rows[i].expand) {
570 num_rows_expanding++;
571 }
572 req_height += rows[i].size;
573 }
574
575 int total_colspacing =
0;
576 int total_rowspacing =
0;
577 for(
int i=
0;i
+1<ncols;i++) {
578 if(cols[i].size >
0) {
579 total_colspacing += w->grid.columnspacing;
580 }
581 }
582 for(
int i=
0;i
+1<nrows;i++) {
583 if(rows[i].size >
0) {
584 total_rowspacing += w->grid.rowspacing;
585 }
586 }
587
588 if(req_width >
0 && req_height >
0) {
589
590 req_width += total_colspacing;
591 req_height += total_rowspacing;
592
593 Widget parent = w->core.parent;
594 Dimension rwidth = req_width;
595 Dimension rheight = req_height;
596 if(rwidth < w->core.width) {
597
598 }
599 if(rheight < w->core.height) {
600
601 }
602
603 if(!w->grid.sizerequest) {
604 Dimension actual_width, actual_height;
605 w->grid.sizerequest =
TRUE;
606
607
608
609
610
611
612
613
614
615 XtMakeResizeRequest((Widget)w, req_width, req_height, &actual_width, &actual_height);
616 w->grid.sizerequest =
FALSE;
617
618 }
619
620
621
622 }
623
624
625 int hexpand =
0;
626 int width_diff = width - req_width;
627 int hexpand2 =
0;
628 if(width_diff >
0 && num_cols_expanding >
0) {
629 hexpand = width_diff / num_cols_expanding;
630 hexpand2 = width_diff-hexpand*num_cols_expanding;
631 }
632 int x = w->grid.padding_left;
633 for(
int i=
0;i<ncols;i++) {
634 cols[i].pos = x;
635 if(cols[i].expand) {
636 cols[i].size += hexpand + hexpand2;
637 }
638 if(cols[i].size >
0) {
639 x += cols[i].size + w->grid.columnspacing;
640 }
641
642 hexpand2 =
0;
643 }
644
645 int vexpand =
0;
646 int height_diff = height - req_height;
647 int vexpand2 =
0;
648 if(height_diff >
0 && num_rows_expanding >
0) {
649 vexpand = height_diff / num_rows_expanding;
650 vexpand2 = height_diff-vexpand*num_rows_expanding;
651 }
652 int y = w->grid.padding_bottom;
653 for(
int i=
0;i<nrows;i++) {
654 rows[i].pos = y;
655 if(rows[i].expand) {
656 rows[i].size += vexpand + vexpand2;
657 }
658 if(rows[i].size >
0) {
659 y += rows[i].size += w->grid.rowspacing;
660 }
661
662 vexpand2 =
0;
663 }
664
665 for(
int i=
0;i<w->composite.num_children;i++) {
666 Widget child = w->composite.children[i];
667 GridConstraintRec *constraints = child->core.constraints;
668 GridDef c = cols[constraints->grid.x];
669 GridDef r = rows[constraints->grid.y];
670 int x = c.pos + constraints->grid.margin_left;
671 int y = r.pos + constraints->grid.margin_top;
672 int width = constraints->grid.pref_width;
673 int height = constraints->grid.pref_height;
674 if(constraints->grid.hfill) {
675 if(constraints->grid.colspan >
1) {
676 Dimension cwidth =
0;
677 for(
int j=
0;j<constraints->grid.colspan;j++) {
678 if(constraints->grid.x+j < ncols) {
679 cwidth += cols[constraints->grid.x+j].size + (j >
0 ? w->grid.columnspacing :
0);
680 }
681 }
682 width = cwidth;
683 }
else {
684 width = c.size - w->grid.columnspacing - constraints->grid.margin_left - constraints->grid.margin_right;
685 }
686 }
687 if(constraints->grid.vfill) {
688 if(constraints->grid.rowspan >
1) {
689 Dimension cheight =
0;
690 for(
int j=
0;j<constraints->grid.rowspan;j++) {
691 if(constraints->grid.y+j < nrows) {
692 cheight += rows[constraints->grid.y+j].size + (j >
0 ? w->grid.rowspacing :
0);
693 }
694 }
695 height = cheight;
696 }
else {
697 height = r.size - w->grid.rowspacing - constraints->grid.margin_top - constraints->grid.margin_bottom;
698 }
699 }
700
701 if(width >
0 && height >
0) {
702 XtConfigureWidget(child, x, y, width, height, child->core.border_width);
703 }
704
705 }
706
707 free(cols);
708 free(rows);
709 }
710
711