diff options
author | marha <marha@users.sourceforge.net> | 2009-11-06 11:03:40 +0000 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2009-11-06 11:03:40 +0000 |
commit | 08cb4425442ca65ec28d6a2f023f885e35a7f0ed (patch) | |
tree | a9061a472d247bce27d7fb6c700c5b7e2755d036 /libXaw/src/Paned.c | |
parent | ccdb20929567c70c1bbdd5df275ca7bea5c747a7 (diff) | |
parent | ace7902333b6f61aab5a6035dbcb222763bff186 (diff) | |
download | vcxsrv-08cb4425442ca65ec28d6a2f023f885e35a7f0ed.tar.gz vcxsrv-08cb4425442ca65ec28d6a2f023f885e35a7f0ed.tar.bz2 vcxsrv-08cb4425442ca65ec28d6a2f023f885e35a7f0ed.zip |
Added libXaw
Diffstat (limited to 'libXaw/src/Paned.c')
-rw-r--r-- | libXaw/src/Paned.c | 2067 |
1 files changed, 2067 insertions, 0 deletions
diff --git a/libXaw/src/Paned.c b/libXaw/src/Paned.c new file mode 100644 index 000000000..a2408ba70 --- /dev/null +++ b/libXaw/src/Paned.c @@ -0,0 +1,2067 @@ +/* $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; +} |