1 /***********************************************************
3 Copyright 1987, 1988, 1994, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
26 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
30 Permission to use, copy, modify, and distribute this software and its
31 documentation for any purpose and without fee is hereby granted,
32 provided that the above copyright notice appear in all copies and that
33 both that copyright notice and this permission notice appear in
34 supporting documentation, and that the name of Digital not be
35 used in advertising or publicity pertaining to distribution of the
36 software without specific, written prior permission.
38 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
46 ******************************************************************/
49 * Command.c - Command button widget
56 #include <X11/IntrinsicP.h>
57 #include <X11/StringDefs.h>
58 #include <X11/extensions/shape.h>
59 #include <X11/Xmu/Converters.h>
60 #include <X11/Xmu/Drawing.h>
61 #include <X11/Xmu/Misc.h>
62 #include <X11/Xaw/CommandP.h>
63 #include <X11/Xaw/XawInit.h>
66 #define DEFAULT_HIGHLIGHT_THICKNESS 2
67 #define DEFAULT_SHAPE_HIGHLIGHT 32767
68 #define STR_EQUAL(str1, str2) (str1 == str2 || strcmp(str1, str2) == 0)
73 static void XawCommandClassInitialize(void);
74 static void XawCommandDestroy(Widget);
75 static void XawCommandInitialize(Widget, Widget, ArgList, Cardinal*);
76 static void XawCommandRealize(Widget, Mask*, XSetWindowAttributes*);
77 static void XawCommandResize(Widget);
78 static void XawCommandRedisplay(Widget, XEvent*, Region);
79 static Boolean XawCommandSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
80 static void XawCommandGetValuesHook(Widget, ArgList, Cardinal*);
81 static Bool ChangeSensitive(Widget);
86 static GC Get_GC(CommandWidget, Pixel, Pixel);
87 static void PaintCommandWidget(Widget, XEvent*, Region, Bool);
88 static Region HighlightRegion(CommandWidget);
89 static Bool ShapeButton(CommandWidget, Bool);
90 static void XawCommandToggle(Widget);
95 static void Highlight(Widget, XEvent*, String*, Cardinal*);
96 static void Notify(Widget, XEvent*, String*, Cardinal*);
97 static void Reset(Widget, XEvent*, String*, Cardinal*);
98 static void Set(Widget, XEvent*, String*, Cardinal*);
99 static void Unhighlight(Widget, XEvent*, String*, Cardinal*);
100 static void Unset(Widget, XEvent*, String*, Cardinal*);
105 static char defaultTranslations[] =
106 "<Enter>:" "highlight()\n"
107 "<Leave>:" "reset()\n"
108 "<Btn1Down>:" "set()\n"
109 "<Btn1Up>:" "notify() unset()\n"
112 #define offset(field) XtOffsetOf(CommandRec, field)
113 static XtResource resources[] = {
119 offset(command.callbacks),
124 XtNhighlightThickness,
128 offset(command.highlight_thickness),
130 (XtPointer)DEFAULT_SHAPE_HIGHLIGHT
137 offset(command.shape_style),
139 (XtPointer)XawShapeRectangle
142 XtNcornerRoundPercent,
143 XtCCornerRoundPercent,
146 offset(command.corner_round),
153 static XtActionsRec actionsList[] = {
156 {"highlight", Highlight},
159 {"unhighlight", Unhighlight}
162 #define SuperClass ((LabelWidgetClass)&labelClassRec)
164 CommandClassRec commandClassRec = {
167 (WidgetClass)SuperClass, /* superclass */
168 "Command", /* class_name */
169 sizeof(CommandRec), /* size */
170 XawCommandClassInitialize, /* class_initialize */
171 NULL, /* class_part_initialize */
172 False, /* class_inited */
173 XawCommandInitialize, /* initialize */
174 NULL, /* initialize_hook */
175 XawCommandRealize, /* realize */
176 actionsList, /* actions */
177 XtNumber(actionsList), /* num_actions */
178 resources, /* resources */
179 XtNumber(resources), /* num_resources */
180 NULLQUARK, /* xrm_class */
181 False, /* compress_motion */
182 True, /* compress_exposure */
183 True, /* compress_enterleave */
184 False, /* visible_interest */
185 XawCommandDestroy, /* destroy */
186 XawCommandResize, /* resize */
187 XawCommandRedisplay, /* expose */
188 XawCommandSetValues, /* set_values */
189 NULL, /* set_values_hook */
190 XtInheritSetValuesAlmost, /* set_values_almost */
191 XawCommandGetValuesHook, /* get_values_hook */
192 NULL, /* accept_focus */
193 XtVersion, /* version */
194 NULL, /* callback_private */
195 defaultTranslations, /* tm_table */
196 XtInheritQueryGeometry, /* query_geometry */
197 XtInheritDisplayAccelerator, /* display_accelerator */
198 NULL, /* extension */
202 ChangeSensitive, /* change_sensitive */
214 WidgetClass commandWidgetClass = (WidgetClass)&commandClassRec;
220 Get_GC(CommandWidget cbw, Pixel fg, Pixel bg)
224 values.foreground = fg;
225 values.background = bg;
226 values.font = cbw->label.font->fid;
227 values.cap_style = CapProjecting;
229 if (cbw->command.highlight_thickness > 1)
230 values.line_width = cbw->command.highlight_thickness;
232 values.line_width = 0;
234 if (cbw->simple.international == True)
235 return (XtAllocateGC((Widget)cbw, 0,
236 GCForeground | GCBackground | GCLineWidth |
237 GCCapStyle, &values, GCFont, 0));
239 return (XtGetGC((Widget)cbw,
240 GCForeground | GCBackground | GCFont | GCLineWidth |
241 GCCapStyle, &values));
246 XawCommandInitialize(Widget request, Widget cnew,
247 ArgList args, Cardinal *num_args)
249 CommandWidget cbw = (CommandWidget)cnew;
250 int shape_event_base, shape_error_base;
252 if (!cbw->label.font) XtError("Aborting: no font found\n");
254 if (cbw->command.shape_style != XawShapeRectangle &&
255 !XShapeQueryExtension(XtDisplay(cnew), &shape_event_base,
257 cbw->command.shape_style = XawShapeRectangle;
259 if (cbw->command.highlight_thickness == DEFAULT_SHAPE_HIGHLIGHT) {
260 if (cbw->command.shape_style != XawShapeRectangle)
261 cbw->command.highlight_thickness = 0;
263 cbw->command.highlight_thickness = DEFAULT_HIGHLIGHT_THICKNESS;
266 cbw->command.normal_GC = Get_GC(cbw, cbw->label.foreground,
267 cbw->core.background_pixel);
268 cbw->command.inverse_GC = Get_GC(cbw, cbw->core.background_pixel,
269 cbw->label.foreground);
270 XtReleaseGC(cnew, cbw->label.normal_GC);
271 cbw->label.normal_GC = cbw->command.normal_GC;
273 cbw->command.set = False;
274 cbw->command.highlighted = HighlightNone;
278 HighlightRegion(CommandWidget cbw)
280 static Region outerRegion = NULL, innerRegion, emptyRegion;
283 if (cbw->command.highlight_thickness == 0 ||
284 cbw->command.highlight_thickness > Min(XtWidth(cbw), XtHeight(cbw)) / 2)
287 if (outerRegion == NULL) {
288 /* save time by allocating scratch regions only once. */
289 outerRegion = XCreateRegion();
290 innerRegion = XCreateRegion();
291 emptyRegion = XCreateRegion();
295 rect.width = XtWidth(cbw);
296 rect.height = XtHeight(cbw);
297 XUnionRectWithRegion(&rect, emptyRegion, outerRegion);
298 rect.x = rect.y = cbw->command.highlight_thickness;
299 rect.width -= cbw->command.highlight_thickness * 2;
300 rect.height -= cbw->command.highlight_thickness * 2;
301 XUnionRectWithRegion(&rect, emptyRegion, innerRegion);
302 XSubtractRegion(outerRegion, innerRegion, outerRegion);
304 return (outerRegion);
307 /***************************
309 ***************************/
311 XawCommandToggle(Widget w)
313 CommandWidget xaw = (CommandWidget)w;
318 XtSetArg(args[num_args], XtNbackground,
319 xaw->label.foreground); ++num_args;
320 XtSetArg(args[num_args], XtNforeground,
321 xaw->core.background_pixel); ++num_args;
322 XtSetValues(w, args, num_args);
327 Set(Widget w, XEvent *event, String *params, Cardinal *num_params)
329 CommandWidget cbw = (CommandWidget)w;
331 if (cbw->command.set)
335 cbw->command.set= True;
340 Unset(Widget w, XEvent *event, String *params, Cardinal *num_params)
342 CommandWidget cbw = (CommandWidget)w;
344 if (!cbw->command.set)
347 cbw->command.set = False;
353 Reset(Widget w, XEvent *event, String *params, Cardinal *num_params)
355 CommandWidget cbw = (CommandWidget)w;
357 if (cbw->command.set) {
358 cbw->command.highlighted = HighlightNone;
359 Unset(w, event, params, num_params);
362 Unhighlight(w, event, params, num_params);
367 Highlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
369 CommandWidget cbw = (CommandWidget)w;
371 if (*num_params == (Cardinal)0)
372 cbw->command.highlighted = HighlightWhenUnset;
374 if (*num_params != (Cardinal)1)
375 XtWarning("Too many parameters passed to highlight action table.");
376 switch (params[0][0]) {
379 cbw->command.highlighted = HighlightAlways;
382 cbw->command.highlighted = HighlightWhenUnset;
388 PaintCommandWidget(w, event, HighlightRegion(cbw), True);
393 Unhighlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
395 CommandWidget cbw = (CommandWidget)w;
397 cbw->command.highlighted = HighlightNone;
399 PaintCommandWidget(w, event, HighlightRegion(cbw), True);
404 Notify(Widget w, XEvent *event, String *params, Cardinal *num_params)
406 CommandWidget cbw = (CommandWidget)w;
408 /* check to be sure state is still Set so that user can cancel
409 the action (e.g. by moving outside the window, in the default
412 if (cbw->command.set)
413 XtCallCallbackList(w, cbw->command.callbacks, (XtPointer) NULL);
417 XawCommandRedisplay(Widget w, XEvent *event, Region region)
419 PaintCommandWidget(w, event, region, False);
427 * region - region to paint (passed to the superclass)
428 * change - did it change either set or highlight state?
431 PaintCommandWidget(Widget w, XEvent *event, Region region, Bool change)
433 CommandWidget cbw = (CommandWidget)w;
437 very_thick = cbw->command.highlight_thickness
438 > Min(XtWidth(cbw), XtHeight(cbw)) / 2;
440 if (cbw->command.highlight_thickness == 0) {
441 (*SuperClass->core_class.expose) (w, event, region);
446 * If we are set then use the same colors as if we are not highlighted
449 if (cbw->command.highlighted != HighlightNone) {
450 rev_gc = cbw->command.normal_GC;
453 rev_gc = cbw->command.inverse_GC;
456 if (!((!change && cbw->command.highlighted == HighlightNone)
457 || (cbw->command.highlighted == HighlightWhenUnset
458 && cbw->command.set))) {
460 XFillRectangle(XtDisplay(w),XtWindow(w), rev_gc,
461 0, 0, XtWidth(cbw), XtHeight(cbw));
463 /* wide lines are centered on the path, so indent it */
464 if (cbw->core.background_pixmap != XtUnspecifiedPixmap &&
465 rev_gc == cbw->command.inverse_GC) {
466 XClearArea(XtDisplay(w), XtWindow(w),
467 0, 0, XtWidth(cbw), cbw->command.highlight_thickness,
469 XClearArea(XtDisplay(w), XtWindow(w),
470 0, cbw->command.highlight_thickness,
471 cbw->command.highlight_thickness,
472 XtHeight(cbw) - (cbw->command.highlight_thickness<<1),
474 XClearArea(XtDisplay(w), XtWindow(w),
475 XtWidth(cbw) - cbw->command.highlight_thickness,
476 cbw->command.highlight_thickness,
477 cbw->command.highlight_thickness,
478 XtHeight(cbw) - (cbw->command.highlight_thickness<<1),
480 XClearArea(XtDisplay(w), XtWindow(w),
481 0, XtHeight(cbw) - cbw->command.highlight_thickness,
482 XtWidth(cbw), cbw->command.highlight_thickness,
486 int offset = cbw->command.highlight_thickness / 2;
488 XDrawRectangle(XtDisplay(w),XtWindow(w), rev_gc, offset, offset,
489 XtWidth(cbw) - cbw->command.highlight_thickness,
490 XtHeight(cbw) - cbw->command.highlight_thickness);
495 (*SuperClass->core_class.expose)(w, event, region);
499 XawCommandDestroy(Widget w)
501 CommandWidget cbw = (CommandWidget)w;
503 /* Label will release cbw->command.normal_GC */
504 XtReleaseGC(w, cbw->command.inverse_GC);
509 XawCommandSetValues(Widget current, Widget request, Widget cnew,
510 ArgList args, Cardinal *num_args)
512 CommandWidget oldcbw = (CommandWidget)current;
513 CommandWidget cbw = (CommandWidget)cnew;
514 Boolean redisplay = False;
516 if (oldcbw->core.sensitive != cbw->core.sensitive && !cbw->core.sensitive) {
517 cbw->command.highlighted = HighlightNone;
521 if (cbw->command.set) {
523 Pixel foreground, background;
525 foreground = oldcbw->label.foreground;
526 background = oldcbw->core.background_pixel;
527 for (i = 0; i < *num_args; i++) {
528 if (STR_EQUAL(args[i].name, XtNforeground))
529 background = cbw->label.foreground;
530 else if (STR_EQUAL(args[i].name, XtNbackground))
531 foreground = cbw->core.background_pixel;
533 cbw->label.foreground = foreground;
534 cbw->core.background_pixel = background;
537 if (oldcbw->label.foreground != cbw->label.foreground
538 || oldcbw->core.background_pixel != cbw->core.background_pixel
539 || oldcbw->command.highlight_thickness
540 != cbw->command.highlight_thickness
541 || oldcbw->label.font != cbw->label.font) {
542 XtReleaseGC(cnew, cbw->command.inverse_GC);
544 cbw->command.normal_GC = Get_GC(cbw, cbw->label.foreground,
545 cbw->core.background_pixel);
546 cbw->command.inverse_GC = Get_GC(cbw, cbw->core.background_pixel,
547 cbw->label.foreground);
548 XtReleaseGC(cnew, cbw->label.normal_GC);
549 cbw->label.normal_GC = cbw->command.normal_GC;
554 if (XtIsRealized(cnew)
555 && oldcbw->command.shape_style != cbw->command.shape_style
556 && !ShapeButton(cbw, True))
557 cbw->command.shape_style = oldcbw->command.shape_style;
563 XawCommandGetValuesHook(Widget w, ArgList args, Cardinal *num_args)
565 CommandWidget cbw = (CommandWidget)w;
568 for (i = 0; i < *num_args; i++) {
569 if (STR_EQUAL(args[i].name, XtNforeground))
570 *((String*)args[i].value) = cbw->command.set ?
571 (String)cbw->core.background_pixel : (String)cbw->label.foreground;
572 else if (STR_EQUAL(args[i].name, XtNbackground))
573 *((String*)args[i].value) = cbw->command.set ?
574 (String)cbw->label.foreground : (String)cbw->core.background_pixel;
579 XawCommandClassInitialize(void)
581 XawInitializeWidgetSet();
582 XtSetTypeConverter(XtRString, XtRShapeStyle, XmuCvtStringToShapeStyle,
583 NULL, 0, XtCacheNone, NULL);
584 XtSetTypeConverter(XtRShapeStyle, XtRString, XmuCvtShapeStyleToString,
585 NULL, 0, XtCacheNone, NULL);
589 ShapeButton(CommandWidget cbw, Bool checkRectangular)
591 Dimension corner_size = 0;
593 if (cbw->command.shape_style == XawShapeRoundedRectangle) {
594 corner_size = XtWidth(cbw) < XtHeight(cbw) ?
595 XtWidth(cbw) : XtHeight(cbw);
596 corner_size = (corner_size * cbw->command.corner_round) / 100;
599 if (checkRectangular || cbw->command.shape_style != XawShapeRectangle) {
600 if (!XmuReshapeWidget((Widget)cbw, cbw->command.shape_style,
601 corner_size, corner_size)) {
602 cbw->command.shape_style = XawShapeRectangle;
611 XawCommandRealize(Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
613 (*commandWidgetClass->core_class.superclass->core_class.realize)
614 (w, valueMask, attributes);
616 ShapeButton((CommandWidget)w, False);
620 XawCommandResize(Widget w)
623 ShapeButton((CommandWidget)w, False);
625 (*commandWidgetClass->core_class.superclass->core_class.resize)(w);
629 ChangeSensitive(Widget w)
631 CommandWidget cbw = (CommandWidget)w;
633 if (XtIsRealized(w)) {
634 if (XtIsSensitive(w)) {
635 if (w->core.border_pixmap != XtUnspecifiedPixmap)
636 XSetWindowBorderPixmap(XtDisplay(w), XtWindow(w),
637 w->core.border_pixmap);
639 XSetWindowBorder(XtDisplay(w), XtWindow(w),
640 w->core.border_pixel);
643 if (cbw->simple.insensitive_border == None)
644 cbw->simple.insensitive_border =
645 XmuCreateStippledPixmap(XtScreen(w),
646 w->core.border_pixel,
648 cbw->label.foreground :
649 w->core.background_pixel,
651 XSetWindowBorderPixmap(XtDisplay(w), XtWindow(w),
652 cbw->simple.insensitive_border);