#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))))
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*);
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);
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,
None
},
{
XtNgripCursor,
XtCCursor,
XtRCursor,
sizeof(Cursor),
offset(grip_cursor),
XtRImmediate,
None
},
{
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,
None
},
{
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 = {
{
(WidgetClass)SuperClass,
"Paned",
sizeof(PanedRec),
XawPanedClassInitialize,
NULL,
False,
XawPanedInitialize,
NULL,
XawPanedRealize,
NULL,
0,
resources,
XtNumber(resources),
NULLQUARK,
True,
True,
True,
False,
XawPanedDestroy,
XawPanedResize,
XawPanedRedisplay,
XawPanedSetValues,
NULL,
XtInheritSetValuesAlmost,
NULL,
NULL,
XtVersion,
NULL,
NULL,
XtInheritQueryGeometry,
XtInheritDisplayAccelerator,
NULL,
},
{
XawPanedGeometryManager,
XawPanedChangeManaged,
XawPanedInsertChild,
XawPanedDeleteChild,
NULL,
},
{
subresources,
XtNumber(subresources),
sizeof(PanedConstraintsRec),
NULL,
NULL,
XawPanedPaneSetValues,
NULL,
},
};
WidgetClass panedWidgetClass = (WidgetClass)&panedClassRec;
WidgetClass vPanedWidgetClass = (WidgetClass)&panedClassRec;
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);
}
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) {
_dir = LowRightPane;
_index = pw->paned.num_panes - 1;
}
childP = pw->composite.children + _index;
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);
if (_dir == LowRightPane)
--childP;
else
++childP;
if ((childP - pw->composite.children) < 0 ||
(childP - pw->composite.children) >= pw->paned.num_panes) {
if (--rules < 1)
return (NULL);
childP = pw->composite.children + _index;
}
}
}
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 (*sizeused != pane_size) {
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;
rule3_ok = SatisfiesRule3(pane, shrink);
from_stack = False;
PushPaneStack(pw, pane);
}
old = pane->size;
pane->size += pane_size - *sizeused;
if (from_stack) {
if (shrink) {
AssignMax(pane->size, start_size);
}
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);
}
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);
}
}
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;
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 (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;
}
ForAllPanes(pw, childP) {
PaneInfo(*childP)->delta = loc;
loc += PaneInfo(*childP)->size + pw->paned.internal_bw;
}
}
static void
CommitNewLocations(PanedWidget pw)
{
Widget *childP;
XWindowChanges changes;
changes.stack_mode = Above;
ForAllPanes(pw, childP) {
Pane pane = PaneInfo(*childP);
Widget grip = pane->grip;
if (IsVert(pw)) {
XtMoveWidget(*childP, (Position) 0, pane->delta);
XtResizeWidget(*childP, XtWidth(pw), pane->size, 0);
if (HasGrip(*childP)) {
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)) {
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);
}
}
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);
}
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);
}
}
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);
}
static void
_DrawInternalBorders(PanedWidget pw, GC gc)
{
Widget *childP;
int on_loc, off_loc;
unsigned int on_size, off_size;
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)
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);
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);
}
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];
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);
}
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 (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;
}
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);
}
static void
CommitGripAdjustment(PanedWidget pw)
{
EraseTrackLines(pw);
CommitNewLocations(pw);
DrawInternalBorders(pw);
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;
}
}
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':
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;
}
}
static void
ResortChildren(PanedWidget pw)
{
Widget *unmanagedP, *childP;
unmanagedP = NULL;
ForAllChildren(pw, childP) {
if (!IsPane(*childP) || !XtIsManaged(*childP)) {
if (unmanagedP == NULL)
unmanagedP = childP;
}
else {
if (unmanagedP != NULL) {
Widget child = *unmanagedP;
*unmanagedP = *childP;
*childP = child;
childP = unmanagedP;
unmanagedP = NULL;
}
}
}
}
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;
XtManageChildren(managed_grips, managedP - managed_grips);
}
if (unmanagedP != unmanaged_grips)
XtUnmanageChildren(unmanaged_grips, unmanagedP - unmanaged_grips);
XtFree((char *)managed_grips);
XtFree((char *)unmanaged_grips);
}
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);
}
static void
GetGCs(Widget w)
{
PanedWidget pw = (PanedWidget)w;
XtGCMask valuemask;
XGCValues values;
values.foreground = pw->paned.internal_bp;
valuemask = GCForeground;
pw->paned.normgc = XtGetGC(w, valuemask, &values);
values.foreground = pw->core.background_pixel;
valuemask = GCForeground;
pw->paned.invgc = XtGetGC(w, valuemask, &values);
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);
}
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;
}
}
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);
}
}
}
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;
}
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;
}
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);
}
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);
}
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 ((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);
if (result != XtGeometryNo) {
if (vert)
XtHeight(pw) = on_size;
else
XtWidth(pw) = on_size;
}
RefigureLocations(pw, PaneIndex(w), AnyPane);
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 (!((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);
}
return (XtGeometryDone);
}
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);
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);
(*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)
{
if (IsPane(w) && HasGrip(w))
XtDestroyWidget(PaneInfo(w)->grip);
(*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 ((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;
pw->paned.num_panes++;
}
else
break;
}
SetChildrenPrefSizes((PanedWidget) w, size);
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);
}
static void
XawPanedRedisplay(Widget w, XEvent *event, Region region)
{
DrawInternalBorders((PanedWidget)w);
}
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)) {
if (IsVert(new_pw))
XtWidth(new_pw) = 0;
else
XtHeight(new_pw) = 0;
new_pw->paned.resize_children_to_pref = True;
XawPanedChangeManaged(cnew);
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);
}
if (old_pw->paned.grip_indent != new_pw->paned.grip_indent &&
XtIsRealized(cnew)) {
CommitNewLocations(new_pw);
redisplay = True;
}
return (redisplay);
}
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;
if (old_pane->min != new_pane->min || old_pane->max != new_pane->max)
XawPanedSetMinMax(cnew, (int)new_pane->min, (int)new_pane->max);
if (old_pane->show_grip != new_pane->show_grip) {
if (new_pane->show_grip == True) {
CreateGrip(cnew);
if (XtIsRealized(XtParent(cnew))) {
if (XtIsManaged(cnew))
XtManageChild(PaneInfo(cnew)->grip);
XtRealizeWidget(PaneInfo(cnew)->grip);
CommitNewLocations((PanedWidget)XtParent(cnew));
}
}
else if (HasGrip(old)) {
XtDestroyWidget(old_pane->grip);
new_pane->grip = NULL;
redisplay = True;
}
}
return (redisplay);
}
void
XawPanedSetMinMax(Widget widget, int min, int max)
{
Pane pane = PaneInfo(widget);
pane->min = min;
pane->max = max;
RefigureLocationsAndCommit(widget->core.parent);
}
void
XawPanedGetMinMax(Widget widget, int *min, int *max)
{
Pane pane = PaneInfo(widget);
*min = pane->min;
*max = pane->max;
}
void
XawPanedSetRefigureMode(Widget w,
#if NeedWidePrototypes
int mode
#else
Boolean mode
#endif
)
{
((PanedWidget)w)->paned.refiguremode = mode;
RefigureLocationsAndCommit(w);
}
int
XawPanedGetNumSub(Widget w)
{
return (((PanedWidget)w)->paned.num_panes);
}
void
XawPanedAllowResize(Widget widget,
#if NeedWidePrototypes
int allow_resize
#else
Boolean allow_resize
#endif
)
{
PaneInfo(widget)->allow_resize = allow_resize;
}