1 /* $XConsortium: Paned.c,v 1.27 94/04/17 20:12:28 kaleb Exp $ */
2 
3 /***********************************************************
4 
5 Copyright (c) 1987, 1988, 1994  X Consortium
6 
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
20 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 
24 Except as contained in this notice, the name of the X Consortium shall not be
25 used in advertising or otherwise to promote the sale, use or other dealings
26 in this Software without prior written authorization from the X Consortium.
27 
28 
29 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
30 
31                         All Rights Reserved
32 
33 Permission to use, copy, modify, and distribute this software and its
34 documentation for any purpose and without fee is hereby granted,
35 provided that the above copyright notice appear in all copies and that
36 both that copyright notice and this permission notice appear in
37 supporting documentation, and that the name of Digital not be
38 used in advertising or publicity pertaining to distribution of the
39 software without specific, written prior permission.
40 
41 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
42 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
43 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
44 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
45 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
46 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47 SOFTWARE.
48 
49 ******************************************************************/
50 
51 /*
52  * Paned.c - Paned Composite Widget.
53  *
54  * Updated and significantly modified from the Athena VPaned Widget.
55  *
56  * Date:    March 1, 1989
57  *
58  * By:      Chris D. Peterson
59  *          MIT X Consortium
60  *          kit@expo.lcs.mit.edu
61  */
62 
63 #include <X11/IntrinsicP.h>
64 #include <X11/cursorfont.h>
65 #include <X11/StringDefs.h>
66 
67 #include <X11/Xmu/Misc.h>
68 #include <X11/Xmu/Converters.h>
69 
70 #include "XawInit.h"
71 #include "Grip.h"
72 #include "PanedP.h"
73 
74 /* I don't know why Paned.c calls _XawImCallVendorShellExtResize, but... */
75 #include "XawImP.h"
76 
77 #include <ctype.h>
78 
79 typedef enum {UpLeftPane = 'U', LowRightPane = 'L',
80 	      ThisBorderOnly = 'T', AnyPane = 'A' } Direction;
81 
82 #define NO_INDEX -100
83 #define IS_GRIP  NULL
84 
85 #define PaneInfo(w)	((Pane)(w)->core.constraints)
86 #define HasGrip(w)	(PaneInfo(w)->grip != NULL)
87 #define IsPane(w)	((w)->core.widget_class != gripWidgetClass)
88 #define PaneIndex(w)	(PaneInfo(w)->position)
89 #define IsVert(w)       ( (w)->paned.orientation == XtorientVertical )
90 
91 #define ForAllPanes(pw, childP) \
92   for ( (childP) = (pw)->composite.children ; \
93         (childP) < (pw)->composite.children + (pw)->paned.num_panes ; \
94         (childP)++ )
95 
96 #define ForAllChildren(pw, childP) \
97   for ( (childP) = (pw)->composite.children ; \
98         (childP) < (pw)->composite.children + (pw)->composite.num_children ; \
99         (childP)++ )
100 
101 /*****************************************************************************
102  *
103  * Full instance record declaration
104  *
105  ****************************************************************************/
106 
107 static char defGripTranslations[] =
108     "<Btn1Down>:		GripAction(Start, UpLeftPane) \n\
109      <Btn2Down>:		GripAction(Start, ThisBorderOnly) \n\
110      <Btn3Down>:		GripAction(Start, LowRightPane) \n\
111      <Btn1Motion>:		GripAction(Move, UpLeft) \n\
112      <Btn2Motion>:		GripAction(Move, ThisBorder) \n\
113      <Btn3Motion>:		GripAction(Move, LowRight) \n\
114      Any<BtnUp>:		GripAction(Commit)";
115 
116 #define offset(field) XtOffsetOf(PanedRec, paned.field)
117 
118 static XtResource resources[] = {
119     {XtNinternalBorderColor, XtCBorderColor, XtRPixel, sizeof(Pixel),
120 	 offset(internal_bp), XtRString,
121          (XtPointer) XtDefaultForeground},
122     {XtNinternalBorderWidth, XtCBorderWidth, XtRDimension, sizeof(Dimension),
123 	 offset(internal_bw), XtRImmediate, (XtPointer) 1},
124     {XtNgripIndent, XtCGripIndent, XtRPosition, sizeof(Position),
125 	 offset(grip_indent), XtRImmediate, (XtPointer) 10},
126     {XtNrefigureMode, XtCBoolean, XtRBoolean, sizeof(Boolean),
127          offset(refiguremode), XtRImmediate, (XtPointer) TRUE},
128     {XtNgripTranslations, XtCTranslations, XtRTranslationTable,
129          sizeof(XtTranslations),
130          offset(grip_translations), XtRString, (XtPointer)defGripTranslations},
131     {XtNorientation,  XtCOrientation, XtROrientation, sizeof(XtOrientation),
132          offset(orientation), XtRImmediate, (XtPointer) XtorientVertical},
133 
134     /* Cursors - both horiz and vertical have to work. */
135 
136     {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
137          offset(cursor), XtRImmediate, None},
138     {XtNgripCursor, XtCCursor, XtRCursor, sizeof(Cursor),
139          offset(grip_cursor), XtRImmediate, None},
140     {XtNverticalGripCursor, XtCCursor, XtRCursor, sizeof(Cursor),
141          offset(v_grip_cursor), XtRString, "sb_v_double_arrow"},
142     {XtNhorizontalGripCursor, XtCCursor, XtRCursor, sizeof(Cursor),
143          offset(h_grip_cursor), XtRString, "sb_h_double_arrow"},
144 
145     {XtNbetweenCursor, XtCCursor, XtRCursor, sizeof(Cursor),
146          offset(adjust_this_cursor), XtRString, None},
147     {XtNverticalBetweenCursor, XtCCursor, XtRCursor, sizeof(Cursor),
148          offset(v_adjust_this_cursor), XtRString, "sb_left_arrow"},
149     {XtNhorizontalBetweenCursor, XtCCursor, XtRCursor, sizeof(Cursor),
150          offset(h_adjust_this_cursor), XtRString, "sb_up_arrow"},
151 
152     {XtNupperCursor, XtCCursor, XtRCursor, sizeof(Cursor),
153          offset(adjust_upper_cursor), XtRString, "sb_up_arrow"},
154     {XtNlowerCursor, XtCCursor, XtRCursor, sizeof(Cursor),
155          offset(adjust_lower_cursor), XtRString, "sb_down_arrow"},
156     {XtNleftCursor, XtCCursor, XtRCursor, sizeof(Cursor),
157          offset(adjust_left_cursor), XtRString, "sb_left_arrow"},
158     {XtNrightCursor, XtCCursor, XtRCursor, sizeof(Cursor),
159          offset(adjust_right_cursor), XtRString, "sb_right_arrow"},
160 };
161 
162 #undef offset
163 
164 #define offset(field) XtOffsetOf(PanedConstraintsRec, paned.field)
165 
166 static XtResource subresources[] = {
167     {XtNallowResize, XtCBoolean, XtRBoolean, sizeof(Boolean),
168 	 offset(allow_resize), XtRImmediate, (XtPointer) FALSE},
169     {XtNposition, XtCPosition, XtRInt, sizeof(int),
170          offset(position), XtRImmediate, (XtPointer) 0},
171     {XtNmin, XtCMin, XtRDimension, sizeof(Dimension),
172          offset(min), XtRImmediate, (XtPointer) PANED_GRIP_SIZE},
173     {XtNmax, XtCMax, XtRDimension, sizeof(Dimension),
174          offset(max), XtRImmediate, (XtPointer) ~0},
175     {XtNpreferredPaneSize, XtCPreferredPaneSize, XtRDimension,
176 	 sizeof(Dimension), offset(preferred_size),
177          XtRImmediate, (XtPointer) PANED_ASK_CHILD},
178     {XtNresizeToPreferred, XtCBoolean, XtRBoolean, sizeof(Boolean),
179          offset(resize_to_pref), XtRImmediate, (XtPointer) FALSE},
180     {XtNskipAdjust, XtCBoolean, XtRBoolean, sizeof(Boolean),
181          offset(skip_adjust), XtRImmediate, (XtPointer) FALSE},
182     {XtNshowGrip, XtCShowGrip, XtRBoolean, sizeof(Boolean),
183 	 offset(show_grip), XtRImmediate, (XtPointer) TRUE},
184 };
185 
186 #undef offset
187 
188 static void ClassInitialize(), Initialize();
189 static void Realize(), Resize();
190 static void Redisplay();
191 static void GetGCs(), ReleaseGCs();
192 static void RefigureLocationsAndCommit();
193 static Boolean SetValues();
194 static XtGeometryResult GeometryManager();
195 static void ChangeManaged();
196 static void InsertChild();
197 static void DeleteChild();
198 static Boolean PaneSetValues();
199 static Dimension PaneSize(), GetRequestInfo();
200 static Boolean SatisfiesRule1(), SatisfiesRule2(), SatisfiesRule3();
201 
202 static void PushPaneStack();
203 static void GetPaneStack();
204 static Boolean PopPaneStack();
205 static void ClearPaneStack();
206 
207 #define SuperClass ((ConstraintWidgetClass)&constraintClassRec)
208 
209 PanedClassRec panedClassRec = {
210    {
211 /* core class fields */
212     /* superclass         */   (WidgetClass) SuperClass,
213     /* class name         */   "Paned",
214     /* size               */   sizeof(PanedRec),
215     /* class_initialize   */   ClassInitialize,
216     /* class_part init    */   NULL,
217     /* class_inited       */   FALSE,
218     /* initialize         */   Initialize,
219     /* initialize_hook    */   NULL,
220     /* realize            */   Realize,
221     /* actions            */   NULL,
222     /* num_actions        */   0,
223     /* resources          */   resources,
224     /* resource_count     */   XtNumber(resources),
225     /* xrm_class          */   NULLQUARK,
226     /* compress_motion    */   TRUE,
227     /* compress_exposure  */   TRUE,
228     /* compress_enterleave*/   TRUE,
229     /* visible_interest   */   FALSE,
230     /* destroy            */   ReleaseGCs,
231     /* resize             */   Resize,
232     /* expose             */   Redisplay,
233     /* set_values         */   SetValues,
234     /* set_values_hook    */   NULL,
235     /* set_values_almost  */   XtInheritSetValuesAlmost,
236     /* get_values_hook    */   NULL,
237     /* accept_focus       */   NULL,
238     /* version            */   XtVersion,
239     /* callback_private   */   NULL,
240     /* tm_table           */   NULL,
241     /* query_geometry	  */   XtInheritQueryGeometry,
242     /* display_accelerator*/   XtInheritDisplayAccelerator,
243     /* extension          */   NULL
244    }, {
245 /* composite class fields */
246     /* geometry_manager   */   GeometryManager,
247     /* change_managed     */   ChangeManaged,
248     /* insert_child       */   InsertChild,
249     /* delete_child       */   DeleteChild,
250     /* extension          */   NULL
251    }, {
252 /* constraint class fields */
253     /* subresources       */   subresources,
254     /* subresource_count  */   XtNumber(subresources),
255     /* constraint_size    */   sizeof(PanedConstraintsRec),
256     /* initialize         */   NULL,
257     /* destroy            */   NULL,
258     /* set_values         */   PaneSetValues,
259     /* extension          */   NULL
260    }
261 };
262 
263 WidgetClass panedWidgetClass = (WidgetClass) &panedClassRec;
264 
265 /* For compatibility. */
266 WidgetClass vPanedWidgetClass = (WidgetClass) &panedClassRec;
267 
268 /***********************************************************
269  *
270  * Private Functions.
271  *
272  ************************************************************/
273 
274 /*	Function Name: AdjustPanedSize
275  *	Description: Adjusts the size of the pane.
276  *	Arguments: pw - the paned widget to adjust.
277  *                 off_size - the new off_size to use.
278  *                 result_ret - result of query ** RETURNED **
279  *                 on_size_ret - the new on_size ** RETURNED **
280  *                 off_size_ret - the new off_size ** RETURNED **
281  *	Returns: the amount of change in size.
282  */
283 
284 static void
AdjustPanedSize(pw,off_size,result_ret,on_size_ret,off_size_ret)285 AdjustPanedSize(pw, off_size, result_ret, on_size_ret, off_size_ret)
286 PanedWidget pw;
287 Dimension off_size;
288 XtGeometryResult * result_ret;
289 Dimension * on_size_ret, * off_size_ret;
290 {
291     Dimension old_size = PaneSize( (Widget) pw, IsVert(pw));
292     Dimension newsize = 0;
293     Widget * childP;
294     XtWidgetGeometry request, reply;
295     request.request_mode = CWWidth | CWHeight;
296 
297     ForAllPanes(pw, childP) {
298         int size = Max(PaneInfo(*childP)->size, (int)PaneInfo(*childP)->min);
299 	AssignMin(size, (int) PaneInfo(*childP)->max);
300         newsize += size + pw->paned.internal_bw;
301     }
302     newsize -= pw->paned.internal_bw;
303 
304     if (newsize < 1) newsize = 1;
305 
306     if ( IsVert(pw) ) {
307         request.width = off_size;
308 	request.height = newsize;
309     }
310     else {
311         request.width = newsize;
312 	request.height = off_size;
313     }
314 
315     if (result_ret != NULL) {
316       request.request_mode |= XtCWQueryOnly;
317 
318       *result_ret = XtMakeGeometryRequest( (Widget) pw, &request, &reply );
319       _XawImCallVendorShellExtResize( (Widget) pw );
320 
321       if ( (newsize == old_size) || (*result_ret == XtGeometryNo) ) {
322 	  *on_size_ret = old_size;
323 	  *off_size_ret = off_size;
324 	  return;
325       }
326       if (*result_ret != XtGeometryAlmost) {
327 	  *on_size_ret = GetRequestInfo( &request, IsVert(pw) );
328       	  *off_size_ret = GetRequestInfo( &request, !IsVert(pw) );
329 	  return;
330       }
331       *on_size_ret = GetRequestInfo( &reply, IsVert(pw) );
332       *off_size_ret = GetRequestInfo( &reply, !IsVert(pw) );
333       return;
334     }
335 
336     if (newsize == old_size) return;
337 
338     if (XtMakeGeometryRequest( (Widget) pw,
339 			      &request, &reply) == XtGeometryAlmost)
340         XtMakeGeometryRequest( (Widget) pw, &reply, &request);
341 }
342 
343 /*	Function Name: PaneSize
344  *	Description: returns the width or height of the pane depending
345  *                   upon the orientation we are using.
346  *	Arguments: w - and widget.
347  *                 vertical - TRUE if this is vertically oriented pane.
348  *	Returns: the size requested
349  *
350  *      vertical  - return height
351  *      !vertical - return width
352  */
353 
354 static Dimension
PaneSize(w,vertical)355 PaneSize(w, vertical)
356 Widget w;
357 Boolean vertical;
358 {
359     if (vertical) return (w->core.height);
360     return (w->core.width);
361 }
362 
363 /*	Function Name: GetRequestInfo
364  *	Description: returns request information.
365  *	Arguments:  geo_struct - a geometry struct to get information out of.
366  *                  vert - TRUE if this is a vertical paned widget.
367  *	Returns: the request information.
368  */
369 
370 static Dimension
GetRequestInfo(geo_struct,vert)371 GetRequestInfo(geo_struct, vert)
372 XtWidgetGeometry * geo_struct;
373 Boolean vert;
374 {
375     if ( vert ) return ( (Dimension) geo_struct->height);
376     return ( (Dimension) geo_struct->width);
377 }
378 
379 /*	Function Name: ChoosePaneToResize.
380  *	Description: This function chooses a pane to resize.
381  *                   They are chosen using the following rules:
382  *
383  *                   1) size < max && size > min
384  *                   2) skip adjust == FALSE
385  *                   3) widget not its prefered height &&
386  *                      this change will bring it closer &&
387  *                      The user has not resized this pane.
388  *
389  *                   If no widgets are found that fits all the rules then
390  *                      rule #3 is broken.
391  *                   If there are still no widgets found than
392  *                      rule #2 is broken.
393  *                   Rule #1 is never broken.
394  *                   If no widgets are found then NULL is returned.
395  *
396  *	Arguments: pw - the paned widget.
397  *                 paneindex - the index of the current pane.
398  *                 dir - direction to search first.
399  *                 shrink - TRUE if we need to shrink a pane, FALSE otherwise.
400  *	Returns: pane to resize or NULL.
401  */
402 
403 static Pane
ChoosePaneToResize(pw,paneindex,dir,shrink)404 ChoosePaneToResize(pw, paneindex, dir, shrink)
405 PanedWidget pw;
406 int paneindex;
407 Direction dir;
408 Boolean shrink;
409 {
410     Widget *childP;
411     int rules = 3;
412     Direction _dir = dir;
413     int _index = paneindex;
414 
415     if ( (paneindex == NO_INDEX) || (dir == AnyPane) ) {  /* Use defaults. */
416       _dir = LowRightPane;		/* Go up. - really. */
417       _index = pw->paned.num_panes - 1;	/* Start the last pane, and work
418 					   backwards. */
419     }
420     childP = pw->composite.children + _index;
421 
422     /* CONSTCOND */
423     while(TRUE) {
424         Pane pane = PaneInfo(*childP);
425 
426         if ( (rules < 3 || SatisfiesRule3(pane, shrink)) &&
427 	     (rules < 2 || SatisfiesRule2(pane))         &&
428 	     (SatisfiesRule1(pane, shrink))              &&
429 	     ((paneindex != PaneIndex(*childP)) || (dir == AnyPane)) )
430 	    return(pane);
431 
432 /*
433  * This is counter-intuitive, but if we are resizing the pane
434  * above the grip we want to choose a pane below the grip to lose,
435  * and visa-versa.
436  */
437 
438 	if (_dir == LowRightPane) --childP; else ++childP;
439 
440 /*
441  * If we have come to and edge then reduce the rule set, and try again.
442  * If we are reduced the rules to none, then return NULL.
443  */
444 
445 	if ( (childP - pw->composite.children < 0) ||
446 	     (childP - pw->composite.children >= pw->paned.num_panes) ) {
447 	    if (--rules < 1)  /* less strict rules. */
448 	      return(NULL);
449 	    childP = pw->composite.children + _index;
450 	}
451     }
452 }
453 
454 /*	Function Name: StatisfiesRule1
455  *	Description: check for to see if this pane satisfies rule 1.
456  *	Arguments: pane - the pane to check.
457  *                 shrink -TRUE if we want to shrink this pane, FALSE otherwise
458  *	Returns: TRUE if the rule is satisfied.
459  */
460 
461 static Boolean
SatisfiesRule1(pane,shrink)462 SatisfiesRule1(pane, shrink)
463 Pane pane;
464 Boolean shrink;
465 {
466   return( (shrink && (pane->size != pane->min)) ||
467 	  (!shrink && (pane->size != pane->max)) );
468 }
469 
470 /*	Function Name: StatisfiesRule2
471  *	Description: check for to see if this pane satisfies rule 2.
472  *	Arguments: pane - the pane to check.
473  *	Returns: TRUE if the rule is satisfied.
474  */
475 
476 static Boolean
SatisfiesRule2(pane)477 SatisfiesRule2(pane)
478 Pane pane;
479 {
480   return(!pane->skip_adjust || pane->paned_adjusted_me);
481 }
482 
483 /*	Function Name: StatisfiesRule3
484  *	Description: check for to see if this pane satisfies rule 3.
485  *	Arguments: pane - the pane to check.
486  *                 shrink -TRUE if we want to shrink this pane, FALSE otherwise
487  *	Returns: TRUE if the rule is satisfied.
488  */
489 
490 static Boolean
SatisfiesRule3(pane,shrink)491 SatisfiesRule3(pane, shrink)
492 Pane pane;
493 Boolean shrink;
494 {
495   return ( pane->paned_adjusted_me &&
496 	   ( (shrink && ((int)pane->wp_size <= pane->size)) ||
497 	     (!shrink && ((int)pane->wp_size >= pane->size))) );
498 }
499 
500 /*	Function Name: LoopAndRefigureChildren.
501  *	Description: if we are resizing either the UpleftPane or LowRight Pane
502  *                   loop through all the children to see if any will allow us
503  *                   to resize them.
504  *	Arguments: pw - the paned widget.
505  *                 paneindex - the number of the pane border we are moving.
506  *                 dir - the pane to move (either UpLeftPane or LowRightPane).
507  *                 sizeused - current amount of space used.
508  *                            THIS VALUE IS USED AND RETURNED.
509  *	Returns: none.
510  */
511 
512 static void
LoopAndRefigureChildren(pw,paneindex,dir,sizeused)513 LoopAndRefigureChildren(pw, paneindex, dir, sizeused)
514 PanedWidget pw;
515 int paneindex, *sizeused;
516 Direction dir;
517 {
518     int pane_size = (int) PaneSize( (Widget) pw, IsVert(pw));
519     Boolean shrink = (*sizeused > pane_size);
520 
521     if (dir == LowRightPane) paneindex++;
522 
523     while (*sizeused != pane_size) { /* While all panes do not fit properly. */
524 /*
525  * Choose a pane to resize.
526  * First look on the Pane Stack, and then go hunting for another one.
527  * If we fail to find a pane to resize then give up.
528  */
529         Pane pane;
530 	int start_size;
531 	Dimension old;
532 	Boolean rule3_ok = FALSE, from_stack = TRUE;
533 
534 	GetPaneStack(pw, shrink, &pane, &start_size);
535 	if (pane == NULL) {
536 	    pane = ChoosePaneToResize(pw, paneindex, dir, shrink);
537 	    if (pane == NULL)
538 	        return; /* no one to resize, give up. */
539 
540 	    rule3_ok = SatisfiesRule3(pane, shrink);
541 	    from_stack = FALSE;
542 	    PushPaneStack(pw, pane);
543 	}
544 
545 
546 /*
547  * Try to resize this pane so that all panes will fit, take min and max
548  * into account.
549  */
550 	old = pane->size;
551 	pane->size += pane_size - *sizeused;
552 
553 	if (from_stack) {
554 	    if (shrink) {
555 	        AssignMax(pane->size, start_size);
556 	    }			/* don't remove these braces. */
557 	    else
558 	        AssignMin(pane->size, start_size);
559 
560 	    if (pane->size == start_size) (void) PopPaneStack(pw);
561 	}
562 	else if (rule3_ok) {
563 	    if (shrink) {
564 	        AssignMax(pane->size, (int) pane->wp_size);
565 	    }			/* don't remove these braces. */
566 	    else
567 	        AssignMin(pane->size, (int) pane->wp_size);
568 	}
569 
570 	pane->paned_adjusted_me = (pane->size != pane->wp_size);
571 	AssignMax(pane->size, (int) pane->min);
572 	AssignMin(pane->size, (int) pane->max);
573 	*sizeused += (pane->size - old);
574     }
575 }
576 
577 /*	Function Name: RefigureLocations
578  *	Description: refigures all locations of children.
579  *	Arguments: pw - the paned widget.
580  *                 paneindex - child to start refiguring at.
581  *                 dir - direction to move from child.
582  *	Returns: none.
583  *
584  *      There are special arguments to paneindex and dir, they are:
585  *      paneindex - NO_INDEX.
586  *      dir   - AnyPane.
587  *
588  *      If either of these is true then all panes may be resized and
589  *      the choosing of panes procedes in reverse order starting with the
590  *      last child.
591  */
592 
593 static void
RefigureLocations(pw,paneindex,dir)594 RefigureLocations(pw, paneindex, dir)
595 PanedWidget pw;
596 int paneindex;
597 Direction dir;
598 {
599     Widget *childP;
600     int pane_size = (int) PaneSize( (Widget) pw, IsVert(pw) );
601     int sizeused = 0;
602     Position loc = 0;
603 
604     if (pw->paned.num_panes == 0 || !pw->paned.refiguremode) return;
605 
606 /*
607  * Get an initial estimate of the size we will use.
608  */
609 
610     ForAllPanes(pw, childP) {
611         Pane pane = PaneInfo(*childP);
612 	AssignMax(pane->size, (int) pane->min);
613 	AssignMin(pane->size, (int) pane->max);
614 	sizeused += (int) pane->size + (int) pw->paned.internal_bw;
615     }
616     sizeused -= (int) pw->paned.internal_bw;
617 
618     if ( (dir != ThisBorderOnly) && (sizeused != pane_size) )
619       LoopAndRefigureChildren(pw, paneindex, dir, &sizeused);
620 
621 /*
622  * If we still are not the right size, then tell the pane that
623  * wanted to resize that it can't.
624  */
625 
626 
627     if ( (paneindex != NO_INDEX) && (dir != AnyPane) ) {
628 	Pane pane = PaneInfo(*(pw->composite.children + paneindex));
629         Dimension old = pane->size;
630 
631 	pane->size += pane_size - sizeused;
632 	AssignMax(pane->size, (int) pane->min);
633 	AssignMin(pane->size, (int) pane->max);
634 	sizeused += pane->size - old;
635     }
636 
637 /*
638  * It is possible that the panes will not fit inside the vpaned widget, but
639  * we have tried out best.
640  *
641  * Assign each pane a location.
642  */
643 
644     ForAllPanes(pw, childP) {
645         PaneInfo(*childP)->delta = loc;
646         loc += PaneInfo(*childP)->size + pw->paned.internal_bw;
647     }
648 }
649 
650 /*	Function Name: CommitNewLocations
651  *	Description: Commits all of the previously figured locations.
652  *	Arguments: pw - the paned widget.
653  *	Returns: none.
654  */
655 
656 static void
CommitNewLocations(pw)657 CommitNewLocations(pw)
658 PanedWidget pw;
659 {
660     Widget *childP;
661     XWindowChanges changes;
662 
663     changes.stack_mode = Above;
664 
665     ForAllPanes(pw, childP) {
666 	Pane pane = PaneInfo(*childP);
667 	Widget grip = pane->grip; /* may be NULL. */
668 
669 	if (IsVert(pw)) {
670 	    XtMoveWidget(*childP, (Position) 0, pane->delta);
671 	    XtResizeWidget(*childP, pw->core.width, (Dimension) pane->size,
672 			   (Dimension) 0);
673 
674 	    if (HasGrip(*childP)) {	    /* Move and Display the Grip */
675 	        changes.x = pw->core.width - pw->paned.grip_indent -
676 		            grip->core.width - grip->core.border_width*2;
677 		changes.y = (*childP)->core.y + (*childP)->core.height -
678 		            grip->core.height/2 - grip->core.border_width +
679 			    pw->paned.internal_bw/2;
680 	    }
681 	}
682 	else {
683 	    XtMoveWidget(*childP, pane->delta, (Position) 0);
684 	    XtResizeWidget(*childP, (Dimension) pane->size, pw->core.height,
685 			   (Dimension) 0);
686 
687 
688 	    if (HasGrip(*childP)) {	    /* Move and Display the Grip */
689 	        changes.x = (*childP)->core.x + (*childP)->core.width -
690 	                    grip->core.width/2 - grip->core.border_width +
691 			    pw->paned.internal_bw/2;
692 		changes.y = pw->core.height - pw->paned.grip_indent -
693 	                    grip->core.height - grip->core.border_width*2;
694 	    }
695 	}
696 
697 /*
698  * This should match XtMoveWidget, except that we're also insuring the
699  * grip is Raised in the same request.
700  */
701 
702 	if (HasGrip(*childP)) {
703 	    grip->core.x = changes.x;
704 	    grip->core.y = changes.y;
705 
706 	    if (XtIsRealized(pane->grip))
707 	        XConfigureWindow( XtDisplay(pane->grip), XtWindow(pane->grip),
708 				  CWX | CWY | CWStackMode, &changes );
709 	}
710     }
711     ClearPaneStack(pw);
712 }
713 
714 /*	Function Name: RefigureLocationsAndCommit
715  *	Description: Refigures all locations in a paned widget and
716  *                   commits them immediately.
717  *	Arguments: pw - the paned widget.
718  *	Returns: none
719  *
720  *      This function does nothing if any of the following are true.
721  *      o refiguremode is false.
722  *      o The widget is unrealized.
723  *      o There are no panes is the paned widget.
724  *
725  *      NOTE: This is the resize Procedure for the Paned widget.
726  */
727 
728 static void
RefigureLocationsAndCommit(w)729 RefigureLocationsAndCommit(w)
730 Widget w;
731 {
732     PanedWidget pw = (PanedWidget) w;
733     if (pw->paned.refiguremode && XtIsRealized( (Widget) pw) &&
734 	pw->paned.num_panes > 0 ) {
735 	RefigureLocations(pw, NO_INDEX, AnyPane);
736 	CommitNewLocations(pw);
737     }
738 }
739 
740 /*	Function Name: _DrawRect
741  *	Description: Draws a rectangle in the proper orientation.
742  *	Arguments: pw - the paned widget.
743  *                 gc - gc to used for the draw.
744  *                 on_olc, off_loc - location of upper left corner of rect.
745  *                 on_size, off_size - size of rectangle.
746  *	Returns: none
747  */
748 
749 static void
_DrawRect(pw,gc,on_loc,off_loc,on_size,off_size)750 _DrawRect(pw, gc, on_loc, off_loc, on_size, off_size)
751 PanedWidget pw;
752 GC gc;
753 int on_loc, off_loc;
754 unsigned int on_size, off_size;
755 {
756   if (IsVert(pw))
757     XFillRectangle(XtDisplay(pw), XtWindow(pw), gc,
758 		   off_loc, on_loc, off_size, on_size);
759   else
760     XFillRectangle(XtDisplay(pw), XtWindow(pw), gc,
761 		   on_loc, off_loc, on_size, off_size);
762 }
763 
764 /*	Function Name: _DrawInternalBorders
765  *	Description: Draws the internal borders into the paned widget.
766  *	Arguments: pw - the paned widget.
767  *                 gc - the GC to use to draw the borders.
768  *	Returns: none.
769  */
770 
771 static void
_DrawInternalBorders(pw,gc)772 _DrawInternalBorders(pw, gc)
773 PanedWidget pw;
774 GC gc;
775 {
776     Widget *childP;
777     int on_loc, off_loc;
778     unsigned int on_size, off_size;
779 
780 /*
781  * This is an optimization.  Do not paint the internal borders if
782  * they are the same color as the background.
783  */
784 
785     if (pw->core.background_pixel == pw->paned.internal_bp)
786 	return;
787 
788     off_loc = 0;
789     off_size = (unsigned int) PaneSize( (Widget) pw, !IsVert(pw) );
790     on_size = (unsigned int) pw->paned.internal_bw;
791 
792     ForAllPanes(pw, childP) {
793         on_loc = IsVert(pw) ? (*childP)->core.y : (*childP)->core.x;
794 	on_loc -= (int) on_size;
795 
796 	_DrawRect( pw, gc, on_loc, off_loc, on_size, off_size);
797     }
798 }
799 
800 /*
801  * This allows good reuse of code, as well as descriptive function names.
802  */
803 
804 #define DrawInternalBorders(pw) _DrawInternalBorders((pw), (pw)->paned.normgc);
805 #define EraseInternalBorders(pw) _DrawInternalBorders((pw), (pw)->paned.invgc);
806 
807 /*	Function Name: _DrawTrackLines
808  *	Description: Draws the lines that animate the pane borders when the
809  *                   grips are moved.
810  *	Arguments: pw - the Paned widget.
811  *                 erase - if True then just erase track lines, else
812  *                         draw them in.
813  *	Returns: none.
814  */
815 
816 static void
_DrawTrackLines(pw,erase)817 _DrawTrackLines(pw, erase)
818 PanedWidget pw;
819 Boolean erase;
820 {
821     Widget *childP;
822     Pane pane;
823     int on_loc, off_loc;
824     unsigned int on_size, off_size;
825 
826     off_loc = 0;
827     off_size = PaneSize( (Widget) pw, !IsVert(pw));
828 
829     ForAllPanes(pw, childP) {
830         pane = PaneInfo(*childP);
831 	if ( erase || (pane->olddelta != pane->delta) ) {
832 	    on_size = pw->paned.internal_bw;
833 	    if (!erase) {
834 	        on_loc = PaneInfo(*childP)->olddelta - (int) on_size;
835 
836 		_DrawRect( pw, pw->paned.flipgc,
837 			  on_loc, off_loc, on_size, off_size);
838 	    }
839 
840 	    on_loc = PaneInfo(*childP)->delta - (int) on_size;
841 
842 	    _DrawRect(pw, pw->paned.flipgc,
843 		      on_loc, off_loc, on_size, off_size);
844 
845 	    pane->olddelta = pane->delta;
846 	}
847     }
848 }
849 
850 /*
851  * This allows good reuse of code, as well as descriptive function names.
852  */
853 
854 #define DrawTrackLines(pw) _DrawTrackLines((pw), FALSE);
855 #define EraseTrackLines(pw) _DrawTrackLines((pw), TRUE);
856 
857 /*	Function Name: GetEventLocation
858  *	Description: Converts and event to an x and y location.
859  *	Arguments: pw - the paned widget.
860  *                 event - a pointer to an event.
861  *	Returns: if this is a vertical pane then (y) else (x).
862  */
863 
864 static int
GetEventLocation(pw,event)865 GetEventLocation(pw, event)
866 PanedWidget pw;
867 XEvent *event;
868 {
869     int x, y;
870 
871     switch (event->xany.type) {
872         case ButtonPress:
873 	case ButtonRelease:
874             x = event->xbutton.x_root;
875 	    y = event->xbutton.y_root;
876 	    break;
877 	case KeyPress:
878 	case KeyRelease:
879 	    x = event->xkey.x_root;
880 	    y = event->xkey.y_root;
881 	    break;
882         case MotionNotify:
883 	    x = event->xmotion.x_root;
884 	    y = event->xmotion.y_root;
885 	    break;
886 	default:
887 	    x = pw->paned.start_loc;
888 	    y = pw->paned.start_loc;
889     }
890     if (IsVert(pw))
891         return(y);
892     return(x);
893 }
894 
895 /*	Function Name: StartGripAdjustment
896  *	Description: Starts the grip adjustment procedure.
897  *	Arguments: pw - the paned widget.
898  *                 grip - the grip widget selected.
899  *                 dir - the direction that we are to be moving.
900  *	Returns: none.
901  */
902 
903 static void
StartGripAdjustment(pw,grip,dir)904 StartGripAdjustment(pw, grip, dir)
905 PanedWidget pw;
906 Widget grip;
907 Direction dir;
908 {
909     Widget *childP;
910     Cursor cursor;
911 
912     pw->paned.whichadd = pw->paned.whichsub = (Widget) NULL;
913 
914     if (dir == ThisBorderOnly || dir == UpLeftPane)
915       pw->paned.whichadd = pw->composite.children[PaneIndex(grip)];
916     if (dir == ThisBorderOnly || dir == LowRightPane)
917       pw->paned.whichsub = pw->composite.children[PaneIndex(grip) + 1];
918 
919 /*
920  * Change the cursor.
921  */
922 
923     if (XtIsRealized(grip)) {
924         if ( IsVert(pw) ) {
925 	    if (dir == UpLeftPane)
926 	        cursor = pw->paned.adjust_upper_cursor;
927 	    else if (dir == LowRightPane)
928   	        cursor = pw->paned.adjust_lower_cursor;
929 	    else {
930 	        if ( pw->paned.adjust_this_cursor == None)
931 		    cursor = pw->paned.v_adjust_this_cursor;
932 		else
933 		    cursor = pw->paned.adjust_this_cursor;
934 	    }
935 	}
936 	else {
937 	    if (dir == UpLeftPane)
938 	        cursor = pw->paned.adjust_left_cursor;
939 	    else if (dir == LowRightPane)
940   	        cursor = pw->paned.adjust_right_cursor;
941 	    else {
942 	        if (pw->paned.adjust_this_cursor == None)
943 		    cursor = pw->paned.h_adjust_this_cursor;
944 		else
945 		    cursor = pw->paned.adjust_this_cursor;
946 	    }
947 	}
948 
949 	XDefineCursor(XtDisplay(grip), XtWindow(grip), cursor);
950     }
951 
952     EraseInternalBorders(pw);
953     ForAllPanes(pw, childP)
954         PaneInfo(*childP)->olddelta = -99;
955 }
956 
957 /*	Function Name: MoveGripAdjustment
958  *	Description: This routine moves all panes around when a grip is moved.
959  *	Arguments: pw - the paned widget.
960  *                 grip - the grip that we are moving.
961  *                 dir - the direction the pane we are interested is w.r.t the
962  *                       grip.
963  *                 loc - location of pointer in proper direction.
964  *	Returns: none.
965  */
966 
967 static void
MoveGripAdjustment(pw,grip,dir,loc)968 MoveGripAdjustment(pw, grip, dir, loc)
969 PanedWidget pw;
970 Widget grip;
971 Direction dir;
972 int loc;
973 {
974     int diff, add_size = 0, sub_size = 0;
975 
976     diff = loc - pw->paned.start_loc;
977 
978     if (pw->paned.whichadd)
979         add_size = PaneSize(pw->paned.whichadd, IsVert(pw) ) + diff;
980 
981     if (pw->paned.whichsub)
982         sub_size = PaneSize(pw->paned.whichsub, IsVert(pw) ) - diff;
983 
984 /*
985  * If moving this border only then do not allow either of the borders
986  * to go beyond the min or max size allowed.
987  */
988 
989     if ( (dir == ThisBorderOnly) ) {
990       int old_add_size = add_size, old_sub_size;
991 
992       AssignMax(add_size, (int) PaneInfo(pw->paned.whichadd)->min);
993       AssignMin(add_size, (int) PaneInfo(pw->paned.whichadd)->max);
994       if (add_size != old_add_size)
995 	  sub_size += old_add_size - add_size;
996 
997       old_sub_size = sub_size;
998       AssignMax(sub_size, (int) PaneInfo(pw->paned.whichsub)->min);
999       AssignMin(sub_size, (int) PaneInfo(pw->paned.whichsub)->max);
1000       if (sub_size != old_sub_size) return; /* Abort to current sizes. */
1001     }
1002 
1003     if (add_size != 0)
1004         PaneInfo(pw->paned.whichadd)->size = add_size;
1005     if (sub_size != 0)
1006         PaneInfo(pw->paned.whichsub)->size = sub_size;
1007     RefigureLocations(pw, PaneIndex(grip), dir);
1008     DrawTrackLines(pw);
1009 }
1010 
1011 /*	Function Name: CommitGripAdjustment
1012  *	Description: Commits the grip adjustment.
1013  *	Arguments: pw - the paned widget.
1014  *	Returns: none
1015  */
1016 
1017 static void
CommitGripAdjustment(pw)1018 CommitGripAdjustment(pw)
1019 PanedWidget pw;
1020 {
1021     EraseTrackLines(pw);
1022     CommitNewLocations(pw);
1023     DrawInternalBorders(pw);
1024 
1025 /*
1026  * Since the user selected this size then use it as the preferred size.
1027  */
1028 
1029     if (pw->paned.whichadd) {
1030         Pane pane = PaneInfo(pw->paned.whichadd);
1031 	pane->wp_size = pane->size;
1032     }
1033     if (pw->paned.whichsub) {
1034         Pane pane = PaneInfo(pw->paned.whichsub);
1035 	pane->wp_size = pane->size;
1036     }
1037 }
1038 
1039 /*	Function Name: HandleGrip
1040  *	Description: Handles the grip manipulations.
1041  *	Arguments: grip - the grip widget that has been moved.
1042  *                 junk - ** NOT USED **
1043  *                 call_data - data passed to us from the grip widget.
1044  *	Returns: none.
1045  */
1046 
1047 /* ARGSUSED */
1048 static void
HandleGrip(grip,junk,callData)1049 HandleGrip(grip, junk, callData)
1050 Widget grip;
1051 XtPointer junk, callData;
1052 {
1053     XawGripCallData call_data = (XawGripCallData)callData;
1054     PanedWidget pw = (PanedWidget) XtParent(grip);
1055     int loc;
1056     char action_type;
1057     Cursor cursor;
1058     Direction direction = 0;
1059     Arg arglist[1];
1060 
1061     action_type = *call_data->params[0];
1062 
1063     if (call_data->num_params == 0                             ||
1064 	(action_type == 'C' && call_data->num_params != 1)      ||
1065 	(action_type != 'C' && call_data->num_params != 2))
1066       	XtError( "Paned GripAction has been passed incorrect parameters." );
1067 
1068     if (islower(action_type)) action_type = toupper(action_type);
1069 
1070     loc = GetEventLocation(pw, (XEvent *) (call_data->event));
1071 
1072     if (action_type != 'C') {
1073 	if ( isupper(*call_data->params[1]) )
1074 	  direction = (Direction) *call_data->params[1];
1075 	else
1076 	  direction = (Direction) toupper(*call_data->params[1]);
1077     }
1078 
1079     switch (action_type) {
1080 	case 'S':		/* Start adjustment */
1081             pw->paned.resize_children_to_pref = FALSE;
1082             StartGripAdjustment(pw, grip, direction);
1083 	    pw->paned.start_loc = loc;
1084 	    break;
1085 
1086 	case 'M':
1087 	    MoveGripAdjustment(pw, grip, direction, loc);
1088 	    break;
1089 
1090 	case 'C':
1091 	    XtSetArg(arglist[0], XtNcursor, &cursor);
1092 	    XtGetValues(grip, arglist, (Cardinal) 1);
1093 	    XDefineCursor(XtDisplay(grip), XtWindow(grip), cursor);
1094 	    CommitGripAdjustment(pw);
1095 	    break;
1096 
1097 	default:
1098 	    XtError( "Paned GripAction(); 1st parameter invalid" );
1099      }
1100 }
1101 
1102 /*	Function Name: ResortChildren
1103  *	Description: Resorts the children so that all managed children
1104  *                   are first.
1105  *	Arguments: pw - the paned widget.
1106  *	Returns: none.
1107  */
1108 
1109 static void
ResortChildren(pw)1110 ResortChildren(pw)
1111 PanedWidget pw;
1112 {
1113     Widget * unmanagedP, * childP;
1114 
1115     unmanagedP = NULL;
1116     ForAllChildren(pw, childP) {
1117        if (!IsPane(*childP) || !XtIsManaged(*childP)) {
1118 	   /*
1119 	    * We only keep track of the first unmanaged pane.
1120 	    */
1121 	   if (unmanagedP == NULL)
1122 	       unmanagedP = childP;
1123        }
1124        else {			     /* must be a managed pane */
1125 	   /*
1126 	    * If an earlier widget was not a managed pane, then swap
1127 	    */
1128 	   if (unmanagedP != NULL) {
1129 	       Widget child = *unmanagedP;
1130 	       *unmanagedP = *childP;
1131 	       *childP = child;
1132 	       childP = unmanagedP;  /* easiest to just back-track */
1133 	       unmanagedP = NULL;    /* in case there is another managed */
1134 	   }
1135        }
1136    }
1137 }
1138 
1139 /*	Function Name: ManageAndUnmanageGrips
1140  *	Description: This function manages and unmanages the grips so that
1141  *                   the managed state of each grip matches that of its pane.
1142  *	Arguments: pw - the paned widget.
1143  *	Returns: none.
1144  */
1145 
1146 static void
ManageAndUnmanageGrips(pw)1147 ManageAndUnmanageGrips(pw)
1148 PanedWidget pw;
1149 {
1150    WidgetList managed_grips, unmanaged_grips;
1151    Widget *managedP, *unmanagedP, *childP;
1152    Cardinal alloc_size;
1153 
1154    alloc_size = (Cardinal) sizeof(Widget) * pw->composite.num_children / 2;
1155    managedP = managed_grips = (WidgetList) XtMalloc(alloc_size);
1156    unmanagedP = unmanaged_grips = (WidgetList) XtMalloc(alloc_size);
1157 
1158    ForAllChildren(pw, childP)
1159        if (IsPane(*childP) && HasGrip(*childP)) {
1160 	   if ( XtIsManaged(*childP) )
1161 	       *managedP++ = PaneInfo(*childP)->grip;
1162 	   else
1163 	       *unmanagedP++ = PaneInfo(*childP)->grip;
1164        }
1165 
1166    if (managedP != managed_grips) {
1167        *unmanagedP++ = *--managedP;   /* Last grip is never managed */
1168        XtManageChildren( managed_grips, (Cardinal)(managedP - managed_grips) );
1169    }
1170 
1171    if (unmanagedP != unmanaged_grips)
1172        XtUnmanageChildren( unmanaged_grips,
1173 			   (Cardinal)(unmanagedP - unmanaged_grips) );
1174 
1175    XtFree((char *)managed_grips);
1176    XtFree((char *)unmanaged_grips);
1177 }
1178 
1179 /*	Function Name: CreateGrip
1180  *	Description: Creates a grip widget.
1181  *	Arguments: child - the child that wants a grip to be created for it.
1182  *	Returns: none.
1183  */
1184 
1185 static void
CreateGrip(child)1186 CreateGrip(child)
1187 Widget child;
1188 {
1189     PanedWidget pw = (PanedWidget) XtParent(child);
1190     Arg arglist[2];
1191     Cardinal num_args = 0;
1192     Cursor cursor;
1193 
1194     XtSetArg(arglist[num_args], XtNtranslations, pw->paned.grip_translations);
1195     num_args++;
1196     if ( (cursor = pw->paned.grip_cursor) == None ) {
1197         if (IsVert(pw))
1198 	    cursor = pw->paned.v_grip_cursor;
1199 	else
1200 	    cursor = pw->paned.h_grip_cursor;
1201     }
1202 
1203     XtSetArg(arglist[num_args], XtNcursor, cursor);
1204     num_args++;
1205     PaneInfo(child)->grip = XtCreateWidget("grip", gripWidgetClass, (Widget)pw,
1206 					   arglist, num_args);
1207 
1208     XtAddCallback(PaneInfo(child)->grip, XtNcallback,
1209 		  HandleGrip, (XtPointer) child);
1210 }
1211 
1212 /*	Function Name: GetGCs
1213  *	Description: Gets new GC's.
1214  *	Arguments: w - the paned widget.
1215  *	Returns: none.
1216  */
1217 
1218 static void
GetGCs(w)1219 GetGCs(w)
1220 Widget w;
1221 {
1222     PanedWidget pw = (PanedWidget) w;
1223     XtGCMask valuemask;
1224     XGCValues values;
1225 
1226 /*
1227  * Draw pane borders in internal border color.
1228  */
1229 
1230     values.foreground = pw->paned.internal_bp;
1231     valuemask = GCForeground;
1232     pw->paned.normgc = XtGetGC(w, valuemask, &values);
1233 
1234 /*
1235  * Erase pane borders with background color.
1236  */
1237 
1238     values.foreground = pw->core.background_pixel;
1239     valuemask = GCForeground;
1240     pw->paned.invgc = XtGetGC(w, valuemask, &values);
1241 
1242 /*
1243  * Draw Track lines (animate pane borders) in internal border color ^ bg color.
1244  */
1245 
1246     values.function = GXinvert;
1247     values.plane_mask = pw->paned.internal_bp ^ pw->core.background_pixel;
1248     values.subwindow_mode = IncludeInferiors;
1249     valuemask = GCPlaneMask | GCFunction | GCSubwindowMode;
1250     pw->paned.flipgc = XtGetGC(w, valuemask, &values);
1251 }
1252 
1253 /*	Function Name: SetChildrenPrefSizes.
1254  *	Description: Sets the preferred sizes of the children.
1255  *	Arguments: pw - the paned widget.
1256  *	Returns: none.
1257  */
1258 
1259 static void
SetChildrenPrefSizes(pw,off_size)1260 SetChildrenPrefSizes(pw, off_size)
1261 PanedWidget pw;
1262 Dimension off_size;
1263 {
1264     Widget * childP;
1265     Boolean vert = IsVert(pw);
1266     XtWidgetGeometry request, reply;
1267 
1268     ForAllPanes(pw, childP)
1269         if ( pw->paned.resize_children_to_pref          ||
1270 	     (PaneInfo(*childP)->size == 0)             ||
1271 	     (PaneInfo(*childP)->resize_to_pref) ) {
1272 
1273 	    if (PaneInfo(*childP)->preferred_size != PANED_ASK_CHILD)
1274 	        PaneInfo(*childP)->wp_size=PaneInfo(*childP)->preferred_size;
1275 	    else {
1276 	        if( vert ) {
1277 		    request.request_mode = CWWidth;
1278 		    request.width = off_size;
1279 		}
1280 		else {
1281 		    request.request_mode = CWHeight;
1282 		    request.height = off_size;
1283 		}
1284 
1285 		if ((XtQueryGeometry( *childP, &request, &reply )
1286 	                                         == XtGeometryAlmost) &&
1287 		    (reply.request_mode = (vert ? CWHeight : CWWidth)))
1288 		    PaneInfo(*childP)->wp_size = GetRequestInfo(&reply, vert);
1289 		else
1290 		    PaneInfo(*childP)->wp_size = PaneSize(*childP, vert);
1291 	    }
1292 
1293 	    PaneInfo(*childP)->size = PaneInfo(*childP)->wp_size;
1294 	  }
1295 }
1296 
1297 /*	Function Name: ChangeAllGripCursors
1298  *	Description: Changes all the grip cursors.
1299  *	Arguments: pw - the paned widget.
1300  *	Returns: none
1301  */
1302 
1303 static void
ChangeAllGripCursors(pw)1304 ChangeAllGripCursors(pw)
1305 PanedWidget pw;
1306 {
1307     Widget * childP;
1308 
1309     ForAllPanes(pw, childP) {
1310 	Arg arglist[1];
1311 	Cursor cursor;
1312 
1313 	if ( (cursor = pw->paned.grip_cursor) == None ) {
1314 	    if ( IsVert(pw) )
1315 	        cursor = pw->paned.v_grip_cursor;
1316 	    else
1317 	        cursor = pw->paned.h_grip_cursor;
1318         }
1319 
1320 	if (HasGrip (*childP)) {
1321 	    XtSetArg(arglist[0], XtNcursor, cursor);
1322 	    XtSetValues(PaneInfo(*childP)->grip, arglist, (Cardinal) 1);
1323 	}
1324     }
1325 }
1326 
1327 /************************************************************
1328  *
1329  * Stack Manipulation routines (Private).
1330  *
1331  ************************************************************/
1332 
1333 /*	Function Name: PushPaneStack
1334  *	Description: Pushes a value onto the pane stack.
1335  *	Arguments: pw - the paned widget.
1336  *                 pane - the pane that we are pushing.
1337  *	Returns: none.
1338  */
1339 
1340 static void
PushPaneStack(pw,pane)1341 PushPaneStack(pw, pane)
1342 PanedWidget pw;
1343 Pane pane;
1344 {
1345   PaneStack * stack = (PaneStack *) XtMalloc(sizeof(PaneStack));
1346 
1347   stack->next = pw->paned.stack;
1348   stack->pane = pane;
1349   stack->start_size = pane->size;
1350 
1351   pw->paned.stack = stack;
1352 }
1353 
1354 /*	Function Name: GetPaneStack
1355  *	Description: Gets the top value from the pane stack.
1356  *	Arguments: pw - the paned widget.
1357  *                 shrink - TRUE if we want to shrink this pane,
1358  *                          FALSE otherwise.
1359  * ** RETURNED **  pane - the pane that we are popping.
1360  * ** RETURNED **  start_size - the size that this pane started at.
1361  *	Returns: none.
1362  */
1363 
1364 static void
GetPaneStack(pw,shrink,pane,start_size)1365 GetPaneStack(pw, shrink, pane, start_size)
1366 PanedWidget pw;
1367 Boolean shrink;
1368 Pane * pane;
1369 int * start_size;
1370 {
1371   if (pw->paned.stack == NULL) {
1372     *pane = NULL;
1373     return;
1374   }
1375 
1376   *pane = pw->paned.stack->pane;
1377   *start_size = pw->paned.stack->start_size;
1378 
1379   if (shrink != ((*pane)->size > *start_size)) *pane = NULL;
1380 }
1381 
1382 /*	Function Name: PopPaneStack
1383  *	Description: Pops the top item off the pane stack.
1384  *	Arguments: pw - the paned widget.
1385  *	Returns: TRUE if this is not the last element on the stack.
1386  */
1387 
1388 static Boolean
PopPaneStack(pw)1389 PopPaneStack(pw)
1390 PanedWidget pw;
1391 {
1392   PaneStack * stack = pw->paned.stack;
1393 
1394   if (stack == NULL) return(FALSE);
1395 
1396   pw->paned.stack = stack->next;
1397   XtFree((char*)stack);
1398 
1399   if (pw->paned.stack == NULL) return(FALSE);
1400   return(TRUE);
1401 }
1402 
1403 /*	Function Name: ClearPaneStack
1404  *	Description: removes all entries from the pane stack.
1405  *	Arguments: pw - the paned widget.
1406  *	Returns: none
1407  */
1408 
1409 static void
ClearPaneStack(pw)1410 ClearPaneStack(pw)
1411 PanedWidget pw;
1412 {
1413   while(PopPaneStack(pw));
1414 }
1415 
1416 /************************************************************
1417  *
1418  * Semi-public routines.
1419  *
1420  ************************************************************/
1421 
1422 /*	Function Name: ClassInitialize
1423  *	Description: The Paned widgets class initialization proc.
1424  *	Arguments: none.
1425  *	Returns: none.
1426  */
1427 
1428 static void
ClassInitialize()1429 ClassInitialize()
1430 {
1431     XawInitializeWidgetSet();
1432     XtAddConverter( XtRString, XtROrientation, XmuCvtStringToOrientation,
1433 		    (XtConvertArgList)NULL, (Cardinal)0 );
1434 }
1435 
1436 /* The Geometry Manager only allows changes after Realize if
1437  * allow_resize is True in the constraints record.
1438  *
1439  * For vertically paned widgets:
1440  *
1441  * It only allows height changes, but offers the requested height
1442  * as a compromise if both width and height changes were requested.
1443  *
1444  * For horizontal widgets the converse is true.
1445  * As all good Geometry Managers should, we will return No if the
1446  * request will have no effect; i.e. when the requestor is already
1447  * of the desired geometry.
1448  */
1449 
GeometryManager(w,request,reply)1450 static XtGeometryResult GeometryManager(w, request, reply)
1451 Widget w;
1452 XtWidgetGeometry *request, *reply;
1453 {
1454     PanedWidget pw = (PanedWidget) XtParent(w);
1455     XtGeometryMask mask = request->request_mode;
1456     Dimension old_size, old_wpsize, old_paned_size;
1457     Pane pane = PaneInfo(w);
1458     Boolean vert = IsVert(pw);
1459     Dimension on_size, off_size;
1460     XtGeometryResult result;
1461     Boolean almost = FALSE;
1462 
1463 /*
1464  * If any of the following is true, disallow the geometry change.
1465  *
1466  * o The paned widget is realized and allow_resize is false for the pane.
1467  * o The child did not ask to change the on_size.
1468  * o The request is not a width or height request.
1469  * o The requested size is the same as the current size.
1470  */
1471 
1472     if ( (XtIsRealized((Widget)pw) && !pane->allow_resize)        ||
1473 	 !(mask & ((vert) ? CWHeight : CWWidth))                  ||
1474          (mask & ~(CWWidth | CWHeight))                           ||
1475          (GetRequestInfo(request, vert) ==  PaneSize(w, vert)) ) {
1476         return XtGeometryNo;
1477     }
1478 
1479     old_paned_size = PaneSize( (Widget) pw, vert);
1480     old_wpsize = pane->wp_size;
1481     old_size = pane->size;
1482 
1483     pane->wp_size = pane->size = GetRequestInfo(request, vert);
1484 
1485     AdjustPanedSize(pw, PaneSize((Widget) pw, !vert), &result, &on_size,
1486 		    &off_size);
1487 
1488 /*
1489  * Fool the Refigure Locations proc to thinking that we are
1490  * a different on_size;
1491  */
1492 
1493     if (result != XtGeometryNo) {
1494 	if (vert)
1495 	    pw->core.height = on_size;
1496 	else
1497 	    pw->core.width = on_size;
1498     }
1499 
1500     RefigureLocations(pw, PaneIndex(w), AnyPane);
1501 
1502 /*
1503  * Set up reply struct and reset core on_size.
1504  */
1505 
1506     if (vert) {
1507         pw->core.height = old_paned_size;
1508         reply->height = pane->size;
1509 	reply->width = off_size;
1510     }
1511     else {
1512         pw->core.width = old_paned_size;
1513         reply->height = off_size;
1514 	reply->width = pane->size;
1515     }
1516 
1517 /*
1518  * IF either of the following is true.
1519  *
1520  * o There was a "off_size" request and the new "off_size" is different
1521  *   from that requested.
1522  * o There was no "off_size" request and the new "off_size" is different
1523  *
1524  * o The "on_size" we will allow is different from that requested.
1525  *
1526  * THEN: set almost
1527  */
1528 
1529     if ( !((vert ? CWWidth : CWHeight) & mask)) {
1530         if (vert)
1531 	    request->width = w->core.width;
1532 	else
1533 	    request->height = w->core.height;
1534     }
1535 
1536     almost = GetRequestInfo(request, !vert) != GetRequestInfo(reply, !vert);
1537     almost |= (GetRequestInfo(request, vert) != GetRequestInfo(reply, vert));
1538 
1539     if ( (mask & XtCWQueryOnly) || almost ) {
1540 	pane->wp_size = old_wpsize;
1541 	pane->size = old_size;
1542 	RefigureLocations(pw, PaneIndex(w), AnyPane);
1543 	reply->request_mode = CWWidth | CWHeight;
1544 	if (almost) return XtGeometryAlmost;
1545     }
1546     else {
1547         AdjustPanedSize(pw, PaneSize((Widget) pw, !vert),
1548 			(XtGeometryResult *)NULL,
1549 			(Dimension *)NULL, (Dimension *)NULL);
1550 	CommitNewLocations( pw );	/* layout already refigured. */
1551     }
1552     return XtGeometryDone;
1553 }
1554 
1555 /* ARGSUSED */
Initialize(request,new,args,num_args)1556 static void Initialize(request, new, args, num_args)
1557 Widget request, new;
1558 ArgList args;
1559 Cardinal *num_args;
1560 {
1561     PanedWidget pw = (PanedWidget)new;
1562 
1563     GetGCs( (Widget) pw);
1564 
1565     pw->paned.recursively_called = False;
1566     pw->paned.stack = NULL;
1567     pw->paned.resize_children_to_pref = TRUE;
1568     pw->paned.num_panes = 0;
1569 }
1570 
1571 static void
Realize(w,valueMask,attributes)1572 Realize(w, valueMask, attributes)
1573 Widget w;
1574 Mask *valueMask;
1575 XSetWindowAttributes *attributes;
1576 {
1577     PanedWidget pw = (PanedWidget) w;
1578     Widget * childP;
1579 
1580     if ((attributes->cursor = (pw)->paned.cursor) != None)
1581 	*valueMask |= CWCursor;
1582 
1583     (*SuperClass->core_class.realize) (w, valueMask, attributes);
1584 
1585 /*
1586  * Before we commit the new locations we need to realize all the panes and
1587  * their grips.
1588  */
1589 
1590     ForAllPanes(pw, childP) {
1591         XtRealizeWidget( *childP );
1592 	if (HasGrip (*childP))
1593 	    XtRealizeWidget( PaneInfo(*childP)->grip );
1594     }
1595 
1596     RefigureLocationsAndCommit(w);
1597     pw->paned.resize_children_to_pref = FALSE;
1598 } /* Realize */
1599 
1600 static void
ReleaseGCs(w)1601 ReleaseGCs(w)
1602 Widget w;
1603 {
1604     PanedWidget pw = (PanedWidget)w;
1605 
1606     XtReleaseGC( w, pw->paned.normgc );
1607     XtReleaseGC( w, pw->paned.invgc );
1608     XtReleaseGC( w, pw->paned.flipgc );
1609 }
1610 
InsertChild(w)1611 static void InsertChild(w)
1612 Widget w;
1613 {
1614    Pane pane = PaneInfo(w);
1615 
1616    /* insert the child widget in the composite children list with the */
1617    /* superclass insert_child routine.                                */
1618    (*SuperClass->composite_class.insert_child)(w);
1619 
1620    if (!IsPane(w)) return;
1621 
1622    /* ||| Panes will be added in the order they are created, temporarily */
1623 
1624    if ( pane->show_grip == TRUE ) {
1625        CreateGrip(w);
1626        if (pane->min == PANED_GRIP_SIZE)
1627 	   pane->min = PaneSize(pane->grip, IsVert((PanedWidget) XtParent(w)));
1628    }
1629    else {
1630        if (pane->min == PANED_GRIP_SIZE)
1631 	   pane->min = 1;
1632        pane->grip = NULL;
1633    }
1634 
1635    pane->size = 0;
1636    pane->paned_adjusted_me = FALSE;
1637 
1638 } /* InsertChild */
1639 
DeleteChild(w)1640 static void DeleteChild(w)
1641 Widget w;
1642 {
1643     /* remove the subwidget info and destroy the grip */
1644 
1645     if ( IsPane(w) && HasGrip(w) ) XtDestroyWidget(PaneInfo(w)->grip);
1646 
1647     /* delete the child widget in the composite children list with the */
1648     /* superclass delete_child routine.                                */
1649     (*SuperClass->composite_class.delete_child) (w);
1650 
1651 } /* DeleteChild */
1652 
ChangeManaged(w)1653 static void ChangeManaged(w)
1654    Widget w;
1655 {
1656    PanedWidget pw = (PanedWidget)w;
1657    Boolean vert = IsVert(pw);
1658    Dimension size;
1659    Widget *childP;
1660 
1661    if (pw->paned.recursively_called++) return;
1662 
1663 /*
1664  * If the size is zero then set it to the size of the widest or tallest pane.
1665  */
1666 
1667    if ( (size = PaneSize( (Widget) pw, !vert )) == 0) {
1668        size = 1;
1669        ForAllChildren(pw, childP)
1670 	   if ( XtIsManaged(*childP) && (PaneSize( *childP, !vert ) > size) )
1671 	       size = PaneSize( *childP, !vert );
1672    }
1673 
1674    ManageAndUnmanageGrips(pw);
1675    pw->paned.recursively_called = False;
1676    ResortChildren(pw);
1677 
1678    pw->paned.num_panes = 0;
1679    ForAllChildren(pw, childP)
1680        if ( IsPane(*childP) ) {
1681 	   if ( XtIsManaged(*childP) ) {
1682 	       Pane pane = PaneInfo(*childP);
1683 	       if (HasGrip(*childP))
1684 		   PaneInfo(pane->grip)->position = pw->paned.num_panes;
1685 	       pane->position = pw->paned.num_panes; /*TEMPORY -CDP 3/89 */
1686 	       pw->paned.num_panes++;
1687 	   }
1688 	   else
1689 	       break;		/* This list is already sorted. */
1690        }
1691 
1692    SetChildrenPrefSizes( (PanedWidget) w, size);
1693 
1694 /*
1695  * ForAllPanes can now be used.
1696  */
1697 
1698    if ( PaneSize((Widget) pw, vert) == 0 )
1699        AdjustPanedSize(pw, size, (XtGeometryResult *)NULL,
1700 			(Dimension *)NULL, (Dimension *)NULL);
1701 
1702    if (XtIsRealized( (Widget) pw))
1703        RefigureLocationsAndCommit( (Widget) pw);
1704 
1705 } /* ChangeManaged */
1706 
1707 /*	Function Name: Resize
1708  *	Description: The paned widget's resize proc.
1709  *	Arguments: w - the paned widget.
1710  *	Returns: none.
1711  */
1712 
1713 static void
Resize(w)1714 Resize(w)
1715 Widget w;
1716 {
1717     SetChildrenPrefSizes( (PanedWidget) w,
1718 			  PaneSize(w, !IsVert((PanedWidget) w)) );
1719     RefigureLocationsAndCommit(w);
1720 }
1721 
1722 /* ARGSUSED */
1723 static void
Redisplay(w,event,region)1724 Redisplay(w, event, region)
1725 Widget w;
1726 XEvent * event;			/* unused. */
1727 Region region;			/* unused. */
1728 {
1729     DrawInternalBorders( (PanedWidget) w);
1730 }
1731 
1732 /* ARGSUSED */
1733 static Boolean
SetValues(old,request,new,args,num_args)1734 SetValues(old, request, new, args, num_args)
1735 Widget old, request, new;
1736 ArgList args;
1737 Cardinal *num_args;
1738 {
1739     PanedWidget old_pw = (PanedWidget) old;
1740     PanedWidget new_pw = (PanedWidget) new;
1741     Boolean redisplay = FALSE;
1742 
1743     if ( (old_pw->paned.cursor != new_pw->paned.cursor) && XtIsRealized(new))
1744         XDefineCursor(XtDisplay(new), XtWindow(new), new_pw->paned.cursor);
1745 
1746     if ( (old_pw->paned.internal_bp != new_pw->paned.internal_bp) ||
1747 	 (old_pw->core.background_pixel != new_pw->core.background_pixel) ) {
1748         ReleaseGCs(old);
1749 	GetGCs(new);
1750 	redisplay = TRUE;
1751     }
1752 
1753     if ( (old_pw->paned.grip_cursor != new_pw->paned.grip_cursor)     ||
1754  	 (old_pw->paned.v_grip_cursor != new_pw->paned.v_grip_cursor) ||
1755  	 (old_pw->paned.h_grip_cursor != new_pw->paned.h_grip_cursor) ) {
1756         ChangeAllGripCursors(new_pw);
1757     }
1758 
1759     if ( IsVert(old_pw) != IsVert(new_pw)) {
1760 /*
1761  * We are fooling the paned widget into thinking that is needs to
1762  * fully refigure everything, which is what we want.
1763  */
1764         if (IsVert(new_pw))
1765 	    new_pw->core.width = 0;
1766 	else
1767 	    new_pw->core.height = 0;
1768 
1769 	new_pw->paned.resize_children_to_pref = TRUE;
1770         ChangeManaged(new);	/* Seems weird, but does the right thing. */
1771 	new_pw->paned.resize_children_to_pref = FALSE;
1772 	if (new_pw->paned.grip_cursor == None)
1773 	    ChangeAllGripCursors(new_pw);
1774 	return(TRUE);
1775     }
1776 
1777     if (old_pw->paned.internal_bw != new_pw->paned.internal_bw) {
1778         AdjustPanedSize( new_pw, PaneSize(new, !IsVert(old_pw)),
1779 			 (XtGeometryResult *)NULL,
1780 			 (Dimension *)NULL, (Dimension *)NULL);
1781         RefigureLocationsAndCommit(new);
1782 	return(TRUE);		/* We have done a full configuration, return.*/
1783     }
1784 
1785     if ( (old_pw->paned.grip_indent != new_pw->paned.grip_indent) &&
1786 	 (XtIsRealized(new)) ) {
1787         CommitNewLocations(new_pw);
1788 	redisplay = TRUE;
1789     }
1790 
1791     return (redisplay);
1792 } /* SetValues */
1793 
1794 
1795 /* ARGSUSED */
1796 static Boolean
PaneSetValues(old,request,new,args,num_args)1797 PaneSetValues(old, request, new, args, num_args)
1798 Widget old, request, new;
1799 ArgList args;
1800 Cardinal *num_args;
1801 {
1802     Pane old_pane = PaneInfo(old);
1803     Pane new_pane = PaneInfo(new);
1804     Boolean redisplay = FALSE;
1805 
1806     /* Check for new min and max. */
1807 
1808     if (old_pane->min != new_pane->min || old_pane->max != new_pane->max)
1809 	XawPanedSetMinMax(new, (int)new_pane->min, (int)new_pane->max);
1810 
1811     /* Check for change in XtNshowGrip. */
1812 
1813     if (old_pane->show_grip != new_pane->show_grip) {
1814         if (new_pane->show_grip == TRUE) {
1815 	    CreateGrip(new);
1816 	    if (XtIsRealized(XtParent(new))) {
1817 	        if (XtIsManaged(new)) /* if paned is unrealized this will
1818 				       happen automatically at realize time.*/
1819 		    XtManageChild(PaneInfo(new)->grip); /* manage the grip. */
1820 		XtRealizeWidget(PaneInfo(new)->grip); /* realize the grip. */
1821 	        CommitNewLocations( (PanedWidget) XtParent(new) );
1822 	    }
1823 	}
1824 	else if ( HasGrip(old) ) {
1825 	    XtDestroyWidget( old_pane->grip );
1826 	    new_pane->grip = NULL;
1827 	    redisplay = TRUE;
1828 	}
1829     }
1830 
1831   /* ||| need to look at position changes */
1832 
1833     return(redisplay);
1834 }
1835 
1836 /************************************************************
1837  *
1838  * Public routines.
1839  *
1840  ************************************************************/
1841 
1842 /*	Function Name: XawPanedSetMinMax
1843  *	Description: Sets the min and max size for a pane.
1844  *	Arguments: widget - the widget that is a child of the Paned widget.
1845  *                 min, max - the new min and max size for the pane.
1846  *	Returns: none.
1847  */
1848 
1849 void
1850 #if NeedFunctionPrototypes
XawPanedSetMinMax(Widget widget,int min,int max)1851 XawPanedSetMinMax(Widget widget, int min, int max)
1852 #else
1853 XawPanedSetMinMax(widget, min, max)
1854 Widget widget;
1855 int min, max;
1856 #endif
1857 {
1858     Pane pane = PaneInfo(widget);
1859 
1860     pane->min = min;
1861     pane->max = max;
1862     RefigureLocationsAndCommit( widget->core.parent );
1863 }
1864 
1865 /*	Function Name: XawPanedGetMinMax
1866  *	Description: Gets the min and max size for a pane.
1867  *	Arguments: widget - the widget that is a child of the Paned widget.
1868  ** RETURNED **    min, max - the current min and max size for the pane.
1869  *	Returns: none.
1870  */
1871 
1872 void
1873 #if NeedFunctionPrototypes
XawPanedGetMinMax(Widget widget,int * min,int * max)1874 XawPanedGetMinMax(Widget widget, int *min, int *max)
1875 #else
1876 XawPanedGetMinMax(widget, min, max)
1877 Widget widget;
1878 int    *min, *max;
1879 #endif
1880 {
1881     Pane pane = PaneInfo(widget);
1882 
1883     *min = pane->min;
1884     *max = pane->max;
1885 }
1886 
1887 /*	Function Name: XawPanedSetRefigureMode
1888  *	Description: Allows a flag to be set the will inhibit
1889  *                   the paned widgets relayout routine.
1890  *	Arguments: w - the paned widget.
1891  *                 mode - if FALSE then inhibit refigure.
1892  *	Returns: none.
1893  */
1894 
1895 void
1896 #if NeedFunctionPrototypes
XawPanedSetRefigureMode(Widget w,int mode)1897 XawPanedSetRefigureMode(Widget w,
1898 #if NeedWidePrototypes
1899 			int mode)
1900 #else
1901 			Boolean mode)
1902 #endif
1903 #else
1904 XawPanedSetRefigureMode(w, mode)
1905 Widget w;
1906 Boolean mode;
1907 #endif
1908 {
1909     ((PanedWidget) w)->paned.refiguremode = mode;
1910     RefigureLocationsAndCommit( w );
1911 }
1912 
1913 /*	Function Name: XawPanedGetNumSub
1914  *	Description: Returns the number of panes in the paned widget.
1915  *	Arguments: w - the paned widget.
1916  *	Returns: the number of panes in the paned widget.
1917  */
1918 
1919 int
1920 #if NeedFunctionPrototypes
XawPanedGetNumSub(Widget w)1921 XawPanedGetNumSub(Widget w)
1922 #else
1923 XawPanedGetNumSub(w)
1924 Widget w;
1925 #endif
1926 {
1927     return ((PanedWidget)w)->paned.num_panes;
1928 }
1929 
1930 /*	Function Name: XawPanedAllowResize
1931  *	Description: Allows a flag to be set that determines if the paned
1932  *                   widget will allow geometry requests from this child
1933  *	Arguments: widget - a child of the paned widget.
1934  *	Returns: none.
1935  */
1936 
1937 void
1938 #if NeedFunctionPrototypes
XawPanedAllowResize(Widget widget,int allow_resize)1939 XawPanedAllowResize(Widget widget,
1940 #if NeedWidePrototypes
1941 		    int allow_resize)
1942 #else
1943 		    Boolean allow_resize)
1944 #endif
1945 #else
1946 XawPanedAllowResize(widget, allow_resize)
1947 Widget widget;
1948 Boolean allow_resize;
1949 #endif
1950 {
1951     PaneInfo(widget)->allow_resize = allow_resize;
1952 }
1953