/* * 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 #include "XmI.h" #include #include #include /* * 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[] = ": ManagerEnter() \n\ : ManagerLeave() \n\ : ManagerFocusOut() \n\ : 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; }