#include <stdio.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/extensions/shape.h>
#include <X11/Xmu/Converters.h>
#include <X11/Xmu/Drawing.h>
#include <X11/Xmu/Misc.h>
#include <X11/Xaw/CommandP.h>
#include <X11/Xaw/XawInit.h>
#include "Private.h"
#define DEFAULT_HIGHLIGHT_THICKNESS 2
#define DEFAULT_SHAPE_HIGHLIGHT 32767
#define STR_EQUAL(str1, str2) (str1 == str2 || strcmp(str1, str2) == 0)
static void XawCommandClassInitialize(void);
static void XawCommandDestroy(Widget);
static void XawCommandInitialize(Widget, Widget, ArgList, Cardinal*);
static void XawCommandRealize(Widget, Mask*, XSetWindowAttributes*);
static void XawCommandResize(Widget);
static void XawCommandRedisplay(Widget, XEvent*, Region);
static Boolean XawCommandSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
static void XawCommandGetValuesHook(Widget, ArgList, Cardinal*);
static Bool ChangeSensitive(Widget);
static GC Get_GC(CommandWidget, Pixel, Pixel);
static void PaintCommandWidget(Widget, XEvent*, Region, Bool);
static Region HighlightRegion(CommandWidget);
static Bool ShapeButton(CommandWidget, Bool);
static void XawCommandToggle(Widget);
static void Highlight(Widget, XEvent*, String*, Cardinal*);
static void Notify(Widget, XEvent*, String*, Cardinal*);
static void Reset(Widget, XEvent*, String*, Cardinal*);
static void Set(Widget, XEvent*, String*, Cardinal*);
static void Unhighlight(Widget, XEvent*, String*, Cardinal*);
static void Unset(Widget, XEvent*, String*, Cardinal*);
static char defaultTranslations[] =
"<Enter>:" "highlight()\n"
"<Leave>:" "reset()\n"
"<Btn1Down>:" "set()\n"
"<Btn1Up>:" "notify() unset()\n"
;
#define offset(field) XtOffsetOf(CommandRec, field)
static XtResource resources[] = {
{
XtNcallback,
XtCCallback,
XtRCallback,
sizeof(XtPointer),
offset(command.callbacks),
XtRCallback,
NULL
},
{
XtNhighlightThickness,
XtCThickness,
XtRDimension,
sizeof(Dimension),
offset(command.highlight_thickness),
XtRImmediate,
(XtPointer)DEFAULT_SHAPE_HIGHLIGHT
},
{
XtNshapeStyle,
XtCShapeStyle,
XtRShapeStyle,
sizeof(int),
offset(command.shape_style),
XtRImmediate,
(XtPointer)XawShapeRectangle
},
{
XtNcornerRoundPercent,
XtCCornerRoundPercent,
XtRDimension,
sizeof(Dimension),
offset(command.corner_round),
XtRImmediate,
(XtPointer)25
},
};
#undef offset
static XtActionsRec actionsList[] = {
{"set", Set},
{"notify", Notify},
{"highlight", Highlight},
{"reset", Reset},
{"unset", Unset},
{"unhighlight", Unhighlight}
};
#define SuperClass ((LabelWidgetClass)&labelClassRec)
CommandClassRec commandClassRec = {
{
(WidgetClass)SuperClass,
"Command",
sizeof(CommandRec),
XawCommandClassInitialize,
NULL,
False,
XawCommandInitialize,
NULL,
XawCommandRealize,
actionsList,
XtNumber(actionsList),
resources,
XtNumber(resources),
NULLQUARK,
False,
True,
True,
False,
XawCommandDestroy,
XawCommandResize,
XawCommandRedisplay,
XawCommandSetValues,
NULL,
XtInheritSetValuesAlmost,
XawCommandGetValuesHook,
NULL,
XtVersion,
NULL,
defaultTranslations,
XtInheritQueryGeometry,
XtInheritDisplayAccelerator,
NULL,
},
{
ChangeSensitive,
},
{
0,
},
{
0,
},
};
WidgetClass commandWidgetClass = (WidgetClass)&commandClassRec;
static GC
Get_GC(CommandWidget cbw, Pixel fg, Pixel bg)
{
XGCValues values;
values.foreground = fg;
values.background = bg;
values.font = cbw->label.font->fid;
values.cap_style = CapProjecting;
if (cbw->command.highlight_thickness > 1)
values.line_width = cbw->command.highlight_thickness;
else
values.line_width = 0;
if (cbw->simple.international == True)
return (XtAllocateGC((Widget)cbw, 0,
GCForeground | GCBackground | GCLineWidth |
GCCapStyle, &values, GCFont, 0));
else
return (XtGetGC((Widget)cbw,
GCForeground | GCBackground | GCFont | GCLineWidth |
GCCapStyle, &values));
}
static void
XawCommandInitialize(Widget request, Widget cnew,
ArgList args, Cardinal *num_args)
{
CommandWidget cbw = (CommandWidget)cnew;
int shape_event_base, shape_error_base;
if (cbw->command.shape_style != XawShapeRectangle &&
!XShapeQueryExtension(XtDisplay(cnew), &shape_event_base,
&shape_error_base))
cbw->command.shape_style = XawShapeRectangle;
if (cbw->command.highlight_thickness == DEFAULT_SHAPE_HIGHLIGHT) {
if (cbw->command.shape_style != XawShapeRectangle)
cbw->command.highlight_thickness = 0;
else
cbw->command.highlight_thickness = DEFAULT_HIGHLIGHT_THICKNESS;
}
cbw->command.normal_GC = Get_GC(cbw, cbw->label.foreground,
cbw->core.background_pixel);
cbw->command.inverse_GC = Get_GC(cbw, cbw->core.background_pixel,
cbw->label.foreground);
XtReleaseGC(cnew, cbw->label.normal_GC);
cbw->label.normal_GC = cbw->command.normal_GC;
cbw->command.set = False;
cbw->command.highlighted = HighlightNone;
}
static Region
HighlightRegion(CommandWidget cbw)
{
static Region outerRegion = NULL, innerRegion, emptyRegion;
XRectangle rect;
if (cbw->command.highlight_thickness == 0 ||
cbw->command.highlight_thickness > Min(XtWidth(cbw), XtHeight(cbw)) / 2)
return (NULL);
if (outerRegion == NULL) {
outerRegion = XCreateRegion();
innerRegion = XCreateRegion();
emptyRegion = XCreateRegion();
}
rect.x = rect.y = 0;
rect.width = XtWidth(cbw);
rect.height = XtHeight(cbw);
XUnionRectWithRegion(&rect, emptyRegion, outerRegion);
rect.x = rect.y = cbw->command.highlight_thickness;
rect.width -= cbw->command.highlight_thickness * 2;
rect.height -= cbw->command.highlight_thickness * 2;
XUnionRectWithRegion(&rect, emptyRegion, innerRegion);
XSubtractRegion(outerRegion, innerRegion, outerRegion);
return (outerRegion);
}
static void
XawCommandToggle(Widget w)
{
CommandWidget xaw = (CommandWidget)w;
Arg args[2];
Cardinal num_args;
num_args = 0;
XtSetArg(args[num_args], XtNbackground,
xaw->label.foreground); ++num_args;
XtSetArg(args[num_args], XtNforeground,
xaw->core.background_pixel); ++num_args;
XtSetValues(w, args, num_args);
}
static void
Set(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
CommandWidget cbw = (CommandWidget)w;
if (cbw->command.set)
return;
XawCommandToggle(w);
cbw->command.set= True;
}
static void
Unset(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
CommandWidget cbw = (CommandWidget)w;
if (!cbw->command.set)
return;
cbw->command.set = False;
XawCommandToggle(w);
}
static void
Reset(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
CommandWidget cbw = (CommandWidget)w;
if (cbw->command.set) {
cbw->command.highlighted = HighlightNone;
Unset(w, event, params, num_params);
}
else
Unhighlight(w, event, params, num_params);
}
static void
Highlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
CommandWidget cbw = (CommandWidget)w;
if (*num_params == (Cardinal)0)
cbw->command.highlighted = HighlightWhenUnset;
else {
if (*num_params != (Cardinal)1)
XtWarning("Too many parameters passed to highlight action table.");
switch (params[0][0]) {
case 'A':
case 'a':
cbw->command.highlighted = HighlightAlways;
break;
default:
cbw->command.highlighted = HighlightWhenUnset;
break;
}
}
if (XtIsRealized(w))
PaintCommandWidget(w, event, HighlightRegion(cbw), True);
}
static void
Unhighlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
CommandWidget cbw = (CommandWidget)w;
cbw->command.highlighted = HighlightNone;
if (XtIsRealized(w))
PaintCommandWidget(w, event, HighlightRegion(cbw), True);
}
static void
Notify(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
CommandWidget cbw = (CommandWidget)w;
if (cbw->command.set)
XtCallCallbackList(w, cbw->command.callbacks, (XtPointer) NULL);
}
static void
XawCommandRedisplay(Widget w, XEvent *event, Region region)
{
PaintCommandWidget(w, event, region, False);
}
static void
PaintCommandWidget(Widget w, XEvent *event, Region region, Bool change)
{
CommandWidget cbw = (CommandWidget)w;
Bool very_thick;
GC norm_gc, rev_gc;
very_thick = cbw->command.highlight_thickness
> Min(XtWidth(cbw), XtHeight(cbw)) / 2;
if (cbw->command.highlight_thickness == 0) {
(*SuperClass->core_class.expose) (w, event, region);
return;
}
if (cbw->command.highlighted != HighlightNone) {
norm_gc = cbw->command.inverse_GC;
rev_gc = cbw->command.normal_GC;
}
else {
norm_gc = cbw->command.normal_GC;
rev_gc = cbw->command.inverse_GC;
}
if (!((!change && cbw->command.highlighted == HighlightNone)
|| (cbw->command.highlighted == HighlightWhenUnset
&& cbw->command.set))) {
if (very_thick)
XFillRectangle(XtDisplay(w),XtWindow(w), rev_gc,
0, 0, XtWidth(cbw), XtHeight(cbw));
else {
if (cbw->core.background_pixmap != XtUnspecifiedPixmap &&
rev_gc == cbw->command.inverse_GC) {
XClearArea(XtDisplay(w), XtWindow(w),
0, 0, XtWidth(cbw), cbw->command.highlight_thickness,
False);
XClearArea(XtDisplay(w), XtWindow(w),
0, cbw->command.highlight_thickness,
cbw->command.highlight_thickness,
XtHeight(cbw) - (cbw->command.highlight_thickness<<1),
False);
XClearArea(XtDisplay(w), XtWindow(w),
XtWidth(cbw) - cbw->command.highlight_thickness,
cbw->command.highlight_thickness,
cbw->command.highlight_thickness,
XtHeight(cbw) - (cbw->command.highlight_thickness<<1),
False);
XClearArea(XtDisplay(w), XtWindow(w),
0, XtHeight(cbw) - cbw->command.highlight_thickness,
XtWidth(cbw), cbw->command.highlight_thickness,
False);
}
else {
int offset = cbw->command.highlight_thickness / 2;
XDrawRectangle(XtDisplay(w),XtWindow(w), rev_gc, offset, offset,
XtWidth(cbw) - cbw->command.highlight_thickness,
XtHeight(cbw) - cbw->command.highlight_thickness);
}
}
}
(*SuperClass->core_class.expose)(w, event, region);
}
static void
XawCommandDestroy(Widget w)
{
CommandWidget cbw = (CommandWidget)w;
XtReleaseGC(w, cbw->command.inverse_GC);
}
static Boolean
XawCommandSetValues(Widget current, Widget request, Widget cnew,
ArgList args, Cardinal *num_args)
{
CommandWidget oldcbw = (CommandWidget)current;
CommandWidget cbw = (CommandWidget)cnew;
Boolean redisplay = False;
if (oldcbw->core.sensitive != cbw->core.sensitive && !cbw->core.sensitive) {
cbw->command.highlighted = HighlightNone;
redisplay = True;
}
if (cbw->command.set) {
unsigned int i;
Pixel foreground, background;
foreground = oldcbw->label.foreground;
background = oldcbw->core.background_pixel;
for (i = 0; i < *num_args; i++) {
if (STR_EQUAL(args[i].name, XtNforeground))
background = cbw->label.foreground;
else if (STR_EQUAL(args[i].name, XtNbackground))
foreground = cbw->core.background_pixel;
}
cbw->label.foreground = foreground;
cbw->core.background_pixel = background;
}
if (oldcbw->label.foreground != cbw->label.foreground
|| oldcbw->core.background_pixel != cbw->core.background_pixel
|| oldcbw->command.highlight_thickness
!= cbw->command.highlight_thickness
|| oldcbw->label.font != cbw->label.font) {
XtReleaseGC(cnew, cbw->command.inverse_GC);
cbw->command.normal_GC = Get_GC(cbw, cbw->label.foreground,
cbw->core.background_pixel);
cbw->command.inverse_GC = Get_GC(cbw, cbw->core.background_pixel,
cbw->label.foreground);
XtReleaseGC(cnew, cbw->label.normal_GC);
cbw->label.normal_GC = cbw->command.normal_GC;
redisplay = True;
}
if (XtIsRealized(cnew)
&& oldcbw->command.shape_style != cbw->command.shape_style
&& !ShapeButton(cbw, True))
cbw->command.shape_style = oldcbw->command.shape_style;
return (redisplay);
}
static void
XawCommandGetValuesHook(Widget w, ArgList args, Cardinal *num_args)
{
CommandWidget cbw = (CommandWidget)w;
unsigned int i;
for (i = 0; i < *num_args; i++) {
if (STR_EQUAL(args[i].name, XtNforeground))
*((String*)args[i].value) = cbw->command.set ?
(String)cbw->core.background_pixel : (String)cbw->label.foreground;
else if (STR_EQUAL(args[i].name, XtNbackground))
*((String*)args[i].value) = cbw->command.set ?
(String)cbw->label.foreground : (String)cbw->core.background_pixel;
}
}
static void
XawCommandClassInitialize(void)
{
XawInitializeWidgetSet();
XtSetTypeConverter(XtRString, XtRShapeStyle, XmuCvtStringToShapeStyle,
NULL, 0, XtCacheNone, NULL);
XtSetTypeConverter(XtRShapeStyle, XtRString, XmuCvtShapeStyleToString,
NULL, 0, XtCacheNone, NULL);
}
static Bool
ShapeButton(CommandWidget cbw, Bool checkRectangular)
{
Dimension corner_size = 0;
if (cbw->command.shape_style == XawShapeRoundedRectangle) {
corner_size = XtWidth(cbw) < XtHeight(cbw) ?
XtWidth(cbw) : XtHeight(cbw);
corner_size = (corner_size * cbw->command.corner_round) / 100;
}
if (checkRectangular || cbw->command.shape_style != XawShapeRectangle) {
if (!XmuReshapeWidget((Widget)cbw, cbw->command.shape_style,
corner_size, corner_size)) {
cbw->command.shape_style = XawShapeRectangle;
return (False);
}
}
return (True);
}
static void
XawCommandRealize(Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
{
(*commandWidgetClass->core_class.superclass->core_class.realize)
(w, valueMask, attributes);
ShapeButton((CommandWidget)w, False);
}
static void
XawCommandResize(Widget w)
{
if (XtIsRealized(w))
ShapeButton((CommandWidget)w, False);
(*commandWidgetClass->core_class.superclass->core_class.resize)(w);
}
static Bool
ChangeSensitive(Widget w)
{
CommandWidget cbw = (CommandWidget)w;
if (XtIsRealized(w)) {
if (XtIsSensitive(w)) {
if (w->core.border_pixmap != XtUnspecifiedPixmap)
XSetWindowBorderPixmap(XtDisplay(w), XtWindow(w),
w->core.border_pixmap);
else
XSetWindowBorder(XtDisplay(w), XtWindow(w),
w->core.border_pixel);
}
else {
if (cbw->simple.insensitive_border == None)
cbw->simple.insensitive_border =
XmuCreateStippledPixmap(XtScreen(w),
w->core.border_pixel,
cbw->command.set ?
cbw->label.foreground :
w->core.background_pixel,
w->core.depth);
XSetWindowBorderPixmap(XtDisplay(w), XtWindow(w),
cbw->simple.insensitive_border);
}
}
return (False);
}