diff options
Diffstat (limited to 'libXaw/src/Paned.c')
-rw-r--r-- | libXaw/src/Paned.c | 4131 |
1 files changed, 2064 insertions, 2067 deletions
diff --git a/libXaw/src/Paned.c b/libXaw/src/Paned.c index a2408ba70..842ea0e59 100644 --- a/libXaw/src/Paned.c +++ b/libXaw/src/Paned.c @@ -1,2067 +1,2064 @@ -/* $Xorg: Paned.c,v 1.4 2001/02/09 02:03:45 xorgcvs Exp $ */ - -/*********************************************************** - -Copyright 1987, 1988, 1994, 1998 The Open Group - -Permission to use, copy, modify, distribute, and sell this software and its -documentation for any purpose is hereby granted without fee, provided that -the above copyright notice appear in all copies and that both that -copyright notice and this permission notice appear in supporting -documentation. - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -Except as contained in this notice, the name of The Open Group shall not be -used in advertising or otherwise to promote the sale, use or other dealings -in this Software without prior written authorization from The Open Group. - - -Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts. - - All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that copyright notice and this permission notice appear in -supporting documentation, and that the name of Digital not be -used in advertising or publicity pertaining to distribution of the -software without specific, written prior permission. - -DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING -ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL -DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR -ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -******************************************************************/ -/* $XFree86: xc/lib/Xaw/Paned.c,v 1.11 2001/08/23 00:03:19 dawes Exp $ */ - -/* - * Updated and significantly modified from the Athena VPaned Widget. - * - * Date: March 1, 1989 - * - * By: Chris D. Peterson - * MIT X Consortium - * kit@expo.lcs.mit.edu - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include <X11/IntrinsicP.h> -#include <X11/cursorfont.h> -#include <X11/StringDefs.h> -#include <X11/Xmu/CharSet.h> -#include <X11/Xmu/Converters.h> -#include <X11/Xmu/Misc.h> -#include <X11/Xmu/SysUtil.h> -#include <X11/Xaw/Grip.h> -#include <X11/Xaw/PanedP.h> -#include <X11/Xaw/XawImP.h> -#include <X11/Xaw/XawInit.h> -#include "Private.h" - -typedef enum { - UpLeftPane = 'U', - LowRightPane = 'L', - ThisBorderOnly = 'T', - AnyPane = 'A' -} Direction; - -#define NO_INDEX -100 -#define IS_GRIP NULL - -#define PaneInfo(w) ((Pane)(w)->core.constraints) -#define HasGrip(w) (PaneInfo(w)->grip != NULL) -#define IsPane(w) ((w)->core.widget_class != gripWidgetClass) -#define PaneIndex(w) (PaneInfo(w)->position) -#define IsVert(w) ((w)->paned.orientation == XtorientVertical) - -#define ForAllPanes(pw, childP) \ -for ((childP) = (pw)->composite.children; \ - (childP) < (pw)->composite.children + (pw)->paned.num_panes; \ - (childP)++) - -#define ForAllChildren(pw, childP) \ -for ((childP) = (pw)->composite.children; \ - (childP) < (pw)->composite.children + (pw)->composite.num_children; \ - (childP)++) - -#define PaneSize(paned, vertical) \ - ((vertical) ? XtHeight(paned) : XtWidth(paned)) - -#define GetRequestInfo(geo, vertical) \ - ((vertical) ? (geo)->height : (geo)->width) - -#define SatisfiesRule1(pane, shrink) \ - (((shrink) && ((pane)->size != (pane)->min)) \ - || (!(shrink) && ((pane)->size != (pane)->max))) - -#define SatisfiesRule2(pane) \ - (!(pane)->skip_adjust || (pane)->paned_adjusted_me) - -#define SatisfiesRule3(pane, shrink) \ - ((pane)->paned_adjusted_me \ - && (((shrink) && ((int)(pane)->wp_size <= (pane)->size)) \ - || (!(shrink) && ((int)(pane)->wp_size >= (pane)->size)))) - - -/* - * Class Methods - */ -static void XawPanedClassInitialize(void); -static void XawPanedChangeManaged(Widget); -static void XawPanedDeleteChild(Widget); -static void XawPanedDestroy(Widget); -static XtGeometryResult XawPanedGeometryManager(Widget, XtWidgetGeometry*, - XtWidgetGeometry*); -static void XawPanedInitialize(Widget, Widget, ArgList, Cardinal*); -static void XawPanedInsertChild(Widget); -static Boolean XawPanedPaneSetValues(Widget, Widget, Widget, - ArgList, Cardinal*); -static void XawPanedRealize(Widget, Mask*, XSetWindowAttributes*); -static void XawPanedRedisplay(Widget, XEvent*, Region); -static void XawPanedResize(Widget); -static Boolean XawPanedSetValues(Widget, Widget, Widget, ArgList, Cardinal*); - -/* - * Prototypes - */ -static void _DrawInternalBorders(PanedWidget, GC); -static void _DrawRect(PanedWidget, GC, int, int, unsigned int, unsigned int); -static void _DrawTrackLines(PanedWidget, Bool); -static void AdjustPanedSize(PanedWidget, unsigned int, XtGeometryResult*, - Dimension*, Dimension*); -static void ChangeAllGripCursors(PanedWidget); -static Pane ChoosePaneToResize(PanedWidget, int, Direction, Bool); -static void ClearPaneStack(PanedWidget); -static void CommitGripAdjustment(PanedWidget); -static void CreateGrip(Widget); -static int GetEventLocation(PanedWidget, XEvent*); -static void GetGCs(Widget); -static void GetPaneStack(PanedWidget, Bool, Pane*, int*); -static void HandleGrip(Widget, XtPointer, XtPointer); -static void LoopAndRefigureChildren(PanedWidget, int, Direction, int*); -static void ManageAndUnmanageGrips(PanedWidget); -static void MoveGripAdjustment(PanedWidget, Widget, Direction, int); -static Bool PopPaneStack(PanedWidget); -static void PushPaneStack(PanedWidget, Pane); -static void RefigureLocations(PanedWidget, int, Direction); -static void RefigureLocationsAndCommit(Widget); -static void ReleaseGCs(Widget); -static void ResortChildren(PanedWidget); -static void SetChildrenPrefSizes(PanedWidget, unsigned int); -static void StartGripAdjustment(PanedWidget, Widget, Direction); - -/* - * Initialization - */ -static char defGripTranslations[] = -"<Btn1Down>:" "GripAction(Start,UpLeftPane)\n" -"<Btn2Down>:" "GripAction(Start,ThisBorderOnly)\n" -"<Btn3Down>:" "GripAction(Start,LowRightPane)\n" -"<Btn1Motion>:" "GripAction(Move,UpLeft)\n" -"<Btn2Motion>:" "GripAction(Move,ThisBorder)\n" -"<Btn3Motion>:" "GripAction(Move,LowRight)\n" -"Any<BtnUp>:" "GripAction(Commit)\n" -; - -#define offset(field) XtOffsetOf(PanedRec, paned.field) -static XtResource resources[] = { - { - XtNinternalBorderColor, - XtCBorderColor, - XtRPixel, - sizeof(Pixel), - offset(internal_bp), - XtRString, - (XtPointer)XtDefaultForeground - }, - { - XtNinternalBorderWidth, - XtCBorderWidth, - XtRDimension, - sizeof(Dimension), - offset(internal_bw), - XtRImmediate, - (XtPointer)1 - }, - { - XtNgripIndent, - XtCGripIndent, - XtRPosition, - sizeof(Position), - offset(grip_indent), - XtRImmediate, - (XtPointer)10 - }, - { - XtNrefigureMode, - XtCBoolean, - XtRBoolean, - sizeof(Boolean), - offset(refiguremode), - XtRImmediate, - (XtPointer)True - }, - { - XtNgripTranslations, - XtCTranslations, - XtRTranslationTable, - sizeof(XtTranslations), - offset(grip_translations), - XtRString, - (XtPointer)defGripTranslations - }, - { - XtNorientation, - XtCOrientation, - XtROrientation, - sizeof(XtOrientation), - offset(orientation), - XtRImmediate, - (XtPointer)XtorientVertical - }, - { - XtNcursor, - XtCCursor, - XtRCursor, - sizeof(Cursor), - offset(cursor), - XtRImmediate, - NULL - }, - { - XtNgripCursor, - XtCCursor, - XtRCursor, - sizeof(Cursor), - offset(grip_cursor), - XtRImmediate, - NULL - }, - { - XtNverticalGripCursor, - XtCCursor, - XtRCursor, - sizeof(Cursor), - offset(v_grip_cursor), - XtRString, - "sb_v_double_arrow" - }, - { - XtNhorizontalGripCursor, - XtCCursor, - XtRCursor, - sizeof(Cursor), - offset(h_grip_cursor), - XtRString, - "sb_h_double_arrow" - }, - { - XtNbetweenCursor, - XtCCursor, - XtRCursor, - sizeof(Cursor), - offset(adjust_this_cursor), - XtRString, - NULL - }, - { - XtNverticalBetweenCursor, - XtCCursor, - XtRCursor, - sizeof(Cursor), - offset(v_adjust_this_cursor), - XtRString, - "sb_left_arrow" - }, - { - XtNhorizontalBetweenCursor, - XtCCursor, - XtRCursor, - sizeof(Cursor), - offset(h_adjust_this_cursor), - XtRString, - "sb_up_arrow" - }, - { - XtNupperCursor, - XtCCursor, - XtRCursor, - sizeof(Cursor), - offset(adjust_upper_cursor), - XtRString, - "sb_up_arrow" - }, - { - XtNlowerCursor, - XtCCursor, - XtRCursor, - sizeof(Cursor), - offset(adjust_lower_cursor), - XtRString, - "sb_down_arrow" - }, - { - XtNleftCursor, - XtCCursor, - XtRCursor, - sizeof(Cursor), - offset(adjust_left_cursor), - XtRString, - "sb_left_arrow" - }, - { - XtNrightCursor, - XtCCursor, - XtRCursor, - sizeof(Cursor), - offset(adjust_right_cursor), - XtRString, - "sb_right_arrow" - }, -}; -#undef offset - -#define offset(field) XtOffsetOf(PanedConstraintsRec, paned.field) -static XtResource subresources[] = { - { - XtNallowResize, - XtCBoolean, - XtRBoolean, - sizeof(Boolean), - offset(allow_resize), - XtRImmediate, - (XtPointer)False - }, - { - XtNposition, - XtCPosition, - XtRInt, - sizeof(int), - offset(position), - XtRImmediate, - (XtPointer)0 - }, - { - XtNmin, - XtCMin, - XtRDimension, - sizeof(Dimension), - offset(min), - XtRImmediate, - (XtPointer)PANED_GRIP_SIZE - }, - { - XtNmax, - XtCMax, - XtRDimension, - sizeof(Dimension), - offset(max), - XtRImmediate, - (XtPointer)~0 - }, - { - XtNpreferredPaneSize, - XtCPreferredPaneSize, - XtRDimension, - sizeof(Dimension), - offset(preferred_size), - XtRImmediate, - (XtPointer)PANED_ASK_CHILD - }, - { - XtNresizeToPreferred, - XtCBoolean, - XtRBoolean, - sizeof(Boolean), - offset(resize_to_pref), - XtRImmediate, - (XtPointer)False - }, - { - XtNskipAdjust, - XtCBoolean, - XtRBoolean, - sizeof(Boolean), - offset(skip_adjust), - XtRImmediate, - (XtPointer)False - }, - { - XtNshowGrip, - XtCShowGrip, - XtRBoolean, - sizeof(Boolean), - offset(show_grip), - XtRImmediate, - (XtPointer)True - }, -}; -#undef offset - -#define SuperClass ((ConstraintWidgetClass)&constraintClassRec) - -PanedClassRec panedClassRec = { - /* core */ - { - (WidgetClass)SuperClass, /* superclass */ - "Paned", /* class name */ - sizeof(PanedRec), /* size */ - XawPanedClassInitialize, /* class_initialize */ - NULL, /* class_part init */ - False, /* class_inited */ - XawPanedInitialize, /* initialize */ - NULL, /* initialize_hook */ - XawPanedRealize, /* realize */ - NULL, /* actions */ - 0, /* num_actions */ - resources, /* resources */ - XtNumber(resources), /* num_resources */ - NULLQUARK, /* xrm_class */ - True, /* compress_motion */ - True, /* compress_exposure */ - True, /* compress_enterleave */ - False, /* visible_interest */ - XawPanedDestroy, /* destroy */ - XawPanedResize, /* resize */ - XawPanedRedisplay, /* expose */ - XawPanedSetValues, /* set_values */ - NULL, /* set_values_hook */ - XtInheritSetValuesAlmost, /* set_values_almost */ - NULL, /* get_values_hook */ - NULL, /* accept_focus */ - XtVersion, /* version */ - NULL, /* callback_private */ - NULL, /* tm_table */ - XtInheritQueryGeometry, /* query_geometry */ - XtInheritDisplayAccelerator, /* display_accelerator */ - NULL, /* extension */ - }, - /* composite */ - { - XawPanedGeometryManager, /* geometry_manager */ - XawPanedChangeManaged, /* change_managed */ - XawPanedInsertChild, /* insert_child */ - XawPanedDeleteChild, /* delete_child */ - NULL, /* extension */ - }, - /* constraint */ - { - subresources, /* subresources */ - XtNumber(subresources), /* subresource_count */ - sizeof(PanedConstraintsRec), /* constraint_size */ - NULL, /* initialize */ - NULL, /* destroy */ - XawPanedPaneSetValues, /* set_values */ - NULL, /* extension */ - }, -}; - -WidgetClass panedWidgetClass = (WidgetClass)&panedClassRec; -WidgetClass vPanedWidgetClass = (WidgetClass)&panedClassRec; - -/* - * Implementation - */ -/* Function: - * AdjustPanedSize - * - * Parameters: - * pw - paned widget to adjust - * off_size - new off_size to use - * result_ret - result of query (return) - * on_size_ret - new on_size (return) - * off_size_ret - new off_size (return) - * - * Description: - * Adjusts the size of the pane. - * - * Returns: - * amount of change in size - */ -static void -AdjustPanedSize(PanedWidget pw, unsigned int off_size, - XtGeometryResult *result_ret, - Dimension *on_size_ret, Dimension *off_size_ret) -{ - Dimension old_size = PaneSize((Widget)pw, IsVert(pw)); - Dimension newsize = 0; - Widget *childP; - XtWidgetGeometry request, reply; - - request.request_mode = CWWidth | CWHeight; - - ForAllPanes(pw, childP) { - int size = Max(PaneInfo(*childP)->size, (int)PaneInfo(*childP)->min); - - AssignMin(size, (int)PaneInfo(*childP)->max); - newsize += size + pw->paned.internal_bw; - } - newsize -= pw->paned.internal_bw; - - if (newsize < 1) - newsize = 1; - - if (IsVert(pw)) { - request.width = off_size; - request.height = newsize; - } - else { - request.width = newsize; - request.height = off_size; - } - - if (result_ret != NULL) { - request.request_mode |= XtCWQueryOnly; - - *result_ret = XtMakeGeometryRequest((Widget)pw, &request, &reply); - _XawImCallVendorShellExtResize((Widget)pw); - - if (newsize == old_size || *result_ret == XtGeometryNo) { - *on_size_ret = old_size; - *off_size_ret = off_size; - return; - } - if (*result_ret != XtGeometryAlmost) { - *on_size_ret = GetRequestInfo(&request, IsVert(pw)); - *off_size_ret = GetRequestInfo(&request, !IsVert(pw)); - return; - } - *on_size_ret = GetRequestInfo(&reply, IsVert(pw)); - *off_size_ret = GetRequestInfo(&reply, !IsVert(pw)); - return; - } - - if (newsize == old_size) - return; - - if (XtMakeGeometryRequest((Widget)pw, &request, &reply) == XtGeometryAlmost) - XtMakeGeometryRequest((Widget)pw, &reply, &request); -} - -/* - * Function: - * ChoosePaneToResize. - * - * Parameters: - * pw - paned widget - * paneindex - index of the current pane - * dir - direction to search first - * shrink - True if we need to shrink a pane, False otherwise - * - * Description: - * This function chooses a pane to resize. - They are chosen using the following rules: - * - * 1) size < max && size > min - * 2) skip adjust == False - * 3) widget not its prefered height - * && this change will bring it closer - * && The user has not resized this pane. - * - * If no widgets are found that fits all the rules then - * rule #3 is broken. - * If there are still no widgets found than - * rule #2 is broken. - * Rule #1 is never broken. - * If no widgets are found then NULL is returned. - * - * Returns: - * pane to resize or NULL - */ -static Pane -ChoosePaneToResize(PanedWidget pw, int paneindex, Direction dir, Bool shrink) -{ - Widget *childP; - int rules = 3; - Direction _dir = dir; - int _index = paneindex; - - if (paneindex == NO_INDEX || dir == AnyPane) { /* Use defaults */ - _dir = LowRightPane; /* Go up - really */ - _index = pw->paned.num_panes - 1; /* Start the last pane, and work - backwards */ - } - childP = pw->composite.children + _index; - - /*CONSTCOND*/ - while(True) { - Pane pane = PaneInfo(*childP); - - if ((rules < 3 || SatisfiesRule3(pane, shrink)) - && (rules < 2 || SatisfiesRule2(pane)) - && SatisfiesRule1(pane, shrink) - && (paneindex != PaneIndex(*childP) || dir == AnyPane)) - return (pane); - - /* - * This is counter-intuitive, but if we are resizing the pane - * above the grip we want to choose a pane below the grip to lose, - * and visa-versa - */ - if (_dir == LowRightPane) - --childP; - else - ++childP; - - /* - * If we have come to and edge then reduce the rule set, and try again - * If we are reduced the rules to none, then return NULL - */ - if ((childP - pw->composite.children) < 0 || - (childP - pw->composite.children) >= pw->paned.num_panes) { - if (--rules < 1) /* less strict rules */ - return (NULL); - childP = pw->composite.children + _index; - } - } -} - -/* - * Function: - * LoopAndRefigureChildren - * - * Parameters: - * pw - paned widget - * paneindex - number of the pane border we are moving - * dir - pane to move (either UpLeftPane or LowRightPane) - * sizeused - current amount of space used (used and returned) - * - * Description: - * If we are resizing either the UpleftPane or LowRight Pane loop - * through all the children to see if any will allow us to resize them. - */ -static void -LoopAndRefigureChildren(PanedWidget pw, int paneindex, Direction dir, - int *sizeused) -{ - int pane_size = (int)PaneSize((Widget)pw, IsVert(pw)); - Boolean shrink = (*sizeused > pane_size); - - if (dir == LowRightPane) - paneindex++; - - /* While all panes do not fit properly */ - while (*sizeused != pane_size) { - /* - * Choose a pane to resize - * First look on the Pane Stack, and then go hunting for another one - * If we fail to find a pane to resize then give up - */ - Pane pane; - int start_size; - Dimension old; - Boolean rule3_ok = False, from_stack = True; - - GetPaneStack(pw, shrink, &pane, &start_size); - if (pane == NULL) { - pane = ChoosePaneToResize(pw, paneindex, dir, shrink); - if (pane == NULL) - return; /* no one to resize, give up */ - - rule3_ok = SatisfiesRule3(pane, shrink); - from_stack = False; - PushPaneStack(pw, pane); - } - - /* - * Try to resize this pane so that all panes will fit, take min and max - * into account - */ - old = pane->size; - pane->size += pane_size - *sizeused; - - if (from_stack) { - if (shrink) { - AssignMax(pane->size, start_size); - } /* don't remove these braces */ - else - AssignMin(pane->size, start_size); - - if (pane->size == start_size) - (void)PopPaneStack(pw); - } - else if (rule3_ok) { - if (shrink) { - AssignMax(pane->size, (int)pane->wp_size); - } /* don't remove these braces */ - else - AssignMin(pane->size, (int)pane->wp_size); - } - - pane->paned_adjusted_me = pane->size != pane->wp_size; - AssignMax(pane->size, (int)pane->min); - AssignMin(pane->size, (int)pane->max); - *sizeused += (pane->size - old); - } -} - -/* - * Function: - * RefigureLocations - * - * Parameters: - * pw - paned widget - * paneindex - child to start refiguring at - * dir - direction to move from child - * - * Description: - * Refigures all locations of children. - * There are special arguments to paneindex and dir, they are: - * paneindex - NO_INDEX. - * dir - AnyPane. - * - * If either of these is true then all panes may be resized and - * the choosing of panes procedes in reverse order starting with the - * last child. - */ -static void -RefigureLocations(PanedWidget pw, int paneindex, Direction dir) -{ - Widget *childP; - int pane_size = (int)PaneSize((Widget)pw, IsVert(pw)); - int sizeused = 0; - Position loc = 0; - - if (pw->paned.num_panes == 0 || !pw->paned.refiguremode) - return; - - /* - * Get an initial estimate of the size we will use - */ - ForAllPanes(pw, childP) { - Pane pane = PaneInfo(*childP); - - AssignMax(pane->size, (int) pane->min); - AssignMin(pane->size, (int) pane->max); - sizeused += (int)pane->size + (int)pw->paned.internal_bw; - } - sizeused -= (int)pw->paned.internal_bw; - - if (dir != ThisBorderOnly && sizeused != pane_size) - LoopAndRefigureChildren(pw, paneindex, dir, &sizeused); - - /* - * If we still are not the right size, then tell the pane that - * wanted to resize that it can't - */ - if (paneindex != NO_INDEX && dir != AnyPane) { - Pane pane = PaneInfo(*(pw->composite.children + paneindex)); - Dimension old = pane->size; - - pane->size += pane_size - sizeused; - AssignMax(pane->size, (int) pane->min); - AssignMin(pane->size, (int) pane->max); - sizeused += pane->size - old; - } - - /* - * It is possible that the panes will not fit inside the vpaned widget, but - * we have tried out best - * - * Assign each pane a location - */ - ForAllPanes(pw, childP) { - PaneInfo(*childP)->delta = loc; - loc += PaneInfo(*childP)->size + pw->paned.internal_bw; - } -} - -/* - * Function: - * CommitNewLocations - * - * Parameters: - * pw - paned widget - * - * Description: - * Commits all of the previously figured locations. - */ -static void -CommitNewLocations(PanedWidget pw) -{ - Widget *childP; - XWindowChanges changes; - - changes.stack_mode = Above; - - ForAllPanes(pw, childP) { - Pane pane = PaneInfo(*childP); - Widget grip = pane->grip; /* may be NULL */ - - if (IsVert(pw)) { - XtMoveWidget(*childP, (Position) 0, pane->delta); - XtResizeWidget(*childP, XtWidth(pw), pane->size, 0); - - if (HasGrip(*childP)) { /* Move and Display the Grip */ - changes.x = XtWidth(pw) - pw->paned.grip_indent - - XtWidth(grip) - (XtBorderWidth(grip) << 1); - changes.y = XtY(*childP) + XtHeight(*childP) - - (XtHeight(grip) >> 1) - XtBorderWidth(grip) + - (pw->paned.internal_bw >> 1); - } - } - else { - XtMoveWidget(*childP, pane->delta, 0); - XtResizeWidget(*childP, pane->size, XtHeight(pw), 0); - - if (HasGrip(*childP)) { /* Move and Display the Grip */ - changes.x = XtX(*childP) + XtWidth(*childP) - - (XtWidth(grip) >> 1) - XtBorderWidth(grip) + - (pw->paned.internal_bw >> 1); - changes.y = XtHeight(pw) - pw->paned.grip_indent - - XtHeight(grip) - (XtBorderWidth(grip) << 1); - } - } - - /* - * This should match XtMoveWidget, except that we're also insuring the - * grip is Raised in the same request - */ - - if (HasGrip(*childP)) { - XtX(grip) = changes.x; - XtY(grip) = changes.y; - - if (XtIsRealized(pane->grip)) - XConfigureWindow(XtDisplay(pane->grip), XtWindow(pane->grip), - CWX | CWY | CWStackMode, &changes); - } - } - ClearPaneStack(pw); -} - -/* - * Function: - * RefigureLocationsAndCommit - * - * Parameters: - * pw - paned widget - * - * Description: - * Refigures all locations in a paned widget and commits them immediately. - * - * This function does nothing if any of the following are true. - * o refiguremode is false. - * o The widget is unrealized. - * o There are no panes is the paned widget. - */ -static void -RefigureLocationsAndCommit(Widget w) -{ - PanedWidget pw = (PanedWidget)w; - - if (pw->paned.refiguremode && XtIsRealized(w) && pw->paned.num_panes > 0) { - RefigureLocations(pw, NO_INDEX, AnyPane); - CommitNewLocations(pw); - } -} - -/* - * Function: - * _DrawRect - * - * Parameters: - * pw - paned widget - * gc - gc to used for the draw - * on_olc - location of upper left corner of rect - * off_loc - "" - * on_size - size of rectangle - * off_size - "" - * - * Description: - * Draws a rectangle in the proper orientation. - */ -static void -_DrawRect(PanedWidget pw, GC gc, int on_loc, int off_loc, - unsigned int on_size, unsigned int off_size) -{ - if (IsVert(pw)) - XFillRectangle(XtDisplay((Widget)pw), XtWindow((Widget)pw), gc, - off_loc, on_loc, off_size, on_size); - else - XFillRectangle(XtDisplay((Widget)pw), XtWindow((Widget)pw), gc, - on_loc, off_loc, on_size, off_size); -} - -/* - * Function: - * _DrawInternalBorders - * - * Parameters: - * pw - paned widget - * gc - GC to use to draw the borders - * - * Description: - * Draws the internal borders into the paned widget. - */ -static void -_DrawInternalBorders(PanedWidget pw, GC gc) -{ - Widget *childP; - int on_loc, off_loc; - unsigned int on_size, off_size; - - /* - * This is an optimization. Do not paint the internal borders if - * they are the same color as the background - */ - if (pw->core.background_pixel == pw->paned.internal_bp) - return; - - off_loc = 0; - off_size = (unsigned int) PaneSize((Widget)pw, !IsVert(pw)); - on_size = (unsigned int)pw->paned.internal_bw; - - ForAllPanes(pw, childP) { - on_loc = IsVert(pw) ? XtY(*childP) : XtX(*childP); - on_loc -= (int)on_size; - - _DrawRect(pw, gc, on_loc, off_loc, on_size, off_size); - } -} - -#define DrawInternalBorders(pw) \ - _DrawInternalBorders((pw), (pw)->paned.normgc) -#define EraseInternalBorders(pw) \ - _DrawInternalBorders((pw), (pw)->paned.invgc) -/* - * Function Name: - * _DrawTrackLines - * - * Parameters: - * pw - Paned widget - * erase - if True then just erase track lines, else draw them in - * - * Description: - * Draws the lines that animate the pane borders when the grips are moved. - */ -static void -_DrawTrackLines(PanedWidget pw, Bool erase) -{ - Widget *childP; - Pane pane; - int on_loc, off_loc; - unsigned int on_size, off_size; - - off_loc = 0; - off_size = PaneSize((Widget)pw, !IsVert(pw)); - - ForAllPanes(pw, childP) { - pane = PaneInfo(*childP); - if (erase || pane->olddelta != pane->delta) { - on_size = pw->paned.internal_bw; - if (!erase) { - on_loc = PaneInfo(*childP)->olddelta - (int) on_size; - _DrawRect(pw, pw->paned.flipgc, - on_loc, off_loc, on_size, off_size); - } - - on_loc = PaneInfo(*childP)->delta - (int)on_size; - - _DrawRect(pw, pw->paned.flipgc, - on_loc, off_loc, on_size, off_size); - - pane->olddelta = pane->delta; - } - } -} - -#define DrawTrackLines(pw) _DrawTrackLines((pw), False); -#define EraseTrackLines(pw) _DrawTrackLines((pw), True); -/* - * Function: - * GetEventLocation - * - * Parameters: - * pw - the paned widget - * event - pointer to an event - * - * Description: - * Converts and event to an x and y location. - * - * Returns: - * if this is a vertical pane then (y) else (x) - */ -static int -GetEventLocation(PanedWidget pw, XEvent *event) -{ - int x, y; - - switch (event->xany.type) { - case ButtonPress: - case ButtonRelease: - x = event->xbutton.x_root; - y = event->xbutton.y_root; - break; - case KeyPress: - case KeyRelease: - x = event->xkey.x_root; - y = event->xkey.y_root; - break; - case MotionNotify: - x = event->xmotion.x_root; - y = event->xmotion.y_root; - break; - default: - x = pw->paned.start_loc; - y = pw->paned.start_loc; - } - - if (IsVert(pw)) - return (y); - - return (x); -} - -/* - * Function: - * StartGripAdjustment - * - * Parameters: - * pw - paned widget - * grip - grip widget selected - * dir - direction that we are to be moving - * - * Description: - * Starts the grip adjustment procedure. - */ -static void -StartGripAdjustment(PanedWidget pw, Widget grip, Direction dir) -{ - Widget *childP; - Cursor cursor; - - pw->paned.whichadd = pw->paned.whichsub = NULL; - - if (dir == ThisBorderOnly || dir == UpLeftPane) - pw->paned.whichadd = pw->composite.children[PaneIndex(grip)]; - if (dir == ThisBorderOnly || dir == LowRightPane) - pw->paned.whichsub = pw->composite.children[PaneIndex(grip) + 1]; - - /* - * Change the cursor - */ - if (XtIsRealized(grip)) { - if (IsVert(pw)) { - if (dir == UpLeftPane) - cursor = pw->paned.adjust_upper_cursor; - else if (dir == LowRightPane) - cursor = pw->paned.adjust_lower_cursor; - else { - if (pw->paned.adjust_this_cursor == None) - cursor = pw->paned.v_adjust_this_cursor; - else - cursor = pw->paned.adjust_this_cursor; - } - } - else { - if (dir == UpLeftPane) - cursor = pw->paned.adjust_left_cursor; - else if (dir == LowRightPane) - cursor = pw->paned.adjust_right_cursor; - else { - if (pw->paned.adjust_this_cursor == None) - cursor = pw->paned.h_adjust_this_cursor; - else - cursor = pw->paned.adjust_this_cursor; - } - } - - XDefineCursor(XtDisplay(grip), XtWindow(grip), cursor); - } - - EraseInternalBorders(pw); - ForAllPanes(pw, childP) - PaneInfo(*childP)->olddelta = -99; - - EraseTrackLines(pw); -} - -/* - * Function: - * MoveGripAdjustment - * - * Parameters: - * pw - paned widget - * grip - grip that we are moving - * dir - direction the pane we are interested is w.r.t the grip - * loc - location of pointer in proper direction - * - * Description: - * This routine moves all panes around when a grip is moved. - */ -static void -MoveGripAdjustment(PanedWidget pw, Widget grip, Direction dir, int loc) -{ - int diff, add_size = 0, sub_size = 0; - - diff = loc - pw->paned.start_loc; - - if (pw->paned.whichadd) - add_size = PaneSize(pw->paned.whichadd, IsVert(pw)) + diff; - - if (pw->paned.whichsub) - sub_size = PaneSize(pw->paned.whichsub, IsVert(pw)) - diff; - - /* - * If moving this border only then do not allow either of the borders - * to go beyond the min or max size allowed - */ - if (dir == ThisBorderOnly) { - int old_add_size = add_size, old_sub_size; - - AssignMax(add_size, (int)PaneInfo(pw->paned.whichadd)->min); - AssignMin(add_size, (int)PaneInfo(pw->paned.whichadd)->max); - if (add_size != old_add_size) - sub_size += old_add_size - add_size; - - old_sub_size = sub_size; - AssignMax(sub_size, (int)PaneInfo(pw->paned.whichsub)->min); - AssignMin(sub_size, (int)PaneInfo(pw->paned.whichsub)->max); - if (sub_size != old_sub_size) - return; /* Abort to current sizes */ - } - - if (add_size != 0) - PaneInfo(pw->paned.whichadd)->size = add_size; - if (sub_size != 0) - PaneInfo(pw->paned.whichsub)->size = sub_size; - RefigureLocations(pw, PaneIndex(grip), dir); - DrawTrackLines(pw); -} - -/* - * Function: - * CommitGripAdjustment - * - * Parameters: - * pw - paned widget - * - * Description: - * Commits the grip adjustment. - */ -static void -CommitGripAdjustment(PanedWidget pw) -{ - EraseTrackLines(pw); - CommitNewLocations(pw); - DrawInternalBorders(pw); - - /* - * Since the user selected this size then use it as the preferred size - */ - if (pw->paned.whichadd) { - Pane pane = PaneInfo(pw->paned.whichadd); - - pane->wp_size = pane->size; - } - if (pw->paned.whichsub) { - Pane pane = PaneInfo(pw->paned.whichsub); - - pane->wp_size = pane->size; - } -} - -/* - * Function: - * HandleGrip - * - * Parameters: - * grip - grip widget that has been moved - * temp - (not used) - * call_data - data passed to us from the grip widget - * - * Description: - * Handles the grip manipulations. - */ -/*ARGSUSED*/ -static void -HandleGrip(Widget grip, XtPointer temp, XtPointer callData) -{ - XawGripCallData call_data = (XawGripCallData)callData; - PanedWidget pw = (PanedWidget) XtParent(grip); - int loc; - char action_type[2], direction[2]; - Cursor cursor; - Arg arglist[1]; - - if (call_data->num_params) - XmuNCopyISOLatin1Uppered(action_type, call_data->params[0], - sizeof(action_type)); - - if (call_data->num_params == 0 - || (action_type[0] == 'C' && call_data->num_params != 1) - || (action_type[0] != 'C' && call_data->num_params != 2)) - XtAppError(XtWidgetToApplicationContext(grip), - "Paned GripAction has been passed incorrect parameters."); - - loc = GetEventLocation(pw, (XEvent *)call_data->event); - - if (action_type[0] != 'C') - XmuNCopyISOLatin1Uppered(direction, call_data->params[1], - sizeof(direction)); - - switch (action_type[0]) { - case 'S': /* Start adjustment */ - pw->paned.resize_children_to_pref = False; - StartGripAdjustment(pw, grip, (Direction)direction[0]); - pw->paned.start_loc = loc; - break; - case 'M': - MoveGripAdjustment(pw, grip, (Direction)direction[0], loc); - break; - case 'C': - XtSetArg(arglist[0], XtNcursor, &cursor); - XtGetValues(grip, arglist, 1); - XDefineCursor(XtDisplay(grip), XtWindow(grip), cursor); - CommitGripAdjustment(pw); - break; - default: - XtAppError(XtWidgetToApplicationContext(grip), - "Paned GripAction(); 1st parameter invalid"); - break; - } -} - -/* - * Function: - * ResortChildren - * - * Arguments: - * pw - paned widget - * - * Description: - * Resorts the children so that all managed children are first. - */ -static void -ResortChildren(PanedWidget pw) -{ - Widget *unmanagedP, *childP; - - unmanagedP = NULL; - ForAllChildren(pw, childP) { - if (!IsPane(*childP) || !XtIsManaged(*childP)) { - /* - * We only keep track of the first unmanaged pane - */ - if (unmanagedP == NULL) - unmanagedP = childP; - } - else { /* must be a managed pane */ - /* - * If an earlier widget was not a managed pane, then swap - */ - if (unmanagedP != NULL) { - Widget child = *unmanagedP; - - *unmanagedP = *childP; - *childP = child; - childP = unmanagedP; /* easiest to just back-track */ - unmanagedP = NULL; /* in case there is another managed */ - } - } - } -} - -/* - * Function: - * ManageAndUnmanageGrips - * - * Parameters: - * pw - paned widget - * - * Description: - * This function manages and unmanages the grips so that - * the managed state of each grip matches that of its pane. - */ -static void -ManageAndUnmanageGrips(PanedWidget pw) -{ - WidgetList managed_grips, unmanaged_grips; - Widget *managedP, *unmanagedP, *childP; - Cardinal alloc_size; - - alloc_size = sizeof(Widget) * (pw->composite.num_children >> 1); - managedP = managed_grips = (WidgetList)XtMalloc(alloc_size); - unmanagedP = unmanaged_grips = (WidgetList)XtMalloc(alloc_size); - - ForAllChildren(pw, childP) - if (IsPane(*childP) && HasGrip(*childP)) { - if (XtIsManaged(*childP)) - *managedP++ = PaneInfo(*childP)->grip; - else - *unmanagedP++ = PaneInfo(*childP)->grip; - } - - if (managedP != managed_grips) { - *unmanagedP++ = *--managedP; /* Last grip is never managed */ - XtManageChildren(managed_grips, managedP - managed_grips); - } - - if (unmanagedP != unmanaged_grips) - XtUnmanageChildren(unmanaged_grips, unmanagedP - unmanaged_grips); - - XtFree((char *)managed_grips); - XtFree((char *)unmanaged_grips); -} - -/* - * Function: - * CreateGrip - * - * Parameters: - * child - child that wants a grip to be created for it - * - * Description: - * Creates a grip widget. - */ -static void -CreateGrip(Widget child) -{ - PanedWidget pw = (PanedWidget)XtParent(child); - Arg arglist[2]; - Cardinal num_args = 0; - Cursor cursor; - - XtSetArg(arglist[num_args], XtNtranslations, pw->paned.grip_translations); - num_args++; - if ((cursor = pw->paned.grip_cursor) == None) { - if (IsVert(pw)) - cursor = pw->paned.v_grip_cursor; - else - cursor = pw->paned.h_grip_cursor; - } - - XtSetArg(arglist[num_args], XtNcursor, cursor); - num_args++; - PaneInfo(child)->grip = XtCreateWidget("grip", gripWidgetClass, (Widget)pw, - arglist, num_args); - - XtAddCallback(PaneInfo(child)->grip, XtNcallback, - HandleGrip, (XtPointer)child); -} - -/* - * Function: - * GetGCs - * - * Parameters: - * w - paned widget - */ -static void -GetGCs(Widget w) -{ - PanedWidget pw = (PanedWidget)w; - XtGCMask valuemask; - XGCValues values; - - /* - * Draw pane borders in internal border color - */ - values.foreground = pw->paned.internal_bp; - valuemask = GCForeground; - pw->paned.normgc = XtGetGC(w, valuemask, &values); - - /* - * Erase pane borders with background color - */ - values.foreground = pw->core.background_pixel; - valuemask = GCForeground; - pw->paned.invgc = XtGetGC(w, valuemask, &values); - - /* - * Draw Track lines (animate pane borders) in - * internal border color ^ bg color - */ - values.function = GXinvert; - values.plane_mask = pw->paned.internal_bp ^ pw->core.background_pixel; - values.subwindow_mode = IncludeInferiors; - valuemask = GCPlaneMask | GCFunction | GCSubwindowMode; - pw->paned.flipgc = XtGetGC(w, valuemask, &values); -} - -/* - * Function: - * SetChildrenPrefSizes - * - * Parameters: - * pw - paned widget - * - * Description: - * Sets the preferred sizes of the children. - */ -static void -SetChildrenPrefSizes(PanedWidget pw, unsigned int off_size) -{ - Widget *childP; - Boolean vert = IsVert(pw); - XtWidgetGeometry request, reply; - - ForAllPanes(pw, childP) - if (pw->paned.resize_children_to_pref || PaneInfo(*childP)->size == 0 || - PaneInfo(*childP)->resize_to_pref) { - if (PaneInfo(*childP)->preferred_size != PANED_ASK_CHILD) - PaneInfo(*childP)->wp_size = PaneInfo(*childP)->preferred_size; - else { - if(vert) { - request.request_mode = CWWidth; - request.width = off_size; - } - else { - request.request_mode = CWHeight; - request.height = off_size; - } - - if ((XtQueryGeometry(*childP, &request, &reply) - == XtGeometryAlmost) - && (reply.request_mode = (vert ? CWHeight : CWWidth))) - PaneInfo(*childP)->wp_size = GetRequestInfo(&reply, vert); - else - PaneInfo(*childP)->wp_size = PaneSize(*childP, vert); - } - - PaneInfo(*childP)->size = PaneInfo(*childP)->wp_size; - } -} - -/* - * Function: - * ChangeAllGripCursors - * - * Parameters: - * pw - paned widget - * - * Description: - * Changes all the grip cursors. - */ -static void -ChangeAllGripCursors(PanedWidget pw) -{ - Widget *childP; - - ForAllPanes(pw, childP) { - Arg arglist[1]; - Cursor cursor; - - if ((cursor = pw->paned.grip_cursor) == None) { - if (IsVert(pw)) - cursor = pw->paned.v_grip_cursor; - else - cursor = pw->paned.h_grip_cursor; - } - - if (HasGrip(*childP)) { - XtSetArg(arglist[0], XtNcursor, cursor); - XtSetValues(PaneInfo(*childP)->grip, arglist, 1); - } - } -} - -/* - * Function: - * PushPaneStack - * - * Parameters: - * pw - paned widget - * pane - pane that we are pushing - * - * Description: - * Pushes a value onto the pane stack. - */ -static void -PushPaneStack(PanedWidget pw, Pane pane) -{ - PaneStack *stack = (PaneStack *)XtMalloc(sizeof(PaneStack)); - - stack->next = pw->paned.stack; - stack->pane = pane; - stack->start_size = pane->size; - - pw->paned.stack = stack; -} - -/* - * Function: - * GetPaneStack - * - * Parameters: - * pw - paned widget - * shrink - True if we want to shrink this pane, False otherwise - * pane - pane that we are popping (return) - * start_size - size that this pane started at (return) - * - * Description: - * Gets the top value from the pane stack. - */ -static void -GetPaneStack(PanedWidget pw, Bool shrink, Pane *pane, int *start_size) -{ - if (pw->paned.stack == NULL) { - *pane = NULL; - return; - } - - *pane = pw->paned.stack->pane; - *start_size = pw->paned.stack->start_size; - - if (shrink != ((*pane)->size > *start_size)) - *pane = NULL; -} - -/* - * Function: - * PopPaneStack - * - * Parameters: - * pw - paned widget - * - * Description: - * Pops the top item off the pane stack. - * - * Returns: True if this is not the last element on the stack - */ -static Bool -PopPaneStack(PanedWidget pw) -{ - PaneStack *stack = pw->paned.stack; - - if (stack == NULL) - return (False); - - pw->paned.stack = stack->next; - XtFree((char *)stack); - - if (pw->paned.stack == NULL) - return (False); - - return (True); -} - -/* - * Function: - * ClearPaneStack - * - * Parameters: - * pw - paned widget - * - * Description: - * Removes all entries from the pane stack. - */ -static void -ClearPaneStack(PanedWidget pw) -{ - while(PopPaneStack(pw)) - ; -} - -static void -XawPanedClassInitialize(void) -{ - XawInitializeWidgetSet(); - XtAddConverter(XtRString, XtROrientation, XmuCvtStringToOrientation, - NULL, 0); - XtSetTypeConverter(XtROrientation, XtRString, XmuCvtOrientationToString, - NULL, 0, XtCacheNone, NULL); -} - -/* The Geometry Manager only allows changes after Realize if - * allow_resize is True in the constraints record. - * - * For vertically paned widgets: - * - * It only allows height changes, but offers the requested height - * as a compromise if both width and height changes were requested. - * - * For horizontal widgets the converse is true. - * As all good Geometry Managers should, we will return No if the - * request will have no effect; i.e. when the requestor is already - * of the desired geometry. - */ -static XtGeometryResult -XawPanedGeometryManager(Widget w, XtWidgetGeometry *request, - XtWidgetGeometry *reply) -{ - PanedWidget pw = (PanedWidget)XtParent(w); - XtGeometryMask mask = request->request_mode; - Dimension old_size, old_wpsize, old_paned_size; - Pane pane = PaneInfo(w); - Boolean vert = IsVert(pw); - Dimension on_size, off_size; - XtGeometryResult result; - Boolean almost = False; - - /* - * If any of the following is true, disallow the geometry change - * - * o The paned widget is realized and allow_resize is false for the pane - * o The child did not ask to change the on_size - * o The request is not a width or height request - * o The requested size is the same as the current size - */ - - if ((XtIsRealized((Widget)pw) && !pane->allow_resize) - || !(mask & (vert ? CWHeight : CWWidth)) - ||(mask & ~(CWWidth | CWHeight)) - || GetRequestInfo(request, vert) == PaneSize(w, vert)) - return (XtGeometryNo); - - old_paned_size = PaneSize((Widget)pw, vert); - old_wpsize = pane->wp_size; - old_size = pane->size; - - pane->wp_size = pane->size = GetRequestInfo(request, vert); - - AdjustPanedSize(pw, PaneSize((Widget)pw, !vert), &result, &on_size, - &off_size); - - /* - * Fool the Refigure Locations proc to thinking that we are - * a different on_size - */ - - if (result != XtGeometryNo) { - if (vert) - XtHeight(pw) = on_size; - else - XtWidth(pw) = on_size; - } - - RefigureLocations(pw, PaneIndex(w), AnyPane); - - /* - * Set up reply struct and reset core on_size - */ - if (vert) { - XtHeight(pw) = old_paned_size; - reply->height = pane->size; - reply->width = off_size; - } - else { - XtWidth(pw) = old_paned_size; - reply->height = off_size; - reply->width = pane->size; - } - - /* - * IF either of the following is true - * - * o There was a "off_size" request and the new "off_size" is different - * from that requested - * o There was no "off_size" request and the new "off_size" is different - * - * o The "on_size" we will allow is different from that requested - * - * THEN: set almost - */ - if (!((vert ? CWWidth : CWHeight) & mask)) { - if (vert) - request->width = XtWidth(w); - else - request->height = XtHeight(w); - } - - almost = GetRequestInfo(request, !vert) != GetRequestInfo(reply, !vert); - almost |= (GetRequestInfo(request, vert) != GetRequestInfo(reply, vert)); - - if ((mask & XtCWQueryOnly) || almost) { - pane->wp_size = old_wpsize; - pane->size = old_size; - RefigureLocations(pw, PaneIndex(w), AnyPane); - reply->request_mode = CWWidth | CWHeight; - if (almost) - return (XtGeometryAlmost); - } - else { - AdjustPanedSize(pw, PaneSize((Widget) pw, !vert), NULL, NULL, NULL); - CommitNewLocations(pw); /* layout already refigured */ - } - - return (XtGeometryDone); -} - -/*ARGSUSED*/ -static void -XawPanedInitialize(Widget request, Widget cnew, - ArgList args, Cardinal *num_args) -{ - PanedWidget pw = (PanedWidget)cnew; - - GetGCs((Widget)pw); - - pw->paned.recursively_called = False; - pw->paned.stack = NULL; - pw->paned.resize_children_to_pref = True; - pw->paned.num_panes = 0; -} - -static void -XawPanedRealize(Widget w, Mask *valueMask, XSetWindowAttributes *attributes) -{ - PanedWidget pw = (PanedWidget)w; - Widget *childP; - - if ((attributes->cursor = pw->paned.cursor) != None) - *valueMask |= CWCursor; - - (*SuperClass->core_class.realize)(w, valueMask, attributes); - - /* - * Before we commit the new locations we need to realize all the panes and - * their grips - */ - ForAllPanes(pw, childP) { - XtRealizeWidget(*childP); - if (HasGrip(*childP)) - XtRealizeWidget(PaneInfo(*childP)->grip); - } - - RefigureLocationsAndCommit(w); - pw->paned.resize_children_to_pref = False; -} - -static void -XawPanedDestroy(Widget w) -{ - ReleaseGCs(w); -} - -static void -ReleaseGCs(Widget w) -{ - PanedWidget pw = (PanedWidget)w; - - XtReleaseGC(w, pw->paned.normgc); - XtReleaseGC(w, pw->paned.invgc); - XtReleaseGC(w, pw->paned.flipgc); -} - -static void -XawPanedInsertChild(Widget w) -{ - Pane pane = PaneInfo(w); - - /* insert the child widget in the composite children list with the - superclass insert_child routine - */ - (*SuperClass->composite_class.insert_child)(w); - - if (!IsPane(w)) - return; - - if (pane->show_grip == True) { - CreateGrip(w); - if (pane->min == PANED_GRIP_SIZE) - pane->min = PaneSize(pane->grip, IsVert((PanedWidget)XtParent(w))); - } - else { - if (pane->min == PANED_GRIP_SIZE) - pane->min = 1; - pane->grip = NULL; - } - - pane->size = 0; - pane->paned_adjusted_me = False; -} - -static void -XawPanedDeleteChild(Widget w) -{ - /* remove the subwidget info and destroy the grip */ - if (IsPane(w) && HasGrip(w)) - XtDestroyWidget(PaneInfo(w)->grip); - - /* delete the child widget in the composite children list with the - superclass delete_child routine - */ - (*SuperClass->composite_class.delete_child)(w); -} - -static void -XawPanedChangeManaged(Widget w) -{ - PanedWidget pw = (PanedWidget)w; - Boolean vert = IsVert(pw); - Dimension size; - Widget *childP; - - if (pw->paned.recursively_called++) - return; - - /* - * If the size is zero then set it to the size of the widest or tallest pane - */ - - if ((size = PaneSize((Widget)pw, !vert)) == 0) { - size = 1; - ForAllChildren(pw, childP) - if (XtIsManaged(*childP) && (PaneSize(*childP, !vert) > size)) - size = PaneSize(*childP, !vert); - } - - ManageAndUnmanageGrips(pw); - pw->paned.recursively_called = False; - ResortChildren(pw); - - pw->paned.num_panes = 0; - ForAllChildren(pw, childP) - if (IsPane(*childP)) { - if (XtIsManaged(*childP)) { - Pane pane = PaneInfo(*childP); - - if (HasGrip(*childP)) - PaneInfo(pane->grip)->position = pw->paned.num_panes; - pane->position = pw->paned.num_panes; /* TEMPORY -CDP 3/89 */ - pw->paned.num_panes++; - } - else - break; /* This list is already sorted */ - } - - SetChildrenPrefSizes((PanedWidget) w, size); - - /* - * ForAllPanes can now be used - */ - if (PaneSize((Widget) pw, vert) == 0) - AdjustPanedSize(pw, size, NULL, NULL, NULL); - - if (XtIsRealized((Widget)pw)) - RefigureLocationsAndCommit((Widget)pw); -} - -static void -XawPanedResize(Widget w) -{ - SetChildrenPrefSizes((PanedWidget)w, - PaneSize(w, !IsVert((PanedWidget)w))); - RefigureLocationsAndCommit(w); -} - -/*ARGSUSED*/ -static void -XawPanedRedisplay(Widget w, XEvent *event, Region region) -{ - DrawInternalBorders((PanedWidget)w); -} - -/*ARGSUSED*/ -static Boolean -XawPanedSetValues(Widget old, Widget request, Widget cnew, - ArgList args, Cardinal *num_args) -{ - PanedWidget old_pw = (PanedWidget)old; - PanedWidget new_pw = (PanedWidget)cnew; - Boolean redisplay = False; - - if ((old_pw->paned.cursor != new_pw->paned.cursor) && XtIsRealized(cnew)) - XDefineCursor(XtDisplay(cnew), XtWindow(cnew), new_pw->paned.cursor); - - if (old_pw->paned.internal_bp != new_pw->paned.internal_bp || - old_pw->core.background_pixel != new_pw->core.background_pixel) { - ReleaseGCs(old); - GetGCs(cnew); - redisplay = True; - } - - if (old_pw->paned.grip_cursor != new_pw->paned.grip_cursor || - old_pw->paned.v_grip_cursor != new_pw->paned.v_grip_cursor || - old_pw->paned.h_grip_cursor != new_pw->paned.h_grip_cursor) - ChangeAllGripCursors(new_pw); - - if (IsVert(old_pw) != IsVert(new_pw)) { - /* - * We are fooling the paned widget into thinking that is needs to - * fully refigure everything, which is what we want - */ - if (IsVert(new_pw)) - XtWidth(new_pw) = 0; - else - XtHeight(new_pw) = 0; - - new_pw->paned.resize_children_to_pref = True; - XawPanedChangeManaged(cnew); /* Seems weird, but does the right thing */ - new_pw->paned.resize_children_to_pref = False; - if (new_pw->paned.grip_cursor == None) - ChangeAllGripCursors(new_pw); - return (True); - } - - if (old_pw->paned.internal_bw != new_pw->paned.internal_bw) { - AdjustPanedSize(new_pw, PaneSize(cnew, !IsVert(old_pw)), - NULL, NULL, NULL); - RefigureLocationsAndCommit(cnew); - return (True); /* We have done a full configuration, return */ - } - - if (old_pw->paned.grip_indent != new_pw->paned.grip_indent && - XtIsRealized(cnew)) { - CommitNewLocations(new_pw); - redisplay = True; - } - - return (redisplay); -} - -/*ARGSUSED*/ -static Boolean -XawPanedPaneSetValues(Widget old, Widget request, Widget cnew, - ArgList args, Cardinal *num_args) -{ - Pane old_pane = PaneInfo(old); - Pane new_pane = PaneInfo(cnew); - Boolean redisplay = False; - - /* Check for new min and max */ - if (old_pane->min != new_pane->min || old_pane->max != new_pane->max) - XawPanedSetMinMax(cnew, (int)new_pane->min, (int)new_pane->max); - - /* Check for change in XtNshowGrip */ - if (old_pane->show_grip != new_pane->show_grip) { - if (new_pane->show_grip == True) { - CreateGrip(cnew); - if (XtIsRealized(XtParent(cnew))) { - if (XtIsManaged(cnew)) /* if paned is unrealized this will - happen automatically at realize time - */ - XtManageChild(PaneInfo(cnew)->grip); /* manage the grip */ - XtRealizeWidget(PaneInfo(cnew)->grip); /* realize the grip */ - CommitNewLocations((PanedWidget)XtParent(cnew)); - } - } - else if (HasGrip(old)) { - XtDestroyWidget(old_pane->grip); - new_pane->grip = NULL; - redisplay = True; - } - } - - return (redisplay); -} - -/* - * Public routines - */ -/* - * Function: - * XawPanedSetMinMax - * - * Parameters: - * widget - widget that is a child of the Paned widget - * min - new min and max size for the pane - * max - "" - * - * Description: - * Sets the min and max size for a pane. - */ -void -XawPanedSetMinMax(Widget widget, int min, int max) -{ - Pane pane = PaneInfo(widget); - - pane->min = min; - pane->max = max; - RefigureLocationsAndCommit(widget->core.parent); -} - -/* - * Function: - * XawPanedGetMinMax - * - * Parameters: - * widget - widget that is a child of the Paned widget - * min - current min and max size for the pane (return) - * max - "" - * - * Description: - * Gets the min and max size for a pane. - */ -void -XawPanedGetMinMax(Widget widget, int *min, int *max) -{ - Pane pane = PaneInfo(widget); - - *min = pane->min; - *max = pane->max; -} - -/* - * Function: - * XawPanedSetRefigureMode - * - * Parameters: - * w - paned widget - * mode - if False then inhibit refigure - * - * Description: - * Allows a flag to be set the will inhibit - * the paned widgets relayout routine. - */ -void -XawPanedSetRefigureMode(Widget w, -#if NeedWidePrototypes - int mode -#else - Boolean mode -#endif -) -{ - ((PanedWidget)w)->paned.refiguremode = mode; - RefigureLocationsAndCommit(w); -} - -/* - * Function: - * XawPanedGetNumSub - * - * Parameters: - * w - paned widget - * - * Description: - * Returns the number of panes in the paned widget. - * Returns: - * the number of panes in the paned widget - */ -int -XawPanedGetNumSub(Widget w) -{ - return (((PanedWidget)w)->paned.num_panes); -} - -/* - * Function: - * XawPanedAllowResize - * - * Parameters: - * widget - child of the paned widget - * - * Description: - * Allows a flag to be set that determines if the paned - * widget will allow geometry requests from this child. - */ -void -XawPanedAllowResize(Widget widget, -#if NeedWidePrototypes - int allow_resize -#else - Boolean allow_resize -#endif -) -{ - PaneInfo(widget)->allow_resize = allow_resize; -} +/***********************************************************
+
+Copyright 1987, 1988, 1994, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+
+Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Digital not be
+used in advertising or publicity pertaining to distribution of the
+software without specific, written prior permission.
+
+DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+******************************************************************/
+
+/*
+ * Updated and significantly modified from the Athena VPaned Widget.
+ *
+ * Date: March 1, 1989
+ *
+ * By: Chris D. Peterson
+ * MIT X Consortium
+ * kit@expo.lcs.mit.edu
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <X11/IntrinsicP.h>
+#include <X11/cursorfont.h>
+#include <X11/StringDefs.h>
+#include <X11/Xmu/CharSet.h>
+#include <X11/Xmu/Converters.h>
+#include <X11/Xmu/Misc.h>
+#include <X11/Xmu/SysUtil.h>
+#include <X11/Xaw/Grip.h>
+#include <X11/Xaw/PanedP.h>
+#include <X11/Xaw/XawImP.h>
+#include <X11/Xaw/XawInit.h>
+#include "Private.h"
+
+typedef enum {
+ UpLeftPane = 'U',
+ LowRightPane = 'L',
+ ThisBorderOnly = 'T',
+ AnyPane = 'A'
+} Direction;
+
+#define NO_INDEX -100
+#define IS_GRIP NULL
+
+#define PaneInfo(w) ((Pane)(w)->core.constraints)
+#define HasGrip(w) (PaneInfo(w)->grip != NULL)
+#define IsPane(w) ((w)->core.widget_class != gripWidgetClass)
+#define PaneIndex(w) (PaneInfo(w)->position)
+#define IsVert(w) ((w)->paned.orientation == XtorientVertical)
+
+#define ForAllPanes(pw, childP) \
+for ((childP) = (pw)->composite.children; \
+ (childP) < (pw)->composite.children + (pw)->paned.num_panes; \
+ (childP)++)
+
+#define ForAllChildren(pw, childP) \
+for ((childP) = (pw)->composite.children; \
+ (childP) < (pw)->composite.children + (pw)->composite.num_children; \
+ (childP)++)
+
+#define PaneSize(paned, vertical) \
+ ((vertical) ? XtHeight(paned) : XtWidth(paned))
+
+#define GetRequestInfo(geo, vertical) \
+ ((vertical) ? (geo)->height : (geo)->width)
+
+#define SatisfiesRule1(pane, shrink) \
+ (((shrink) && ((pane)->size != (pane)->min)) \
+ || (!(shrink) && ((pane)->size != (pane)->max)))
+
+#define SatisfiesRule2(pane) \
+ (!(pane)->skip_adjust || (pane)->paned_adjusted_me)
+
+#define SatisfiesRule3(pane, shrink) \
+ ((pane)->paned_adjusted_me \
+ && (((shrink) && ((int)(pane)->wp_size <= (pane)->size)) \
+ || (!(shrink) && ((int)(pane)->wp_size >= (pane)->size))))
+
+
+/*
+ * Class Methods
+ */
+static void XawPanedClassInitialize(void);
+static void XawPanedChangeManaged(Widget);
+static void XawPanedDeleteChild(Widget);
+static void XawPanedDestroy(Widget);
+static XtGeometryResult XawPanedGeometryManager(Widget, XtWidgetGeometry*,
+ XtWidgetGeometry*);
+static void XawPanedInitialize(Widget, Widget, ArgList, Cardinal*);
+static void XawPanedInsertChild(Widget);
+static Boolean XawPanedPaneSetValues(Widget, Widget, Widget,
+ ArgList, Cardinal*);
+static void XawPanedRealize(Widget, Mask*, XSetWindowAttributes*);
+static void XawPanedRedisplay(Widget, XEvent*, Region);
+static void XawPanedResize(Widget);
+static Boolean XawPanedSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
+
+/*
+ * Prototypes
+ */
+static void _DrawInternalBorders(PanedWidget, GC);
+static void _DrawRect(PanedWidget, GC, int, int, unsigned int, unsigned int);
+static void _DrawTrackLines(PanedWidget, Bool);
+static void AdjustPanedSize(PanedWidget, unsigned int, XtGeometryResult*,
+ Dimension*, Dimension*);
+static void ChangeAllGripCursors(PanedWidget);
+static Pane ChoosePaneToResize(PanedWidget, int, Direction, Bool);
+static void ClearPaneStack(PanedWidget);
+static void CommitGripAdjustment(PanedWidget);
+static void CreateGrip(Widget);
+static int GetEventLocation(PanedWidget, XEvent*);
+static void GetGCs(Widget);
+static void GetPaneStack(PanedWidget, Bool, Pane*, int*);
+static void HandleGrip(Widget, XtPointer, XtPointer);
+static void LoopAndRefigureChildren(PanedWidget, int, Direction, int*);
+static void ManageAndUnmanageGrips(PanedWidget);
+static void MoveGripAdjustment(PanedWidget, Widget, Direction, int);
+static Bool PopPaneStack(PanedWidget);
+static void PushPaneStack(PanedWidget, Pane);
+static void RefigureLocations(PanedWidget, int, Direction);
+static void RefigureLocationsAndCommit(Widget);
+static void ReleaseGCs(Widget);
+static void ResortChildren(PanedWidget);
+static void SetChildrenPrefSizes(PanedWidget, unsigned int);
+static void StartGripAdjustment(PanedWidget, Widget, Direction);
+
+/*
+ * Initialization
+ */
+static char defGripTranslations[] =
+"<Btn1Down>:" "GripAction(Start,UpLeftPane)\n"
+"<Btn2Down>:" "GripAction(Start,ThisBorderOnly)\n"
+"<Btn3Down>:" "GripAction(Start,LowRightPane)\n"
+"<Btn1Motion>:" "GripAction(Move,UpLeft)\n"
+"<Btn2Motion>:" "GripAction(Move,ThisBorder)\n"
+"<Btn3Motion>:" "GripAction(Move,LowRight)\n"
+"Any<BtnUp>:" "GripAction(Commit)\n"
+;
+
+#define offset(field) XtOffsetOf(PanedRec, paned.field)
+static XtResource resources[] = {
+ {
+ XtNinternalBorderColor,
+ XtCBorderColor,
+ XtRPixel,
+ sizeof(Pixel),
+ offset(internal_bp),
+ XtRString,
+ (XtPointer)XtDefaultForeground
+ },
+ {
+ XtNinternalBorderWidth,
+ XtCBorderWidth,
+ XtRDimension,
+ sizeof(Dimension),
+ offset(internal_bw),
+ XtRImmediate,
+ (XtPointer)1
+ },
+ {
+ XtNgripIndent,
+ XtCGripIndent,
+ XtRPosition,
+ sizeof(Position),
+ offset(grip_indent),
+ XtRImmediate,
+ (XtPointer)10
+ },
+ {
+ XtNrefigureMode,
+ XtCBoolean,
+ XtRBoolean,
+ sizeof(Boolean),
+ offset(refiguremode),
+ XtRImmediate,
+ (XtPointer)True
+ },
+ {
+ XtNgripTranslations,
+ XtCTranslations,
+ XtRTranslationTable,
+ sizeof(XtTranslations),
+ offset(grip_translations),
+ XtRString,
+ (XtPointer)defGripTranslations
+ },
+ {
+ XtNorientation,
+ XtCOrientation,
+ XtROrientation,
+ sizeof(XtOrientation),
+ offset(orientation),
+ XtRImmediate,
+ (XtPointer)XtorientVertical
+ },
+ {
+ XtNcursor,
+ XtCCursor,
+ XtRCursor,
+ sizeof(Cursor),
+ offset(cursor),
+ XtRImmediate,
+ NULL
+ },
+ {
+ XtNgripCursor,
+ XtCCursor,
+ XtRCursor,
+ sizeof(Cursor),
+ offset(grip_cursor),
+ XtRImmediate,
+ NULL
+ },
+ {
+ XtNverticalGripCursor,
+ XtCCursor,
+ XtRCursor,
+ sizeof(Cursor),
+ offset(v_grip_cursor),
+ XtRString,
+ "sb_v_double_arrow"
+ },
+ {
+ XtNhorizontalGripCursor,
+ XtCCursor,
+ XtRCursor,
+ sizeof(Cursor),
+ offset(h_grip_cursor),
+ XtRString,
+ "sb_h_double_arrow"
+ },
+ {
+ XtNbetweenCursor,
+ XtCCursor,
+ XtRCursor,
+ sizeof(Cursor),
+ offset(adjust_this_cursor),
+ XtRString,
+ NULL
+ },
+ {
+ XtNverticalBetweenCursor,
+ XtCCursor,
+ XtRCursor,
+ sizeof(Cursor),
+ offset(v_adjust_this_cursor),
+ XtRString,
+ "sb_left_arrow"
+ },
+ {
+ XtNhorizontalBetweenCursor,
+ XtCCursor,
+ XtRCursor,
+ sizeof(Cursor),
+ offset(h_adjust_this_cursor),
+ XtRString,
+ "sb_up_arrow"
+ },
+ {
+ XtNupperCursor,
+ XtCCursor,
+ XtRCursor,
+ sizeof(Cursor),
+ offset(adjust_upper_cursor),
+ XtRString,
+ "sb_up_arrow"
+ },
+ {
+ XtNlowerCursor,
+ XtCCursor,
+ XtRCursor,
+ sizeof(Cursor),
+ offset(adjust_lower_cursor),
+ XtRString,
+ "sb_down_arrow"
+ },
+ {
+ XtNleftCursor,
+ XtCCursor,
+ XtRCursor,
+ sizeof(Cursor),
+ offset(adjust_left_cursor),
+ XtRString,
+ "sb_left_arrow"
+ },
+ {
+ XtNrightCursor,
+ XtCCursor,
+ XtRCursor,
+ sizeof(Cursor),
+ offset(adjust_right_cursor),
+ XtRString,
+ "sb_right_arrow"
+ },
+};
+#undef offset
+
+#define offset(field) XtOffsetOf(PanedConstraintsRec, paned.field)
+static XtResource subresources[] = {
+ {
+ XtNallowResize,
+ XtCBoolean,
+ XtRBoolean,
+ sizeof(Boolean),
+ offset(allow_resize),
+ XtRImmediate,
+ (XtPointer)False
+ },
+ {
+ XtNposition,
+ XtCPosition,
+ XtRInt,
+ sizeof(int),
+ offset(position),
+ XtRImmediate,
+ (XtPointer)0
+ },
+ {
+ XtNmin,
+ XtCMin,
+ XtRDimension,
+ sizeof(Dimension),
+ offset(min),
+ XtRImmediate,
+ (XtPointer)PANED_GRIP_SIZE
+ },
+ {
+ XtNmax,
+ XtCMax,
+ XtRDimension,
+ sizeof(Dimension),
+ offset(max),
+ XtRImmediate,
+ (XtPointer)~0
+ },
+ {
+ XtNpreferredPaneSize,
+ XtCPreferredPaneSize,
+ XtRDimension,
+ sizeof(Dimension),
+ offset(preferred_size),
+ XtRImmediate,
+ (XtPointer)PANED_ASK_CHILD
+ },
+ {
+ XtNresizeToPreferred,
+ XtCBoolean,
+ XtRBoolean,
+ sizeof(Boolean),
+ offset(resize_to_pref),
+ XtRImmediate,
+ (XtPointer)False
+ },
+ {
+ XtNskipAdjust,
+ XtCBoolean,
+ XtRBoolean,
+ sizeof(Boolean),
+ offset(skip_adjust),
+ XtRImmediate,
+ (XtPointer)False
+ },
+ {
+ XtNshowGrip,
+ XtCShowGrip,
+ XtRBoolean,
+ sizeof(Boolean),
+ offset(show_grip),
+ XtRImmediate,
+ (XtPointer)True
+ },
+};
+#undef offset
+
+#define SuperClass ((ConstraintWidgetClass)&constraintClassRec)
+
+PanedClassRec panedClassRec = {
+ /* core */
+ {
+ (WidgetClass)SuperClass, /* superclass */
+ "Paned", /* class name */
+ sizeof(PanedRec), /* size */
+ XawPanedClassInitialize, /* class_initialize */
+ NULL, /* class_part init */
+ False, /* class_inited */
+ XawPanedInitialize, /* initialize */
+ NULL, /* initialize_hook */
+ XawPanedRealize, /* realize */
+ NULL, /* actions */
+ 0, /* num_actions */
+ resources, /* resources */
+ XtNumber(resources), /* num_resources */
+ NULLQUARK, /* xrm_class */
+ True, /* compress_motion */
+ True, /* compress_exposure */
+ True, /* compress_enterleave */
+ False, /* visible_interest */
+ XawPanedDestroy, /* destroy */
+ XawPanedResize, /* resize */
+ XawPanedRedisplay, /* expose */
+ XawPanedSetValues, /* set_values */
+ NULL, /* set_values_hook */
+ XtInheritSetValuesAlmost, /* set_values_almost */
+ NULL, /* get_values_hook */
+ NULL, /* accept_focus */
+ XtVersion, /* version */
+ NULL, /* callback_private */
+ NULL, /* tm_table */
+ XtInheritQueryGeometry, /* query_geometry */
+ XtInheritDisplayAccelerator, /* display_accelerator */
+ NULL, /* extension */
+ },
+ /* composite */
+ {
+ XawPanedGeometryManager, /* geometry_manager */
+ XawPanedChangeManaged, /* change_managed */
+ XawPanedInsertChild, /* insert_child */
+ XawPanedDeleteChild, /* delete_child */
+ NULL, /* extension */
+ },
+ /* constraint */
+ {
+ subresources, /* subresources */
+ XtNumber(subresources), /* subresource_count */
+ sizeof(PanedConstraintsRec), /* constraint_size */
+ NULL, /* initialize */
+ NULL, /* destroy */
+ XawPanedPaneSetValues, /* set_values */
+ NULL, /* extension */
+ },
+};
+
+WidgetClass panedWidgetClass = (WidgetClass)&panedClassRec;
+WidgetClass vPanedWidgetClass = (WidgetClass)&panedClassRec;
+
+/*
+ * Implementation
+ */
+/* Function:
+ * AdjustPanedSize
+ *
+ * Parameters:
+ * pw - paned widget to adjust
+ * off_size - new off_size to use
+ * result_ret - result of query (return)
+ * on_size_ret - new on_size (return)
+ * off_size_ret - new off_size (return)
+ *
+ * Description:
+ * Adjusts the size of the pane.
+ *
+ * Returns:
+ * amount of change in size
+ */
+static void
+AdjustPanedSize(PanedWidget pw, unsigned int off_size,
+ XtGeometryResult *result_ret,
+ Dimension *on_size_ret, Dimension *off_size_ret)
+{
+ Dimension old_size = PaneSize((Widget)pw, IsVert(pw));
+ Dimension newsize = 0;
+ Widget *childP;
+ XtWidgetGeometry request, reply;
+
+ request.request_mode = CWWidth | CWHeight;
+
+ ForAllPanes(pw, childP) {
+ int size = Max(PaneInfo(*childP)->size, (int)PaneInfo(*childP)->min);
+
+ AssignMin(size, (int)PaneInfo(*childP)->max);
+ newsize += size + pw->paned.internal_bw;
+ }
+ newsize -= pw->paned.internal_bw;
+
+ if (newsize < 1)
+ newsize = 1;
+
+ if (IsVert(pw)) {
+ request.width = off_size;
+ request.height = newsize;
+ }
+ else {
+ request.width = newsize;
+ request.height = off_size;
+ }
+
+ if (result_ret != NULL) {
+ request.request_mode |= XtCWQueryOnly;
+
+ *result_ret = XtMakeGeometryRequest((Widget)pw, &request, &reply);
+ _XawImCallVendorShellExtResize((Widget)pw);
+
+ if (newsize == old_size || *result_ret == XtGeometryNo) {
+ *on_size_ret = old_size;
+ *off_size_ret = off_size;
+ return;
+ }
+ if (*result_ret != XtGeometryAlmost) {
+ *on_size_ret = GetRequestInfo(&request, IsVert(pw));
+ *off_size_ret = GetRequestInfo(&request, !IsVert(pw));
+ return;
+ }
+ *on_size_ret = GetRequestInfo(&reply, IsVert(pw));
+ *off_size_ret = GetRequestInfo(&reply, !IsVert(pw));
+ return;
+ }
+
+ if (newsize == old_size)
+ return;
+
+ if (XtMakeGeometryRequest((Widget)pw, &request, &reply) == XtGeometryAlmost)
+ XtMakeGeometryRequest((Widget)pw, &reply, &request);
+}
+
+/*
+ * Function:
+ * ChoosePaneToResize.
+ *
+ * Parameters:
+ * pw - paned widget
+ * paneindex - index of the current pane
+ * dir - direction to search first
+ * shrink - True if we need to shrink a pane, False otherwise
+ *
+ * Description:
+ * This function chooses a pane to resize.
+ They are chosen using the following rules:
+ *
+ * 1) size < max && size > min
+ * 2) skip adjust == False
+ * 3) widget not its prefered height
+ * && this change will bring it closer
+ * && The user has not resized this pane.
+ *
+ * If no widgets are found that fits all the rules then
+ * rule #3 is broken.
+ * If there are still no widgets found than
+ * rule #2 is broken.
+ * Rule #1 is never broken.
+ * If no widgets are found then NULL is returned.
+ *
+ * Returns:
+ * pane to resize or NULL
+ */
+static Pane
+ChoosePaneToResize(PanedWidget pw, int paneindex, Direction dir, Bool shrink)
+{
+ Widget *childP;
+ int rules = 3;
+ Direction _dir = dir;
+ int _index = paneindex;
+
+ if (paneindex == NO_INDEX || dir == AnyPane) { /* Use defaults */
+ _dir = LowRightPane; /* Go up - really */
+ _index = pw->paned.num_panes - 1; /* Start the last pane, and work
+ backwards */
+ }
+ childP = pw->composite.children + _index;
+
+ /*CONSTCOND*/
+ while(True) {
+ Pane pane = PaneInfo(*childP);
+
+ if ((rules < 3 || SatisfiesRule3(pane, shrink))
+ && (rules < 2 || SatisfiesRule2(pane))
+ && SatisfiesRule1(pane, shrink)
+ && (paneindex != PaneIndex(*childP) || dir == AnyPane))
+ return (pane);
+
+ /*
+ * This is counter-intuitive, but if we are resizing the pane
+ * above the grip we want to choose a pane below the grip to lose,
+ * and visa-versa
+ */
+ if (_dir == LowRightPane)
+ --childP;
+ else
+ ++childP;
+
+ /*
+ * If we have come to and edge then reduce the rule set, and try again
+ * If we are reduced the rules to none, then return NULL
+ */
+ if ((childP - pw->composite.children) < 0 ||
+ (childP - pw->composite.children) >= pw->paned.num_panes) {
+ if (--rules < 1) /* less strict rules */
+ return (NULL);
+ childP = pw->composite.children + _index;
+ }
+ }
+}
+
+/*
+ * Function:
+ * LoopAndRefigureChildren
+ *
+ * Parameters:
+ * pw - paned widget
+ * paneindex - number of the pane border we are moving
+ * dir - pane to move (either UpLeftPane or LowRightPane)
+ * sizeused - current amount of space used (used and returned)
+ *
+ * Description:
+ * If we are resizing either the UpleftPane or LowRight Pane loop
+ * through all the children to see if any will allow us to resize them.
+ */
+static void
+LoopAndRefigureChildren(PanedWidget pw, int paneindex, Direction dir,
+ int *sizeused)
+{
+ int pane_size = (int)PaneSize((Widget)pw, IsVert(pw));
+ Boolean shrink = (*sizeused > pane_size);
+
+ if (dir == LowRightPane)
+ paneindex++;
+
+ /* While all panes do not fit properly */
+ while (*sizeused != pane_size) {
+ /*
+ * Choose a pane to resize
+ * First look on the Pane Stack, and then go hunting for another one
+ * If we fail to find a pane to resize then give up
+ */
+ Pane pane;
+ int start_size;
+ Dimension old;
+ Boolean rule3_ok = False, from_stack = True;
+
+ GetPaneStack(pw, shrink, &pane, &start_size);
+ if (pane == NULL) {
+ pane = ChoosePaneToResize(pw, paneindex, dir, shrink);
+ if (pane == NULL)
+ return; /* no one to resize, give up */
+
+ rule3_ok = SatisfiesRule3(pane, shrink);
+ from_stack = False;
+ PushPaneStack(pw, pane);
+ }
+
+ /*
+ * Try to resize this pane so that all panes will fit, take min and max
+ * into account
+ */
+ old = pane->size;
+ pane->size += pane_size - *sizeused;
+
+ if (from_stack) {
+ if (shrink) {
+ AssignMax(pane->size, start_size);
+ } /* don't remove these braces */
+ else
+ AssignMin(pane->size, start_size);
+
+ if (pane->size == start_size)
+ (void)PopPaneStack(pw);
+ }
+ else if (rule3_ok) {
+ if (shrink) {
+ AssignMax(pane->size, (int)pane->wp_size);
+ } /* don't remove these braces */
+ else
+ AssignMin(pane->size, (int)pane->wp_size);
+ }
+
+ pane->paned_adjusted_me = pane->size != pane->wp_size;
+ AssignMax(pane->size, (int)pane->min);
+ AssignMin(pane->size, (int)pane->max);
+ *sizeused += (pane->size - old);
+ }
+}
+
+/*
+ * Function:
+ * RefigureLocations
+ *
+ * Parameters:
+ * pw - paned widget
+ * paneindex - child to start refiguring at
+ * dir - direction to move from child
+ *
+ * Description:
+ * Refigures all locations of children.
+ * There are special arguments to paneindex and dir, they are:
+ * paneindex - NO_INDEX.
+ * dir - AnyPane.
+ *
+ * If either of these is true then all panes may be resized and
+ * the choosing of panes procedes in reverse order starting with the
+ * last child.
+ */
+static void
+RefigureLocations(PanedWidget pw, int paneindex, Direction dir)
+{
+ Widget *childP;
+ int pane_size = (int)PaneSize((Widget)pw, IsVert(pw));
+ int sizeused = 0;
+ Position loc = 0;
+
+ if (pw->paned.num_panes == 0 || !pw->paned.refiguremode)
+ return;
+
+ /*
+ * Get an initial estimate of the size we will use
+ */
+ ForAllPanes(pw, childP) {
+ Pane pane = PaneInfo(*childP);
+
+ AssignMax(pane->size, (int) pane->min);
+ AssignMin(pane->size, (int) pane->max);
+ sizeused += (int)pane->size + (int)pw->paned.internal_bw;
+ }
+ sizeused -= (int)pw->paned.internal_bw;
+
+ if (dir != ThisBorderOnly && sizeused != pane_size)
+ LoopAndRefigureChildren(pw, paneindex, dir, &sizeused);
+
+ /*
+ * If we still are not the right size, then tell the pane that
+ * wanted to resize that it can't
+ */
+ if (paneindex != NO_INDEX && dir != AnyPane) {
+ Pane pane = PaneInfo(*(pw->composite.children + paneindex));
+ Dimension old = pane->size;
+
+ pane->size += pane_size - sizeused;
+ AssignMax(pane->size, (int) pane->min);
+ AssignMin(pane->size, (int) pane->max);
+ sizeused += pane->size - old;
+ }
+
+ /*
+ * It is possible that the panes will not fit inside the vpaned widget, but
+ * we have tried out best
+ *
+ * Assign each pane a location
+ */
+ ForAllPanes(pw, childP) {
+ PaneInfo(*childP)->delta = loc;
+ loc += PaneInfo(*childP)->size + pw->paned.internal_bw;
+ }
+}
+
+/*
+ * Function:
+ * CommitNewLocations
+ *
+ * Parameters:
+ * pw - paned widget
+ *
+ * Description:
+ * Commits all of the previously figured locations.
+ */
+static void
+CommitNewLocations(PanedWidget pw)
+{
+ Widget *childP;
+ XWindowChanges changes;
+
+ changes.stack_mode = Above;
+
+ ForAllPanes(pw, childP) {
+ Pane pane = PaneInfo(*childP);
+ Widget grip = pane->grip; /* may be NULL */
+
+ if (IsVert(pw)) {
+ XtMoveWidget(*childP, (Position) 0, pane->delta);
+ XtResizeWidget(*childP, XtWidth(pw), pane->size, 0);
+
+ if (HasGrip(*childP)) { /* Move and Display the Grip */
+ changes.x = XtWidth(pw) - pw->paned.grip_indent -
+ XtWidth(grip) - (XtBorderWidth(grip) << 1);
+ changes.y = XtY(*childP) + XtHeight(*childP) -
+ (XtHeight(grip) >> 1) - XtBorderWidth(grip) +
+ (pw->paned.internal_bw >> 1);
+ }
+ }
+ else {
+ XtMoveWidget(*childP, pane->delta, 0);
+ XtResizeWidget(*childP, pane->size, XtHeight(pw), 0);
+
+ if (HasGrip(*childP)) { /* Move and Display the Grip */
+ changes.x = XtX(*childP) + XtWidth(*childP) -
+ (XtWidth(grip) >> 1) - XtBorderWidth(grip) +
+ (pw->paned.internal_bw >> 1);
+ changes.y = XtHeight(pw) - pw->paned.grip_indent -
+ XtHeight(grip) - (XtBorderWidth(grip) << 1);
+ }
+ }
+
+ /*
+ * This should match XtMoveWidget, except that we're also insuring the
+ * grip is Raised in the same request
+ */
+
+ if (HasGrip(*childP)) {
+ XtX(grip) = changes.x;
+ XtY(grip) = changes.y;
+
+ if (XtIsRealized(pane->grip))
+ XConfigureWindow(XtDisplay(pane->grip), XtWindow(pane->grip),
+ CWX | CWY | CWStackMode, &changes);
+ }
+ }
+ ClearPaneStack(pw);
+}
+
+/*
+ * Function:
+ * RefigureLocationsAndCommit
+ *
+ * Parameters:
+ * pw - paned widget
+ *
+ * Description:
+ * Refigures all locations in a paned widget and commits them immediately.
+ *
+ * This function does nothing if any of the following are true.
+ * o refiguremode is false.
+ * o The widget is unrealized.
+ * o There are no panes is the paned widget.
+ */
+static void
+RefigureLocationsAndCommit(Widget w)
+{
+ PanedWidget pw = (PanedWidget)w;
+
+ if (pw->paned.refiguremode && XtIsRealized(w) && pw->paned.num_panes > 0) {
+ RefigureLocations(pw, NO_INDEX, AnyPane);
+ CommitNewLocations(pw);
+ }
+}
+
+/*
+ * Function:
+ * _DrawRect
+ *
+ * Parameters:
+ * pw - paned widget
+ * gc - gc to used for the draw
+ * on_olc - location of upper left corner of rect
+ * off_loc - ""
+ * on_size - size of rectangle
+ * off_size - ""
+ *
+ * Description:
+ * Draws a rectangle in the proper orientation.
+ */
+static void
+_DrawRect(PanedWidget pw, GC gc, int on_loc, int off_loc,
+ unsigned int on_size, unsigned int off_size)
+{
+ if (IsVert(pw))
+ XFillRectangle(XtDisplay((Widget)pw), XtWindow((Widget)pw), gc,
+ off_loc, on_loc, off_size, on_size);
+ else
+ XFillRectangle(XtDisplay((Widget)pw), XtWindow((Widget)pw), gc,
+ on_loc, off_loc, on_size, off_size);
+}
+
+/*
+ * Function:
+ * _DrawInternalBorders
+ *
+ * Parameters:
+ * pw - paned widget
+ * gc - GC to use to draw the borders
+ *
+ * Description:
+ * Draws the internal borders into the paned widget.
+ */
+static void
+_DrawInternalBorders(PanedWidget pw, GC gc)
+{
+ Widget *childP;
+ int on_loc, off_loc;
+ unsigned int on_size, off_size;
+
+ /*
+ * This is an optimization. Do not paint the internal borders if
+ * they are the same color as the background
+ */
+ if (pw->core.background_pixel == pw->paned.internal_bp)
+ return;
+
+ off_loc = 0;
+ off_size = (unsigned int) PaneSize((Widget)pw, !IsVert(pw));
+ on_size = (unsigned int)pw->paned.internal_bw;
+
+ ForAllPanes(pw, childP) {
+ on_loc = IsVert(pw) ? XtY(*childP) : XtX(*childP);
+ on_loc -= (int)on_size;
+
+ _DrawRect(pw, gc, on_loc, off_loc, on_size, off_size);
+ }
+}
+
+#define DrawInternalBorders(pw) \
+ _DrawInternalBorders((pw), (pw)->paned.normgc)
+#define EraseInternalBorders(pw) \
+ _DrawInternalBorders((pw), (pw)->paned.invgc)
+/*
+ * Function Name:
+ * _DrawTrackLines
+ *
+ * Parameters:
+ * pw - Paned widget
+ * erase - if True then just erase track lines, else draw them in
+ *
+ * Description:
+ * Draws the lines that animate the pane borders when the grips are moved.
+ */
+static void
+_DrawTrackLines(PanedWidget pw, Bool erase)
+{
+ Widget *childP;
+ Pane pane;
+ int on_loc, off_loc;
+ unsigned int on_size, off_size;
+
+ off_loc = 0;
+ off_size = PaneSize((Widget)pw, !IsVert(pw));
+
+ ForAllPanes(pw, childP) {
+ pane = PaneInfo(*childP);
+ if (erase || pane->olddelta != pane->delta) {
+ on_size = pw->paned.internal_bw;
+ if (!erase) {
+ on_loc = PaneInfo(*childP)->olddelta - (int) on_size;
+ _DrawRect(pw, pw->paned.flipgc,
+ on_loc, off_loc, on_size, off_size);
+ }
+
+ on_loc = PaneInfo(*childP)->delta - (int)on_size;
+
+ _DrawRect(pw, pw->paned.flipgc,
+ on_loc, off_loc, on_size, off_size);
+
+ pane->olddelta = pane->delta;
+ }
+ }
+}
+
+#define DrawTrackLines(pw) _DrawTrackLines((pw), False);
+#define EraseTrackLines(pw) _DrawTrackLines((pw), True);
+/*
+ * Function:
+ * GetEventLocation
+ *
+ * Parameters:
+ * pw - the paned widget
+ * event - pointer to an event
+ *
+ * Description:
+ * Converts and event to an x and y location.
+ *
+ * Returns:
+ * if this is a vertical pane then (y) else (x)
+ */
+static int
+GetEventLocation(PanedWidget pw, XEvent *event)
+{
+ int x, y;
+
+ switch (event->xany.type) {
+ case ButtonPress:
+ case ButtonRelease:
+ x = event->xbutton.x_root;
+ y = event->xbutton.y_root;
+ break;
+ case KeyPress:
+ case KeyRelease:
+ x = event->xkey.x_root;
+ y = event->xkey.y_root;
+ break;
+ case MotionNotify:
+ x = event->xmotion.x_root;
+ y = event->xmotion.y_root;
+ break;
+ default:
+ x = pw->paned.start_loc;
+ y = pw->paned.start_loc;
+ }
+
+ if (IsVert(pw))
+ return (y);
+
+ return (x);
+}
+
+/*
+ * Function:
+ * StartGripAdjustment
+ *
+ * Parameters:
+ * pw - paned widget
+ * grip - grip widget selected
+ * dir - direction that we are to be moving
+ *
+ * Description:
+ * Starts the grip adjustment procedure.
+ */
+static void
+StartGripAdjustment(PanedWidget pw, Widget grip, Direction dir)
+{
+ Widget *childP;
+ Cursor cursor;
+
+ pw->paned.whichadd = pw->paned.whichsub = NULL;
+
+ if (dir == ThisBorderOnly || dir == UpLeftPane)
+ pw->paned.whichadd = pw->composite.children[PaneIndex(grip)];
+ if (dir == ThisBorderOnly || dir == LowRightPane)
+ pw->paned.whichsub = pw->composite.children[PaneIndex(grip) + 1];
+
+ /*
+ * Change the cursor
+ */
+ if (XtIsRealized(grip)) {
+ if (IsVert(pw)) {
+ if (dir == UpLeftPane)
+ cursor = pw->paned.adjust_upper_cursor;
+ else if (dir == LowRightPane)
+ cursor = pw->paned.adjust_lower_cursor;
+ else {
+ if (pw->paned.adjust_this_cursor == None)
+ cursor = pw->paned.v_adjust_this_cursor;
+ else
+ cursor = pw->paned.adjust_this_cursor;
+ }
+ }
+ else {
+ if (dir == UpLeftPane)
+ cursor = pw->paned.adjust_left_cursor;
+ else if (dir == LowRightPane)
+ cursor = pw->paned.adjust_right_cursor;
+ else {
+ if (pw->paned.adjust_this_cursor == None)
+ cursor = pw->paned.h_adjust_this_cursor;
+ else
+ cursor = pw->paned.adjust_this_cursor;
+ }
+ }
+
+ XDefineCursor(XtDisplay(grip), XtWindow(grip), cursor);
+ }
+
+ EraseInternalBorders(pw);
+ ForAllPanes(pw, childP)
+ PaneInfo(*childP)->olddelta = -99;
+
+ EraseTrackLines(pw);
+}
+
+/*
+ * Function:
+ * MoveGripAdjustment
+ *
+ * Parameters:
+ * pw - paned widget
+ * grip - grip that we are moving
+ * dir - direction the pane we are interested is w.r.t the grip
+ * loc - location of pointer in proper direction
+ *
+ * Description:
+ * This routine moves all panes around when a grip is moved.
+ */
+static void
+MoveGripAdjustment(PanedWidget pw, Widget grip, Direction dir, int loc)
+{
+ int diff, add_size = 0, sub_size = 0;
+
+ diff = loc - pw->paned.start_loc;
+
+ if (pw->paned.whichadd)
+ add_size = PaneSize(pw->paned.whichadd, IsVert(pw)) + diff;
+
+ if (pw->paned.whichsub)
+ sub_size = PaneSize(pw->paned.whichsub, IsVert(pw)) - diff;
+
+ /*
+ * If moving this border only then do not allow either of the borders
+ * to go beyond the min or max size allowed
+ */
+ if (dir == ThisBorderOnly) {
+ int old_add_size = add_size, old_sub_size;
+
+ AssignMax(add_size, (int)PaneInfo(pw->paned.whichadd)->min);
+ AssignMin(add_size, (int)PaneInfo(pw->paned.whichadd)->max);
+ if (add_size != old_add_size)
+ sub_size += old_add_size - add_size;
+
+ old_sub_size = sub_size;
+ AssignMax(sub_size, (int)PaneInfo(pw->paned.whichsub)->min);
+ AssignMin(sub_size, (int)PaneInfo(pw->paned.whichsub)->max);
+ if (sub_size != old_sub_size)
+ return; /* Abort to current sizes */
+ }
+
+ if (add_size != 0)
+ PaneInfo(pw->paned.whichadd)->size = add_size;
+ if (sub_size != 0)
+ PaneInfo(pw->paned.whichsub)->size = sub_size;
+ RefigureLocations(pw, PaneIndex(grip), dir);
+ DrawTrackLines(pw);
+}
+
+/*
+ * Function:
+ * CommitGripAdjustment
+ *
+ * Parameters:
+ * pw - paned widget
+ *
+ * Description:
+ * Commits the grip adjustment.
+ */
+static void
+CommitGripAdjustment(PanedWidget pw)
+{
+ EraseTrackLines(pw);
+ CommitNewLocations(pw);
+ DrawInternalBorders(pw);
+
+ /*
+ * Since the user selected this size then use it as the preferred size
+ */
+ if (pw->paned.whichadd) {
+ Pane pane = PaneInfo(pw->paned.whichadd);
+
+ pane->wp_size = pane->size;
+ }
+ if (pw->paned.whichsub) {
+ Pane pane = PaneInfo(pw->paned.whichsub);
+
+ pane->wp_size = pane->size;
+ }
+}
+
+/*
+ * Function:
+ * HandleGrip
+ *
+ * Parameters:
+ * grip - grip widget that has been moved
+ * temp - (not used)
+ * call_data - data passed to us from the grip widget
+ *
+ * Description:
+ * Handles the grip manipulations.
+ */
+/*ARGSUSED*/
+static void
+HandleGrip(Widget grip, XtPointer temp, XtPointer callData)
+{
+ XawGripCallData call_data = (XawGripCallData)callData;
+ PanedWidget pw = (PanedWidget) XtParent(grip);
+ int loc;
+ char action_type[2], direction[2];
+ Cursor cursor;
+ Arg arglist[1];
+
+ if (call_data->num_params)
+ XmuNCopyISOLatin1Uppered(action_type, call_data->params[0],
+ sizeof(action_type));
+
+ if (call_data->num_params == 0
+ || (action_type[0] == 'C' && call_data->num_params != 1)
+ || (action_type[0] != 'C' && call_data->num_params != 2))
+ XtAppError(XtWidgetToApplicationContext(grip),
+ "Paned GripAction has been passed incorrect parameters.");
+
+ loc = GetEventLocation(pw, (XEvent *)call_data->event);
+
+ if (action_type[0] != 'C')
+ XmuNCopyISOLatin1Uppered(direction, call_data->params[1],
+ sizeof(direction));
+
+ switch (action_type[0]) {
+ case 'S': /* Start adjustment */
+ pw->paned.resize_children_to_pref = False;
+ StartGripAdjustment(pw, grip, (Direction)direction[0]);
+ pw->paned.start_loc = loc;
+ break;
+ case 'M':
+ MoveGripAdjustment(pw, grip, (Direction)direction[0], loc);
+ break;
+ case 'C':
+ XtSetArg(arglist[0], XtNcursor, &cursor);
+ XtGetValues(grip, arglist, 1);
+ XDefineCursor(XtDisplay(grip), XtWindow(grip), cursor);
+ CommitGripAdjustment(pw);
+ break;
+ default:
+ XtAppError(XtWidgetToApplicationContext(grip),
+ "Paned GripAction(); 1st parameter invalid");
+ break;
+ }
+}
+
+/*
+ * Function:
+ * ResortChildren
+ *
+ * Arguments:
+ * pw - paned widget
+ *
+ * Description:
+ * Resorts the children so that all managed children are first.
+ */
+static void
+ResortChildren(PanedWidget pw)
+{
+ Widget *unmanagedP, *childP;
+
+ unmanagedP = NULL;
+ ForAllChildren(pw, childP) {
+ if (!IsPane(*childP) || !XtIsManaged(*childP)) {
+ /*
+ * We only keep track of the first unmanaged pane
+ */
+ if (unmanagedP == NULL)
+ unmanagedP = childP;
+ }
+ else { /* must be a managed pane */
+ /*
+ * If an earlier widget was not a managed pane, then swap
+ */
+ if (unmanagedP != NULL) {
+ Widget child = *unmanagedP;
+
+ *unmanagedP = *childP;
+ *childP = child;
+ childP = unmanagedP; /* easiest to just back-track */
+ unmanagedP = NULL; /* in case there is another managed */
+ }
+ }
+ }
+}
+
+/*
+ * Function:
+ * ManageAndUnmanageGrips
+ *
+ * Parameters:
+ * pw - paned widget
+ *
+ * Description:
+ * This function manages and unmanages the grips so that
+ * the managed state of each grip matches that of its pane.
+ */
+static void
+ManageAndUnmanageGrips(PanedWidget pw)
+{
+ WidgetList managed_grips, unmanaged_grips;
+ Widget *managedP, *unmanagedP, *childP;
+ Cardinal alloc_size;
+
+ alloc_size = sizeof(Widget) * (pw->composite.num_children >> 1);
+ managedP = managed_grips = (WidgetList)XtMalloc(alloc_size);
+ unmanagedP = unmanaged_grips = (WidgetList)XtMalloc(alloc_size);
+
+ ForAllChildren(pw, childP)
+ if (IsPane(*childP) && HasGrip(*childP)) {
+ if (XtIsManaged(*childP))
+ *managedP++ = PaneInfo(*childP)->grip;
+ else
+ *unmanagedP++ = PaneInfo(*childP)->grip;
+ }
+
+ if (managedP != managed_grips) {
+ *unmanagedP++ = *--managedP; /* Last grip is never managed */
+ XtManageChildren(managed_grips, managedP - managed_grips);
+ }
+
+ if (unmanagedP != unmanaged_grips)
+ XtUnmanageChildren(unmanaged_grips, unmanagedP - unmanaged_grips);
+
+ XtFree((char *)managed_grips);
+ XtFree((char *)unmanaged_grips);
+}
+
+/*
+ * Function:
+ * CreateGrip
+ *
+ * Parameters:
+ * child - child that wants a grip to be created for it
+ *
+ * Description:
+ * Creates a grip widget.
+ */
+static void
+CreateGrip(Widget child)
+{
+ PanedWidget pw = (PanedWidget)XtParent(child);
+ Arg arglist[2];
+ Cardinal num_args = 0;
+ Cursor cursor;
+
+ XtSetArg(arglist[num_args], XtNtranslations, pw->paned.grip_translations);
+ num_args++;
+ if ((cursor = pw->paned.grip_cursor) == None) {
+ if (IsVert(pw))
+ cursor = pw->paned.v_grip_cursor;
+ else
+ cursor = pw->paned.h_grip_cursor;
+ }
+
+ XtSetArg(arglist[num_args], XtNcursor, cursor);
+ num_args++;
+ PaneInfo(child)->grip = XtCreateWidget("grip", gripWidgetClass, (Widget)pw,
+ arglist, num_args);
+
+ XtAddCallback(PaneInfo(child)->grip, XtNcallback,
+ HandleGrip, (XtPointer)child);
+}
+
+/*
+ * Function:
+ * GetGCs
+ *
+ * Parameters:
+ * w - paned widget
+ */
+static void
+GetGCs(Widget w)
+{
+ PanedWidget pw = (PanedWidget)w;
+ XtGCMask valuemask;
+ XGCValues values;
+
+ /*
+ * Draw pane borders in internal border color
+ */
+ values.foreground = pw->paned.internal_bp;
+ valuemask = GCForeground;
+ pw->paned.normgc = XtGetGC(w, valuemask, &values);
+
+ /*
+ * Erase pane borders with background color
+ */
+ values.foreground = pw->core.background_pixel;
+ valuemask = GCForeground;
+ pw->paned.invgc = XtGetGC(w, valuemask, &values);
+
+ /*
+ * Draw Track lines (animate pane borders) in
+ * internal border color ^ bg color
+ */
+ values.function = GXinvert;
+ values.plane_mask = pw->paned.internal_bp ^ pw->core.background_pixel;
+ values.subwindow_mode = IncludeInferiors;
+ valuemask = GCPlaneMask | GCFunction | GCSubwindowMode;
+ pw->paned.flipgc = XtGetGC(w, valuemask, &values);
+}
+
+/*
+ * Function:
+ * SetChildrenPrefSizes
+ *
+ * Parameters:
+ * pw - paned widget
+ *
+ * Description:
+ * Sets the preferred sizes of the children.
+ */
+static void
+SetChildrenPrefSizes(PanedWidget pw, unsigned int off_size)
+{
+ Widget *childP;
+ Boolean vert = IsVert(pw);
+ XtWidgetGeometry request, reply;
+
+ ForAllPanes(pw, childP)
+ if (pw->paned.resize_children_to_pref || PaneInfo(*childP)->size == 0 ||
+ PaneInfo(*childP)->resize_to_pref) {
+ if (PaneInfo(*childP)->preferred_size != PANED_ASK_CHILD)
+ PaneInfo(*childP)->wp_size = PaneInfo(*childP)->preferred_size;
+ else {
+ if(vert) {
+ request.request_mode = CWWidth;
+ request.width = off_size;
+ }
+ else {
+ request.request_mode = CWHeight;
+ request.height = off_size;
+ }
+
+ if ((XtQueryGeometry(*childP, &request, &reply)
+ == XtGeometryAlmost)
+ && (reply.request_mode = (vert ? CWHeight : CWWidth)))
+ PaneInfo(*childP)->wp_size = GetRequestInfo(&reply, vert);
+ else
+ PaneInfo(*childP)->wp_size = PaneSize(*childP, vert);
+ }
+
+ PaneInfo(*childP)->size = PaneInfo(*childP)->wp_size;
+ }
+}
+
+/*
+ * Function:
+ * ChangeAllGripCursors
+ *
+ * Parameters:
+ * pw - paned widget
+ *
+ * Description:
+ * Changes all the grip cursors.
+ */
+static void
+ChangeAllGripCursors(PanedWidget pw)
+{
+ Widget *childP;
+
+ ForAllPanes(pw, childP) {
+ Arg arglist[1];
+ Cursor cursor;
+
+ if ((cursor = pw->paned.grip_cursor) == None) {
+ if (IsVert(pw))
+ cursor = pw->paned.v_grip_cursor;
+ else
+ cursor = pw->paned.h_grip_cursor;
+ }
+
+ if (HasGrip(*childP)) {
+ XtSetArg(arglist[0], XtNcursor, cursor);
+ XtSetValues(PaneInfo(*childP)->grip, arglist, 1);
+ }
+ }
+}
+
+/*
+ * Function:
+ * PushPaneStack
+ *
+ * Parameters:
+ * pw - paned widget
+ * pane - pane that we are pushing
+ *
+ * Description:
+ * Pushes a value onto the pane stack.
+ */
+static void
+PushPaneStack(PanedWidget pw, Pane pane)
+{
+ PaneStack *stack = (PaneStack *)XtMalloc(sizeof(PaneStack));
+
+ stack->next = pw->paned.stack;
+ stack->pane = pane;
+ stack->start_size = pane->size;
+
+ pw->paned.stack = stack;
+}
+
+/*
+ * Function:
+ * GetPaneStack
+ *
+ * Parameters:
+ * pw - paned widget
+ * shrink - True if we want to shrink this pane, False otherwise
+ * pane - pane that we are popping (return)
+ * start_size - size that this pane started at (return)
+ *
+ * Description:
+ * Gets the top value from the pane stack.
+ */
+static void
+GetPaneStack(PanedWidget pw, Bool shrink, Pane *pane, int *start_size)
+{
+ if (pw->paned.stack == NULL) {
+ *pane = NULL;
+ return;
+ }
+
+ *pane = pw->paned.stack->pane;
+ *start_size = pw->paned.stack->start_size;
+
+ if (shrink != ((*pane)->size > *start_size))
+ *pane = NULL;
+}
+
+/*
+ * Function:
+ * PopPaneStack
+ *
+ * Parameters:
+ * pw - paned widget
+ *
+ * Description:
+ * Pops the top item off the pane stack.
+ *
+ * Returns: True if this is not the last element on the stack
+ */
+static Bool
+PopPaneStack(PanedWidget pw)
+{
+ PaneStack *stack = pw->paned.stack;
+
+ if (stack == NULL)
+ return (False);
+
+ pw->paned.stack = stack->next;
+ XtFree((char *)stack);
+
+ if (pw->paned.stack == NULL)
+ return (False);
+
+ return (True);
+}
+
+/*
+ * Function:
+ * ClearPaneStack
+ *
+ * Parameters:
+ * pw - paned widget
+ *
+ * Description:
+ * Removes all entries from the pane stack.
+ */
+static void
+ClearPaneStack(PanedWidget pw)
+{
+ while(PopPaneStack(pw))
+ ;
+}
+
+static void
+XawPanedClassInitialize(void)
+{
+ XawInitializeWidgetSet();
+ XtAddConverter(XtRString, XtROrientation, XmuCvtStringToOrientation,
+ NULL, 0);
+ XtSetTypeConverter(XtROrientation, XtRString, XmuCvtOrientationToString,
+ NULL, 0, XtCacheNone, NULL);
+}
+
+/* The Geometry Manager only allows changes after Realize if
+ * allow_resize is True in the constraints record.
+ *
+ * For vertically paned widgets:
+ *
+ * It only allows height changes, but offers the requested height
+ * as a compromise if both width and height changes were requested.
+ *
+ * For horizontal widgets the converse is true.
+ * As all good Geometry Managers should, we will return No if the
+ * request will have no effect; i.e. when the requestor is already
+ * of the desired geometry.
+ */
+static XtGeometryResult
+XawPanedGeometryManager(Widget w, XtWidgetGeometry *request,
+ XtWidgetGeometry *reply)
+{
+ PanedWidget pw = (PanedWidget)XtParent(w);
+ XtGeometryMask mask = request->request_mode;
+ Dimension old_size, old_wpsize, old_paned_size;
+ Pane pane = PaneInfo(w);
+ Boolean vert = IsVert(pw);
+ Dimension on_size, off_size;
+ XtGeometryResult result;
+ Boolean almost = False;
+
+ /*
+ * If any of the following is true, disallow the geometry change
+ *
+ * o The paned widget is realized and allow_resize is false for the pane
+ * o The child did not ask to change the on_size
+ * o The request is not a width or height request
+ * o The requested size is the same as the current size
+ */
+
+ if ((XtIsRealized((Widget)pw) && !pane->allow_resize)
+ || !(mask & (vert ? CWHeight : CWWidth))
+ ||(mask & ~(CWWidth | CWHeight))
+ || GetRequestInfo(request, vert) == PaneSize(w, vert))
+ return (XtGeometryNo);
+
+ old_paned_size = PaneSize((Widget)pw, vert);
+ old_wpsize = pane->wp_size;
+ old_size = pane->size;
+
+ pane->wp_size = pane->size = GetRequestInfo(request, vert);
+
+ AdjustPanedSize(pw, PaneSize((Widget)pw, !vert), &result, &on_size,
+ &off_size);
+
+ /*
+ * Fool the Refigure Locations proc to thinking that we are
+ * a different on_size
+ */
+
+ if (result != XtGeometryNo) {
+ if (vert)
+ XtHeight(pw) = on_size;
+ else
+ XtWidth(pw) = on_size;
+ }
+
+ RefigureLocations(pw, PaneIndex(w), AnyPane);
+
+ /*
+ * Set up reply struct and reset core on_size
+ */
+ if (vert) {
+ XtHeight(pw) = old_paned_size;
+ reply->height = pane->size;
+ reply->width = off_size;
+ }
+ else {
+ XtWidth(pw) = old_paned_size;
+ reply->height = off_size;
+ reply->width = pane->size;
+ }
+
+ /*
+ * IF either of the following is true
+ *
+ * o There was a "off_size" request and the new "off_size" is different
+ * from that requested
+ * o There was no "off_size" request and the new "off_size" is different
+ *
+ * o The "on_size" we will allow is different from that requested
+ *
+ * THEN: set almost
+ */
+ if (!((vert ? CWWidth : CWHeight) & mask)) {
+ if (vert)
+ request->width = XtWidth(w);
+ else
+ request->height = XtHeight(w);
+ }
+
+ almost = GetRequestInfo(request, !vert) != GetRequestInfo(reply, !vert);
+ almost |= (GetRequestInfo(request, vert) != GetRequestInfo(reply, vert));
+
+ if ((mask & XtCWQueryOnly) || almost) {
+ pane->wp_size = old_wpsize;
+ pane->size = old_size;
+ RefigureLocations(pw, PaneIndex(w), AnyPane);
+ reply->request_mode = CWWidth | CWHeight;
+ if (almost)
+ return (XtGeometryAlmost);
+ }
+ else {
+ AdjustPanedSize(pw, PaneSize((Widget) pw, !vert), NULL, NULL, NULL);
+ CommitNewLocations(pw); /* layout already refigured */
+ }
+
+ return (XtGeometryDone);
+}
+
+/*ARGSUSED*/
+static void
+XawPanedInitialize(Widget request, Widget cnew,
+ ArgList args, Cardinal *num_args)
+{
+ PanedWidget pw = (PanedWidget)cnew;
+
+ GetGCs((Widget)pw);
+
+ pw->paned.recursively_called = False;
+ pw->paned.stack = NULL;
+ pw->paned.resize_children_to_pref = True;
+ pw->paned.num_panes = 0;
+}
+
+static void
+XawPanedRealize(Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
+{
+ PanedWidget pw = (PanedWidget)w;
+ Widget *childP;
+
+ if ((attributes->cursor = pw->paned.cursor) != None)
+ *valueMask |= CWCursor;
+
+ (*SuperClass->core_class.realize)(w, valueMask, attributes);
+
+ /*
+ * Before we commit the new locations we need to realize all the panes and
+ * their grips
+ */
+ ForAllPanes(pw, childP) {
+ XtRealizeWidget(*childP);
+ if (HasGrip(*childP))
+ XtRealizeWidget(PaneInfo(*childP)->grip);
+ }
+
+ RefigureLocationsAndCommit(w);
+ pw->paned.resize_children_to_pref = False;
+}
+
+static void
+XawPanedDestroy(Widget w)
+{
+ ReleaseGCs(w);
+}
+
+static void
+ReleaseGCs(Widget w)
+{
+ PanedWidget pw = (PanedWidget)w;
+
+ XtReleaseGC(w, pw->paned.normgc);
+ XtReleaseGC(w, pw->paned.invgc);
+ XtReleaseGC(w, pw->paned.flipgc);
+}
+
+static void
+XawPanedInsertChild(Widget w)
+{
+ Pane pane = PaneInfo(w);
+
+ /* insert the child widget in the composite children list with the
+ superclass insert_child routine
+ */
+ (*SuperClass->composite_class.insert_child)(w);
+
+ if (!IsPane(w))
+ return;
+
+ if (pane->show_grip == True) {
+ CreateGrip(w);
+ if (pane->min == PANED_GRIP_SIZE)
+ pane->min = PaneSize(pane->grip, IsVert((PanedWidget)XtParent(w)));
+ }
+ else {
+ if (pane->min == PANED_GRIP_SIZE)
+ pane->min = 1;
+ pane->grip = NULL;
+ }
+
+ pane->size = 0;
+ pane->paned_adjusted_me = False;
+}
+
+static void
+XawPanedDeleteChild(Widget w)
+{
+ /* remove the subwidget info and destroy the grip */
+ if (IsPane(w) && HasGrip(w))
+ XtDestroyWidget(PaneInfo(w)->grip);
+
+ /* delete the child widget in the composite children list with the
+ superclass delete_child routine
+ */
+ (*SuperClass->composite_class.delete_child)(w);
+}
+
+static void
+XawPanedChangeManaged(Widget w)
+{
+ PanedWidget pw = (PanedWidget)w;
+ Boolean vert = IsVert(pw);
+ Dimension size;
+ Widget *childP;
+
+ if (pw->paned.recursively_called++)
+ return;
+
+ /*
+ * If the size is zero then set it to the size of the widest or tallest pane
+ */
+
+ if ((size = PaneSize((Widget)pw, !vert)) == 0) {
+ size = 1;
+ ForAllChildren(pw, childP)
+ if (XtIsManaged(*childP) && (PaneSize(*childP, !vert) > size))
+ size = PaneSize(*childP, !vert);
+ }
+
+ ManageAndUnmanageGrips(pw);
+ pw->paned.recursively_called = False;
+ ResortChildren(pw);
+
+ pw->paned.num_panes = 0;
+ ForAllChildren(pw, childP)
+ if (IsPane(*childP)) {
+ if (XtIsManaged(*childP)) {
+ Pane pane = PaneInfo(*childP);
+
+ if (HasGrip(*childP))
+ PaneInfo(pane->grip)->position = pw->paned.num_panes;
+ pane->position = pw->paned.num_panes; /* TEMPORY -CDP 3/89 */
+ pw->paned.num_panes++;
+ }
+ else
+ break; /* This list is already sorted */
+ }
+
+ SetChildrenPrefSizes((PanedWidget) w, size);
+
+ /*
+ * ForAllPanes can now be used
+ */
+ if (PaneSize((Widget) pw, vert) == 0)
+ AdjustPanedSize(pw, size, NULL, NULL, NULL);
+
+ if (XtIsRealized((Widget)pw))
+ RefigureLocationsAndCommit((Widget)pw);
+}
+
+static void
+XawPanedResize(Widget w)
+{
+ SetChildrenPrefSizes((PanedWidget)w,
+ PaneSize(w, !IsVert((PanedWidget)w)));
+ RefigureLocationsAndCommit(w);
+}
+
+/*ARGSUSED*/
+static void
+XawPanedRedisplay(Widget w, XEvent *event, Region region)
+{
+ DrawInternalBorders((PanedWidget)w);
+}
+
+/*ARGSUSED*/
+static Boolean
+XawPanedSetValues(Widget old, Widget request, Widget cnew,
+ ArgList args, Cardinal *num_args)
+{
+ PanedWidget old_pw = (PanedWidget)old;
+ PanedWidget new_pw = (PanedWidget)cnew;
+ Boolean redisplay = False;
+
+ if ((old_pw->paned.cursor != new_pw->paned.cursor) && XtIsRealized(cnew))
+ XDefineCursor(XtDisplay(cnew), XtWindow(cnew), new_pw->paned.cursor);
+
+ if (old_pw->paned.internal_bp != new_pw->paned.internal_bp ||
+ old_pw->core.background_pixel != new_pw->core.background_pixel) {
+ ReleaseGCs(old);
+ GetGCs(cnew);
+ redisplay = True;
+ }
+
+ if (old_pw->paned.grip_cursor != new_pw->paned.grip_cursor ||
+ old_pw->paned.v_grip_cursor != new_pw->paned.v_grip_cursor ||
+ old_pw->paned.h_grip_cursor != new_pw->paned.h_grip_cursor)
+ ChangeAllGripCursors(new_pw);
+
+ if (IsVert(old_pw) != IsVert(new_pw)) {
+ /*
+ * We are fooling the paned widget into thinking that is needs to
+ * fully refigure everything, which is what we want
+ */
+ if (IsVert(new_pw))
+ XtWidth(new_pw) = 0;
+ else
+ XtHeight(new_pw) = 0;
+
+ new_pw->paned.resize_children_to_pref = True;
+ XawPanedChangeManaged(cnew); /* Seems weird, but does the right thing */
+ new_pw->paned.resize_children_to_pref = False;
+ if (new_pw->paned.grip_cursor == None)
+ ChangeAllGripCursors(new_pw);
+ return (True);
+ }
+
+ if (old_pw->paned.internal_bw != new_pw->paned.internal_bw) {
+ AdjustPanedSize(new_pw, PaneSize(cnew, !IsVert(old_pw)),
+ NULL, NULL, NULL);
+ RefigureLocationsAndCommit(cnew);
+ return (True); /* We have done a full configuration, return */
+ }
+
+ if (old_pw->paned.grip_indent != new_pw->paned.grip_indent &&
+ XtIsRealized(cnew)) {
+ CommitNewLocations(new_pw);
+ redisplay = True;
+ }
+
+ return (redisplay);
+}
+
+/*ARGSUSED*/
+static Boolean
+XawPanedPaneSetValues(Widget old, Widget request, Widget cnew,
+ ArgList args, Cardinal *num_args)
+{
+ Pane old_pane = PaneInfo(old);
+ Pane new_pane = PaneInfo(cnew);
+ Boolean redisplay = False;
+
+ /* Check for new min and max */
+ if (old_pane->min != new_pane->min || old_pane->max != new_pane->max)
+ XawPanedSetMinMax(cnew, (int)new_pane->min, (int)new_pane->max);
+
+ /* Check for change in XtNshowGrip */
+ if (old_pane->show_grip != new_pane->show_grip) {
+ if (new_pane->show_grip == True) {
+ CreateGrip(cnew);
+ if (XtIsRealized(XtParent(cnew))) {
+ if (XtIsManaged(cnew)) /* if paned is unrealized this will
+ happen automatically at realize time
+ */
+ XtManageChild(PaneInfo(cnew)->grip); /* manage the grip */
+ XtRealizeWidget(PaneInfo(cnew)->grip); /* realize the grip */
+ CommitNewLocations((PanedWidget)XtParent(cnew));
+ }
+ }
+ else if (HasGrip(old)) {
+ XtDestroyWidget(old_pane->grip);
+ new_pane->grip = NULL;
+ redisplay = True;
+ }
+ }
+
+ return (redisplay);
+}
+
+/*
+ * Public routines
+ */
+/*
+ * Function:
+ * XawPanedSetMinMax
+ *
+ * Parameters:
+ * widget - widget that is a child of the Paned widget
+ * min - new min and max size for the pane
+ * max - ""
+ *
+ * Description:
+ * Sets the min and max size for a pane.
+ */
+void
+XawPanedSetMinMax(Widget widget, int min, int max)
+{
+ Pane pane = PaneInfo(widget);
+
+ pane->min = min;
+ pane->max = max;
+ RefigureLocationsAndCommit(widget->core.parent);
+}
+
+/*
+ * Function:
+ * XawPanedGetMinMax
+ *
+ * Parameters:
+ * widget - widget that is a child of the Paned widget
+ * min - current min and max size for the pane (return)
+ * max - ""
+ *
+ * Description:
+ * Gets the min and max size for a pane.
+ */
+void
+XawPanedGetMinMax(Widget widget, int *min, int *max)
+{
+ Pane pane = PaneInfo(widget);
+
+ *min = pane->min;
+ *max = pane->max;
+}
+
+/*
+ * Function:
+ * XawPanedSetRefigureMode
+ *
+ * Parameters:
+ * w - paned widget
+ * mode - if False then inhibit refigure
+ *
+ * Description:
+ * Allows a flag to be set the will inhibit
+ * the paned widgets relayout routine.
+ */
+void
+XawPanedSetRefigureMode(Widget w,
+#if NeedWidePrototypes
+ int mode
+#else
+ Boolean mode
+#endif
+)
+{
+ ((PanedWidget)w)->paned.refiguremode = mode;
+ RefigureLocationsAndCommit(w);
+}
+
+/*
+ * Function:
+ * XawPanedGetNumSub
+ *
+ * Parameters:
+ * w - paned widget
+ *
+ * Description:
+ * Returns the number of panes in the paned widget.
+ * Returns:
+ * the number of panes in the paned widget
+ */
+int
+XawPanedGetNumSub(Widget w)
+{
+ return (((PanedWidget)w)->paned.num_panes);
+}
+
+/*
+ * Function:
+ * XawPanedAllowResize
+ *
+ * Parameters:
+ * widget - child of the paned widget
+ *
+ * Description:
+ * Allows a flag to be set that determines if the paned
+ * widget will allow geometry requests from this child.
+ */
+void
+XawPanedAllowResize(Widget widget,
+#if NeedWidePrototypes
+ int allow_resize
+#else
+ Boolean allow_resize
+#endif
+)
+{
+ PaneInfo(widget)->allow_resize = allow_resize;
+}
|