diff options
Diffstat (limited to 'src/gui_xmebw.c')
-rw-r--r-- | src/gui_xmebw.c | 1406 |
1 files changed, 1406 insertions, 0 deletions
diff --git a/src/gui_xmebw.c b/src/gui_xmebw.c new file mode 100644 index 000000000..fbe0ba99b --- /dev/null +++ b/src/gui_xmebw.c @@ -0,0 +1,1406 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ +/* + * + * (C) 2002,2005 by Marcin Dalecki <martin@dalecki.de> + * + * MARCIN DALECKI ASSUMES NO RESPONSIBILITY FOR THE USE OR INABILITY TO USE ANY + * OF THIS SOFTWARE . THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + * KIND, AND MARCIN DALECKI EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES, + * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * Enhanced Motif PushButton widget with move over behaviour. + */ + +#include <ctype.h> +#include <stdio.h> +#include <assert.h> + +#include <Xm/XmP.h> +#include <Xm/DrawP.h> +#ifndef LESSTIF_VERSION +# include <Xm/TraitP.h> +# include <Xm/Manager.h> +# include <Xm/UnhighlightT.h> +# include <Xm/XpmP.h> +#else +# include <X11/xpm.h> +#endif +#include <Xm/ManagerP.h> +#include <Xm/Display.h> +#include <Xm/DisplayP.h> + +#include <X11/Shell.h> +#include <X11/ShellP.h> + +#include "gui_xmebwp.h" + +/* Provide some missing wrappers, which are missed from the LessTif + * implementation. + * + * We neither use XmeGetPixmapData or _XmGetPixmapData, since with LessTif the + * pixmap will not appear in it's caches properly. We cache the interresting + * values in XmEnhancedButtonPart instead ourself. + */ +#ifdef LESSTIF_VERSION +# ifndef Lab_IsMenupane +# define Lab_IsMenupane(w) (Lab_MenuType(w) == (int)XmMENU_POPUP || \ + Lab_MenuType(w) == (int)XmMENU_PULLDOWN) +# endif +# define XmeClearBorder _XmClearBorder +# define XmeDrawShadows _XmDrawShadows +# define XmeDrawHighlight(a, b, c, d, e, f, g, h) \ + _XmDrawHighlight(a, b, c, d, e, f, g, h, LineSolid) +#endif + +/* + * Motif internals we have to cheat around with. + */ + +/* Hopefully this will never change... */ +#ifndef XmFOCUS_IGNORE +# define XmFOCUS_IGNORE 1<<1 +#endif + +extern Boolean _XmGetInDragMode(Widget widget); +extern void _XmPrimitiveEnter(Widget wid, + XEvent * event, + String * params, Cardinal * num_params); +extern void _XmPrimitiveLeave(Widget wid, + XEvent * event, + String * params, Cardinal * num_params); +extern void _XmSetFocusFlag(Widget w, unsigned int mask, Boolean value); +extern void _XmCalcLabelDimensions(Widget wid); + +/* + * Declaration of class methods. + */ +static void Destroy(Widget w); +static void Initialize(Widget rq, Widget eb, ArgList args, Cardinal *n); +static Boolean SetValues(Widget current, Widget request, Widget new, ArgList args, Cardinal *n); +static void Redisplay(Widget, XEvent *, Region); + +/* + * Declaration of action methods. + */ +static void Enter(Widget, XEvent *, String *, Cardinal *); +static void Leave(Widget, XEvent *, String *, Cardinal *); +static void BorderHighlight(Widget); +static void BorderUnhighlight(Widget); + +/* + * 4 x 4 stipple for desensitized widgets + */ +#define stipple_width 4 +#define stipple_height 4 +static char stipple_bits[] = { 0x0a, 0x05, 0x0a, 0x05 }; +#define STIPPLE_BITMAP xmEnhancedButtonClassRec.enhancedbutton_class.stipple_bitmap + +/* + * Override actions. + */ +static XtActionsRec actionsList[] = +{ + {"Enter", Enter}, + {"Leave", Leave}, +}; + +static XtResource resources[] = +{ + { + XmNpixmapData, XmCPixmap, XmRString, sizeof(String), + XtOffsetOf(XmEnhancedButtonRec, enhancedbutton.pixmap_data), + XmRImmediate, (XtPointer) NULL + }, { + XmNpixmapFile, XmCPixmap, XmRString, sizeof(String), + XtOffsetOf(XmEnhancedButtonRec, enhancedbutton.pixmap_file), + XmRImmediate, (XtPointer) NULL + }, { + XmNspacing, XmCSpacing, XmRHorizontalDimension, sizeof(Dimension), + XtOffsetOf(XmEnhancedButtonRec, enhancedbutton.spacing), + XmRImmediate, (XtPointer) 2 + }, + { + XmNlabelLocation, XmCLocation, XmRInt, sizeof(int), + XtOffsetOf(XmEnhancedButtonRec, enhancedbutton.label_location), + XtRImmediate, (XtPointer) XmRIGHT + } +}; + +XmEnhancedButtonClassRec xmEnhancedButtonClassRec = +{ + { + /* core_class fields */ + /* superclass */ (WidgetClass) & xmPushButtonClassRec, + /* class_name */ "XmEnhancedButton", + /* widget_size */ sizeof(XmEnhancedButtonRec), + /* class_initialize */ NULL, + /* class_part_initialize */ NULL, + /* class_inited */ False, + /* initialize */ Initialize, + /* initialize_hook */ NULL, + /* realize */ XtInheritRealize, + /* actions */ actionsList, + /* num_actions */ XtNumber(actionsList), + /* resources */ resources, + /* num_resources */ XtNumber(resources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ True, + /* compress_exposure */ XtExposeCompressMaximal, + /* compress_enterleave */ True, + /* visible_interest */ False, + /* destroy */ Destroy, + /* resize */ XtInheritResize, + /* expose */ Redisplay, + /* set_values */ SetValues, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ NULL, + /* accept_focus */ XtInheritAcceptFocus, + /* version */ XtVersion, + /* callback_private */ NULL, + /* tm_table */ NULL, + /* query_geometry */ NULL, + /* display_accelerator */ XtInheritDisplayAccelerator, + /* extension */ NULL + }, + + /* primitive_class fields */ + { + /* border highlight */ BorderHighlight, + /* border_unhighlight */ BorderUnhighlight, + /* translations */ XtInheritTranslations, + /* arm and activate */ XmInheritArmAndActivate, + /* synthetic resources */ NULL, + /* number of syn res */ 0, + /* extension */ NULL, + }, + + /* label_class fields */ + { + /* setOverrideCallback */ XmInheritSetOverrideCallback, + /* menuProcs */ XmInheritMenuProc, + /* translations */ XtInheritTranslations, + /* extension */ NULL, + }, + + /* pushbutton_class record */ + { + /* extension */ (XtPointer) NULL, + }, + + /* enhancedbutton_class fields */ + { + /* stipple_bitmap */ None + } +}; + + +WidgetClass xmEnhancedButtonWidgetClass = + (WidgetClass)&xmEnhancedButtonClassRec; + + +/* + * Create a slightly fainter pixmap to be shown on button entry. + */ + static unsigned short +bump_color(unsigned short value) +{ + int tmp = 2 * (((int) value - 65535) / 3) + 65535; + + return tmp; +} + +/*ARGSUSED*/ + static int +alloc_color(Display *display, + Colormap colormap, + char *colorname, + XColor *xcolor, + void *closure) +{ + int status; + + if (colorname) + if (!XParseColor(display, colormap, colorname, xcolor)) + return -1; + + xcolor->red = bump_color(xcolor->red); + xcolor->green = bump_color(xcolor->green); + xcolor->blue = bump_color(xcolor->blue); + + status = XAllocColor(display, colormap, xcolor); + return status != 0 ? 1 : 0; +} + +/* XPM */ +static char * blank_xpm[] = +{ +/* width height ncolors cpp [x_hot y_hot] */ +"12 12 4 1 0 0", +/* colors */ +" s iconColor1 m black c #000000", +". s none m none c none", +"X s topShadowColor m none c #DCDEE5", +"o s bottomShadowColor m black c #5D6069", +/* pixels */ +" ..", +" XXXXXXXX ..", +" X....... o.", +" X....... o.", +" X....... o.", +" X....... o.", +" X....... o.", +" X....... o.", +" X....... o.", +" o.", +"..ooooooooo.", +"............"}; + +/* + * Set the pixmap. + */ + static void +set_pixmap(XmEnhancedButtonWidget eb) +{ + XpmAttributes attr; + Pixmap sen_pix; + Window root; + static XpmColorSymbol color[8] = { + {"none", "none", 0}, + {"None", "none", 0}, + {"background", NULL, 0}, + {"foreground", NULL, 0}, + {"bottomShadowColor", NULL, 0}, + {"topShadowColor", NULL, 0}, + {"highlightColor", NULL, 0}, + {"armColor", NULL, 0} + }; + int scr; + Display *dpy = XtDisplay(eb); + int x; + int y; + unsigned int height, width, border, depth; + int status; + Pixmap mask; + Pixmap pix = None; + Pixmap arm_pix = None; + Pixmap ins_pix = None; + Pixmap high_pix = None; + char **data = (char **) eb->enhancedbutton.pixmap_data; + int shift; + GC gc; + + /* Make sure there is a default value for the pixmap. + */ + if (!data) + return; + + gc = XtGetGC((Widget)eb, (XtGCMask)0, NULL); + + scr = DefaultScreen(dpy); + root = RootWindow(dpy, scr); + + eb->label.pixmap = None; + eb->enhancedbutton.pixmap_depth = 0; + eb->enhancedbutton.pixmap_width = 0; + eb->enhancedbutton.pixmap_height = 0; + eb->enhancedbutton.normal_pixmap = None; + eb->enhancedbutton.armed_pixmap = None; + eb->enhancedbutton.highlight_pixmap = None; + eb->enhancedbutton.insensitive_pixmap = None; + + /* Setup color subsititution table. */ + color[0].pixel = eb->core.background_pixel; + color[1].pixel = eb->core.background_pixel; + color[2].pixel = eb->core.background_pixel; + color[3].pixel = eb->primitive.foreground; + color[4].pixel = eb->core.background_pixel; + color[5].pixel = eb->primitive.top_shadow_color; + color[6].pixel = eb->primitive.highlight_color; + color[7].pixel = eb->pushbutton.arm_color; + + /* Create the "sensitive" pixmap. */ + attr.valuemask = XpmColorSymbols | XpmCloseness; + attr.closeness = 65535; /* accuracy isn't crucial */ + attr.colorsymbols = color; + attr.numsymbols = XtNumber(color); + + status = XpmCreatePixmapFromData(dpy, root, data, &pix, &mask, &attr); + + /* If somethin failed, we will fill in the default pixmap. */ + if (status != XpmSuccess) + status = XpmCreatePixmapFromData(dpy, root, blank_xpm, &pix, + &mask, &attr); + + XpmFreeAttributes(&attr); + + XGetGeometry(dpy, pix, &root, &x, &y, &width, &height, &border, &depth); + + if (eb->enhancedbutton.label_location == XmTOP + || eb->enhancedbutton.label_location == XmBOTTOM) + shift = eb->primitive.shadow_thickness / 2; + else + shift = eb->primitive.shadow_thickness / 2; + + if (shift < 1) + shift = 1; + + sen_pix = XCreatePixmap(dpy, root, width + shift, height + shift, depth); + + XSetForeground(dpy, gc, eb->core.background_pixel); + XFillRectangle(dpy, sen_pix, gc, 0, 0, width + shift, height + shift); + XSetClipMask(dpy, gc, mask); + XSetClipOrigin(dpy, gc, shift, shift); + XCopyArea(dpy, pix, sen_pix, gc, 0, 0, width, height, shift, shift); + + /* Create the "highlight" pixmap. */ + color[4].pixel = eb->primitive.bottom_shadow_color; + attr.valuemask = XpmColorSymbols | XpmCloseness | XpmAllocColor; + attr.closeness = 65535; /* accuracy isn't crucial */ + attr.colorsymbols = color; + attr.numsymbols = XtNumber(color); + attr.alloc_color = alloc_color; + + status = XpmCreatePixmapFromData(dpy, root, data, &pix, NULL, &attr); + XpmFreeAttributes(&attr); + + high_pix = XCreatePixmap(dpy, root, width + shift, height + shift, depth); + +#if 1 + XSetForeground(dpy, gc, eb->core.background_pixel); +#else + XSetForeground(dpy, gc, eb->primitive.top_shadow_color); +#endif + XSetClipMask(dpy, gc, None); + XFillRectangle(dpy, high_pix, gc, 0, 0, width + shift, height + shift); + XSetClipMask(dpy, gc, mask); + XSetClipOrigin(dpy, gc, 0, 0); + XCopyArea(dpy, pix, high_pix, gc, 0, 0, width, height, 0, 0); + + arm_pix = XCreatePixmap(dpy, pix, width + shift, height + shift, depth); + + if (eb->pushbutton.fill_on_arm) + XSetForeground(dpy, gc, eb->pushbutton.arm_color); + else + XSetForeground(dpy, gc, eb->core.background_pixel); + XSetClipOrigin(dpy, gc, shift, shift); + XSetClipMask(dpy, gc, None); + XFillRectangle(dpy, arm_pix, gc, 0, 0, width + shift, height + shift); + XSetClipMask(dpy, gc, mask); + XSetClipOrigin(dpy, gc, 2 * shift, 2 * shift); + XCopyArea(dpy, pix, arm_pix, gc, 0, 0, width, height, 2 * shift, 2 * shift); + + XFreePixmap(dpy, pix); + XFreePixmap(dpy, mask); + + /* Create the "insensitive" pixmap. */ + attr.valuemask = XpmColorSymbols | XpmCloseness | XpmColorKey; + attr.closeness = 65535; /* accuracy isn't crucial */ + attr.colorsymbols = color; + attr.numsymbols = sizeof(color) / sizeof(color[0]); + attr.color_key = XPM_MONO; + status = XpmCreatePixmapFromData(dpy, root, data, &pix, &mask, &attr); + + /* Need to create new Pixmaps with the mask applied. */ + + ins_pix = XCreatePixmap(dpy, root, width + shift, height + shift, depth); + + XSetForeground(dpy, gc, eb->core.background_pixel); + XSetClipOrigin(dpy, gc, 0, 0); + XSetClipMask(dpy, gc, None); + XFillRectangle(dpy, ins_pix, gc, 0, 0, width + shift, height + shift); + XSetClipMask(dpy, gc, mask); + XSetForeground(dpy, gc, eb->primitive.top_shadow_color); + XSetClipOrigin(dpy, gc, 2 * shift, 2 * shift); + XFillRectangle(dpy, ins_pix, gc, 2 * shift, 2 * shift, width, height); + XSetForeground(dpy, gc, eb->primitive.bottom_shadow_color); + XSetClipOrigin(dpy, gc, shift, shift); + XFillRectangle(dpy, ins_pix, gc, 0, 0, width + shift, height + shift); + XtReleaseGC((Widget) eb, gc); + + XpmFreeAttributes(&attr); + + eb->enhancedbutton.pixmap_depth = depth; + eb->enhancedbutton.pixmap_width = width; + eb->enhancedbutton.pixmap_height = height; + eb->enhancedbutton.normal_pixmap = sen_pix; + eb->enhancedbutton.highlight_pixmap = high_pix; + eb->enhancedbutton.insensitive_pixmap = ins_pix; + eb->enhancedbutton.armed_pixmap = arm_pix; + + eb->enhancedbutton.doing_setvalues = True; + eb->enhancedbutton.doing_setvalues = False; + + XFreePixmap(dpy, pix); + XFreePixmap(dpy, mask); +} + +#define BUTTON_MASK ( \ + Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask \ +) + + static void +draw_shadows(XmEnhancedButtonWidget eb) +{ + GC top_gc; + GC bottom_gc; + Boolean etched_in; + + if (!eb->primitive.shadow_thickness) + return; + + if ((eb->core.width <= 2 * eb->primitive.highlight_thickness) + || (eb->core.height <= 2 * eb->primitive.highlight_thickness)) + return; + +#ifndef LESSTIF_VERSION + { + XmDisplay dpy; + + dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(eb)); + etched_in = dpy->display.enable_etched_in_menu; + } +#else + etched_in = False; +#endif + if (!etched_in ^ eb->pushbutton.armed) + { + top_gc = eb->primitive.top_shadow_GC; + bottom_gc = eb->primitive.bottom_shadow_GC; + } + else + { + top_gc = eb->primitive.bottom_shadow_GC; + bottom_gc = eb->primitive.top_shadow_GC; + } + + XmeDrawShadows(XtDisplay(eb), XtWindow(eb), + top_gc, + bottom_gc, + eb->primitive.highlight_thickness, + eb->primitive.highlight_thickness, + eb->core.width - 2 * eb->primitive.highlight_thickness, + eb->core.height - 2 * eb->primitive.highlight_thickness, + eb->primitive.shadow_thickness, + (unsigned)(etched_in ? XmSHADOW_IN : XmSHADOW_OUT)); +} + + static void +draw_highlight(XmEnhancedButtonWidget eb) +{ + eb->primitive.highlighted = True; + eb->primitive.highlight_drawn = True; + + if (!XtWidth(eb) || !XtHeight(eb) || !eb->primitive.highlight_thickness) + return; + + XmeDrawHighlight(XtDisplay(eb), XtWindow(eb), + eb->primitive.highlight_GC, 0, 0, + XtWidth(eb), XtHeight(eb), + eb->primitive.highlight_thickness); +} + + static void +draw_unhighlight(XmEnhancedButtonWidget eb) +{ + GC manager_background_GC; + + eb->primitive.highlighted = False; + eb->primitive.highlight_drawn = False; + + if (!XtWidth(eb) || !XtHeight(eb) || !eb->primitive.highlight_thickness) + return; + + if (XmIsManager(eb->core.parent)) + { +#ifndef LESSTIF_VERSION + XmSpecifyUnhighlightTrait UnhighlightT; + + if (((UnhighlightT = (XmSpecifyUnhighlightTrait) XmeTraitGet((XtPointer) + XtClass(eb->core.parent), XmQTspecifyUnhighlight)) + != NULL) && (UnhighlightT->getUnhighlightGC != NULL)) + { + /* if unhighlight trait in parent use specified GC... */ + manager_background_GC = + UnhighlightT->getUnhighlightGC(eb->core.parent, (Widget) eb); + } + else + { + /* ...otherwise, use parent's background GC */ + manager_background_GC = ((XmManagerWidget) + (eb->core.parent))->manager.background_GC; + } +#else + manager_background_GC = ((XmManagerWidget) + (eb->core.parent))->manager.background_GC; +#endif + XmeDrawHighlight(XtDisplay(eb), XtWindow(eb), + manager_background_GC, + 0, 0, XtWidth(eb), XtHeight(eb), + eb->primitive.highlight_thickness); + if (!eb->pushbutton.armed && eb->primitive.shadow_thickness) + XmeClearBorder(XtDisplay(eb), XtWindow(eb), + eb->primitive.highlight_thickness, + eb->primitive.highlight_thickness, + eb->core.width - 2 * eb->primitive.highlight_thickness, + eb->core.height - 2 * eb->primitive.highlight_thickness, + eb->primitive.shadow_thickness); + } + else + XmeClearBorder(XtDisplay(eb), XtWindow(eb), 0, 0, XtWidth(eb), + XtHeight(eb), eb->primitive.highlight_thickness); +} + +/*ARGSUSED*/ + static void +draw_pixmap(XmEnhancedButtonWidget eb, XEvent *event, Region region) +{ + Pixmap pix; + GC gc = eb->label.normal_GC; + int depth; + Cardinal width; + Cardinal height; + Cardinal w; + Cardinal h; + int x; + int y; + + if (!XtIsSensitive((Widget) eb)) + pix = eb->enhancedbutton.insensitive_pixmap; + else + { + if (eb->primitive.highlighted && !eb->pushbutton.armed) + pix = eb->enhancedbutton.highlight_pixmap; + else if (eb->pushbutton.armed) + pix = eb->enhancedbutton.armed_pixmap; + else + pix = eb->enhancedbutton.normal_pixmap; + } + + if (pix == None || !eb->enhancedbutton.pixmap_data) + return; + + depth = eb->enhancedbutton.pixmap_depth; + w = eb->enhancedbutton.pixmap_width; + h = eb->enhancedbutton.pixmap_height; + + gc = eb->label.normal_GC; + x = eb->primitive.highlight_thickness + + eb->primitive.shadow_thickness + + eb->label.margin_width; + y = eb->primitive.highlight_thickness + + eb->primitive.shadow_thickness + + eb->label.margin_height; + width = eb->core.width - 2 * x; + if (w < width) + width = w; + height = eb->core.height - 2 * y; + if (h < height) + height = h; + if (depth == eb->core.depth) + XCopyArea(XtDisplay(eb), pix, XtWindow(eb), gc, 0, 0, + width, height, x, y); + else if (depth == 1) + XCopyPlane(XtDisplay(eb), pix, XtWindow(eb), gc, 0, 0, + width, height, x, y, (unsigned long)1); +} + +/* + * Draw the label contained in the pushbutton. + */ + static void +draw_label(XmEnhancedButtonWidget eb, XEvent *event, Region region) +{ + GC tmp_gc = NULL; + Boolean replaceGC = False; + Boolean deadjusted = False; +#ifndef LESSTIF_VERSION + XmDisplay dpy = (XmDisplay)XmGetXmDisplay(XtDisplay(eb)); + Boolean etched_in = dpy->display.enable_etched_in_menu; +#else + Boolean etched_in = False; +#endif + + if (eb->pushbutton.armed + && ((!Lab_IsMenupane(eb) && eb->pushbutton.fill_on_arm) + || (Lab_IsMenupane(eb) && etched_in))) + { + if (eb->label.label_type == (int)XmSTRING + && eb->pushbutton.arm_color == eb->primitive.foreground) + { + tmp_gc = eb->label.normal_GC; + eb->label.normal_GC = eb->pushbutton.background_gc; + replaceGC = True; + } + } + + /* + * If the button contains a labeled pixmap, we will take it instead of our + * own pixmap. + */ + + if (eb->label.label_type == (int)XmPIXMAP) + { + if (eb->pushbutton.armed) + { + if (eb->pushbutton.arm_pixmap != XmUNSPECIFIED_PIXMAP) + eb->label.pixmap = eb->pushbutton.arm_pixmap; + else + eb->label.pixmap = eb->pushbutton.unarm_pixmap; + } + else + /* pushbutton is not armed */ + eb->label.pixmap = eb->pushbutton.unarm_pixmap; + } + + /* + * Temporarily remove the Xm3D_ENHANCE_PIXEL hack ("adjustment") from the + * margin values, so we don't confuse Label. + */ + if (eb->pushbutton.default_button_shadow_thickness > 0) + { + deadjusted = True; + Lab_MarginLeft(eb) -= Xm3D_ENHANCE_PIXEL; + Lab_MarginRight(eb) -= Xm3D_ENHANCE_PIXEL; + Lab_MarginTop(eb) -= Xm3D_ENHANCE_PIXEL; + Lab_MarginBottom(eb) -= Xm3D_ENHANCE_PIXEL; + } + + { + XtExposeProc expose; + + XtProcessLock(); + expose = xmLabelClassRec.core_class.expose; + XtProcessUnlock(); + (*expose)((Widget) eb, event, region); + } + + if (deadjusted) + { + Lab_MarginLeft(eb) += Xm3D_ENHANCE_PIXEL; + Lab_MarginRight(eb) += Xm3D_ENHANCE_PIXEL; + Lab_MarginTop(eb) += Xm3D_ENHANCE_PIXEL; + Lab_MarginBottom(eb) += Xm3D_ENHANCE_PIXEL; + } + + if (replaceGC) + eb->label.normal_GC = tmp_gc; +} + +/*ARGSUSED*/ + static void +Enter(Widget wid, XEvent *event, String *params, Cardinal *num_params) +{ + XmEnhancedButtonWidget eb = (XmEnhancedButtonWidget) wid; + XmPushButtonCallbackStruct call_value; + + if (Lab_IsMenupane(eb)) + { + if ((((ShellWidget) XtParent(XtParent(eb)))->shell.popped_up) + && _XmGetInDragMode((Widget) eb)) + { +#ifndef LESSTIF_VERSION + XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(wid)); + Boolean etched_in = dpy->display.enable_etched_in_menu; +#else + Boolean etched_in = False; +#endif + + if (eb->pushbutton.armed) + return; + + /* ...so KHelp event is delivered correctly. */ + _XmSetFocusFlag(XtParent(XtParent(eb)), XmFOCUS_IGNORE, TRUE); + XtSetKeyboardFocus(XtParent(XtParent(eb)), (Widget) eb); + _XmSetFocusFlag(XtParent(XtParent(eb)), XmFOCUS_IGNORE, FALSE); + + eb->pushbutton.armed = TRUE; + + ((XmManagerWidget) XtParent(wid))->manager.active_child = wid; + + /* etched in menu button */ + if (etched_in && !XmIsTearOffButton(eb)) + { + XFillRectangle(XtDisplay(eb), XtWindow(eb), + eb->pushbutton.fill_gc, + 0, 0, eb->core.width, eb->core.height); + draw_label(eb, event, NULL); + draw_pixmap(eb, event, NULL); + } + + if ((eb->core.width > 2 * eb->primitive.highlight_thickness) + && (eb->core.height > + 2 * eb->primitive.highlight_thickness)) + { + XmeDrawShadows(XtDisplay(eb), XtWindow(eb), + eb->primitive.top_shadow_GC, + eb->primitive.bottom_shadow_GC, + eb->primitive.highlight_thickness, + eb->primitive.highlight_thickness, + eb->core.width - 2 * eb->primitive.highlight_thickness, + eb->core.height - 2 * eb->primitive.highlight_thickness, + eb->primitive.shadow_thickness, + (unsigned)(etched_in ? XmSHADOW_IN : XmSHADOW_OUT)); + } + + if (eb->pushbutton.arm_callback) + { + XFlush(XtDisplay(eb)); + + call_value.reason = (int)XmCR_ARM; + call_value.event = event; + XtCallCallbackList((Widget) eb, + eb->pushbutton.arm_callback, + &call_value); + } + } + } + else + { + XtExposeProc expose; + + _XmPrimitiveEnter((Widget) eb, event, NULL, NULL); + if (eb->pushbutton.armed == TRUE) + { + XtProcessLock(); + expose = XtClass(eb)->core_class.expose; + XtProcessUnlock(); + (*expose) (wid, event, (Region) NULL); + } + + draw_highlight(eb); + draw_shadows(eb); + draw_pixmap(eb, event, NULL); + } +} + +/*ARGSUSED*/ + static void +Leave(Widget wid, XEvent *event, String *params, Cardinal *num_params) +{ + XmEnhancedButtonWidget eb = (XmEnhancedButtonWidget)wid; + XmPushButtonCallbackStruct call_value; + + if (Lab_IsMenupane(eb)) + { +#ifndef LESSTIF_VERSION + XmDisplay dpy = (XmDisplay) XmGetXmDisplay(XtDisplay(wid)); + Boolean etched_in = dpy->display.enable_etched_in_menu; +#else + Boolean etched_in = False; +#endif + + if (_XmGetInDragMode((Widget)eb) + && eb->pushbutton.armed + && ( /* !ActiveTearOff || */ + event->xcrossing.mode == NotifyNormal)) + { + eb->pushbutton.armed = FALSE; + + ((XmManagerWidget) XtParent(wid))->manager.active_child = NULL; + + if (etched_in && !XmIsTearOffButton(eb)) + { + XFillRectangle(XtDisplay(eb), XtWindow(eb), + eb->pushbutton.background_gc, + 0, 0, eb->core.width, eb->core.height); + draw_label(eb, event, NULL); + draw_pixmap(eb, event, NULL); + } + else + XmeClearBorder + (XtDisplay(eb), XtWindow(eb), + eb->primitive.highlight_thickness, + eb->primitive.highlight_thickness, + eb->core.width - + 2 * eb->primitive.highlight_thickness, + eb->core.height - + 2 * eb->primitive.highlight_thickness, + eb->primitive.shadow_thickness); + + if (eb->pushbutton.disarm_callback) + { + XFlush(XtDisplay(eb)); + + call_value.reason = (int)XmCR_DISARM; + call_value.event = event; + XtCallCallbackList((Widget) eb, + eb->pushbutton.disarm_callback, + &call_value); + } + } + } + else + { + _XmPrimitiveLeave((Widget) eb, event, NULL, NULL); + + if (eb->pushbutton.armed == TRUE) + { + XtExposeProc expose; + eb->pushbutton.armed = FALSE; + XtProcessLock(); + expose = XtClass(eb)->core_class.expose; + XtProcessUnlock(); + (*expose) (wid, event, (Region)NULL); + draw_unhighlight(eb); + draw_pixmap(eb, event, NULL); + eb->pushbutton.armed = TRUE; + } + else + { + draw_unhighlight(eb); + draw_pixmap(eb, event, NULL); + } + } +} + +#define IsNull(p) ((p) == XmUNSPECIFIED_PIXMAP) + + static void +set_size(XmEnhancedButtonWidget newtb) +{ + unsigned int w = 0; + unsigned int h = 0; + + _XmCalcLabelDimensions((Widget) newtb); + + /* Find out how big the pixmap is */ + if (newtb->enhancedbutton.pixmap_data + && !IsNull(newtb->label.pixmap) + && !IsNull(newtb->enhancedbutton.normal_pixmap)) + { + w = newtb->enhancedbutton.pixmap_width; + h = newtb->enhancedbutton.pixmap_height; + } + + /* + * Plase note that we manipulate the width only in case of push buttons not + * used in the context of a menu pane. + */ + if (Lab_IsMenupane(newtb)) + { + newtb->label.margin_left = w + 2 * (newtb->primitive.shadow_thickness + + newtb->primitive.highlight_thickness) + + newtb->label.margin_width; + } + else + { + newtb->label.margin_left = w; + newtb->core.width = w + 2 * (newtb->primitive.shadow_thickness + + newtb->primitive.highlight_thickness + + newtb->label.margin_width) + + newtb->label.TextRect.width; + + if (newtb->label.TextRect.width > 0) + { + newtb->label.margin_left += newtb->label.margin_width + + newtb->primitive.shadow_thickness; + newtb->core.width += newtb->label.margin_width + + newtb->primitive.shadow_thickness; + } + } + if (newtb->label.TextRect.height < h) + { + newtb->core.height = h + 2 * (newtb->primitive.shadow_thickness + + newtb->primitive.highlight_thickness + + newtb->label.margin_height); + } + else + { + /* FIXME: We should calculate an drawing offset for the pixmap here to + * adjust it. */ + } + +#if 0 + printf("%d %d %d %d %d %d - %d %d\n", newtb->enhancedbutton.normal_pixmap, + h, newtb->core.height, + newtb->primitive.shadow_thickness, + newtb->primitive.highlight_thickness, + newtb->label.margin_height, + newtb->core.width, + newtb->core.height); +#endif + + /* Invoke Label's Resize procedure. */ + { + XtWidgetProc resize; + XtProcessLock(); + resize = xmLabelClassRec.core_class.resize; + XtProcessUnlock(); + + (* resize) ((Widget) newtb); + } +} + +/*ARGSUSED*/ + static void +Initialize(Widget rq, Widget ebw, ArgList args, Cardinal *n) +{ + XmEnhancedButtonWidget request = (XmEnhancedButtonWidget)rq; + XmEnhancedButtonWidget eb = (XmEnhancedButtonWidget)ebw; + XtWidgetProc resize; + + XtProcessLock(); + resize = xmLabelClassRec.core_class.resize; + XtProcessUnlock(); + + /* Create a bitmap for stippling (Drawable resources are cheap). */ + if (STIPPLE_BITMAP == None) + { + Display *dpy = XtDisplay((Widget) request); + Window rootW = DefaultRootWindow(dpy); + + STIPPLE_BITMAP = XCreateBitmapFromData(dpy, rootW, stipple_bits, + stipple_width, stipple_height); + } + eb->enhancedbutton.doing_setvalues = False; + + /* First see what type of extended label this is. + */ + if (eb->enhancedbutton.pixmap_data) + { + XmString str; + set_pixmap(eb); + + /* FIXME: this is not the perfect way to deal with menues, which do not + * have any string set right now. */ + str = XmStringCreateLocalized(""); + XtVaSetValues((Widget) eb, XmNlabelString, str, NULL); + XmStringFree(str); + } + eb->label.pixmap = eb->enhancedbutton.normal_pixmap; + + if (request->core.width == 0) + eb->core.width = 0; + if (request->core.height == 0) + eb->core.height = 0; + set_size(eb); + + (* resize)((Widget)eb); +} + + static void +free_pixmaps(XmEnhancedButtonWidget eb) +{ + /* + * Clear the old pixmaps. + */ + Pixmap norm_pix = eb->enhancedbutton.normal_pixmap; + Pixmap arm_pix = eb->enhancedbutton.armed_pixmap; + Pixmap insen_pix = eb->enhancedbutton.insensitive_pixmap; + Pixmap high_pix = eb->enhancedbutton.highlight_pixmap; + + if (norm_pix != None && norm_pix != XmUNSPECIFIED_PIXMAP) + XFreePixmap(XtDisplay(eb), norm_pix); + + if (arm_pix != None && arm_pix != XmUNSPECIFIED_PIXMAP) + XFreePixmap(XtDisplay(eb), arm_pix); + + if (insen_pix != None && insen_pix != XmUNSPECIFIED_PIXMAP) + XFreePixmap(XtDisplay(eb), insen_pix); + + if (high_pix != None && high_pix != XmUNSPECIFIED_PIXMAP) + XFreePixmap(XtDisplay(eb), high_pix); +} + + static void +Destroy(Widget w) +{ + if (!XmIsEnhancedButton(w)) + return; + + free_pixmaps((XmEnhancedButtonWidget)w); +} + +/*ARGSUSED*/ + static Boolean +SetValues(Widget current, Widget request, Widget new, ArgList args, Cardinal *n) +{ + XmEnhancedButtonWidget cur = (XmEnhancedButtonWidget) current; + XmEnhancedButtonWidget eb = (XmEnhancedButtonWidget) new; + Boolean redraw = False; + Boolean change = True; + Display *dpy = XtDisplay(current); + +#define NOT_EQUAL(field) (cur->field != eb->field) + + /* + * Make sure that lost sensitivity is causing the border to vanish as well. + */ + if (NOT_EQUAL(core.sensitive) && !Lab_IsMenupane(current)) + { + if (cur->core.sensitive == True) + { + draw_unhighlight(eb); + } + else + { + int r_x; + int r_y; + unsigned int r_height; + unsigned int r_width; + unsigned int r_border; + unsigned int r_depth; + int root_x; + int root_y; + int win_x; + int win_y; + Window root; + Window root_q; + Window child; + unsigned int mask; + + /* + * Aritificially let the highlight appear if the mouse is over us. + */ + /* Best way to get the root window of object: */ + XGetGeometry(dpy, XtWindow(cur), &root, &r_x, &r_y, &r_width, + &r_height, &r_border, &r_depth); + XQueryPointer(XtDisplay(cur), XtWindow(cur), &root_q, &child, + &root_x, &root_y, &win_x, &win_y, &mask); + + if (root == root_q) + { + if ((win_x < 0) || (win_y < 0)) + return False; + + if ((win_x > r_width) || (win_y > r_height)) + return False; + draw_highlight(eb); + draw_shadows(eb); + } + } + + return True; + } + + /* + * Check for changed ExtLabelString. + */ + if (NOT_EQUAL(primitive.shadow_thickness)) + { + redraw = True; + /* Don't change the pixmaps */ + change = False; + } + + if (NOT_EQUAL(primitive.foreground)) + redraw = True; + if (NOT_EQUAL(core.background_pixel)) + redraw = True; + if (NOT_EQUAL(pushbutton.fill_on_arm)) + redraw = True; + if (NOT_EQUAL(enhancedbutton.spacing)) + redraw = True; + if (NOT_EQUAL(enhancedbutton.label_location)) + { + redraw = True; + change = False; + } + if (NOT_EQUAL(label._label)) + { + redraw = True; + set_size(eb); + } + + if (redraw == True) + { + if (change) + set_pixmap(eb); + if (eb->primitive.highlighted) + eb->label.pixmap = eb->enhancedbutton.highlight_pixmap; + else + eb->label.pixmap = eb->enhancedbutton.normal_pixmap; + if (change) + set_size(eb); + redraw = False; + } + + return redraw; +} + + static void +Redisplay(Widget w, XEvent *event, Region region) +{ + XmEnhancedButtonWidget eb = (XmEnhancedButtonWidget) w; +#ifndef LESSTIF_VERSION + XmDisplay dpy; + XtEnum default_button_emphasis; +#endif + XRectangle box; + int dx; + int adjust; + short fill = 0; + + if (!XtIsRealized((Widget)eb)) + return; + +#ifndef LESSTIF_VERSION + dpy = (XmDisplay)XmGetXmDisplay(XtDisplay(eb)); + default_button_emphasis = dpy->display.default_button_emphasis; +#endif + + /* + * Compute the area allocated to the label of the pushbutton; fill in the + * dimensions in the box. + */ + + if ((eb->pushbutton.arm_color == eb->primitive.top_shadow_color) + || (eb->pushbutton.arm_color == eb->primitive.bottom_shadow_color)) + fill = 1; + + if (eb->pushbutton.compatible) + adjust = eb->pushbutton.show_as_default; + else + adjust = eb->pushbutton.default_button_shadow_thickness; + + if (adjust > 0) + { + adjust = adjust + eb->primitive.shadow_thickness; + adjust = (adjust << 1); + dx = eb->primitive.highlight_thickness + adjust + fill; + } + else + dx = (eb->primitive.highlight_thickness + + eb->primitive.shadow_thickness + fill); + + box.x = dx; + box.y = dx; + adjust = (dx << 1); + box.width = eb->core.width - adjust; + box.height = eb->core.height - adjust; + + /* + * Redraw the background. + */ + if (!Lab_IsMenupane(eb)) + { + GC gc; + + /* Don't shade if the button contains a label with a pixmap, since + * there is no variant of the label available with the needed + * background. + */ + if (eb->pushbutton.armed && eb->pushbutton.fill_on_arm) + { + if (eb->label.label_type == (int)XmPIXMAP) + { + if (eb->pushbutton.arm_pixmap != XmUNSPECIFIED_PIXMAP) + gc = eb->pushbutton.fill_gc; + else + gc = eb->pushbutton.background_gc; + } + else + gc = eb->pushbutton.fill_gc; + } + else + gc = eb->pushbutton.background_gc; + /* really need to fill with background if not armed ? */ + if (gc) + XFillRectangle(XtDisplay(eb), XtWindow(eb), gc, + box.x, box.y, box.width, box.height); + } + + draw_label(eb, event, region); + + if (Lab_IsMenupane(eb)) + { + if (eb->pushbutton.armed) + (*(((XmPushButtonWidgetClass)XtClass(eb)) + ->primitive_class.border_highlight))(w); + draw_pixmap(eb, event, region); + } + else + { + int adjust = 0; + +#ifndef LESSTIF_VERSION + /* + * NOTE: PushButton has two types of shadows: primitive-shadow and + * default-button-shadow. If pushbutton is in a menu only primitive + * shadows are drawn. + */ + switch (default_button_emphasis) + { + case XmEXTERNAL_HIGHLIGHT: + adjust = (eb->primitive.highlight_thickness - + (eb->pushbutton.default_button_shadow_thickness ? + Xm3D_ENHANCE_PIXEL : 0)); + break; + + case XmINTERNAL_HIGHLIGHT: + adjust = 0; + break; + + default: + assert(FALSE); + return; + } +#endif + + /* + * Clear the area not occupied by label with parents background color. + * Label will invoke BorderUnhighlight() on the highlight_thickness + * area, which is redundant when XmEXTERNAL_HIGHLIGHT default button + * shadow emphasis is used. + */ + if (box.x > adjust) + { + int borderwidth =box.x - adjust; + int rectwidth = eb->core.width - 2 * adjust; + int rectheight = eb->core.height - 2 * adjust; + + if (XmIsManager(XtParent(eb))) + { + XmeDrawHighlight(XtDisplay(eb), XtWindow(eb), + XmParentBackgroundGC(eb), + adjust, adjust, rectwidth, rectheight, borderwidth); + } + else + { + XmeClearBorder(XtDisplay(eb), XtWindow(eb), + adjust, adjust, rectwidth, rectheight, borderwidth); + } + +#ifndef LESSTIF_VERSION + switch (default_button_emphasis) + { + case XmINTERNAL_HIGHLIGHT: + /* The call above erases the border highlighting. */ + if (eb->primitive.highlight_drawn) + (*(((XmPushButtonWidgetClass) XtClass (eb)) + ->primitive_class.border_highlight)) ((Widget) eb) ; + break; + + default: + break; + } +#endif + } + + if (eb->pushbutton.default_button_shadow_thickness) + { + if (eb->pushbutton.show_as_default) + { + /* + * - get the topShadowColor and bottomShadowColor from the + * parent; use those colors to construct top and bottom gc; + * use these GCs to draw the shadows of the button. + * + * - Should not be called if pushbutton is in a row column or + * in a menu. + * + * - Should be called only if a defaultbuttonshadow is to be + * drawn. + */ + GC top_gc; + GC bottom_gc; + int default_button_shadow_thickness; + int x, y, width, height, delta; + Widget parent; + + if (eb->pushbutton.compatible + && (eb->pushbutton.show_as_default == 0)) + return; + + if (!eb->pushbutton.compatible + && (eb->pushbutton.default_button_shadow_thickness + == 0)) + return; + + delta = eb->primitive.highlight_thickness; + + /* + * May need more complex computation for getting the GCs. + */ + parent = XtParent(eb); + if (XmIsManager(parent)) + { + /* Use the parent's GC so monochrome works. */ + bottom_gc = XmParentTopShadowGC(eb); + top_gc = XmParentBottomShadowGC(eb); + } + else + { + /* Use your own pixel for drawing. */ + bottom_gc = eb->primitive.top_shadow_GC; + top_gc = eb->primitive.bottom_shadow_GC; + } + + if ((bottom_gc == None) || (top_gc == None)) + return; + + + if (eb->pushbutton.compatible) + default_button_shadow_thickness = + eb->pushbutton.show_as_default; + else + default_button_shadow_thickness = + eb->pushbutton.default_button_shadow_thickness; + +#ifndef LESSTIF_VERSION + /* + * Compute location of bounding box to contain the + * defaultButtonShadow. + */ + switch (default_button_emphasis) + { + case XmEXTERNAL_HIGHLIGHT: + delta = eb->primitive.highlight_thickness; + break; + + case XmINTERNAL_HIGHLIGHT: + delta = Xm3D_ENHANCE_PIXEL; + break; + + default: + assert(FALSE); + return; + } +#endif + + x = y = delta; + width = eb->core.width - 2 * delta; + height = eb->core.height - 2 * delta; + + if ((width > 0) && (height > 0)) + XmeDrawShadows(XtDisplay(eb), XtWindow(eb), + top_gc, bottom_gc, x, y, width, height, + default_button_shadow_thickness, + (unsigned)XmSHADOW_OUT); + } + } + + if (eb->primitive.highlight_drawn) + draw_shadows(eb); + draw_pixmap(eb, event, region); + } +} + + static void +BorderHighlight(Widget w) +{ + XmEnhancedButtonWidget eb = (XmEnhancedButtonWidget)w; + + (*(xmPushButtonClassRec.primitive_class.border_highlight))(w); + draw_pixmap(eb, NULL, NULL); +} + + static void +BorderUnhighlight(Widget w) +{ + XmEnhancedButtonWidget eb = (XmEnhancedButtonWidget)w; + + (*(xmPushButtonClassRec.primitive_class.border_unhighlight))(w); + draw_pixmap(eb, NULL, NULL); +} |