/* $TOG: IconG.c /main/28 1999/01/26 15:30:46 mgreess $ */ /* * @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 */ #include #include #include #include #include #include #include #include /* for XmeTraitSet */ #include #include "BaseClassI.h" #include "CacheI.h" #include "ColorI.h" #include "DrawI.h" #include "ExtObjectI.h" #include "ImageCachI.h" #include "MessagesI.h" #include "PixConvI.h" #include "RepTypeI.h" #include "ScreenI.h" #include "SyntheticI.h" #include "TravActI.h" #include "XmI.h" #include "XmTabListI.h" #include "XmosI.h" #include "IconGI.h" /* spacing between the line and the detail string. Those could be moved as plain resources later. */ #define DEFAULT_LABEL_MARGIN_WIDTH 2 #define DEFAULT_LABEL_MARGIN_HEIGHT 2 #define DEFAULT_HOR_SPACING 4 /* This macro should probably be put in XmI.h and used everywhere */ #define PIXMAP_VALID(pix) \ (pix != XmUNSPECIFIED_PIXMAP && pix != None) #define SHOW_DETAIL(wid, container_data) \ (IG_Detail(wid) && IG_DetailCount(wid) && \ (container_data)->detail_order_count) #define INVALID_DIMENSION ((Dimension)-1) /******** Static Function Declarations ********/ /* XmRCallProcs */ static void CheckSetRenderTable( Widget wid, int offset, XrmValue *value); /* Converters */ static Boolean CvtStringToIconPixmap( Display *dpy, XrmValue *args, Cardinal *numArgs, XrmValue *fromVal, XrmValue *toVal, XtPointer *closure_ret) ; /* Hooks */ static void GetLabelString( Widget wid, int offset, XtArgVal *value); /* BaseClass methods */ static void SecondaryObjectCreate( Widget req, Widget new_w, ArgList args, Cardinal *num_args) ; static void InitializePosthook( Widget req, Widget new_w, ArgList args, Cardinal *num_args) ; static Boolean SetValuesPrehook( Widget oldParent, Widget refParent, Widget newParent, ArgList args, Cardinal *num_args) ; static void GetValuesPrehook( Widget newParent, ArgList args, Cardinal *num_args) ; static void GetValuesPosthook( Widget new_w, ArgList args, Cardinal *num_args) ; static Boolean SetValuesPosthook( Widget current, Widget req, Widget new_w, ArgList args, Cardinal *num_args) ; static int IconGCacheCompare( XtPointer A, XtPointer B) ; static Cardinal GetIconGClassSecResData( WidgetClass w_class, XmSecondaryResourceData **data_rtn) ; static XtPointer GetIconGClassSecResBase( Widget widget, XtPointer client_data) ; /* RectObj methods */ static void ClassInitialize( void ); static void ClassPartInitialize( WidgetClass wc); static void Initialize( Widget rw, Widget nw, ArgList args, Cardinal *num_args); static void Destroy( Widget wid); static void Redisplay( Widget wid, XEvent *event, Region region); static Boolean SetValues( Widget cw, Widget rw, Widget nw, ArgList args, Cardinal *num_args); static XtGeometryResult QueryGeometry( Widget wid, XtWidgetGeometry *intended, XtWidgetGeometry *reply); /* XmGadget methods */ static void HighlightBorder( Widget w) ; static void UnhighlightBorder( Widget w) ; static void InputDispatch( Widget wid, XEvent *event, Mask event_mask); static Boolean GetBaselines( Widget wid, Dimension **baselines, int *line_count); static void MarginsProc( Widget w, XmBaselineMargins *margins_rec); static Boolean GetDisplayRect( Widget wid, XRectangle *displayrect); /* XmIconGadget methods */ /* Action procs */ /* Internal functions */ static void GetLabelXY( Widget wid, Position * x_ret, Position * y_ret); static Position GetLargeIconX( Widget wid); static Position GetSmallIconY( Widget wid); static Dimension GetIconLabelWidth( Widget wid); static Dimension GetIconLabelHeight( Widget wid); static Cardinal GetShapeInfo( Widget wid, Position large_icon_x, Position small_icon_y, Position label_x, Position label_y, Dimension first_column_width, Dimension ht, XPoint * points); static void GetContainerData( Widget wid, XmContainerData container_data); static void ChangeHighlightGC( Widget wid, XtEnum selection_mode, int line_width); static void UpdateSelectGCs( Widget wid, Pixel select_color); static void UpdateGCs( Widget wid); static XmStringTable GetStringTableReOrdered( XmStringTable st, Cardinal st_count, Cardinal * order, Cardinal order_count); static void GetStringTableExtent( Screen * screen, XmStringTable st, Cardinal st_count, XmRenderTable render_table, XmTabList tab_list, Dimension hor_spacing, Dimension * width_ret, Dimension * height_ret, Position * baseline_ret); static void GetSize( Widget wid, Dimension *ideal_width, Dimension *ideal_height); /* Trait methods */ 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 GetColors(Widget widget, XmAccessColorData color_data); static Boolean PointIn(Widget widget, Position x, Position y); /******** End Static Function Declarations ********/ /*** Xt trivia: How do you manage a flag that tells you that something happened during a resource conversion ? We need a association outside the widget instance for the OwnIconMask flag. This is because the converter sets this flag and the widget Initialize cannot initialize it afterward without overiding it. So we use the XContext manager for that. (I could probably have used private resource too...) ***/ /* those are created in ClassInitialize and filled by the IconConverter. */ static XContext largeIconContext = (XContext) NULL; static XContext smallIconContext = (XContext) NULL; static XPointer dummy; #define OwnLargeMask(widget) \ (XFindContext(XtDisplay(widget), \ (Window) widget, \ largeIconContext, \ &dummy) == 0) #define OwnSmallMask(widget) \ (XFindContext(XtDisplay(widget), \ (Window) widget, \ smallIconContext, \ &dummy) == 0) #define MESSAGE0 _XmMMsgPixConv_0000 /***** The resources of this class */ static XtResource resources[] = { /* The following hackery is a way in Xt to see if a widget has been initialized. We need to know whether or not the gadget cache is valid. We use "." in the name so that an end user cannot access it from a resource file. With that in place, we just need to check IG_Cache(w) != NULL to see if the gadget has been initialized. */ { XmNdotCache, XmCDotCache, XmRPointer, sizeof(XtPointer), XtOffset(XmIconGadget, icong.cache), XtRImmediate, (XtPointer) NULL}, { XmNlabelString,XmCXmString,XmRXmString,sizeof(XmString), XtOffset(XmIconGadget,icong.label_string), XmRImmediate,(XtPointer)NULL}, { XmNlargeIconMask,XmCIconMask,XmRBitmap,sizeof(Pixmap), XtOffset(XmIconGadget,icong.large_icon_mask), XmRImmediate,(XtPointer)XmUNSPECIFIED_PIXMAP}, { XmNlargeIconPixmap,XmCIconPixmap,XmRLargeIconPixmap,sizeof(Pixmap), XtOffset(XmIconGadget,icong.large_icon_pixmap), XmRImmediate,(XtPointer)XmUNSPECIFIED_PIXMAP}, { XmNsmallIconMask,XmCIconMask,XmRBitmap,sizeof(Pixmap), XtOffset(XmIconGadget,icong.small_icon_mask), XmRImmediate,(XtPointer)XmUNSPECIFIED_PIXMAP}, { XmNsmallIconPixmap,XmCIconMask,XmRSmallIconPixmap,sizeof(Pixmap), XtOffset(XmIconGadget,icong.small_icon_pixmap), XmRImmediate,(XtPointer)XmUNSPECIFIED_PIXMAP}, { XmNviewType,XmCViewType,XmRViewType,sizeof(unsigned char), XtOffset(XmIconGadget,icong.viewtype), XmRImmediate,(XtPointer)XmLARGE_ICON}, { XmNvisualEmphasis,XmCVisualEmphasis,XmRVisualEmphasis, sizeof(unsigned char), XtOffset(XmIconGadget,icong.visual_emphasis), XmRImmediate,(XtPointer)XmNOT_SELECTED}, { XmNdetail,XmCDetail,XmRXmStringTable, sizeof(XmStringTable), XtOffset(XmIconGadget,icong.detail), XmRImmediate,(XtPointer)NULL}, { XmNdetailCount,XmCDetailCount,XmRCardinal,sizeof(Cardinal), XtOffset(XmIconGadget,icong.detail_count), XmRImmediate,(XtPointer)0}, { "pri.vate","Pri.vate",XmRBoolean, sizeof(Boolean), XtOffset(XmIconGadget, icong.check_set_render_table), XmRImmediate, (XtPointer) False}, }; static XtResource cache_resources[] = { { XmNfontList, XmCFontList, XmRFontList, sizeof(XmRenderTable), XtOffsetOf(XmIconGCacheObjRec, icon_cache.render_table), XmRCallProc,(XtPointer)CheckSetRenderTable }, { XmNrenderTable, XmCRenderTable, XmRRenderTable, sizeof(XmRenderTable), XtOffsetOf(XmIconGCacheObjRec, icon_cache.render_table), XmRCallProc,(XtPointer)CheckSetRenderTable }, { XmNbackground, XmCBackground, XmRPixel, sizeof (Pixel), XtOffsetOf(XmIconGCacheObjRec, icon_cache.background), XmRCallProc, (XtPointer) _XmBackgroundColorDefault }, { XmNforeground, XmCForeground, XmRPixel, sizeof (Pixel), XtOffsetOf(XmIconGCacheObjRec, icon_cache.foreground), XmRCallProc, (XtPointer) _XmForegroundColorDefault }, { XmNtopShadowColor, XmCTopShadowColor, XmRPixel, sizeof (Pixel), XtOffsetOf(XmIconGCacheObjRec, icon_cache.top_shadow_color), XmRCallProc, (XtPointer) _XmTopShadowColorDefault }, { XmNbottomShadowColor, XmCBottomShadowColor, XmRPixel, sizeof (Pixel), XtOffsetOf(XmIconGCacheObjRec, icon_cache.bottom_shadow_color), XmRCallProc, (XtPointer) _XmBottomShadowColorDefault }, { XmNhighlightColor, XmCHighlightColor, XmRPixel, sizeof (Pixel), XtOffsetOf(XmIconGCacheObjRec, icon_cache.highlight_color), XmRCallProc, (XtPointer) _XmHighlightColorDefault }, { XmNbackgroundPixmap, XmCBackgroundPixmap, XmRPixmap, sizeof (Pixmap), XtOffsetOf(XmIconGCacheObjRec, icon_cache.background_pixmap), XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP }, { XmNtopShadowPixmap, XmCTopShadowPixmap, XmRTopShadowPixmap, sizeof (Pixmap), XtOffsetOf(XmIconGCacheObjRec, icon_cache.top_shadow_pixmap), XmRCallProc, (XtPointer) _XmTopShadowPixmapDefault }, { XmNbottomShadowPixmap, XmCBottomShadowPixmap, XmRBottomShadowPixmap, sizeof (Pixmap), XtOffsetOf(XmIconGCacheObjRec, icon_cache.bottom_shadow_pixmap), XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP }, { XmNhighlightPixmap, XmCHighlightPixmap, XmRHighlightPixmap, sizeof (Pixmap), XtOffsetOf(XmIconGCacheObjRec, icon_cache.highlight_pixmap), XmRCallProc, (XtPointer) _XmHighlightPixmapDefault }, { XmNalignment, XmCAlignment, XmRAlignment, sizeof(unsigned char), XtOffsetOf(XmIconGCacheObjRec, icon_cache.alignment), XmRImmediate, (XtPointer) XmALIGNMENT_CENTER }, { XmNspacing, XmCSpacing, XmRHorizontalDimension, sizeof(Dimension), XtOffsetOf(XmIconGCacheObjRec, icon_cache.spacing), XmRImmediate, (XtPointer) 4 }, { XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension, sizeof(Dimension), XtOffsetOf(XmIconGCacheObjRec, icon_cache.margin_width), XmRImmediate, (XtPointer) 2 }, { XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension, sizeof(Dimension), XtOffsetOf(XmIconGCacheObjRec, icon_cache.margin_height), XmRImmediate, (XtPointer) 2 }, }; static XmSyntheticResource syn_resources[] = { { XmNlabelString,sizeof(XmString), XtOffset(XmIconGadget,icong.label_string),GetLabelString,NULL }, }; static XmSyntheticResource cache_syn_resources[] = { { XmNspacing, sizeof(Dimension), XtOffsetOf(XmIconGCacheObjRec, icon_cache.spacing), XmeFromHorizontalPixels, XmeToHorizontalPixels }, { XmNmarginWidth, sizeof(Dimension), XtOffsetOf(XmIconGCacheObjRec, icon_cache.margin_width), XmeFromHorizontalPixels, XmeToHorizontalPixels }, { XmNmarginHeight, sizeof(Dimension), XtOffsetOf(XmIconGCacheObjRec, icon_cache.margin_height), XmeFromVerticalPixels, XmeToVerticalPixels }, }; /* ext rec static initialization */ externaldef(xmicongcacheobjclassrec) XmIconGCacheObjClassRec xmIconGCacheObjClassRec = { { /* superclass */ (WidgetClass) &xmExtClassRec, /* class_name */ "XmIconGadget", /* widget_size */ sizeof(XmIconGCacheObjRec), /* class_initialize */ NULL, /* chained class init */ NULL, /* class_inited */ False, /* initialize */ NULL, /* initialize hook */ NULL, /* realize */ NULL, /* actions */ NULL, /* num_actions */ 0, /* resources */ cache_resources, /* num_resources */ XtNumber(cache_resources), /* xrm_class */ NULLQUARK, /* compress_motion */ False, /* compress_exposure */ False, /* compress enter/exit*/ False, /* visible_interest */ False, /* destroy */ NULL, /* resize */ NULL, /* expose */ NULL, /* set_values */ NULL, /* set values hook */ NULL, /* set values almost */ NULL, /* get values hook */ NULL, /* accept_focus */ NULL, /* version */ XtVersion, /* callback offsetlst */ NULL, /* default trans */ NULL, /* query geo proc */ NULL, /* display accelerator*/ NULL, /* extension record */ NULL, }, { /* synthetic resources */ cache_syn_resources, /* num_syn_resources */ XtNumber(cache_syn_resources), /* extension */ NULL, } }; static XmBaseClassExtRec iconGBaseClassExtRec = { NULL, /* next_extension */ NULLQUARK, /* record_typ */ XmBaseClassExtVersion, /* version */ sizeof(XmBaseClassExtRec), /* record_size */ XmInheritInitializePrehook, /* initializePrehook */ SetValuesPrehook, /* setValuesPrehook */ InitializePosthook, /* initializePosthook */ SetValuesPosthook, /* setValuesPosthook */ (WidgetClass)&xmIconGCacheObjClassRec, /* secondaryObjectClass */ SecondaryObjectCreate, /* secondaryObjectCreate */ GetIconGClassSecResData, /* getSecResData */ {0}, /* Other Flags */ GetValuesPrehook, /* getValuesPrehook */ GetValuesPosthook, /* getValuesPosthook */ NULL, /* classPartInitPrehook */ NULL, /* classPartInitPosthook*/ NULL, /* ext_resources */ NULL, /* compiled_ext_resources*/ 0, /* num_ext_resources */ FALSE, /* use_sub_resources */ XmInheritWidgetNavigable, /* widgetNavigable */ XmInheritFocusChange, /* focusChange */ }; static XmCacheClassPart IconGClassCachePart = { {NULL, 0, 0}, /* head of class cache list */ _XmCacheCopy, /* Copy routine */ _XmCacheDelete, /* Delete routine */ IconGCacheCompare, /* Comparison routine */ }; static XmGadgetClassExtRec GadClassExtRec = { NULL, NULLQUARK, XmGadgetClassExtVersion, sizeof(XmGadgetClassExtRec), GetBaselines, /* widget_baseline */ GetDisplayRect, /* widget_display_rect */ MarginsProc, /* widget_margins */ }; externaldef( xmicongadgetclassrec) XmIconGadgetClassRec xmIconGadgetClassRec = { /* RectObjClassPart */ { (WidgetClass) &xmGadgetClassRec, /* superclass */ "XmIconGadget", /* class_name */ sizeof (XmIconGadgetRec), /* widget_size */ ClassInitialize, /* class_initialize */ ClassPartInitialize, /* class_part_initialize*/ False, /* class_inited */ Initialize, /* initialize */ NULL, /* initialize_hook */ NULL, /* realize */ NULL, /* actions */ 0, /* num_actions */ resources, /* resources */ XtNumber (resources), /* num_resources */ NULLQUARK, /* xrm_class */ True, /* compress_motion */ True, /* compress_exposure */ True, /* compress_enterleave */ False, /* visible_interest */ Destroy, /* destroy */ NULL, /* resize */ Redisplay, /* expose */ SetValues, /* set_values */ NULL, /* set_values_hook */ XtInheritSetValuesAlmost, /* set_values_almost */ NULL, /* get_values_hook */ NULL, /* accept_focus */ XtVersion, /* version */ NULL, /* callback private */ NULL, /* tm_table */ QueryGeometry, /* query_geometry */ NULL, /* display_accelerator */ (XtPointer)&iconGBaseClassExtRec, /* extension */ }, /* XmGadget Class Part */ { HighlightBorder, /* border_highlight */ UnhighlightBorder, /* border_unhighlight */ NULL, /* arm_and_activate */ InputDispatch, /* input_dispatch */ NULL, /* visual_change */ syn_resources, /* get_resources */ XtNumber(syn_resources), /* num_get_resources */ &IconGClassCachePart, /* class_cache_part */ (XtPointer)&GadClassExtRec, /* extension */ }, /* XmIconGadget Class Part */ { NULL, /* get_container_parent */ NULL, /* extension */ }, }; externaldef(xmicongadgetclass) WidgetClass xmIconGadgetClass=(WidgetClass)&xmIconGadgetClassRec; /* ContainerItem Trait record for IconGadget */ static XmConst XmContainerItemTraitRec iconCIT = { 0, /* version */ ContItemSetValues, ContItemGetValues, }; /* CareVisual Trait record for IconGadget */ static XmConst XmCareVisualTraitRec iconCVT = { 0, /* version */ HandleRedraw, }; /* Access Colors Trait record for IconGadget */ static XmConst XmAccessColorsTraitRec iconACT = { 0, /* version */ GetColors }; /* Point In Trait record for IconGadget */ static XmConst XmPointInTraitRec iconPIT = { 0, /* version */ PointIn, }; /******** for the special IconPixmap/Mask converter */ static XtConvertArgRec largeIconArgs[] = { { XtBaseOffset, (XtPointer) 0, sizeof (int) }, { XtAddress, (XtPointer)(int)XmLARGE_ICON, 0} }; static XtConvertArgRec smallIconArgs[] = { { XtBaseOffset, (XtPointer) 0, sizeof (int) }, { XtAddress, (XtPointer)(int)XmSMALL_ICON, 0} }; /*** XmRCallProcs ***/ /* * XmRCallProc routine for checking icon_cache.render_table before setting * it to NULL. If "check_set_render_table" is True, then function has * been called twice on same widget, thus resource needs to be set NULL, * otherwise leave it alone. */ /*ARGSUSED*/ static void CheckSetRenderTable(Widget wid, int offset, XrmValue *value) { XmIconGadget ig = (XmIconGadget)wid; /* Check if been here before */ if (ig->icong.check_set_render_table) value->addr = NULL; else { ig->icong.check_set_render_table = True; value->addr = (char*)&(IG_RenderTable(ig)); } } /************************************************************************ * * FetchPixmap * ************************************************************************/ /*ARGSUSED*/ static void FetchPixmap( Widget widget, String image_name, unsigned char res_type, Pixmap * pixmap) { int depth ; XtPointer mask_addr ; XmAccessColorDataRec acc_color_rec; XmAccessColorsTrait access_colors_trait ; depth = - XtParent(widget)->core.depth; /* this is the convention used by XmGetPixmapByDepth, pass a negative depth means do bitmap if you can */ /* always called when the cache is valid and the colors can be returned */ access_colors_trait = (XmAccessColorsTrait) XmeTraitGet((XtPointer)XtClass(widget), XmQTaccessColors) ; access_colors_trait->getColors(widget, &acc_color_rec); *pixmap = _XmGetScaledPixmap (XtScreen(widget), widget, image_name, &acc_color_rec, depth, FALSE, 0); if (*pixmap == XmUNSPECIFIED_PIXMAP) { return ; } /* now we see if a mask is to be fetched too */ if (res_type == XmLARGE_ICON) { mask_addr = (XtPointer)&(IG_LargeIconMask(widget)) ; } else { mask_addr = (XtPointer)&(IG_SmallIconMask(widget)) ; } /* fetch only if a mask has not been specified in the resource slot */ if (*(Pixmap *)mask_addr == XmUNSPECIFIED_PIXMAP) { char mask_name[255] ; /* Fetch the mask out of image_name and ask for it. ImageCache: The mask_name returned is the same as the one used by the ImageCache reader to cache the mask associated with an XPM file, so we will get it from the cache if an XPM file with a mask was specified for image_name. When an XPM file with a mask in it is read, the mask is cached with mask_name. */ _XmOSGenerateMaskName(image_name, mask_name) ; *(Pixmap*)mask_addr = (Pixmap) XmGetScaledPixmap(widget, mask_name, 1, 0, 1, 0); /* mark that we have to destroy the mask */ if (*(Pixmap *)mask_addr != XmUNSPECIFIED_PIXMAP) { if (res_type == XmLARGE_ICON) { XSaveContext(XtDisplay(widget), (Window) widget, largeIconContext, (XPointer) True); } else { XSaveContext(XtDisplay(widget), (Window) widget, smallIconContext, (XPointer) True); } } } } /************************************************************************ * * CvtStringToIconPixmap * ************************************************************************/ /*ARGSUSED*/ static Boolean CvtStringToIconPixmap( Display *dpy, XrmValue *args, Cardinal *numArgs, XrmValue *fromVal, XrmValue *toVal, XtPointer *closure_ret) /* unused */ { Pixmap pixmap = XmUNSPECIFIED_PIXMAP; String image_name = (String) (fromVal->addr); Widget widget ; unsigned char res_type; if (*numArgs != 2) { XtAppWarningMsg (XtDisplayToApplicationContext(dpy), "wrongParameters", "cvtStringToPixmap", "XtToolkitError", MESSAGE0, (String *) NULL, (Cardinal *)NULL); return False; } /* CR 7568: Set widget before we use it. */ widget = *((Widget *) args[0].addr); /* get back the resource type: LARGE or SMALL_ICON */ res_type = (unsigned char) (int) (long) args[1].addr; if (XmeNamesAreEqual(image_name, "none")) { pixmap = None ; _XM_CONVERTER_DONE ( toVal, Pixmap, pixmap, XmDestroyPixmap(XtScreen(widget), pixmap) ;) } if (XmeNamesAreEqual(image_name, XmSunspecified_pixmap)) { pixmap = XmUNSPECIFIED_PIXMAP ; _XM_CONVERTER_DONE ( toVal, Pixmap, pixmap, XmDestroyPixmap(XtScreen(widget), pixmap) ;) } /* First we have to check if the gadget has been initialized before trying to create the pixmap. We need the colors and if the cache is not yet created, we have to delay the conversion. */ if (!IG_Cache(widget)) { pixmap = XmDELAYED_PIXMAP; /* we need to stach away the name of the pixmap resource, since we'll need it in Initialize, when XmDELAYED_PIXMAP is treated, and XtGetSubResources is not going to work for XtVaTypeArg time resource, which are not in the database. */ if (res_type == XmLARGE_ICON) IG_LargePixmapName(widget) = image_name ; else IG_SmallPixmapName(widget) = image_name ; _XM_CONVERTER_DONE ( toVal, Pixmap, pixmap, XmDestroyPixmap(XtScreen(widget), pixmap) ;) } /* fetch the pixmap */ FetchPixmap(widget, image_name, res_type, &pixmap); if (pixmap == XmUNSPECIFIED_PIXMAP) { XtDisplayStringConversionWarning(dpy, image_name, "Large/SmallIconPixmap"); return False; } _XM_CONVERTER_DONE ( toVal, Pixmap, pixmap, XmDestroyPixmap(XtScreen(widget), pixmap) ;) } /************************************************************************ * GetLabelString ************************************************************************/ /*ARGSUSED*/ static void GetLabelString( Widget wid, int offset, /* unused */ XtArgVal *value) { XmString string = NULL; if (IG_LabelString(wid)) string = XmStringCopy(IG_LabelString(wid)); *value = (XtArgVal)string; } /************************************************************************ * * SecondaryObjectCreate * ************************************************************************/ /* ARGSUSED */ static void SecondaryObjectCreate( Widget req, Widget new_w, ArgList args, Cardinal *num_args ) { XmBaseClassExt *cePtr; XmWidgetExtData extData; WidgetClass wc; Cardinal size; XtPointer newSec, reqSec; cePtr = _XmGetBaseClassExtPtr(XtClass(new_w), XmQmotif); wc = (*cePtr)->secondaryObjectClass; size = wc->core_class.widget_size; newSec = _XmExtObjAlloc(size); reqSec = _XmExtObjAlloc(size); /* * Update pointers in instance records now so references to resources * in the cache record will be valid for use in CallProcs. */ IG_Cache(new_w) = &(((XmIconGCacheObject)newSec)->icon_cache); IG_Cache(req) = &(((XmIconGCacheObject)reqSec)->icon_cache); /* * fetch the resources in superclass to subclass order */ XtGetSubresources(new_w, newSec, NULL, NULL, wc->core_class.resources, wc->core_class.num_resources, args, *num_args ); extData = (XmWidgetExtData) XtCalloc(1, sizeof(XmWidgetExtDataRec)); extData->widget = (Widget)newSec; extData->reqWidget = (Widget)reqSec; ((XmIconGCacheObject)newSec)->ext.extensionType = XmCACHE_EXTENSION; ((XmIconGCacheObject)newSec)->ext.logicalParent = new_w; _XmPushWidgetExtData(new_w, extData, ((XmIconGCacheObject)newSec)->ext.extensionType); memcpy(reqSec, newSec, size); } /************************************************************************ * * InitializePosthook * ************************************************************************/ /* ARGSUSED */ static void InitializePosthook( Widget req, Widget new_w, ArgList args, Cardinal *num_args ) { XmWidgetExtData ext; XmIconGadget sw = (XmIconGadget)new_w; /* * - register parts in cache. * - update cache pointers * - and free req */ _XmProcessLock(); IG_Cache(sw) = (XmIconGCacheObjPart *) _XmCachePart( IG_ClassCachePart(sw), (XtPointer) IG_Cache(sw), sizeof(XmIconGCacheObjPart)); /* * might want to break up into per-class work that gets explicitly * chained. For right now, each class has to replicate all * superclass logic in hook routine */ /* * free the req subobject used for comparisons */ _XmPopWidgetExtData((Widget) sw, &ext, XmCACHE_EXTENSION); _XmExtObjFree((XtPointer) ext->widget); _XmExtObjFree((XtPointer) ext->reqWidget); _XmProcessUnlock(); XtFree( (char *) ext); } /************************************************************************ * * SetValuesPrehook * ************************************************************************/ /* ARGSUSED */ static Boolean SetValuesPrehook( Widget oldParent, Widget refParent, Widget newParent, ArgList args, Cardinal *num_args ) { XmWidgetExtData extData; XmBaseClassExt *cePtr; WidgetClass ec; XmIconGCacheObject newSec, reqSec; Cardinal size; _XmProcessLock(); cePtr = _XmGetBaseClassExtPtr(XtClass(newParent), XmQmotif); ec = (*cePtr)->secondaryObjectClass; size = ec->core_class.widget_size; newSec = (XmIconGCacheObject)_XmExtObjAlloc(size); reqSec = (XmIconGCacheObject)_XmExtObjAlloc(size); _XmProcessUnlock(); newSec->object.self = (Widget)newSec; newSec->object.widget_class = ec; newSec->object.parent = XtParent(newParent); newSec->object.xrm_name = newParent->core.xrm_name; newSec->object.being_destroyed = False; newSec->object.destroy_callbacks = NULL; newSec->object.constraints = NULL; newSec->ext.logicalParent = newParent; newSec->ext.extensionType = XmCACHE_EXTENSION; memcpy( &(newSec->icon_cache), IG_Cache(newParent), sizeof(XmIconGCacheObjPart)); extData = (XmWidgetExtData) XtCalloc(1, sizeof(XmWidgetExtDataRec)); extData->widget = (Widget)newSec; extData->reqWidget = (Widget)reqSec; _XmPushWidgetExtData(newParent, extData, XmCACHE_EXTENSION); XtSetSubvalues((XtPointer)newSec, ec->core_class.resources, ec->core_class.num_resources, args, *num_args); memcpy((XtPointer)reqSec, (XtPointer)newSec, size); IG_Cache(newParent) = &(((XmIconGCacheObject)newSec)->icon_cache); IG_Cache(refParent) = &(((XmIconGCacheObject)extData->reqWidget)->icon_cache); _XmExtImportArgs((Widget)newSec, args, num_args); return FALSE; } /************************************************************************ * * GetValuesPrehook * ************************************************************************/ /* ARGSUSED */ static void GetValuesPrehook( Widget newParent, ArgList args, Cardinal *num_args ) { XmWidgetExtData extData; XmBaseClassExt *cePtr; WidgetClass ec; XmIconGCacheObject newSec; Cardinal size; cePtr = _XmGetBaseClassExtPtr(XtClass(newParent), XmQmotif); ec = (*cePtr)->secondaryObjectClass; size = ec->core_class.widget_size; _XmProcessLock(); newSec = (XmIconGCacheObject)_XmExtObjAlloc(size); _XmProcessUnlock(); newSec->object.self = (Widget)newSec; newSec->object.widget_class = ec; newSec->object.parent = XtParent(newParent); newSec->object.xrm_name = newParent->core.xrm_name; newSec->object.being_destroyed = False; newSec->object.destroy_callbacks = NULL; newSec->object.constraints = NULL; newSec->ext.logicalParent = newParent; newSec->ext.extensionType = XmCACHE_EXTENSION; memcpy( &(newSec->icon_cache), IG_Cache(newParent), sizeof(XmIconGCacheObjPart)); extData = (XmWidgetExtData) XtCalloc(1, sizeof(XmWidgetExtDataRec)); extData->widget = (Widget)newSec; _XmPushWidgetExtData(newParent, extData, XmCACHE_EXTENSION); XtGetSubvalues((XtPointer)newSec, ec->core_class.resources, ec->core_class.num_resources, args, *num_args); _XmExtGetValuesHook((Widget)newSec, args, num_args); } /************************************************************************ * * GetValuesPosthook * ************************************************************************/ /* ARGSUSED */ static void GetValuesPosthook( Widget new_w, ArgList args, Cardinal *num_args ) { XmWidgetExtData ext; _XmPopWidgetExtData(new_w, &ext, XmCACHE_EXTENSION); _XmProcessLock(); _XmExtObjFree((XtPointer) ext->widget); _XmProcessUnlock(); XtFree( (char *) ext); } /************************************************************************ * * SetValuesPosthook * ************************************************************************/ /*ARGSUSED*/ static Boolean SetValuesPosthook( Widget current, Widget req, Widget new_w, ArgList args, Cardinal *num_args ) { XmWidgetExtData ext; /* * - register parts in cache. * - update cache pointers * - and free req */ /* assign if changed! */ _XmProcessLock(); if (!IconGCacheCompare((XtPointer) IG_Cache(new_w), (XtPointer) IG_Cache(current))) { /* delete the old one */ _XmCacheDelete( (XtPointer) IG_Cache(current)); IG_Cache(new_w) = (XmIconGCacheObjPart *) _XmCachePart(IG_ClassCachePart(new_w), (XtPointer) IG_Cache(new_w), sizeof(XmIconGCacheObjPart)); } else IG_Cache(new_w) = IG_Cache(current); _XmPopWidgetExtData(new_w, &ext, XmCACHE_EXTENSION); _XmExtObjFree((XtPointer) ext->widget); _XmExtObjFree((XtPointer) ext->reqWidget); _XmProcessUnlock(); XtFree( (char *) ext); return FALSE; } /*---------------- | RectObj methods | ----------------*/ /************************************************************************ * ClassInitialize * ************************************************************************/ static void ClassInitialize( void ) { iconGBaseClassExtRec.record_type = XmQmotif; /* Install the special converters for pixmap/mask */ XtSetTypeConverter (XmRString, XmRLargeIconPixmap, CvtStringToIconPixmap, largeIconArgs, XtNumber(largeIconArgs), (XtCacheNone | XtCacheRefCount), NULL); XtSetTypeConverter (XmRString, XmRSmallIconPixmap, CvtStringToIconPixmap, smallIconArgs, XtNumber(smallIconArgs), (XtCacheNone | XtCacheRefCount), NULL); largeIconContext = XUniqueContext(); smallIconContext = XUniqueContext(); } /************************************************************************ * ClassPartInitialize * ************************************************************************/ static void ClassPartInitialize( WidgetClass wc) { _XmFastSubclassInit(wc, XmICONGADGET_BIT); /* Install the containerItem trait for me and all subclasses */ XmeTraitSet((XtPointer) wc, XmQTcontainerItem, (XtPointer)&iconCIT); /* Install the care Visual trait for me and all subclasses */ XmeTraitSet((XtPointer) wc, XmQTcareParentVisual, (XtPointer)&iconCVT); /* Install the accessColors trait for all subclasses as well. */ XmeTraitSet((XtPointer) wc, XmQTaccessColors, (XtPointer)&iconACT); /* Install the pointIn trait for all subclasses as well. */ XmeTraitSet((XtPointer) wc, XmQTpointIn, (XtPointer)&iconPIT); } /************************************************************************ * Initialize ************************************************************************/ /*ARGSUSED*/ static void Initialize( Widget rw, Widget nw, ArgList args, /* unused */ Cardinal *num_args) /* unused */ { XmIconGadget new_ig = (XmIconGadget)nw; unsigned int w = 0, h = 0; Cardinal i ; /* XmNviewType */ if (!XmRepTypeValidValue(XmRID_VIEW_TYPE,IG_ViewType(nw),nw)) IG_ViewType(nw) = XmLARGE_ICON; /* XmNvisualEmphasis */ if (!XmRepTypeValidValue(XmRID_VISUAL_EMPHASIS, IG_VisualEmphasis(nw),nw)) IG_VisualEmphasis(nw) = XmNOT_SELECTED; /* XmNalignment */ if (!XmRepTypeValidValue(XmRID_ALIGNMENT, IG_Alignment(nw), nw)) IG_Alignment(nw) = XmALIGNMENT_CENTER; /* XmNrenderTable */ if (IG_RenderTable(nw) == NULL) { XmRenderTable defaultRT = NULL; XtVaGetValues(XtParent(nw), XmNrenderTable, &defaultRT, NULL); if (defaultRT == NULL) defaultRT = XmeGetDefaultRenderTable(nw, XmLABEL_FONTLIST); IG_RenderTable(nw) = XmRenderTableCopy(defaultRT, NULL, 0); } else IG_RenderTable(nw) = XmRenderTableCopy(IG_RenderTable(nw), NULL, 0); /* XmNlabelString */ if (!IG_LabelString(nw)) { IG_LabelString(nw) = XmeGetLocalizedString ( (char *) NULL, nw, XmNlabelString, XrmQuarkToString(new_ig->object.xrm_name)); } else IG_LabelString(nw) = XmStringCopy(IG_LabelString(nw)); /* XmNdetail */ if (IG_Detail(nw) && IG_DetailCount(nw)) { IG_Detail(nw) = (XmStringTable) XtMalloc(IG_DetailCount(nw) * sizeof(XmString)); for (i=0; irectangle.width == 0) new_ig->rectangle.width = 0; if (((XmGadget)rw)->rectangle.height == 0) new_ig->rectangle.height = 0; /* if a size has been specified (not 0), it won't be altered by the GetSize function */ GetSize(nw, &new_ig->rectangle.width, &new_ig->rectangle.height); IG_NormalGC(nw) = NULL; IG_BackgroundGC(nw) = NULL; IG_InsensitiveGC(nw) = NULL; IG_TopShadowGC(nw) = NULL; IG_BottomShadowGC(nw) = NULL; IG_HighlightGC(nw) = NULL; IG_InverseGC(nw) = NULL; IG_SelectedGC(nw) = NULL; /* otherwize UpdateGCs frees them */ UpdateGCs(nw); new_ig->gadget.event_mask = XmHELP_EVENT | XmFOCUS_IN_EVENT | XmFOCUS_OUT_EVENT | XmENTER_EVENT | XmLEAVE_EVENT ; } /************************************************************************ * Destroy ************************************************************************/ static void Destroy( Widget wid) { Cardinal i ; if (IG_RenderTable(wid) != NULL) XmRenderTableFree(IG_RenderTable(wid)); if (IG_LabelString(wid) != NULL) XmStringFree(IG_LabelString(wid)); if (IG_Detail(wid) && IG_DetailCount(wid)) { for (i=0; i IG_LabelRectWidth(wid))) label_x += (IG_LargeIconRectWidth(wid) - IG_LabelRectWidth(wid))/2; else if ((IG_Alignment(wid) == XmALIGNMENT_CENTER) && HAS_MASK(wid) && (IG_LargeIconRectWidth(wid) > IG_LabelRectWidth(wid) + 2*ist)) label_x += (IG_LargeIconRectWidth(wid) - IG_LabelRectWidth(wid) - 2*ist)/2; else if ((IG_Alignment(wid) == XmALIGNMENT_END) && !HAS_MASK(wid) && (IG_LargeIconRectWidth(wid) > IG_LabelRectWidth(wid))) label_x += IG_LargeIconRectWidth(wid) - IG_LabelRectWidth(wid); else if ((IG_Alignment(wid) == XmALIGNMENT_END) && HAS_MASK(wid) && (IG_LargeIconRectWidth(wid) > IG_LabelRectWidth(wid) + 2*ist)) label_x += IG_LargeIconRectWidth(wid) - IG_LabelRectWidth(wid) - 2*ist; label_y += IG_LargeIconRectHeight(wid) + SPACING(wid); } else { /* XmSMALL_ICON */ label_x += IG_SmallIconRectWidth(wid) + SPACING(wid); if (!HAS_MASK(wid) && (IG_SmallIconRectHeight(wid) > IG_LabelRectHeight(wid))) label_y += (IG_SmallIconRectHeight(wid) - IG_LabelRectHeight(wid))/2 ; else if (HAS_MASK(wid) && (IG_SmallIconRectHeight(wid) > IG_LabelRectHeight(wid) + 2*ist)) label_y += (IG_SmallIconRectHeight(wid) - IG_LabelRectHeight(wid) - 2*ist)/2 ; } label_x += IG_MarginWidth(wid); /* test LayoutIsRtoLG(wid) here */ if (LayoutIsRtoLG(wid)) { label_x = XtWidth(wid) - label_x - IG_LabelRectWidth(wid) - IG_HLThickness(wid); } else { label_x += IG_HLThickness(wid) ; } if (x_ret) *x_ret = label_x; if (y_ret) *y_ret = label_y + IG_HLThickness(wid) + IG_MarginHeight(wid); } /************************************************************************ * GetLargeIconX ************************************************************************/ static Position GetLargeIconX( Widget wid) { /* no test LayoutIsRtoLG(wid) here */ Dimension ist = IG_ShadowThickness(wid); Position large_x = IG_HLThickness(wid) + IG_MarginWidth(wid); if ((IG_Alignment(wid) == XmALIGNMENT_CENTER) && !HAS_MASK(wid) && (IG_LabelRectWidth(wid) > IG_LargeIconRectWidth(wid))) large_x += (IG_LabelRectWidth(wid) - IG_LargeIconRectWidth(wid)) /2; else if ((IG_Alignment(wid) == XmALIGNMENT_CENTER) && HAS_MASK(wid) && (IG_LabelRectWidth(wid) + 2*ist > IG_LargeIconRectWidth(wid))) large_x += (IG_LabelRectWidth(wid) + 2*ist - IG_LargeIconRectWidth(wid)) /2; else if ((IG_Alignment(wid) == XmALIGNMENT_END) && !HAS_MASK(wid) && (IG_LargeIconRectWidth(wid) < IG_LabelRectWidth(wid))) large_x += IG_LabelRectWidth(wid) - IG_LargeIconRectWidth(wid); else if ((IG_Alignment(wid) == XmALIGNMENT_END) && HAS_MASK(wid) && (IG_LargeIconRectWidth(wid) < IG_LabelRectWidth(wid) + 2*ist)) large_x += IG_LabelRectWidth(wid) + 2*ist - IG_LargeIconRectWidth(wid); if (!HAS_MASK(wid)) large_x += ist; return large_x; } /************************************************************************ * GetLargeIconY ************************************************************************/ /* the shadow thickness is only incorporated when there is no mask */ #define GetLargeIconY(wid) (IG_HLThickness(wid) + IG_MarginHeight(wid) + \ (HAS_MASK(wid) ? 0 : IG_ShadowThickness(wid))) /************************************************************************ * GetSmallIconX ************************************************************************/ /* the shadow thickness is only incorporated when there is no mask */ #define GetSmallIconX(wid) (IG_HLThickness(wid) + IG_MarginWidth(wid) + \ (HAS_MASK(wid) ? 0 : IG_ShadowThickness(wid))) /************************************************************************ * GetSmallIconY ************************************************************************/ static Position GetSmallIconY( Widget wid) { Dimension ist = IG_ShadowThickness(wid); Position small_y = IG_HLThickness(wid) + IG_MarginHeight(wid); if (!HAS_MASK(wid) && (IG_LabelRectHeight(wid) > IG_SmallIconRectHeight(wid))) small_y += (IG_LabelRectHeight(wid) - IG_SmallIconRectHeight(wid))/2; else if (HAS_MASK(wid) && (IG_LabelRectHeight(wid) + 2*ist > IG_SmallIconRectHeight(wid))) small_y += (IG_LabelRectHeight(wid) + 2*ist - IG_SmallIconRectHeight(wid))/2; if (!HAS_MASK(wid)) small_y += ist; return small_y; } /************************************************************************ * GetIconLabelWidth * including the shadows, the spacing, and the margin ************************************************************************/ static Dimension GetIconLabelWidth( Widget wid) { Dimension width = 2*IG_MarginWidth(wid); if (IG_ViewType(wid) == XmLARGE_ICON) { if (!HAS_MASK(wid)) width += MAX(IG_LargeIconRectWidth(wid), IG_LabelRectWidth(wid)) + 2*IG_ShadowThickness(wid); else width += MAX(IG_LargeIconRectWidth(wid), IG_LabelRectWidth(wid) + 2*IG_ShadowThickness(wid)); } else { /* XmSMALL_ICON */ width += IG_SmallIconRectWidth(wid) + IG_LabelRectWidth(wid) + 2*IG_ShadowThickness(wid) + SPACING(wid); } return width; } /************************************************************************ * GetIconLabelHeight * including the shadows, the possible spacing, and the margin ************************************************************************/ static Dimension GetIconLabelHeight( Widget wid) { Dimension height = 2*IG_MarginHeight(wid); if (IG_ViewType(wid) == XmLARGE_ICON) { height += IG_LargeIconRectHeight(wid) + IG_LabelRectHeight(wid) + 2*IG_ShadowThickness(wid) + SPACING(wid); } else { if (!HAS_MASK(wid)) height += MAX(IG_SmallIconRectHeight(wid), IG_LabelRectHeight(wid)) + 2*IG_ShadowThickness(wid); else height += MAX(IG_SmallIconRectHeight(wid), IG_LabelRectHeight(wid) + 2*IG_ShadowThickness(wid)); } return height; } /*********** * GetShapeInfo. * This return the points that defines the shadow rectangle. * Since this function is used for both shadow and highlight, * the ht parameter is used to differentiate both case. It is -1 * for the highlight case and the real highlightthickness for * the shadow case. * The coordinates passed in should not have integrate any RtoL * layout yet, since the function is doing mirroring at the end. * * The function returns the number of valid points (8 points in * the generic case or only 2 points for a rectangle). * **********/ static Cardinal GetShapeInfo( Widget wid, Position large_icon_x, Position small_icon_y, Position label_x, Position label_y, Dimension first_column_width, Dimension ht, XPoint * points) { Dimension ist = IG_ShadowThickness(wid), rht = IG_HLThickness(wid); Cardinal i, n = 8; XmIconGadget ig = (XmIconGadget) wid ; Boolean highlight_case ; Dimension mh, mw, rmh = IG_MarginHeight(wid), rmw = IG_MarginWidth(wid); Dimension maxX; if (ht == INVALID_DIMENSION) { /* If we're doing the highlight case, mark the dimension as zero but remember it so that the shadow is not drawn later on in this routine */ ht = 0 ; highlight_case = True ; mw = mh = 0; } else { highlight_case = False ; mw = rmw; mh = rmh; } /* then first treat the simple case where either the pixmap or the label is missing */ points[0].x = ht + mw; points[0].y = ht + mh; points[1].x = 2*ist + 2*rht - ht + 2*rmw - mw; points[1].y = 2*ist + 2*rht - ht + 2*rmh - mh; if (XmStringEmpty(IG_LabelString(wid))) { /* no label */ if ((IG_ViewType(wid) == XmLARGE_ICON) && (PIXMAP_VALID(IG_LargeIconPixmap(wid)))) { points[1].x += IG_LargeIconRectWidth(wid) ; points[1].y += IG_LargeIconRectHeight(wid) ; } if ((IG_ViewType(wid) == XmSMALL_ICON) && (PIXMAP_VALID(IG_SmallIconPixmap(wid)))) { points[1].x += IG_SmallIconRectWidth(wid) ; points[1].y += IG_SmallIconRectHeight(wid) ; } n = 2 ; } else {/* a label */ if (!HAS_PIXMAP(wid)) { /* but no pixmap */ points[1].x += IG_LabelRectWidth(wid) ; points[1].y += IG_LabelRectHeight(wid) ; n = 2 ; } } if (n == 8 && IG_ViewType(wid) == XmLARGE_ICON) { /* point #0 is top left corner of label */ points[0].x = label_x - ist - rht + ht - rmw + mw; points[0].y = ht + mh + IG_LargeIconRectHeight(wid); if ((!HAS_MASK(wid) && (IG_LargeIconRectWidth(wid) > IG_LabelRectWidth(wid))) || (HAS_MASK(wid) && (IG_LargeIconRectWidth(wid) > IG_LabelRectWidth(wid) + 2*ist))) { points[0].y += 2*rht - 2*ht + 2*rmh - 2*mh; if (!HAS_MASK(wid)) points[0].y += 2*ist -1; else if (highlight_case) points[0].y -= 1; if (!highlight_case && HAS_MASK(wid)) points[0].y += SPACING(wid); } else points[0].y += SPACING(wid); points[1].x = large_icon_x - (ist + rht - ht + rmw - mw); if (highlight_case && HAS_MASK(wid)) points[1].x += ist; points[1].y = points[0].y ; points[2].x = points[1].x ; points[2].y = ht + mh; points[3].x = large_icon_x + IG_LargeIconRectWidth(wid) + ist + rht - ht + rmw - mw -1; if (highlight_case && HAS_MASK(wid)) points[3].x -= ist; points[3].y = points[2].y ; points[4].x = points[3].x ; points[4].y = points[0].y; points[5].x = label_x + IG_LabelRectWidth(wid) + ist + rht - ht + rmw - mw -1; if (!highlight_case && HAS_MASK(wid) && ist) points[5].x += 1 ; points[5].y = points[0].y ; points[6].x = points[5].x ; points[6].y = IG_LargeIconRectHeight(wid) + IG_LabelRectHeight(wid) + 2*ist + 2*rht - ht + 2*rmh - mh + SPACING(wid) -1; if (!highlight_case && HAS_MASK(wid) && ist) points[6].y += 1 ; points[7].x = points[0].x ; points[7].y = points[6].y ; } else if (n == 8) { /* SMALL_ICON */ /* point #0 is top left corner of pixmap */ points[0].x = ht + mw; points[0].y = small_icon_y - ist - rht + ht - rmh + mh; if (highlight_case && HAS_MASK(wid)) points[0].y += ist; points[1].x = IG_SmallIconRectWidth(wid) + ht + mw; if ((!HAS_MASK(wid) && (IG_SmallIconRectHeight(wid) > IG_LabelRectHeight(wid))) || (HAS_MASK(wid) && (IG_SmallIconRectHeight(wid) > IG_LabelRectHeight(wid) + 2*ist))){ points[1].x += 2*rht - 2*ht + 2*rmw - 2*mw; if (!HAS_MASK(wid)) points[1].x += 2*ist -1; else if (highlight_case) points[1].x -= 1; if (!highlight_case && HAS_MASK(wid)) points[1].x += SPACING(wid); } else points[1].x += SPACING(wid); points[1].y = points[0].y; points[2].x = points[1].x; points[2].y = label_y - ist - rht + ht - rmh + mh; points[3].x = IG_SmallIconRectWidth(wid) + SPACING(wid) + IG_LabelRectWidth(wid) + 2*ist + 2*rht - ht + 2*rmw - mw -1; if (highlight_case && HAS_MASK(wid)) points[3].x -= 1 ; points[3].y = points[2].y; points[4].x = points[3].x; points[4].y = label_y + IG_LabelRectHeight(wid) + ist + rht - ht + rmh - mh -1; if (!highlight_case && HAS_MASK(wid) && ist) points[4].y += 1; points[5].x = points[1].x; points[5].y = points[4].y; points[6].x = points[5].x; points[6].y = small_icon_y + IG_SmallIconRectHeight(wid) + ist + rht - ht + rmh - mh -1; if (highlight_case && HAS_MASK(wid)) points[6].y -= ist; points[7].x = points[0].x ; points[7].y = points[6].y; } /* now treat the case where the pixmap is present but it has a mask: no shadow around the pixmap, just the label, if there is a label of course. Only aply for the shadow, not for the highlight, so we checked that using the ht parameter at the beginning */ if (HAS_MASK(wid) && !highlight_case) { if (XmStringEmpty(IG_LabelString(wid))) { return 0 ; } else if (n == 8) { /* uses the points already computed for the polygon shadow case */ if (IG_ViewType(wid) == XmLARGE_ICON) { points[0].x = points[0].x ; points[0].y = points[0].y ; points[1].x = points[6].x ; points[1].y = points[6].y ; } else { points[0].x = points[2].x ; points[0].y = points[2].y ; points[1].x = points[4].x ; points[1].y = points[4].y ; } n = 2 ; } } /* put the points in the frame */ if (highlight_case) maxX = ig->rectangle.width - ht - mw; else maxX = MIN(ig->rectangle.width - ht - mw, first_column_width); for (i=0; i maxX) points[i].x = maxX; if (points[i].y > ig->rectangle.height - ht - mh) points[i].y = ig->rectangle.height - ht - mh; /* add the gadget position in its parent */ points[i].x += ig->rectangle.x ; points[i].y += ig->rectangle.y ; } /* test LayoutIsRtoLG(wid) here */ if (LayoutIsRtoLG(wid) ) { /* mirror the x position */ for (i = 0; i < n; i++) points[i].x = 2*ig->rectangle.x + XtWidth(wid) - points[i].x -1; /* + in the rectangle case, switch x because of XmeDrawShadow required left-upper right-bottom point order */ if (n == 2) { Position save_x = points[1].x ; points[1].x = points[0].x +1; points[0].x = save_x +1; } } return n ; } /*********** * GetContainerData **********/ static void GetContainerData( Widget wid, XmContainerData container_data) { XmIconGadgetClass igc = (XmIconGadgetClass) XtClass(wid); Widget container_id ; XmContainerTrait container_trait ; XmIconGadget ig = (XmIconGadget)wid; /**** initialize the trait struct */ /* need to set detail_order_count and first_column so that container gets a min base. The problem we're trying to solve here is when the first kid gets created, when it computes its preferred size from its Initialize method, the container cannot come up for a valid dynamic detail_order_count or first_column_width since it doesn't have any child in it yet (this one hasn't been inserted yet: Initialize < InsertChild in Xt). So we pass the current kid value and the Container will use them as min, or default if you want. */ container_data->detail_order_count = IG_DetailCount(wid); container_data->first_column_width = IG_HLThickness(wid) + GetIconLabelWidth(wid) - IG_MarginWidth(wid); container_data->selection_mode = XmNORMAL_MODE ; container_data->detail_order = NULL ; container_data->detail_tablist = NULL ; container_data->select_color = XmREVERSED_GROUND_COLORS ; /*** get the Container information using the trait */ /* first get the widget id from which to fetch the trait */ container_id = (igc->icong_class.get_container_parent)? (*(igc->icong_class.get_container_parent))(wid) : XtParent(wid); /* then get the trait info */ container_trait = (XmContainerTrait) XmeTraitGet((XtPointer) XtClass(container_id), XmQTcontainer) ; if (container_trait) container_trait->getValues(container_id, container_data); else return ; /*** detail_order_count might be 0: mean no detail displayed, even if the icon has some. detail_order might be NULL: mean if there is detail to display, we'll use a default order [1..N] when we need it. detail_tablist might be null, mean concat for the kid. (XmContainer returns NULL unless it can't come up with a reasonable tablist due to its size being NULL or too small) first_column_width might be 0, which mean spatial: use icon/label only */ /* a return of 0 for first column width means we are in spatial, in this case, don't use rectangle.x at all */ if (!container_data->first_column_width) { container_data->first_column_width = IG_HLThickness(wid) + GetIconLabelWidth(wid) - IG_MarginWidth(wid); } else { /* remove the current hor indentation */ if (LayoutIsRtoLG(wid)) { if (XtWidth(XtParent(wid))) { if ((Position)container_data->first_column_width > (XtWidth(XtParent(wid)) - ig->rectangle.width - ig->rectangle.x)) { container_data->first_column_width -= (XtWidth(XtParent(wid)) - ig->rectangle.width - ig->rectangle.x) ; } else { container_data->first_column_width = IG_HLThickness(wid) + IG_MarginWidth(wid); } } else { /* parent not sized yet */ if ((Position)container_data->first_column_width > ig->rectangle.x) container_data->first_column_width -= ig->rectangle.x ; else container_data->first_column_width = IG_HLThickness(wid) + IG_MarginWidth(wid); } } else /* regular case: not RtoL*/ /* here we have to worry of special cases where the first_column_width and the position of the kid are extreme */ if (((Position)container_data->first_column_width > ig->rectangle.x) && ig->rectangle.x >= 0) { container_data->first_column_width -= ig->rectangle.x ; if (container_data->first_column_width < IG_HLThickness(wid) + IG_MarginWidth(wid)) container_data->first_column_width = IG_HLThickness(wid) + IG_MarginWidth(wid); } else container_data->first_column_width = IG_HLThickness(wid) + IG_MarginWidth(wid); } /*** leaving this routine: detail_order_count might be 0: no detail to display detail_order might be NULL. : use implicit order container_data->detail_tablist might be NULL: use concat container_data->first_column_width is: in spatial, Container returned first_column_width=0, and we turned it in GetContainerData into icon_width (included highlight). in outline/detail, first_column_width is the clipping width from the current position of the icon to the start of the detail rendering (included highlight too). */ } /************************************************************************ * Redisplay * This is the main routine of this baby. ************************************************************************/ /*ARGSUSED*/ static void Redisplay( Widget wid, XEvent *event, /* unused */ Region region) /* unused */ { XmIconGadget ig = (XmIconGadget)wid; GC gc; GC background_gc; Dimension pm_width,pm_height; XRectangle clip_rect; Boolean clip_set = False; int depth; XmContainerDataRec container_data ; Position large_icon_x = 0, small_icon_y = 0, small_icon_x, label_x = 0, label_y = 0 ; Dimension w, h, ist = IG_ShadowThickness(wid), ht = IG_HLThickness(wid); Dimension mw = IG_MarginWidth(wid), mh = IG_MarginHeight(wid); Cardinal i ; XPoint shad_points[8] ; /* a gc for the ink (text only) */ if (!XtIsSensitive(wid)) gc = IG_InsensitiveGC(wid); else gc = IG_NormalGC(wid); /**** invert the background gc for selected view */ if (IG_VisualEmphasis(wid) == XmSELECTED) { background_gc = IG_SelectedGC(wid); /* if inverse_gc has been set, it holds the parent background as its foreground (ink). Use it when in selected mode */ if (IG_InverseGC(wid)) gc = IG_InverseGC(wid); } else { background_gc = IG_BackgroundGC(wid); } /**** get the container information */ container_data.valueMask = ContAllValid ; GetContainerData(wid, &container_data); /**** clear the background */ /* in detail mode, clear the entire gadget area using background_gc (which, depending on the selected mode is the selectedGC or the BackgroundGC of the icon), while in iconlabel only, only clear the iconlabel using cleararea (and we will later clear the label part using background_gc) */ if (SHOW_DETAIL(wid, &container_data)) { XSetClipMask(XtDisplay(wid), background_gc, None); XFillRectangle(XtDisplay(wid), XtWindow(wid), background_gc, ig->rectangle.x, ig->rectangle.y, ig->rectangle.width, ig->rectangle.height); } else { XSetClipMask(XtDisplay(wid), IG_BackgroundGC(wid), None); } /**** render the pixmap first */ if ((IG_ViewType(wid) == XmLARGE_ICON) && (PIXMAP_VALID(IG_LargeIconPixmap(wid)))) { large_icon_x = GetLargeIconX(wid); /* no rtl yet */ XmeGetPixmapData(XtScreen(wid), IG_LargeIconPixmap(wid), NULL, &depth, NULL, NULL, NULL, NULL, NULL, NULL); pm_width = IG_LargeIconRectWidth(wid); if (large_icon_x + pm_width > MIN(ig->rectangle.width, container_data.first_column_width)) { pm_width = MIN(ig->rectangle.width - 2*ht, container_data.first_column_width - ht); pm_width -= MIN(pm_width, (Dimension)large_icon_x); if (LayoutIsRtoLG(wid)) large_icon_x = ig->rectangle.width - MIN(ig->rectangle.width - 2*ht, container_data.first_column_width - ht) ; } else { if (LayoutIsRtoLG(wid)) large_icon_x = ig->rectangle.width - large_icon_x - pm_width ; } pm_height = IG_LargeIconRectHeight(wid) ; if (ht + ist + pm_height > ig->rectangle.height - 2*ht) pm_height = ig->rectangle.height - ist - ht; /* clip with the mask if any */ if (PIXMAP_VALID(IG_LargeIconMask(wid))) { XSetClipMask(XtDisplay(wid), IG_NormalGC(wid), IG_LargeIconMask(wid)); XSetClipOrigin(XtDisplay(wid), IG_NormalGC(wid), ig->rectangle.x + large_icon_x, ig->rectangle.y + ht + mh); } else { XSetClipMask(XtDisplay(wid), IG_NormalGC(wid),None); } if (depth == XtParent(wid)->core.depth) XCopyArea(XtDisplay(wid),IG_LargeIconPixmap(wid), XtWindow(wid), IG_NormalGC(wid), 0,0, pm_width, pm_height, ig->rectangle.x + large_icon_x, ig->rectangle.y + GetLargeIconY(wid)); else if (depth == 1) XCopyPlane(XtDisplay(wid),IG_LargeIconPixmap(wid), XtWindow(wid), IG_NormalGC(wid), 0,0, pm_width, pm_height, ig->rectangle.x + large_icon_x, ig->rectangle.y + GetLargeIconY(wid), 1); } if ((IG_ViewType(wid) == XmSMALL_ICON) && (PIXMAP_VALID(IG_SmallIconPixmap(wid)))) { small_icon_y = GetSmallIconY(wid); XmeGetPixmapData(XtScreen(wid), IG_SmallIconPixmap(wid), NULL, &depth, NULL, NULL, NULL, NULL, NULL, NULL); pm_width = IG_SmallIconRectWidth(wid); small_icon_x = GetSmallIconX(wid); if (small_icon_x + pm_width > MIN(ig->rectangle.width - 2*ht, container_data.first_column_width - 2*ht)) { pm_width = MIN(ig->rectangle.width, container_data.first_column_width) - 2*ht; pm_width -= MIN(pm_width, (Dimension)small_icon_x); if (LayoutIsRtoLG(wid)) small_icon_x = ig->rectangle.width + 2*ht - MIN(ig->rectangle.width, container_data.first_column_width) ; } else { if (LayoutIsRtoLG(wid)) small_icon_x = ig->rectangle.width - small_icon_x - pm_width ; } pm_height = IG_SmallIconRectHeight(wid); if (small_icon_y + pm_height > ig->rectangle.height - 2*ht) pm_height = ig->rectangle.height - small_icon_y; /* clip with the mask if any */ if (PIXMAP_VALID(IG_SmallIconMask(wid))) { XSetClipMask(XtDisplay(wid), IG_NormalGC(wid), IG_SmallIconMask(wid)); XSetClipOrigin(XtDisplay(wid), IG_NormalGC(wid), ig->rectangle.x + small_icon_x, ig->rectangle.y + small_icon_y); } else { XSetClipMask(XtDisplay(wid), IG_NormalGC(wid),None); } if (depth == XtParent(wid)->core.depth) XCopyArea(XtDisplay(wid),IG_SmallIconPixmap(wid), XtWindow(wid), IG_NormalGC(wid),0,0, pm_width,pm_height, ig->rectangle.x + small_icon_x, ig->rectangle.y + small_icon_y); else if (depth == 1) XCopyPlane(XtDisplay(wid),IG_SmallIconPixmap(wid), XtWindow(wid), IG_NormalGC(wid),0,0, pm_width,pm_height, ig->rectangle.x + small_icon_x, ig->rectangle.y + small_icon_y, 1); } clip_rect.y = ig->rectangle.y + ht + mh; clip_rect.width = MIN(ig->rectangle.width - 2*ht - 2*mw, container_data.first_column_width - ht - mw); clip_rect.height = ig->rectangle.height - 2*ht - 2*mh; if (LayoutIsRtoLG(wid)) { clip_rect.x = ig->rectangle.x + ig->rectangle.width - ht - clip_rect.width - mw; } else { clip_rect.x = ig->rectangle.x + ht + mw; } XSetClipRectangles(XtDisplay(wid),gc,0,0,&clip_rect,1,Unsorted); XSetClipRectangles(XtDisplay(wid),background_gc,0,0,&clip_rect,1,Unsorted); /**** then draw the label part of the icon */ GetLabelXY(wid, &label_x, &label_y) ; if (!XmStringEmpty(IG_LabelString(wid))) { XFillRectangle(XtDisplay(wid), XtWindow(wid), background_gc, ig->rectangle.x + label_x, ig->rectangle.y + label_y, IG_LabelRectWidth(wid), IG_LabelRectHeight(wid)); /* if we are in the inverse_color case, we need to draw the string with parent background ink, and parent foreground as back color (The previous fillrectangle took care of that last part). gc has been set up to IG_InverseGC at the beginning of this routine, so what's left is the forcing of this ink/foreground */ XmStringDraw(XtDisplay(wid),XtWindow(wid), IG_RenderTable(wid),IG_LabelString(wid), gc, ig->rectangle.x + label_x + DEFAULT_LABEL_MARGIN_WIDTH, ig->rectangle.y + label_y + DEFAULT_LABEL_MARGIN_HEIGHT, IG_LabelRectWidth(wid) - 2*DEFAULT_LABEL_MARGIN_WIDTH, XmALIGNMENT_BEGINNING, LayoutG(wid), NULL); } XSetClipMask(XtDisplay(wid),background_gc,None); /**** now the polygon shadow around the icon+label, or the square shadow around a masked pixmap or a no pixmap icon */ /* only draw shadows if there is something inside */ if (container_data.first_column_width) { Cardinal n ; /* undo the ltr layout for label_x, because getshapeinfo does it */ if (LayoutIsRtoLG(wid)) { label_x = XtWidth(wid) - IG_LabelRectWidth(wid) - label_x ; } n = GetShapeInfo(wid, GetLargeIconX(wid), small_icon_y, label_x, label_y, container_data.first_column_width, ht, &shad_points[0]) ; /* only draw the polygon shadow if there is no mask and an existing pixmap */ if (n == 2) { XmeDrawShadows(XtDisplay(wid),XtWindow(wid), IG_TopShadowGC(wid), IG_BottomShadowGC(wid), shad_points[0].x, shad_points[0].y, shad_points[1].x - shad_points[0].x, shad_points[1].y - shad_points[0].y, ist, XmSHADOW_OUT); } else if (n == 8) { XmeDrawPolygonShadow (XtDisplay(wid),XtWindow(wid), IG_TopShadowGC(wid), IG_BottomShadowGC(wid), shad_points, n, ist, XmSHADOW_OUT); } } /**** then comes the details rendering */ if (SHOW_DETAIL(wid, &container_data)&& container_data.first_column_width >= ht + mw) { unsigned int tab_count = 0 ; Dimension detail_x, detail_y; XmStringTable new_detail ; int lab_baseline = 0, detail_baseline ; /* get the detail table to be displayed */ new_detail = GetStringTableReOrdered(IG_Detail(wid), IG_DetailCount(wid), container_data.detail_order, container_data.detail_order_count); if (container_data.detail_tablist) tab_count = XmTabListTabCount(container_data.detail_tablist) ; /* the extra tabs are ignored */ tab_count = MIN(tab_count, container_data.detail_order_count); /* tab_count might be 0 at this point, but it won't be treated as a special case */ if (IG_LabelString(wid)) lab_baseline = XmStringBaseline(IG_RenderTable(wid), IG_LabelString(wid)) ; /* detail_x is in gadget relative coordinate */ detail_x = container_data.first_column_width; for (i = 0 ; i < IG_DetailCount(wid) ; i++) { Position next_tab_x = 0 ; w = 0 ; detail_x += DEFAULT_HOR_SPACING ; if (container_data.detail_tablist) next_tab_x = container_data.first_column_width + _XmTabListGetPosition(XtScreen(wid), container_data.detail_tablist, XmPIXELS, i); if (new_detail[i]) { /* if we have a tab, use it, don't bother to call an expensive string extent. */ if (i < tab_count) { clip_rect.width = MIN (next_tab_x - detail_x, ig->rectangle.width - 2*ht - 2*mw - detail_x); clip_rect.x = ig->rectangle.x + detail_x; if (LayoutIsRtoLG(wid)) clip_rect.x = ig->rectangle.x + ig->rectangle.width - detail_x - clip_rect.width; clip_rect.y = ig->rectangle.y + ht + mh; clip_rect.height = ig->rectangle.height - 2*ht - 2*mh; XSetClipRectangles(XtDisplay(wid),gc,0,0,&clip_rect,1, Unsorted); } else { XmStringExtent(IG_RenderTable(wid), new_detail[i], &w, &h); if (!clip_set) { clip_rect.x = ig->rectangle.x + ht + mw; clip_rect.y = ig->rectangle.y + ht + mh; clip_rect.width = ig->rectangle.width - 2*ht - 2*mw; clip_rect.height = ig->rectangle.height - 2*ht - 2*mh; XSetClipRectangles(XtDisplay(wid),gc,0,0,&clip_rect,1, Unsorted); /* only set this clip once */ clip_set = True ; } } detail_baseline = XmStringBaseline(IG_RenderTable(wid), new_detail[i]); detail_y = label_y + DEFAULT_LABEL_MARGIN_HEIGHT + lab_baseline - detail_baseline; XmStringDraw(XtDisplay(wid),XtWindow(wid), IG_RenderTable(wid), new_detail[i], gc, (LayoutIsRtoLG(wid)) ? (ig->rectangle.x + ig->rectangle.width - detail_x - ((i < tab_count) ? clip_rect.width : w)) : (ig->rectangle.x + detail_x), ig->rectangle.y + detail_y, ((i < tab_count) ? clip_rect.width : w), XmALIGNMENT_BEGINNING, LayoutG(wid), NULL); /* clip is done in gc */ } if (i < tab_count) { detail_x = next_tab_x; } else { detail_x += w ; } } } /**** draw the highlight if needed */ if (ig->gadget.highlighted) { if(((XmGadgetClass) XtClass(wid))->gadget_class.border_highlight){ (*(((XmGadgetClass) XtClass(wid)) ->gadget_class.border_highlight))(wid) ; } } } /************************************************************************ * SetValues ************************************************************************/ /*ARGSUSED*/ static Boolean SetValues( Widget cw, Widget rw, Widget nw, ArgList args, /* unused */ Cardinal *num_args) /* unused */ { Boolean Relayout = False; Boolean Redraw = False; unsigned int w, h ; Cardinal i ; if (IG_ViewType(nw) != IG_ViewType(cw)) { if (XmRepTypeValidValue(XmRID_VIEW_TYPE,IG_ViewType(nw),nw)) Relayout = Redraw = True; else IG_ViewType(nw) = IG_ViewType(cw); } if (IG_VisualEmphasis(nw) != IG_VisualEmphasis(cw)) { if (XmRepTypeValidValue(XmRID_VISUAL_EMPHASIS, IG_VisualEmphasis(nw),nw)) Redraw = True; else IG_VisualEmphasis(nw) = IG_VisualEmphasis(cw); } if (IG_Alignment(nw) != IG_Alignment(cw)) { if (XmRepTypeValidValue(XmRID_ALIGNMENT, IG_Alignment(nw), nw)) Relayout = Redraw = True; else IG_Alignment(nw) = IG_Alignment(cw); } if ((IG_Background(nw) != IG_Background(cw)) || (IG_Foreground(nw) != IG_Foreground(cw)) || (IG_TopShadowColor(nw) != IG_TopShadowColor(cw)) || (IG_BottomShadowColor(nw) != IG_BottomShadowColor(cw)) || (IG_HighlightColor(nw) != IG_HighlightColor(cw)) || (IG_BackgroundPixmap(nw) != IG_BackgroundPixmap(cw)) || (IG_TopShadowPixmap(nw) != IG_TopShadowPixmap(cw)) || (IG_BottomShadowPixmap(nw) != IG_BottomShadowPixmap(cw)) || (IG_HighlightPixmap(nw) != IG_HighlightPixmap(cw))) { UpdateGCs(nw); } if (IG_RenderTable(nw) != IG_RenderTable(cw)) { XmRenderTableFree(IG_RenderTable(cw)); IG_RenderTable(nw) = XmRenderTableCopy(IG_RenderTable(nw), NULL, 0); UpdateGCs(nw); if (!XmStringEmpty(IG_LabelString(nw))) XmStringExtent(IG_RenderTable(nw), IG_LabelString(nw), &(IG_LabelRectWidth(nw)), &(IG_LabelRectHeight(nw))); IG_LabelRectWidth(nw) += 2*DEFAULT_LABEL_MARGIN_WIDTH ; IG_LabelRectHeight(nw) += 2*DEFAULT_LABEL_MARGIN_HEIGHT ; Relayout = Redraw = True; } if (IG_LabelString(nw) != IG_LabelString(cw)) { XmStringFree(IG_LabelString(cw)); IG_LabelString(nw) = XmStringCopy(IG_LabelString(nw)); if (!XmStringEmpty(IG_LabelString(nw))) XmStringExtent(IG_RenderTable(nw), IG_LabelString(nw), &(IG_LabelRectWidth(nw)), &(IG_LabelRectHeight(nw))); else { IG_LabelRectWidth(nw) = 0 ; IG_LabelRectHeight(nw) = 0 ; } IG_LabelRectWidth(nw) += 2*DEFAULT_LABEL_MARGIN_WIDTH ; IG_LabelRectHeight(nw) += 2*DEFAULT_LABEL_MARGIN_HEIGHT ; Relayout = Redraw = True; } if (IG_LargeIconMask(nw) != IG_LargeIconMask(cw)) { if (OwnLargeMask(cw)) { XDeleteContext(XtDisplay(nw), (Window) nw, largeIconContext) ; if (PIXMAP_VALID(IG_LargeIconMask(cw))) XmDestroyPixmap(XtScreen(cw), IG_LargeIconMask(cw)); } if (IG_ViewType(nw) == XmLARGE_ICON) Relayout = Redraw = True; } if (IG_LargeIconPixmap(nw) != IG_LargeIconPixmap(cw)) { if (IG_ViewType(nw) == XmLARGE_ICON) Relayout = Redraw = True; /* if the new icon is different, refetch the sizes */ if (PIXMAP_VALID(IG_LargeIconPixmap(nw))) XmeGetPixmapData(XtScreen(nw), IG_LargeIconPixmap(nw), NULL, NULL, NULL, NULL, NULL, NULL, &w, &h); else { w = h = 0 ; } IG_LargeIconRectWidth(nw) = (unsigned short)w; IG_LargeIconRectHeight(nw) = (unsigned short)h; } if (IG_SmallIconMask(nw) != IG_SmallIconMask(cw)) { if (OwnSmallMask(cw)) { XDeleteContext(XtDisplay(nw), (Window) nw, smallIconContext) ; if (PIXMAP_VALID(IG_SmallIconMask(cw))) XmDestroyPixmap(XtScreen(cw), IG_SmallIconMask(cw)); } if (IG_ViewType(nw) == XmSMALL_ICON) Relayout = Redraw = True; } if (IG_SmallIconPixmap(nw) != IG_SmallIconPixmap(cw)) { if (IG_ViewType(nw) == XmSMALL_ICON) Relayout = Redraw = True; if (PIXMAP_VALID(IG_SmallIconPixmap(nw))) XmeGetPixmapData(XtScreen(nw), IG_SmallIconPixmap(nw), NULL, NULL, NULL, NULL, NULL, NULL, &w, &h); else { w = h = 0 ; } IG_SmallIconRectWidth(nw) = (unsigned short)w; IG_SmallIconRectHeight(nw) = (unsigned short)h; } if (IG_Detail(nw) != IG_Detail(cw)) { /* new XmNdetail copy in */ /* first free the current detail table and strings if present */ if (IG_Detail(cw) && IG_DetailCount(cw)) { for (i=0; icore.width == cw->core.width) nw->core.width = 0; if (rw->core.height == cw->core.height) nw->core.height = 0; } GetSize(nw, &nw->core.width, &nw->core.height); } return(Redraw); } /************************************************************************ * QueryGeometry ************************************************************************/ static XtGeometryResult QueryGeometry( Widget wid, XtWidgetGeometry *intended, XtWidgetGeometry *desired) { if (IG_RecomputeSize(wid) == False) { desired->width = XtWidth(wid) ; desired->height = XtHeight(wid) ; } else { desired->width = 0 ; desired->height = 0 ; GetSize(wid, &desired->width, &desired->height); /* the above asks for the containertrait firstColumnWidth */ } return XmeReplyToQueryGeometry(wid, intended, desired) ; } /*----------------- | XmGadget methods | -----------------*/ /************************************************************************ * HighlightBorder ************************************************************************/ static void HighlightBorder( Widget w ) { XmIconGadget ig = (XmIconGadget) w ; XmContainerDataRec container_data ; Dimension ht = IG_HLThickness(w) ; /* test LayoutIsRtoLG(wid) here */ ig->gadget.highlighted = True ; ig->gadget.highlight_drawn = True ; if(ig->rectangle.width == 0 || ig->rectangle.height == 0 || ig->gadget.highlight_thickness == 0) return ; /* The highlight is different depending if there is a detail or not. With a detail, it's a rectangular shadow, otherwise it's drawn around the icon+label */ /**** get the container information */ container_data.valueMask = ContFirstColumnWidth | ContSelectionMode ; GetContainerData(w, &container_data); XSetClipMask(XtDisplay(w), IG_HighlightGC(w), None); if (SHOW_DETAIL(w, &container_data)) { ChangeHighlightGC(w, container_data.selection_mode, ht); if (container_data.selection_mode == XmADD_MODE) _XmDrawHighlight(XtDisplay(w),XtWindow(w), IG_HighlightGC(w), ig->rectangle.x, ig->rectangle.y, ig->rectangle.width, ig->rectangle.height, ht, LineDoubleDash); else XmeDrawHighlight(XtDisplay(w),XtWindow(w), IG_HighlightGC(w), ig->rectangle.x, ig->rectangle.y, ig->rectangle.width, ig->rectangle.height, ht); } else { Position label_x, label_y ; XPoint points[8] ; /* do the polygon highlight around the icon + label part */ GetLabelXY(w, &label_x, &label_y) ; /* undo the ltr layout for label_x, because getshapeinfo does it */ if (LayoutIsRtoLG(w)) { label_x = XtWidth(w) - IG_LabelRectWidth(w) - label_x ; } if (GetShapeInfo(w, GetLargeIconX(w), GetSmallIconY(w), label_x, label_y, container_data.first_column_width, INVALID_DIMENSION, points) == 2) { /* only 2 points have been set, that's the simple case */ if (container_data.selection_mode == XmADD_MODE) { ChangeHighlightGC(w, container_data.selection_mode, ht); _XmDrawHighlight(XtDisplay(w),XtWindow(w), IG_HighlightGC(w), points[0].x, points[0].y, points[1].x - points[0].x, points[1].y - points[0].y, ht, LineDoubleDash); } else XmeDrawHighlight(XtDisplay(w),XtWindow(w), IG_HighlightGC(w), points[0].x, points[0].y, points[1].x - points[0].x, points[1].y - points[0].y, ht); } else { ChangeHighlightGC(w, container_data.selection_mode, 1); XmeDrawPolygonShadow (XtDisplay(w),XtWindow(w), IG_HighlightGC(w), IG_HighlightGC(w), points, 8, ht, XmSHADOW_OUT); } } } /************************************************************************ * UnhighlightBorder ************************************************************************/ static void UnhighlightBorder( Widget w ) { XmIconGadget ig = (XmIconGadget) w ; XmContainerDataRec container_data ; Dimension ht = IG_HLThickness(w) ; GC background_gc ; /* test LayoutIsRtoLG(wid) here */ ig->gadget.highlighted = False ; ig->gadget.highlight_drawn = False ; if(ig->rectangle.width == 0 || ig->rectangle.height == 0 || ig->gadget.highlight_thickness == 0) return ; /* unhighlight has to use the current selected background, it cannot call the superclass unhighlight as in highlight because Gadget does a simple clearborder. */ /**** get the container information */ container_data.valueMask = ContFirstColumnWidth ; GetContainerData(w, &container_data); if(XmIsManager (XtParent(w))) { background_gc = ((XmManagerWidget)XtParent(w)) ->manager.background_GC ; } else { XSetClipMask(XtDisplay(w), IG_BackgroundGC(w), None); background_gc = IG_BackgroundGC(w) ; } if (SHOW_DETAIL(w, &container_data)) { /* unhighlight the entire gadget area */ XmeDrawHighlight(XtDisplay(w),XtWindow(w), background_gc, ig->rectangle.x, ig->rectangle.y, ig->rectangle.width, ig->rectangle.height, ht); } else { Position label_x, label_y ; XPoint points[8] ; /* do the polygon unhighlight around the icon + label part */ GetLabelXY(w, &label_x, &label_y) ; /* undo the ltr layout for label_x, because getshapeinfo does it */ if (LayoutIsRtoLG(w)) { label_x = XtWidth(w) - IG_LabelRectWidth(w) - label_x ; } if (GetShapeInfo(w, GetLargeIconX(w), GetSmallIconY(w), label_x, label_y, container_data.first_column_width, INVALID_DIMENSION, points) == 2) { /* only 2 points have been set, that's the simple case */ XmeDrawHighlight(XtDisplay(w),XtWindow(w), background_gc, points[0].x, points[0].y, points[1].x - points[0].x, points[1].y - points[0].y, ht); } else { XmeDrawPolygonShadow (XtDisplay(w),XtWindow(w), background_gc, background_gc, points, 8, ht, XmSHADOW_OUT); } } } /******************************************************************* * * IconGCacheCompare * *******************************************************************/ static int IconGCacheCompare( XtPointer A, XtPointer B ) { XmIconGCacheObjPart *icon_inst = (XmIconGCacheObjPart *) A ; XmIconGCacheObjPart *icon_cache_inst = (XmIconGCacheObjPart *) B ; if((icon_inst-> render_table == icon_cache_inst->render_table) && (icon_inst-> selected_GC == icon_cache_inst->selected_GC) && (icon_inst-> inverse_GC == icon_cache_inst->inverse_GC) && (icon_inst-> normal_GC == icon_cache_inst->normal_GC) && (icon_inst-> background_GC == icon_cache_inst->background_GC) && (icon_inst-> insensitive_GC == icon_cache_inst->insensitive_GC) && (icon_inst-> top_shadow_GC == icon_cache_inst->top_shadow_GC) && (icon_inst-> bottom_shadow_GC == icon_cache_inst->bottom_shadow_GC) && (icon_inst-> highlight_GC == icon_cache_inst->highlight_GC) && (icon_inst-> background == icon_cache_inst->background) && (icon_inst-> foreground == icon_cache_inst->foreground) && (icon_inst-> top_shadow_color == icon_cache_inst->top_shadow_color) && (icon_inst-> highlight_color == icon_cache_inst->highlight_color) && (icon_inst-> top_shadow_pixmap == icon_cache_inst->background_pixmap) && (icon_inst-> background_pixmap == icon_cache_inst->top_shadow_pixmap) && (icon_inst-> highlight_pixmap == icon_cache_inst->highlight_pixmap) && (icon_inst-> bottom_shadow_color == icon_cache_inst->bottom_shadow_color) && (icon_inst-> bottom_shadow_pixmap == icon_cache_inst->bottom_shadow_pixmap) && (icon_inst-> alignment == icon_cache_inst->alignment) && (icon_inst-> spacing == icon_cache_inst->spacing) && (icon_inst-> margin_width == icon_cache_inst->margin_width) && (icon_inst-> margin_height == icon_cache_inst->margin_height) ) return 1; else return 0; } /**************************************************** * Functions for manipulating Secondary Resources. *********************************************************/ /* * GetIconGClassSecResData() * Create a XmSecondaryResourceDataRec for each secondary resource; * Put the pointers to these records in an array of pointers; * Return the pointer to the array of pointers. * client_data = Address of the structure in the class record which * represents the (template of ) the secondary data. */ /*ARGSUSED*/ static Cardinal GetIconGClassSecResData( WidgetClass w_class, /* unused */ XmSecondaryResourceData **data_rtn ) { int arrayCount; XmBaseClassExt bcePtr; String resource_class, resource_name; XtPointer client_data; bcePtr = &(iconGBaseClassExtRec ); client_data = NULL; resource_class = NULL; resource_name = NULL; arrayCount = _XmSecondaryResourceData ( bcePtr, data_rtn, client_data, resource_name, resource_class, GetIconGClassSecResBase); return (arrayCount); } /* * GetIconGClassResBase () * retrun the address of the base of resources. * If client data is the same as the address of the secndary data in the * class record then send the base address of the cache-resources for this * instance of the widget. * Right now we do not try to get the address of the cached_data from * the Gadget component of this instance - since Gadget class does not * have any cached_resources defined. If later secondary resources are * defined for Gadget class then this routine will have to change. */ /*ARGSUSED*/ static XtPointer GetIconGClassSecResBase( Widget widget, XtPointer client_data ) /* unused */ { XtPointer widgetSecdataPtr; widgetSecdataPtr = (XtPointer) (IG_Cache(widget)); return (widgetSecdataPtr); } /************************************************************************ * InputDispatch ************************************************************************/ static void InputDispatch( Widget wid, XEvent *event, Mask event_mask) { if (event_mask & XmHELP_EVENT) _XmSocorro(wid,event,NULL,NULL); else if (event_mask & XmFOCUS_IN_EVENT) _XmFocusInGadget (wid, event, NULL, NULL); else if (event_mask & XmFOCUS_OUT_EVENT) _XmFocusOutGadget (wid, event, NULL, NULL); else if (event_mask & XmENTER_EVENT) _XmEnterGadget (wid, event, NULL, NULL); else if (event_mask & XmLEAVE_EVENT) _XmLeaveGadget (wid, event, NULL, NULL); } /************************************************************************ * GetBaselines ************************************************************************/ static Boolean GetBaselines( Widget wid, Dimension **baselines, int *line_count) { Dimension * base_array; Position label_y ; *line_count = 1; base_array = (Dimension *)XtMalloc(sizeof(Dimension)); GetLabelXY(wid, NULL, &label_y); if (IG_LabelString(wid) == NULL) { base_array[0] = IG_HLThickness(wid) + label_y ; } else { base_array[0] = IG_HLThickness(wid) + label_y + DEFAULT_LABEL_MARGIN_HEIGHT + XmStringBaseline(IG_RenderTable(wid), IG_LabelString(wid)); } *baselines = base_array; return(True); } /************************************************************************ * GetDisplayRect ************************************************************************/ static Boolean GetDisplayRect( Widget wid, XRectangle *displayrect) { Dimension w = 0, h = 0 ; (*displayrect).x = IG_HLThickness(wid); (*displayrect).y = IG_HLThickness(wid); GetSize(wid, &w, &h); (*displayrect).width = w - 2*IG_HLThickness(wid); (*displayrect).height = h - 2*IG_HLThickness(wid) ; return(True); } /************************************************************************ * MarginsProc ************************************************************************/ static void MarginsProc( Widget w, XmBaselineMargins *margins_rec) { if (margins_rec->get_or_set == XmBASELINE_GET) { margins_rec->margin_top = DEFAULT_LABEL_MARGIN_HEIGHT; margins_rec->margin_bottom = DEFAULT_LABEL_MARGIN_HEIGHT; margins_rec->shadow = IG_ShadowThickness(w); margins_rec->highlight = IG_HLThickness(w); margins_rec->text_height = IG_LabelRectHeight(w); margins_rec->margin_height = DEFAULT_LABEL_MARGIN_HEIGHT; } } /*--------------------- | XmIconGadget methods | ---------------------*/ /*------------ | ActionProcs | ------------*/ /*------------------- | Internal functions | -------------------*/ /************************************************************************ * ChangeHighlightGC ************************************************************************/ static void ChangeHighlightGC( Widget wid, XtEnum selection_mode, int line_width) { XtGCMask valueMask; XGCValues values; valueMask = GCLineStyle | GCLineWidth | GCDashList | GCCapStyle ; values.line_width = line_width; values.dashes = MAX(IG_HLThickness(wid), 8); values.cap_style = CapProjecting; values.line_style = (selection_mode == XmADD_MODE) ? LineDoubleDash : LineSolid; XChangeGC(XtDisplay(wid), IG_HighlightGC(wid), valueMask, &values); } /************************************************************************ * UpdateSelectGCs ************************************************************************/ static void UpdateSelectGCs( Widget wid, Pixel select_color) { XGCValues values; XtGCMask valueMask; XFontStruct *fs = (XFontStruct *)NULL; XtGCMask modifyMask = GCClipMask | GCClipXOrigin | GCClipYOrigin; if (IG_SelectedGC(wid)) XtReleaseGC(XtParent(wid),IG_SelectedGC(wid)); if (IG_InverseGC(wid)) XtReleaseGC(XtParent(wid),IG_InverseGC(wid)); valueMask = GCForeground | GCBackground | GCGraphicsExposures; values.graphics_exposures = FALSE; /* we need a font becasue the inverse gc is going to be used to render some text */ if (XmeRenderTableGetDefaultFont(IG_RenderTable(wid), &fs)) { values.font = fs->fid; valueMask |= GCFont; } /* the select color can take the special value XmREVERSED_GROUND_COLORS, which means use parent background as ink for text and parent foreground as back for the icon rendering */ values.background = IG_Foreground(wid) ; if (select_color != XmREVERSED_GROUND_COLORS) { values.foreground = select_color ; IG_InverseGC(wid) = NULL ; } else { /* we need a GC to hold the parent background as ink */ XtVaGetValues(XtParent(wid), XmNbackground, &(values.foreground), NULL); IG_InverseGC(wid) = XtAllocateGC(XtParent(wid), XtParent(wid)->core.depth, valueMask, &values, modifyMask, 0); /* get the foreground for the inversed selected background */ values.background = IG_Background(wid) ; XtVaGetValues(XtParent(wid), XmNforeground, &(values.foreground), NULL); } IG_SelectedGC(wid) = XtAllocateGC(XtParent(wid), XtParent(wid)->core.depth, valueMask, &values, modifyMask, 0); } /************************************************************************ * UpdateGCs ************************************************************************/ static void UpdateGCs( Widget wid) { XGCValues values; XtGCMask valueMask; XFontStruct *fs = (XFontStruct *)NULL; XmContainerDataRec container_data ; Pixel select_color; XtGCMask modifyMask = GCClipMask | GCClipXOrigin | GCClipYOrigin; if (IG_NormalGC(wid)) XtReleaseGC(XtParent(wid),IG_NormalGC(wid)); if (IG_InsensitiveGC(wid)) XtReleaseGC(XtParent(wid),IG_InsensitiveGC(wid)); if (IG_BackgroundGC(wid)) XtReleaseGC(XtParent(wid),IG_BackgroundGC(wid)); if (IG_TopShadowGC(wid)) XtReleaseGC(XtParent(wid),IG_TopShadowGC(wid)); if (IG_BottomShadowGC(wid)) XtReleaseGC(XtParent(wid),IG_BottomShadowGC(wid)); if (IG_HighlightGC(wid)) XtReleaseGC(XtParent(wid),IG_HighlightGC(wid)); /** normal gc **/ valueMask = GCForeground | GCBackground | GCGraphicsExposures; values.foreground = IG_Foreground(wid) ; values.background = IG_Background(wid) ; values.graphics_exposures = FALSE; if (XmeRenderTableGetDefaultFont(IG_RenderTable(wid), &fs)) { values.font = fs->fid; valueMask |= GCFont; } IG_NormalGC(wid) = XtAllocateGC(XtParent(wid), XtParent(wid)->core.depth, valueMask, &values, modifyMask, 0); /** background gc **/ values.foreground = IG_Background(wid) ; values.background = IG_Foreground(wid) ; if (PIXMAP_VALID(IG_BackgroundPixmap(wid))) { int depth ; XmeGetPixmapData(XtScreen(wid),IG_BackgroundPixmap(wid) , NULL, &depth, NULL, NULL, NULL, NULL, NULL, NULL); if (depth == 1) { valueMask |= GCFillStyle | GCStipple ; values.fill_style = FillOpaqueStippled; values.stipple = IG_BackgroundPixmap(wid); } else { valueMask |= GCFillStyle | GCTile ; values.fill_style = FillTiled; values.tile = IG_BackgroundPixmap(wid); } } IG_BackgroundGC(wid) = XtAllocateGC(XtParent(wid), XtParent(wid)->core.depth, valueMask, &values, modifyMask, 0); /** selected gcs **/ /* use a select color from the trait if possible, otherwise default to select background of the parent (or is it of the container logical parent ? not really important for the header case is not selectable... */ /* get the container information */ /* I need the selection mode for the highlight init value */ container_data.valueMask = ContSelectColor | ContSelectionMode; GetContainerData(wid, &container_data); if (container_data.valueMask & ContSelectColor) { select_color = container_data.select_color; } else { select_color = XmREVERSED_GROUND_COLORS ; } UpdateSelectGCs(wid, select_color) ; /** insensitive gc **/ values.foreground = IG_Foreground(wid) ; values.background = IG_Background(wid) ; valueMask |= GCFillStyle | GCStipple; values.fill_style = FillOpaqueStippled; values.stipple = _XmGetInsensitiveStippleBitmap(wid); IG_InsensitiveGC(wid) = XtAllocateGC(XtParent(wid), XtParent(wid)->core.depth, valueMask, &values, modifyMask, 0); /** highlight **/ valueMask = (GCForeground | GCBackground | GCLineWidth | GCLineStyle | GCDashList); modifyMask = (GCLineStyle | GCLineWidth | GCDashList | GCClipXOrigin | GCClipYOrigin | GCClipMask); values.foreground = IG_HighlightColor(wid); XtVaGetValues(XtParent(wid), XmNbackground, &(values.background), NULL); values.line_width = IG_HLThickness(wid); values.dashes = MAX(values.line_width, 8); values.line_style = (container_data.selection_mode == XmADD_MODE) ? LineDoubleDash : LineSolid; IG_HighlightGC(wid) = XtAllocateGC(XtParent(wid), XtParent(wid)->core.depth, valueMask, &values, modifyMask, 0); /** topshadow, bottomshadow gc */ IG_TopShadowGC(wid) = _XmGetPixmapBasedGC (wid, IG_TopShadowColor(wid), IG_Background(wid), IG_TopShadowPixmap(wid)); IG_BottomShadowGC(wid) = _XmGetPixmapBasedGC (wid, IG_BottomShadowColor(wid), IG_Background(wid), IG_BottomShadowPixmap(wid)); } /************************************************************************ * GetStringTableReOrdered. * lazy alloc/filling using realloc * --- Never free the returned array.--- ************************************************************************/ static XmStringTable GetStringTableReOrdered( XmStringTable st, Cardinal st_count, Cardinal * order, Cardinal order_count) { static XmString * Default_st = NULL ; static Cardinal Max_st_count = 0; Cardinal i, count ; if (!order_count || !st_count) return NULL ; /* here we are filling up a new string table out of an existing one and a new order table. Take only the minimum number of both */ count = MIN(order_count, st_count); if (count > Max_st_count) { Max_st_count = MAX(count, 33); Default_st = (XmStringTable) XtRealloc((char*) Default_st, Max_st_count * sizeof(XmString)); } for (i = 0; i < count; i++) { if (order) { if (order[i] <= st_count) Default_st[i] = st[order[i] - 1]; else Default_st[i] = NULL ; } else { Default_st[i] = st[i]; } } return Default_st ; /* This is realloced memory, be sure that no one is keeping reference to this stuff longer enough for it to be realloced again */ } /************************************************************************ * GetStringTableExtent * 1> If the XmTablist has exactly as many entries as XmNdetailOrderCount, the last entry is clipped, and consequently, all IconGadgets will ask for the same size. 2> If the XmTablist is greater than XmNdetailOrderCount, the extra tabs are ignored 3> if the XmTablist is XmNdetailOrderCount-1, then the last detail is not clipped, but extends as far as needed. The IconGadget geometry request will be for the full size. The Container will ask for the maximum width requested by all its IconGadgets. 4> If the XmTablist is less than XmNdetailOrderCount-1, then, concatenate the extra details at the end and request the additional width. ************************************************************************/ static void GetStringTableExtent( Screen * screen, XmStringTable st, Cardinal st_count, XmRenderTable render_table, XmTabList tab_list, Dimension hor_spacing, /* for the tab-less concat details */ Dimension * width_ret, Dimension * height_ret, Position * baseline_ret) { Cardinal i ; Dimension w, h, baseline ; unsigned int tab_count = 0 ; Dimension height_under_max = 0 ; *baseline_ret = 0 ; *width_ret = 0 ; *height_ret = 0 ; if (tab_list) tab_count = XmTabListTabCount(tab_list) ; if (st == NULL || !st_count) return ; /* the extra tabs are ignored */ tab_count = MIN(tab_count, st_count); /* the width is given by the last tab position + the remaining items */ if (tab_count) *width_ret = _XmTabListGetPosition(screen, tab_list, XmPIXELS, tab_count-1); /* the height is the sum of max baseline + max height under baseline */ for (i = 0; i < st_count; i++) { if (st[i]) { XmStringExtent(render_table, st[i], &w, &h); baseline = XmStringBaseline(render_table, st[i]); } else { h = 0 ; w = 0 ; baseline = 0 ; } height_under_max = MAX(height_under_max, h - baseline); *baseline_ret = MAX(*baseline_ret, (Position)baseline); if (i >= tab_count) *width_ret += w + hor_spacing; } *height_ret = *baseline_ret + height_under_max ; } /************************************************************************ * GetSize ************************************************************************/ static void GetSize( Widget wid, Dimension * ret_width, Dimension * ret_height) { XmContainerDataRec container_data ; Dimension ht = IG_HLThickness(wid); Dimension mw = IG_MarginWidth(wid), mh = IG_MarginHeight(wid); int ideal_width, ideal_height; Dimension detail_width, detail_height; XmStringTable new_detail ; Position label_y, lab_baseline, detail_baseline ; /* get the container information */ container_data.valueMask = ContAllValid ; GetContainerData(wid, &container_data); /**** first the size without the detail */ ideal_width = GetIconLabelWidth(wid) ; ideal_height = GetIconLabelHeight(wid) ; if (SHOW_DETAIL(wid, &container_data)) { /* get the detail table to be displayed */ new_detail = GetStringTableReOrdered(IG_Detail(wid), IG_DetailCount(wid), container_data.detail_order, container_data.detail_order_count); /* ask for its extent using the provided container tab list */ /* new_detail might be NULL at this point, extent should return 0 size if so. some new_detail[i] might also be NULL, in which case extent should go to the next tab. note that tab might also be NULL. */ GetStringTableExtent(XtScreen(wid), new_detail, MIN(container_data.detail_order_count, IG_DetailCount(wid)), IG_RenderTable(wid), container_data.detail_tablist, DEFAULT_HOR_SPACING, &detail_width, &detail_height, &detail_baseline); /* width in detail is sum of first_column_width (where the x has been removed already) + the detail width */ ideal_width = container_data.first_column_width + (int)detail_width + mw - ht; /* the baseline have to be taken into account in the calculation of the height needed */ GetLabelXY(wid, NULL, &label_y); lab_baseline = XmStringBaseline(IG_RenderTable(wid), IG_LabelString(wid)); ideal_height = MAX(ideal_height, label_y - ht + DEFAULT_LABEL_MARGIN_HEIGHT + lab_baseline - mh - detail_baseline + detail_height); } /* do not set non null dimensions */ if (*ret_width == 0) *ret_width = ideal_width + 2*ht; if (*ret_height == 0) *ret_height = ideal_height + 2*ht; } /*------------------- | Trait methods | -------------------*/ /************************************************************************ * ContItemSetValues * * Deal with a container setting new attributes on me ************************************************************************/ static void ContItemSetValues(Widget w, XmContainerItemData contItemData) { XtExposeProc expose; /* here there is a match between the containerItem and the IconGadget resource values, because we are doing both at the same time and it's convenient. Others IconGadget kind might have to map our viewType, visualEmphasis values onto their corresponding types */ if (contItemData->valueMask & ContItemViewType) XtVaSetValues(w, XmNviewType, contItemData->view_type, NULL); if (contItemData->valueMask & ContItemVisualEmphasis) { IG_VisualEmphasis(w) = contItemData->visual_emphasis ; if (XtIsRealized(XtParent(w))) { _XmProcessLock(); expose = w->core.widget_class->core_class.expose; _XmProcessUnlock(); (* (expose)) (w, NULL, NULL); } } } /************************************************************************ * ContItemGetValues * ************************************************************************/ static void ContItemGetValues(Widget w, XmContainerItemData contItemData) { if (contItemData->valueMask & ContItemViewType) contItemData->view_type = IG_ViewType(w); if (contItemData->valueMask & ContItemVisualEmphasis) contItemData->visual_emphasis = IG_VisualEmphasis(w); if (contItemData->valueMask & ContItemIconWidth) { contItemData->icon_width = 2*IG_HLThickness(w) + GetIconLabelWidth(w); } if (contItemData->valueMask & ContItemDetailCount) { contItemData->detail_count = IG_DetailCount(w); } } /*ARGSUSED*/ static Boolean HandleRedraw ( Widget kid, Widget cur_parent, /* unused */ Widget new_parent, /* unused */ Mask visual_flag) { XmIconGadget ig = (XmIconGadget) kid ; Boolean redraw = False; XmIconGCacheObjPart oldCopy; if (visual_flag & VisualSelectColor) { XmContainerDataRec container_data ; Pixel select_color; /* this is all shared data, so we need to make a copy because changing any field */ _XmProcessLock(); _XmCacheCopy((XtPointer) IG_Cache(ig), (XtPointer) &oldCopy, sizeof(XmIconGCacheObjPart)); _XmCacheDelete ((XtPointer) IG_Cache(ig)); _XmProcessUnlock(); IG_Cache(ig) = &oldCopy; /* use a select color from the trait if possible, otherwise default to select background of the parent (or is it of the container logical parent ? not really important for the header case is not selectable... */ /* get the container information */ /* I need the selection mode for the highlight init value */ container_data.valueMask = ContSelectColor ; GetContainerData(kid, &container_data); if (container_data.valueMask & ContSelectColor) { select_color = container_data.select_color; } else { select_color = XmREVERSED_GROUND_COLORS ; } UpdateSelectGCs(kid, select_color) ; redraw = True; /* now cache back the new version */ _XmProcessLock(); IG_Cache(ig) = (XmIconGCacheObjPart *) _XmCachePart( IG_ClassCachePart(ig), (XtPointer) IG_Cache(ig), sizeof(XmIconGCacheObjPart)); _XmProcessUnlock(); } return redraw ; } static void GetColors(Widget w, XmAccessColorData color_data) { XmContainerDataRec container_data ; /* since we use our own private converter, no real need to check for validity here, we already do it in the converter itself, but it doesn't hurt and if we ever change IconG to use a generic pixmap converter (solve the mask pixmap setting), it will work all by itself */ if (IG_Cache(w)) { /* mean it's valid */ color_data->valueMask = AccessForeground | AccessBackgroundPixel | AccessHighlightColor | AccessTopShadowColor | AccessBottomShadowColor | AccessSelectColor; color_data->background = IG_Background(w); color_data->foreground = IG_Foreground(w); color_data->highlight_color = IG_Foreground(w); color_data->top_shadow_color = IG_TopShadowColor(w); color_data->bottom_shadow_color = IG_BottomShadowColor(w); container_data.valueMask = ContSelectColor ; /*** get the Container select color using the trait */ { XmIconGadgetClass igc = (XmIconGadgetClass) XtClass(w); Widget container_id ; XmContainerTrait container_trait ; container_id = (igc->icong_class.get_container_parent) ? (*(igc->icong_class.get_container_parent))(w) : XtParent(w); container_trait = (XmContainerTrait) XmeTraitGet((XtPointer)XtClass(container_id), XmQTcontainer) ; /* remove message about uninitialized memory read */ container_data.first_column_width = 0; container_data.select_color = XmREVERSED_GROUND_COLORS; if (container_trait) container_trait->getValues(container_id, &container_data); } if (container_data.valueMask & ContSelectColor) { color_data->select_color = container_data.select_color; } else { color_data->select_color = XmREVERSED_GROUND_COLORS ; } } else { /* cannot access the color of the gadget, because the cache is not yet present. Return that value, so that the converter (probably the one calling it) can take the appropriate step */ color_data->valueMask = AccessColorInvalid ; } } static Boolean PointIn(Widget wid, Position x, Position y) { XmContainerDataRec container_data ; /* x, y in parent coordinates system */ /* first check that point is in bbox */ if (!(x >= wid->core.x && y >= wid->core.y && x < wid->core.x + wid->core.width && y < wid->core.y + wid->core.height)) return False; /* if we have detail then it's enough to answer yes */ container_data.valueMask = ContAllValid ; GetContainerData(wid, &container_data); if (SHOW_DETAIL(wid, &container_data)) return True; else { Position label_x, label_y; XPoint points[8]; Cardinal n; /* now check if it's not in empty space at the corners */ GetLabelXY(wid, &label_x, &label_y); /* undo the ltr layout for label_x, because getshapeinfo does it */ if (LayoutIsRtoLG(wid)) { label_x = XtWidth(wid) - IG_LabelRectWidth(wid) - label_x; } n = GetShapeInfo(wid, GetLargeIconX(wid), GetSmallIconY(wid), label_x, label_y, container_data.first_column_width, INVALID_DIMENSION, points); if (n == 2) { return (x >= points[0].x && x <= points[1].x && y >= points[0].y && y <= points[1].y); } else if (n == 8) { if (IG_ViewType(wid) == XmLARGE_ICON) { Cardinal p0, p2, p3, p5; if (!LayoutIsRtoLG(wid)) { p0 = 0; p2 = 2; p3 = 3; p5 = 5; } else { p0 = 5; p2 = 3; p3 = 2; p5 = 0; } return (y <= points[1].y && /* pixmap row */ x >= points[p2].x && x <= points[p3].x) || (y >= points[1].y && /* label row */ x >= points[p0].x && x <= points[p5].x); } else { /* SMALL_ICON */ return (((!LayoutIsRtoLG(wid) && x <= points[1].x) || (LayoutIsRtoLG(wid) && x >= points[1].x)) && /* pixmap column */ y >= points[0].y && y <= points[7].y) || (((!LayoutIsRtoLG(wid) && x >= points[1].x) || (LayoutIsRtoLG(wid) && x <= points[1].x)) && /* label row */ y >= points[2].y && y <= points[5].y); } } return True; /* actually we should never get there */ } } /*------------------- | _Xm functions | --------------------*/ void _XmIconGadgetIconPos(Widget wid, int *x, int *y) { XmIconGadget ig = (XmIconGadget)wid; Position icon_x; if (ig -> icong.viewtype == XmSMALL_ICON) { icon_x = GetSmallIconX(wid); if (LayoutIsRtoLG(wid)) icon_x = XtWidth(wid) - icon_x - IG_SmallIconRectWidth(wid); *x = icon_x; *y = GetSmallIconY(wid); } else { icon_x = GetLargeIconX(wid); if (LayoutIsRtoLG(wid)) icon_x = XtWidth(wid) - icon_x - IG_LargeIconRectWidth(wid); *x = icon_x; *y = GetLargeIconY(wid); } } /*------------------- | External functions | -------------------*/ /************************************************************************ * XmCreateIconGadget * ************************************************************************/ Widget XmCreateIconGadget( Widget parent, char *name, ArgList arglist, Cardinal argcount) { return(XtCreateWidget(name,xmIconGadgetClass,parent,arglist,argcount)); }