/*
* Motif
*
* Copyright (c) 1987-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*
*/
/************************************************************
* INCLUDE FILES
*************************************************************/
#include <stdio.h>
#include "XmI.h"
#include <Xm/HierarchyP.h>
#include <Xm/PushB.h>
#include <Xm/IconButton.h>
/*
* The bits for the default folder images.
*/
#define open_file_width 12
#define open_file_height 8
static unsigned char open_file_bits[] = {
0x06, 0x00, 0xf9, 0x01, 0x01, 0x01, 0x01, 0x01, 0xf9, 0x0f, 0x05, 0x04,
0x03, 0x02, 0xff, 0x01};
#define close_file_width 12
#define close_file_height 8
static unsigned char close_file_bits[] = {
0x0e, 0x00, 0xf1, 0x01, 0xff, 0x02, 0x81, 0x02, 0x81, 0x02, 0x81, 0x02,
0x81, 0x02, 0xff, 0x01};
/************************************************************
* TYPEDEFS AND DEFINES
*************************************************************/
#define SUPERCLASS ((WidgetClass) &xmManagerClassRec)
#define ALLOC_INC 10
typedef enum {YES, NO, DONT_CARE} SuccessType;
/************************************************************
* MACROS
*************************************************************/
/************************************************************
* GLOBAL DECLARATIONS
*************************************************************/
/************************************************************
* STATIC FUNCTION DECLARATIONS
*************************************************************/
static void ClassInit(), ClassPartInitialize(WidgetClass), InsertChild(Widget);
static void Destroy(Widget), ConstraintDestroy(Widget);
static void Realize(Widget, Mask *, XSetWindowAttributes *);
static void Initialize(Widget, Widget, ArgList, Cardinal *);
static void ConstraintInitialize(Widget, Widget, ArgList, Cardinal *);
static Boolean ConstraintSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal*);
static void ChangeNodeState(HierarchyConstraints);
static void MapNode(HierarchyConstraints), UnmapNode(HierarchyConstraints);
static void UnmapAllExtraNodes(Widget, HierarchyConstraints);
static void BuildNodeTable(Widget, HierarchyConstraints, Cardinal *);
static void ResetOpenCloseButton(Widget, HierarchyConstraints);
static void ToggleNodeState(Widget, XtPointer, XtPointer);
/******************
* Action Routines
******************/
/******************
* Type Converters
******************/
static Boolean CvtStringToNodeState(Display *, XrmValuePtr, Cardinal *,
XrmValuePtr, XrmValuePtr, XtPointer *);
/*********************
* Internal Routines.
*********************/
static void BumpChildren(HierarchyConstraints *, int, int);
static void RemoveNodeFromParent(HierarchyConstraints);
static void AddChild(HierarchyConstraints, HierarchyConstraints);
static void AddChildToList(HierarchyConstraints **, Cardinal *, Cardinal *,
HierarchyConstraints);
static void RemoveChildren(HierarchyConstraints *, Cardinal);
static void DestroyFolderImages(Widget);
static Boolean LoadFolderImages(Widget,Widget);
static HierarchyConstraints GetNodeInfo(Widget);
static Boolean AncestorClosed(HierarchyConstraints);
/************************************************************
* STATIC DECLARATIONS
*************************************************************/
static char defaultTranslations[] =
"<EnterWindow>: ManagerEnter() \n\
<LeaveWindow>: ManagerLeave() \n\
<FocusOut>: ManagerFocusOut() \n\
<FocusIn>: ManagerFocusIn()";
static XtResource resources[] =
{
{
XmNwidth, XmCWidth, XmRHorizontalDimension,
sizeof(Dimension), XtOffsetOf(CoreRec, core.width),
XmRImmediate, (XtPointer) 300
},
{
XmNheight, XmCHeight, XmRVerticalDimension,
sizeof(Dimension), XtOffsetOf(CoreRec, core.height),
XmRImmediate, (XtPointer) 300
},
{
XmNautoClose, XmCAutoClose, XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmHierarchyRec, hierarchy.auto_close),
XmRImmediate, (XtPointer) True
},
{
XmNrefigureMode, XmCBoolean, XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmHierarchyRec, hierarchy.refigure_mode),
XmRImmediate, (XtPointer) True
},
{
XmNnodeStateCallback, XmCNodeStateCallback, XmRCallback,
sizeof(XtCallbackList), XtOffsetOf(XmHierarchyRec, hierarchy.node_state_callback),
XmRPointer, (XtPointer) NULL
},
{
XmNverticalMargin, XmCDimension, XmRVerticalDimension,
sizeof(Dimension), XtOffsetOf(XmHierarchyRec, hierarchy.v_margin),
XmRImmediate, (XtPointer) 2
},
{
XmNhorizontalMargin, XmCDimension, XmRHorizontalDimension,
sizeof(Dimension), XtOffsetOf(XmHierarchyRec, hierarchy.h_margin),
XmRImmediate, (XtPointer) 2
},
{
XmNopenFolderPixmap, XmCPixmap, XmRPrimForegroundPixmap,
sizeof(Pixmap), XtOffsetOf(XmHierarchyRec, hierarchy.open_folder),
XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP
},
{
XmNcloseFolderPixmap, XmCPixmap, XmRPrimForegroundPixmap,
sizeof(Pixmap), XtOffsetOf(XmHierarchyRec, hierarchy.close_folder),
XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP
},
{
XmNnodeStateChangedCallback, XmCNodeStateChangedCallback, XmRCallback,
sizeof(XtCallbackList), XtOffsetOf(XmHierarchyRec, hierarchy.node_state_changed_callback),
XmRPointer, (XtPointer) NULL
},
{
XmNnodeStateBegEndCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), XtOffsetOf(XmHierarchyRec, hierarchy.node_state_beg_end_callback),
XmRPointer, (XtPointer) NULL
},
{
XmNnodeStateBeginEndCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), XtOffsetOf(XmHierarchyRec, hierarchy.node_state_beg_end_callback),
XmRPointer, (XtPointer) NULL
}
};
static XmSyntheticResource get_resources[] =
{
{
XmNhorizontalMargin, sizeof(Dimension),
XtOffsetOf(XmHierarchyRec, hierarchy.h_margin),
XmeFromHorizontalPixels, (XmImportProc) XmeToHorizontalPixels
},
{
XmNverticalMargin, sizeof(Dimension),
XtOffsetOf(XmHierarchyRec, hierarchy.v_margin),
XmeFromVerticalPixels, (XmImportProc) XmeToVerticalPixels
}
};
static XtResource constraints[] =
{
{
XmNnodeState, XmCNodeState, XmRXmHierarchyNodeState,
sizeof(XmHierarchyNodeState), XtOffsetOf(XmHierarchyConstraintRec, hierarchy.state),
XmRImmediate, (XtPointer) XmOpen
},
{
XmNparentNode, XmCParentNode, XmRWidget,
sizeof(Widget), XtOffsetOf(XmHierarchyConstraintRec, hierarchy.parent),
XmRImmediate, (XtPointer) NULL
},
{
XmNinsertBefore, XmCInsertBefore, XmRWidget,
sizeof(Widget), XtOffsetOf(XmHierarchyConstraintRec, hierarchy.insert_before),
XmRImmediate, (XtPointer) NULL
},
{
XmNnodeOpenFolderPixmap, XmCPixmap, XmRPrimForegroundPixmap,
sizeof(Pixmap), XtOffsetOf(XmHierarchyConstraintRec, hierarchy.open_folder),
XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP
},
{
XmNnodeCloseFolderPixmap, XmCPixmap, XmRPrimForegroundPixmap,
sizeof(Pixmap), XtOffsetOf(XmHierarchyConstraintRec, hierarchy.close_folder),
XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP
}
};
XmHierarchyClassRec xmHierarchyClassRec = {
{ /* core fields */
/* superclass */ SUPERCLASS,
/* class_name */ "XmHierarchy",
/* widget_size */ sizeof(XmHierarchyRec),
/* class_initialize */ ClassInit,
/* class_part_initialize */ ClassPartInitialize,
/* class_inited */ FALSE,
/* initialize */ Initialize,
/* initialize_hook */ NULL,
/* realize */ Realize,
/* actions */ NULL,
/* num_actions */ 0,
/* resources */ (XtResource*)resources,
/* num_resources */ XtNumber(resources),
/* xrm_class */ NULLQUARK,
/* compress_motion */ TRUE,
/* compress_exposure */ TRUE,
/* compress_enterleave */ TRUE,
/* visible_interest */ FALSE,
/* destroy */ Destroy,
/* resize */ NULL,
/* expose */ NULL,
/* set_values */ SetValues,
/* set_values_hook */ NULL,
/* set_values_almost */ XtInheritSetValuesAlmost,
/* get_values_hook */ NULL,
/* accept_focus */ NULL,
/* version */ XtVersion,
/* callback_private */ NULL,
/* tm_table */ defaultTranslations,
/* query_geometry */ NULL,
/* display_accelerator */ XtInheritDisplayAccelerator,
/* extension */ NULL
},
{ /* composite_class fields */
/* geometry_manager */ XtInheritGeometryManager,
/* change_managed */ XtInheritChangeManaged,
/* insert_child */ InsertChild,
/* delete_child */ XtInheritDeleteChild,
/* extension */ NULL,
},
{ /* constraint_class fields */
/* resource list */ (XtResource*)constraints,
/* num resources */ XtNumber(constraints),
/* constraint size */ sizeof(XmHierarchyConstraintRec),
/* init proc */ ConstraintInitialize,
/* destroy proc */ ConstraintDestroy,
/* set values proc */ ConstraintSetValues,
/* extension */ NULL,
},
{ /* manager_class fields */
/* default translations */ XtInheritTranslations,
/* syn_resources */ get_resources,
/* num_syn_resources */ XtNumber(get_resources),
/* syn_cont_resources */ NULL,
/* num_syn_cont_resources */ 0,
/* parent_process */ XmInheritParentProcess,
/* extension */ NULL,
},
{ /* Hierarchy fields */
ChangeNodeState, /* The function for changing the node state. */
MapNode, /* Maps a given node. */
UnmapNode, /* Unmaps a given node. */
UnmapAllExtraNodes, /* Unmaps all extra nodes. */
BuildNodeTable, /* Builds up the node table. */
ResetOpenCloseButton, /* Resets the information about the o/c button. */
ToggleNodeState, /* node_toggle function. */
NULL, /* extension */
}
};
WidgetClass xmHierarchyWidgetClass = (WidgetClass) &xmHierarchyClassRec;
/************************************************************
* STATIC CODE
*************************************************************/
/* Function Name: ClassInit
* Description: Called to initialize information specific
* to this widget class.
* Arguments: none.
* Returns: none.
*/
/*ARGSUSED*/
static void
ClassInit()
{
XmHierarchyClassRec* wc = &xmHierarchyClassRec;
XtSetTypeConverter(XmRString, XmRXmHierarchyNodeState,CvtStringToNodeState,
NULL, (Cardinal) 0, XtCacheAll, (XtDestructor) NULL);
}
/* Function Name: ClassPartInitialize
* Description: handles inheritance of class functions.
* Arguments: class - the widget class of this widget.
* Returns: none.
*/
static void
ClassPartInitialize(WidgetClass class)
{
XmHierarchyWidgetClass superC, wc = (XmHierarchyWidgetClass) class;
_XmProcessLock();
superC = (XmHierarchyWidgetClass)wc->core_class.superclass;
/*
* We don't need to check for NULL super since we'll get to The functions
* defined by the Hierarchy class eventually.
*/
if (wc->hierarchy_class.change_node_state == XtInheritChangeNodeState)
{
wc->hierarchy_class.change_node_state =
superC->hierarchy_class.change_node_state;
}
if (wc->hierarchy_class.map_node == XtInheritMapNode)
wc->hierarchy_class.map_node = superC->hierarchy_class.map_node;
if (wc->hierarchy_class.unmap_node == XtInheritUnmapNode)
wc->hierarchy_class.unmap_node = superC->hierarchy_class.unmap_node;
if (wc->hierarchy_class.unmap_all_extra_nodes==XtInheritUnmapAllExtraNodes)
{
wc->hierarchy_class.unmap_all_extra_nodes =
superC->hierarchy_class.unmap_all_extra_nodes;
}
if (wc->hierarchy_class.build_node_table == XtInheritBuildNodeTable)
{
wc->hierarchy_class.build_node_table =
superC->hierarchy_class.build_node_table;
}
if (wc->hierarchy_class.reset_open_close_button ==
XtInheritResetOpenCloseButton)
{
wc->hierarchy_class.reset_open_close_button =
superC->hierarchy_class.reset_open_close_button;
}
if (wc->hierarchy_class.toggle_node_state == XtInheritToggleNodeState) {
wc->hierarchy_class.toggle_node_state =
superC->hierarchy_class.toggle_node_state;
}
_XmProcessUnlock();
}
/* Function Name: Initialize
* Description: Called to initialize information specific
* to this widget.
* Arguments: req - what was originally requested.
* set - what will be created (our superclassed have
* already mucked with this)
* args, num_args - The arguments passed to
* the creation call.
* Returns: none.
*/
/*ARGSUSED*/
static void
Initialize(Widget req, Widget set, ArgList args, Cardinal * num_args)
{
XmHierarchyWidget hw = (XmHierarchyWidget) set;
HierarchyConstraints top_node;
Window root = RootWindowOfScreen(XtScreen(set));
top_node = ((HierarchyConstraints)
XtMalloc(sizeof(HierarchyConstraintRec)));
XmHierarchy_work_proc_id(hw) = (XtWorkProcId) NULL;
XmHierarchy_node_table(hw) = NULL;
XmHierarchy_num_nodes(hw) = XmHierarchy_alloc_nodes(hw) = 0;
XmHierarchy_top_node(hw) = top_node;
/* make default folder button images */
XmHierarchy_def_open_folder(hw) =
XCreateBitmapFromData(XtDisplay(set),root, (char *)open_file_bits,
open_file_width, open_file_height);
XmHierarchy_def_close_folder(hw) =
XCreateBitmapFromData(XtDisplay(set), root,(char *)close_file_bits,
close_file_width, close_file_height);
XmHierarchyC_state(top_node) = XmHidden;
XmHierarchyC_parent(top_node) = NULL;
XmHierarchyC_widget(top_node) = NULL;
XmHierarchyC_status(top_node) = IS_COMPRESSED;
XmHierarchyC_num_children(top_node) = XmHierarchyC_alloc(top_node) = 0;
XmHierarchyC_children(top_node) = NULL;
(void)LoadFolderImages(req, set );
}
/* Function Name: Realize
* Description: Called to realize this widget.
* Arguments: w - Widget to realize.
* valueMask, attributes - attributes to use when creating
* this widget's window.
* Returns: none.
*
* This overrides the Manager's frobbing with various values.
*/
static void
Realize(Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
{
XtCreateWindow (w, InputOutput, CopyFromParent, *valueMask, attributes);
}
/* Function Name: Destroy
* Description: Cleans up after my widget.
* Arguments: w - the widget.
* Returns: none.
*/
static void
Destroy(Widget w)
{
XmHierarchyWidget hw = (XmHierarchyWidget) w;
if( XmHierarchy_work_proc_id(hw) != (XtWorkProcId) NULL )
{
XtRemoveWorkProc(XmHierarchy_work_proc_id(hw));
XmHierarchy_work_proc_id(hw) = (XtWorkProcId) NULL;
}
DestroyFolderImages(w);
XtFree((char *) XmHierarchy_node_table(hw));
XtFree((char *) XmHierarchyC_children(XmHierarchy_top_node(hw)));
XtFree((char *) XmHierarchy_top_node(hw));
XtRemoveAllCallbacks(w, XmNnodeStateBegEndCallback);
}
/* Function Name: InsertChild
* Description: called when a new child is to be added.
* Arguments: w - the new child.
* Returns: none.
*
* This routine simply makes sure that no gadgets are added.
*/
static void
InsertChild(Widget w)
{
XtWidgetProc insert_child;
if (_XmGadgetWarning(w))
return;
_XmProcessLock();
insert_child = ((CompositeWidgetClass) SUPERCLASS)->composite_class.insert_child;
_XmProcessUnlock();
(*insert_child)(w);
}
/************************************************************
*
* Functions for handling the Constraint resources.
*
************************************************************/
/* Function Name: ConstraintInitialize
* Description: Called when a child's constriaint's need initializing.
* Arguments: req - the widget being requested.
* set - what this will become.
* args, num_args - the argument list.
* Returns: none.
*/
/*ARGSUSED*/
static void
ConstraintInitialize(Widget req, Widget set, ArgList args, Cardinal * num_args)
{
XmHierarchyWidget hw = (XmHierarchyWidget) XtParent(set);
XmHierarchyWidgetClass hc = (XmHierarchyWidgetClass) XtClass(hw);
HierarchyConstraints node = GetNodeInfo(set);
if (XmHierarchyC_parent(node) == set) {
XmeWarning(set, XmNnodeParentIsSelfMsg);
XmHierarchyC_parent(node) = NULL;
}
XmHierarchyC_widget(node) = set;
XmHierarchyC_status(node) = IS_COMPRESSED;
XmHierarchyC_num_children(node) = XmHierarchyC_alloc(node) = 0;
XmHierarchyC_children(node) = NULL;
/*
* I will be handling the mapped state of this widget
* myself, not letting the Intrinsics get in the way.
*/
XtSetMappedWhenManaged(set, False);
XmHierarchyC_open_close_button(node) = NULL;
if (XmHierarchyC_state(node) != XmNotInHierarchy) {
XmHierarchyResetButtonProc reset_open_close_button;
_XmProcessLock();
reset_open_close_button = hc->hierarchy_class.reset_open_close_button;
_XmProcessUnlock();
(*reset_open_close_button)((Widget) hw, node);
if (XmHierarchyC_parent(node) == NULL)
AddChild(XmHierarchy_top_node(hw), node);
else
AddChild(GetNodeInfo(XmHierarchyC_parent(node)), node);
}
}
/* Function Name: ConstraintDestroy
* Description: Destroys all data allocated by the constriaint
* record.
* Arguments: w - the widget.
* Returns: none.
*/
/*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* DANGER DANGER DANGER
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*
* This code exercises a bug in the MIT R4 Xt Intrinsics
* that will occur if a large number of widgets deleted from within
* a ConstraintDestroy procedure or a Destroy Proceedure.
*
*/
static void
ConstraintDestroy(Widget w)
{
HierarchyConstraints node = GetNodeInfo(w);
XmHierarchyWidget hw = (XmHierarchyWidget) XtParent(w);
if (XmHierarchyC_state(node) == XmNotInHierarchy)
return;
/*
* If the Hierarchy is being destroyed then we do not want to
* destroy widgets that may already be gone.
*/
if (!hw->core.being_destroyed) {
XmHierarchyWidgetClass hc;
Cardinal current;
hc = (XmHierarchyWidgetClass) XtClass((Widget) hw);
RemoveNodeFromParent(node);
RemoveChildren(XmHierarchyC_children(node), XmHierarchyC_num_children(node));
if (XmHierarchyC_open_close_button(node) != NULL)
XtDestroyWidget(XmHierarchyC_open_close_button(node));
current = 0;
{
XmHierarchyBuildTableProc build_node_table;
_XmProcessLock();
build_node_table = hc->hierarchy_class.build_node_table;
_XmProcessUnlock();
(*build_node_table) ((Widget)hw, XmHierarchy_top_node(hw), ¤t);
}
XmHierarchy_num_nodes(hw) = current;
}
XtFree((char *) XmHierarchyC_children(node));
}
/* Function Name: RecursiveChildSetValues
* Description: Gets the id of the old pixmap and then sets the
* folder buttons
* Arguments: HierarchyConstraints node - current node
* Pixmap open_folder - new open folder image
* Pixmap close_folder - new close folder image
* Returns: none
*/
static void
SetChildValues( HierarchyConstraints node, Pixmap open_folder,
Pixmap close_folder )
{
Arg args[1];
Pixmap which = None;
if (XmHierarchyC_state(node) == XmOpen)
{
if ( (XmUNSPECIFIED_PIXMAP != XmHierarchyC_open_folder(node)) && XmHierarchyC_open_folder(node))
which = XmHierarchyC_open_folder(node);
else
which = open_folder; /* can be None */
XtSetArg(args[0], XmNpixmap, which );
XtSetValues(XmHierarchyC_open_close_button(node), args, 1 );
}
else
if (XmHierarchyC_state(node) == XmClosed)
{
if ( (XmUNSPECIFIED_PIXMAP != XmHierarchyC_close_folder(node)) && XmHierarchyC_close_folder(node))
which = XmHierarchyC_close_folder(node);
else
which = close_folder; /* can be None */
XtSetArg(args[0], XmNpixmap, which );
XtSetValues(XmHierarchyC_open_close_button(node), args, 1 );
}
}
/* Function Name: RecursiveChildSetValues
* Description: Traverses the tree, and calls SetChildValues on each
* node
* Arguments: HierarchyConstraints curr_node
* Pixmap open_folder
* Pixmap close_folder
* Returns: none
*/
static void
RecursiveSetChildValues( HierarchyConstraints curr_node, Pixmap open_folder,
Pixmap close_folder )
{
HierarchyConstraints *curr_child;
Cardinal num=0, i;
if (XmHierarchyC_widget(curr_node) != NULL)
SetChildValues( curr_node, open_folder, close_folder );
if (XmHierarchyC_num_children(curr_node) == 0) return;
curr_child = XmHierarchyC_children(curr_node);
num = XmHierarchyC_num_children(curr_node);
for (i = 0; i < num; i++, curr_child++) {
RecursiveSetChildValues( *curr_child, open_folder, close_folder );
}
}
/* Function Name: SetValues
* Description: Called when XtSetValues is called
* Arguments: current - the current (old) widget values.
* request - before superclassed have changed things.
* set - what will acutally be the new values.
* args, num_args - the arguments in the list.
* Returns: Boolean
*/
/*ARGSUSED*/
static Boolean
SetValues(Widget w, Widget request, Widget set, ArgList args,
Cardinal *num_args)
{
XmHierarchyWidget setw = (XmHierarchyWidget)set;
if (!LoadFolderImages( w, set )) return(False);
RecursiveSetChildValues(XmHierarchy_top_node(setw),
XmHierarchy_open_folder(setw),
XmHierarchy_close_folder(setw));
return(True);
}
/* Function Name: ConstraintSetValues
* Description: Called a constraint is changed on my children.
* Arguments: current - the current (old) widget values.
* request - before superclassed have changed things.
* set - what will acutally be the new values.
* args, num_args - the arguments in the list.
* Returns: none
*/
/*ARGSUSED*/
static Boolean
ConstraintSetValues(Widget current, Widget request, Widget set,
ArgList args, Cardinal * num_args)
{
XmHierarchyWidgetClass hc;
XmHierarchyWidget hw = (XmHierarchyWidget) XtParent(set);
HierarchyConstraints new_node = GetNodeInfo(set);
HierarchyConstraints old_node = GetNodeInfo(current);
Boolean insert_change = False;
int i;
for (i = 0; i < *num_args; i++)
if (streq(args[i].name, XmNinsertBefore)) {
insert_change = True;
break;
}
hc = (XmHierarchyWidgetClass) XtClass(XtParent(set));
if ((XmHierarchyC_parent(new_node) != XmHierarchyC_parent(old_node)) ||
(insert_change))
{
Widget parent = XmHierarchyC_parent(new_node);
if (XmHierarchyC_parent(new_node) == set) {
XmeWarning(set, XmNnodeParentIsSelfMsg);
XmHierarchyC_parent(new_node) = XmHierarchyC_parent(old_node);
}
else {
/*
* We can't just remove old_node because it is a copy of
* the widget and our compare to see if exists in the parent
* will fail. So we store the new parent in a temp variable.
* reset parent to the old one, then remove it from the old parent,
* and finnally add it to the new parent.
*/
XmHierarchyC_parent(new_node) = XmHierarchyC_parent(old_node);
RemoveNodeFromParent(new_node);
XmHierarchyC_parent(new_node) = parent;
if (parent == NULL) {
XmHierarchyWidget hw = (XmHierarchyWidget) XtParent(set);
AddChild(XmHierarchy_top_node(hw), new_node);
}
else
AddChild(GetNodeInfo(XmHierarchyC_parent(new_node)), new_node);
}
}
if (XmHierarchyC_state(new_node) != XmHierarchyC_state(old_node)) {
XtCallCallbackList((Widget) hw,
XmHierarchy_node_state_beg_end_callback(hw),
(XtPointer) True);
{
XmHierarchyNodeProc change_node_state;
_XmProcessLock();
change_node_state = hc->hierarchy_class.change_node_state;
_XmProcessUnlock();
(*change_node_state)(new_node);
}
XtCallCallbackList((Widget) hw,
XmHierarchy_node_state_beg_end_callback(hw),
(XtPointer) False);
}
if ((XmHierarchyC_open_folder(new_node) != XmHierarchyC_open_folder(old_node))
|| (XmHierarchyC_close_folder(new_node) != XmHierarchyC_close_folder(old_node)) )
SetChildValues(new_node, XmHierarchy_open_folder(hw), XmHierarchy_close_folder(hw));
return(False);
}
/* Function Name: Change node state
* Description: Responds to changes in this node's state.
* Arguments: node - the node that has changed.
* Returns: none
*
* This function closes all ancestors
*/
/*ARGSUSED*/
static void
ChangeNodeState(HierarchyConstraints node)
{
register int i, num;
HierarchyConstraints * childp;
XmHierarchyWidget hw = (XmHierarchyWidget)
XtParent(XmHierarchyC_widget(node));
XmHierarchyWidgetClass hc = (XmHierarchyWidgetClass) XtClass(hw);
XmHierarchyNodeStateData node_data;
XmHierarchyNodeProc change_node_state;
XmHierarchyResetButtonProc reset_open_close_button;
_XmProcessLock();
change_node_state = hc->hierarchy_class.change_node_state;
reset_open_close_button = hc->hierarchy_class.reset_open_close_button;
_XmProcessUnlock();
(*reset_open_close_button) (XtParent(XmHierarchyC_widget(node)), node);
node_data.widget = XmHierarchyC_widget(node);
node_data.state = XmHierarchyC_state(node);
XtCallCallbackList((Widget) hw, XmHierarchy_node_state_changed_callback(hw),
&node_data);
if (XmHierarchy_auto_close(hw)) {
if ((XmHierarchyC_state(node) == XmClosed) ||
((XmHierarchyC_state(node) == XmHidden) && AncestorClosed(node)))
{
childp = XmHierarchyC_children(node);
num = XmHierarchyC_num_children(node);
for (i = 0; i < num; i++, childp++) {
if (XmHierarchyC_state(*childp) == XmOpen) {
XmHierarchyC_state(*childp) = XmClosed;
}
(*change_node_state)(*childp);
}
}
}
}
/* Function Name: AncestorClosed
* Description: Returns true if the first non-hidden ancestor of
* this widget is closed.
* Arguments: node - node to check.
* Returns: A Boolean
*/
static Boolean
AncestorClosed(HierarchyConstraints node)
{
while ((XmHierarchyC_parent(node) != NULL) &&
(XmHierarchyC_state(node) == XmHidden))
{
node = GetNodeInfo(XmHierarchyC_parent(node));
}
return(XmHierarchyC_state(node) == XmClosed);
}
/* Function Name: UnmapAllExtraNodes
* Description: Correctly unmaps each node in the hierarchy that is
* currently compresed out.
* Arguments: w - the ow.
* node - node to work one.
* Returns: none
*/
static void
UnmapAllExtraNodes(Widget w, HierarchyConstraints node)
{
register int i;
XmHierarchyWidgetClass hc = (XmHierarchyWidgetClass) (XtClass(w));
register int num;
register HierarchyConstraints * ptr;
void (*unmap_extra)(Widget, HierarchyConstraints);
XmHierarchyNodeProc unmap_node;
_XmProcessLock();
unmap_extra = hc->hierarchy_class.unmap_all_extra_nodes;
unmap_node = hc->hierarchy_class.unmap_node;
_XmProcessUnlock();
if (XmHierarchyC_status(node) & IS_COMPRESSED)
(*unmap_node)(node);
ptr = XmHierarchyC_children(node);
for (num = XmHierarchyC_num_children(node), i = 0; i < num; i++, ptr++)
(*unmap_extra)(w, *ptr);
}
/* Function Name: MapNode
* Description: Maps all children of a given node.
* Arguments: node - node to map.
* Returns: none.
*/
static void
MapNode(HierarchyConstraints node)
{
if (XmHierarchyC_status(node) & IS_MAPPED)
return;
if (XmHierarchyC_widget(node) != NULL) {
XmHierarchyC_status(node) |= IS_MAPPED;
XtSetMappedWhenManaged(XmHierarchyC_widget(node), True);
}
if (XmHierarchyC_open_close_button(node) != NULL)
XtSetMappedWhenManaged(XmHierarchyC_open_close_button(node), True);
}
/* Function Name: UnmapNode
* Description: Unmaps all children of a given node.
* Arguments: node - node to unmap.
* Returns: none.
*/
static void
UnmapNode(HierarchyConstraints node)
{
if (!(XmHierarchyC_status(node) & IS_MAPPED))
return;
if (XmHierarchyC_widget(node) != NULL) {
XmHierarchyC_status(node) &= ~(IS_MAPPED); /* Unset the IS_MAPPED bit. */
XtSetMappedWhenManaged(XmHierarchyC_widget(node), False);
}
if (XmHierarchyC_open_close_button(node) != NULL)
XtSetMappedWhenManaged(XmHierarchyC_open_close_button(node), False);
}
/* Function Name: _BuildNodeTable
* Description: Recursive part of code that builds the table of
* nodes to display.
* Arguments: w - the hw widget.
* node - node to add.
* current_index - where to add this node.
* Returns: none
*/
static void
_BuildNodeTable(Widget w, HierarchyConstraints node, Cardinal * current_index)
{
XmHierarchyWidget hw = (XmHierarchyWidget) w;
register int i;
if ((node == NULL) || ((XmHierarchyC_widget(node) != NULL) &&
!XtIsManaged(XmHierarchyC_widget(node))))
{
return;
}
if (XmHierarchyC_state(node) != XmHidden) {
XmHierarchyC_status(node) &= ~(IS_COMPRESSED); /* No longer compressed. */
XmHierarchy_node_table(hw)[*current_index] = node;
(*current_index)++;
}
if (XmHierarchyC_state(node) == XmClosed)
return;
for (i = 0; i < XmHierarchyC_num_children(node); i++)
_BuildNodeTable(w, XmHierarchyC_children(node)[i], current_index);
}
/* Function Name: BuildNodeTable
* Description: builds the table of nodes to display.
* Arguments: w - the hw widget.
* node - node to add.
* current_index - where to add this node.
* Returns: none
*/
static void
BuildNodeTable(Widget w, HierarchyConstraints node, Cardinal * current_index)
{
XmHierarchyWidget hw = (XmHierarchyWidget) w;
if ((XmHierarchy_node_table(hw) == NULL) ||
(XmHierarchy_alloc_nodes(hw) < hw->composite.num_children))
{
/*
* This will allocate more space than we need, but shouldn't be too
* terrible.
*/
XmHierarchy_node_table(hw) = (HierarchyConstraints *)
XtRealloc((XtPointer) XmHierarchy_node_table(hw),
sizeof(HierarchyConstraints) * hw->composite.num_children);
XmHierarchy_alloc_nodes(hw) = hw->composite.num_children;
}
_BuildNodeTable(w, node, current_index);
}
/* Function Name: ResetOpenCloseButton
* Description: Creates or Destroys the Open/Close button
* as appropriate.
* Arguments: node - the node to check.
* Returns: none.
*/
static void
ResetOpenCloseButton(Widget w, HierarchyConstraints node)
{
Arg args[5];
Pixmap image;
Cardinal num_args;
XmHierarchyWidget hw = (XmHierarchyWidget) w;
XmHierarchyWidgetClass hc = (XmHierarchyWidgetClass) XtClass(w);
if (XmHierarchyC_state(node) == XmAlwaysOpen) {
if (XmHierarchyC_open_close_button(node) != NULL) {
XtDestroyWidget(XmHierarchyC_open_close_button(node));
XmHierarchyC_open_close_button(node) = NULL;
}
return;
}
switch(XmHierarchyC_state(node)) {
case XmOpen:
case XmHidden:
default:
if ( (XmUNSPECIFIED_PIXMAP != XmHierarchyC_open_folder(node)) && XmHierarchyC_open_folder(node))
image = XmHierarchyC_open_folder(node);
else
image = XmHierarchy_open_folder(hw);
break;
case XmClosed:
if ( (XmUNSPECIFIED_PIXMAP != XmHierarchyC_close_folder(node)) && XmHierarchyC_close_folder(node))
image = XmHierarchyC_close_folder(node);
else
image = XmHierarchy_close_folder(hw);
break;
}
num_args = 0;
XtSetArg(args[num_args], XmNpixmap, image); num_args++;
if (XmHierarchyC_open_close_button(node) == NULL) {
XtSetArg(args[num_args], XmNmappedWhenManaged, False); num_args++;
/*
* Special node state for items that should not be
* considered part of the hierarchy, but are children of this
* widget.
*/
XtSetArg(args[num_args], XmNnodeState, XmNotInHierarchy); num_args++;
XtSetArg(args[num_args], XmNiconPlacement, XmIconOnly); num_args++;
XmHierarchyC_open_close_button(node) =
XtCreateManagedWidget("openAndClose", xmIconButtonWidgetClass,
w, args, num_args);
/*
* Make sure the mapped state of open/close button matches the
* node button that it corrosponds to.
*/
XtSetMappedWhenManaged(XmHierarchyC_open_close_button(node),
((XmHierarchyC_status(node) & IS_MAPPED) ? True: False));
_XmProcessLock();
XtAddCallback(XmHierarchyC_open_close_button(node),
XmNactivateCallback,
hc->hierarchy_class.toggle_node_state, (XtPointer) node);
_XmProcessUnlock();
}
else {
XtSetValues(XmHierarchyC_open_close_button(node), args, num_args);
}
}
/* Function Name: ToggleNodeState
* Description: Toggles the open/close state of a toggle button.
* Arguments: w - the command button that activated this.
* node_ptr - a pointer to the node info.
* call_data - UNUSED.
* Returns: none.
*/
static void
ToggleNodeState ( Widget w,
XtPointer node_ptr,
XtPointer call_data )
{
Arg args[1];
XmHierarchyWidget hw = ( XmHierarchyWidget ) XtParent ( w );
HierarchyConstraints node = ( HierarchyConstraints ) node_ptr;
XmHierarchyWidgetClass hc = (XmHierarchyWidgetClass) XtClass ((Widget) hw );
XmHierarchyNodeStateData node_data;
XmHierarchyNodeProc change_node_state;
_XmProcessLock();
change_node_state = hc->hierarchy_class.change_node_state;
_XmProcessUnlock();
/*
* Unset the icon button.
*/
XtSetArg ( args[0], XmNset, False );
XtSetValues ( w, args, ( Cardinal ) 1 );
if (XmHierarchyC_state(node) == XmOpen )
{
XtCallCallbackList( (Widget) hw,
XmHierarchy_node_state_beg_end_callback ( hw ),
(XtPointer) True );
XmHierarchyC_state ( node ) = XmClosed;
(*change_node_state) ( (HierarchyConstraints) node );
}
else
if ( XmHierarchyC_state ( node ) == XmClosed )
{
XtCallCallbackList ( ( Widget ) hw,
XmHierarchy_node_state_beg_end_callback ( hw ),
( XtPointer ) True );
XmHierarchyC_state ( node ) = XmOpen;
(*change_node_state) ( (HierarchyConstraints) node );
}
else
return;
node_data.widget = XmHierarchyC_widget ( node );
node_data.state = XmHierarchyC_state ( node );
XtCallCallbackList ( ( Widget ) hw,
XmHierarchy_node_state_callback ( hw ),
&node_data );
XtCallCallbackList ( ( Widget ) hw,
XmHierarchy_node_state_beg_end_callback ( hw ),
( XtPointer ) False );
}
/************************************************************
*
* Type Converters.
*
************************************************************/
/* Function Name: CvtStringToNodeState
* Description: Converts a string to a NodeState.
* Arguments: dpy - the X Display.
* args, num_args - *** NOT USED ***
* fromVal - contains the string to convert.
* toVal - contains the converted node state.
* junk - *** UNUSED ***.
* Returns:
*/
/*ARGSUSED*/
static Boolean
CvtStringToNodeState(Display * dpy, XrmValuePtr args, Cardinal *num_args,
XrmValuePtr fromVal, XrmValuePtr toVal, XtPointer *junk)
{
static XmHierarchyNodeState type;
static XrmQuark XtQEAlwaysOpen, XtQEOpen, XtQEClosed, XtQEHidden;
static XrmQuark XtQENotInHierarchy;
static Boolean haveQuarks = FALSE;
XrmQuark q;
char lowerName[BUFSIZ];
if (!haveQuarks) {
XtQEAlwaysOpen = XrmStringToQuark("alwaysopen");
XtQEOpen = XrmStringToQuark("open");
XtQEClosed = XrmStringToQuark("closed");
XtQEHidden = XrmStringToQuark("hidden");
XtQENotInHierarchy = XrmStringToQuark("notinhierarchy");
haveQuarks = TRUE;
}
XmCopyISOLatin1Lowered(lowerName, (char *) fromVal->addr);
q = XrmStringToQuark(lowerName);
if (q == XtQEAlwaysOpen)
type = XmAlwaysOpen;
else if (q == XtQEOpen)
type = XmOpen;
else if (q == XtQEClosed)
type = XmClosed;
else if (q == XtQEHidden)
type = XmHidden;
else if (q == XtQENotInHierarchy) /* note! shouldn't ever be needed */
type = XmNotInHierarchy;
else {
XtDisplayStringConversionWarning(dpy, fromVal->addr,
XmRXmHierarchyNodeState);
return(False); /* Conversion failed. */
}
toVal->size = sizeof(XmHierarchyNodeState);
if (toVal->addr == NULL) {
toVal->addr = (XtPointer) &type;
return(TRUE);
}
if (toVal->size >= sizeof(XmHierarchyNodeState)) {
*((XmHierarchyNodeState *) toVal->addr) = type;
return(TRUE);
}
return(FALSE);
}
/************************************************************
*
* Actions and Callbacks.
*
************************************************************/
/************************************************************
*
* Internal routines.
*
************************************************************/
/* Function Name: LoadFolderImages
* Description: Loads the folder images.
* Arguments: w - the hierarchy widget.
* Returns: none.
*
* If the new image resource value is XmUNSPECIFIED_PIXMAP,
* the image is given the default value. If the image has
* changed return True, otherwise return False
*
* It would be nice if these values were cached per screen or display.
*/
static Boolean
LoadFolderImages(Widget old, Widget set)
{
XmHierarchyWidget setw = (XmHierarchyWidget) set;
XmHierarchyWidget oldw = (XmHierarchyWidget) old;
if (XmHierarchy_open_folder(setw) == XmUNSPECIFIED_PIXMAP){
XmHierarchy_open_folder(setw) = XmHierarchy_def_open_folder(setw);
}
if (XmHierarchy_close_folder(setw) == XmUNSPECIFIED_PIXMAP){
XmHierarchy_close_folder(setw) = XmHierarchy_def_close_folder(setw);
}
if (XmHierarchy_open_folder(oldw) != XmHierarchy_open_folder(setw))
return(True);
if (XmHierarchy_close_folder(oldw) != XmHierarchy_close_folder(setw))
return(True);
return(False);
}
/* Function Name: DestroyFolderImages
* Description: Destroys the internal default folder images.
* Arguments: w - the hierarchy widget.
* Returns: none.
*/
static void
DestroyFolderImages(Widget w)
{
XmHierarchyWidget hw = (XmHierarchyWidget) w;
XFreePixmap(XtDisplay(w), XmHierarchy_def_open_folder(hw));
XFreePixmap(XtDisplay(w), XmHierarchy_def_close_folder(hw));
}
/* Function Name: RemoveChildren
* Description: removes a list of children from this node.
* Arguments: list - list of children to remove.
* num - number of children in the list.
* Returns: none.
*/
static void
RemoveChildren(HierarchyConstraints * list, Cardinal num)
{
register int i;
for (i = 0 ; i < num ; i++, list++ ) {
/*
* Our parent is already gone.
*/
XmHierarchyC_status(*list) |= PARENT_GONE;
XtDestroyWidget(XmHierarchyC_widget(*list));
}
}
/* Function Name: AddChild
* Description: Adds the child specified to the parent.
* Arguments: parent - parent to add this child to.
* child - child to add to this parent.
* Returns: none.
*/
static void
AddChild(HierarchyConstraints parent, HierarchyConstraints child)
{
if (parent == NULL)
return;
AddChildToList(&(XmHierarchyC_children(parent)),
&(XmHierarchyC_num_children(parent)),
&(XmHierarchyC_alloc(parent)), child);
}
/* Function Name: AddChildToList
* Description: Adds a child the the specified list.
* Arguments:
* IN/OUT list - pointer to the list of children to add child to.
* IN/OUT num - pointer to the number of children.
* IN/OUT alloc - the amount of space allocated for children.
* child - child to insert.
* Returns: none.
*/
static void
AddChildToList(HierarchyConstraints ** list, Cardinal * num, Cardinal * alloc,
HierarchyConstraints child)
{
register int i, j;
HierarchyConstraints *l_child;
SuccessType success = DONT_CARE;
Widget insert_before = XmHierarchyC_insert_before(child);
if (*alloc <= *num) {
Cardinal size;
(*alloc) += ALLOC_INC;
size = sizeof(HierarchyConstraints) * (*alloc);
*list = (HierarchyConstraints *) XtRealloc((XtPointer)*list, size);
}
if (insert_before != NULL) {
success = NO;
/*
* Hunt for the sibling that matches the insert_before widget.
*/
for (l_child = (*list) + (i = (*num - 1)); i >= 0; i--, l_child--)
if (XmHierarchyC_widget(*l_child) == insert_before) {
/*
* Bump each child down and then insert the new child.
*/
for (j = (*num - 1); j >= i; j--)
(*list)[j + 1] = (*list)[j];
(*list)[i] = child;
success = YES;
break;
}
}
if (success == NO) {
String params[1];
Cardinal num = 1;
params[0] = XtName(XmHierarchyC_widget(child));
_XmWarningMsg(XmHierarchyC_widget(child), XmNinsertBeforeNotSibling,
XmNinsertBeforeNotSiblingMsg, params, num);
}
if (success != YES) /* Stick it on the end of the list. */
(*list)[*num] = child;
(*num)++; /* It always goes somewhere. */
}
/* Function Name: GetNodeInfo
* Description: Gets the node info associated with this widget.
* Arguments: w - the widget.
* Returns: the node info about this widget.
*/
static HierarchyConstraints
GetNodeInfo(Widget w)
{
return((HierarchyConstraints) ((HierarchyConstraints)w->core.constraints));
}
/* Function Name: RemoveNodeFromParent
* Description: Removes the node from its parents children list.
* Arguments: node - the node to remove.
* Returns: none
*/
static void
RemoveNodeFromParent(HierarchyConstraints node)
{
register int i;
HierarchyConstraints pnode;
if (XmHierarchyC_status(node) & PARENT_GONE)
return;
if (XmHierarchyC_parent(node) == NULL) {
XmHierarchyWidget hw;
hw = (XmHierarchyWidget) XtParent(XmHierarchyC_widget(node));
pnode = XmHierarchy_top_node(hw);
}
else
pnode = GetNodeInfo(XmHierarchyC_parent(node));
for (i = 0; i < XmHierarchyC_num_children(pnode); i++) {
if (XmHierarchyC_children(pnode)[i] == node) {
BumpChildren(XmHierarchyC_children(pnode), i,
(int) XmHierarchyC_num_children(pnode));
XmHierarchyC_num_children(pnode)--;
return;
}
}
}
/* Function Name: BumpChildren
* Description: Bumps the children after this node up one.
* Arguments: nlist - the node list
* i - where to begin bumping.
* num - number of children in list.
* Returns: none
*/
static void
BumpChildren(HierarchyConstraints * nlist, int i, int num)
{
for (i++ ; i < num ; i++ )
nlist[i - 1] = nlist[i];
}
/************************************************************
*
* Public Functions
*
************************************************************/
/* Function Name: XmHierarchyOpenAllAncestors
* Description: This function opens all ancestors of the given node.
* Arguments: nw - the node (widget) that will be changed.
* Returns: none
*/
void
XmHierarchyOpenAllAncestors(Widget nw)
{
Widget parent;
HierarchyConstraints node;
static Arg args[] = {
{ XmNnodeState, (XtArgVal) XmOpen }
};
_XmWidgetToAppContext(nw);
_XmAppLock(app);
if (!XtParent(nw) || !XtIsSubclass(XtParent(nw), xmHierarchyWidgetClass))
{
_XmAppUnlock(app);
return;
}
node = GetNodeInfo(nw);
while ((parent = XmHierarchyC_parent(node)) != NULL) {
node = GetNodeInfo(parent);
if (XmHierarchyC_state(node) == XmClosed)
XtSetValues(XmHierarchyC_widget(node), args, XtNumber(args));
}
_XmAppUnlock(app);
}
/* Function Name: XmHierarchyGetChildNodes
* Description: This function returns the node children of a node
* Arguments: nw - the node (widget) that will be examined
* Returns: a list of Widgets (must be XtFree'd) or NULL
*/
WidgetList XmHierarchyGetChildNodes(Widget nw)
{
HierarchyConstraints node;
WidgetList retval = (WidgetList)NULL;
int i;
_XmWidgetToAppContext(nw);
_XmAppLock(app);
if (!XtParent(nw) || !XtIsSubclass(XtParent(nw), xmHierarchyWidgetClass))
{
_XmAppUnlock(app);
return retval;
}
node = GetNodeInfo(nw);
if (0 == XmHierarchyC_num_children(node))
{
_XmAppUnlock(app);
return retval;
}
retval = (WidgetList)XtMalloc((XmHierarchyC_num_children(node) + 1) * sizeof(Widget));
for (i=0; i < XmHierarchyC_num_children(node); i++)
retval[i] = XmHierarchyC_widget(XmHierarchyC_children(node)[i]);
retval[i] = (Widget)NULL;
_XmAppUnlock(app);
return retval;
}