/* $XConsortium: Simple.c /main/5 1995/07/15 20:41:24 drk $ */ /* * @OPENGROUP_COPYRIGHT@ * COPYRIGHT NOTICE * Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc. * Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group * ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for * the full copyright text. * * This software is subject to an open license. It may only be * used on, with or for operating systems which are themselves open * source systems. You must contact The Open Group for a license * allowing distribution and sublicensing of this software on, with, * or for operating systems which are not Open Source programs. * * See http://www.opengroup.org/openmotif/license for full * details of the license agreement. Any use, reproduction, or * distribution of the program constitutes recipient's acceptance of * this agreement. * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS * PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY * WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY * OR FITNESS FOR A PARTICULAR PURPOSE * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT * NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE * EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. */ /* * HISTORY */ /*********************************** WARNING ********************************** * * ExmSimple is a demonstration widget. OSF provides this widget * solely to teach programmers how to write their own Motif widgets. * OSF does not support this widget in any way *********************************** WARNING *********************************/ /****************************************************************************** * * Simple.c - ExmSimple widget. This widget renders a rectangle or an oval. * The ExmSimple widget demonstrates how to create a * subclass of XmPrimitive that can, itselve, serve as a superclass * for other widgets. ExmSimple also demonstrates how to * * create a new representation type (ExmRSimpleShape). * * install the XmQTcontainerItem trait and its trait methods. * * install the XmQTcareParentVisual trait and methods. * * access the trait methods of the XmQTcontainer trait. * See the "OSF/Motif Widget Writer's Guide" for more details. * ******************************************************************************/ /* Include appropriate header files. */ #include /* private header file for the ExmSimple widget */ #include /* header file for Xme drawing functions */ #include /* header file for representation type facility */ #include /* header file for screen information */ #include /* header file for installing traits */ #include /* header file for XmQTcareParentVisual trait */ #include /* header file for XmQTcontainerItem trait */ #include /* header file for XmQTcontainer trait */ /* The following section defines constants for the widget. The IDEAL_SHAPE_SIZE constant defines the starting preferred width and height for the widget visual (which is either a rectangle or an oval). */ static XmConst int IDEAL_SHAPE_SIZE = 30; static XmConst int FIND_NATURAL_SIZE = 0; /* Declare all static functions. */ static void ClassInitialize(void); static void ClassPartInitialize ( WidgetClass widgetClass ); static void Initialize( Widget request_w, Widget new_w, ArgList args, Cardinal *num_args ); static void Destroy ( Widget w); static void Realize( Widget w, XtValueMask *p_valueMask, XSetWindowAttributes *attributes ); static void Resize ( Widget w); static void Redisplay ( Widget w, XEvent *event, Region region); static Boolean SetValues ( Widget old_w, Widget request_w, Widget new_w, ArgList args, Cardinal *num_args); static XtGeometryResult QueryGeometry ( Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply); static void DrawVisual ( Widget w); static void DrawShadow ( Widget w); static void CreateGC ( Widget w); static void DestroyGC ( Widget w); static GC SelectGC ( Widget w); static void CalcVisualSize ( Widget w); static void CalcWidgetSize ( Widget w); static Boolean WidgetDisplayRect( Widget w, XRectangle *displayrect); static void Reconfigure ( WidgetClass class, Widget new_w, Widget old_w); static void ContItemSetValues(Widget w, XmContainerItemData contItemData); static void ContItemGetValues(Widget w, XmContainerItemData contItemData); static Boolean HandleRedraw (Widget kid, Widget cur_parent, Widget new_parent, Mask visual_flag); static void SetSelectedVisual (Widget wid) ; /* Define the resources for the ExmSimple widget. This widget supports three new resources: ExmNsimpleShape, XmNmarginWidth, and XmNmarginHeight. Naturally, ExmSimple also supports the resources of its two superclasses: Core and XmPrimitive. */ static XtResource resources[] = { { ExmNsimpleShape, /* resource name */ ExmCSimpleShape, /* resource class */ ExmRSimpleShape, /* resource data type */ sizeof (unsigned char), /* all representation types have this size */ XtOffsetOf( ExmSimpleRec, simple.simple_shape), /* offset */ XmRImmediate, /* default value appears on next line */ (XtPointer)ExmSHAPE_OVAL /* default shape is oval */ }, { XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension, sizeof (Dimension), XtOffsetOf( ExmSimpleRec, simple.margin_width), XmRImmediate, (XtPointer) 4 }, { XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension, sizeof (Dimension), XtOffsetOf( ExmSimpleRec, simple.margin_height), XmRImmediate, (XtPointer) 4 }, }; /* Two of the three resources will also be handled as synthetic resources. */ static XmSyntheticResource syn_resources[] = { { XmNmarginWidth, sizeof (Dimension), XtOffsetOf( ExmSimpleRec, simple.margin_width), XmeFromHorizontalPixels, XmeToHorizontalPixels }, { XmNmarginHeight, sizeof (Dimension), XtOffsetOf( ExmSimpleRec, simple.margin_height), XmeFromVerticalPixels, XmeToVerticalPixels }, }; /* Define the widget class record. See Chapter 3 of the "OSF/Motif Widget Writer's Guide" for details. */ /* Here is the XmPrimitive class extension record. */ static XmPrimitiveClassExtRec primClassExtRec = { /* next_extension */ NULL, /* record_type */ NULLQUARK, /* version */ XmPrimitiveClassExtVersion, /* record_size */ sizeof(XmPrimitiveClassExtRec), /* widget_baseline */ NULL, /* widget_display_rect */ WidgetDisplayRect, /* widget_margins */ NULL, }; externaldef (exmsimpleclassrec) ExmSimpleClassRec exmSimpleClassRec = { { /* Here is the core class record. */ /* superclass */ (WidgetClass)&xmPrimitiveClassRec, /* class_name */ "ExmSimple", /* widget_size */ sizeof(ExmSimpleRec), /* class_initialize */ ClassInitialize, /* class_part_initialize */ ClassPartInitialize, /* class_inited */ FALSE, /* initialize */ Initialize, /* initialize_hook */ NULL, /* realize */ Realize, /* actions */ NULL, /* num_actions */ 0, /* resources */ resources, /* num_resources */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ TRUE, /* compress_exposure */ XtExposeCompressMaximal, /* compress_enterleave */ TRUE, /* visible_interest */ FALSE, /* destroy */ Destroy, /* resize */ Resize, /* expose */ Redisplay, /* 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 */ XtInheritTranslations, /* query_geometry */ QueryGeometry, /* display_accelerator */ NULL, /* extension */ NULL, }, { /* Here is the XmPrimitive class record. */ /* border_highlight */ XmInheritBorderHighlight, /* border_unhighlight */ XmInheritBorderUnhighlight, /* translations */ XtInheritTranslations, /* arm_and_activate */ NULL, /* syn_resources */ syn_resources, /* num_syn_resources */ XtNumber(syn_resources), /* extension */ (XtPointer)&primClassExtRec, }, { /* Here is the ExmSimple class record. */ /* draw_visual */ DrawVisual, /* draw_shadow */ DrawShadow, /* create_gc */ CreateGC, /* destroy_gc */ DestroyGC, /* select_gc */ SelectGC, /* calc_visual_size */ CalcVisualSize, /* calc_widget_size */ CalcWidgetSize, /* reconfigure */ Reconfigure, /* extension */ NULL, } }; /* Establish the widget class name as an externally accessible symbol. Use the "externaldef" macro rather than the "extern" keyword. */ externaldef( exmsimplewidgetclass) WidgetClass exmSimpleWidgetClass = (WidgetClass) &exmSimpleClassRec; /* Declare trait record variables. */ /* Declare a trait record variable for the XmQTcontainerItem trait. */ static XmConst XmContainerItemTraitRec simpleCIT = { 0, /* version */ ContItemSetValues, ContItemGetValues, }; /* Declare a trait record variable for the XmQTcareParentVisual trait. */ static XmConst XmCareVisualTraitRec simpleCVT = { 0, /* version */ HandleRedraw, }; /* Declare any global static variables. */ /* The SimpleShapeNames variable holds some normalized values. The XmRepTypeRegister function will use these values to determine the legal values for a given representation type. */ static String SimpleShapeNames[] = { "simple_oval", "simple_rectangle" }; static XmRepTypeId simpleShapeId; /****************************************************************************** * * ClassInitialize: * Called the first time a widget of this class is instantiated. * *****************************************************************************/ static void ClassInitialize( void ) { /* The ExmNsimpleShape resource requires a value of data type ExmRSimpleShape. Since this is not a standard Motif data type, we must create this data type just for the ExmSimple widget. We want ExmRSimpleShape to hold an enumerated value, either XmSIMPLE_OVAL or XmSIMPLE_RECTANGLE. The best way to accomplish this is to register the new data type with representation type facility. */ simpleShapeId = XmRepTypeRegister (ExmRSimpleShape, SimpleShapeNames, NULL, XtNumber(SimpleShapeNames)); } /****************************************************************************** * * ClassPartInitialize: * Called when this widget or a subclass of this widget is instantiated. * *****************************************************************************/ static void ClassPartInitialize ( WidgetClass widgetClass ) { ExmSimpleWidgetClass wc = (ExmSimpleWidgetClass)widgetClass; ExmSimpleWidgetClass sc = (ExmSimpleWidgetClass) wc->core_class.superclass; /* The following code allows subclasses of ExmSimple to inherit certain methods of ExmSimple. */ if (wc->simple_class.draw_visual == ExmInheritDrawVisual) wc->simple_class.draw_visual = sc->simple_class.draw_visual; if (wc->simple_class.draw_shadow == ExmInheritDrawShadow) wc->simple_class.draw_shadow = sc->simple_class.draw_shadow; if (wc->simple_class.create_gc == ExmInheritCreateGC) wc->simple_class.create_gc = sc->simple_class.create_gc; if (wc->simple_class.destroy_gc == ExmInheritDestroyGC) wc->simple_class.destroy_gc = sc->simple_class.destroy_gc; if (wc->simple_class.select_gc == ExmInheritSelectGC) wc->simple_class.select_gc = sc->simple_class.select_gc; if (wc->simple_class.calc_visual_size == ExmInheritCalcVisualSize) wc->simple_class.calc_visual_size = sc->simple_class.calc_visual_size; if (wc->simple_class.calc_widget_size == ExmInheritCalcWidgetSize) wc->simple_class.calc_widget_size = sc->simple_class.calc_widget_size; if (wc->simple_class.reconfigure == ExmInheritReconfigure) wc->simple_class.reconfigure = sc->simple_class.reconfigure; /* Install the containerItem trait on ExmSimple and all its subclasses. */ XmeTraitSet((XtPointer) wc, XmQTcontainerItem, (XtPointer) &simpleCIT); /* Install the careParentVisual trait on ExmSimple and all subclasses. */ XmeTraitSet((XtPointer) wc, XmQTcareParentVisual, (XtPointer) &simpleCVT); } /****************************************************************************** * * Initialize: * Called by the Intrinsics when this widget is instantiated. * *****************************************************************************/ static void Initialize( Widget request_w, Widget new_w, ArgList args, Cardinal *num_args ) { ExmSimpleWidgetClass wc = (ExmSimpleWidgetClass)XtClass(new_w); ExmSimpleWidget rw = (ExmSimpleWidget)request_w; ExmSimpleWidget nw = (ExmSimpleWidget)new_w; /* Look at the value assigned to the ExmNsimpleShape resource. If the value assigned is neither ExmSHAPE_OVAL nor ExmSHAPE_RECTANGLE, then issue a warning message and set ExmNsimpleShape to ExmSHAPE_OVAL. */ if (!XmRepTypeValidValue (simpleShapeId, nw->simple.simple_shape, (Widget)nw)) nw->simple.simple_shape = ExmSHAPE_OVAL; /* Call a function that creates the GC's needed by the widget. */ if (wc->simple_class.create_gc) (*(wc->simple_class.create_gc))((Widget)nw); /* If the widget's width is set to 0, that's a trigger for the widget to calculate its width. We are not actually going to calculate its width here, rather we are going to set the need_to_compute_width flag appropriately. */ if (rw->core.width == FIND_NATURAL_SIZE) { nw->simple.need_to_compute_width = True; } else { nw->simple.need_to_compute_width = False; nw->simple.pref_width = rw->core.width; nw->core.width = rw->core.width; } if (rw->core.height == FIND_NATURAL_SIZE) nw->simple.need_to_compute_height = True; else { nw->simple.need_to_compute_height = False; nw->simple.pref_height = rw->core.height; nw->core.height = rw->core.height; } /* mark us as not selected to start with */ nw->simple.saved_foreground = XmUNSPECIFIED_PIXEL ; /* In order not to resize the widget at each level of the Initialize chain, the actual class is passed to this method */ if (wc->simple_class.reconfigure) (*(wc->simple_class.reconfigure))(exmSimpleWidgetClass, new_w, NULL); } /****************************************************************************** * * Destroy: * Called by the Intrinsics whenever this widget is deallocated. * *****************************************************************************/ static void Destroy (Widget w) { ExmSimpleWidgetClass wc = (ExmSimpleWidgetClass) XtClass(w); /* The ExmSimple widget allocates two internal GC's. In order to prevent memory leaks, we must destroy these GC's. */ if (wc->simple_class.destroy_gc) (*(wc->simple_class.destroy_gc))(w); } /***************************************************************************** * * Realize * Called by the Intrinsics to create the window for the widget. This * class's realize method creates a propagating window for this * exact class, but uses the default window otherwise * *****************************************************************************/ static void Realize(Widget w, XtValueMask *p_valueMask, XSetWindowAttributes *attributes ) { Mask valueMask = *p_valueMask; /* First call Primitive's method */ xmPrimitiveClassRec.core_class.realize(w, p_valueMask, attributes); /* ExmSimple wants to propagate all unused events to its hierarchy, which Primitive.Realize doesn't do. So if this is an ExmSimple widget, we fix the do_not_propagate window attribute */ if (XtClass(w) == exmSimpleWidgetClass) { Mask adjustMask; XSetWindowAttributes xswa; adjustMask = CWDontPropagate; xswa.do_not_propagate_mask = NoEventMask; XChangeWindowAttributes(XtDisplay(w), XtWindow(w), adjustMask, &xswa); } } /****************************************************************************** * * Resize: * Called by the Intrinsics whenever a parent resizes a child. * Also called by the Reconfigure method. * *****************************************************************************/ static void Resize ( Widget w ) { ExmSimpleWidgetClass wc = (ExmSimpleWidgetClass)XtClass(w); ExmSimpleWidget sw = (ExmSimpleWidget)w; Dimension mw, mh; Dimension window_decoration_thickness; Dimension total_target_widget_width, total_target_widget_height; /* Call CalcVisualSize */ if (wc->simple_class.calc_visual_size) (*(wc->simple_class.calc_visual_size))((Widget)sw); window_decoration_thickness = sw->primitive.highlight_thickness + sw->primitive.shadow_thickness; mw = window_decoration_thickness + sw->simple.margin_width; total_target_widget_width = (2 * mw) + sw->simple.visual.width; /* When there is not enough space to display the entire widget, we must clip part of the widget, but which part? */ if (sw->core.width >= total_target_widget_width) { /* We have enough space to display everything (the visual, the margins, and the border decorations). */ sw->simple.visual.x = mw; sw->simple.visual.width = sw->core.width - (2 * mw); } else if (sw->core.width > ((2 * window_decoration_thickness) + sw->simple.visual.width)) { /* We do not have enough space to display everything, but we do have enough space to display the visual and the border decorations. The left and right margins will have to be reduced. */ sw->simple.visual.x = (sw->core.width - sw->simple.visual.width)/2; } else if (sw->core.width > 2 * window_decoration_thickness) { /* Space is very tight. We will eliminate the left and right margins all together. Furthermore, we will reduce the size of the visual. */ sw->simple.visual.x = window_decoration_thickness; sw->simple.visual.width = sw->core.width - (2 * window_decoration_thickness); } else { /* We do not have enough space to display even one pixel of the visual. */ sw->simple.visual.width = 0; } /* Now do the same for the vertical dimension. */ mh = window_decoration_thickness + sw->simple.margin_height; total_target_widget_height = (2 * mh) + sw->simple.visual.height; if (sw->core.height >= total_target_widget_height) { /* We have enough space to display everything (the visual, the margins, and the border decorations). */ sw->simple.visual.y = mh; sw->simple.visual.height = sw->core.height - (2 * mh); } else if (sw->core.height > ((2 * window_decoration_thickness) + sw->simple.visual.height)) { /* We do not have enough space to display everything, but we do have enough space to display the visual and the border decorations. The top and bottom margins will have to be reduced. */ sw->simple.visual.y = (sw->core.height - sw->simple.visual.height)/2; } else if (sw->core.height > 2 * window_decoration_thickness) { /* Space is very tight. We will eliminate the top and right margins all together. Furthermore, we will reduce the size of the visual. */ sw->simple.visual.y = window_decoration_thickness; sw->simple.visual.height = sw->core.height - (2 * window_decoration_thickness); } else { /* We do not have enough space to display even one pixel of the visual. */ sw->simple.visual.height = 0; } } /****************************************************************************** * * Redisplay: * Called by the Intrinsics whenever a portion of the widget that was * obscured becomes exposed. * *****************************************************************************/ static void Redisplay ( Widget w, XEvent *event, Region region ) { ExmSimpleWidgetClass wc = (ExmSimpleWidgetClass)XtClass(w); /* Call the function that draws the widget visual. */ if (wc->simple_class.draw_visual) (*wc->simple_class.draw_visual) (w); /* Call the function that draws the widget shadow. */ if (wc->simple_class.draw_shadow) (*wc->simple_class.draw_shadow) (w); /* Envelop our superclass expose method. The superclass expose method of XmPrimitive knows how to draw the border highlight. */ (*(xmPrimitiveClassRec.core_class.expose))(w, event, region); } /****************************************************************************** * * SetValues: * Called by the Intrinsics when an application attempts to * change the value of a resource. * *****************************************************************************/ static Boolean SetValues ( Widget old_w, Widget request_w, Widget new_w, ArgList args, Cardinal *num_args ) { ExmSimpleWidgetClass wc = (ExmSimpleWidgetClass)XtClass(new_w); ExmSimpleWidget cw = (ExmSimpleWidget)old_w; ExmSimpleWidget rw = (ExmSimpleWidget)request_w; ExmSimpleWidget nw = (ExmSimpleWidget)new_w; Boolean redisplayFlag = False; /* Validate the value of ExmNsimpleShape by calling XmRepTypeValidValue. */ if (nw->simple.simple_shape != cw->simple.simple_shape) { if (!XmRepTypeValidValue (simpleShapeId, nw->simple.simple_shape, (Widget)nw)) nw->simple.simple_shape = cw->simple.simple_shape; else redisplayFlag = True; } /* Redisplay on change in sensitivity */ if (XtIsSensitive(new_w) != XtIsSensitive(old_w)) redisplayFlag = True; /* If the widget's foreground or background color changes, then we must update the GC. */ if (nw->primitive.foreground != cw->primitive.foreground || nw->core.background_pixel != cw->core.background_pixel) { if (wc->simple_class.destroy_gc) (*(wc->simple_class.destroy_gc))((Widget)cw); if (wc->simple_class.create_gc) (*(wc->simple_class.create_gc))((Widget)nw); redisplayFlag = True; } /* Check for application geometry settings. '0' means 'ideal size' */ if (rw->core.width == FIND_NATURAL_SIZE) { nw->core.width = FIND_NATURAL_SIZE; nw->simple.need_to_compute_width = True; } else if (rw->core.width != cw->core.width) { nw->core.width = rw->core.width; nw->simple.pref_width = rw->core.width; nw->simple.need_to_compute_width = False; } if (rw->core.height == FIND_NATURAL_SIZE) { nw->core.height = FIND_NATURAL_SIZE; nw->simple.need_to_compute_height = True; } else if (rw->core.height != cw->core.height) { nw->core.height = rw->core.height; nw->simple.pref_height = rw->core.height; nw->simple.need_to_compute_height = False; } /* Check for any changes in total widget set, margin size, or window decoration size. If any are found, call Reconfigure. */ nw->simple.need_to_reconfigure = False; if (nw->core.width != cw->core.width || nw->core.height != cw->core.height || nw->simple.margin_width != cw->simple.margin_width || nw->simple.margin_height != cw->simple.margin_height || nw->primitive.shadow_thickness != cw->primitive.shadow_thickness || nw->primitive.highlight_thickness != cw->primitive.highlight_thickness ) Reconfigure (exmSimpleWidgetClass, new_w, old_w); return (redisplayFlag); } /****************************************************************************** * * QueryGeometry: * Called by the Intrinsics in response to a proposed changed in geometry. * *****************************************************************************/ static XtGeometryResult QueryGeometry ( Widget widget, XtWidgetGeometry *parent_request, XtWidgetGeometry *child_reply ) { ExmSimpleWidget sw = (ExmSimpleWidget) widget; if (!XtIsRealized(widget)) { /* Simple has not yet been realized. */ child_reply->width = XtWidth(widget); /* might be 0 */ child_reply->height = XtHeight(widget); /* might be 0 */ } else { /* Simple has been realized. */ child_reply->width = sw->simple.pref_width; child_reply->height = sw->simple.pref_height; } /* Return Simple's preferred size */ return XmeReplyToQueryGeometry(widget, parent_request, child_reply); } /****************************************************************************** * * DrawVisual: * Called by ExmSimple whenever it needs to draw or redraw the * widget visual (either an oval or a rectangle). * *****************************************************************************/ static void DrawVisual ( Widget w ) { ExmSimpleWidgetClass wc = (ExmSimpleWidgetClass)XtClass(w); ExmSimpleWidget sw = (ExmSimpleWidget)w; /* Draw the oval or the rectangle, space permitting. */ if (sw->simple.visual.width > 0 && sw->simple.visual.height > 0) { switch (sw->simple.simple_shape) { case(ExmSHAPE_OVAL): default: XFillArc (XtDisplay(w), XtWindow(w), wc->simple_class.select_gc(w), sw->simple.visual.x, sw->simple.visual.y, sw->simple.visual.width, sw->simple.visual.height, 0, 360 * 64); break; case(ExmSHAPE_RECTANGLE): XFillRectangle (XtDisplay(w), XtWindow(w), wc->simple_class.select_gc(w), sw->simple.visual.x, sw->simple.visual.y, sw->simple.visual.width, sw->simple.visual.height); break; } } } /****************************************************************************** * * DrawShadow: * Called by Redisplay. * *****************************************************************************/ static void DrawShadow ( Widget w ) { ExmSimpleWidget sw = (ExmSimpleWidget)w; /* If there is enough room in the widget to draw a shadow, and if the shadow thickness resource is nonzero, then draw a Motif-style shadow in the appropriate place around the widget's border. */ if (sw->core.width > (2 * sw->primitive.highlight_thickness) && sw->core.height > (2 * sw->primitive.highlight_thickness) && sw->primitive.shadow_thickness > 0) XmeDrawShadows (XtDisplay (sw), XtWindow (sw), sw->primitive.top_shadow_GC, sw->primitive.bottom_shadow_GC, sw->primitive.highlight_thickness, sw->primitive.highlight_thickness, sw->core.width - (2 * sw->primitive.highlight_thickness), sw->core.height - (2 * sw->primitive.highlight_thickness), sw->primitive.shadow_thickness, XmSHADOW_ETCHED_OUT); } /****************************************************************************** * * CreateGC: * Called by Initialize and by SetValues. * *****************************************************************************/ static void CreateGC ( Widget w ) { ExmSimpleWidget sw = (ExmSimpleWidget)w; XGCValues values; XtGCMask valueMask; Arg args[2]; Pixmap insensitiveStippleBitmap; /* This function creates two GC's: one to render a sensitive widget and the other to render an insensitive widget. */ /* First, create the sensitive GC (named normal_GC). */ valueMask = GCForeground | GCBackground | GCGraphicsExposures; values.foreground = sw->primitive.foreground; values.background = sw->core.background_pixel; values.graphics_exposures = False; sw->simple.normal_gc = XtGetGC ((Widget)sw, valueMask, &values); /* Next, create the insensitive GC. This GC will share the same foreground, background, and graphics exposures as the sensitive GC, but will hold a different fill style and stipple pattern. The stipple pattern is stored in the XmNinsensitiveStippleBitmap resource of XmScreen. */ valueMask |= GCFillStyle | GCStipple; values.fill_style = FillStippled; /* Gather the Motif-appropriate insensitive stipple bitmap. */ XtSetArg(args[0], XmNinsensitiveStippleBitmap, &insensitiveStippleBitmap); XtGetValues(XmGetXmScreen(XtScreen(w)), args, 1); values.stipple = insensitiveStippleBitmap; sw->simple.insensitive_gc = XtGetGC((Widget)sw, valueMask, &values); } /****************************************************************************** * * DestroyGC: * Called by the Destroy method. * *****************************************************************************/ static void DestroyGC ( Widget w ) { ExmSimpleWidget sw = (ExmSimpleWidget)w; /* Deallocate the resources used by the two GC's. */ XtReleaseGC ((Widget)sw, sw->simple.normal_gc); XtReleaseGC ((Widget)sw, sw->simple.insensitive_gc); } /****************************************************************************** * * SelectGC: * Called by DrawVisual. * *****************************************************************************/ static GC SelectGC ( Widget w ) { ExmSimpleWidget sw = (ExmSimpleWidget)w; GC drawGC; /* Select between the normal (sensitive) GC and the insensitive GC. */ drawGC = XtIsSensitive(w) ? sw->simple.normal_gc : sw->simple.insensitive_gc; return (drawGC); } /****************************************************************************** * * CalcVisualSize: * Called by CalcWidgetSize. * *****************************************************************************/ static void CalcVisualSize ( Widget w ) { ExmSimpleWidget sw = (ExmSimpleWidget)w; /* Calculate the ideal size of class's visual */ sw->simple.visual.width = IDEAL_SHAPE_SIZE; sw->simple.visual.height = IDEAL_SHAPE_SIZE; } /****************************************************************************** * * CalcWidgetSize: * Called by Reconfigure * *****************************************************************************/ static void CalcWidgetSize( Widget w ) { ExmSimpleWidgetClass wc = (ExmSimpleWidgetClass)XtClass(w); ExmSimpleWidget sw = (ExmSimpleWidget)w; /* Call CalcVisualSize */ if (wc->simple_class.calc_visual_size) (*(wc->simple_class.calc_visual_size))((Widget)sw); /* Compute the widget's width if asked to. Otherwise, set the widget's width to the preferred width. */ if (sw->simple.need_to_compute_width == True) sw->core.width = sw->simple.visual.width + (2 * (sw->simple.margin_width + sw->primitive.shadow_thickness + sw->primitive.highlight_thickness)); else sw->core.width = sw->simple.pref_width; /* Compute the widget's height if asked to. Otherwise, set the widget's height to the preferred height. */ if (sw->simple.need_to_compute_height == True) sw->core.height = sw->simple.visual.height + (2 * (sw->simple.margin_height + sw->primitive.shadow_thickness + sw->primitive.highlight_thickness)); else sw->core.height = sw->simple.pref_height; } /****************************************************************************** * * WidgetDisplayRect: * Called by several Motif managers to determine how to align the visuals * drawn by primitives. In addition, an application can access this * method by calling XmWidgetGetDisplayRect. * *****************************************************************************/ static Boolean WidgetDisplayRect( Widget w, XRectangle *displayrect ) { ExmSimpleWidget my_widget = (ExmSimpleWidget) w; if ((my_widget->simple.visual.width > 0) && (my_widget->simple.visual.height > 0)) { /* The widget is currently displaying a visual. Write the dimensions of the visual's bounding box into displayrect. */ displayrect->x = my_widget->simple.visual.x; displayrect->y = my_widget->simple.visual.y; displayrect->width = my_widget->simple.visual.width; displayrect->height = my_widget->simple.visual.height; return True; /* Yes, this widget contains something displayable. */ } else { /* The widget is not currently displaying a visual. */ return False; } } /****************************************************************************** * * Reconfigure: * Called by the Initialize and SetValues methods. * *****************************************************************************/ static void Reconfigure ( WidgetClass class, Widget new_w, Widget old_w ) { ExmSimpleWidgetClass wc = (ExmSimpleWidgetClass)class; ExmSimpleWidget nw = (ExmSimpleWidget)new_w; ExmSimpleWidget cw = (ExmSimpleWidget)old_w; /* If Reconfigure is called from a leaf chained method, the following code calls CalcWidgetSize. If Reconfigure is not called from a leaf chained method, wait until the final leaf method is called. (That is because the subclass CalcWidgetSize method may need information derived in its SetValues method.) */ /* The Reconfigure method can only reconfigure an ExmSimple widget or an ExmSimple subclass. */ if (!ExmIsSimple((Widget)nw)) return; if (class == XtClass(nw)) { if (wc->simple_class.calc_widget_size) (*(wc->simple_class.calc_widget_size))((Widget)nw); nw->simple.pref_width = nw->core.width; nw->simple.pref_height = nw->core.height; if (cw == NULL || (nw->core.width == cw->core.width && nw->core.height == cw->core.height) ) { if (wc->core_class.resize) (*(wc->core_class.resize))((Widget)nw); } } else nw->simple.need_to_reconfigure = True; } /******--*********************** Trait Methods ****************--***********/ /****************************************************************************** * * ContItemSetValues * This is a trait method of the XmQTcontainterItem trait. * *****************************************************************************/ static void ContItemSetValues(Widget w, XmContainerItemData contItemData) { ExmSimpleWidget sw = (ExmSimpleWidget)w; /* A Container widget calls this trait method to set new visual attributes on ExmSimple. */ if (contItemData->valueMask & ContItemViewType) { /* We will treat SMALL_ICON as one shape (oval) and LARGE_ICON as a different shape (rectangle). */ if (contItemData->view_type == XmSMALL_ICON) XtVaSetValues(w, ExmNsimpleShape, ExmSHAPE_OVAL, NULL); else XtVaSetValues(w, ExmNsimpleShape, ExmSHAPE_RECTANGLE, NULL); } if (contItemData->valueMask & ContItemVisualEmphasis) { if (contItemData->visual_emphasis == XmSELECTED) { /* ok, we are forced selected, so save current foreground and then fetch the new select color and set it */ /* only save the foreground the first time thru */ if (sw->simple.saved_foreground == XmUNSPECIFIED_PIXEL) sw->simple.saved_foreground = sw->primitive.foreground ; SetSelectedVisual (w) ; } else { /* put back our old foreground and forget saved_foreground. The assumption is that the app will not set the foreground during the time the widget is selected. */ XtVaSetValues(w, XmNforeground, sw->simple.saved_foreground, NULL); sw->simple.saved_foreground = XmUNSPECIFIED_PIXEL ; } } } /****************************************************************************** * * ContItemGetValues * This is a trait method of the XmQTcontainterItem trait. * *****************************************************************************/ static void ContItemGetValues(Widget w, XmContainerItemData contItemData) { ExmSimpleWidget sw = (ExmSimpleWidget)w; if (contItemData->valueMask & ContItemViewType) { if (sw->simple.simple_shape == ExmSHAPE_OVAL) contItemData->view_type = XmSMALL_ICON; else contItemData->view_type = XmLARGE_ICON; } if (contItemData->valueMask & ContItemVisualEmphasis) { /* we know awe are in a selected state if our foreground is currently saved */ if (sw->simple.saved_foreground == XmUNSPECIFIED_PIXEL) contItemData->visual_emphasis = XmNOT_SELECTED; else contItemData->visual_emphasis = XmSELECTED; } if (contItemData->valueMask & ContItemIconWidth) { contItemData->icon_width = sw->core.width - sw->core.x; } if (contItemData->valueMask & ContItemDetailCount) { contItemData->detail_count = 0; } } /****************************************************************************** * * SetSelectedVisual * Get the select color of the parent and set our foreground * *****************************************************************************/ static void SetSelectedVisual ( Widget wid) { /* our parent is notifying us that its select color has changed so let's try to get the new value using the Container trait getValue method and then change our foreground - somehow, there is the assumption that if this method gets called with SelectColor on, then it must be a Container, which is ok in 2.0 */ XmContainerDataRec container_data ; XmContainerTrait container_trait ; Pixel select_color = XmUNSPECIFIED_PIXEL; ExmSimpleWidget sw = (ExmSimpleWidget)wid; /* get the container trait record */ container_trait = (XmContainerTrait) XmeTraitGet((XtPointer) XtClass(XtParent(wid)), XmQTcontainer) ; if (container_trait) { /* get the container information */ container_data.valueMask = ContSelectColor ; container_trait->getValues(XtParent(wid), &container_data); if (container_data.valueMask & ContSelectColor) { /* if the Container uses reverse ground, convert that to using black pixel */ if (container_data.select_color == XmREVERSED_GROUND_COLORS) select_color = BlackPixelOfScreen(XtScreen(wid)); else select_color = container_data.select_color; } } /* only set the foreground of the one selected */ if ((select_color != XmUNSPECIFIED_PIXEL) && (sw->simple.saved_foreground != XmUNSPECIFIED_PIXEL)) XtVaSetValues(wid, XmNforeground, select_color, NULL) ; } /****************************************************************************** * * HandleRedraw * This is a trait method of the XmQTcareParentVisual trait. * *****************************************************************************/ static Boolean HandleRedraw ( Widget kid, Widget cur_parent, Widget new_parent, Mask visual_flag) { Boolean redraw = False; XmCareVisualTrait care_visual ; if (visual_flag & VisualSelectColor) { SetSelectedVisual (kid) ; /* no need to set redraw to True since SetSelectedVisual calls XtSetValues which already re-exposes when foreground changes */ } /* at this point we need to envelop our superclass trait method since we are overiding it but we still want its job to be done */ care_visual = (XmCareVisualTrait) XmeTraitGet(xmPrimitiveWidgetClass, XmQTcareParentVisual) ; /* care_visual never NULL on Primitive ! */ redraw |= care_visual->redraw(kid, cur_parent, new_parent, visual_flag) ; return redraw ; } /****************************************************************************** * * ExmCreateSimple: * Called by an application. * *****************************************************************************/ Widget ExmCreateSimple ( Widget parent, char *name, Arg *arglist, Cardinal argCount ) { /* Convenience function to instantiate an ExmSimple widget. */ return (XtCreateWidget (name, exmSimpleWidgetClass, parent, arglist, argCount)); }