1 /*
2 * Motif Tools Library, Version 3.1
3 * $Id: Layout.c,v 1.3 2001/07/07 01:38:33 grmcdorman Exp $
4 *
5 * Written by David Flanagan.
6 * Copyright (c) 1992-2001 by David Flanagan.
7 * All Rights Reserved. See the file COPYRIGHT for details.
8 * This is open source software. See the file LICENSE for details.
9 * There is no warranty for this software. See NO_WARRANTY for details.
10 *
11 * $Log: Layout.c,v $
12 * Revision 1.3 2001/07/07 01:38:33 grmcdorman
13 * This change fixes redraw problems with Layout. Formerly,
14 * Layout would erase and redraw most of the layout (especially
15 * captions) on expose events. This caused noticable and
16 * ugly flickering.
17 *
18 * Revision 1.2 2001/04/15 15:29:36 grmcdorman
19 * * XmtCallCallback has two new arguments types: XmtRCallbackUserData, which
20 * is the XmNuserData value, and XmtRCallbackImmediate, which is a value
21 * embedded in the list.
22 *
23 * * Two new functions, XmtCreateQueryListChildren and XmtCreateQueryListChild,
24 * are provided. They are like the XmtCreate* functions except that they
25 * return a list of the widgets created (quark and pointer to the widget).
26 *
27 * * Major enhancements to XmtInputField:
28 * - The input field now has a cancel() action. This reverts the field's
29 * value to that prior to the start of editing (i.e. the last commit).
30 * No default translation is bound to this action, however.
31 * - There is a callback for the cancel action (XmtNcancelCallback).
32 * - The input field can be set to cancel, commit, or do nothing on focus
33 * out. (Previously, it always did a commit). The default is commit.
34 * (XmtNfocusOutAction)
35 *
36 * * XmtLayout:
37 * - It now has a losingFocusCallback (XmNloosingFocusCallback).
38 * - It, and the layout widgets (XmtLayoutBox/XmtLayoutString), now
39 * support background pixmaps.
40 * - It now supports XmNresizePolicy.
41 * - Strings in the layout parser are converted to XmStrings by
42 * XtConvertAndStore, so any custom XmString conversion is used
43 * (as, for example, the Xmt convert, which supports the @[]
44 * embedded items)
45 *
46 * * Other:
47 * - Pixmaps are convered using XtConvertAndStore, again to allow
48 * custom converters.
49 *
50 * Bug Fixes: (for Solaris 2.5.1/Motif 1.2/Sparc system)
51 * * XmtInputField did not work properly if the widget had traversalOn
52 * false.
53 * * XmtLayout's child geometry manager was called by Xt when
54 * a shell child was added to the layout; it did not handle
55 * this case.
56 * * XmtLayout had an XmtWarningMsg call with a missing argument (line 2029).
57 * * Widgets automatically created by XmtLayout parsing have been given
58 * non-blank names. [You may wish to tweak this by adding, for example,
59 * a leading underscore.]
60 * * Under some circumstances, XmtNameToWidget could be called during
61 * widget creation, with 'w->core.num_popups' uninitialized. The
62 * workaround applied is to ignore the popup list if the 'num_popups'
63 * value is more than 50 or negative.
64 *
65 * Revision 1.1.1.1 2001/02/10 13:45:43 motiftools
66 * Initial import of Xmt310 to CVS
67 *
68 *
69 */
70
71 #include <stdio.h>
72 #include <Xmt/XmtP.h>
73 #include <Xmt/LayoutP.h>
74 #include <Xmt/LayoutGP.h>
75 #include <Xmt/ConvertersP.h>
76 #include <Xmt/Pixmap.h>
77 #include <Xm/DialogS.h>
78 #if (XmVersion >= 1002)
79 #include <Xm/DrawP.h> /* declaration of Motif drawing routines */
80 #endif
81
82 #include <X11/IntrinsicP.h>
83
84 #define offset(field) XtOffsetOf(XmtLayoutRec, field)
85 static XtResource resources[] = {
86 {XmtNlayout, XmtCLayout, XtRString, sizeof(String),
87 offset(layout.layout), XtRString, NULL},
88 #if XmVersion < 2000
89 {XmtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
90 offset(layout.font), XtRString, XtDefaultFont},
91 #else /* Motif 2.0 or later */
92 {XmtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *),
93 offset(layout.font), XtRImmediate, (XtPointer) NULL},
94 #endif
95 {XmtNfontList, XmCFontList, XmRFontList, sizeof(XmFontList),
96 offset(layout.font_list), XtRImmediate, (XtPointer) NULL},
97 #if XmVersion >= 2000
98 {XmtNrenderTable, XmCRenderTable, XmRRenderTable,
99 sizeof(XmRenderTable), offset(layout.render_table),
100 XtRImmediate, (XtPointer) NULL},
101 #endif
102 {XmtNdefaultSpacing, XmtCDefaultSpacing, XtRDimension, sizeof(Dimension),
103 offset(layout.default_spacing), XtRImmediate, (XtPointer) 10},
104 {XmtNorientation, XmCOrientation, XmROrientation,
105 sizeof(unsigned char), offset(layout.orientation),
106 XtRImmediate, (XtPointer) XmVERTICAL},
107 {XmtNdebugLayout, XmtCDebugLayout, XtRBoolean,
108 sizeof(Boolean), offset(layout.debug_layout),
109 XtRImmediate, (XtPointer)False},
110 {XmNlosingFocusCallback,XmCCallback,XmRCallback,
111 sizeof (XtCallbackList), offset(layout.losing_focus_callback),
112 XmRImmediate, (XtPointer) NULL},
113 /* override some BulletinBoard defaults */
114 {XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension,
115 sizeof(Dimension),
116 XtOffsetOf(struct _XmBulletinBoardRec, bulletin_board.margin_width),
117 XmRImmediate, (XtPointer)5},
118 {XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension,
119 sizeof(Dimension),
120 XtOffsetOf(struct _XmBulletinBoardRec, bulletin_board.margin_height),
121 XmRImmediate, (XtPointer)5},
122 };
123 #undef offset
124
125 #define offset(field) XtOffsetOf(XmtLayoutConstraintsRec, layout.field)
126 static XtResource constraint_resources[] = {
127 {XmtNlayoutWidth, XmtCLayoutWidth, XtRDimension,
128 sizeof(Dimension), offset(width),
129 XtRImmediate, (XtPointer) 0},
130 {XmtNlayoutHeight, XmtCLayoutHeight, XtRDimension,
131 sizeof(Dimension), offset(height),
132 XtRImmediate, (XtPointer) 0},
133 {XmtNlayoutStretchability, XmtCLayoutStretchability, XtRDimension,
134 sizeof(Dimension), offset(stretchability),
135 XtRImmediate, (XtPointer) -1}, /* dynamic default */
136 {XmtNlayoutShrinkability, XmtCLayoutShrinkability, XtRDimension,
137 sizeof(Dimension), offset(shrinkability),
138 XtRImmediate, (XtPointer) -1}, /* dynamic default */
139 {XmtNlayoutCaption, XmtCLayoutCaption, XmRXmString,
140 sizeof(XmString), offset(caption),
141 XtRImmediate, NULL},
142 {XmtNlayoutIn, XmtCLayoutIn, XtRWidget,
143 sizeof(Object), offset(in),
144 XtRImmediate, (XtPointer) NULL},
145 {XmtNlayoutPosition, XmtCLayoutPosition, XtRPosition,
146 sizeof(Position), offset(position),
147 XtRImmediate, (XtPointer) -1},
148 {XmtNlayoutAfter, XmtCLayoutAfter, XtRWidget,
149 sizeof(Object), offset(after),
150 XtRImmediate, (XtPointer) NULL},
151 {XmtNlayoutBefore, XmtCLayoutBefore, XtRWidget,
152 sizeof(Object), offset(before),
153 XtRImmediate, (XtPointer) NULL},
154 {XmtNlayoutAllowResize, XmtCLayoutAllowResize, XtRBoolean,
155 sizeof(Boolean), offset(allow_resize),
156 XtRImmediate, (XtPointer)True},
157 {XmtNlayoutSensitive, XmtCLayoutSensitive, XtRBoolean,
158 sizeof(Boolean), offset(sensitive),
159 XtRImmediate, (XtPointer)True},
160 {XmtNlayoutJustification, XmtCLayoutJustification, XmtRXmtLayoutJustification,
161 sizeof(unsigned char), offset(justification),
162 XtRImmediate, (XtPointer)XmtLayoutFilled},
163 {XmtNlayoutMarginWidth, XmtCLayoutMarginWidth, XtRUnsignedChar,
164 sizeof(unsigned char), offset(margin_width),
165 XtRImmediate, (XtPointer)255}, /* special unset value */
166 {XmtNlayoutMarginHeight, XmtCLayoutMarginHeight, XtRUnsignedChar,
167 sizeof(unsigned char), offset(margin_height),
168 XtRImmediate, (XtPointer)255}, /* special unset value */
169 {XmtNlayoutFrameType, XmtCLayoutFrameType, XmtRXmtLayoutFrameType,
170 sizeof(unsigned char), offset(frame_type),
171 XtRImmediate, (XtPointer)XmtLayoutFrameNone},
172 {XmtNlayoutFrameLineType, XmtCLayoutFrameLineType, XmtRXmtLayoutFrameLineType,
173 sizeof(unsigned char), offset(frame_line_type),
174 XtRImmediate, (XtPointer)XmtLayoutFrameEtchedIn},
175 {XmtNlayoutFramePosition, XmtCLayoutFramePosition, XmtRXmtLayoutFramePosition,
176 sizeof(unsigned char), offset(frame_position),
177 XtRImmediate, (XtPointer)XmtLayoutFrameInside},
178 {XmtNlayoutFrameMargin, XmtCLayoutFrameMargin, XtRUnsignedChar,
179 sizeof(unsigned char), offset(frame_margin),
180 XtRImmediate, (XtPointer)2},
181 {XmtNlayoutFrameThickness, XmtCLayoutFrameThickness, XtRUnsignedChar,
182 sizeof(unsigned char), offset(frame_thickness),
183 XtRImmediate, (XtPointer)2},
184 {XmtNlayoutCaptionPosition, XmtCLayoutCaptionPosition, XmtRXmtLayoutEdge,
185 sizeof(unsigned char), offset(caption_position),
186 XtRImmediate, (XtPointer)XmtLayoutLeft},
187 {XmtNlayoutCaptionJustification, XmtCLayoutCaptionJustification,
188 XmtRXmtLayoutJustification,
189 sizeof(unsigned char), offset(caption_justification),
190 XtRImmediate, (XtPointer)XmtLayoutCentered},
191 {XmtNlayoutCaptionAlignment, XmtCLayoutCaptionAlignment, XmRAlignment,
192 sizeof(unsigned char), offset(caption_alignment),
193 XtRImmediate, (XtPointer)XmALIGNMENT_BEGINNING},
194 {XmtNlayoutCaptionMargin, XmtCLayoutCaptionMargin, XtRUnsignedChar,
195 sizeof(unsigned char), offset(caption_margin),
196 XtRImmediate, (XtPointer)2},
197 };
198 #undef offset
199
200 #if NeedFunctionPrototypes
201 static void ClassInitialize(void);
202 static void Initialize(Widget, Widget, ArgList, Cardinal *);
203 static void Destroy(Widget);
204 static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
205 static void Resize(Widget);
206 static void Realize(Widget, XtValueMask *, XSetWindowAttributes *);
207 static void Redisplay(Widget, XEvent *, Region);
208 static void ChangeManaged(Widget);
209 static XtGeometryResult GeometryManager(Widget, XtWidgetGeometry *,
210 XtWidgetGeometry *);
211 static XtGeometryResult QueryGeometry(Widget, XtWidgetGeometry *,
212 XtWidgetGeometry *);
213 static void InsertChild(Widget);
214 static void DeleteChild(Widget);
215 static void ConstraintInitialize(Widget, Widget, ArgList, Cardinal *);
216 static void ConstraintDestroy(Widget);
217 static Boolean ConstraintSetValues(Widget,Widget, Widget, ArgList, Cardinal *);
218 static void FocusMoved(Widget,XtPointer,XtPointer);
219 #else
220 static void ClassInitialize();
221 static void Initialize();
222 static void Destroy();
223 static Boolean SetValues();
224 static void Resize();
225 static void Realize();
226 static void Redisplay();
227 static void ChangeManaged();
228 static XtGeometryResult GeometryManager();
229 static XtGeometryResult QueryGeometry();
230 static void InsertChild();
231 static void DeleteChild();
232 static void ConstraintInitialize();
233 static void ConstraintDestroy();
234 static Boolean ConstraintSetValues();
235 static void FocusMoved();
236 #endif
237
238 #define superclass (&xmBulletinBoardClassRec)
239
240 externaldef(xmtlayoutclassrec) XmtLayoutClassRec xmtLayoutClassRec = {
241 { /* core_class fields */
242 /* superclass */ (WidgetClass) superclass,
243 /* class_name */ "XmtLayout",
244 /* widget_size */ sizeof(XmtLayoutRec),
245 /* class_initialize */ ClassInitialize,
246 /* class_part_init */ NULL,
247 /* class_inited */ FALSE,
248 /* initialize */ Initialize,
249 /* initialize_hook */ NULL,
250 /* realize */ Realize,
251 /* actions */ NULL,
252 /* num_actions */ 0,
253 /* resources */ resources,
254 /* num_resources */ XtNumber(resources),
255 /* xrm_class */ NULLQUARK,
256 /* compress_motion */ TRUE,
257 /* compress_exposure */ XtExposeCompressMaximal,
258 /* compress_enterleave*/ TRUE,
259 /* visible_interest */ FALSE,
260 /* destroy */ Destroy,
261 /* resize */ Resize,
262 /* expose */ Redisplay,
263 /* set_values */ SetValues,
264 /* set_values_hook */ NULL,
265 /* set_values_almost */ XtInheritSetValuesAlmost,
266 /* get_values_hook */ NULL,
267 /* accept_focus */ NULL,
268 /* version */ XtVersion,
269 /* callback_private */ NULL,
270 /* tm_table */ XtInheritTranslations,
271 /* query_geometry */ QueryGeometry,
272 /* display_accelerator*/ XtInheritDisplayAccelerator,
273 /* extension */ NULL
274 },
275 { /* composite_class fields */
276 /* geometry_manager */ GeometryManager,
277 /* change_managed */ ChangeManaged,
278 /* insert_child */ InsertChild,
279 /* delete_child */ DeleteChild,
280 /* extension */ NULL
281 },
282 { /* constraint_class fields */
283 /* resource list */ constraint_resources,
284 /* num resources */ XtNumber(constraint_resources),
285 /* constraint size */ sizeof(XmtLayoutConstraintsRec),
286 /* init proc */ ConstraintInitialize,
287 /* destroy proc */ ConstraintDestroy,
288 /* set values proc */ ConstraintSetValues,
289 /* extension */ NULL
290 },
291 { /* manager_class */
292 /* translations */ XtInheritTranslations,
293 /* syn_resources */ NULL,
294 /* num_syn_resources */ 0,
295 /* syn_cont_resources */ NULL,
296 /* num_syn_cont_resources */0,
297 /* parent_process */ XmInheritParentProcess,
298 /* extension */ NULL
299 },
300 { /* Bulletin Board */
301 /* always_install_accelerators */ False,
302 /* geo_matrix_create */ NULL,
303 /* focus_moved_proc */ FocusMoved, /*XmInheritFocusMovedProc,*/
304 /* extension */ NULL
305 },
306 { /* XmtLayout */
307 /* parser */ NULL,
308 /* lookup_type_proc */ NULL,
309 /* create_proc */ NULL,
310 /* extension */ NULL
311 }
312 };
313
314 externaldef(xmtlayoutwidgetclass)
315 WidgetClass xmtLayoutWidgetClass = (WidgetClass) &xmtLayoutClassRec;
316
317 #if NeedFunctionPrototypes
ClassInitialize(void)318 static void ClassInitialize(void)
319 #else
320 static void ClassInitialize()
321 #endif
322 {
323 static String justification_names[] = {
324 "Bottom", "Center", "Centered", "Filled", "Left", "Right", "Top"};
325 static int justification_values[] = {
326 XmtLayoutFlushBottom, XmtLayoutCentered, XmtLayoutCentered,
327 XmtLayoutFilled,XmtLayoutFlushLeft,
328 XmtLayoutFlushRight, XmtLayoutFlushTop};
329 static String justification_prefixes[] = {"Xmt", "Layout", "Flush", NULL};
330
331 static String edge_names[] = {
332 "Bottom", "Left", "Right", "Top"};
333 static int edge_values[] = {
334 XmtLayoutBottom, XmtLayoutLeft, XmtLayoutRight, XmtLayoutTop
335 };
336 static String edge_prefixes[] = {"Xmt", "Layout", NULL};
337
338 static String line_type_names[] = {
339 "Double", "DoubleLine", "Etched", "EtchedIn", "EtchedOut",
340 "Shadow", "ShadowIn", "ShadowOut", "Single", "SingleLine",
341 };
342 static int line_type_values[] = {
343 XmtLayoutFrameDoubleLine, XmtLayoutFrameDoubleLine,
344 XmtLayoutFrameEtchedIn, XmtLayoutFrameEtchedIn,
345 XmtLayoutFrameEtchedOut, XmtLayoutFrameShadowIn,
346 XmtLayoutFrameShadowIn, XmtLayoutFrameShadowOut,
347 XmtLayoutFrameSingleLine, XmtLayoutFrameSingleLine
348 };
349
350 static String frame_type_names[] = {
351 "Bottom", "Box", "Left", "None", "Right", "Top" };
352 static int frame_type_values[] = {
353 XmtLayoutFrameBottom, XmtLayoutFrameBox, XmtLayoutFrameLeft,
354 XmtLayoutFrameNone, XmtLayoutFrameRight, XmtLayoutFrameTop
355 };
356 static String frame_type_prefixes[] = {"Xmt", "Layout", "Frame", NULL};
357
358 static String position_names[] = { "Inside", "Outside", "Through" };
359 static int position_values[] = {
360 XmtLayoutFrameInside, XmtLayoutFrameOutside, XmtLayoutFrameThrough };
361
362 static String space_type_names[] = {
363 "CTabbed", "Even", "Interval", "LCR",
364 "LREven", "LTabbed", "None", "RTabbed"
365 };
366 static int space_type_values[] = {
367 XmtLayoutSpaceCTabbed, XmtLayoutSpaceEven,
368 XmtLayoutSpaceInterval, XmtLayoutSpaceLCR,
369 XmtLayoutSpaceLREven, XmtLayoutSpaceLTabbed,
370 XmtLayoutSpaceNone, XmtLayoutSpaceRTabbed
371 };
372 static String space_type_prefixes[] = {"Xmt", "Layout", "Space", NULL};
373
374 /* A bitmap we use for stippling captions */
375 # define _xmt_gray50_width 32
376 # define _xmt_gray50_height 2
377 static unsigned char _xmt_gray50_bits[] = {
378 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa};
379
380 XmtRegisterEnumConverter(XmtRXmtLayoutJustification,
381 justification_names, justification_values,
382 XtNumber(justification_names),
383 justification_prefixes);
384
385 XmtRegisterEnumConverter(XmtRXmtLayoutEdge,
386 edge_names, edge_values,
387 XtNumber(edge_names),
388 edge_prefixes);
389
390 XmtRegisterEnumConverter(XmtRXmtLayoutFrameLineType,
391 line_type_names, line_type_values,
392 XtNumber(line_type_names),
393 frame_type_prefixes); /* really frame_type here */
394
395 XmtRegisterEnumConverter(XmtRXmtLayoutFrameType,
396 frame_type_names, frame_type_values,
397 XtNumber(frame_type_names),
398 frame_type_prefixes);
399
400 XmtRegisterEnumConverter(XmtRXmtLayoutFramePosition,
401 position_names, position_values,
402 XtNumber(position_names),
403 frame_type_prefixes); /* really */
404
405 XmtRegisterEnumConverter(XmtRXmtLayoutSpaceType,
406 space_type_names, space_type_values,
407 XtNumber(space_type_names),
408 space_type_prefixes);
409
410 XmtRegisterXbmData("_xmt_gray50", (char *)_xmt_gray50_bits, NULL,
411 _xmt_gray50_width, _xmt_gray50_height, 0, 0);
412 }
413
414 #if XmVersion < 2000
415 #if NeedFunctionPrototypes
FontFromFontList(XmtLayoutWidget lw)416 static void FontFromFontList(XmtLayoutWidget lw)
417 #else
418 static void FontFromFontList(lw)
419 XmtLayoutWidget lw;
420 #endif
421 {
422 XmFontContext context;
423 XmStringCharSet charset;
424
425 lw->layout.font_list = XmFontListCopy(lw->layout.font_list);
426 (void)XmFontListInitFontContext(&context, lw->layout.font_list);
427 (void)XmFontListGetNextFont(context, &charset, &lw->layout.font);
428 XmFontListFreeFontContext(context);
429 XtFree(charset);
430 }
431 #endif
432
433 #if NeedFunctionPrototypes
GetGCs(XmtLayoutWidget lw)434 static void GetGCs(XmtLayoutWidget lw)
435 #else
436 static void GetGCs(lw)
437 XmtLayoutWidget lw;
438 #endif
439 {
440 XGCValues gcv;
441 XtGCMask mask;
442
443 /*
444 * we set a font, even though we don't use it because XmStringDraw
445 * frobs the font field and will cause an X error if it is unset.
446 */
447 gcv.foreground = lw->manager.foreground;
448 gcv.background = lw->core.background_pixel;
449 gcv.font = lw->layout.font->fid;
450 gcv.line_width = 0;
451 gcv.graphics_exposures = False;
452 mask = GCForeground | GCBackground | GCFont | GCLineWidth |
453 GCGraphicsExposures;
454 if ((lw->core.background_pixmap != None) &&
455 (lw->core.background_pixmap != XmUNSPECIFIED_PIXMAP))
456 {
457 mask |= GCFillStyle | GCTile;
458 gcv.fill_style = FillTiled;
459 gcv.tile = lw->core.background_pixmap;
460 }
461 lw->layout.gc = XtGetGC((Widget)lw, mask, &gcv);
462
463 /*
464 * We could remember this bitmap and free it when the Layout is destroyed,
465 * but because of caching, this will rarely be worth the trouble.
466 */
467 gcv.fill_style = FillStippled;
468 gcv.stipple = XmtLookupBitmap((Widget)lw, "_xmt_gray50");
469 mask |= GCFillStyle | GCStipple;
470 mask &= ~GCTile;
471
472 lw->layout.grey_gc = XtGetGC((Widget)lw, mask, &gcv);
473 }
474
475 /* ARGSUSED */
476 #if NeedFunctionPrototypes
Initialize(Widget request,Widget init,ArgList args,Cardinal * num_args)477 static void Initialize(Widget request, Widget init,
478 ArgList args, Cardinal *num_args)
479 #else
480 static void Initialize(request, init, args, num_args)
481 Widget request;
482 Widget init;
483 ArgList args;
484 Cardinal *num_args;
485 #endif
486 {
487 XmtLayoutWidget lw = (XmtLayoutWidget) init;
488 Display *dpy = XtDisplay(init);
489 int scr = XScreenNumberOfScreen(XtScreen(init));
490 Arg arg;
491
492 #if XmVersion < 2000
493 /*
494 * Copy the font list resource, and get its first font.
495 * Or, create a font list from the font.
496 */
497 if (lw->layout.font_list)
498 FontFromFontList(lw);
499 else
500 lw->layout.font_list = XmFontListCreate(lw->layout.font,
501 XmSTRING_DEFAULT_CHARSET);
502 #else /* Motif 2.0 or later */
503 if (!lw->layout.render_table) {
504 if (!lw->layout.font_list) {
505 if (lw->layout.font) {
506 Arg args[1];
507 XmRendition rendition;
508
509 /*
510 * If no renderTable or fontList was specified, but there is
511 * a font, then create a renderTable.
512 */
513 XtSetArg(args[0], XmNfont, lw->layout.font);
514 rendition = XmRenditionCreate(init, (XmStringTag)"default",
515 args, 1);
516 lw->layout.render_table =
517 #if (XmVersion >= 2001)
518 XmRenderTableAddRenditions(NULL, &rendition, 1,
519 XmMERGE_REPLACE);
520 #else
521 XmRenderTableAddRenditions(NULL, &rendition, 1, XmREPLACE);
522 #endif
523 }
524 else {
525 /*
526 * Nothing was specified, so look up the default
527 * renderTable.
528 */
529 lw->layout.render_table =
530 XmeGetDefaultRenderTable(init, XmLABEL_FONTLIST);
531
532 /* Make a copy of the renderTable. */
533 lw->layout.render_table =
534 XmRenderTableCopy(lw->layout.render_table, NULL, 0);
535 }
536 }
537 else {
538 /*
539 * There is a fontList, so copy it to the renderTable.
540 * NOTE: This code relies on the fact that there is no
541 * disitinction between a fontList and a renderTable
542 * in Motif 2.0.
543 */
544 lw->layout.render_table = XmFontListCopy(lw->layout.font_list);
545 }
546 }
547 else {
548 /* Make a copy of the renderTable. */
549 lw->layout.render_table =
550 XmRenderTableCopy(lw->layout.render_table, NULL, 0);
551 }
552
553 /*
554 * If no font was explicitly given, extract the default font from
555 * the renderTable.
556 */
557 if (!lw->layout.font)
558 XmeRenderTableGetDefaultFont(lw->layout.render_table,
559 &lw->layout.font);
560 #endif
561
562 /* figure out resolution independence values */
563 lw->layout.pixpermm =(DisplayWidth(dpy,scr)/DisplayWidthMM(dpy,scr) +
564 DisplayHeight(dpy,scr)/DisplayHeightMM(dpy,scr)) / 2;
565 lw->layout.pixperem = XTextWidth(lw->layout.font, "M", 1);
566
567
568 /* get a GC for use by our gadget children */
569 GetGCs(lw);
570
571 /* initialize misc. variables */
572 lw->layout.needs_layout = False;
573 lw->layout.layout_disabled = 0;
574
575 lw->layout.in_parser = False;
576 lw->layout.geometry_okay = False;
577 lw->layout.widget_info = NULL;
578
579 /*
580 * create the toplevel XmtLayoutBox gadget.
581 */
582 lw->layout.in_parser = True;
583 XtSetArg(arg, XmtNorientation, lw->layout.orientation);
584 /*
585 * got to initialize it to NULL first in order to detect
586 * this special case in ConstraintInitialize
587 */
588 lw->layout.toplevel = NULL;
589 lw->layout.toplevel = XmtCreateLayoutBox(init, "topbox", &arg, 1);
590 XtManageChild(lw->layout.toplevel);
591
592 /*
593 * go parse the layout string, if any.
594 * We don't copy this string because we parse it once
595 * and never need it again.
596 */
597 if (lw->layout.layout) {
598 if (xmtLayoutClassRec.layout_class.parser == NULL)
599 XmtWarningMsg("XmtLayout", "noParser",
600 "%s: no parser registered for layout string.\n\tSee XmtRegisterLayoutParser().",
601 XtName((Widget)lw));
602 else
603 (*xmtLayoutClassRec.layout_class.parser)(lw, lw->layout.layout);
604 }
605 lw->layout.in_parser = False;
606
607 /*
608 * go layout any children that were automatically created by
609 * parsing the layout string, but don't issue a resize request for
610 * the desired size. If width and height are not set, we set them
611 * from the preferred size.
612 */
613 _XmtLayoutChildren(lw, True);
614 if (lw->core.width == 0)
615 lw->core.width = LayoutConstraints(lw->layout.toplevel).pref_w +
616 2*lw->bulletin_board.margin_width;
617
618 if (lw->core.height == 0)
619 lw->core.height = LayoutConstraints(lw->layout.toplevel).pref_h +
620 2*lw->bulletin_board.margin_height;
621 }
622
623 #if NeedFunctionPrototypes
Destroy(Widget w)624 static void Destroy(Widget w)
625 #else
626 static void Destroy(w)
627 Widget w;
628 #endif
629 {
630 XmtLayoutWidget lw = (XmtLayoutWidget) w;
631
632 #if XmVersion < 2000
633 if (lw->layout.font_list) XmFontListFree(lw->layout.font_list);
634 #else /* Motif 2.0 or later */
635 if (lw->layout.render_table) XmRenderTableFree(lw->layout.render_table);
636 #endif
637
638 XtReleaseGC(w, lw->layout.gc);
639 XtReleaseGC(w, lw->layout.grey_gc);
640 }
641
642 #if NeedFunctionPrototypes
Realize(Widget w,XtValueMask * vm,XSetWindowAttributes * wa)643 static void Realize(Widget w, XtValueMask *vm, XSetWindowAttributes *wa)
644 #else
645 static void Realize(w, vm, wa)
646 Widget w;
647 XtValueMask *vm;
648 XSetWindowAttributes *wa;
649 #endif
650 {
651 XmtLayoutWidget lw = (XmtLayoutWidget)w;
652 Widget *children;
653 Cardinal num;
654 int i;
655
656 /*
657 * Because Motif (1.1, at least) treats all RectObjs as XmGadgets,
658 * we've had to make LayoutGadgets a subclass of Object that just
659 * happen to have many of the same fields as RectObj. There are
660 * a number of hacks here to support this--see the redefinition of
661 * XtIsManaged(), and XmtSetRectObj(), for example, in LayoutP.h
662 *
663 * This is another of those hacks--when the Layout is realized with
664 * only gadget children (as can happen with the XmtWorkingBox, e.g.)
665 * the Intrinsics decide that it has no managed children, and never
666 * invoke the ChangeManaged procedure. We attempt to compensate for
667 * that here.
668 */
669 children = lw->composite.children;
670 num = lw->composite.num_children;
671 for(i=0; i < num; i++)
672 if (XtIsManaged(children[i]) &&
673 (XtIsWidget(children[i]) || !XmtIsLayoutGadget(children[i])))
674 break;
675 if (i == num)
676 ChangeManaged(w);
677
678 /*
679 * And now envelop our superclass's realize method, so we
680 * actually get realized.
681 */
682 (*superclass->core_class.realize)(w, vm, wa);
683 }
684
685 /* ARGSUSED */
686 #if NeedFunctionPrototypes
SetValues(Widget current,Widget request,Widget set,ArgList args,Cardinal * num_args)687 static Boolean SetValues(Widget current, Widget request, Widget set,
688 ArgList args, Cardinal *num_args)
689 #else
690 static Boolean SetValues(current, request, set, args, num_args)
691 Widget current;
692 Widget request;
693 Widget set;
694 ArgList args;
695 Cardinal *num_args;
696 #endif
697 {
698 XmtLayoutWidget cw = (XmtLayoutWidget) current;
699 XmtLayoutWidget nw = (XmtLayoutWidget) set;
700 Boolean got_new_gc = False;
701 Boolean relayout = False;
702 Boolean redisplay = False;
703
704 #define Changed(field) (nw->layout.field != cw->layout.field)
705
706 /* can't change XmtNlayout */
707 if (Changed(layout)) {
708 XmtWarningMsg("XmtLayout", "setlayout",
709 "%s: the XmtNlayout resource may not be changed.",
710 XtName(set));
711 nw->layout.layout = cw->layout.layout;
712 }
713
714 /* can't change XmtNorientation */
715 if (Changed(orientation)) {
716 XmtWarningMsg("XmtLayout", "setorient",
717 "%s: the XmtNorientation resource may not be changed.",
718 XtName(set));
719 nw->layout.orientation = cw->layout.orientation;
720 }
721
722 #if XmVersion < 2000
723 /*
724 * if fontlist or font changes, free old and figure out the other one.
725 */
726 if (Changed(font_list)) {
727 XmFontListFree(cw->layout.font_list);
728 FontFromFontList(nw);
729 }
730 else if (Changed(font)) {
731 XmFontListFree(cw->layout.font_list);
732 nw->layout.font_list = XmFontListCreate(nw->layout.font,
733 XmSTRING_DEFAULT_CHARSET);
734 }
735 #else /* Motif 2.0 or later */
736 if (Changed(render_table) || !nw->layout.font) {
737 XmRenderTableFree(cw->layout.render_table);
738 if (nw->layout.render_table == NULL) {
739 nw->layout.render_table =
740 XmeGetDefaultRenderTable(set, XmLABEL_FONTLIST);
741 }
742 nw->layout.render_table =
743 XmRenderTableCopy(nw->layout.render_table, NULL, 0);
744 /* unset the font, so it will be recomputed below */
745 nw->layout.font = NULL;
746 }
747 else if (Changed(font_list)) {
748 XmRenderTableFree(cw->layout.render_table);
749 if (nw->layout.font_list == NULL) {
750 nw->layout.font_list =
751 XmeGetDefaultRenderTable(set, XmLABEL_FONTLIST);
752 }
753 nw->layout.render_table = XmFontListCopy(nw->layout.font_list);
754 /* unset the font, so it will be recomputed below */
755 nw->layout.font = NULL;
756 }
757 else if (Changed(font)) {
758 Arg args[1];
759 XmRendition rendition;
760
761 XmRenderTableFree(cw->layout.render_table);
762
763 XtSetArg(args[0], XmNfont, nw->layout.font);
764 rendition = XmRenditionCreate(set, (XmStringTag)"default",
765 args, 1);
766 nw->layout.render_table =
767 #if (XmVersion >= 2001)
768 XmRenderTableAddRenditions(NULL, &rendition, 1, XmMERGE_REPLACE);
769 #else
770 XmRenderTableAddRenditions(NULL, &rendition, 1, XmREPLACE);
771 #endif
772 }
773
774 if (!nw->layout.font)
775 /* Extract the default font from the renderTable. */
776 XmeRenderTableGetDefaultFont(nw->layout.render_table,
777 &nw->layout.font);
778 #endif
779
780 /*
781 * if the font list changed through either of the above cases,
782 * get a new GC, change resolution independence values,
783 * invoke the change_font method on all LayoutStringGadget children,
784 * and re-measure all caption strings.
785 */
786 #if XmVersion < 2000
787 if (Changed(font_list)) {
788 #else /* Motif 2.0 or later */
789 if (Changed(render_table)) {
790 #endif
791 int i;
792 Widget child;
793 XmtLayoutConstraintsPart *c;
794
795 XtReleaseGC(set, cw->layout.gc);
796 XtReleaseGC(set, cw->layout.grey_gc);
797 GetGCs(nw);
798 got_new_gc = True;
799
800 /*
801 * we can compute new resolution independence conversion values,
802 * but we cannot go update all the children that had their size
803 * based on the font...
804 */
805 nw->layout.pixperem = XTextWidth(nw->layout.font, "M", 1);
806
807 /*
808 * tell any LayoutGadget children that care about the change.
809 * This is a hardcoded dependency which is a little gross.
810 * It means that we don't have to keep a bunch of copies of
811 * the same fontlist around, however.
812 */
813 for(i=0; i < nw->composite.num_children; i++) {
814 child = nw->composite.children[i];
815 c = LayoutConstraintsRec(child);
816 if (!XtIsWidget(child) && !XmIsGadget(child)
817 && XtIsSubclass(child, xmtLayoutGadgetClass))
818 _XmtCallChangeFontMethod(child);
819 if (c->caption) {
820 #if XmVersion < 2000
821 XmStringExtent(nw->layout.font_list, c->caption,
822 &c->caption_width, &c->caption_height);
823 #else /* Motif 2.0 or later */
824 XmStringExtent(nw->layout.render_table, c->caption,
825 &c->caption_width, &c->caption_height);
826 #endif
827 }
828 }
829
830 relayout = True;
831 }
832
833 if (Changed(debug_layout))
834 relayout = True;
835
836 /* if colors changed and we haven't already done so, get a new gc */
837 if (!got_new_gc &&
838 ((nw->core.background_pixel != cw->core.background_pixel) ||
839 (nw->manager.foreground != cw->manager.foreground))) {
840 XtReleaseGC(set, cw->layout.gc);
841 XtReleaseGC(set, cw->layout.grey_gc);
842 GetGCs(nw);
843 redisplay = True;
844 }
845
846 /* if margin size changed, re-layout everything */
847 if ((nw->bulletin_board.margin_width != cw->bulletin_board.margin_width) ||
848 (nw->bulletin_board.margin_height != cw->bulletin_board.margin_height))
849 relayout = True;
850
851 /* if sensitivity changed, redisplay everything to change captions */
852 if (nw->core.sensitive != cw->core.sensitive) redisplay = True;
853
854 if (relayout)
855 _XmtLayoutChildren(nw, True);
856
857 return redisplay | relayout;
858
859 #undef Changed
860 }
861
862 #if NeedFunctionPrototypes
_XmtLayoutChildren(XmtLayoutWidget lw,XmtWideBoolean resize)863 void _XmtLayoutChildren(XmtLayoutWidget lw, XmtWideBoolean resize)
864 #else
865 void _XmtLayoutChildren(lw, resize)
866 XmtLayoutWidget lw;
867 int resize;
868 #endif
869 {
870 XtWidgetGeometry geometry;
871
872 /* don't do anything if we've been told not to,
873 * but remember to later
874 */
875 if (lw->layout.layout_disabled > 0) {
876 lw->layout.needs_layout = True;
877 return;
878 }
879
880 /*
881 * figure out how big we'd like to be.
882 * the gadget's query_geometry methods also do other necessary
883 * computation, so this must be called before the resize method...
884 */
885 XtQueryGeometry(lw->layout.toplevel, NULL, &geometry);
886
887 /* XXX
888 * Under some circumstances, this query may return a width and height
889 * of 0. If the margins are zero as well, the call to
890 * XtMakeResizeRequest() below will cause an X Error. So we ensure
891 * that this never happens. Note that it is probably a bug that is
892 * making the query return a 0,0 size, but it can't hurt to be safe here...
893 */
894 if (geometry.width == 0) geometry.width = 1;
895 if (geometry.height == 0) geometry.height = 1;
896
897 /* remember this preferred size */
898 LayoutConstraints(lw->layout.toplevel).pref_w = geometry.width;
899 LayoutConstraints(lw->layout.toplevel).pref_h = geometry.height;
900
901 /* add a margin all the way around */
902 geometry.width += 2*lw->bulletin_board.margin_width;
903 geometry.height += 2*lw->bulletin_board.margin_height;
904
905 /* ask for size plus margins unless we're being called from Resize */
906 if (resize &&
907 ((geometry.width != lw->core.width) ||
908 (geometry.height != lw->core.height))) {
909 XtGeometryResult result;
910 Dimension compromisew, compromiseh;
911 Dimension requestedw, requestedh;
912
913 requestedw = lw->core.width;
914 requestedh = lw->core.height;
915
916 if (lw->bulletin_board.resize_policy == XmRESIZE_ANY) {
917 requestedw = geometry.width;
918 requestedh = geometry.height;
919 } else if (lw->bulletin_board.resize_policy == XmRESIZE_GROW) {
920 if (requestedw < geometry.width) {
921 requestedw = geometry.width;
922 }
923 if (requestedh < geometry.height) {
924 requestedh = geometry.height;
925 }
926 }
927 result = XtMakeResizeRequest((Widget)lw,
928 requestedw, requestedh,
929 &compromisew, &compromiseh);
930 if (result == XtGeometryAlmost)
931 XtMakeResizeRequest((Widget)lw,compromisew,compromiseh,NULL, NULL);
932 }
933
934 /*
935 * Whether we got a new size or not, configure all the kids
936 * to the current size.
937 * If the size hasn't changed, this call is a no-op.
938 * This means that when we're called from changeManaged, often
939 * nothing is called, and the new widget doesn't get configured
940 * to appear in the right place. To work around this, we explictly
941 * set the width on the toplevel box to something different.
942 */
943 lw->layout.toplevel->core.width = 0;
944 XtConfigureWidget(lw->layout.toplevel,
945 lw->bulletin_board.margin_width,
946 lw->bulletin_board.margin_height,
947 lw->core.width - 2*lw->bulletin_board.margin_width,
948 lw->core.height - 2*lw->bulletin_board.margin_height,
949 lw->layout.toplevel->core.border_width);
950
951 lw->layout.needs_layout = False;
952
953 /*
954 * When the Layout contains a lot of layout gadgets, this relayout
955 * process will cause a lot of XClearArea() expose events. For
956 * complicated layouts, the Intrinsics may call the Expose() method
957 * before all the events have arrived and been put in the queue.
958 * Adding a call to XSync() here seems to help with this problem
959 * in some cases.
960 */
961 XSync(XtDisplay(lw), False);
962 }
963
964
965 #if NeedFunctionPrototypes
DrawFrame(XmtLayoutWidget lw,XmtLayoutFrameType type,XmtLayoutFrameLineType linetype,int thickness,int x,int y,int w,int h)966 static void DrawFrame(XmtLayoutWidget lw, XmtLayoutFrameType type,
967 XmtLayoutFrameLineType linetype,
968 int thickness, int x, int y, int w, int h)
969 #else
970 static void DrawFrame(lw, type, linetype, thickness, x, y, w, h)
971 XmtLayoutWidget lw;
972 XmtLayoutFrameType type;
973 XmtLayoutFrameLineType linetype;
974 int thickness;
975 int x;
976 int y;
977 int w;
978 int h;
979 #endif
980 {
981 Display *dpy = XtDisplay((Widget)lw);
982 Window win = XtWindow((Widget)lw);
983 Boolean horizontal = False;
984 GC topgc = lw->manager.top_shadow_GC;
985 GC botgc = lw->manager.bottom_shadow_GC;
986 GC tmpgc; /* for swapping */
987 int halfthick = thickness/2;
988
989 if (type == XmtLayoutFrameNone) return;
990
991 if (type == XmtLayoutFrameTop || type == XmtLayoutFrameBottom)
992 horizontal = True;
993
994 if (thickness == 1) linetype = XmtLayoutFrameSingleLine;
995
996 if (linetype == XmtLayoutFrameSingleLine) {
997 XGCValues values;
998
999 if (thickness > 1) {
1000 values.line_width = thickness;
1001 XChangeGC(dpy, lw->layout.gc, GCLineWidth, &values);
1002 }
1003
1004 if ((lw->core.background_pixmap != None) &&
1005 (lw->core.background_pixmap != XmUNSPECIFIED_PIXMAP)) {
1006 XSetFillStyle(dpy, lw->layout.gc, FillSolid);
1007 }
1008 if (type == XmtLayoutFrameBox)
1009 XDrawRectangle(dpy, win, lw->layout.gc,
1010 x+halfthick, y+halfthick,
1011 w-thickness, h-thickness);
1012 else if (horizontal)
1013 XDrawLine(dpy, win, lw->layout.gc,
1014 x, y+halfthick, x+w, y+halfthick);
1015 else
1016 XDrawLine(dpy, win, lw->layout.gc,
1017 x+halfthick, y, x+halfthick, y+h);
1018
1019 if (thickness > 1) {
1020 values.line_width = 0;
1021 XChangeGC(dpy, lw->layout.gc, GCLineWidth, &values);
1022 }
1023 }
1024 else if (linetype == XmtLayoutFrameDoubleLine)
1025 {
1026 if (type == XmtLayoutFrameBox) {
1027 XDrawRectangle(dpy, win, lw->layout.gc, x, y, w-1, h-1);
1028 XDrawRectangle(dpy, win, lw->layout.gc,
1029 x+thickness-1, y+thickness-1,
1030 w-2*(thickness-1)-1, h-2*(thickness-1)-1);
1031 }
1032 else if (horizontal) {
1033 XDrawLine(dpy, win, lw->layout.gc, x, y, x+w, y);
1034 XDrawLine(dpy, win, lw->layout.gc,
1035 x, y+thickness-1, x+w, y+thickness-1);
1036 }
1037 else {
1038 XDrawLine(dpy, win, lw->layout.gc, x, y, x, y+h);
1039 XDrawLine(dpy, win, lw->layout.gc,
1040 x+thickness-1, y, x+thickness-1, y+h);
1041 }
1042 }
1043 else {
1044 if (type == XmtLayoutFrameBox) {
1045 #if XmVersion >= 1002
1046 {
1047 int xmtype;
1048
1049 switch(linetype) {
1050 case XmtLayoutFrameShadowIn:
1051 xmtype = XmSHADOW_IN;
1052 break;
1053 case XmtLayoutFrameShadowOut:
1054 xmtype = XmSHADOW_OUT;
1055 break;
1056 default:
1057 case XmtLayoutFrameEtchedIn:
1058 xmtype = XmSHADOW_ETCHED_IN;
1059 break;
1060 case XmtLayoutFrameEtchedOut:
1061 xmtype = XmSHADOW_ETCHED_OUT;
1062 break;
1063 }
1064 #if XmVersion >= 2000
1065 XmeDrawShadows(dpy, win, topgc, botgc,
1066 x, y, w, h, thickness, xmtype);
1067 #else
1068 _XmDrawShadows(dpy, win, topgc, botgc,
1069 x, y, w, h, thickness, xmtype);
1070 #endif
1071 }
1072 #else
1073 {
1074 int roundthick = halfthick*2;
1075
1076 if (linetype == XmtLayoutFrameShadowIn ||
1077 linetype == XmtLayoutFrameEtchedIn) {
1078 tmpgc = botgc;
1079 botgc = topgc;
1080 topgc = tmpgc;
1081 }
1082
1083 switch(linetype) {
1084 case XmtLayoutFrameShadowOut:
1085 case XmtLayoutFrameShadowIn:
1086 _XmDrawShadow(dpy, win, topgc, botgc, thickness,
1087 x, y, w, h);
1088 break;
1089 case XmtLayoutFrameEtchedOut:
1090 case XmtLayoutFrameEtchedIn:
1091 _XmDrawShadow(dpy, win, topgc, botgc, halfthick,
1092 x, y, w, h);
1093 _XmDrawShadow(dpy, win, botgc, topgc, halfthick,
1094 x+halfthick, y+halfthick,
1095 w-roundthick, h-roundthick);
1096 break;
1097 default:
1098 break;
1099 }
1100 }
1101 #endif
1102 }
1103 else { /* draw an etched line in or out */
1104 if (linetype == XmtLayoutFrameShadowIn)
1105 linetype = XmtLayoutFrameEtchedIn;
1106 if (linetype == XmtLayoutFrameShadowOut)
1107 linetype = XmtLayoutFrameEtchedOut;
1108 if (linetype == XmtLayoutFrameEtchedIn) {
1109 tmpgc = botgc;
1110 botgc = topgc;
1111 topgc = tmpgc;
1112 }
1113 if (horizontal) {
1114 XFillRectangle(dpy, win, topgc, x, y, w, halfthick);
1115 XFillRectangle(dpy, win, botgc,
1116 x, y+halfthick, w, thickness-halfthick);
1117 }
1118 else {
1119 XFillRectangle(dpy, win, topgc, x, y, halfthick, h);
1120 XFillRectangle(dpy, win, botgc,
1121 x+halfthick, y, thickness-halfthick, h);
1122 }
1123 }
1124 }
1125 }
1126
1127
1128 #if NeedFunctionPrototypes
DrawFrameAndCaption(XmtLayoutWidget lw,Widget c,Region region,Boolean clear)1129 static void DrawFrameAndCaption(XmtLayoutWidget lw, Widget c, Region region, Boolean clear)
1130 #else
1131 static void DrawFrameAndCaption(lw, c, region, clear)
1132 XmtLayoutWidget lw;
1133 Widget c;
1134 Region region;
1135 Boolean clear;
1136 #endif
1137 {
1138 XmtLayoutConstraintsPart *cc;
1139 int x, y, w, h; /* coordinates of widget */
1140 int fx, fy, fw, fh; /* coordinates of outside of frame */
1141 int cx, cy, cw, ch; /* coordinates of caption bounding box*/
1142 XmtLayoutFrameType frame_type;
1143 XmtLayoutFrameLineType frame_line_type;
1144 int frame_thickness;
1145 int frame_margin;
1146 XmtLayoutFramePosition frame_position;
1147 int frame_total;
1148 int caption_total_width, caption_total_height;
1149 Boolean frame_redrawn;
1150
1151 /*
1152 * For the specified child widget:
1153 * compute the position of the frame and caption. If the frame intersects
1154 * the region, redraw it. If the caption intersects the region, or
1155 * if the frame intersects the caption and the frame was redrawn, then
1156 * redraw the caption
1157 */
1158
1159 cc = LayoutConstraintsRec(c);
1160
1161 /* get the frame args. If debug_layout is set, force fixed values */
1162 frame_type = cc->frame_type;
1163 frame_line_type = cc->frame_line_type;
1164 frame_margin = cc->frame_margin;
1165 frame_thickness = cc->frame_thickness;
1166 frame_position = cc->frame_position;
1167 if (lw->layout.debug_layout) {
1168 frame_type = XmtLayoutFrameBox;
1169 frame_line_type = XmtLayoutFrameSingleLine;
1170 frame_margin = 5;
1171 frame_thickness = 1;
1172 frame_position = XmtLayoutFrameOutside;
1173 }
1174
1175 frame_total = frame_margin + frame_thickness;
1176 if (cc->caption) {
1177 caption_total_width = cc->caption_width + cc->caption_margin;
1178 caption_total_height = cc->caption_height + cc->caption_margin;
1179 }
1180
1181 /* if no frame or caption, don't do anything */
1182 if (cc->caption == NULL && frame_type == XmtLayoutFrameNone)
1183 return;
1184
1185 /* widget coordinates */
1186 x = c->core.x; y = c->core.y; w = c->core.width; h = c->core.height;
1187
1188 /* compute coordinates of outside of frame */
1189 if (frame_type != XmtLayoutFrameNone) {
1190 fx = x - frame_total;
1191 fy = y - frame_total;
1192 fw = w + 2*frame_total;
1193 fh = h + 2*frame_total;
1194 if (cc->caption &&
1195 (frame_position == XmtLayoutFrameOutside)) {
1196 switch (cc->caption_position) {
1197 case XmtLayoutTop:
1198 fy -= caption_total_height;
1199 /* note no break statement */
1200 case XmtLayoutBottom:
1201 fh += caption_total_height;
1202 break;
1203 case XmtLayoutLeft:
1204 fx -= caption_total_width;
1205 /* note no break statement */
1206 case XmtLayoutRight:
1207 fw += caption_total_width;
1208 break;
1209 }
1210 }
1211 }
1212
1213 /* if the frame is just a line rather than a box, adjust coords */
1214 /* (x,y) will be top left of line, now, not outside of frame */
1215 switch(frame_type) {
1216 case XmtLayoutFrameBottom:
1217 fy += fh - frame_thickness;
1218 /* note: no break statement */
1219 case XmtLayoutFrameTop:
1220 fx += frame_total;
1221 fw -= 2*frame_total;
1222 break;
1223 case XmtLayoutFrameRight:
1224 fx += fw - frame_thickness;
1225 /* note: no break */
1226 case XmtLayoutFrameLeft:
1227 fy += frame_total;
1228 fh -= 2*frame_total;
1229 break;
1230 default: break;
1231 }
1232
1233 /* compute coordinates of caption bounding box */
1234 if (cc->caption) {
1235 /* width and height are given */
1236 cw = cc->caption_width;
1237 ch = cc->caption_height;
1238
1239 /* compute one dimension based on position */
1240 switch (cc->caption_position) {
1241 case XmtLayoutTop:
1242 cy = y - (cc->caption_margin + ch);
1243 break;
1244 case XmtLayoutBottom:
1245 cy = y + h + cc->caption_margin;
1246 break;
1247 case XmtLayoutLeft:
1248 cx = x - (cc->caption_margin + cw);
1249 break;
1250 case XmtLayoutRight:
1251 cx = x + w + cc->caption_margin;
1252 break;
1253 }
1254
1255 /* compute the other dimension based on justification */
1256 if ((cc->caption_position == XmtLayoutTop) ||
1257 (cc->caption_position == XmtLayoutBottom)) {
1258 switch (cc->caption_justification) {
1259 case XmtLayoutFilled:
1260 case XmtLayoutFlushLeft: cx = x; break;
1261 case XmtLayoutCentered: cx = x + (w - cw)/2; break;
1262 case XmtLayoutFlushRight: cx = x + w - cw; break;
1263 }
1264 }
1265 else if ((cc->caption_position == XmtLayoutLeft) ||
1266 (cc->caption_position == XmtLayoutRight)) {
1267 switch (cc->caption_justification) {
1268 case XmtLayoutFilled:
1269 case XmtLayoutFlushLeft: cy = y; break;
1270 case XmtLayoutCentered: cy = y + (h - ch)/2; break;
1271 case XmtLayoutFlushRight: cy = y + h - ch; break;
1272 }
1273 }
1274
1275 /* if there is a frame inside the caption, adjust position */
1276 if ((frame_type != XmtLayoutFrameNone) &&
1277 (frame_position == XmtLayoutFrameInside)) {
1278
1279 /* adjustments for full frames */
1280 if (frame_type == XmtLayoutFrameBox) {
1281 switch (cc->caption_position) {
1282 case XmtLayoutTop: cy -= frame_total; break;
1283 case XmtLayoutBottom: cy += frame_total; break;
1284 case XmtLayoutLeft: cx -= frame_total; break;
1285 case XmtLayoutRight: cx += frame_total; break;
1286 }
1287
1288 if ((cc->caption_position == XmtLayoutTop) ||
1289 (cc->caption_position == XmtLayoutBottom)) {
1290 switch (cc->caption_justification) {
1291 case XmtLayoutFilled:
1292 case XmtLayoutFlushLeft: cx -= frame_total; break;
1293 case XmtLayoutCentered: break;
1294 case XmtLayoutFlushRight: cx += frame_total; break;
1295 }
1296 }
1297 else if ((cc->caption_position == XmtLayoutLeft) ||
1298 (cc->caption_position == XmtLayoutRight)) {
1299 switch (cc->caption_justification) {
1300 case XmtLayoutFilled:
1301 case XmtLayoutFlushLeft: cy -= frame_total; break;
1302 case XmtLayoutCentered: break;
1303 case XmtLayoutFlushRight: cy += frame_total; break;
1304 }
1305 }
1306 }
1307 else if (frame_type == XmtLayoutFrameLeft) {
1308 if (cc->caption_position == XmtLayoutLeft)
1309 cx -= frame_total;
1310 }
1311 else if (frame_type == XmtLayoutFrameRight) {
1312 if (cc->caption_position == XmtLayoutRight)
1313 cx += frame_total;
1314 }
1315 else if (frame_type == XmtLayoutFrameTop) {
1316 if (cc->caption_position == XmtLayoutTop)
1317 cy -= frame_total;
1318 }
1319 else if (frame_type == XmtLayoutFrameBottom) {
1320 if (cc->caption_position == XmtLayoutBottom)
1321 cy += frame_total;
1322 }
1323 }
1324 }
1325
1326 /* if there is a frame, and it is in the exposed region, redraw it */
1327 frame_redrawn = False;
1328 if ((frame_type != XmtLayoutFrameNone) &&
1329 (!region || (XRectInRegion(region, fx, fy, fw, fh) != RectangleOut))) {
1330 frame_redrawn = True;
1331 DrawFrame(lw, frame_type, frame_line_type, frame_thickness,
1332 fx, fy, fw, fh);
1333 }
1334
1335 /*
1336 * if there is a caption, and it is in the exposed region,
1337 * or if it intersects the frame and the frame was redrawn
1338 * then redraw it.
1339 */
1340 if (cc->caption &&
1341 (!region ||
1342 (XRectInRegion(region, cx, cy, cw, ch) != RectangleOut) ||
1343 (frame_redrawn && (frame_position == XmtLayoutFrameThrough)))) {
1344 /* X protocol ignores stippling with DrawImage functions,
1345 * so we simulate XmStringDrawImage by clearing first
1346 *
1347 * This is, of course, not needed if this is due to an Expose.
1348 */
1349 if (clear || (frame_redrawn && frame_position == XmtLayoutFrameThrough)) {
1350
1351 XClearArea(XtDisplay((Widget)lw), XtWindow((Widget)lw),
1352 cx, cy, cw, ch, False);
1353 }
1354 /* Lazy here: instead of having a separate GC for text,
1355 just change FillStyle if there is a background pixmap
1356 */
1357 if (lw->core.background_pixmap != None &&
1358 lw->core.background_pixmap != XmUNSPECIFIED_PIXMAP)
1359 {
1360 XSetFillStyle(XtDisplay((Widget)lw), lw->layout.gc, FillSolid);
1361 }
1362 XmStringDraw(XtDisplay((Widget)lw), XtWindow((Widget)lw),
1363 #if XmVersion < 2000
1364 lw->layout.font_list,
1365 #else /* Motif 2.0 or later */
1366 lw->layout.render_table,
1367 #endif
1368 cc->caption,
1369 (lw->core.ancestor_sensitive &&
1370 lw->core.sensitive &&
1371 cc->sensitive)
1372 ?lw->layout.gc
1373 :lw->layout.grey_gc,
1374 cx, cy, cw,
1375 cc->caption_alignment,
1376 XmSTRING_DIRECTION_L_TO_R, NULL);
1377 if (lw->core.background_pixmap != None &&
1378 lw->core.background_pixmap != XmUNSPECIFIED_PIXMAP)
1379 {
1380 XSetFillStyle(XtDisplay((Widget)lw), lw->layout.gc, FillTiled);
1381 }
1382 }
1383 }
1384
1385
1386 #if NeedFunctionPrototypes
DrawFramesAndCaptions(XmtLayoutWidget lw,Region region)1387 static void DrawFramesAndCaptions(XmtLayoutWidget lw, Region region)
1388 #else
1389 static void DrawFramesAndCaptions(lw, region)
1390 XmtLayoutWidget lw;
1391 Region region;
1392 #endif
1393 {
1394 int i;
1395 Widget c;
1396
1397 /*
1398 * For each child widget:
1399 * compute the position of the frame and caption. If the frame intersects
1400 * the region, redraw it. If the caption intersects the region, or
1401 * if the frame intersects the caption and the frame was redrawn, then
1402 * redraw the caption
1403 */
1404
1405 ForEachChild(lw, c)
1406 if (XtIsManaged(c))
1407 DrawFrameAndCaption(lw, c, region, False);
1408 }
1409
1410 #if NeedFunctionPrototypes
Redisplay(Widget widget,XEvent * event,Region region)1411 static void Redisplay(Widget widget, XEvent *event, Region region)
1412 #else
1413 static void Redisplay(widget, event, region)
1414 Widget widget;
1415 XEvent *event;
1416 Region region;
1417 #endif
1418 {
1419 XmtLayoutWidget lw = (XmtLayoutWidget) widget;
1420
1421 /* invoke the Redisplay method of the topmost XmtLayoutBox */
1422 _XmtRedisplayGadget(lw->layout.toplevel, event, region);
1423
1424 /* redisplay any Xm Gadgets */
1425 _XmtRedisplayGadgets(widget, event, region);
1426
1427 /* go draw all the XmtLayout frames and captions */
1428 DrawFramesAndCaptions(lw, region);
1429 }
1430
1431 #if NeedFunctionPrototypes
Resize(Widget w)1432 static void Resize(Widget w)
1433 #else
1434 static void Resize(w)
1435 Widget w;
1436 #endif
1437 {
1438 if (XtIsRealized(w)) XClearWindow(XtDisplay(w), XtWindow(w));
1439 _XmtLayoutChildren((XmtLayoutWidget) w, False);
1440 }
1441
1442 #if NeedFunctionPrototypes
ChangeManaged(Widget w)1443 static void ChangeManaged(Widget w)
1444 #else
1445 static void ChangeManaged(w)
1446 Widget w;
1447 #endif
1448 {
1449 _XmtLayoutChildren((XmtLayoutWidget) w, True);
1450 }
1451
1452
1453
1454
1455 /*
1456 * This GeometryManager() method is invoked in two distinct cases.
1457 * 1) When a child widget calls XtMakeGeometryRequest() to change something.
1458 * In this case, we deny the request if XmtNlayoutAllowResize if False,
1459 * or if the child is trying to change its position, rather than its size.
1460 * Otherwise we grant the request. When we grant this request, we call
1461 * _XmtLayoutChildren() to configure the widget (and any of its siblings
1462 * that change as a result, and return XtGeometryDone. The algorithm in
1463 * this case is modified from the Xaw Form widget.
1464 * 2) When the user sets a resource on a child that directly or indirectly
1465 * changes a geometry field of the widget. After a SetValues() request,
1466 * the Intrinsics automatically call this method if any geometry fields
1467 * have changed. In this case, the ConstraintSetValues() method will
1468 * always be called before this method is. We have to handle this case
1469 * specially because of the constraint resources. If the XmtNlayoutIn
1470 * constraint is set, for example, then the CSV method will call
1471 * _XmtLayoutChildren() to rearrange things. This means that the position
1472 * of the child widget will change, and this change will be legal. If
1473 * we didn't have a special case, the change would be rejected. Also,
1474 * since _XmtLayoutChildren() has already been called, we know that we
1475 * don't have to call it again here. We do have to call XtConfigureWidget()
1476 * however--when ConstraintSetValues() calls _XmtLayoutChildren(),
1477 * the geometry fields of the widget are set at their new values, and so
1478 * when _XmtLayoutChildren() tries to configure the widget to those
1479 * new values (in the resize() method of LayoutBox.c), the Intrinsics
1480 * will think that it doesn't have to do anything.
1481 * Note the use of the geometry_okay flag for communication between
1482 * the CSV method and this method.
1483 */
1484 /* ARGSUSED */
1485 #if NeedFunctionPrototypes
GeometryManager(Widget w,XtWidgetGeometry * request,XtWidgetGeometry * reply)1486 static XtGeometryResult GeometryManager(Widget w, XtWidgetGeometry *request,
1487 XtWidgetGeometry *reply)
1488 #else
1489 static XtGeometryResult GeometryManager(w, request, reply)
1490 Widget w;
1491 XtWidgetGeometry *request;
1492 XtWidgetGeometry *reply;
1493 #endif
1494 {
1495 XmtLayoutWidget lw = (XmtLayoutWidget)XtParent(w);
1496 Position x,y;
1497 Dimension width, height, border_width;
1498
1499 if (XtIsShell(w)) {
1500 return(0);
1501 }
1502
1503 /* this is case 2 described above */
1504 if (lw->layout.geometry_okay) {
1505 XtConfigureWidget(w,
1506 (request->request_mode&CWX)?request->x:w->core.x,
1507 (request->request_mode&CWY)?request->y:w->core.y,
1508 (request->request_mode&CWWidth)?request->width:w->core.width,
1509 (request->request_mode&CWHeight)?request->height:w->core.height,
1510 (request->request_mode&CWBorderWidth)?request->border_width
1511 :w->core.border_width);
1512
1513 /* make sure we don't do this again without cause */
1514 lw->layout.geometry_okay = False;
1515
1516 /*
1517 * Tell the Intrinsics we've done the update for it. Note
1518 * that in this case, when the geometry_okay flag is set,
1519 * the Layout widget has already been re-laid out. However,
1520 * this particular child may not have had its window
1521 * coordinates updated, as explained in a comment in
1522 * ConstraintSetValues(). Thus we do have to do the update here.
1523 */
1524 return XtGeometryDone;
1525 }
1526
1527 /* Otherwise, we handle case 1 described above */
1528 if (!LayoutConstraints(w).allow_resize) return XtGeometryNo;
1529
1530 if (request->request_mode & ~(XtCWQueryOnly | CWWidth | CWHeight))
1531 return XtGeometryNo;
1532
1533 if (request->request_mode & CWWidth)
1534 width = request->width;
1535 else
1536 width = w->core.width;
1537
1538 if (request->request_mode & CWHeight)
1539 height = request->height;
1540 else
1541 height = w->core.height;
1542
1543 if (width == w->core.width && height == w->core.height)
1544 return XtGeometryNo;
1545
1546 if (!(request->request_mode & XtCWQueryOnly)) {
1547 XtResizeWidget(w, width, height, w->core.border_width);
1548 _XmtLayoutChildren((XmtLayoutWidget)XtParent(w), True);
1549 return XtGeometryDone;
1550 }
1551 else
1552 return XtGeometryYes;
1553 }
1554
1555 /* stolen from Xaw Form widget. Hope it works right */
1556 #if NeedFunctionPrototypes
QueryGeometry(Widget widget,XtWidgetGeometry * request,XtWidgetGeometry * reply)1557 static XtGeometryResult QueryGeometry(Widget widget,
1558 XtWidgetGeometry *request,
1559 XtWidgetGeometry *reply)
1560 #else
1561 static XtGeometryResult QueryGeometry(widget, request, reply)
1562 Widget widget;
1563 XtWidgetGeometry *request;
1564 XtWidgetGeometry *reply;
1565 #endif
1566 {
1567 XmtLayoutWidget w = (XmtLayoutWidget)widget;
1568 int wantedWidth;
1569 int wantedHeight;
1570
1571 if (w->bulletin_board.resize_policy == XmRESIZE_NONE) {
1572 wantedWidth = w->core.width;
1573 wantedHeight = w->core.height;
1574 } else {
1575 wantedWidth = LayoutConstraints(w->layout.toplevel).pref_w +
1576 2 * w->bulletin_board.margin_width;
1577 wantedHeight = LayoutConstraints(w->layout.toplevel).pref_h +
1578 2 * w->bulletin_board.margin_height;
1579 if (w->bulletin_board.resize_policy == XmRESIZE_GROW) {
1580 if (wantedWidth < w->core.width) {
1581 wantedWidth = w->core.width;
1582 }
1583 if (wantedHeight < w->core.height) {
1584 wantedHeight = w->core.height;
1585 }
1586 } /* else resize_policy == XmRESIZE_ANY */
1587 }
1588 reply->width = wantedWidth;
1589 reply->height = wantedHeight;
1590 reply->request_mode = CWWidth | CWHeight;
1591 if (request->request_mode & (CWWidth | CWHeight) == (CWWidth | CWHeight)
1592 && request->width == reply->width
1593 && request->height == reply->height)
1594 return XtGeometryYes;
1595 else if (reply->width == w->core.width && reply->height == w->core.height)
1596 return XtGeometryNo;
1597 else
1598 return XtGeometryAlmost;
1599 }
1600
1601 #if NeedFunctionPrototypes
InsertChild(Widget w)1602 static void InsertChild(Widget w)
1603 #else
1604 static void InsertChild(w)
1605 Widget w;
1606 #endif
1607 {
1608 /*
1609 * This is another Motif workaround.
1610 * The BulletinBoard and Manager class InsertChild procedures ignore
1611 * non-rectobj children, and never insert them in the children array.
1612 * The workaround is to call the bulletin board method if this is a
1613 * RectObj, and call the composite method if this is a LayoutGadget,
1614 * and do nothing otherwise. Same for DeleteChild.
1615 */
1616 if (XtIsRectObj(w))
1617 (*xmBulletinBoardClassRec.composite_class.insert_child)(w);
1618 else if (XmtIsLayoutGadget(w))
1619 (*compositeClassRec.composite_class.insert_child)(w);
1620 }
1621
1622
1623 #if NeedFunctionPrototypes
DeleteChild(Widget w)1624 static void DeleteChild(Widget w)
1625 #else
1626 static void DeleteChild(w)
1627 Widget w;
1628 #endif
1629 {
1630 /*
1631 * this is a hack. See InsertChild()
1632 */
1633 if (XtIsRectObj(w))
1634 (*xmBulletinBoardClassRec.composite_class.delete_child)(w);
1635 else if (XmtIsLayoutGadget(w))
1636 (*compositeClassRec.composite_class.delete_child)(w);
1637 }
1638
1639
1640 #if NeedFunctionPrototypes
RepositionContents(Widget container)1641 static void RepositionContents(Widget container)
1642 #else
1643 static void RepositionContents(container)
1644 Widget container;
1645 #endif
1646 {
1647 Widget c; /* child */
1648 XmtLayoutConstraintsPart *cc; /* child constraints */
1649 int i;
1650
1651 c = LayoutConstraints(container).first_child;
1652 i = 0;
1653 while(c) {
1654 cc = LayoutConstraintsRec(c);
1655 cc->position = i++;
1656 c = cc->before;
1657 }
1658 }
1659
1660 #if NeedFunctionPrototypes
PlaceObjectAfter(Widget w,Widget after)1661 static void PlaceObjectAfter(Widget w, Widget after)
1662 #else
1663 static void PlaceObjectAfter(w, after)
1664 Widget w;
1665 Widget after;
1666 #endif
1667 {
1668 XmtLayoutConstraintsPart *c = LayoutConstraintsRec(w);
1669 XmtLayoutConstraintsPart *p = LayoutConstraintsRec(after);
1670 XmtLayoutConstraintsPart *n;
1671 Widget container = p->in ? p->in :
1672 ((XmtLayoutWidget)XtParent(w))->layout.toplevel;
1673
1674 c->in = p->in;
1675 c->after = after;
1676 c->before = p->before;
1677 p->before = w;
1678 if (c->before != NULL) {
1679 n = LayoutConstraintsRec(c->before);
1680 n->after = w;
1681 }
1682 RepositionContents(container);
1683 }
1684
1685 #if NeedFunctionPrototypes
PlaceObjectBefore(Widget w,Widget before)1686 static void PlaceObjectBefore(Widget w, Widget before)
1687 #else
1688 static void PlaceObjectBefore(w, before)
1689 Widget w;
1690 Widget before;
1691 #endif
1692 {
1693 XmtLayoutConstraintsPart *c = LayoutConstraintsRec(w);
1694 XmtLayoutConstraintsPart *n = LayoutConstraintsRec(before);
1695 XmtLayoutConstraintsPart *p;
1696 Widget container = n->in ? n->in :
1697 ((XmtLayoutWidget)XtParent(w))->layout.toplevel;
1698
1699 c->in = n->in;
1700 c->before = before;
1701 c->after = n->after;
1702 n->after = w;
1703
1704 if (c->after == NULL)
1705 LayoutConstraints(container).first_child = w;
1706 else {
1707 p = LayoutConstraintsRec(c->after);
1708 p->before = w;
1709 }
1710 RepositionContents(container);
1711 }
1712
1713 #if NeedFunctionPrototypes
PlaceObjectIn(Widget w,Widget in,int pos)1714 static void PlaceObjectIn(Widget w, Widget in, int pos)
1715 #else
1716 static void PlaceObjectIn(w, in, pos)
1717 Widget w;
1718 Widget in;
1719 int pos;
1720 #endif
1721 {
1722 XmtLayoutConstraintsPart *c = LayoutConstraintsRec(w);
1723 XmtLayoutConstraintsPart *cc; /* container */
1724 Widget n, p; /* next, previous */
1725 int j;
1726 Widget container = in ? in :
1727 ((XmtLayoutWidget)XtParent(w))->layout.toplevel;
1728
1729 /*
1730 * if in is NULL, we leave the layoutIn constraint NULL as well,
1731 * instead of using the pointer to the actual internal container.
1732 * The value NULL is more meaningful to a programmer who might
1733 * query this resource.
1734 */
1735 c->in = in;
1736
1737 /* now go find the position it belongs at */
1738 cc = LayoutConstraintsRec(container);
1739 for(p = NULL, n = cc->first_child, j = 0;
1740 n && (j != pos);
1741 p = n, n = LayoutConstraints(n).before, j++);
1742 c->position = j; /* convert a -1 position to actual position */
1743 c->after = p;
1744 c->before = n;
1745 if (p)
1746 LayoutConstraints(p).before = w;
1747 else
1748 cc->first_child = w;
1749 if (n)
1750 LayoutConstraints(n).after = w;
1751 RepositionContents(container);
1752 }
1753
1754 /*
1755 * This procedure is called mostly from the SetValues method, and its
1756 * two arguments are the "current" and "set" arguments to that method.
1757 * We need to use the copy widget, because it has its doubly-linked
1758 * list intact, and we can extract the widget we need. But we need
1759 * the actual widget as well, so that we can detect whether that
1760 * widget actually occurs on the list.
1761 */
1762 #if NeedFunctionPrototypes
UnlinkObject(Widget copy,Widget actual)1763 static void UnlinkObject(Widget copy, Widget actual)
1764 #else
1765 static void UnlinkObject(copy, actual)
1766 Widget copy, actual;
1767 #endif
1768 {
1769 XmtLayoutConstraintsPart *c = LayoutConstraintsRec(copy);
1770 Widget container = c->in ? c->in :
1771 ((XmtLayoutWidget)XtParent(copy))->layout.toplevel;
1772
1773 /*
1774 * Note that this procedure may sometimes be called more than once
1775 * on a particular child. Thus the test in the else clause below
1776 * is necessary. If the child has already been unlinked, then
1777 * this test will fail, and nothing will be done.
1778 */
1779 if (c->before)
1780 LayoutConstraints(c->before).after = c->after;
1781 if (c->after)
1782 LayoutConstraints(c->after).before = c->before;
1783 else if (LayoutConstraints(container).first_child == actual)
1784 LayoutConstraints(container).first_child = c->before;
1785
1786 RepositionContents(container);
1787 c->before = c->after = c->in = NULL;
1788 }
1789
1790 #if NeedFunctionPrototypes
set_parsed_info(XmtLayoutWidget lw,Widget child)1791 static Boolean set_parsed_info(XmtLayoutWidget lw, Widget child)
1792 #else
1793 static Boolean set_parsed_info(lw, child)
1794 XmtLayoutWidget lw;
1795 Widget child;
1796 #endif
1797 {
1798 XmtLayoutInfo *info, *last;
1799 XmtLayoutConstraintsPart *c = LayoutConstraintsRec(child);
1800 XmtLayoutConstraintsPart *mark;
1801
1802 /* see if the child's name appears in the list */
1803 for(last = NULL, info = lw->layout.widget_info;
1804 info; last = info, info = info->next)
1805 if (info->name == child->core.xrm_name) break;
1806
1807 /*
1808 * If no info was found, and if the child
1809 * is a scrolled window, and its name ends in "SW"
1810 * see if we have info for the grandchild's name without the SW.
1811 * This is a special case to make scrolled lists and scrolled texts
1812 * easier to use in a layout widget.
1813 */
1814 if (!info && XmIsScrolledWindow(child)) {
1815 String name = XtName(child);
1816 int len = strlen(name);
1817 XrmQuark grandchild_name;
1818
1819 if ((name[len-2] == 'S') && (name[len-1] == 'W')) {
1820 name = XtNewString(name);
1821 name[len-2] = '\0';
1822 grandchild_name = XrmStringToQuark(name);
1823 XtFree(name);
1824
1825 for(last = NULL, info = lw->layout.widget_info;
1826 info; last = info, info = info->next)
1827 if (info->name == grandchild_name) break;
1828 }
1829 }
1830
1831 /* if we found some info unlink it, otherwise quit */
1832 if (info) {
1833 if (last) last->next = info->next;
1834 else lw->layout.widget_info = info->next;
1835 }
1836 else return False;
1837
1838 /* override any constraints with info from the layout string */
1839
1840 #define Merge(field)\
1841 if (info->dummy_constraints.field) c->field = info->constraints.field
1842
1843 Merge(width);
1844 Merge(height);
1845 Merge(stretchability);
1846 Merge(shrinkability);
1847 Merge(allow_resize);
1848 Merge(sensitive);
1849 Merge(justification);
1850 Merge(margin_width);
1851 Merge(margin_height);
1852 Merge(frame_type);
1853 Merge(frame_line_type);
1854 Merge(frame_position);
1855 Merge(frame_margin);
1856 Merge(frame_thickness);
1857 Merge(caption_position);
1858 Merge(caption_justification);
1859 Merge(caption_alignment);
1860 Merge(caption_margin);
1861 Merge(caption);
1862
1863 #undef Merge
1864
1865 /* this private flag is a special case */
1866 c->dont_copy_caption = info->constraints.dont_copy_caption;
1867 c->free_caption = info->constraints.free_caption;
1868
1869 /*
1870 * Set after or before or in to the same value as
1871 * the marker widget we created in the parser. We don't need to fully
1872 * attach this widget, just set a position resource so that
1873 * ConstraintInitialize can attach it in the right place.
1874 * Unlink and destroy the marker widget.
1875 */
1876 mark = LayoutConstraintsRec(info->constraints.after);
1877 c->in = mark->in;
1878 c->position = mark->position;
1879 /* destroy the marker object, and remove it from the list */
1880 XtDestroyWidget(info->constraints.after);
1881
1882 XtFree((char *) info);
1883 return True;
1884 }
1885
1886
1887 /* ARGSUSED */
1888 #if NeedFunctionPrototypes
ConstraintInitialize(Widget request,Widget init,ArgList arglist,Cardinal * num_args)1889 static void ConstraintInitialize(Widget request, Widget init,
1890 ArgList arglist, Cardinal *num_args)
1891 #else
1892 static void ConstraintInitialize(request, init, arglist, num_args)
1893 Widget request;
1894 Widget init;
1895 ArgList arglist;
1896 Cardinal *num_args;
1897 #endif
1898 {
1899 XmtLayoutConstraintsPart *c = LayoutConstraintsRec(init);
1900 XmtLayoutWidget lw = (XmtLayoutWidget)XtParent(init);
1901
1902 /*
1903 * we don't use constraints for non-rectobjs. See comment
1904 * in ConstraintSetValues.
1905 */
1906 if (!XtIsWidget(init) &&
1907 !XmIsGadget(init) &&
1908 !XmtIsLayoutGadget(init))
1909 return;
1910
1911 /*
1912 * make a note if this is a widget or gadget.
1913 */
1914 if (XtIsWidget(init) || XmIsGadget(init))
1915 c->type = XmtLayoutChild;
1916
1917 c->dont_copy_caption = False;
1918
1919 /*
1920 * go check if there is constraint info about this widget saved away.
1921 * If so, set it, overriding any resources already set.
1922 * Don't bother checking if this widget was created by the parser.
1923 */
1924 if (!lw->layout.in_parser) set_parsed_info(lw, init);
1925
1926 /*
1927 * if stretchability and shrinkability are unset,
1928 * set the default depending on type
1929 */
1930 if (c->stretchability == (Dimension) -1) {
1931 if ((c->type == XmtLayoutChild) ||
1932 (c->type == XmtLayoutSpace) ||
1933 (c->type == XmtLayoutRow) ||
1934 (c->type == XmtLayoutCol))
1935 c->stretchability = XmtLAYOUT_DEFAULT_STRETCHABILITY;
1936 else
1937 c->stretchability = 0;
1938 }
1939 if (c->shrinkability == (Dimension) -1) {
1940 if ((c->type == XmtLayoutChild) ||
1941 (c->type == XmtLayoutSpace) ||
1942 (c->type == XmtLayoutRow) ||
1943 (c->type == XmtLayoutCol))
1944 c->shrinkability = XmtLAYOUT_DEFAULT_SHRINKABILITY;
1945 else
1946 c->shrinkability = 0;
1947 }
1948
1949 /*
1950 * if margin width or margin height are unset, set default
1951 * depending on type.
1952 */
1953 if (c->margin_width == 255) {
1954 if ((c->type == XmtLayoutRow) || (c->type == XmtLayoutCol))
1955 c->margin_width = 0;
1956 else
1957 c->margin_width = lw->layout.default_spacing/2;
1958 }
1959 if (c->margin_height == 255) {
1960 if ((c->type == XmtLayoutRow) || (c->type == XmtLayoutCol))
1961 c->margin_height = 0;
1962 else
1963 c->margin_height = lw->layout.default_spacing/2;
1964 }
1965
1966 /* if there is a caption, copy it and figure out how big it is */
1967 if (c->caption) {
1968 if (!c->dont_copy_caption) {
1969 c->caption = XmStringCopy(c->caption);
1970 c->free_caption = 1;
1971 }
1972 #if XmVersion < 2000
1973 XmStringExtent(lw->layout.font_list, c->caption,
1974 &c->caption_width, &c->caption_height);
1975 #else
1976 XmStringExtent(lw->layout.render_table, c->caption,
1977 &c->caption_width, &c->caption_height);
1978 #endif
1979 }
1980
1981 /*
1982 * Now figure out where this object will be laid out.
1983 * This can be specified in a number of ways:
1984 * after,
1985 * before, or
1986 * in, optionally combined with position.
1987 * The fields are examined in the order listed, and the first one
1988 * specified is used. Whichever fields are specified, all
1989 * except position are updated to reflect the actual layout.
1990 * If none are specified, then the widget is inserted in the toplevel
1991 * row or column. position defaults to -1, which inserts
1992 * at the end of the row or column.
1993 * Note that if the toplevel box isn't created yet, then we must
1994 * be creating it now, and we shouldn't place it anywhere.
1995 */
1996 if (lw->layout.toplevel != 0) {
1997 if (c->after)
1998 PlaceObjectAfter(init, c->after);
1999 else if (c->before)
2000 PlaceObjectBefore(init, c->before);
2001 else {
2002 PlaceObjectIn(init, c->in, c->position);
2003 }
2004 }
2005
2006 c->first_child = NULL;
2007 }
2008
2009
2010 #if NeedFunctionPrototypes
ConstraintDestroy(Widget w)2011 static void ConstraintDestroy(Widget w)
2012 #else
2013 static void ConstraintDestroy(w)
2014 Widget w;
2015 #endif
2016 {
2017 XmtLayoutWidget lw = (XmtLayoutWidget)XtParent(w);
2018 XmtLayoutConstraintsPart *c = LayoutConstraintsRec(w);
2019
2020 if (!XtIsWidget(w) && !XmIsGadget(w) && !XmtIsLayoutGadget(w))
2021 return;
2022
2023 /* if there is a caption, free it */
2024 if (c->caption && c->free_caption)
2025 XmStringFree(c->caption);
2026
2027 /*
2028 * if the whole layout is being destroyed, don't
2029 * bother messing with the linked lists. If this is a container,
2030 * we don't need to mess with the kids because they will be destroyed.
2031 */
2032 if (lw->core.being_destroyed)
2033 return;
2034
2035 /* unlink the item */
2036 UnlinkObject(w, w);
2037 }
2038
2039
2040 /* ARGSUSED */
2041 #if NeedFunctionPrototypes
ConstraintSetValues(Widget current,Widget request,Widget set,ArgList arglist,Cardinal * num_args)2042 static Boolean ConstraintSetValues(Widget current, Widget request, Widget set,
2043 ArgList arglist, Cardinal *num_args)
2044 #else
2045 static Boolean ConstraintSetValues(current, request, set, arglist, num_args)
2046 Widget current;
2047 Widget request;
2048 Widget set;
2049 ArgList arglist;
2050 Cardinal *num_args;
2051 #endif
2052 {
2053 XmtLayoutWidget lw = (XmtLayoutWidget)XtParent(set);
2054 XmtLayoutConstraintsPart *c = LayoutConstraintsRec(current);
2055 XmtLayoutConstraintsPart *s = LayoutConstraintsRec(set);
2056 Boolean relayout = False;
2057 Boolean redisplay = False;
2058
2059 /*
2060 * ** Another gross Motif hack.
2061 * Motif creates screwy non-rectobj cache objects for every Gadget.
2062 * These objects have NULL constraint fields but are passed to
2063 * this function anyway. They are subclasses of xmExtObjectClass,
2064 * so we could test for them and rule them out. But since none of
2065 * our constraints make sense for any non-rect object, we'll just
2066 * test that it is a subclass of RectObj. We'll insert the same test
2067 * in the other constraint methods for efficiency
2068 */
2069
2070 if (!XtIsWidget(set) && !XmIsGadget(set) && !XmtIsLayoutGadget(set))
2071 return False;
2072
2073 #define Changed(field) (s->field != c->field)
2074
2075 if (Changed(justification) || Changed(margin_width) ||
2076 Changed(margin_height) || Changed(frame_type) ||
2077 Changed(frame_position) || Changed(frame_margin) ||
2078 Changed(caption_position) || Changed(caption_margin) ||
2079 Changed(width) || Changed(height) ||
2080 Changed(stretchability) || Changed(shrinkability))
2081 relayout = True;
2082
2083 if (Changed(caption_justification)) redisplay = True;
2084
2085 if (Changed(sensitive) || Changed(frame_line_type) ||
2086 Changed(caption_alignment))
2087 if (XtIsRealized((Widget)lw))
2088 DrawFrameAndCaption(lw, set, NULL, True);
2089
2090 if (Changed(caption)) {
2091 if (c->caption && c->free_caption) XmStringFree(c->caption);
2092 if (s->caption) {
2093 s->caption = XmStringCopy(s->caption);
2094 s->free_caption = 1;
2095 #if XmVersion < 2000
2096 XmStringExtent(lw->layout.font_list, s->caption,
2097 &s->caption_width, &s->caption_height);
2098 #else
2099 XmStringExtent(lw->layout.render_table, s->caption,
2100 &s->caption_width, &s->caption_height);
2101 #endif
2102 }
2103 relayout = True;
2104 }
2105
2106 if (set != ((XmtLayoutWidget)XtParent(set))->layout.toplevel) {
2107 if (Changed(after)) {
2108 if (!s->after || (XtParent(s->after) != (Widget)lw)) {
2109 XmtWarningMsg("XmtLayout", "badAfter",
2110 "XmtNlayoutAfter constraint of child `%s'\n\tmust be a sibling of the child.",
2111 XtName((Widget)set));
2112 s->after = c->after;
2113 }
2114 else {
2115 Widget after = s->after;
2116 UnlinkObject(current, set);
2117 PlaceObjectAfter(set, after);
2118 relayout = True;
2119 }
2120 }
2121 else if (Changed(before)) {
2122 if (!s->before || (XtParent(s->before) != (Widget)lw)) {
2123 XmtWarningMsg("XmtLayout", "badBefore",
2124 "XmtNlayoutBefore constraint of child `%s'\n\tmust be a sibling of the child.",
2125 XtName((Widget)set));
2126 s->before = c->before;
2127 }
2128 else {
2129 Widget before = s->before;
2130 UnlinkObject(current, set);
2131 PlaceObjectBefore(set, before);
2132 relayout = True;
2133 }
2134 }
2135 else if (Changed(in) || Changed(position)) {
2136 if (Changed(in) && s->in &&
2137 ((XtParent(s->in) != (Widget)lw) ||
2138 (!XtIsSubclass(s->in, xmtLayoutBoxGadgetClass)))) {
2139 XmtWarningMsg("XmtLayout", "badIn",
2140 "XmtNlayoutIn constraint of child `%s'\n\tmust be an XmtLayoutBox sibling of the child, or NULL.",
2141 XtName((Widget)set));
2142 s->in = c->in;
2143 }
2144 else {
2145 Widget in = s->in;
2146 int position = s->position;
2147 UnlinkObject(current, set);
2148 PlaceObjectIn(set, in, position);
2149 relayout = True;
2150 }
2151 }
2152 }
2153
2154 /*
2155 * It doesn't make sense to change the position of children of a layout
2156 * widget by setting XtNx or XtNy. So, if these have been changed,
2157 * warn, and undo the changes. Note that it is legal to set the
2158 * width or height of a child--if these fields have changed, the
2159 * Intrinsics will automatically call the GeometryManager field to
2160 * make the change, and the GeometryManager will do the relayout,
2161 * so we don't need to handle this case at all.
2162 */
2163 if ((set->core.x != current->core.x) || (set->core.y != current->core.y)) {
2164 set->core.x = current->core.x;
2165 set->core.y = current->core.y;
2166 XmtWarningMsg("XmtLayout", "cantsetpos",
2167 "Widget %s: can't set XtNx or XtNy resources of a child of\n\tan XmtLayout widget. Changes ignored.",
2168 XtName((Widget) set));
2169 }
2170
2171 #undef Changed
2172
2173 /*
2174 * If any of these changes require a relayout, do that now.
2175 *
2176 * If the changes or the relayout changed any of the widget's
2177 * geometry fields, then the Intrinsics will invoke the
2178 * GeometryManager() method to verify that those changes are okay.
2179 * But we've just called _XmtLayoutChildren() so we know that they're
2180 * okay. So we set a flag to tell GeometryManager() to approve
2181 * the changes, even though they may include position changes
2182 * which are normally rejected.
2183 * Notice, however, that when we call _XmtLayoutChildren() here,
2184 * the core geometry fields are at their new values, and thus, when
2185 * the relayout procedure ends up calling XtConfigureWidget()
2186 * (actually XmtConfigureObject, in LayoutBox.c) on this child,
2187 * the Intrinsics may find that the new geometry matches the current
2188 * geometry, and thus will not update the actual window fields.
2189 * Therefore, we've got to be sure that the geometry manager
2190 * takes this into account.
2191 * See comment at GeometryManager() for more information.
2192 */
2193 if (relayout) {
2194 _XmtLayoutChildren(lw, True);
2195
2196 if ((set->core.x != current->core.x) ||
2197 (set->core.y != current->core.y) ||
2198 (set->core.width != current->core.width) ||
2199 (set->core.height != current->core.height))
2200 lw->layout.geometry_okay = True;
2201 }
2202
2203 /*
2204 * Returning True from this method will only redraw the child, not
2205 * the entire Layout widget, as happens when SetValues() returns True.
2206 * So if either relayout or redisplay is True, then we'll need to force
2207 * the redraw ourselves. We do this by using XClearArea() to generate
2208 * an Expose event. The relayout process may generate other Expose
2209 * events if gadgets are moved around, but these events will be combined
2210 * into a single call to the Layout Redisplay() method. The reason that
2211 * it is important to do this is that the Layout provides captions and
2212 * frames for its children, and these have to be redrawn when the
2213 * children move or change size. In particular, if only a widget child
2214 * is moved, then the relayout call won't generate any expose events,
2215 * and without the XClearArea() below, the captions and frames would
2216 * not be redrawn correctly.
2217 */
2218
2219 if ((relayout || redisplay) && XtIsRealized((Widget)lw))
2220 XClearArea(XtDisplay((Widget) lw), XtWindow((Widget) lw),
2221 lw->core.x, lw->core.y, lw->core.width, lw->core.height,
2222 True);
2223
2224 return False;
2225 }
2226
2227
2228 /* ARGSUSED */
2229 #if NeedFunctionPrototypes
2230 void
FocusMoved(wid,client_data,data)2231 FocusMoved( wid, client_data, data )
2232 Widget wid ;
2233 XtPointer client_data ;
2234 XtPointer data ;
2235 #else
2236 void
2237 FocusMoved(
2238 Widget wid,
2239 XtPointer client_data,
2240 XtPointer data )
2241 #endif /* _NO_PROTO */
2242 {
2243 XmtLayoutWidget lw = (XmtLayoutWidget) client_data;
2244 XmAnyCallbackStruct cb ;
2245 XmFocusMovedCallbackStruct * call_data
2246 = (XmFocusMovedCallbackStruct *) data ;
2247 Widget testWidget;
2248 Boolean hadFocus, losingFocus;
2249 /*
2250 * Perform superclass focus processing.
2251 */
2252 (superclass->bulletin_board_class.focus_moved_proc)(wid, client_data, data);
2253 /*
2254 * Is focus processing still in effect?
2255 */
2256 if (!call_data->cont) {
2257 return;
2258 }
2259 /*
2260 * Does the old widget have us as an ancestor, but the current doesn't?
2261 */
2262 testWidget = call_data->old_focus;
2263 hadFocus = False;
2264 while (testWidget != NULL && !XtIsShell(testWidget)) {
2265 if (testWidget == (Widget) lw) {
2266 hadFocus = True;
2267 break;
2268 }
2269 testWidget = XtParent(testWidget);
2270 }
2271
2272 if (hadFocus) {
2273 testWidget = call_data->new_focus;
2274
2275 losingFocus = True;
2276 while (testWidget != NULL && !XtIsShell(testWidget)) {
2277 if (testWidget == (Widget) lw) {
2278 losingFocus = False;
2279 break;
2280 }
2281 testWidget = XtParent(testWidget);
2282 }
2283
2284 if (losingFocus) {
2285 cb.reason = XmCR_LOSING_FOCUS ;
2286 cb.event = NULL ;
2287 XtCallCallbackList( (Widget) lw,
2288 lw->layout.losing_focus_callback, &cb) ;
2289 }
2290 }
2291 }
2292
2293 #if NeedFunctionPrototypes
XmtLayoutDisableLayout(Widget w)2294 void XmtLayoutDisableLayout(Widget w)
2295 #else
2296 void XmtLayoutDisableLayout(w)
2297 Widget w;
2298 #endif
2299 {
2300 XmtLayoutWidget lw = (XmtLayoutWidget) w;
2301
2302 XmtAssertWidgetClass(w, xmtLayoutWidgetClass, "XmtLayoutDisable");
2303 lw->layout.layout_disabled++;
2304 }
2305
2306 #if NeedFunctionPrototypes
XmtLayoutEnableLayout(Widget w)2307 void XmtLayoutEnableLayout(Widget w)
2308 #else
2309 void XmtLayoutEnableLayout(w)
2310 Widget w;
2311 #endif
2312 {
2313 XmtLayoutWidget lw = (XmtLayoutWidget) w;
2314
2315 XmtAssertWidgetClass(w, xmtLayoutWidgetClass, "XmtEnableLayout");
2316 if (lw->layout.layout_disabled > 0) lw->layout.layout_disabled--;
2317 if (lw->layout.needs_layout) _XmtLayoutChildren(lw, True);
2318 }
2319
2320
2321 #if NeedFunctionPrototypes
XmtLayoutConvertSizeToPixels(Widget w,double size,XmtLayoutUnitType units)2322 int XmtLayoutConvertSizeToPixels(Widget w, double size,XmtLayoutUnitType units)
2323 #else
2324 int XmtLayoutConvertSizeToPixels(w, size, units)
2325 Widget w;
2326 double size;
2327 XmtLayoutUnitType units;
2328 #endif
2329 {
2330 XmtLayoutWidget lw = (XmtLayoutWidget) w;
2331
2332 XmtAssertWidgetClass(w, xmtLayoutWidgetClass,
2333 "XmtLayoutConvertSizeToPixels");
2334
2335 /* convert to pixels */
2336 /* note intentional missing break statements */
2337 switch(units) {
2338 case XmtLayoutPoints:
2339 size /= 72; /* 1 point = 1/72 inch */
2340 case XmtLayoutInches:
2341 size *= 25.4; /* 1 inch = 25.4 mm */
2342 case XmtLayoutMillimeters:
2343 size *= lw->layout.pixpermm; /* pixels per mm depends on screen res */
2344 break;
2345 case XmtLayoutEns:
2346 size /= 2; /* 1 en = 1/2 em */
2347 case XmtLayoutEms:
2348 size *= lw->layout.pixperem; /* pixels per em depends on font size */
2349 break;
2350 }
2351
2352 /* round to the nearest pixel */
2353 return (int) size;
2354 }
2355
2356 #if NeedFunctionPrototypes
XmtCreateLayout(Widget parent,String name,ArgList args,Cardinal n)2357 Widget XmtCreateLayout(Widget parent, String name,
2358 ArgList args, Cardinal n)
2359 #else
2360 Widget XmtCreateLayout(parent, name, args, n)
2361 Widget parent;
2362 String name;
2363 ArgList args;
2364 Cardinal n;
2365 #endif
2366 {
2367 return XtCreateWidget(name, xmtLayoutWidgetClass, parent, args, n);
2368 }
2369
2370 #if NeedFunctionPrototypes
XmtCreateLayoutDialog(Widget parent,String name,ArgList al,Cardinal ac)2371 Widget XmtCreateLayoutDialog(Widget parent, String name,
2372 ArgList al, Cardinal ac)
2373 #else
2374 Widget XmtCreateLayoutDialog(parent, name, al, ac)
2375 Widget parent;
2376 String name;
2377 ArgList al;
2378 Cardinal ac;
2379 #endif
2380 {
2381 Widget shell, w;
2382 String shell_name;
2383
2384 shell_name = XtMalloc(strlen(name) + 7);
2385 (void)sprintf(shell_name, "%s_shell", name);
2386
2387 shell = XmCreateDialogShell(parent, shell_name, al, ac);
2388 XtFree(shell_name);
2389 XtVaSetValues(shell, XmNallowShellResize, True, NULL);
2390
2391 w = XtCreateWidget(name, xmtLayoutWidgetClass, shell, al, ac);
2392 XtAddCallback(w, XtNdestroyCallback,
2393 (XtCallbackProc)_XmDestroyParentCallback, NULL);
2394 return w;
2395 }
2396
2397
2398