1 /* vi:set ts=8 sts=4 sw=4:
3 * VIM - Vi IMproved by Bram Moolenaar
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
11 * (C) 2002,2005 by Marcin Dalecki <martin@dalecki.de>
13 * MARCIN DALECKI ASSUMES NO RESPONSIBILITY FOR THE USE OR INABILITY TO USE ANY
14 * OF THIS SOFTWARE . THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
15 * KIND, AND MARCIN DALECKI EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES,
16 * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS FOR A PARTICULAR PURPOSE.
21 * Enhanced Motif PushButton widget with move over behavior.
30 #if defined(HAVE_XM_TRAITP_H) && defined(HAVE_XM_MANAGER_H) \
31 && defined(HAVE_XM_UNHIGHLIGHTT_H) && defined(HAVE_XM_XPMP_H)
32 # include <Xm/TraitP.h>
33 # include <Xm/Manager.h>
34 # include <Xm/UnhighlightT.h>
40 #include <Xm/ManagerP.h>
41 #include <Xm/Display.h>
42 #include <Xm/DisplayP.h>
44 #include <X11/Shell.h>
45 #include <X11/ShellP.h>
47 #include "gui_xmebwp.h"
49 /* Provide some missing wrappers, which are missed from the LessTif
50 * implementation. Also missing in Motif 1.2 and earlier.
52 * We neither use XmeGetPixmapData or _XmGetPixmapData, since with LessTif the
53 * pixmap will not appear in it's caches properly. We cache the interesting
54 * values in XmEnhancedButtonPart instead ourself.
56 #if defined(LESSTIF_VERSION) || (XmVersion <= 1002)
57 # ifndef Lab_IsMenupane
58 # define Lab_IsMenupane(w) (Lab_MenuType(w) == (int)XmMENU_POPUP || \
59 Lab_MenuType(w) == (int)XmMENU_PULLDOWN)
61 # define XmeClearBorder _XmClearBorder
62 # define XmeDrawShadows _XmDrawShadows
63 # define XmeDrawHighlight(a, b, c, d, e, f, g, h) \
64 _XmDrawHighlight(a, b, c, d, e, f, g, h, LineSolid)
68 * Motif internals we have to cheat around with.
71 /* Hopefully this will never change... */
72 #ifndef XmFOCUS_IGNORE
73 # define XmFOCUS_IGNORE 1<<1
76 extern Boolean
_XmGetInDragMode(Widget widget
);
77 extern void _XmPrimitiveEnter(Widget wid
,
79 String
* params
, Cardinal
* num_params
);
80 extern void _XmPrimitiveLeave(Widget wid
,
82 String
* params
, Cardinal
* num_params
);
83 extern void _XmSetFocusFlag(Widget w
, unsigned int mask
, Boolean value
);
84 extern void _XmCalcLabelDimensions(Widget wid
);
87 * Declaration of class methods.
89 static void Destroy(Widget w
);
90 static void Initialize(Widget rq
, Widget eb
, ArgList args
, Cardinal
*n
);
91 static Boolean
SetValues(Widget current
, Widget request
, Widget
new, ArgList args
, Cardinal
*n
);
92 static void Redisplay(Widget
, XEvent
*, Region
);
95 * Declaration of action methods.
97 static void Enter(Widget
, XEvent
*, String
*, Cardinal
*);
98 static void Leave(Widget
, XEvent
*, String
*, Cardinal
*);
99 static void BorderHighlight(Widget
);
100 static void BorderUnhighlight(Widget
);
103 * 4 x 4 stipple for desensitized widgets
105 #define stipple_width 4
106 #define stipple_height 4
107 static char stipple_bits
[] = { 0x0a, 0x05, 0x0a, 0x05 };
108 #define STIPPLE_BITMAP xmEnhancedButtonClassRec.enhancedbutton_class.stipple_bitmap
113 static XtActionsRec actionsList
[] =
119 static XtResource resources
[] =
122 XmNpixmapData
, XmCPixmap
, XmRString
, sizeof(String
),
123 XtOffsetOf(XmEnhancedButtonRec
, enhancedbutton
.pixmap_data
),
124 XmRImmediate
, (XtPointer
) NULL
126 XmNpixmapFile
, XmCPixmap
, XmRString
, sizeof(String
),
127 XtOffsetOf(XmEnhancedButtonRec
, enhancedbutton
.pixmap_file
),
128 XmRImmediate
, (XtPointer
) NULL
130 XmNspacing
, XmCSpacing
, XmRHorizontalDimension
, sizeof(Dimension
),
131 XtOffsetOf(XmEnhancedButtonRec
, enhancedbutton
.spacing
),
132 XmRImmediate
, (XtPointer
) 2
135 XmNlabelLocation
, XmCLocation
, XmRInt
, sizeof(int),
136 XtOffsetOf(XmEnhancedButtonRec
, enhancedbutton
.label_location
),
137 XtRImmediate
, (XtPointer
) XmRIGHT
141 /* This is needed to work around a bug in Lesstif 2, leaving the extension
142 * NULL somehow results in getting it set to an invalid pointer. */
143 XmPrimitiveClassExtRec xmEnhancedButtonPrimClassExtRec
=
145 /* next_extension */ NULL
,
146 /* record_type */ NULLQUARK
,
147 /* version */ XmPrimitiveClassExtVersion
,
148 /* record_size */ sizeof(XmPrimitiveClassExtRec
),
149 /* widget_baseline */ XmInheritBaselineProc
,
150 /* widget_display_rect */ XmInheritDisplayRectProc
,
151 /* widget_margins */ NULL
154 XmEnhancedButtonClassRec xmEnhancedButtonClassRec
=
157 /* core_class fields */
158 /* superclass */ (WidgetClass
) & xmPushButtonClassRec
,
159 /* class_name */ "XmEnhancedButton",
160 /* widget_size */ sizeof(XmEnhancedButtonRec
),
161 /* class_initialize */ NULL
,
162 /* class_part_initialize */ NULL
,
163 /* class_inited */ False
,
164 /* initialize */ Initialize
,
165 /* initialize_hook */ NULL
,
166 /* realize */ XtInheritRealize
,
167 /* actions */ actionsList
,
168 /* num_actions */ XtNumber(actionsList
),
169 /* resources */ resources
,
170 /* num_resources */ XtNumber(resources
),
171 /* xrm_class */ NULLQUARK
,
172 /* compress_motion */ True
,
173 /* compress_exposure */ XtExposeCompressMaximal
,
174 /* compress_enterleave */ True
,
175 /* visible_interest */ False
,
176 /* destroy */ Destroy
,
177 /* resize */ XtInheritResize
,
178 /* expose */ Redisplay
,
179 /* set_values */ SetValues
,
180 /* set_values_hook */ NULL
,
181 /* set_values_almost */ XtInheritSetValuesAlmost
,
182 /* get_values_hook */ NULL
,
183 /* accept_focus */ XtInheritAcceptFocus
,
184 /* version */ XtVersion
,
185 /* callback_private */ NULL
,
187 /* query_geometry */ NULL
,
188 /* display_accelerator */ XtInheritDisplayAccelerator
,
192 /* primitive_class fields */
194 /* border highlight */ BorderHighlight
,
195 /* border_unhighlight */ BorderUnhighlight
,
196 /* translations */ XtInheritTranslations
,
197 /* arm and activate */ XmInheritArmAndActivate
,
198 /* synthetic resources */ NULL
,
199 /* number of syn res */ 0,
200 /* extension */ (XtPointer
)&xmEnhancedButtonPrimClassExtRec
,
203 /* label_class fields */
205 /* setOverrideCallback */ XmInheritSetOverrideCallback
,
206 /* menuProcs */ XmInheritMenuProc
,
207 /* translations */ XtInheritTranslations
,
208 /* extension */ NULL
,
211 /* pushbutton_class record */
213 /* extension */ (XtPointer
) NULL
,
216 /* enhancedbutton_class fields */
218 /* stipple_bitmap */ None
223 WidgetClass xmEnhancedButtonWidgetClass
=
224 (WidgetClass
)&xmEnhancedButtonClassRec
;
228 * Create a slightly fainter pixmap to be shown on button entry.
230 static unsigned short
231 bump_color(unsigned short value
)
233 int tmp
= 2 * (((int) value
- 65535) / 3) + 65535;
240 alloc_color(Display
*display
,
249 if (!XParseColor(display
, colormap
, colorname
, xcolor
))
252 xcolor
->red
= bump_color(xcolor
->red
);
253 xcolor
->green
= bump_color(xcolor
->green
);
254 xcolor
->blue
= bump_color(xcolor
->blue
);
256 status
= XAllocColor(display
, colormap
, xcolor
);
257 return status
!= 0 ? 1 : 0;
261 static char * blank_xpm
[] =
263 /* width height ncolors cpp [x_hot y_hot] */
266 " s iconColor1 m black c #000000",
267 ". s none m none c none",
268 "X s topShadowColor m none c #DCDEE5",
269 "o s bottomShadowColor m black c #5D6069",
288 set_pixmap(XmEnhancedButtonWidget eb
)
290 /* Configure defines XPMATTRIBUTES_TYPE as XpmAttributes or as
291 * XpmAttributes_21, depending on what is in Xm/XpmP.h. */
292 XPMATTRIBUTES_TYPE attr
;
295 static XpmColorSymbol color
[8] = {
298 {"background", NULL
, 0},
299 {"foreground", NULL
, 0},
300 {"bottomShadowColor", NULL
, 0},
301 {"topShadowColor", NULL
, 0},
302 {"highlightColor", NULL
, 0},
303 {"armColor", NULL
, 0}
306 Display
*dpy
= XtDisplay(eb
);
309 unsigned int height
, width
, border
, depth
;
313 Pixmap arm_pix
= None
;
314 Pixmap ins_pix
= None
;
315 Pixmap high_pix
= None
;
316 char **data
= (char **) eb
->enhancedbutton
.pixmap_data
;
317 char *fname
= (char *) eb
->enhancedbutton
.pixmap_file
;
321 /* Make sure there is a default value for the pixmap.
326 gc
= XtGetGC((Widget
)eb
, (XtGCMask
)0, NULL
);
328 scr
= DefaultScreen(dpy
);
329 root
= RootWindow(dpy
, scr
);
331 eb
->label
.pixmap
= None
;
333 eb
->enhancedbutton
.pixmap_depth
= 0;
334 eb
->enhancedbutton
.pixmap_width
= 0;
335 eb
->enhancedbutton
.pixmap_height
= 0;
336 eb
->enhancedbutton
.normal_pixmap
= None
;
337 eb
->enhancedbutton
.armed_pixmap
= None
;
338 eb
->enhancedbutton
.highlight_pixmap
= None
;
339 eb
->enhancedbutton
.insensitive_pixmap
= None
;
341 /* We use dynamic colors, get them now. */
342 motif_get_toolbar_colors(
343 &eb
->core
.background_pixel
,
344 &eb
->primitive
.foreground
,
345 &eb
->primitive
.bottom_shadow_color
,
346 &eb
->primitive
.top_shadow_color
,
347 &eb
->primitive
.highlight_color
);
349 /* Setup color subsititution table. */
350 color
[0].pixel
= eb
->core
.background_pixel
;
351 color
[1].pixel
= eb
->core
.background_pixel
;
352 color
[2].pixel
= eb
->core
.background_pixel
;
353 color
[3].pixel
= eb
->primitive
.foreground
;
354 color
[4].pixel
= eb
->core
.background_pixel
;
355 color
[5].pixel
= eb
->primitive
.top_shadow_color
;
356 color
[6].pixel
= eb
->primitive
.highlight_color
;
357 color
[7].pixel
= eb
->pushbutton
.arm_color
;
359 /* Create the "sensitive" pixmap. */
360 attr
.valuemask
= XpmColorSymbols
| XpmCloseness
;
361 attr
.closeness
= 65535; /* accuracy isn't crucial */
362 attr
.colorsymbols
= color
;
363 attr
.numsymbols
= XtNumber(color
);
366 status
= XpmReadFileToPixmap(dpy
, root
, fname
, &pix
, &mask
, &attr
);
367 if (!fname
|| status
!= XpmSuccess
)
368 status
= XpmCreatePixmapFromData(dpy
, root
, data
, &pix
, &mask
, &attr
);
370 /* If something failed, we will fill in the default pixmap. */
371 if (status
!= XpmSuccess
)
372 status
= XpmCreatePixmapFromData(dpy
, root
, blank_xpm
, &pix
,
375 XpmFreeAttributes(&attr
);
377 XGetGeometry(dpy
, pix
, &root
, &x
, &y
, &width
, &height
, &border
, &depth
);
379 if (eb
->enhancedbutton
.label_location
== (int)XmTOP
380 || eb
->enhancedbutton
.label_location
== (int)XmBOTTOM
)
381 shift
= eb
->primitive
.shadow_thickness
/ 2;
383 shift
= eb
->primitive
.shadow_thickness
/ 2;
388 sen_pix
= XCreatePixmap(dpy
, root
, width
+ shift
, height
+ shift
, depth
);
390 XSetForeground(dpy
, gc
, eb
->core
.background_pixel
);
391 XFillRectangle(dpy
, sen_pix
, gc
, 0, 0, width
+ shift
, height
+ shift
);
392 XSetClipMask(dpy
, gc
, mask
);
393 XSetClipOrigin(dpy
, gc
, shift
, shift
);
394 XCopyArea(dpy
, pix
, sen_pix
, gc
, 0, 0, width
, height
, shift
, shift
);
396 /* Create the "highlight" pixmap. */
397 color
[4].pixel
= eb
->primitive
.bottom_shadow_color
;
398 #ifdef XpmAllocColor /* SGI doesn't have it */
399 attr
.valuemask
= XpmColorSymbols
| XpmCloseness
| XpmAllocColor
;
400 attr
.alloc_color
= alloc_color
;
402 attr
.valuemask
= XpmColorSymbols
| XpmCloseness
;
404 attr
.closeness
= 65535; /* accuracy isn't crucial */
405 attr
.colorsymbols
= color
;
406 attr
.numsymbols
= XtNumber(color
);
408 status
= XpmCreatePixmapFromData(dpy
, root
, data
, &pix
, NULL
, &attr
);
409 XpmFreeAttributes(&attr
);
411 high_pix
= XCreatePixmap(dpy
, root
, width
+ shift
, height
+ shift
, depth
);
414 XSetForeground(dpy
, gc
, eb
->core
.background_pixel
);
416 XSetForeground(dpy
, gc
, eb
->primitive
.top_shadow_color
);
418 XSetClipMask(dpy
, gc
, None
);
419 XFillRectangle(dpy
, high_pix
, gc
, 0, 0, width
+ shift
, height
+ shift
);
420 XSetClipMask(dpy
, gc
, mask
);
421 XSetClipOrigin(dpy
, gc
, 0, 0);
422 XCopyArea(dpy
, pix
, high_pix
, gc
, 0, 0, width
, height
, 0, 0);
424 arm_pix
= XCreatePixmap(dpy
, pix
, width
+ shift
, height
+ shift
, depth
);
426 if (eb
->pushbutton
.fill_on_arm
)
427 XSetForeground(dpy
, gc
, eb
->pushbutton
.arm_color
);
429 XSetForeground(dpy
, gc
, eb
->core
.background_pixel
);
430 XSetClipOrigin(dpy
, gc
, shift
, shift
);
431 XSetClipMask(dpy
, gc
, None
);
432 XFillRectangle(dpy
, arm_pix
, gc
, 0, 0, width
+ shift
, height
+ shift
);
433 XSetClipMask(dpy
, gc
, mask
);
434 XSetClipOrigin(dpy
, gc
, 2 * shift
, 2 * shift
);
435 XCopyArea(dpy
, pix
, arm_pix
, gc
, 0, 0, width
, height
, 2 * shift
, 2 * shift
);
437 XFreePixmap(dpy
, pix
);
438 XFreePixmap(dpy
, mask
);
440 /* Create the "insensitive" pixmap. */
441 attr
.valuemask
= XpmColorSymbols
| XpmCloseness
| XpmColorKey
;
442 attr
.closeness
= 65535; /* accuracy isn't crucial */
443 attr
.colorsymbols
= color
;
444 attr
.numsymbols
= sizeof(color
) / sizeof(color
[0]);
445 attr
.color_key
= XPM_MONO
;
446 status
= XpmCreatePixmapFromData(dpy
, root
, data
, &pix
, &mask
, &attr
);
448 /* Need to create new Pixmaps with the mask applied. */
450 ins_pix
= XCreatePixmap(dpy
, root
, width
+ shift
, height
+ shift
, depth
);
452 XSetForeground(dpy
, gc
, eb
->core
.background_pixel
);
453 XSetClipOrigin(dpy
, gc
, 0, 0);
454 XSetClipMask(dpy
, gc
, None
);
455 XFillRectangle(dpy
, ins_pix
, gc
, 0, 0, width
+ shift
, height
+ shift
);
456 XSetClipMask(dpy
, gc
, mask
);
457 XSetForeground(dpy
, gc
, eb
->primitive
.top_shadow_color
);
458 XSetClipOrigin(dpy
, gc
, 2 * shift
, 2 * shift
);
459 XFillRectangle(dpy
, ins_pix
, gc
, 2 * shift
, 2 * shift
, width
, height
);
460 XSetForeground(dpy
, gc
, eb
->primitive
.bottom_shadow_color
);
461 XSetClipOrigin(dpy
, gc
, shift
, shift
);
462 XFillRectangle(dpy
, ins_pix
, gc
, 0, 0, width
+ shift
, height
+ shift
);
463 XtReleaseGC((Widget
) eb
, gc
);
465 XpmFreeAttributes(&attr
);
467 eb
->enhancedbutton
.pixmap_depth
= depth
;
468 eb
->enhancedbutton
.pixmap_width
= width
;
469 eb
->enhancedbutton
.pixmap_height
= height
;
470 eb
->enhancedbutton
.normal_pixmap
= sen_pix
;
471 eb
->enhancedbutton
.highlight_pixmap
= high_pix
;
472 eb
->enhancedbutton
.insensitive_pixmap
= ins_pix
;
473 eb
->enhancedbutton
.armed_pixmap
= arm_pix
;
475 eb
->enhancedbutton
.doing_setvalues
= True
;
476 eb
->enhancedbutton
.doing_setvalues
= False
;
478 XFreePixmap(dpy
, pix
);
479 XFreePixmap(dpy
, mask
);
482 #define BUTTON_MASK ( \
483 Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask \
487 draw_shadows(XmEnhancedButtonWidget eb
)
493 if (!eb
->primitive
.shadow_thickness
)
496 if ((eb
->core
.width
<= 2 * eb
->primitive
.highlight_thickness
)
497 || (eb
->core
.height
<= 2 * eb
->primitive
.highlight_thickness
))
500 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
504 dpy
= (XmDisplay
) XmGetXmDisplay(XtDisplay(eb
));
505 etched_in
= dpy
->display
.enable_etched_in_menu
;
510 if (!etched_in
^ eb
->pushbutton
.armed
)
512 top_gc
= eb
->primitive
.top_shadow_GC
;
513 bottom_gc
= eb
->primitive
.bottom_shadow_GC
;
517 top_gc
= eb
->primitive
.bottom_shadow_GC
;
518 bottom_gc
= eb
->primitive
.top_shadow_GC
;
521 XmeDrawShadows(XtDisplay(eb
), XtWindow(eb
),
524 eb
->primitive
.highlight_thickness
,
525 eb
->primitive
.highlight_thickness
,
526 eb
->core
.width
- 2 * eb
->primitive
.highlight_thickness
,
527 eb
->core
.height
- 2 * eb
->primitive
.highlight_thickness
,
528 eb
->primitive
.shadow_thickness
,
529 (unsigned)(etched_in
? XmSHADOW_IN
: XmSHADOW_OUT
));
533 draw_highlight(XmEnhancedButtonWidget eb
)
535 eb
->primitive
.highlighted
= True
;
536 eb
->primitive
.highlight_drawn
= True
;
538 if (!XtWidth(eb
) || !XtHeight(eb
) || !eb
->primitive
.highlight_thickness
)
541 XmeDrawHighlight(XtDisplay(eb
), XtWindow(eb
),
542 eb
->primitive
.highlight_GC
, 0, 0,
543 XtWidth(eb
), XtHeight(eb
),
544 eb
->primitive
.highlight_thickness
);
548 draw_unhighlight(XmEnhancedButtonWidget eb
)
550 GC manager_background_GC
;
552 eb
->primitive
.highlighted
= False
;
553 eb
->primitive
.highlight_drawn
= False
;
555 if (!XtWidth(eb
) || !XtHeight(eb
) || !eb
->primitive
.highlight_thickness
)
558 if (XmIsManager(eb
->core
.parent
))
561 XmSpecifyUnhighlightTrait UnhighlightT
;
563 if (((UnhighlightT
= (XmSpecifyUnhighlightTrait
) XmeTraitGet((XtPointer
)
564 XtClass(eb
->core
.parent
), XmQTspecifyUnhighlight
))
565 != NULL
) && (UnhighlightT
->getUnhighlightGC
!= NULL
))
567 /* if unhighlight trait in parent use specified GC... */
568 manager_background_GC
=
569 UnhighlightT
->getUnhighlightGC(eb
->core
.parent
, (Widget
) eb
);
573 /* ...otherwise, use parent's background GC */
574 manager_background_GC
= ((XmManagerWidget
)
575 (eb
->core
.parent
))->manager
.background_GC
;
578 manager_background_GC
= ((XmManagerWidget
)
579 (eb
->core
.parent
))->manager
.background_GC
;
581 XmeDrawHighlight(XtDisplay(eb
), XtWindow(eb
),
582 manager_background_GC
,
583 0, 0, XtWidth(eb
), XtHeight(eb
),
584 eb
->primitive
.highlight_thickness
);
585 if (!eb
->pushbutton
.armed
&& eb
->primitive
.shadow_thickness
)
586 XmeClearBorder(XtDisplay(eb
), XtWindow(eb
),
587 eb
->primitive
.highlight_thickness
,
588 eb
->primitive
.highlight_thickness
,
589 eb
->core
.width
- 2 * eb
->primitive
.highlight_thickness
,
590 eb
->core
.height
- 2 * eb
->primitive
.highlight_thickness
,
591 eb
->primitive
.shadow_thickness
);
594 XmeClearBorder(XtDisplay(eb
), XtWindow(eb
), 0, 0, XtWidth(eb
),
595 XtHeight(eb
), eb
->primitive
.highlight_thickness
);
600 draw_pixmap(XmEnhancedButtonWidget eb
, XEvent
*event
, Region region
)
603 GC gc
= eb
->label
.normal_GC
;
612 if (!XtIsSensitive((Widget
) eb
))
613 pix
= eb
->enhancedbutton
.insensitive_pixmap
;
616 if (eb
->primitive
.highlighted
&& !eb
->pushbutton
.armed
)
617 pix
= eb
->enhancedbutton
.highlight_pixmap
;
618 else if (eb
->pushbutton
.armed
)
619 pix
= eb
->enhancedbutton
.armed_pixmap
;
621 pix
= eb
->enhancedbutton
.normal_pixmap
;
624 if (pix
== None
|| !eb
->enhancedbutton
.pixmap_data
)
627 depth
= eb
->enhancedbutton
.pixmap_depth
;
628 w
= eb
->enhancedbutton
.pixmap_width
;
629 h
= eb
->enhancedbutton
.pixmap_height
;
631 gc
= eb
->label
.normal_GC
;
632 x
= eb
->primitive
.highlight_thickness
633 + eb
->primitive
.shadow_thickness
634 + eb
->label
.margin_width
;
635 y
= eb
->primitive
.highlight_thickness
636 + eb
->primitive
.shadow_thickness
637 + eb
->label
.margin_height
;
638 width
= eb
->core
.width
- 2 * x
;
641 height
= eb
->core
.height
- 2 * y
;
644 if (depth
== eb
->core
.depth
)
645 XCopyArea(XtDisplay(eb
), pix
, XtWindow(eb
), gc
, 0, 0,
646 width
, height
, x
, y
);
648 XCopyPlane(XtDisplay(eb
), pix
, XtWindow(eb
), gc
, 0, 0,
649 width
, height
, x
, y
, (unsigned long)1);
653 * Draw the label contained in the pushbutton.
656 draw_label(XmEnhancedButtonWidget eb
, XEvent
*event
, Region region
)
659 Boolean replaceGC
= False
;
660 Boolean deadjusted
= False
;
661 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
662 XmDisplay dpy
= (XmDisplay
)XmGetXmDisplay(XtDisplay(eb
));
663 Boolean etched_in
= dpy
->display
.enable_etched_in_menu
;
665 Boolean etched_in
= False
;
668 if (eb
->pushbutton
.armed
669 && ((!Lab_IsMenupane(eb
) && eb
->pushbutton
.fill_on_arm
)
670 || (Lab_IsMenupane(eb
) && etched_in
)))
672 if (eb
->label
.label_type
== (int)XmSTRING
673 && eb
->pushbutton
.arm_color
== eb
->primitive
.foreground
)
675 tmp_gc
= eb
->label
.normal_GC
;
676 eb
->label
.normal_GC
= eb
->pushbutton
.background_gc
;
682 * If the button contains a labeled pixmap, we will take it instead of our
686 if (eb
->label
.label_type
== (int)XmPIXMAP
)
688 if (eb
->pushbutton
.armed
)
690 if (eb
->pushbutton
.arm_pixmap
!= XmUNSPECIFIED_PIXMAP
)
691 eb
->label
.pixmap
= eb
->pushbutton
.arm_pixmap
;
693 eb
->label
.pixmap
= eb
->pushbutton
.unarm_pixmap
;
696 /* pushbutton is not armed */
697 eb
->label
.pixmap
= eb
->pushbutton
.unarm_pixmap
;
701 * Temporarily remove the Xm3D_ENHANCE_PIXEL hack ("adjustment") from the
702 * margin values, so we don't confuse Label.
704 if (eb
->pushbutton
.default_button_shadow_thickness
> 0)
707 Lab_MarginLeft(eb
) -= Xm3D_ENHANCE_PIXEL
;
708 Lab_MarginRight(eb
) -= Xm3D_ENHANCE_PIXEL
;
709 Lab_MarginTop(eb
) -= Xm3D_ENHANCE_PIXEL
;
710 Lab_MarginBottom(eb
) -= Xm3D_ENHANCE_PIXEL
;
717 expose
= xmLabelClassRec
.core_class
.expose
;
719 (*expose
)((Widget
) eb
, event
, region
);
724 Lab_MarginLeft(eb
) += Xm3D_ENHANCE_PIXEL
;
725 Lab_MarginRight(eb
) += Xm3D_ENHANCE_PIXEL
;
726 Lab_MarginTop(eb
) += Xm3D_ENHANCE_PIXEL
;
727 Lab_MarginBottom(eb
) += Xm3D_ENHANCE_PIXEL
;
731 eb
->label
.normal_GC
= tmp_gc
;
736 Enter(Widget wid
, XEvent
*event
, String
*params
, Cardinal
*num_params
)
738 XmEnhancedButtonWidget eb
= (XmEnhancedButtonWidget
) wid
;
739 XmPushButtonCallbackStruct call_value
;
741 if (Lab_IsMenupane(eb
))
743 if ((((ShellWidget
) XtParent(XtParent(eb
)))->shell
.popped_up
)
744 && _XmGetInDragMode((Widget
) eb
))
746 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
747 XmDisplay dpy
= (XmDisplay
) XmGetXmDisplay(XtDisplay(wid
));
748 Boolean etched_in
= dpy
->display
.enable_etched_in_menu
;
750 Boolean etched_in
= False
;
753 if (eb
->pushbutton
.armed
)
756 /* ...so KHelp event is delivered correctly. */
757 _XmSetFocusFlag(XtParent(XtParent(eb
)), XmFOCUS_IGNORE
, TRUE
);
758 XtSetKeyboardFocus(XtParent(XtParent(eb
)), (Widget
) eb
);
759 _XmSetFocusFlag(XtParent(XtParent(eb
)), XmFOCUS_IGNORE
, FALSE
);
761 eb
->pushbutton
.armed
= TRUE
;
763 ((XmManagerWidget
) XtParent(wid
))->manager
.active_child
= wid
;
765 /* etched in menu button */
766 if (etched_in
&& !XmIsTearOffButton(eb
))
768 XFillRectangle(XtDisplay(eb
), XtWindow(eb
),
769 eb
->pushbutton
.fill_gc
,
770 0, 0, eb
->core
.width
, eb
->core
.height
);
771 draw_label(eb
, event
, NULL
);
772 draw_pixmap(eb
, event
, NULL
);
775 if ((eb
->core
.width
> 2 * eb
->primitive
.highlight_thickness
)
776 && (eb
->core
.height
>
777 2 * eb
->primitive
.highlight_thickness
))
779 XmeDrawShadows(XtDisplay(eb
), XtWindow(eb
),
780 eb
->primitive
.top_shadow_GC
,
781 eb
->primitive
.bottom_shadow_GC
,
782 eb
->primitive
.highlight_thickness
,
783 eb
->primitive
.highlight_thickness
,
784 eb
->core
.width
- 2 * eb
->primitive
.highlight_thickness
,
785 eb
->core
.height
- 2 * eb
->primitive
.highlight_thickness
,
786 eb
->primitive
.shadow_thickness
,
787 (unsigned)(etched_in
? XmSHADOW_IN
: XmSHADOW_OUT
));
790 if (eb
->pushbutton
.arm_callback
)
792 XFlush(XtDisplay(eb
));
794 call_value
.reason
= (int)XmCR_ARM
;
795 call_value
.event
= event
;
796 XtCallCallbackList((Widget
) eb
,
797 eb
->pushbutton
.arm_callback
,
806 _XmPrimitiveEnter((Widget
) eb
, event
, NULL
, NULL
);
807 if (eb
->pushbutton
.armed
== TRUE
)
810 expose
= XtClass(eb
)->core_class
.expose
;
812 (*expose
) (wid
, event
, (Region
) NULL
);
817 draw_pixmap(eb
, event
, NULL
);
823 Leave(Widget wid
, XEvent
*event
, String
*params
, Cardinal
*num_params
)
825 XmEnhancedButtonWidget eb
= (XmEnhancedButtonWidget
)wid
;
826 XmPushButtonCallbackStruct call_value
;
828 if (Lab_IsMenupane(eb
))
830 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
831 XmDisplay dpy
= (XmDisplay
) XmGetXmDisplay(XtDisplay(wid
));
832 Boolean etched_in
= dpy
->display
.enable_etched_in_menu
;
834 Boolean etched_in
= False
;
837 if (_XmGetInDragMode((Widget
)eb
)
838 && eb
->pushbutton
.armed
839 && ( /* !ActiveTearOff || */
840 event
->xcrossing
.mode
== NotifyNormal
))
842 eb
->pushbutton
.armed
= FALSE
;
844 ((XmManagerWidget
) XtParent(wid
))->manager
.active_child
= NULL
;
846 if (etched_in
&& !XmIsTearOffButton(eb
))
848 XFillRectangle(XtDisplay(eb
), XtWindow(eb
),
849 eb
->pushbutton
.background_gc
,
850 0, 0, eb
->core
.width
, eb
->core
.height
);
851 draw_label(eb
, event
, NULL
);
852 draw_pixmap(eb
, event
, NULL
);
856 (XtDisplay(eb
), XtWindow(eb
),
857 eb
->primitive
.highlight_thickness
,
858 eb
->primitive
.highlight_thickness
,
860 2 * eb
->primitive
.highlight_thickness
,
862 2 * eb
->primitive
.highlight_thickness
,
863 eb
->primitive
.shadow_thickness
);
865 if (eb
->pushbutton
.disarm_callback
)
867 XFlush(XtDisplay(eb
));
869 call_value
.reason
= (int)XmCR_DISARM
;
870 call_value
.event
= event
;
871 XtCallCallbackList((Widget
) eb
,
872 eb
->pushbutton
.disarm_callback
,
879 _XmPrimitiveLeave((Widget
) eb
, event
, NULL
, NULL
);
881 if (eb
->pushbutton
.armed
== TRUE
)
884 eb
->pushbutton
.armed
= FALSE
;
886 expose
= XtClass(eb
)->core_class
.expose
;
888 (*expose
) (wid
, event
, (Region
)NULL
);
889 draw_unhighlight(eb
);
890 draw_pixmap(eb
, event
, NULL
);
891 eb
->pushbutton
.armed
= TRUE
;
895 draw_unhighlight(eb
);
896 draw_pixmap(eb
, event
, NULL
);
901 #define IsNull(p) ((p) == XmUNSPECIFIED_PIXMAP)
904 set_size(XmEnhancedButtonWidget newtb
)
909 _XmCalcLabelDimensions((Widget
) newtb
);
911 /* Find out how big the pixmap is */
912 if (newtb
->enhancedbutton
.pixmap_data
913 && !IsNull(newtb
->label
.pixmap
)
914 && !IsNull(newtb
->enhancedbutton
.normal_pixmap
))
916 w
= newtb
->enhancedbutton
.pixmap_width
;
917 h
= newtb
->enhancedbutton
.pixmap_height
;
921 * Plase note that we manipulate the width only in case of push buttons not
922 * used in the context of a menu pane.
924 if (Lab_IsMenupane(newtb
))
926 newtb
->label
.margin_left
= w
+ 2 * (newtb
->primitive
.shadow_thickness
927 + newtb
->primitive
.highlight_thickness
)
928 + newtb
->label
.margin_width
;
932 newtb
->label
.margin_left
= w
;
933 newtb
->core
.width
= w
+ 2 * (newtb
->primitive
.shadow_thickness
934 + newtb
->primitive
.highlight_thickness
935 + newtb
->label
.margin_width
)
936 + newtb
->label
.TextRect
.width
;
938 if (newtb
->label
.TextRect
.width
> 0)
940 newtb
->label
.margin_left
+= newtb
->label
.margin_width
941 + newtb
->primitive
.shadow_thickness
;
942 newtb
->core
.width
+= newtb
->label
.margin_width
943 + newtb
->primitive
.shadow_thickness
;
946 if (newtb
->label
.TextRect
.height
< h
)
948 newtb
->core
.height
= h
+ 2 * (newtb
->primitive
.shadow_thickness
949 + newtb
->primitive
.highlight_thickness
950 + newtb
->label
.margin_height
);
954 /* FIXME: We should calculate an drawing offset for the pixmap here to
959 printf("%d %d %d %d %d %d - %d %d\n", newtb
->enhancedbutton
.normal_pixmap
,
960 h
, newtb
->core
.height
,
961 newtb
->primitive
.shadow_thickness
,
962 newtb
->primitive
.highlight_thickness
,
963 newtb
->label
.margin_height
,
968 /* Invoke Label's Resize procedure. */
972 resize
= xmLabelClassRec
.core_class
.resize
;
975 (* resize
) ((Widget
) newtb
);
981 Initialize(Widget rq
, Widget ebw
, ArgList args
, Cardinal
*n
)
983 XmEnhancedButtonWidget request
= (XmEnhancedButtonWidget
)rq
;
984 XmEnhancedButtonWidget eb
= (XmEnhancedButtonWidget
)ebw
;
988 resize
= xmLabelClassRec
.core_class
.resize
;
991 /* Create a bitmap for stippling (Drawable resources are cheap). */
992 if (STIPPLE_BITMAP
== None
)
994 Display
*dpy
= XtDisplay((Widget
) request
);
995 Window rootW
= DefaultRootWindow(dpy
);
997 STIPPLE_BITMAP
= XCreateBitmapFromData(dpy
, rootW
, stipple_bits
,
998 stipple_width
, stipple_height
);
1000 eb
->enhancedbutton
.doing_setvalues
= False
;
1002 /* First see what type of extended label this is.
1004 if (eb
->enhancedbutton
.pixmap_data
)
1009 /* FIXME: this is not the perfect way to deal with menues, which do not
1010 * have any string set right now. */
1011 str
= XmStringCreateLocalized("");
1012 XtVaSetValues((Widget
) eb
, XmNlabelString
, str
, NULL
);
1015 eb
->label
.pixmap
= eb
->enhancedbutton
.normal_pixmap
;
1017 if (request
->core
.width
== 0)
1019 if (request
->core
.height
== 0)
1020 eb
->core
.height
= 0;
1023 (* resize
)((Widget
)eb
);
1027 free_pixmaps(XmEnhancedButtonWidget eb
)
1030 * Clear the old pixmaps.
1032 Pixmap norm_pix
= eb
->enhancedbutton
.normal_pixmap
;
1033 Pixmap arm_pix
= eb
->enhancedbutton
.armed_pixmap
;
1034 Pixmap insen_pix
= eb
->enhancedbutton
.insensitive_pixmap
;
1035 Pixmap high_pix
= eb
->enhancedbutton
.highlight_pixmap
;
1037 if (norm_pix
!= None
&& norm_pix
!= XmUNSPECIFIED_PIXMAP
)
1038 XFreePixmap(XtDisplay(eb
), norm_pix
);
1040 if (arm_pix
!= None
&& arm_pix
!= XmUNSPECIFIED_PIXMAP
)
1041 XFreePixmap(XtDisplay(eb
), arm_pix
);
1043 if (insen_pix
!= None
&& insen_pix
!= XmUNSPECIFIED_PIXMAP
)
1044 XFreePixmap(XtDisplay(eb
), insen_pix
);
1046 if (high_pix
!= None
&& high_pix
!= XmUNSPECIFIED_PIXMAP
)
1047 XFreePixmap(XtDisplay(eb
), high_pix
);
1053 if (!XmIsEnhancedButton(w
))
1056 free_pixmaps((XmEnhancedButtonWidget
)w
);
1061 SetValues(Widget current
, Widget request
, Widget
new, ArgList args
, Cardinal
*n
)
1063 XmEnhancedButtonWidget cur
= (XmEnhancedButtonWidget
) current
;
1064 XmEnhancedButtonWidget eb
= (XmEnhancedButtonWidget
) new;
1065 Boolean redraw
= False
;
1066 Boolean change
= True
;
1067 Display
*dpy
= XtDisplay(current
);
1069 #define NOT_EQUAL(field) (cur->field != eb->field)
1072 * Make sure that lost sensitivity is causing the border to vanish as well.
1074 if (NOT_EQUAL(core
.sensitive
) && !Lab_IsMenupane(current
))
1076 if (cur
->core
.sensitive
== True
)
1078 draw_unhighlight(eb
);
1084 unsigned int r_height
;
1085 unsigned int r_width
;
1086 unsigned int r_border
;
1087 unsigned int r_depth
;
1098 * Artificially let the highlight appear if the mouse is over us.
1100 /* Best way to get the root window of object: */
1101 XGetGeometry(dpy
, XtWindow(cur
), &root
, &r_x
, &r_y
, &r_width
,
1102 &r_height
, &r_border
, &r_depth
);
1103 XQueryPointer(XtDisplay(cur
), XtWindow(cur
), &root_q
, &child
,
1104 &root_x
, &root_y
, &win_x
, &win_y
, &mask
);
1108 if ((win_x
< 0) || (win_y
< 0))
1111 if ((win_x
> r_width
) || (win_y
> r_height
))
1122 * Check for changed ExtLabelString.
1124 if (NOT_EQUAL(primitive
.shadow_thickness
))
1127 /* Don't change the pixmaps */
1131 if (NOT_EQUAL(primitive
.foreground
))
1133 if (NOT_EQUAL(core
.background_pixel
))
1135 if (NOT_EQUAL(pushbutton
.fill_on_arm
))
1137 if (NOT_EQUAL(enhancedbutton
.spacing
))
1139 if (NOT_EQUAL(enhancedbutton
.label_location
))
1144 if (NOT_EQUAL(label
._label
))
1154 if (eb
->primitive
.highlighted
)
1155 eb
->label
.pixmap
= eb
->enhancedbutton
.highlight_pixmap
;
1157 eb
->label
.pixmap
= eb
->enhancedbutton
.normal_pixmap
;
1167 Redisplay(Widget w
, XEvent
*event
, Region region
)
1169 XmEnhancedButtonWidget eb
= (XmEnhancedButtonWidget
) w
;
1170 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
1172 XtEnum default_button_emphasis
;
1179 if (!XtIsRealized((Widget
)eb
))
1182 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
1183 dpy
= (XmDisplay
)XmGetXmDisplay(XtDisplay(eb
));
1184 default_button_emphasis
= dpy
->display
.default_button_emphasis
;
1188 * Compute the area allocated to the label of the pushbutton; fill in the
1189 * dimensions in the box.
1192 if ((eb
->pushbutton
.arm_color
== eb
->primitive
.top_shadow_color
)
1193 || (eb
->pushbutton
.arm_color
== eb
->primitive
.bottom_shadow_color
))
1196 if (eb
->pushbutton
.compatible
)
1197 adjust
= eb
->pushbutton
.show_as_default
;
1199 adjust
= eb
->pushbutton
.default_button_shadow_thickness
;
1203 adjust
= adjust
+ eb
->primitive
.shadow_thickness
;
1204 adjust
= (adjust
<< 1);
1205 dx
= eb
->primitive
.highlight_thickness
+ adjust
+ fill
;
1208 dx
= (eb
->primitive
.highlight_thickness
1209 + eb
->primitive
.shadow_thickness
+ fill
);
1214 box
.width
= eb
->core
.width
- adjust
;
1215 box
.height
= eb
->core
.height
- adjust
;
1218 * Redraw the background.
1220 if (!Lab_IsMenupane(eb
))
1224 /* Don't shade if the button contains a label with a pixmap, since
1225 * there is no variant of the label available with the needed
1228 if (eb
->pushbutton
.armed
&& eb
->pushbutton
.fill_on_arm
)
1230 if (eb
->label
.label_type
== (int)XmPIXMAP
)
1232 if (eb
->pushbutton
.arm_pixmap
!= XmUNSPECIFIED_PIXMAP
)
1233 gc
= eb
->pushbutton
.fill_gc
;
1235 gc
= eb
->pushbutton
.background_gc
;
1238 gc
= eb
->pushbutton
.fill_gc
;
1241 gc
= eb
->pushbutton
.background_gc
;
1242 /* really need to fill with background if not armed ? */
1244 XFillRectangle(XtDisplay(eb
), XtWindow(eb
), gc
,
1245 box
.x
, box
.y
, box
.width
, box
.height
);
1248 draw_label(eb
, event
, region
);
1250 if (Lab_IsMenupane(eb
))
1252 if (eb
->pushbutton
.armed
)
1253 (*(((XmPushButtonWidgetClass
)XtClass(eb
))
1254 ->primitive_class
.border_highlight
))(w
);
1255 draw_pixmap(eb
, event
, region
);
1261 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
1263 * NOTE: PushButton has two types of shadows: primitive-shadow and
1264 * default-button-shadow. If pushbutton is in a menu only primitive
1265 * shadows are drawn.
1267 switch (default_button_emphasis
)
1269 case XmEXTERNAL_HIGHLIGHT
:
1270 adjust
= (eb
->primitive
.highlight_thickness
-
1271 (eb
->pushbutton
.default_button_shadow_thickness
?
1272 Xm3D_ENHANCE_PIXEL
: 0));
1275 case XmINTERNAL_HIGHLIGHT
:
1286 * Clear the area not occupied by label with parents background color.
1287 * Label will invoke BorderUnhighlight() on the highlight_thickness
1288 * area, which is redundant when XmEXTERNAL_HIGHLIGHT default button
1289 * shadow emphasis is used.
1293 int borderwidth
=box
.x
- adjust
;
1294 int rectwidth
= eb
->core
.width
- 2 * adjust
;
1295 int rectheight
= eb
->core
.height
- 2 * adjust
;
1297 if (XmIsManager(XtParent(eb
)))
1299 XmeDrawHighlight(XtDisplay(eb
), XtWindow(eb
),
1300 XmParentBackgroundGC(eb
),
1301 adjust
, adjust
, rectwidth
, rectheight
, borderwidth
);
1305 XmeClearBorder(XtDisplay(eb
), XtWindow(eb
),
1306 adjust
, adjust
, rectwidth
, rectheight
, borderwidth
);
1309 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
1310 switch (default_button_emphasis
)
1312 case XmINTERNAL_HIGHLIGHT
:
1313 /* The call above erases the border highlighting. */
1314 if (eb
->primitive
.highlight_drawn
)
1315 (*(((XmPushButtonWidgetClass
) XtClass (eb
))
1316 ->primitive_class
.border_highlight
)) ((Widget
) eb
) ;
1325 if (eb
->pushbutton
.default_button_shadow_thickness
)
1327 if (eb
->pushbutton
.show_as_default
)
1330 * - get the topShadowColor and bottomShadowColor from the
1331 * parent; use those colors to construct top and bottom gc;
1332 * use these GCs to draw the shadows of the button.
1334 * - Should not be called if pushbutton is in a row column or
1337 * - Should be called only if a defaultbuttonshadow is to be
1342 int default_button_shadow_thickness
;
1343 int x
, y
, width
, height
, delta
;
1346 if (eb
->pushbutton
.compatible
1347 && (eb
->pushbutton
.show_as_default
== 0))
1350 if (!eb
->pushbutton
.compatible
1351 && (eb
->pushbutton
.default_button_shadow_thickness
1355 delta
= eb
->primitive
.highlight_thickness
;
1358 * May need more complex computation for getting the GCs.
1360 parent
= XtParent(eb
);
1361 if (XmIsManager(parent
))
1363 /* Use the parent's GC so monochrome works. */
1364 bottom_gc
= XmParentTopShadowGC(eb
);
1365 top_gc
= XmParentBottomShadowGC(eb
);
1369 /* Use your own pixel for drawing. */
1370 bottom_gc
= eb
->primitive
.top_shadow_GC
;
1371 top_gc
= eb
->primitive
.bottom_shadow_GC
;
1374 if ((bottom_gc
== None
) || (top_gc
== None
))
1378 if (eb
->pushbutton
.compatible
)
1379 default_button_shadow_thickness
=
1380 eb
->pushbutton
.show_as_default
;
1382 default_button_shadow_thickness
=
1383 eb
->pushbutton
.default_button_shadow_thickness
;
1385 #if !defined(LESSTIF_VERSION) && (XmVersion > 1002)
1387 * Compute location of bounding box to contain the
1388 * defaultButtonShadow.
1390 switch (default_button_emphasis
)
1392 case XmEXTERNAL_HIGHLIGHT
:
1393 delta
= eb
->primitive
.highlight_thickness
;
1396 case XmINTERNAL_HIGHLIGHT
:
1397 delta
= Xm3D_ENHANCE_PIXEL
;
1407 width
= eb
->core
.width
- 2 * delta
;
1408 height
= eb
->core
.height
- 2 * delta
;
1410 if ((width
> 0) && (height
> 0))
1411 XmeDrawShadows(XtDisplay(eb
), XtWindow(eb
),
1412 top_gc
, bottom_gc
, x
, y
, width
, height
,
1413 default_button_shadow_thickness
,
1414 (unsigned)XmSHADOW_OUT
);
1418 if (eb
->primitive
.highlight_drawn
)
1420 draw_pixmap(eb
, event
, region
);
1425 BorderHighlight(Widget w
)
1427 XmEnhancedButtonWidget eb
= (XmEnhancedButtonWidget
)w
;
1429 (*(xmPushButtonClassRec
.primitive_class
.border_highlight
))(w
);
1430 draw_pixmap(eb
, NULL
, NULL
);
1434 BorderUnhighlight(Widget w
)
1436 XmEnhancedButtonWidget eb
= (XmEnhancedButtonWidget
)w
;
1438 (*(xmPushButtonClassRec
.primitive_class
.border_unhighlight
))(w
);
1439 draw_pixmap(eb
, NULL
, NULL
);
1442 #endif /* FEAT_TOOLBAR */