/*
* Motif
*
* Copyright (c) 1987-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*
*/
/************************************************************
* INCLUDE FILES
*************************************************************/
#include <Xm/XmP.h>
#include <Xm/DrawP.h>
#include <Xm/TraitP.h>
#include <Xm/ActivatableT.h>
#include <stdio.h>
#include <Xm/IconButtonP.h>
#include <X11/bitmaps/gray>
#include <Xm/ExtP.h>
#include "PrimitiveI.h"
#include "XmStrDefsI.h"
#include "xmlist.h"
#include "RepTypeI.h"
/************************************************************
* TYPEDEFS AND DEFINES
*************************************************************/
#define SUPERCLASS ((WidgetClass) &xmPrimitiveClassRec)
#define FILL_SPACE(iw) ((iw)->primitive.highlight_thickness + \
(iw)->primitive.shadow_thickness)
#define H_SPACE(iw) (FILL_SPACE(iw) + XmIconButton_h_space(iw))
#define V_SPACE(iw) (FILL_SPACE(iw) + XmIconButton_v_space(iw))
#define ALLOC_INCREMENT 5
#define DELAY 100
#define NO_TIMER 0
#define NEW_LINE ('\n')
#define EOL ('\0')
typedef struct _PixCacheEntry {
Display *display;
Pixmap pixmap;
long count; /*The tree widget uses the folder icon A LOT*/
Dimension width, height, depth;
} PixCacheEntry;
/************************************************************
* MACROS
*************************************************************/
#define streq(a, b) (((a) != NULL) && ((b) != NULL) && (strcmp((a), (b)) == 0))
#define ValidPixmap(p) ((p)!=None&&(p)!=XmUNSPECIFIED_PIXMAP)
/************************************************************
* GLOBAL DECLARATIONS
*************************************************************/
extern void _XmSelectColorDefault();
static XmList pix_cache_list = NULL;
/************************************************************
* STATIC FUNCTION DECLARATIONS
*************************************************************/
static void Resize(Widget), Destroy(Widget), ClassInit(void);
static void ClassPartInitialize(WidgetClass w_class);
static void Initialize(Widget, Widget, ArgList, Cardinal *);
static void Redisplay(Widget, XEvent *, Region);
static XtGeometryResult QueryGeometry(Widget,
XtWidgetGeometry *, XtWidgetGeometry *);
static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
static void SetValuesAlmost(Widget, Widget,
XtWidgetGeometry *, XtWidgetGeometry *);
static void GetValues_labelString ( Widget w, int n, XtArgVal *value) ;
static void ChangeCB(Widget w, XtCallbackProc activCB, XtPointer closure, Boolean setunset);
/************************
* Actions and callbacks.
************************/
static void ToggleState(Widget, XEvent *, String *, Cardinal *);
static void Notify(Widget, XEvent *, String *, Cardinal *);
static void DoubleNotify(Widget, XEvent *, String *, Cardinal *);
static void ArmAndActivate(Widget, XEvent *, String *, Cardinal *);
static void ButtonUp(Widget, XEvent *, String *, Cardinal *);
/*********************
* Internal Routines.
*********************/
static XmListElem * GetCacheElem(Display *, Pixmap);
static Boolean CheckPixCache(Display *, Pixmap,
unsigned int *, unsigned int *, unsigned int *);
static void AddPixCache(Display *, Pixmap,
unsigned int, unsigned int, unsigned int);
static void IncPixCache(Display *, Pixmap);
static void DecPixCache(Display *, Pixmap);
static void Deactivate(XtPointer, XtIntervalId *);
static void GetDesiredSize(Widget, Dimension *, Dimension *);
static void RequestNewSize(Widget, Dimension, Dimension);
static void CalcLocations(Widget), DrawTextAndImage(Widget, GC, GC, GC);
static void CreateGCs(Widget), DestroyGCs(Widget w);
static void FromPaddingPixels(Widget, int, XtArgVal *);
static XmImportOperator ToPaddingPixels(Widget, int, XtArgVal *);
static XmString CreateXmString(Widget, String);
static void CheckSetRenderTable(Widget wid, int offs, XrmValue *value);
/******************
* Type Converters
******************/
static Boolean CvtStringToIconPlacement(Display *, XrmValuePtr, Cardinal *,
XrmValuePtr, XrmValuePtr);
/************************************************************
* STATIC DECLARATIONS
*************************************************************/
/*
* It seems redundant to have both Btn1Up and BtnUp bound to
* EndDrag, but for some reason BtnUp does not cause the event to
* fire on button 1, must be some Translations magic that I don't
* understand.
*
* CDP - 5/11/91.
*/
typedef struct _StippleInfo {
struct _StippleInfo *next;
Pixmap stipple;
Display *disp;
Screen *screen;
} StippleInfo;
/*
* ||| It would be nice to put this in the widget class.
*/
static StippleInfo *stipple_cache; /* Only one of these for each app. */
static char defaultTranslations[] =
"<Btn1Down>,<Btn1Up>: XiToggle() XmNotify() XiButtonUp()\n\
<Btn1Down>: XiGetFocus() XiToggle() \n\
<Key>osfSelect: XiArmAndActivate()\n\
<Key>osfActivate: XiArmAndActivate()\n\
None<Key>space: XiArmAndActivate()\n\
None<Key>Return: XiArmAndActivate()\n\
<Btn1Down>,<Leave>: XiToggle()";
/*
* These are the primitive translations that we need, this list
* adds enter and leave to the primitive defaults.
*/
static char traverseTranslations[] =
"<Key>osfBeginLine: PrimitiveTraverseHome()\n\
<Key>osfHelp: PrimitiveHelp()\n\
<Key>osfUp: PrimitiveTraverseUp()\n\
<Key>osfDown: PrimitiveTraverseDown()\n\
<Key>osfLeft: PrimitiveTraverseLeft()\n\
<Key>osfRight: PrimitiveTraverseRight()\n\
Shift ~Meta ~Alt <Key>Tab: PrimitivePrevTabGroup()\n\
~Meta ~Alt <Key>Tab: PrimitiveNextTabGroup()\n\
<FocusIn>: PrimitiveFocusIn()\n\
<FocusOut>: PrimitiveFocusOut()\n\
<Enter>: PrimitiveEnter()\n\
<Leave>: PrimitiveLeave()\n\
<Unmap>: PrimitiveUnmap()";
static XtActionsRec actionsList[] =
{
{"XiArmAndActivate", ArmAndActivate},
{"XiToggle", ToggleState},
{"XmNotify", Notify},
{"XiGetFocus", _XmGetFocus},
{"XiDoubleNotify", DoubleNotify},
{"XiButtonUp", ButtonUp},
/*
* Why aren't these in primitive?
*/
{ "PrimitiveEnter", (XtActionProc) _XmPrimitiveEnter },
{ "PrimitiveLeave", (XtActionProc) _XmPrimitiveLeave },
};
static XtResource resources[] =
{
{
XmNlabel, XmCLabel, XmRString,
sizeof(String), XtOffsetOf(XmIconButtonRec, icon.label),
XmRImmediate, (XtPointer) NULL
},
{
XmNlabelString, XmCLabelString, XmRXmString,
sizeof(XmString), XtOffsetOf(XmIconButtonRec, icon.label_string),
XmRImmediate, (XtPointer) NULL
},
{
XmNpixmap, XmCPixmap, XmRPrimForegroundPixmap,
sizeof(Pixmap), XtOffsetOf(XmIconButtonRec, icon.pixmap),
XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP
},
{
"pri.vate", "Pri.vate", XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmIconButtonRec, icon.check_set_render_table),
XmRImmediate, (XtPointer) False
},
{
XmNfontList, XmCFontList, XmRFontList,
sizeof(XmFontList), XtOffsetOf(XmIconButtonRec, icon.font_list),
XmRCallProc, (XtPointer)CheckSetRenderTable
},
{
XmNrenderTable, XmCRenderTable, XmRRenderTable,
sizeof(XmRenderTable), XtOffsetOf(XmIconButtonRec, icon.font_list),
XmRCallProc, (XtPointer)CheckSetRenderTable
},
{
XmNalignment, XmCAlignment, XmRAlignment,
sizeof(unsigned char), XtOffsetOf(XmIconButtonRec, icon.alignment),
XmRImmediate,(XtPointer) XmALIGNMENT_BEGINNING
},
{
XmNstringDirection, XmCStringDirection, XmRStringDirection,
sizeof(unsigned char), XtOffsetOf(XmIconButtonRec, icon.string_direction),
XmRImmediate, (XtPointer) XmDEFAULT_DIRECTION
},
{
XmNiconPlacement, XmCIconPlacement, XmRXmIconPlacement,
sizeof(XmIconPlacement), XtOffsetOf(XmIconButtonRec, icon.icon_placement),
XmRImmediate, (XtPointer) XmIconTop
},
{
XmNrecomputeSize, XmCBoolean , XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmIconButtonRec, icon.recompute),
XmRImmediate, (XtPointer) True
},
{
XmNarmColor, XmCArmColor, XmRPixel,
sizeof(Pixel), XtOffsetOf(XmIconButtonRec, icon.arm_color),
XmRCallProc, (XtPointer) _XmSelectColorDefault
},
{
XmNset, XmCBoolean , XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmIconButtonRec, icon.set),
XmRImmediate, (XtPointer) False
},
{
XmNverticalMargin, XmCSpace, XmRVerticalDimension,
sizeof(Dimension), XtOffsetOf(XmIconButtonRec, icon.v_space),
XmRImmediate, (XtPointer) 2
},
{
XmNhorizontalMargin, XmCSpace, XmRHorizontalDimension,
sizeof(Dimension), XtOffsetOf(XmIconButtonRec, icon.h_space),
XmRImmediate, (XtPointer) 2
},
{
XmNiconTextPadding, XmCSpace, XmRVerticalDimension,
sizeof(Dimension), XtOffsetOf(XmIconButtonRec, icon.icon_text_padding),
XmRImmediate, (XtPointer) 2
},
{
XmNactivateCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), XtOffsetOf(XmIconButtonRec, icon.activate_callback),
XmRPointer, (XtPointer) NULL
},
{
XmNdoubleClickCallback, XmCCallback, XmRCallback,
sizeof(XtCallbackList), XtOffsetOf(XmIconButtonRec, icon.double_click_callback),
XmRPointer, (XtPointer) NULL
},
{
XmNpixmapWidth, XmCDimension, XmRDimension,
sizeof(Dimension), XtOffsetOf(XmIconButtonRec, icon.pix_width),
XmRImmediate, (XtPointer) 0
},
{
XmNpixmapHeight, XmCDimension, XmRDimension,
sizeof(Dimension), XtOffsetOf(XmIconButtonRec, icon.pix_height),
XmRImmediate, (XtPointer) 0
},
{
XmNpixmapDepth, XmCDimension, XmRDimension,
sizeof(Dimension), XtOffsetOf(XmIconButtonRec, icon.pix_depth),
XmRImmediate, (XtPointer) 0
}
};
static XmSyntheticResource get_resources[] =
{
{
XmNhorizontalMargin, sizeof(Dimension),
XtOffsetOf(XmIconButtonRec, icon.h_space),
XmeFromHorizontalPixels, (XmImportProc) XmeToHorizontalPixels
},
{
XmNverticalMargin, sizeof(Dimension),
XtOffsetOf(XmIconButtonRec, icon.v_space),
XmeFromVerticalPixels, (XmImportProc) XmeToVerticalPixels
},
{
XmNiconTextPadding, sizeof(Dimension),
XtOffsetOf(XmIconButtonRec, icon.icon_text_padding),
FromPaddingPixels, (XmImportProc) ToPaddingPixels
},
{
XmNlabelString, sizeof(XmString),
XtOffsetOf(XmIconButtonRec, icon.label_string),
GetValues_labelString, NULL
}
};
XmIconButtonClassRec xmIconButtonClassRec = {
{ /* core fields */
/* superclass */ SUPERCLASS,
/* class_name */ XM_ICON_BUTTON_CLASS_NAME,
/* widget_size */ sizeof(XmIconButtonRec),
/* class_initialize */ ClassInit,
/* class_part_initialize */ ClassPartInitialize,
/* class_inited */ FALSE,
/* initialize */ Initialize,
/* initialize_hook */ NULL,
/* realize */ XtInheritRealize,
/* actions */ actionsList,
/* num_actions */ XtNumber(actionsList),
/* resources */ (XtResourceList)resources,
/* num_resources */ XtNumber(resources),
/* xrm_class */ NULLQUARK,
/* compress_motion */ TRUE,
/* compress_exposure */ XtExposeCompressMultiple,
/* compress_enterleave */ TRUE,
/* visible_interest */ FALSE,
/* destroy */ Destroy,
/* resize */ Resize,
/* expose */ Redisplay,
/* set_values */ SetValues,
/* set_values_hook */ NULL,
/* set_values_almost */ SetValuesAlmost,
/* get_values_hook */ NULL,
/* accept_focus */ NULL,
/* version */ XtVersion,
/* callback_private */ NULL,
/* tm_table */ defaultTranslations,
/* query_geometry */ (XtGeometryHandler) QueryGeometry,
/* display_accelerator */ XtInheritDisplayAccelerator,
/* extension */ NULL
},
{ /* Xmprimitive fields */
(XtWidgetProc)_XtInherit, /* border_highlight */
(XtWidgetProc)_XtInherit, /* border_unhighlight */
traverseTranslations, /* translations */
NULL, /* arm_and_activate */
get_resources, /* syn resources */
XtNumber(get_resources), /* num syn_resources */
NULL /* extension */
},
{ /* Icon Button class fields */
NULL /* extension */
}
};
WidgetClass xmIconButtonWidgetClass = (WidgetClass)&xmIconButtonClassRec;
/* Trait record for iconButton */
static XmConst XmActivatableTraitRec iconButtonAT =
{
0, /* version */
ChangeCB /* changeCB */
};
/************************************************************
* STATIC CODE
*************************************************************/
/* Function Name: ClassInit
* Description: Called to initialize information specific
* to this widget class.
* Arguments: none.
* Returns: none.
*/
/*ARGSUSED*/
static void
ClassInit()
{
XmIconButtonClassRec *wc = &xmIconButtonClassRec;
XtSetTypeConverter(XmRString, XmRXmIconPlacement,
(XtTypeConverter) CvtStringToIconPlacement,
NULL, (Cardinal) 0, XtCacheAll, (XtDestructor) NULL);
}
/*
* ClassPartInitialize sets up the fast subclassing for the widget.
*/
static void
#ifdef _NO_PROTO
ClassPartInitialize(w_class)
WidgetClass w_class ;
#else
ClassPartInitialize(WidgetClass w_class)
#endif /* _NO_PROTO */
{
_XmFastSubclassInit (w_class, XmICONBUTTON_BIT );
/* Install the activatable trait for all subclasses */
XmeTraitSet((XtPointer)w_class, XmQTactivatable, (XtPointer) &iconButtonAT);
}
/* Function Name: Initialize
* Description: Called to initialize information specific
* to this widget.
* Arguments: req - what was originally requested.
* set - what will be created (our superclassed have
* already mucked with this)
* args, num_args - The arguments passed to
* the creation call.
* Returns: none.
*/
/*ARGSUSED*/
static void
Initialize(Widget req, Widget set, ArgList args, Cardinal * num_args)
{
XmIconButtonWidget iw = (XmIconButtonWidget) set;
Boolean resetPixmapValues = True;
XmIconButton_unset_timer(iw) = NO_TIMER;
XmIconButton_time(iw) = 0L;
/*
* If the label string is specified then it wins. If only the label
* is specified the it is converted into an XmString and stored
* in the label_string.
*/
XmIconButton_label_from_name(iw) = False;
if (XmIconButton_label_string(iw) == NULL) {
if (XmIconButton_label(iw) == NULL)
{
XmIconButton_label_string(iw) = CreateXmString(set, XtName(set));
XmIconButton_label_from_name(iw) = True;
}
else {
if ((XmIconButton_label_string(iw) =
CreateXmString(set, XmIconButton_label(iw))) == NULL)
{
XmIconButton_label_string(iw) = CreateXmString(set, XtName(set));
XmIconButton_label_from_name(iw) = True;
}
}
}
else {
XmIconButton_label_string(iw) =
XmStringCopy(XmIconButton_label_string(iw));
}
if (XmIconButton_label(iw))
XmIconButton_label(iw) = XtNewString(XmIconButton_label(iw));
if (ValidPixmap(XmIconButton_pixmap(iw)))
{
/* here's what we enforce: all must be non-zero */
if ( (0 != XmIconButton_pix_width(iw)) &&
(0 != XmIconButton_pix_height(iw)) &&
(0 != XmIconButton_pix_depth(iw)) )
resetPixmapValues = False;
}
if (resetPixmapValues)
{
XmIconButton_pix_width(iw) = 0;
XmIconButton_pix_height(iw) = 0;
XmIconButton_pix_depth(iw) = 0;
}
else
{
/* we have a validPixmap and valid values */
AddPixCache(XtDisplay(set), XmIconButton_pixmap(iw),
XmIconButton_pix_width(iw),
XmIconButton_pix_height(iw),
XmIconButton_pix_depth(iw));
IncPixCache(XtDisplay(set), XmIconButton_pixmap(iw));
}
/* If layout_direction is set, it overrides string_direction.
* If string_direction is set, but not layout_direction, use
* string_direction value.
* If neither is set, get from parent
*/
if (XmPrim_layout_direction(iw) != XmDEFAULT_DIRECTION) {
if (XmIconButton_string_direction(iw) == XmDEFAULT_DIRECTION)
XmIconButton_string_direction(iw) =
XmDirectionToStringDirection(XmPrim_layout_direction(iw));
} else if (XmIconButton_string_direction(iw) != XmDEFAULT_DIRECTION) {
XmPrim_layout_direction(iw) =
XmStringDirectionToDirection(XmIconButton_string_direction(iw));
} else {
XmPrim_layout_direction(iw) = _XmGetLayoutDirection(XtParent(set));
XmIconButton_string_direction(iw) =
XmDirectionToStringDirection(XmPrim_layout_direction(iw));
}
if (!XmRepTypeValidValue(XmRID_STRING_DIRECTION,
XmIconButton_string_direction(iw), (Widget) iw))
{
XmIconButton_string_direction(iw) = XmSTRING_DIRECTION_L_TO_R;
XmPrim_layout_direction(iw) =
XmStringDirectionToDirection(XmIconButton_string_direction(iw));
}
if (XmIconButton_font_list(iw) == NULL)
{
XmIconButton_font_list(iw) = XmeGetDefaultRenderTable((Widget) iw,
XmBUTTON_FONTLIST);
}
/* Make a local copy of the font list */
XmIconButton_font_list(iw) = XmFontListCopy( XmIconButton_font_list(iw));
if ((req->core.width == 0) || (req->core.height == 0)) {
Dimension width, height;
GetDesiredSize(set, &width, &height);
RequestNewSize(set, width, height);
}
CalcLocations(set);
CreateGCs(set);
}
/* Function Name: Resize
* Description: Called when this widget has been resized.
* Arguments: w - the widget to resize.
* Returns: none.
*/
static void
Resize(Widget w)
{
CalcLocations(w);
}
/* Function Name: Redisplay
* Description: This function redraws the contents of the widget.
* Arguments: w - the widget.
* event - event that caused the exposure.
* region - the region containing all the exposures.
* Returns: none
*/
/*ARGSUSED*/
static void
Redisplay(Widget w, XEvent * event, Region region)
{
XmIconButtonWidget iw = (XmIconButtonWidget) w;
int dx, dy, width, height;
GC topgc, bottomgc, text_gc, icon_gc, icon_stippled_gc;
dx = iw->primitive.highlight_thickness;
dy = dx;
width = iw->core.width - (2 * dx);
height = iw->core.height - (2 * dy);
if (XmIconButton_set(iw)) {
Dimension fill_width, fill_height;
if ((int)iw->core.width > (int)(2 * H_SPACE(iw)))
fill_width = iw->core.width - 2 * FILL_SPACE(iw);
else
fill_width = 0;
if ((int)iw->core.height > (int)(2 * V_SPACE(iw)))
fill_height = iw->core.height - 2 * FILL_SPACE(iw);
else
fill_height = 0;
if ((fill_width != 0) && (fill_height != 0))
XFillRectangle(XtDisplay(w), XtWindow(w), XmIconButton_fill_gc(iw),
FILL_SPACE(iw), FILL_SPACE(iw),
fill_width, fill_height);
icon_gc = XmIconButton_pixmap_fill_gc(iw);
icon_stippled_gc = XmIconButton_stippled_set_gc(iw);
topgc = iw->primitive.bottom_shadow_GC;
bottomgc = iw->primitive.top_shadow_GC;
}
else {
icon_gc = XmIconButton_gc(iw);
icon_stippled_gc = XmIconButton_stippled_unset_gc(iw);
topgc = iw->primitive.top_shadow_GC;
bottomgc = iw->primitive.bottom_shadow_GC;
}
if (XtIsSensitive(w)) {
if (XmIconButton_set(iw))
text_gc = XmIconButton_pixmap_fill_gc(iw);
else
text_gc = XmIconButton_gc(iw);
icon_stippled_gc = None;
}
else {
if (XmIconButton_set(iw))
text_gc = XmIconButton_stippled_set_text_gc(iw);
else
text_gc = XmIconButton_stippled_text_gc(iw);
}
DrawTextAndImage(w, text_gc, icon_gc, icon_stippled_gc);
XmeDrawShadows(XtDisplay(w), XtWindow(w), topgc, bottomgc,
dx, dy, width, height, iw->primitive.shadow_thickness,
XmSHADOW_OUT);
if (iw->primitive.highlighted)
_XmExtHighlightBorder(w);
else
_XmExtUnhighlightBorder(w);
}
/* Function Name: SetValuesAlmost
* Description: Handles the case of our geom request being denied.
* Arguments: old - the old state of the widget.
* set - the new state of the widget.
* request - the requested new geometry.
* reply - the compromise from our parent.
* Returns: none
*/
/* ARGSUSED */
static void
SetValuesAlmost(Widget old, Widget set,
XtWidgetGeometry * request, XtWidgetGeometry * reply)
{
if (request->request_mode != 0) /* XtGeometryAlmost, make new request */
*request = *reply;
CalcLocations(set);
}
/* Function Name: SetValues
* Description: Called when some widget data needs to be modified on-
* the-fly.
* Arguments: current - the current (old) widget values.
* request - before superclassed have changed things.
* set - what will acutally be the new values.
* args, num_args - the arguments in the list.
* Returns: none
*/
/*ARGSUSED*/
static Boolean
SetValues(Widget current, Widget request, Widget set,
ArgList args, Cardinal * num_args)
{
Boolean resetGCs, recalc, redisplay, reinit_l, reinit_ls;
XmIconButtonWidget old_iw = (XmIconButtonWidget) current;
XmIconButtonWidget set_iw = (XmIconButtonWidget) set;
register int i;
Boolean pixmapChanged = False;
Boolean pixmapGeoChanged = False;
Boolean resetPixmapValues = False;
reinit_l = reinit_ls = resetGCs = recalc = redisplay = False;
for (i = 0; i < *num_args; i++) {
String name = args[i].name;
if (streq(XmNlabel, name))
reinit_l = resetGCs = recalc = redisplay = TRUE;
if (streq(XmNlabelString, name))
reinit_ls = resetGCs = recalc = redisplay = TRUE;
if (streq(XmNpixmap, name))
{
DecPixCache(XtDisplay(current), XmIconButton_pixmap(old_iw));
recalc = redisplay = TRUE;
pixmapChanged = True;
}
if ( streq(XmNpixmapWidth, name) || streq(XmNpixmapHeight, name) || streq(XmNpixmapDepth, name) )
{
pixmapGeoChanged = True;
/* for now, we naively assume that the user knows that all of
** these resources should be changed at the same time
*/
}
if (streq(XmNset, name)) {
/*
* Remove the timer since programmer has changed value.
*/
if (XmIconButton_unset_timer(set_iw) != NO_TIMER) {
XtRemoveTimeOut(XmIconButton_unset_timer(set_iw));
XmIconButton_unset_timer(set_iw) = NO_TIMER;
}
}
}
/* ----------------------------------------------------------------- */
/* now make sense of the pixmap changes */
if (pixmapChanged && !pixmapGeoChanged)
{
/* for backward compatibility, reset values and fall through to
** GetDesiredSize
*/
resetPixmapValues = True;
}
else if (pixmapGeoChanged && !pixmapChanged)
{
/* we don't allow this case */
resetPixmapValues = True;
}
/* else if neither changed, then we don't worry about anything */
/* else if both changed, we use new values */
if (pixmapGeoChanged)
{
/* here's what we enforce: all must be non-zero */
if (!( (0 != XmIconButton_pix_width(set_iw)) &&
(0 != XmIconButton_pix_height(set_iw)) &&
(0 != XmIconButton_pix_depth(set_iw)) ))
resetPixmapValues = True;
}
/* for backward-compatibility, preserve old behavior in which pixmap
** can change without sizes changing when recomputeSize is not set, in
** which case we restore the values rather than use the new ones
*/
if (resetPixmapValues)
{
if (XmIconButton_recompute(set_iw))
{
XmIconButton_pix_width(set_iw) = 0;
XmIconButton_pix_height(set_iw) =
XmIconButton_pix_depth(set_iw) = 0;
}
else
{
XmIconButton_pix_width(set_iw) = XmIconButton_pix_width(old_iw);
XmIconButton_pix_height(set_iw) = XmIconButton_pix_height(old_iw);
XmIconButton_pix_depth(set_iw) = XmIconButton_pix_depth(old_iw);
}
}
/* ----------------------------------------------------------------- */
if ((old_iw->primitive.foreground != set_iw->primitive.foreground) ||
(old_iw->core.background_pixel != set_iw->core.background_pixel) ||
(XmIconButton_arm_color(old_iw) != XmIconButton_arm_color(set_iw)))
{
resetGCs = redisplay = True;
}
if( XtIsSensitive(current) != XtIsSensitive(set) )
{
redisplay = True;
}
if( XmIconButton_font_list(old_iw) != XmIconButton_font_list(set_iw) ) {
if( XmIconButton_font_list(old_iw) != NULL )
{
XmFontListFree (XmIconButton_font_list(old_iw));
}
if( XmIconButton_font_list(set_iw) == NULL )
{
XmIconButton_font_list(set_iw) = XmeGetDefaultRenderTable(set,
XmBUTTON_FONTLIST);
}
XmIconButton_font_list(set_iw) = XmFontListCopy(XmIconButton_font_list(set_iw));
recalc = redisplay = True;
}
if ((XmIconButton_icon_placement(old_iw) != XmIconButton_icon_placement(set_iw)) ||
(XmIconButton_v_space(old_iw) != XmIconButton_v_space(set_iw)) ||
(XmIconButton_h_space(old_iw) != XmIconButton_h_space(set_iw)) ||
(XmIconButton_icon_text_padding(old_iw) != XmIconButton_icon_text_padding(set_iw)))
{
recalc = redisplay = TRUE;
}
if ((XmIconButton_set(old_iw) != XmIconButton_set(set_iw)) ||
(XmIconButton_alignment(old_iw) != XmIconButton_alignment(set_iw)) ||
(XmIconButton_string_direction(old_iw) != XmIconButton_string_direction(set_iw)) ||
(XmPrim_layout_direction(old_iw) != XmPrim_layout_direction(set_iw)))
{
redisplay = TRUE;
}
if (XmIconButton_recompute(old_iw) != XmIconButton_recompute(set_iw)) {
if (XmIconButton_recompute(set_iw))
redisplay = recalc = TRUE;
}
if (reinit_l || reinit_ls)
{
/*
* The order here makes sure that label string overrides label
* when both are set. Fix up data first, then check what we
* should be displaying. If both have changed, deal only with
* the label string case.
*/
/* this has the desired behavior, except in this case: only
* XmNlabel is set at the beginning, then it migrates to
* XmNlabelString; then XmNlabel is reset to NULL. What value
* should be used?
*/
/* Boolean was_from_name; */
if (reinit_ls) {
XmStringFree(XmIconButton_label_string(old_iw));
if (XmIconButton_label_string(set_iw))
XmIconButton_label_string(set_iw) = XmStringCopy(XmIconButton_label_string(set_iw));
}
if (reinit_l) {
XtFree(XmIconButton_label(old_iw));
if (XmIconButton_label(set_iw))
XmIconButton_label(set_iw) = XtNewString(XmIconButton_label(set_iw));
}
/* was_from_name = XmIconButton_label_from_name(set_iw); */
XmIconButton_label_from_name(set_iw) = False;
if (reinit_ls) {
if (XmIconButton_label_string(set_iw) == NULL) {
if (XmIconButton_label(set_iw) == NULL)
{
XmIconButton_label_string(set_iw) = CreateXmString(set, XtName(set));
XmIconButton_label_from_name(set_iw) = True;
}
else
{
if ((XmIconButton_label_string(set_iw) =
CreateXmString(set, XmIconButton_label(set_iw))) == NULL)
{
XmIconButton_label_string(set_iw) =
CreateXmString(set, XtName(set));
XmIconButton_label_from_name(set_iw) = True;
}
}
}
}
else
if (reinit_l) {
/* spec says, if labelString is set it is used, which
* isn't enough to really work with; I think it really
* means that if both are set, XmNlabelString is used,
* which is a much different thing
*/
/* now I'm confused as to why this was ever necessary */
/* if (was_from_name) */
{
XmStringFree(XmIconButton_label_string(set_iw));
if (XmIconButton_label(set_iw) == NULL)
{
XmIconButton_label_string(set_iw) = CreateXmString(set, XtName(set));
XmIconButton_label_from_name(set_iw) = True;
}
else
{
if ((XmIconButton_label_string(set_iw) =
CreateXmString(set, XmIconButton_label(set_iw))) == NULL)
{
XmIconButton_label_string(set_iw) =
CreateXmString(set, XtName(set));
XmIconButton_label_from_name(set_iw) = True;
}
}
}
}
}
if (recalc) {
if (XmIconButton_recompute(set_iw)) {
Dimension width, height;
GetDesiredSize(set, &width, &height);
/*
* SetValues will ask for a new size.
*/
set->core.height = height;
set->core.width = width;
}
CalcLocations(set);
}
if (resetGCs) {
DestroyGCs(current);
CreateGCs(set);
}
return(redisplay);
}
/* Function Name: Destroy
* Description: Cleans up after the widget.
* Arguments: w - the widget.
* Returns: none.
*/
/*ARGSUSED*/
static void
Destroy(Widget w)
{
XmIconButtonWidget iw = (XmIconButtonWidget) w;
XtFree(XmIconButton_label(iw));
XmStringFree(XmIconButton_label_string(iw));
if (XmIconButton_font_list(iw) != NULL) XmFontListFree (XmIconButton_font_list(iw));
DestroyGCs(w);
if (XmIconButton_unset_timer(w) != NO_TIMER) {
XtRemoveTimeOut(XmIconButton_unset_timer(w));
XmIconButton_unset_timer(w) = NO_TIMER;
}
}
/* Function Name: QueryGeometry
* Description: Called when my parent wants to know what size
* I would like to be.
* Arguments: w - the widget to check.
* indended - constriants imposed by the parent.
* preferred - what I would like.
* Returns: See Xt Manual.
*/
static XtGeometryResult
QueryGeometry(Widget w,XtWidgetGeometry *intended, XtWidgetGeometry *preferred)
{
XmIconButtonWidget iw = (XmIconButtonWidget) w;
if (XmIconButton_recompute(iw))
GetDesiredSize(w, &(preferred->width), &(preferred->height));
else {
preferred->width = w->core.width;
preferred->height = w->core.height;
}
return(_XmHWQuery(w, intended, preferred));
}
/************************************************************
*
* Type Converters.
*
************************************************************/
/* Function Name: CvtStringToIconPlacement
* Description: Converts a string to an Icon Placement
* Arguments: dpy - the X Display.
* args, num_args - *** NOT USED ***
* fromVal - contains the string to convert.
* toVal - contains the converted node state.
* Returns: True if the SetValues succeeds.
*/
/*ARGSUSED*/
static Boolean
CvtStringToIconPlacement(Display * dpy, XrmValuePtr args, Cardinal *num_args,
XrmValuePtr fromVal, XrmValuePtr toVal)
{
static XmIconPlacement type;
static XrmQuark XtQETop;
static XrmQuark XtQELeft;
static XrmQuark XtQERight;
static XrmQuark XtQEBottom;
static XrmQuark XtQEIconOnly;
static XrmQuark XtQEIconNone;
static Boolean haveQuarks = FALSE;
XrmQuark q;
char lowerName[BUFSIZ];
if (!haveQuarks) {
XtQETop = XrmStringToQuark("top");
XtQELeft = XrmStringToQuark("left");
XtQERight = XrmStringToQuark("right");
XtQEBottom = XrmStringToQuark("bottom");
XtQEIconOnly = XrmStringToQuark("icononly");
XtQEIconNone = XrmStringToQuark("none");
haveQuarks = TRUE;
}
XmCopyISOLatin1Lowered(lowerName, (char *) fromVal->addr);
q = XrmStringToQuark(lowerName);
if ( (q == XtQETop) || streq(lowerName, "icontop") )
type = XmIconTop;
else if ( (q == XtQELeft) || streq(lowerName, "iconleft") )
type = XmIconLeft;
else if ( (q == XtQERight) || streq(lowerName, "iconright") )
type = XmIconRight;
else if ( (q == XtQEBottom) || streq(lowerName, "iconbottom") )
type = XmIconBottom;
else if (q == XtQEIconOnly)
type = XmIconOnly;
else if ( (q == XtQEIconNone) || streq(lowerName, "iconnone") )
type = XmIconNone;
else {
XtDisplayStringConversionWarning(dpy,
fromVal->addr, XmRXmIconPlacement);
return(FALSE); /* Conversion failed. */
}
if (toVal->addr == NULL) {
toVal->size = sizeof(XmIconPlacement);
toVal->addr = (XtPointer) &type;
return(TRUE);
}
if (toVal->size >= sizeof(XmIconPlacement)) {
XmIconPlacement *loc = (XmIconPlacement *)toVal->addr;
*loc = type;
return(TRUE);
}
toVal->size = sizeof(XmIconPlacement);
return(FALSE);
}
/************************************************************
*
* Actions and Callbacks.
*
************************************************************/
/* Function Name: ToggleState
* Description: Toggles the state of the icon button.
* Arguments: w - the icon button widget.
* event - the event that caused this action.
* params, num_params - action routine parameters.
* Returns: none.
*/
/*ARGSUSED*/
static void
ToggleState(Widget w, XEvent * event, String * params, Cardinal * num_params)
{
XmIconButtonWidget iw = (XmIconButtonWidget) w;
Arg args[1];
XtSetArg(args[0], XmNset, !(XmIconButton_set(iw)));
XtSetValues(w, args, (Cardinal) 1);
}
/* Function Name: DoubleNotify
* Description: Calls all functions on the icon button's
* doubleClickCallback list
* Arguments: w - the icon button widget.
* event - the event that caused this action.
* params, num_params - action routine parameters.
* Returns: none.
*/
/*ARGSUSED*/
static void
DoubleNotify(Widget w, XEvent * event, String * params, Cardinal * num_params)
{
XmIconButtonWidget iw = (XmIconButtonWidget) w;
XmIconButtonCallbackInfo info;
info.state = XmIconButton_set(iw);
info.event = event;
XtCallCallbackList(w, XmIconButton_double_click_callback(iw), &info);
}
/* Function Name: Notify
* Description: Calls all functions on the icon button's
* activateCallback list
* Arguments: w - the icon button widget.
* event - the event that caused this action.
* params, num_params - action routine parameters.
* Returns: none.
*/
/*ARGSUSED*/
static void
Notify(Widget w, XEvent * event, String * params, Cardinal * num_params)
{
XmIconButtonWidget iw = (XmIconButtonWidget) w;
XmIconButtonCallbackInfo info;
Boolean dclick;
if ((event->type == ButtonPress) || (event->type == ButtonRelease))
dclick = ((event->xbutton.time - XmIconButton_time(iw)) <=
XtGetMultiClickTime(XtDisplay(w)));
else
dclick = False;
info.state = XmIconButton_set(iw);
info.event = event;
if (dclick)
XtCallCallbackList(w, XmIconButton_double_click_callback(iw), &info);
else
XtCallCallbackList(w, XmIconButton_activate_callback(iw), &info);
}
/* Function Name: ArmAndActivate
* Description: Arms the button, notifies it of the action, then
* disarms the button after a small delay.
* Arguments: w - the icon button widget.
* event - the event that caused this action.
* params, num_params - action routine parameters.
* Returns: none.
*/
/*ARGSUSED*/
static void
ArmAndActivate(Widget w,
XEvent * event, String * params, Cardinal * num_params)
{
XmIconButtonWidget iw = (XmIconButtonWidget) w;
Arg args[1];
if (!XmIconButton_set(iw)) {
XtSetArg(args[0], XmNset, True);
XtSetValues(w, args, (Cardinal) 1);
}
XmIconButton_unset_timer(iw) = XtAppAddTimeOut(XtWidgetToApplicationContext(w),
(unsigned long) DELAY,
Deactivate, (XtPointer) w);
Notify(w, event, params, num_params);
}
/* Function Name: Deactivate
* Description: Called when the icon button should be deactivated.
* Arguments: data - the client data.
* timer - the timer that fired.
* Returns: none.
*/
/* ARGSUSED */
static void
Deactivate(XtPointer data, XtIntervalId *timer)
{
Arg args[1];
Widget w = (Widget) data;
XmIconButtonWidget iw = (XmIconButtonWidget) w;
XtSetArg(args[0], XmNset, False);
XtSetValues(w, args, (Cardinal) 1);
XmIconButton_unset_timer(iw) = NO_TIMER;
}
/* Function Name: ButtonUp
* Description: Saves the timestamp of the ButtonUp event
* for later double click processing
* Arguments: w - the icon button widget.
* event - the event that caused this action.
* params, num_params - action routine parameters.
* Returns: none.
*/
/*ARGSUSED*/
static void
ButtonUp(Widget w,
XEvent * event, String * params, Cardinal * num_params)
{
XmIconButtonWidget iw = (XmIconButtonWidget) w;
XmIconButton_time(iw) = event->xbutton.time;
}
/************************************************************
*
* Internal routines.
*
************************************************************/
/* Function Name: GetCacheElem
* Description: Gets an element in the cache.
* Arguments: disp, pixmap - The keys into the cache.
* Returns: elem - The list elem for this element.
*/
static XmListElem *
GetCacheElem(Display *disp, Pixmap pix)
{
register XmListElem *elem;
if (pix_cache_list == NULL)
return(NULL);
for (elem = XmListFirst(pix_cache_list); elem != NULL;
elem = XmListElemNext(elem))
{
PixCacheEntry * entry = (PixCacheEntry *) XmListElemData(elem);
if ((entry->display == disp) && (entry->pixmap == pix))
{
return(elem);
}
}
return(NULL);
}
/* Function Name: CheckPixCache
* Description: Checks the cache to see if this pixmap is in it.
* Arguments: disp, pixmap - The keys into the cache.
* width, height and depth - data about the pixmap.
* Returns: True if a match found.
*/
static Boolean
CheckPixCache(Display *disp, Pixmap pixmap,
unsigned int *width, unsigned int *height, unsigned int *depth)
{
XmListElem * elem = GetCacheElem(disp, pixmap);
PixCacheEntry * entry;
if (elem == NULL)
return(False);
entry = (PixCacheEntry *) XmListElemData(elem);
*width = entry->width;
*height = entry->height;
*depth = entry->depth;
return(True);
}
/* Function Name: AddPixCache
* Description: Adds or updates data in the pixmap cache.
* Arguments: disp, pixmap - The keys into the cache.
* width, height and depth - data about the pixmap.
* Returns: True if a match found.
*/
static void
AddPixCache(Display *disp, Pixmap pixmap,
unsigned int width, unsigned int height, unsigned int depth)
{
XmListElem * elem = GetCacheElem(disp, pixmap);
PixCacheEntry * entry;
if (elem == NULL)
{
entry = (PixCacheEntry *) XtCalloc(sizeof(PixCacheEntry), 1);
entry->display = disp;
entry->pixmap = pixmap;
if (pix_cache_list == NULL)
pix_cache_list = _XmListInit();
_XmListAddBefore(pix_cache_list, NULL, (XtPointer) entry);
}
else
entry = (PixCacheEntry *) XmListElemData(elem);
entry->width = width;
entry->height = height;
entry->depth = depth;
}
/* Function Name: IncPixCache
* Description: Increments the count in the pixmap cache.
* Arguments: disp - The current display.
* pix - The pixmap to increment.
* Returns: none.
*/
static void
IncPixCache(Display *disp, Pixmap pix)
{
XmListElem * elem = GetCacheElem(disp, pix);
if (elem != NULL)
(((PixCacheEntry *) XmListElemData(elem))->count)++;
}
/* Function Name: DecPixCache
* Description: Decrements the count in the pixmap cache.
* Arguments: disp - The current display.
* pix - The pixmap to increment.
* Returns: none.
*/
static void
DecPixCache(Display *disp, Pixmap pix)
{
XmListElem * elem = GetCacheElem(disp, pix);
PixCacheEntry * entry;
if (elem == NULL)
return;
entry = (PixCacheEntry *) XmListElemData(elem);
if (entry->count > 0)
(entry->count)--;
if (entry->count == 0) {
_XmListRemove(pix_cache_list, elem);
XtFree((char *) entry);
}
}
/* ARGSUSED */
static void GetValues_labelString ( Widget w, int n, XtArgVal *value)
{
(*value) = (XtArgVal) XmStringCopy(XmIconButton_label_string(w));
}
/* Function Name: FromPaddingPixels
* Description: Converts from pixels to current unit type
* does either horiz or vert depending on icon placement.
* Arguments: widget - the icon button widget.
* offset, value - passed to correct function based
* on orientation.
* Returns: none
*/
static void
FromPaddingPixels(Widget widget, int offset, XtArgVal *value)
{
XmIconButtonWidget iw = (XmIconButtonWidget) widget;
switch(XmIconButton_icon_placement(iw)) {
case XmIconTop:
case XmIconBottom:
XmeFromVerticalPixels(widget, offset, value);
break;
default: /* everything else is horiz. */
XmeFromHorizontalPixels(widget, offset, value);
break;
}
}
/* Function Name: ToPaddingPixels
* Description: Converts to pixels from current unit type
* does either horiz or vert depending on icon placement.
* Arguments: widget - the icon button widget.
* offset, value - passed to correct function based
* on orientation.
* Returns: the import order from _XmTo{Horizontal, Vertical}Pixels.
*/
static XmImportOperator
ToPaddingPixels(Widget widget, int offset, XtArgVal *value)
{
XmIconButtonWidget iw = (XmIconButtonWidget) widget;
switch(XmIconButton_icon_placement(iw)) {
case XmIconTop:
case XmIconBottom:
return(XmeToVerticalPixels(widget, offset, value));
default:
return(XmeToHorizontalPixels(widget, offset, value));
}
}
/* Function Name: GetDesiredSize
* Description: Gets the size that this widget would like to be.
* Arguments: w - the icon widget.
* RETURNED width, height - the desired size.
* Returns: none.
*/
static void
GetDesiredSize(Widget w, Dimension * width, Dimension * height)
{
XmIconButtonWidget iw = (XmIconButtonWidget) w;
Dimension total_width, total_height;
XmStringExtent(XmIconButton_font_list(iw), XmIconButton_label_string(iw),
&total_width, &total_height);
if( (XmIconButton_icon_placement(iw) != XmIconNone) && ValidPixmap(XmIconButton_pixmap(iw)) )
{
Window root;
int x, y;
unsigned int local_width, local_height, bw, depth;
/*
* If we have an icon of unknown size then ask the server,
* be sure to not make a round trip if not needed.
*/
if ((XmIconButton_pix_width(iw) == 0) || (XmIconButton_pix_height(iw) == 0) ||
(XmIconButton_pix_depth(iw) == 0))
{
if (!CheckPixCache(XtDisplay(w), XmIconButton_pixmap(iw),
&local_width, &local_height, &depth))
{
XGetGeometry(XtDisplay(w), XmIconButton_pixmap(iw), &root, &x, &y,
&local_width, &local_height, &bw, &depth);
AddPixCache(XtDisplay(w), XmIconButton_pixmap(iw),
local_width, local_height, depth);
}
IncPixCache(XtDisplay(w), XmIconButton_pixmap(iw));
XmIconButton_pix_width(iw) = local_width;
XmIconButton_pix_height(iw) = local_height;
XmIconButton_pix_depth(iw) = depth;
}
else {
local_width = XmIconButton_pix_width(iw);
local_height = XmIconButton_pix_height(iw);
depth = XmIconButton_pix_depth(iw);
}
switch (XmIconButton_icon_placement(iw)) {
case XmIconTop:
case XmIconBottom:
total_height += local_height + XmIconButton_icon_text_padding(iw);
if ( local_width > total_width )
total_width = local_width;
break;
case XmIconOnly:
total_height = local_height;
total_width = local_width;
break;
case XmIconLeft:
case XmIconRight:
total_width += local_width + XmIconButton_icon_text_padding(iw);
if (local_height > total_height)
total_height = local_height;
break;
default:
break;
}
}
else {
XmIconButton_pix_width(iw) = XmIconButton_pix_height(iw) = 0;
XmIconButton_pix_depth(iw) = 0;
}
*height = total_height + 2 * V_SPACE(iw);
*width = total_width + 2 * H_SPACE(iw);
}
/* Function Name: RequestNewSize
* Description: Asks our parent for a new size.
* Arguments: w - the Icon Button widget.
* width, height - the width and height we want to be.
* Returns: none.
*/
static void
RequestNewSize(Widget w, Dimension width, Dimension height)
{
Dimension w_ret, h_ret;
XtGeometryResult ret_val;
ret_val = XtMakeResizeRequest(w, width, height, &w_ret, &h_ret);
if (ret_val == XtGeometryAlmost)
(void) XtMakeResizeRequest(w, w_ret, h_ret, NULL, NULL);
Resize(w); /* May not have been called. */
}
/* Function Name: CalcLocations
* Description: Calculates where the icon and strings should be
* painted.
* Arguments: w - the icon button widget.
* Returns: none.
*/
static void
CalcLocations(Widget w)
{
XmIconButtonWidget iw = (XmIconButtonWidget) w;
Dimension width, height, d_width, d_height;
Dimension extra_y_space;
Boolean have_pixmap = True;
width = w->core.width;
height = w->core.height;
GetDesiredSize(w, &d_width, &d_height);
if (height > d_height)
extra_y_space = (int)(height - d_height)/2;
else
extra_y_space = 0;
XmIconButton_max_text_width(iw) = width - 2 * H_SPACE(iw);
XmIconButton_max_text_height(iw) = height - 2 * V_SPACE(iw);
XmIconButton_text_x(iw) = H_SPACE(iw);
XmIconButton_text_y(iw) = V_SPACE(iw);
if( XmIconButton_icon_placement(iw) != XmIconNone && ValidPixmap(XmIconButton_pixmap(iw)) )
{
/*
* Here we actually have a pixmap so lets figure out the
* location of the pixmap. First we will loook at the
* horizontal position.
*/
switch (XmIconButton_icon_placement(iw)) {
case XmIconLeft: /* Flush Left */
XmIconButton_pix_x(iw) = (Position) H_SPACE(iw);
break;
case XmIconRight: /* Flush Right */
XmIconButton_pix_x(iw) = (Position) (width - H_SPACE(iw) -
XmIconButton_pix_width(iw));
break;
default: /* Centered */
XmIconButton_pix_x(iw) = ((Position) width -
(Position) XmIconButton_pix_width(iw))/2;
break;
}
/*
* Now lets deside on the the vertical position
*/
switch (XmIconButton_icon_placement(iw)) {
case XmIconTop: /* Centered At the top */
XmIconButton_pix_y(iw) = V_SPACE(iw) + extra_y_space;
break;
case XmIconBottom: /* Centered at the bottom */
XmIconButton_pix_y(iw) = ((Position) height -
((Position) V_SPACE(iw) +
(Position) extra_y_space +
(Position) XmIconButton_pix_height(iw)));
break;
default: /* Centered */
XmIconButton_pix_y(iw) = ((Position) height -
(Position) XmIconButton_pix_height(iw))/2;
break;
}
}
else
{
/*
* If we get here that means that we do not have a pixmap
* to play with so lets just zero the x and y locations of the
* pixmap.
*/
XmIconButton_pix_x(iw) = XmIconButton_pix_y(iw) = 0;
have_pixmap = False;
}
/*
* Now that we know the location of the pixmap, lets go and try to
* find out what we want to do with the XmString if there is one.
*/
if( XmIconButton_icon_placement(iw) != XmIconOnly ) {
Dimension text_width, text_height;
int tmp;
/*
* First let find out what the size of the string we have is
*/
XmStringExtent(XmIconButton_font_list(iw), XmIconButton_label_string(iw),
&text_width, &text_height);
XmIconButton_max_text_height(iw) = text_height;
switch (XmIconButton_icon_placement(iw)) {
case XmIconLeft: /* Aligned to Right of Icon. */
/*
* If the pixmap is to our left then we can use all the
* space to the right of the pixmap.
*/
if( have_pixmap )
{
XmIconButton_text_x(iw) = XmIconButton_pix_x(iw) + XmIconButton_pix_width(iw) +
XmIconButton_icon_text_padding(iw);
if( (tmp = (int)width - (int)H_SPACE(iw) -
(int)XmIconButton_text_x(iw)) < 0 )
{
tmp = 0;
}
XmIconButton_max_text_width(iw) = tmp;
}
break;
case XmIconRight: /* Aligned to left of Icon. */
if( have_pixmap )
{
XmIconButton_text_x(iw) = H_SPACE(iw);
if( (tmp = XmIconButton_pix_x(iw) - XmIconButton_text_x(iw)) < 0 ) tmp = 0;
XmIconButton_max_text_width(iw) = tmp;
}
break;
default:
break;
}
switch (XmIconButton_icon_placement(iw)) {
case XmIconTop: /* Along Bottom. */
XmIconButton_text_y(iw) = height - (V_SPACE(iw) + (Position)text_height);
if( have_pixmap )
{
tmp = XmIconButton_pix_y(iw) + XmIconButton_pix_height(iw) +
XmIconButton_icon_text_padding(iw);
if( XmIconButton_text_y(iw) < tmp )
{
XmIconButton_text_y(iw) = tmp;
if( (tmp = height - V_SPACE(iw) - XmIconButton_text_y(iw)) < 0 )
tmp = 0;
XmIconButton_max_text_height(iw) = tmp;
}
}
break;
case XmIconBottom: /* Along Top. */
XmIconButton_text_y(iw) = V_SPACE(iw);
if( have_pixmap )
{
tmp = XmIconButton_pix_y(iw) - XmIconButton_icon_text_padding(iw) -
XmIconButton_text_y(iw);
if( tmp < 0 ) tmp = 0;
XmIconButton_max_text_height(iw) = tmp;
}
break;
default:
/* Centered. */
XmIconButton_text_y(iw) = ((Position) height - (Position) text_height)/2;
break;
}
}
/*
* Else
*
* Text_x and Text_y are garbage, but never used.
*/
}
/* Function Name: DrawTextAndImage
* Description: Renders the Text and the image.
* Arguments: w - the icon button widget.
* text_gc - gc to use when drawing the text.
* icon_gc - gc to use when drawing the icon.
* icon_stippled_gc - gc to use to fake a stipple
* on the image.
* Returns: none.
*/
static void
DrawTextAndImage(Widget w, GC text_gc, GC icon_gc, GC icon_stippled_gc)
{
XmIconButtonWidget iw = (XmIconButtonWidget) w;
if( XmIconButton_icon_placement(iw) != XmIconNone && ValidPixmap(XmIconButton_pixmap(iw)) )
{
if (XmIconButton_pix_depth(iw) == 1)
{
XCopyPlane(XtDisplay(w), XmIconButton_pixmap(iw), XtWindow(w), icon_gc,
0, 0, XmIconButton_pix_width(iw), XmIconButton_pix_height(iw),
XmIconButton_pix_x(iw), XmIconButton_pix_y(iw), 1L);
}
else
{
XCopyArea(XtDisplay(w), XmIconButton_pixmap(iw), XtWindow(w), icon_gc,
0, 0, XmIconButton_pix_width(iw), XmIconButton_pix_height(iw),
XmIconButton_pix_x(iw), XmIconButton_pix_y(iw));
}
/*
* Stipple the background color over the top of the image
* since XCopyPlace and Area do not use the tile or stipple.
*/
if( icon_stippled_gc != None )
{
XFillRectangle(XtDisplay(w), XtWindow(w), icon_stippled_gc,
XmIconButton_pix_x(iw), XmIconButton_pix_y(iw),
XmIconButton_pix_width(iw), XmIconButton_pix_height(iw));
}
}
if( XmIconButton_icon_placement(iw) != XmIconOnly )
{
int size, tmp;
XRectangle clip;
clip.x = XmIconButton_text_x(iw);
clip.y = XmIconButton_text_y(iw);
clip.width = XmIconButton_max_text_width(iw);
clip.height = XmIconButton_max_text_height(iw);
if( (int)clip.x < (int)H_SPACE(iw) ) clip.x = H_SPACE(iw);
if( (int)clip.y < (int)V_SPACE(iw) ) clip.y = V_SPACE(iw);
size = XtWidth(iw) - H_SPACE(iw);
if( (int) (clip.x + clip.width) > size )
{
tmp = size - (int)clip.x;
if( tmp < 0 ) tmp = 0;
clip.width = tmp;
}
size = XtHeight(iw) - V_SPACE(iw);
if( (int)(clip.y + clip.height) > size )
{
tmp = size - (int)clip.y;
if( tmp < 0 ) tmp = 0;
clip.height = tmp;
}
if( clip.width != 0 && clip.height != 0 )
{
/*
* Set the clip rectangle so things do not
* overlap or go out of bounds.
*/
XSetClipRectangles(XtDisplay(w), text_gc,
0, 0, &clip, 1, Unsorted);
#ifdef FIX_1381
/*Draw shadow for insensitive text*/
if (!XtIsSensitive(w)) {
XmStringDraw(XtDisplay(w), XtWindow(w), XmIconButton_font_list(iw),
XmIconButton_label_string(iw), XmIconButton_shadow_gc(iw),
XmIconButton_text_x(iw)+1, XmIconButton_text_y(iw)+1,
XmIconButton_max_text_width(iw), XmIconButton_alignment(iw),
XmPrim_layout_direction(iw), NULL);
}
#endif
XmStringDraw(XtDisplay(w), XtWindow(w), XmIconButton_font_list(iw),
XmIconButton_label_string(iw), text_gc,
XmIconButton_text_x(iw), XmIconButton_text_y(iw),
XmIconButton_max_text_width(iw), XmIconButton_alignment(iw),
XmPrim_layout_direction(iw), NULL);
XSetClipMask(XtDisplay(w), text_gc, None);
}
}
}
/*
* There is almost always only 1 display, and certainly only a few, therefore
* there is no need to be clever here, just make sure it works for one
* fast, and doesn't break when using many.
*
* Would be nice to refocunt and remove...
*/
static Pixmap
GetGreyStipple(Widget w)
{
StippleInfo *set, *ptr;
for (ptr = stipple_cache; ptr != NULL; ptr = ptr->next) {
/* Check for both screen and display, such that it displays */
/* correctly on multi-headed X-servers. */
/* Change Request #: CR03619 */
if (ptr->disp == XtDisplay(w) && ptr->screen == XtScreen(w)) {
return (ptr->stipple);
}
}
set = (StippleInfo *) XtMalloc(sizeof(StippleInfo));
set->stipple = XCreateBitmapFromData(XtDisplay(w),
RootWindowOfScreen(XtScreen(w)),
gray_bits, gray_width, gray_height);
set->disp = XtDisplay(w);
set->screen = XtScreen(w);
set->next = NULL;
if (stipple_cache == NULL)
stipple_cache = set;
else
for (ptr = stipple_cache; ptr != NULL; ptr = ptr->next)
if (ptr->next == NULL) {
ptr->next = set;
break;
}
return(set->stipple);
}
/* Function Name: CreateGCs
* Description: Creates the Graphics contexts
* Arguments: w - the icon button widget.
* Returns: none
*/
static void
CreateGCs(Widget w)
{
XmIconButtonWidget iw = (XmIconButtonWidget) w;
XtGCMask mask, smask;
XGCValues values;
Pixel fg, bg;
Pixmap stipple;
Arg args[2];
Cardinal num_args = 0;
XFontStruct *fs = NULL;
XtSetArg(args[num_args], XmNforeground, &fg); num_args++;
XtSetArg(args[num_args], XmNbackground, &bg); num_args++;
XtGetValues(w, args, num_args);
stipple = GetGreyStipple(w);
XmeRenderTableGetDefaultFont(XmIconButton_font_list(iw), &fs);
values.foreground = fg;
values.background = bg;
values.graphics_exposures = False;
values.stipple = stipple;
values.fill_style = FillStippled;
mask = GCForeground | GCBackground | GCGraphicsExposures;
#ifdef FIX_1381
smask = mask | GCFillStyle;
#else
smask = mask | GCStipple | GCFillStyle;
#endif
if (fs) {
values.font = fs->fid;
mask |= GCFont;
}
XmIconButton_gc(iw) = XtGetGC(w, mask, &values);
#ifdef FIX_1381
/*generally gray insensitive foreground (instead stipple)*/
values.foreground = _XmAssignInsensitiveColor(iw);
XmIconButton_insensitive_text_gc(iw) = XtGetGC(w, smask, &values);
#else
XmIconButton_stippled_text_gc(iw) = XtGetGC(w, smask, &values);
#endif
#ifdef FIX_1381
/*light shadow for insensitive text (instead stipple)*/
values.foreground = iw->primitive.top_shadow_color;
XmIconButton_shadow_gc(iw) = XtGetGC(w, smask, &values);
#endif
/*
* HACK ALERT: !!! Motif hack for monochrome displays. !!!
* If fg and arm color are the same then replace fg color
* with bg color.
*/
if (values.foreground == XmIconButton_arm_color(iw))
values.foreground = bg;
/*
* else just use the same fg color we used to be using.
*/
values.background = XmIconButton_arm_color(iw);
XmIconButton_pixmap_fill_gc(iw) = XtGetGC(w, mask, &values);
XmIconButton_stippled_set_text_gc(iw) = XtGetGC(w, smask, &values);
mask = GCForeground;
values.foreground = XmIconButton_arm_color(iw);
XmIconButton_fill_gc(iw) = XtGetGC(w, mask, &values);
values.foreground = bg;
smask = mask | GCStipple | GCFillStyle;
XmIconButton_stippled_unset_gc(iw) = XtGetGC(w, smask, &values);
values.foreground = XmIconButton_arm_color(iw);
XmIconButton_stippled_set_gc(iw) = XtGetGC(w, smask, &values);
}
/* Function Name: DestroyGCs
* Description: Destroys all GC's needed by icon button.
* Arguments: w - the icon button widget.
* Returns: none.
*/
static void
DestroyGCs(Widget w)
{
XmIconButtonWidget iw = (XmIconButtonWidget) w;
XtReleaseGC(w, XmIconButton_gc(iw));
XtReleaseGC(w, XmIconButton_fill_gc(iw));
XtReleaseGC(w, XmIconButton_pixmap_fill_gc(iw));
XtReleaseGC(w, XmIconButton_stippled_set_gc(iw));
XtReleaseGC(w, XmIconButton_stippled_unset_gc(iw));
#ifdef FIX_1381
XtReleaseGC(w, XmIconButton_shadow_gc(iw));
XtReleaseGC(w, XmIconButton_insensitive_text_gc(iw));
#else
XtReleaseGC(w, XmIconButton_stippled_text_gc(iw));
#endif
XtReleaseGC(w, XmIconButton_stippled_set_text_gc(iw));
}
/* Function Name: CreateXmString
* Description: Given a char * create an Xm String.
* an remember to put in the new lines.
* Arguments: str - the String.
* Returns: The Motif string for this string.
*/
static XmString
CreateXmString(Widget w, String str)
{
XrmValue fromVal, toVal;
XmString xmstr;
fromVal.size = strlen(str) + 1; /* space for NULL. */
fromVal.addr = str;
toVal.size = sizeof(XmString);
toVal.addr = (XtPointer) &xmstr;
if (XtConvertAndStore(w, XmRString, &fromVal, XmRXmString, &toVal)) {
xmstr = XmStringCopy(xmstr); /* because I free it later. */
return(xmstr);
}
return(NULL);
}
/*
* XmRCallProc routine for checking font_list 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 offs,
XrmValue *value)
{
XmIconButtonWidget lw = (XmIconButtonWidget)wid;
/* Check if been here before */
if (lw->icon.check_set_render_table)
value->addr = NULL;
else {
lw->icon.check_set_render_table = True;
value->addr = (char*)&(lw->icon.font_list);
}
}
/* Function name: ChangeCB
* Description: add or remove the activate callback list.
* Arguments: w - the child widget ha� its list of callbacks modified
* activCB - the callback to add or remove from
* closure - additional data to be passed to the callback
* setunset - set/unset flag
* Returns: none
*/
static void
ChangeCB(
Widget w,
XtCallbackProc activCB,
XtPointer closure,
Boolean setunset)
{
if (setunset)
XtAddCallback (w, XmNactivateCallback, activCB, closure);
else
XtRemoveCallback (w, XmNactivateCallback, activCB, closure);
}
/************************************************************
*
* Public routines.
*
************************************************************/
/* Function Name: XmCreateIconButton
* Description: Creation Routine for UIL and ADA.
* Arguments: parent - the parent widget.
* name - the name of the widget.
* args, num_args - the number and list of args.
* Returns: The created widget.
*/
Widget
XmCreateIconButton(Widget parent, String name,
ArgList args, Cardinal num_args)
{
return(XtCreateWidget(name, xmIconButtonWidgetClass,
parent, args, num_args));
}