upload tizen2.0 source
[framework/uifw/xorg/lib/libxaw.git] / src / Command.c
1 /***********************************************************
2
3 Copyright 1987, 1988, 1994, 1998  The Open Group
4
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
9 documentation.
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
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.
20
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.
24
25
26 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
27
28                         All Rights Reserved
29
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.
37
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
44 SOFTWARE.
45
46 ******************************************************************/
47
48 /*
49  * Command.c - Command button widget
50  */
51
52 #ifdef HAVE_CONFIG_H
53 #include <config.h>
54 #endif
55 #include <stdio.h>
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>
64 #include "Private.h"
65
66 #define DEFAULT_HIGHLIGHT_THICKNESS 2
67 #define DEFAULT_SHAPE_HIGHLIGHT 32767
68 #define STR_EQUAL(str1, str2)   (str1 == str2 || strcmp(str1, str2) == 0)
69
70 /*
71  * Class Methods
72  */
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);
82
83 /*
84  * Prototypes
85  */
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);
91
92 /*
93  * Actions
94  */
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*);
101
102 /*
103  * Initialization
104  */
105 static char defaultTranslations[] =
106 "<Enter>:"      "highlight()\n"
107 "<Leave>:"      "reset()\n"
108 "<Btn1Down>:"   "set()\n"
109 "<Btn1Up>:"     "notify() unset()\n"
110 ;
111
112 #define offset(field) XtOffsetOf(CommandRec, field)
113 static XtResource resources[] = {
114   {
115     XtNcallback,
116     XtCCallback,
117     XtRCallback,
118     sizeof(XtPointer),
119     offset(command.callbacks),
120     XtRCallback,
121     NULL
122   },
123   {
124     XtNhighlightThickness,
125     XtCThickness,
126     XtRDimension,
127     sizeof(Dimension),
128     offset(command.highlight_thickness),
129     XtRImmediate,
130     (XtPointer)DEFAULT_SHAPE_HIGHLIGHT
131   },
132   {
133     XtNshapeStyle,
134     XtCShapeStyle,
135     XtRShapeStyle,
136     sizeof(int),
137     offset(command.shape_style),
138     XtRImmediate,
139     (XtPointer)XawShapeRectangle
140   },
141   {
142     XtNcornerRoundPercent,
143     XtCCornerRoundPercent,
144     XtRDimension,
145     sizeof(Dimension),
146     offset(command.corner_round),
147     XtRImmediate,
148     (XtPointer)25
149   },
150 };
151 #undef offset
152
153 static XtActionsRec actionsList[] = {
154   {"set",               Set},
155   {"notify",            Notify},
156   {"highlight",         Highlight},
157   {"reset",             Reset},
158   {"unset",             Unset},
159   {"unhighlight",       Unhighlight}
160 };
161
162 #define SuperClass ((LabelWidgetClass)&labelClassRec)
163
164 CommandClassRec commandClassRec = {
165   /* core */
166   {
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 */
199   },
200   /* simple */
201   {
202     ChangeSensitive,                    /* change_sensitive */
203   },
204   /* label */
205   {
206     NULL,                               /* not used */
207   },
208   /* command */
209   {
210     NULL,                               /* not used */
211   },
212 };
213
214 WidgetClass commandWidgetClass = (WidgetClass)&commandClassRec;
215
216 /*
217  * Implementation
218  */
219 static GC
220 Get_GC(CommandWidget cbw, Pixel fg, Pixel bg)
221 {
222     XGCValues   values;
223
224     values.foreground   = fg;
225     values.background   = bg;
226     values.font         = cbw->label.font->fid;
227     values.cap_style    = CapProjecting;
228
229     if (cbw->command.highlight_thickness > 1)
230         values.line_width = cbw->command.highlight_thickness;
231     else
232         values.line_width = 0;
233
234     if (cbw->simple.international == True)
235         return (XtAllocateGC((Widget)cbw, 0,
236                              GCForeground | GCBackground | GCLineWidth |
237                              GCCapStyle, &values, GCFont, 0));
238     else
239         return (XtGetGC((Widget)cbw,
240                         GCForeground | GCBackground | GCFont | GCLineWidth |
241                         GCCapStyle, &values));
242 }
243
244 /*ARGSUSED*/
245 static void
246 XawCommandInitialize(Widget request, Widget cnew,
247                      ArgList args, Cardinal *num_args)
248 {
249     CommandWidget cbw = (CommandWidget)cnew;
250     int shape_event_base, shape_error_base;
251
252     if (!cbw->label.font) XtError("Aborting: no font found\n");
253
254     if (cbw->command.shape_style != XawShapeRectangle &&
255         !XShapeQueryExtension(XtDisplay(cnew), &shape_event_base,
256                               &shape_error_base))
257         cbw->command.shape_style = XawShapeRectangle;
258
259     if (cbw->command.highlight_thickness == DEFAULT_SHAPE_HIGHLIGHT) {
260         if (cbw->command.shape_style != XawShapeRectangle)
261             cbw->command.highlight_thickness = 0;
262         else
263             cbw->command.highlight_thickness = DEFAULT_HIGHLIGHT_THICKNESS;
264     }
265
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;
272
273     cbw->command.set = False;
274     cbw->command.highlighted = HighlightNone;
275 }
276
277 static Region
278 HighlightRegion(CommandWidget cbw)
279 {
280     static Region outerRegion = NULL, innerRegion, emptyRegion;
281     XRectangle rect;
282
283     if (cbw->command.highlight_thickness == 0 ||
284         cbw->command.highlight_thickness > Min(XtWidth(cbw), XtHeight(cbw)) / 2)
285         return (NULL);
286
287     if (outerRegion == NULL) {
288         /* save time by allocating scratch regions only once. */
289         outerRegion = XCreateRegion();
290         innerRegion = XCreateRegion();
291         emptyRegion = XCreateRegion();
292     }
293
294     rect.x = rect.y = 0;
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);
303
304     return (outerRegion);
305 }
306
307 /***************************
308 *  Action Procedures
309 ***************************/
310 static void
311 XawCommandToggle(Widget w)
312 {
313     CommandWidget xaw = (CommandWidget)w;
314     Arg args[2];
315     Cardinal num_args;
316
317     num_args = 0;
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);
323 }
324
325 /*ARGSUSED*/
326 static void
327 Set(Widget w, XEvent *event, String *params, Cardinal *num_params)
328 {
329     CommandWidget cbw = (CommandWidget)w;
330
331     if (cbw->command.set)
332         return;
333
334     XawCommandToggle(w);
335     cbw->command.set= True;
336 }
337
338 /*ARGSUSED*/
339 static void
340 Unset(Widget w, XEvent *event, String *params, Cardinal *num_params)
341 {
342     CommandWidget cbw = (CommandWidget)w;
343
344     if (!cbw->command.set)
345         return;
346
347     cbw->command.set = False;
348     XawCommandToggle(w);
349 }
350
351 /*ARGSUSED*/
352 static void
353 Reset(Widget w, XEvent *event, String *params, Cardinal *num_params)
354 {
355     CommandWidget cbw = (CommandWidget)w;
356
357     if (cbw->command.set) {
358         cbw->command.highlighted = HighlightNone;
359         Unset(w, event, params, num_params);
360     }
361     else
362         Unhighlight(w, event, params, num_params);
363 }
364
365 /*ARGSUSED*/
366 static void
367 Highlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
368 {
369     CommandWidget cbw = (CommandWidget)w;
370
371     if (*num_params == (Cardinal)0)
372         cbw->command.highlighted = HighlightWhenUnset;
373     else {
374         if (*num_params != (Cardinal)1)
375             XtWarning("Too many parameters passed to highlight action table.");
376         switch (params[0][0]) {
377             case 'A':
378             case 'a':
379                 cbw->command.highlighted = HighlightAlways;
380                 break;
381             default:
382                 cbw->command.highlighted = HighlightWhenUnset;
383                 break;
384         }
385     }
386
387     if (XtIsRealized(w))
388         PaintCommandWidget(w, event, HighlightRegion(cbw), True);
389 }
390
391 /*ARGSUSED*/
392 static void
393 Unhighlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
394 {
395     CommandWidget cbw = (CommandWidget)w;
396
397     cbw->command.highlighted = HighlightNone;
398     if (XtIsRealized(w))
399         PaintCommandWidget(w, event, HighlightRegion(cbw), True);
400 }
401
402 /*ARGSUSED*/
403 static void
404 Notify(Widget w, XEvent *event, String *params, Cardinal *num_params)
405 {
406     CommandWidget cbw = (CommandWidget)w;
407
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
410        bindings.
411     */
412     if (cbw->command.set)
413         XtCallCallbackList(w, cbw->command.callbacks, (XtPointer) NULL);
414 }
415
416 static void
417 XawCommandRedisplay(Widget w, XEvent *event, Region region)
418 {
419     PaintCommandWidget(w, event, region, False);
420 }
421
422 /*
423  * Function:
424  *      PaintCommandWidget
425  * Parameters:
426  *      w      - command widget
427  *      region - region to paint (passed to the superclass)
428  *                 change - did it change either set or highlight state?
429  */
430 static void
431 PaintCommandWidget(Widget w, XEvent *event, Region region, Bool change)
432 {
433     CommandWidget cbw = (CommandWidget)w;
434     Bool very_thick;
435     GC rev_gc;
436
437     very_thick = cbw->command.highlight_thickness
438                  > Min(XtWidth(cbw), XtHeight(cbw)) / 2;
439
440     if (cbw->command.highlight_thickness == 0) {
441         (*SuperClass->core_class.expose) (w, event, region);
442         return;
443     }
444
445     /*
446      * If we are set then use the same colors as if we are not highlighted
447      */
448
449     if (cbw->command.highlighted != HighlightNone) {
450         rev_gc = cbw->command.normal_GC;
451     }
452     else {
453         rev_gc = cbw->command.inverse_GC;
454     }
455
456     if (!((!change && cbw->command.highlighted == HighlightNone)
457         || (cbw->command.highlighted == HighlightWhenUnset
458             && cbw->command.set))) {
459         if (very_thick)
460             XFillRectangle(XtDisplay(w),XtWindow(w), rev_gc,
461                            0, 0, XtWidth(cbw), XtHeight(cbw));
462         else {
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,
468                            False);
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),
473                            False);
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),
479                            False);
480                 XClearArea(XtDisplay(w), XtWindow(w),
481                            0, XtHeight(cbw) - cbw->command.highlight_thickness,
482                            XtWidth(cbw), cbw->command.highlight_thickness,
483                            False);
484             }
485             else {
486                 int offset = cbw->command.highlight_thickness / 2;
487
488                 XDrawRectangle(XtDisplay(w),XtWindow(w), rev_gc, offset, offset,
489                                XtWidth(cbw) - cbw->command.highlight_thickness,
490                               XtHeight(cbw) - cbw->command.highlight_thickness);
491            }
492         }
493     }
494
495     (*SuperClass->core_class.expose)(w, event, region);
496 }
497
498 static void
499 XawCommandDestroy(Widget w)
500 {
501     CommandWidget cbw = (CommandWidget)w;
502
503     /* Label will release cbw->command.normal_GC */
504     XtReleaseGC(w, cbw->command.inverse_GC);
505 }
506
507 /*ARGSUSED*/
508 static Boolean
509 XawCommandSetValues(Widget current, Widget request, Widget cnew,
510                     ArgList args, Cardinal *num_args)
511 {
512     CommandWidget oldcbw = (CommandWidget)current;
513     CommandWidget cbw = (CommandWidget)cnew;
514     Boolean redisplay = False;
515
516     if (oldcbw->core.sensitive != cbw->core.sensitive && !cbw->core.sensitive) {
517         cbw->command.highlighted = HighlightNone;
518         redisplay = True;
519     }
520
521     if (cbw->command.set) {
522         unsigned int i;
523         Pixel foreground, background;
524
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;
532         }
533         cbw->label.foreground = foreground;
534         cbw->core.background_pixel = background;
535     }
536
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);
543
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;
550
551         redisplay = True;
552     }
553
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;
558
559     return (redisplay);
560 }
561
562 static void
563 XawCommandGetValuesHook(Widget w, ArgList args, Cardinal *num_args)
564 {
565     CommandWidget cbw = (CommandWidget)w;
566     unsigned int i;
567
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;
575     }
576 }
577
578 static void
579 XawCommandClassInitialize(void)
580 {
581     XawInitializeWidgetSet();
582     XtSetTypeConverter(XtRString, XtRShapeStyle, XmuCvtStringToShapeStyle,
583                        NULL, 0, XtCacheNone, NULL);
584     XtSetTypeConverter(XtRShapeStyle, XtRString, XmuCvtShapeStyleToString,
585                        NULL, 0, XtCacheNone, NULL);
586 }
587
588 static Bool
589 ShapeButton(CommandWidget cbw, Bool checkRectangular)
590 {
591     Dimension corner_size = 0;
592
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;
597     }
598
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;
603             return (False);
604         }
605     }
606
607     return (True);
608 }
609
610 static void
611 XawCommandRealize(Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
612 {
613     (*commandWidgetClass->core_class.superclass->core_class.realize)
614         (w, valueMask, attributes);
615
616     ShapeButton((CommandWidget)w, False);
617 }
618
619 static void
620 XawCommandResize(Widget w)
621 {
622     if (XtIsRealized(w))
623         ShapeButton((CommandWidget)w, False);
624
625     (*commandWidgetClass->core_class.superclass->core_class.resize)(w);
626 }
627
628 static Bool
629 ChangeSensitive(Widget w)
630 {
631     CommandWidget cbw = (CommandWidget)w;
632
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);
638             else
639                 XSetWindowBorder(XtDisplay(w), XtWindow(w),
640                                  w->core.border_pixel);
641         }
642         else {
643             if (cbw->simple.insensitive_border == None)
644                 cbw->simple.insensitive_border =
645                     XmuCreateStippledPixmap(XtScreen(w),
646                                             w->core.border_pixel,
647                                             cbw->command.set ?
648                                                 cbw->label.foreground :
649                                                 w->core.background_pixel,
650                                             w->core.depth);
651             XSetWindowBorderPixmap(XtDisplay(w), XtWindow(w),
652                                    cbw->simple.insensitive_border);
653         }
654     }
655
656     return (False);
657 }