rust/cargo-c: update to 0.10.7+cargo-0.84.0
[oi-userland.git] / components / x11 / libXaw4 / src / Xaw3_1Box.c
blob5226c7463ad4b1b68595e0fb49826f4b7a0b4470
1 #ifndef lint
2 static char Xrcsid[] = "$XConsortium: Box.c,v 1.43 89/12/07 20:14:26 kit Exp $";
3 #endif /* lint */
6 /***********************************************************
7 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
8 and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
10 All Rights Reserved
12 Permission to use, copy, modify, and distribute this software and its
13 documentation for any purpose and without fee is hereby granted,
14 provided that the above copyright notice appear in all copies and that
15 both that copyright notice and this permission notice appear in
16 supporting documentation, and that the names of Digital or MIT not be
17 used in advertising or publicity pertaining to distribution of the
18 software without specific, written prior permission.
20 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
21 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
22 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
23 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
24 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
25 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
26 SOFTWARE.
28 ******************************************************************/
31 /*
32 * Box.c - Box composite widget
36 #include <X11/IntrinsicP.h>
37 #include <X11/StringDefs.h>
38 #include <X11/Xmu/Misc.h>
39 #include <./Xaw3_1XawInit.h>
40 #include <./Xaw3_1BoxP.h>
42 /****************************************************************
44 * Box Resources
46 ****************************************************************/
48 static XtResource resources[] = {
49 { XtNhSpace, XtCHSpace, XtRDimension, sizeof(Dimension),
50 XtOffsetOf(BoxRec, box.h_space),
51 XtRImmediate, (XtPointer)4 },
52 { XtNvSpace, XtCVSpace, XtRDimension, sizeof(Dimension),
53 XtOffsetOf(BoxRec, box.v_space),
54 XtRImmediate, (XtPointer)4 },
55 { XtNorientation, XtCOrientation, XtROrientation, sizeof(XtOrientation),
56 XtOffsetOf(BoxRec, box.orientation),
57 XtRImmediate, (XtPointer)XtorientVertical },
60 /****************************************************************
62 * Full class record constant
64 ****************************************************************/
66 static void ClassInitialize();
67 static void Initialize();
68 static void Realize();
69 static void Resize();
70 static Boolean SetValues();
71 static XtGeometryResult GeometryManager();
72 static void ChangeManaged();
73 static XtGeometryResult PreferredSize();
75 BoxClassRec boxClassRec = {
77 /* core_class fields */
78 /* superclass */ (WidgetClass) &compositeClassRec,
79 /* class_name */ "Box",
80 /* widget_size */ sizeof(BoxRec),
81 /* class_initialize */ ClassInitialize,
82 /* class_part_init */ NULL,
83 /* class_inited */ FALSE,
84 /* initialize */ Initialize,
85 /* initialize_hook */ NULL,
86 /* realize */ Realize,
87 /* actions */ NULL,
88 /* num_actions */ 0,
89 /* resources */ resources,
90 /* num_resources */ XtNumber(resources),
91 /* xrm_class */ NULLQUARK,
92 /* compress_motion */ TRUE,
93 /* compress_exposure */ TRUE,
94 /* compress_enterleave*/ TRUE,
95 /* visible_interest */ FALSE,
96 /* destroy */ NULL,
97 /* resize */ Resize,
98 /* expose */ NULL,
99 /* set_values */ SetValues,
100 /* set_values_hook */ NULL,
101 /* set_values_almost */ XtInheritSetValuesAlmost,
102 /* get_values_hook */ NULL,
103 /* accept_focus */ NULL,
104 /* version */ XtVersion,
105 /* callback_private */ NULL,
106 /* tm_table */ NULL,
107 /* query_geometry */ PreferredSize,
108 /* display_accelerator*/ XtInheritDisplayAccelerator,
109 /* extension */ NULL
111 /* composite_class fields */
112 /* geometry_manager */ GeometryManager,
113 /* change_managed */ ChangeManaged,
114 /* insert_child */ XtInheritInsertChild,
115 /* delete_child */ XtInheritDeleteChild,
116 /* extension */ NULL
118 /* Box class fields */
119 /* empty */ 0,
123 WidgetClass boxWidgetClass = (WidgetClass)&boxClassRec;
126 /****************************************************************
128 * Private Routines
130 ****************************************************************/
134 * Do a layout, either actually assigning positions, or just calculating size.
135 * Returns minimum width and height that will preserve the same layout.
139 static DoLayout(bbw, width, height, reply_width, reply_height, position)
140 BoxWidget bbw;
141 Dimension width, height;
142 Dimension *reply_width, *reply_height; /* bounding box */
143 Boolean position; /* actually reposition the windows? */
145 Boolean vbox = (bbw->box.orientation == XtorientVertical);
146 Cardinal i;
147 Dimension w, h; /* Width and height needed for box */
148 Dimension lw, lh; /* Width and height needed for current line */
149 Dimension bw, bh; /* Width and height needed for current widget */
150 Dimension h_space; /* Local copy of bbw->box.h_space */
151 register Widget widget; /* Current widget */
152 int num_mapped_children = 0;
154 /* Box width and height */
155 h_space = bbw->box.h_space;
156 w = h_space;
157 h = bbw->box.v_space;
159 /* Line width and height */
160 lh = 0;
161 lw = h_space;
163 for (i = 0; i < bbw->composite.num_children; i++) {
164 widget = bbw->composite.children[i];
165 if (widget->core.managed) {
166 if (widget->core.mapped_when_managed) num_mapped_children++;
167 /* Compute widget width */
168 bw = widget->core.width + 2*widget->core.border_width + h_space;
169 if (lw + bw > width) {
170 if (lw > h_space) {
171 /* At least one widget on this line, and
172 * can't fit any more. Start new line if vbox.
174 AssignMax(w, lw);
175 if (vbox) {
176 h += lh + bbw->box.v_space;
177 lh = 0;
178 lw = h_space;
181 else if (!position) {
182 /* too narrow for this widget; we'll assume we can grow */
183 DoLayout(bbw, lw + bw, height, reply_width,
184 reply_height, position);
185 return;
188 if (position && (lw != widget->core.x || h != widget->core.y)) {
189 /* It would be nice to use window gravity, but there isn't
190 * sufficient fine-grain control to nicely handle all
191 * situations (e.g. when only the height changes --
192 * a common case). Explicit unmapping is a cheap hack
193 * to speed things up & avoid the visual jitter as
194 * things slide around.
196 * %%% perhaps there should be a client resource to
197 * control this. If so, we'll have to optimize to
198 * perform the moves from the correct end so we don't
199 * force extra exposures as children occlude each other.
201 if (XtIsRealized(widget))
202 XUnmapWindow( XtDisplay(widget), XtWindow(widget) );
203 XtMoveWidget(bbw->composite.children[i], (int)lw, (int)h);
205 lw += bw;
206 bh = widget->core.height + 2*widget->core.border_width;
207 AssignMax(lh, bh);
208 } /* if managed */
209 } /* for */
211 if (!vbox && width && lw > width && lh < height) {
212 /* reduce width if too wide and height not filled */
213 Dimension sw = lw, sh = lh;
214 Dimension width_needed;
215 XtOrientation orientation = bbw->box.orientation;
216 bbw->box.orientation = XtorientVertical;
217 while (sh < height && sw > width) {
218 width_needed = sw;
219 DoLayout(bbw, sw-1, height, &sw, &sh, False);
221 if (sh < height) width_needed = sw;
222 if (width_needed != lw) {
223 DoLayout(bbw,width_needed,height,reply_width,reply_height,position);
224 bbw->box.orientation = orientation;
225 return;
227 bbw->box.orientation = orientation;
230 if (position && XtIsRealized((Widget)bbw)) {
231 if (bbw->composite.num_children == num_mapped_children)
232 XMapSubwindows( XtDisplay((Widget)bbw), XtWindow((Widget)bbw) );
233 else {
234 int i = num_mapped_children;
235 register Widget *childP = bbw->composite.children;
236 for (; i > 0; childP++) {
237 if (XtIsManaged(*childP) &&
238 (*childP)->core.mapped_when_managed) {
239 XtMapWidget(*childP);
240 i--;
246 /* Finish off last line */
247 if (lw > h_space) {
248 AssignMax(w, lw);
249 h += lh + bbw->box.v_space;
252 *reply_width = Max(w, 1);
253 *reply_height = Max(h, 1);
258 * Calculate preferred size, given constraining box, caching it in the widget.
262 static XtGeometryResult PreferredSize(widget, constraint, preferred)
263 Widget widget;
264 XtWidgetGeometry *constraint, *preferred;
266 BoxWidget w = (BoxWidget)widget;
267 Dimension width /*, height */;
268 Dimension preferred_width = w->box.preferred_width;
269 Dimension preferred_height = w->box.preferred_height;
271 constraint->request_mode &= CWWidth | CWHeight;
273 if (constraint->request_mode == 0)
274 /* parent isn't going to change w or h, so nothing to re-compute */
275 return XtGeometryYes;
277 if (constraint->request_mode == w->box.last_query_mode &&
278 (!(constraint->request_mode & CWWidth) ||
279 constraint->width == w->box.last_query_width) &&
280 (!(constraint->request_mode & CWHeight) ||
281 constraint->height == w->box.last_query_height)) {
282 /* same query; current preferences are still valid */
283 preferred->request_mode = CWWidth | CWHeight;
284 preferred->width = preferred_width;
285 preferred->height = preferred_height;
286 if (constraint->request_mode == (CWWidth | CWHeight) &&
287 constraint->width == preferred_width &&
288 constraint->height == preferred_height)
289 return XtGeometryYes;
290 else
291 return XtGeometryAlmost;
294 /* else gotta do it the long way...
295 I have a preference for tall and narrow, so if my width is
296 constrained, I'll accept it; otherwise, I'll compute the minimum
297 width that will fit me within the height constraint */
299 w->box.last_query_mode = constraint->request_mode;
300 w->box.last_query_width = constraint->width;
301 w->box.last_query_height= constraint->height;
303 if (constraint->request_mode & CWWidth)
304 width = constraint->width;
305 else /* if (constraint->request_mode & CWHeight) */ {
306 /* let's see if I can become any narrower */
307 width = 0;
308 constraint->width = 65535;
311 /* height is currently ignored by DoLayout.
312 height = (constraint->request_mode & CWHeight) ? constraint->height
313 : *preferred_height;
315 DoLayout(w, width, (Dimension)0,
316 &preferred_width, &preferred_height, FALSE);
318 if (constraint->request_mode & CWHeight &&
319 preferred_height > constraint->height) {
320 /* find minimum width for this height */
321 if (preferred_width > constraint->width) {
322 /* punt; over-constrained */
324 else {
325 width = preferred_width;
326 do { /* find some width big enough to stay within this height */
327 width *= 2;
328 if (width > constraint->width) width = constraint->width;
329 DoLayout(w, width, 0, &preferred_width, &preferred_height, FALSE);
330 } while (preferred_height > constraint->height &&
331 width < constraint->width);
332 if (width != constraint->width) {
333 do { /* find minimum width */
334 width = preferred_width;
335 DoLayout(w, preferred_width-1, 0,
336 &preferred_width, &preferred_height, FALSE);
337 } while (preferred_height < constraint->height);
338 /* one last time */
339 DoLayout(w, width, 0, &preferred_width, &preferred_height, FALSE);
344 preferred->request_mode = CWWidth | CWHeight;
345 preferred->width = w->box.preferred_width = preferred_width;
346 preferred->height = w->box.preferred_height = preferred_height;
348 if (constraint->request_mode == (CWWidth|CWHeight)
349 && constraint->width == preferred_width
350 && constraint->height == preferred_height)
351 return XtGeometryYes;
352 else
353 return XtGeometryAlmost;
359 * Actually layout the box
363 static void Resize(w)
364 Widget w;
366 Dimension junk;
368 DoLayout((BoxWidget)w, w->core.width, w->core.height, &junk, &junk, TRUE);
370 } /* Resize */
374 * Try to do a new layout within the current width and height;
375 * if that fails try to resize and do it within the box returne
376 * by PreferredSize.
378 * TryNewLayout just says if it's possible, and doesn't actually move the kids
381 static Boolean TryNewLayout(bbw)
382 BoxWidget bbw;
384 Dimension preferred_width, preferred_height;
385 Dimension proposed_width, proposed_height;
386 int iterations;
388 DoLayout( bbw, bbw->core.width, bbw->core.height,
389 &preferred_width, &preferred_height, FALSE );
391 /* at this point, preferred_width is guaranteed to not be greater
392 than bbw->core.width unless some child is larger, so there's no
393 point in re-computing another layout */
395 if ((bbw->core.width == preferred_width) &&
396 (bbw->core.height == preferred_height)) {
397 /* Same size */
398 return (TRUE);
401 /* let's see if our parent will go for a new size. */
402 iterations = 0;
403 proposed_width = preferred_width;
404 proposed_height = preferred_height;
405 do {
406 switch (XtMakeResizeRequest((Widget)bbw,proposed_width,proposed_height,
407 &proposed_width, &proposed_height))
409 case XtGeometryYes:
410 return (TRUE);
412 case XtGeometryNo:
413 if (iterations > 0)
414 /* protect from malicious parents who change their minds */
415 DoLayout( bbw, bbw->core.width, bbw->core.height,
416 &preferred_width, &preferred_height, FALSE );
417 if ((preferred_width <= bbw->core.width) &&
418 (preferred_height <= bbw->core.height))
419 return (TRUE);
420 else
421 return (FALSE);
423 case XtGeometryAlmost:
424 if (proposed_height >= preferred_height &&
425 proposed_width >= preferred_width) {
428 * Take it, and assume the parent knows what it is doing.
430 * The parent must accept this since it was returned in
431 * almost.
434 (void) XtMakeResizeRequest( (Widget)bbw,
435 proposed_width, proposed_height,
436 &proposed_width, &proposed_height);
437 return(TRUE);
439 else if (proposed_width != preferred_width) {
440 /* recalc bounding box; height might change */
441 DoLayout(bbw, proposed_width, 0,
442 &preferred_width, &preferred_height, FALSE);
443 proposed_height = preferred_height;
445 else { /* proposed_height != preferred_height */
446 XtWidgetGeometry constraints, reply;
447 constraints.request_mode = CWHeight;
448 constraints.height = proposed_height;
449 (void)PreferredSize((Widget)bbw, &constraints, &reply);
450 proposed_width = preferred_width;
453 iterations++;
454 } while (iterations < 10);
455 return (FALSE);
460 * Geometry Manager
462 * 'reply' is unused; we say only yeay or nay, never almost.
466 /*ARGSUSED*/
467 static XtGeometryResult GeometryManager(w, request, reply)
468 Widget w;
469 XtWidgetGeometry *request;
470 XtWidgetGeometry *reply; /* RETURN */
473 Dimension width, height, borderWidth;
474 BoxWidget bbw;
476 /* Position request always denied */
477 if ((request->request_mode & CWX && request->x != w->core.x) ||
478 (request->request_mode & CWY && request->y != w->core.y))
479 return (XtGeometryNo);
481 /* Size changes must see if the new size can be accomodated */
482 if (request->request_mode & (CWWidth | CWHeight | CWBorderWidth)) {
484 /* Make all three fields in the request valid */
485 if ((request->request_mode & CWWidth) == 0)
486 request->width = w->core.width;
487 if ((request->request_mode & CWHeight) == 0)
488 request->height = w->core.height;
489 if ((request->request_mode & CWBorderWidth) == 0)
490 request->border_width = w->core.border_width;
492 /* Save current size and set to new size */
493 width = w->core.width;
494 height = w->core.height;
495 borderWidth = w->core.border_width;
496 w->core.width = request->width;
497 w->core.height = request->height;
498 w->core.border_width = request->border_width;
500 /* Decide if new layout works: (1) new widget is smaller,
501 (2) new widget fits in existing Box, (3) Box can be
502 expanded to allow new widget to fit */
504 bbw = (BoxWidget) w->core.parent;
506 /* whenever a child changes his geometry, we attempt to
507 * change ours to be the minimum enclosing size...
508 if (((request->width + request->border_width <= width + borderWidth) &&
509 (request->height + request->border_width <= height + borderWidth))
510 || bbw->box.preferred_width < bbw->core.width
511 || bbw->box.preferred_height < bbw->core.height
512 || TryNewLayout(bbw)) {
514 if (TryNewLayout(bbw)) {
515 /* Fits in existing or new space, relayout */
516 (*XtClass((Widget)bbw)->core_class.resize)((Widget)bbw);
517 return (XtGeometryYes);
518 } else {
519 /* Cannot satisfy request, change back to original geometry */
520 w->core.width = width;
521 w->core.height = height;
522 w->core.border_width = borderWidth;
523 return (XtGeometryNo);
525 }; /* if any size changes requested */
527 /* Any stacking changes don't make a difference, so allow if that's all */
528 return (XtGeometryYes);
531 static void ChangeManaged(w)
532 Widget w;
534 /* Reconfigure the box */
535 (void) TryNewLayout((BoxWidget)w);
536 Resize(w);
539 static void ClassInitialize()
541 XawInitializeWidgetSet();
542 XtAddConverter( XtRString, XtROrientation, XmuCvtStringToOrientation,
543 NULL, (Cardinal)0 );
546 /* ARGSUSED */
547 static void Initialize(request, new)
548 Widget request, new;
550 BoxWidget newbbw = (BoxWidget)new;
552 newbbw->box.last_query_mode = CWWidth | CWHeight;
553 newbbw->box.last_query_width = newbbw->box.last_query_height = 0;
554 newbbw->box.preferred_width = Max(newbbw->box.h_space, 1);
555 newbbw->box.preferred_height = Max(newbbw->box.v_space, 1);
557 if (newbbw->core.width == 0)
558 newbbw->core.width = newbbw->box.preferred_width;
560 if (newbbw->core.height == 0)
561 newbbw->core.height = newbbw->box.preferred_height;
563 } /* Initialize */
565 static void Realize(w, valueMask, attributes)
566 register Widget w;
567 Mask *valueMask;
568 XSetWindowAttributes *attributes;
570 attributes->bit_gravity = NorthWestGravity;
571 *valueMask |= CWBitGravity;
573 XtCreateWindow( w, (unsigned)InputOutput, (Visual *)CopyFromParent,
574 *valueMask, attributes);
575 } /* Realize */
577 /* ARGSUSED */
578 static Boolean SetValues(current, request, new)
579 Widget current, request, new;
581 /* need to relayout if h_space or v_space change */
583 return False;