From b7fcef56071855f7e7a5454e96d05a69096df2bf Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Sun, 2 Jan 2005 11:31:05 +0000 Subject: updated for version 7.0028 --- runtime/doc/usr_41.txt | 5 +- src/Makefile | 9 +- src/gui_motif.c | 206 ++++--- src/gui_xmebw.c | 1406 ++++++++++++++++++++++++++++++++++++++++++++++++ src/gui_xmebw.h | 73 +++ 5 files changed, 1625 insertions(+), 74 deletions(-) create mode 100644 src/gui_xmebw.c create mode 100644 src/gui_xmebw.h diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt index ace402f9a1..a9560fde7c 100644 --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -1,4 +1,4 @@ -*usr_41.txt* For Vim version 7.0aa. Last change: 2004 Oct 06 +*usr_41.txt* For Vim version 7.0aa. Last change: 2005 Jan 01 VIM USER MANUAL - by Bram Moolenaar @@ -84,6 +84,9 @@ variable. Note: If you happen to write a while loop that keeps on running, you can interrupt it by pressing CTRL-C (CTRL-Break on MS-Windows). + Note: + You can try out the examples by yanking the lines from the text here + and executing them with :@" THREE KINDS OF NUMBERS diff --git a/src/Makefile b/src/Makefile index 5e43ee9df7..f2ed0b97c8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1090,10 +1090,10 @@ GTK_TESTTARGET = gui ### Motif GUI MOTIF_SRC = gui.c gui_motif.c gui_x11.c pty.c gui_beval.c \ - gui_xmdlg.c + gui_xmdlg.c gui_xmebw.c MOTIF_OBJ = objects/gui.o objects/gui_motif.o objects/gui_x11.o \ objects/pty.o objects/gui_beval.o \ - objects/gui_xmdlg.o + objects/gui_xmdlg.o objects/gui_xmebw.o MOTIF_DEFS = -DFEAT_GUI_MOTIF $(NARROW_PROTO) MOTIF_IPATH = $(GUI_INC_LOC) MOTIF_LIBS_DIR = $(GUI_LIB_LOC) @@ -1205,7 +1205,7 @@ CARBONGUI_BUNDLE = $(VIMNAME).app CARBONGUI_TESTARG = VIMPROG=../$(CARBONGUI_BUNDLE)/Contents/MacOS/$(VIMTARGET) # All GUI files -ALL_GUI_SRC = gui.c gui_gtk.c gui_gtk_f.c gui_motif.c gui_xmdlg.c gui_athena.c gui_gtk_x11.c gui_x11.c gui_at_sb.c gui_at_fs.c pty.c gui_kde.cc gui_kde_wid.cc gui_kde_x11.cc gui_kde_wid_moc.cc +ALL_GUI_SRC = gui.c gui_gtk.c gui_gtk_f.c gui_motif.c gui_xmdlg.c gui_xmebw.c gui_athena.c gui_gtk_x11.c gui_x11.c gui_at_sb.c gui_at_fs.c pty.c gui_kde.cc gui_kde_wid.cc gui_kde_x11.cc gui_kde_wid_moc.cc ALL_GUI_PRO = gui.pro gui_gtk.pro gui_motif.pro gui_xmdlg.pro gui_athena.pro gui_gtk_x11.pro gui_x11.pro gui_w16.pro gui_w32.pro gui_amiga.pro gui_photon.pro # }}} @@ -2199,6 +2199,9 @@ objects/gui_motif.o: gui_motif.c objects/gui_xmdlg.o: gui_xmdlg.c $(CCC) -o $@ gui_xmdlg.c +objects/gui_xmebw.o: gui_xmebw.c + $(CCC) -o $@ gui_xmebw.c + objects/gui_x11.o: gui_x11.c $(CCC) -o $@ gui_x11.c diff --git a/src/gui_motif.c b/src/gui_motif.c index d345af5cb6..278361339e 100644 --- a/src/gui_motif.c +++ b/src/gui_motif.c @@ -42,6 +42,8 @@ # endif #endif +#include "gui_xmebw.h" /* for our Enhanced Button Widget */ + #if defined(FEAT_GUI_DIALOG) && defined(HAVE_XPM) # include "../pixmaps/alert.xpm" # include "../pixmaps/error.xpm" @@ -126,7 +128,6 @@ scroll_cb(w, client_data, call_data) * End of call-back routines */ -#ifndef LESSTIF_VERSION /* * Implement three dimensional shading of insensitive labels. * By Martin Dalecki. @@ -147,11 +148,11 @@ label_expose(_w, _event, _region) { GC insensitiveGC; XmLabelWidget lw = (XmLabelWidget)_w; - unsigned char label_type = XmSTRING; + unsigned char label_type = (int)XmSTRING; XtVaGetValues(_w, XmNlabelType, &label_type, (XtPointer)0); - if (XtIsSensitive(_w) || label_type != XmSTRING) + if (XtIsSensitive(_w) || label_type != (int)XmSTRING) (*old_label_expose)(_w, _event, _region); else { @@ -194,8 +195,8 @@ label_expose(_w, _event, _region) values.foreground = lw->primitive.top_shadow_color; values.background = lw->core.background_pixel; - lw->label.insensitive_GC = - XtAllocateGC((Widget) lw, 0, mask, &values, dynamic, 0); + lw->label.insensitive_GC = XtAllocateGC((Widget)lw, 0, mask, + &values, dynamic, (XtGCMask)0); (*old_label_expose)(_w, _event, _region); XtReleaseGC(_w, lw->label.insensitive_GC); @@ -210,16 +211,14 @@ label_expose(_w, _event, _region) values.foreground = lw->primitive.bottom_shadow_color; values.background = lw->core.background_pixel; - lw->label.insensitive_GC = - XtAllocateGC((Widget) lw, 0, mask, &values, dynamic, 0); + lw->label.insensitive_GC = XtAllocateGC((Widget) lw, 0, mask, + &values, dynamic, (XtGCMask)0); (*old_label_expose)(_w, _event, _region); XtReleaseGC(_w, lw->label.insensitive_GC); lw->label.insensitive_GC = insensitiveGC; } } -#endif - /* * Create all the motif widgets necessary. @@ -227,7 +226,6 @@ label_expose(_w, _event, _region) void gui_x11_create_widgets() { -#ifndef LESSTIF_VERSION /* * Install the 3D shade effect drawing routines. */ @@ -236,7 +234,6 @@ gui_x11_create_widgets() old_label_expose = xmLabelWidgetClass->core_class.expose; xmLabelWidgetClass->core_class.expose = label_expose; } -#endif /* * Start out by adding the configured border width into the border offset @@ -279,6 +276,7 @@ gui_x11_create_widgets() /* Always stick to right hand side. */ XtSetArg(al[ac], XmNrightOffset, 0); ac++; # endif + XtSetArg(al[ac], XmNmarginHeight, 0); ac++; menuBar = XmCreateMenuBar(vimForm, "menuBar", al, ac); XtManageChild(menuBar); @@ -883,13 +881,84 @@ gui_mch_compute_menu_height(id) */ gui.menu_height = maxy + height - 2 * shadow + 2 * margin + 4; -#ifdef LESSTIF_VERSION /* Somehow the menu bar doesn't resize automatically. Set it here, * even though this is a catch 22. Don't do this when starting up, * somehow the menu gets very high then. */ if (gui.shell_created) XtVaSetValues(menuBar, XmNheight, gui.menu_height, NULL); -#endif +} + +/* + * Icons used by the toolbar code. + */ +#include "gui_x11_pm.h" + +static int check_xpm __ARGS((char_u *path)); +static char **get_toolbar_pixmap __ARGS((vimmenu_T *menu)); + +/* + * Read an Xpm file. Return OK or FAIL. + */ + static int +check_xpm(path) + char_u *path; +{ + XpmAttributes attrs; + int status; + Pixmap mask; + Pixmap map; + + attrs.valuemask = 0; + + /* Create the "sensitive" pixmap */ + status = XpmReadFileToPixmap(gui.dpy, + RootWindow(gui.dpy, DefaultScreen(gui.dpy)), + (char *)path, &map, &mask, &attrs); + XpmFreeAttributes(&attrs); + + if (status == XpmSuccess) + return OK; + return FAIL; +} + + +/* + * Allocated a pixmap for toolbar menu "menu". + * Return a blank pixmap if it fails. + */ + static char ** +get_toolbar_pixmap(menu) + vimmenu_T *menu; +{ + char_u buf[MAXPATHL]; /* buffer storing expanded pathname */ + char **xpm = NULL; /* xpm array */ + int res; + + buf[0] = NUL; /* start with NULL path */ + + if (menu->iconfile != NULL) + { + /* Use the "icon=" argument. */ + gui_find_iconfile(menu->iconfile, buf, "xpm"); + res = check_xpm(buf); + + /* If it failed, try using the menu name. */ + if (res == FAIL && gui_find_bitmap(menu->name, buf, "xpm") == OK) + res = check_xpm(buf); + if (res == OK) + return tb_blank_xpm; + } + + if (menu->icon_builtin || gui_find_bitmap(menu->name, buf, "xpm") == FAIL) + { + if (menu->iconidx >= 0 && menu->iconidx + < (sizeof(built_in_pixmaps) / sizeof(built_in_pixmaps[0]))) + xpm = built_in_pixmaps[menu->iconidx]; + else + xpm = tb_blank_xpm; + } + + return xpm; } void @@ -944,17 +1013,11 @@ gui_mch_add_menu_item(menu, idx) XtSetArg(args[n], XmNwidth, wid); n++; XtSetArg(args[n], XmNminWidth, wid); n++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; - XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; + XtSetArg(args[n], XmNseparatorType, XmSHADOW_ETCHED_IN); n++; #endif } else { - get_toolbar_pixmap(menu, &menu->image, &menu->image_ins); - /* Set the label here, so that we can switch between icons/text - * by changing the XmNlabelType resource. */ - xms = XmStringCreate((char *)menu->dname, STRING_TAG); - XtSetArg(args[n], XmNlabelString, xms); n++; - /* Without shadows one can't sense whatever the button has been * pressed or not! However we wan't to save a bit of space... * Need the highlightThickness to see the focus. @@ -963,21 +1026,22 @@ gui_mch_add_menu_item(menu, idx) XtSetArg(args[n], XmNhighlightOnEnter, True); n++; XtSetArg(args[n], XmNmarginWidth, 0); n++; XtSetArg(args[n], XmNmarginHeight, 0); n++; + /* Set the label here, so that we can switch between icons/text + * by changing the XmNlabelType resource. */ + xms = XmStringCreate((char *)menu->dname, STRING_TAG); + XtSetArg(args[n], XmNlabelString, xms); n++; - if (menu->image == 0) + menu->xpm = get_toolbar_pixmap(menu); + if (menu->xpm == NULL) { XtSetArg(args[n], XmNlabelType, XmSTRING); n++; - XtSetArg(args[n], XmNlabelPixmap, 0); n++; - XtSetArg(args[n], XmNlabelInsensitivePixmap, 0); n++; } else { - XtSetArg(args[n], XmNlabelPixmap, menu->image); n++; - XtSetArg(args[n], XmNlabelInsensitivePixmap, menu->image_ins); n++; - XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++; + XtSetArg(args[n], XmNpixmapData, menu->xpm); n++; + XtSetArg(args[n], XmNlabelLocation, XmBOTTOM); n++; } - type = xmPushButtonWidgetClass; - XtSetArg(args[n], XmNwidth, 80); n++; + type = xmEnhancedButtonWidgetClass; } XtSetArg(args[n], XmNpositionIndex, idx); n++; @@ -985,7 +1049,7 @@ gui_mch_add_menu_item(menu, idx) { menu->id = XtCreateManagedWidget((char *)menu->dname, type, toolBar, args, n); - if (menu->id != NULL && type == xmPushButtonWidgetClass) + if (menu->id != NULL && type == xmEnhancedButtonWidgetClass) { XtAddCallback(menu->id, XmNactivateCallback, gui_x11_menu_cb, menu); @@ -1202,16 +1266,22 @@ gui_mch_submenu_change(menu, colors) #ifdef FEAT_TOOLBAR /* For a toolbar item: Free the pixmap and allocate a new one, * so that the background color is right. */ - if (mp->image != (Pixmap)0) + if (mp->xpm != NULL) { - XFreePixmap(gui.dpy, mp->image); - XFreePixmap(gui.dpy, mp->image_ins); - get_toolbar_pixmap(mp, &mp->image, &mp->image_ins); - if (mp->image != (Pixmap)0) - XtVaSetValues(mp->id, - XmNlabelPixmap, mp->image, - XmNlabelInsensitivePixmap, mp->image_ins, - NULL); + int n = 0; + Arg args[18]; + + mp->xpm = get_toolbar_pixmap(mp); + if (menu->xpm == NULL) + { + XtSetArg(args[n], XmNlabelType, XmSTRING); n++; + } + else + { + XtSetArg(args[n], XmNpixmapData, menu->xpm); n++; + XtSetArg(args[n], XmNlabelLocation, XmBOTTOM); n++; + } + XtSetValues(mp->id, args, n); } # ifdef FEAT_BEVAL /* If we have a tooltip, then we need to change it's font */ @@ -1757,7 +1827,8 @@ set_fontlist(id) XmFontList fl; #ifdef FONTSET_ALWAYS - if (gui.fontset != NOFONTSET) { + if (gui.fontset != NOFONTSET) + { fl = gui_motif_fontset2fontlist((XFontSet *)&gui.fontset); if (fl != NULL) { @@ -1775,7 +1846,8 @@ set_fontlist(id) } } #else - if (gui.norm_font != NOFONT) { + if (gui.norm_font != NOFONT) + { fl = gui_motif_create_fontlist((XFontStruct *)gui.norm_font); if (fl != NULL) { @@ -2672,11 +2744,11 @@ gui_mch_show_toolbar(int showit) (*action)(cur->tip); if (!menu_is_separator(cur->name)) { - if (text == 1 || cur->image == 0) + if (text == 1 || cur->xpm == NULL) + { XtSetArg(args[n], XmNlabelType, XmSTRING); - else - XtSetArg(args[n], XmNlabelType, XmPIXMAP); - n++; + ++n; + } if (cur->id != NULL) { XtUnmanageChild(cur->id); @@ -2737,26 +2809,33 @@ gui_mch_reset_focus() int gui_mch_compute_toolbar_height() { + Dimension borders; Dimension height; /* total Toolbar height */ Dimension whgt; /* height of each widget */ - Dimension marginHeight; /* XmNmarginHeight of toolBar */ - Dimension shadowThickness; /* thickness of Xtparent(toolBar) */ WidgetList children; /* list of toolBar's children */ Cardinal numChildren; /* how many children toolBar has */ int i; + borders = 0; height = 0; - shadowThickness = 0; - marginHeight = 0; if (toolBar != (Widget)0 && toolBarFrame != (Widget)0) { /* get height of XmFrame parent */ + Dimension fst; + Dimension fmh; + Dimension tst; + Dimension tmh; + XtVaGetValues(toolBarFrame, - XmNshadowThickness, &shadowThickness, + XmNshadowThickness, &fst, + XmNmarginHeight, &fmh, NULL); + borders += fst + fmh; XtVaGetValues(toolBar, - XmNmarginHeight, &marginHeight, + XmNshadowThickness, &tst, + XmNmarginHeight, &tmh, XmNchildren, &children, XmNnumChildren, &numChildren, NULL); + borders += tst + tmh; for (i = 0; i < numChildren; i++) { whgt = 0; @@ -2765,8 +2844,13 @@ gui_mch_compute_toolbar_height() height = whgt; } } +#ifdef LESSTIF_VERSION + /* Hack: When starting up we get wrong dimensions. */ + if (height < 10) + height = 24; +#endif - return (int)(height + (marginHeight << 1) + (shadowThickness << 1)); + return (int)(height + (borders << 1)); } #if 0 /* these are never called. */ @@ -2831,23 +2915,6 @@ toolbarbutton_leave_cb(w, client_data, event, cont) gui_mch_set_footer((char_u *) ""); } # endif - - void -gui_mch_get_toolbar_colors(bgp, fgp, bsp, tsp, hsp) - Pixel *bgp; - Pixel *fgp; - Pixel *bsp; - Pixel *tsp; - Pixel *hsp; -{ - XtVaGetValues(toolBar, - XmNbackground, bgp, - XmNforeground, fgp, - XmNbottomShadowColor, bsp, - XmNtopShadowColor, tsp, - XmNhighlightColor, hsp, - NULL); -} #endif /* @@ -2980,10 +3047,9 @@ find_replace_destroy_callback(w, client_data, call_data) { SharedFindReplace *cd = (SharedFindReplace *)client_data; - if (cd != NULL) { + if (cd != NULL) /* suppress_dialog_mnemonics(cd->dialog); */ cd->dialog = (Widget)0; - } } /*ARGSUSED*/ diff --git a/src/gui_xmebw.c b/src/gui_xmebw.c new file mode 100644 index 0000000000..fbe0ba99b8 --- /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 + * + * 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 +#include +#include + +#include +#include +#ifndef LESSTIF_VERSION +# include +# include +# include +# include +#else +# include +#endif +#include +#include +#include + +#include +#include + +#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); +} diff --git a/src/gui_xmebw.h b/src/gui_xmebw.h new file mode 100644 index 0000000000..2aaf5423c3 --- /dev/null +++ b/src/gui_xmebw.h @@ -0,0 +1,73 @@ +/* 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 + * + * 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. + */ + +#ifndef EnhancedB_H +#define EnhancedB_H + +/* + * New resources for the Extended Pushbutton widget + */ + +#ifndef XmNshift +# define XmNshift "shift" +#endif +#ifndef XmCShift +# define XmCShift "Shift" +#endif + +#ifndef XmNlabelLocation +# define XmNlabelLocation "labelLocation" +#endif +#ifndef XmCLocation +# define XmCLocation "Location" +#endif + +#ifndef XmNpixmapData +# define XmNpixmapData "pixmapData" +#endif + +#ifndef XmNpixmapFile +# define XmNpixmapFile "pixmapFile" +#endif + +#ifndef LESSTIF_VERSION +/* + * Constants for labelLocation. + */ + +# include +#else +# define XmLEFT 1 +# define XmRIGHT 2 +# define XmTOP 3 +# define XmBOTTOM 4 +#endif + +#define XmIsEnhancedButton(w) XtIsSubclass(w, xmEnhancedButtonWidgetClass) + +/* + * Convienience creation function. + */ +extern Widget XgCreateEPushButtonWidget(Widget, char *, ArgList, Cardinal); + +extern WidgetClass xmEnhancedButtonWidgetClass; +typedef struct _XmEnhancedButtonClassRec *XmEnhancedButtonWidgetClass; +typedef struct _XmEnhancedButtonRec *XmEnhancedButtonWidget; + +#endif -- cgit v1.2.3