Mercurial > hg > xemacs-beta
annotate lwlib/xlwmenu.c @ 4877:1a9c94ba117c
add issue about building on Cygwin with C++, NEWGC and optimization
| author | Ben Wing <ben@xemacs.org> |
|---|---|
| date | Fri, 15 Jan 2010 07:46:13 -0600 |
| parents | 726060ee587c |
| children | a6c778975d7d |
| rev | line source |
|---|---|
| 428 | 1 /* Implements a lightweight menubar widget. |
| 2 Copyright (C) 1992, 1993, 1994 Lucid, Inc. | |
| 3 Copyright (C) 1995 Tinker Systems and INS Engineering Corp. | |
| 4 | |
| 5 This file is part of the Lucid Widget Library. | |
| 6 | |
| 7 The Lucid Widget Library is free software; you can redistribute it and/or | |
| 8 modify it under the terms of the GNU General Public License as published by | |
| 9 the Free Software Foundation; either version 2, or (at your option) | |
| 10 any later version. | |
| 11 | |
| 12 The Lucid Widget Library is distributed in the hope that it will be useful, | |
| 13 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 15 GNU General Public License for more details. | |
| 16 | |
| 17 You should have received a copy of the GNU General Public License | |
| 18 along with XEmacs; see the file COPYING. If not, write to | |
| 19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
| 20 Boston, MA 02111-1307, USA. */ | |
| 21 | |
| 22 /* Created by devin@lucid.com */ | |
| 23 | |
| 24 #include <config.h> | |
| 25 #include <stdlib.h> | |
| 26 #include <string.h> | |
| 27 #include <ctype.h> | |
| 28 #include <stdio.h> | |
| 29 #include <sys/types.h> | |
| 30 #include <limits.h> | |
| 31 #ifdef HAVE_UNISTD_H | |
| 32 #include <unistd.h> | |
| 33 #endif | |
| 34 | |
| 35 #include <X11/IntrinsicP.h> | |
| 36 #include <X11/ShellP.h> | |
| 37 #include <X11/StringDefs.h> | |
| 38 #include <X11/cursorfont.h> | |
| 39 #include <X11/bitmaps/gray> | |
| 40 | |
| 41 #ifdef NEED_MOTIF | |
| 42 #include <Xm/Xm.h> | |
| 43 #if XmVersion < 1002 /* 1.1 or ancient */ | |
| 44 #undef XmFONTLIST_DEFAULT_TAG | |
| 45 #define XmFONTLIST_DEFAULT_TAG XmSTRING_DEFAULT_CHARSET | |
| 46 #endif /* XmVersion < 1.2 */ | |
| 47 #endif | |
| 3094 | 48 |
| 49 /* #### we may want to turn off USE_XFT here if !USE_XFT_MENUBARS | |
| 50 In fact, maybe that's the right interface overall? */ | |
| 51 #include "lwlib-fonts.h" | |
| 52 #include "lwlib-colors.h" | |
| 428 | 53 #include "xlwmenuP.h" |
| 54 | |
| 55 #ifdef USE_DEBUG_MALLOC | |
| 56 #include <dmalloc.h> | |
| 57 #endif | |
| 58 | |
| 442 | 59 /* simple, naive integer maximum */ |
| 428 | 60 #ifndef max |
| 61 #define max(a,b) ((a)>(b)?(a):(b)) | |
| 62 #endif | |
| 63 | |
| 64 static char | |
| 65 xlwMenuTranslations [] = | |
| 66 "<BtnDown>: start()\n\ | |
| 67 <BtnMotion>: drag()\n\ | |
| 68 <BtnUp>: select()\n\ | |
| 69 "; | |
| 70 | |
| 71 extern Widget lw_menubar_widget; | |
| 72 | |
| 73 static XtResource | |
| 74 xlwMenuResources[] = | |
| 75 { | |
|
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
76 /* The offset macro is a standard trick. The remaining macros are an |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
77 experiment to compress redundancies in resource descriptions, and shut |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
78 up GCC 4.3 (the String casts, which keep G++ from complaining about |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
79 implicit conversions from const char *). */ |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
80 #define offset(field) XtOffset(XlwMenuWidget, menu.field) |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
81 #define fontres(name,_class,repr,type,member,value) \ |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
82 Xt_RESOURCE (name, _class, repr, type, offset(member), XtRString, value) |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
83 #define mflres(name,cls,member,repr,value) \ |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
84 Xt_RESOURCE (name, cls, XmRFontList, XmFontList, offset(member), repr, value) |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
85 #define dimres(name,cls,repr,member,value) \ |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
86 Xt_RESOURCE (name, cls, repr, Dimension, offset(member), XtRImmediate, value) |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
87 #define boolres(nm,cls,member,val) \ |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
88 Xt_RESOURCE (nm, cls, XtRBoolean, Boolean, offset(member), XtRImmediate, val) |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
89 #define cbres(name,member,value) \ |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
90 Xt_RESOURCE (name, XtCCallback, XtRCallback, XtPointer, offset(member), \ |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
91 XtRCallback, value) |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
92 #define pixres(name,_class,member,repr,value) \ |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
93 Xt_RESOURCE (name, _class, XtRPixel, Pixel, offset(member), repr, value) |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
94 #define fgpixres(name,_class,member) \ |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
95 pixres (name, _class, member, XtRString, "XtDefaultForeground") |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
96 #define nullpixres(name,_class,member) \ |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
97 pixres (name, _class, member, XtRImmediate, -1) |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
98 #define pmres(name,cls,member) \ |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
99 Xt_RESOURCE (name, cls, XtRPixmap, Pixmap, offset(member), XtRImmediate, None) |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
100 |
| 3094 | 101 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) |
| 428 | 102 /* There are three font list resources, so that we can accept either of |
| 103 the resources *fontList: or *font:, and so that we can tell the | |
| 104 difference between them being specified, and being defaulted to a | |
| 105 font from the XtRString specified here. */ | |
|
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
106 mflres (XmNfontList, XmCFontList, font_list, XtRImmediate, 0), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
107 mflres (XtNfont, XtCFont, font_list_2, XtRImmediate, 0), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
108 mflres (XmNfontList, XmCFontList, fallback_font_list, |
| 428 | 109 /* We must use an iso8859-1 font here, or people without $LANG set lose. |
| 110 It's fair to assume that those who do have $LANG set also have the | |
| 111 *fontList resource set, or at least know how to deal with this. */ | |
|
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
112 XtRString, (XtPointer) "-*-helvetica-bold-r-*-*-*-120-*-*-*-*-iso8859-1"), |
| 428 | 113 #else |
|
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
114 fontres (XtNfont, XtCFont, XtRFontStruct, XFontStruct *, font, |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
115 "XtDefaultFont"), |
| 3094 | 116 #ifdef USE_XFT_MENUBARS |
|
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
117 fontres (XtNfcFontName, XtCFcFontName, XtRString, String, fcFontName, |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
118 "sans-serif-12:bold"), |
| 3397 | 119 /* #### This needs to be fixed to give a proper type and converter for |
| 120 XftFonts. See also xlwtabs.c. */ | |
|
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
121 fontres (XtNxftFont, XtCXftFont, XtRString, XtPointer, xftFontName, |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
122 "Helvetica-12:bold"), |
| 3094 | 123 #endif |
| 428 | 124 # ifdef USE_XFONTSET |
| 442 | 125 /* #### Consider using the same method as for Motif; see the comment in |
| 126 XlwMenuInitialize(). */ | |
|
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
127 fontres (XtNfontSet, XtCFontSet, XtRFontSet, XFontSet, font_set, |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
128 "XtDefaultFontSet"), |
| 428 | 129 # endif |
| 130 #endif | |
|
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
131 fgpixres (XtNforeground, XtCForeground, foreground), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
132 fgpixres (XtNbuttonForeground, XtCButtonForeground, button_foreground), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
133 fgpixres (XtNhighlightForeground, XtCHighlightForeground, |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
134 highlight_foreground), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
135 fgpixres (XtNtitleForeground, XtCTitleForeground, title_foreground), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
136 dimres (XtNmargin, XtCMargin, XtRDimension, margin, 2), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
137 dimres (XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension, |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
138 horizontal_margin, 2), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
139 dimres (XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension, |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
140 vertical_margin, 1), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
141 dimres (XmNspacing, XmCSpacing, XmRHorizontalDimension, column_spacing, 4), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
142 dimres (XmNindicatorSize, XmCIndicatorSize, XtRDimension, indicator_size, 0), |
| 428 | 143 #if 0 |
|
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
144 dimres (XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension, |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
145 shadow_thickness, 2), |
| 428 | 146 #else |
|
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
147 dimres (XmNshadowThickness, XmCShadowThickness, XtRDimension, |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
148 shadow_thickness, 2), |
| 428 | 149 #endif |
|
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
150 nullpixres (XmNselectColor, XmCSelectColor, select_color), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
151 nullpixres (XmNtopShadowColor, XmCTopShadowColor, top_shadow_color), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
152 nullpixres (XmNbottomShadowColor, XmCBottomShadowColor, bottom_shadow_color), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
153 pmres (XmNtopShadowPixmap, XmCTopShadowPixmap, top_shadow_pixmap), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
154 pmres (XmNbottomShadowPixmap, XmCBottomShadowPixmap, bottom_shadow_pixmap), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
155 |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
156 cbres (XtNopen, open, NULL), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
157 cbres (XtNselect, select, NULL), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
158 Xt_RESOURCE (XtNmenu, XtCMenu, XtRPointer, XtPointer, offset(contents), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
159 XtRImmediate, NULL), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
160 Xt_RESOURCE (XtNcursor, XtCCursor, XtRCursor, Cursor, offset(cursor_shape), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
161 XtRString, "right_ptr"), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
162 Xt_RESOURCE (XtNhorizontal, XtCHorizontal, XtRInt, int, offset(horizontal), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
163 XtRImmediate, True), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
164 boolres (XtNuseBackingStore, XtCUseBackingStore, use_backing_store, False), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
165 boolres (XtNbounceDown, XtCBounceDown, bounce_down, True), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
166 boolres (XtNresourceLabels, XtCResourceLabels, lookup_labels, False), |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
167 |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
168 #undef offset |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
169 #undef mflres |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
170 #undef fontres |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
171 #undef dimres |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
172 #undef boolres |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
173 #undef cbres |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
174 #undef pixres |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
175 #undef fgpixres |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
176 #undef nullpixres |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
177 #undef pmres |
|
4522
fc7067b7f407
Backout last patch; forgot to specify file.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4521
diff
changeset
|
178 }; |
| 428 | 179 |
| 1201 | 180 static Boolean XlwMenuSetValues (Widget current, Widget request, Widget new_, |
| 428 | 181 ArgList args, Cardinal *num_args); |
| 182 static void XlwMenuRealize (Widget w, Mask *valueMask, | |
| 183 XSetWindowAttributes *attributes); | |
| 184 static void XlwMenuRedisplay (Widget w, XEvent *ev, Region region); | |
| 185 static void XlwMenuResize (Widget w); | |
| 1201 | 186 static void XlwMenuInitialize (Widget request, Widget new_, ArgList args, |
| 428 | 187 Cardinal *num_args); |
| 188 static void XlwMenuDestroy (Widget w); | |
| 189 static void XlwMenuClassInitialize (void); | |
| 190 static void Start (Widget w, XEvent *ev, String *params, Cardinal *num_params); | |
| 191 static void Drag (Widget w, XEvent *ev, String *params, Cardinal *num_params); | |
| 192 static void Select(Widget w, XEvent *ev, String *params, Cardinal *num_params); | |
| 193 | |
| 3094 | 194 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) |
| 428 | 195 static XFontStruct *default_font_of_font_list (XmFontList); |
| 196 #endif | |
| 197 | |
| 198 static XtActionsRec | |
| 199 xlwMenuActionsList [] = | |
| 200 { | |
|
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
201 { (String) "start", Start}, |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
202 { (String) "drag", Drag}, |
|
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
203 { (String) "select", Select}, |
| 428 | 204 }; |
| 205 | |
| 206 #define SuperClass ((CoreWidgetClass)&coreClassRec) | |
| 207 | |
| 208 XlwMenuClassRec xlwMenuClassRec = | |
| 209 { | |
| 210 { /* CoreClass fields initialization */ | |
| 211 (WidgetClass) SuperClass, /* superclass */ | |
|
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
212 (String) "XlwMenu", /* class_name */ |
| 428 | 213 sizeof(XlwMenuRec), /* size */ |
| 214 XlwMenuClassInitialize, /* class_initialize */ | |
| 215 NULL, /* class_part_initialize */ | |
| 216 FALSE, /* class_inited */ | |
| 217 XlwMenuInitialize, /* initialize */ | |
| 218 NULL, /* initialize_hook */ | |
| 219 XlwMenuRealize, /* realize */ | |
| 220 xlwMenuActionsList, /* actions */ | |
| 221 XtNumber(xlwMenuActionsList), /* num_actions */ | |
| 222 xlwMenuResources, /* resources */ | |
| 223 XtNumber(xlwMenuResources), /* resource_count */ | |
| 224 NULLQUARK, /* xrm_class */ | |
| 225 TRUE, /* compress_motion */ | |
| 1294 | 226 XtExposeCompressMaximal, /* compress_exposure */ |
| 428 | 227 TRUE, /* compress_enterleave */ |
| 228 FALSE, /* visible_interest */ | |
| 229 XlwMenuDestroy, /* destroy */ | |
| 230 XlwMenuResize, /* resize */ | |
| 231 XlwMenuRedisplay, /* expose */ | |
| 232 XlwMenuSetValues, /* set_values */ | |
| 233 NULL, /* set_values_hook */ | |
| 234 XtInheritSetValuesAlmost, /* set_values_almost */ | |
| 235 NULL, /* get_values_hook */ | |
| 236 NULL, /* #### - should this be set for grabs? accept_focus */ | |
| 237 XtVersion, /* version */ | |
| 238 NULL, /* callback_private */ | |
| 239 xlwMenuTranslations, /* tm_table */ | |
| 240 XtInheritQueryGeometry, /* query_geometry */ | |
| 241 XtInheritDisplayAccelerator, /* display_accelerator */ | |
| 242 NULL /* extension */ | |
| 243 }, /* XlwMenuClass fields initialization */ | |
| 244 { | |
| 245 0 /* dummy */ | |
| 246 }, | |
| 247 }; | |
| 248 | |
| 249 WidgetClass xlwMenuWidgetClass = (WidgetClass) &xlwMenuClassRec; | |
| 250 | |
| 251 extern int lw_menu_accelerate; | |
| 252 | |
| 253 /* Utilities */ | |
| 254 #if 0 /* Apparently not used anywhere */ | |
| 255 | |
| 256 static char * | |
| 257 safe_strdup (char *s) | |
| 258 { | |
| 259 char *result; | |
| 260 if (! s) return 0; | |
| 261 result = (char *) malloc (strlen (s) + 1); | |
| 262 if (! result) | |
| 263 return 0; | |
| 264 strcpy (result, s); | |
| 265 return result; | |
| 266 } | |
| 267 | |
| 268 #endif /* 0 */ | |
| 269 | |
| 270 static void | |
| 271 push_new_stack (XlwMenuWidget mw, widget_value *val) | |
| 272 { | |
| 273 if (!mw->menu.new_stack) | |
| 274 { | |
| 275 mw->menu.new_stack_length = 10; | |
| 276 mw->menu.new_stack = | |
| 277 (widget_value**)XtCalloc (mw->menu.new_stack_length, | |
| 278 sizeof (widget_value*)); | |
| 279 } | |
| 280 else if (mw->menu.new_depth == mw->menu.new_stack_length) | |
| 281 { | |
| 282 mw->menu.new_stack_length *= 2; | |
| 283 mw->menu.new_stack = | |
| 284 (widget_value**)XtRealloc ((char *)mw->menu.new_stack, | |
| 285 mw->menu.new_stack_length * | |
| 286 sizeof (widget_value*)); | |
| 287 } | |
| 288 mw->menu.new_stack [mw->menu.new_depth++] = val; | |
| 289 } | |
| 290 | |
| 291 static void | |
| 292 pop_new_stack_if_no_contents (XlwMenuWidget mw) | |
| 293 { | |
| 294 if (mw->menu.new_depth && | |
| 295 !mw->menu.new_stack [mw->menu.new_depth - 1]->contents) | |
| 296 mw->menu.new_depth -= 1; | |
| 297 } | |
| 298 | |
| 299 static void | |
| 300 make_old_stack_space (XlwMenuWidget mw, int n) | |
| 301 { | |
| 302 if (!mw->menu.old_stack) | |
| 303 { | |
| 304 mw->menu.old_stack_length = max (10, n); | |
| 305 mw->menu.old_stack = | |
| 306 (widget_value**)XtCalloc (mw->menu.old_stack_length, | |
| 307 sizeof (widget_value*)); | |
| 308 } | |
| 309 else if (mw->menu.old_stack_length < n) | |
| 310 { | |
| 311 while (mw->menu.old_stack_length < n) | |
| 312 mw->menu.old_stack_length *= 2; | |
| 313 | |
| 314 mw->menu.old_stack = | |
| 315 (widget_value**)XtRealloc ((char *)mw->menu.old_stack, | |
| 316 mw->menu.old_stack_length * | |
| 317 sizeof (widget_value*)); | |
| 318 } | |
| 319 } | |
| 320 | |
| 321 static Boolean | |
| 322 close_to_reference_time (Widget w, Time reference_time, XEvent *ev) | |
| 323 { | |
| 324 return | |
| 325 reference_time && | |
| 647 | 326 ((int) (ev->xbutton.time - reference_time) < |
| 327 XtGetMultiClickTime (XtDisplay (w))); | |
| 428 | 328 } |
| 329 | |
| 330 /* Size code */ | |
| 331 static int | |
| 332 string_width (XlwMenuWidget mw, | |
| 3094 | 333 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) |
| 428 | 334 XmString s |
| 335 #else | |
| 336 char *s | |
| 337 #endif | |
| 338 ) | |
| 339 { | |
| 3094 | 340 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) |
| 428 | 341 Dimension width, height; |
| 342 XmStringExtent (mw->menu.font_list, s, &width, &height); | |
| 343 return width; | |
| 344 #else | |
| 345 # ifdef USE_XFONTSET | |
| 346 XRectangle ri, rl; | |
| 347 XmbTextExtents (mw->menu.font_set, s, strlen (s), &ri, &rl); | |
| 348 return rl.width; | |
| 349 # else | |
| 3094 | 350 #ifdef USE_XFT_MENUBARS |
| 351 XGlyphInfo glyphinfo; | |
| 3374 | 352 XftTextExtents8 (XtDisplay (mw), mw->menu.renderFont, (FcChar8 *) s, |
| 353 strlen (s), &glyphinfo); | |
| 3094 | 354 return glyphinfo.xOff; |
| 355 #else | |
| 428 | 356 XCharStruct xcs; |
| 357 int drop; | |
| 358 XTextExtents (mw->menu.font, s, strlen (s), &drop, &drop, &drop, &xcs); | |
| 359 return xcs.width; | |
| 3094 | 360 #endif |
| 428 | 361 # endif /* USE_XFONTSET */ |
| 362 #endif | |
| 363 } | |
| 364 | |
| 365 static char massaged_resource_char[256]; | |
| 366 | |
| 367 static void | |
| 368 initialize_massaged_resource_char (void) | |
| 369 { | |
| 370 int j; | |
| 371 for (j = 0; j < (int) sizeof (massaged_resource_char); j++) | |
| 372 { | |
| 373 if ((j >= 'a' && j <= 'z') || | |
| 374 (j >= 'A' && j <= 'Z') || | |
| 375 (j >= '0' && j <= '9') || | |
| 376 (j == '_') || | |
| 377 (j >= 0xa0)) | |
| 378 massaged_resource_char[j] = (char) j; | |
| 379 } | |
| 380 massaged_resource_char ['_'] = '_'; | |
| 381 massaged_resource_char ['+'] = 'P'; /* Convert C++ to cPP */ | |
| 382 massaged_resource_char ['.'] = '_'; /* Convert Buffers... to buffers___ */ | |
| 383 } | |
| 384 | |
| 385 static int | |
| 386 string_width_u (XlwMenuWidget mw, | |
| 3094 | 387 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) |
| 428 | 388 XmString string |
| 389 #else | |
| 390 char *string | |
| 391 #endif | |
| 392 ) | |
| 393 { | |
| 3094 | 394 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) |
| 428 | 395 Dimension width, height; |
| 396 XmString newstring; | |
| 397 #else | |
| 398 # ifdef USE_XFONTSET | |
| 399 XRectangle ri, rl; | |
| 400 # else /* ! USE_XFONTSET */ | |
| 3094 | 401 #ifdef USE_XFT_MENUBARS |
| 402 XGlyphInfo glyphinfo; | |
| 403 #else | |
| 428 | 404 XCharStruct xcs; |
| 405 int drop; | |
| 3094 | 406 #endif |
| 428 | 407 # endif |
| 408 #endif | |
| 409 char* newchars; | |
| 410 int charslength; | |
| 411 char *chars; | |
| 412 int i, j; | |
| 413 | |
| 3094 | 414 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) |
| 428 | 415 chars = ""; |
| 416 if (!XmStringGetLtoR (string, XmFONTLIST_DEFAULT_TAG, &chars)) | |
| 417 chars = ""; | |
| 418 #else | |
| 419 chars = string; | |
| 420 #endif | |
| 421 charslength = strlen (chars); | |
| 422 newchars = (char *) alloca (charslength + 1); | |
| 423 | |
| 424 for (i = j = 0; chars[i] && (j < charslength); i++) | |
| 425 if (chars[i]=='%'&&chars[i+1]=='_') | |
| 426 i++; | |
| 427 else | |
| 428 newchars[j++] = chars[i]; | |
| 429 newchars[j] = '\0'; | |
| 430 | |
| 3094 | 431 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) |
| 428 | 432 newstring = XmStringLtoRCreate (newchars, XmFONTLIST_DEFAULT_TAG); |
| 433 XmStringExtent (mw->menu.font_list, newstring, &width, &height); | |
| 434 XmStringFree (newstring); | |
| 435 XtFree (chars); | |
| 436 return width; | |
| 437 #else | |
| 438 # ifdef USE_XFONTSET | |
| 439 XmbTextExtents (mw->menu.font_set, newchars, j, &ri, &rl); | |
| 440 return rl.width; | |
| 441 # else /* ! USE_XFONTSET */ | |
| 3094 | 442 #ifdef USE_XFT_MENUBARS |
| 3374 | 443 XftTextExtents8 (XtDisplay (mw), mw->menu.renderFont, (FcChar8 *) newchars, |
| 444 j, &glyphinfo); | |
| 3094 | 445 return glyphinfo.xOff; |
| 446 #else | |
| 428 | 447 XTextExtents (mw->menu.font, newchars, j, &drop, &drop, &drop, &xcs); |
| 448 return xcs.width; | |
| 3094 | 449 #endif |
| 428 | 450 # endif /* USE_XFONTSET */ |
| 451 #endif | |
| 452 } | |
| 453 | |
| 454 static void | |
| 442 | 455 massage_resource_name (const char *in, char *out) |
| 428 | 456 { |
| 457 /* Turn a random string into something suitable for using as a resource. | |
| 458 For example: | |
| 459 | |
| 460 "Kill Buffer" -> "killBuffer" | |
| 461 "Find File..." -> "findFile___" | |
| 462 "Search and Replace..." -> "searchAndReplace___" | |
| 463 "C++ Mode Commands" -> "cppModeCommands" | |
| 464 | |
| 465 Valid characters in a resource NAME component are: a-zA-Z0-9_ | |
| 466 */ | |
| 467 | |
| 468 #ifdef PRINT_XLWMENU_RESOURCE_CONVERSIONS | |
| 469 /* Compile with -DPRINT_XLWMENU_RESOURCE_CONVERSIONS to generate a | |
| 470 translation file for menu localizations. */ | |
| 471 char *save_in = in, *save_out = out; | |
| 472 #endif | |
| 473 | |
| 474 Boolean firstp = True; | |
| 475 while (*in) | |
| 476 { | |
| 442 | 477 if (*in == '%' && *(in + 1) == '_') |
| 478 in += 2; | |
| 479 else | |
| 428 | 480 { |
| 442 | 481 char ch; |
| 482 | |
| 483 if (*in == '%' && *(in + 1) == '%') | |
| 484 in++; | |
| 485 ch = massaged_resource_char[(unsigned char) *in++]; | |
| 486 if (ch) | |
| 487 { | |
| 488 int int_ch = (int) (unsigned char) ch; | |
| 489 *out++ = firstp ? tolower (int_ch) : toupper (int_ch); | |
| 490 firstp = False; | |
| 491 while ((ch = massaged_resource_char[(unsigned char) *in++]) | |
| 492 != '\0') | |
| 493 *out++ = ch; | |
| 494 if (!*(in-1)) /* Overshot the NULL byte? */ | |
| 495 break; | |
| 496 } | |
| 428 | 497 } |
| 498 } | |
| 499 *out = 0; | |
| 500 | |
| 501 #ifdef PRINT_XLWMENU_RESOURCE_CONVERSIONS | |
| 502 printf ("! Emacs*XlwMenu.%s.labelString:\t%s\n", save_out, save_in); | |
| 503 printf ( "Emacs*XlwMenu.%s.labelString:\n", save_out); | |
| 504 #endif | |
| 505 } | |
| 506 | |
| 507 static XtResource | |
| 508 nameResource[] = | |
| 509 { | |
|
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
510 { (String) "labelString", (String) "LabelString", XtRString, sizeof(String), |
| 428 | 511 0, XtRImmediate, 0 } |
| 512 }; | |
| 513 | |
| 442 | 514 /* This function searches STRING for parameter inserts of the form: |
| 515 %[padding]1 | |
| 516 padding is either space (' ') or dash ('-') meaning | |
| 517 padding to the left or right of the inserted parameter. | |
| 518 In essence, all %1 strings are replaced by VALUE in the return value. | |
| 519 The caller is expected to free the return value using XtFree(). | |
| 520 %% means insert one % (like printf). | |
| 521 %1 means insert VALUE. | |
| 522 %-1 means insert VALUE followed by one space. The latter is | |
| 523 not inserted if VALUE is a zero length string. | |
| 524 */ | |
| 428 | 525 static char* |
| 442 | 526 parameterize_string (const char *string, const char *value) |
| 428 | 527 { |
| 442 | 528 const char *percent; |
| 428 | 529 char *result; |
| 530 unsigned int done = 0; | |
| 531 unsigned int ntimes; | |
| 532 | |
| 533 if (!string) | |
| 534 { | |
| 535 result = XtMalloc(1); | |
| 536 result[0] = '\0'; | |
| 442 | 537 return result; |
| 428 | 538 } |
| 539 | |
| 540 if (!value) | |
| 541 value = ""; | |
| 542 | |
| 442 | 543 for (ntimes = 1, percent = string; |
| 544 (percent = strchr (percent, '%')); | |
| 428 | 545 ntimes++) |
| 442 | 546 percent++; |
| 428 | 547 |
| 548 result = XtMalloc ((ntimes * strlen(value)) + strlen(string) + 4); | |
| 549 result[0] = '\0'; | |
| 550 | |
| 442 | 551 while ((percent = strchr (string, '%'))) |
| 428 | 552 { |
| 553 unsigned int left_pad; | |
| 554 unsigned int right_pad; | |
| 442 | 555 const char *p; |
| 428 | 556 |
| 557 if (percent[1] == '%') | |
| 558 { /* it's a real % */ | |
| 559 strncat (result, string, 1 + percent - string); /* incl % */ | |
| 560 string = &percent[2]; /* after the second '%' */ | |
| 561 continue; /* with the while() loop */ | |
| 562 } | |
| 563 | |
| 564 left_pad = 0; | |
| 565 right_pad = 0; | |
| 566 | |
| 567 for (p = &percent[1]; /* test *p inside the loop */ ; p++) | |
| 568 { | |
| 569 if (*p == ' ') | |
| 570 { /* left pad */ | |
| 571 left_pad++; | |
| 572 } | |
| 573 else if (*p == '-') | |
| 574 { /* right pad */ | |
| 575 right_pad++; | |
| 576 } | |
| 577 else if (*p == '1') | |
| 578 { /* param and terminator */ | |
| 579 strncat (result, string, percent - string); | |
| 580 if (value[0] != '\0') | |
| 581 { | |
| 582 unsigned int i; | |
| 583 for (i = 0; i < left_pad; i++) | |
| 584 strcat (result, " "); | |
| 585 strcat (result, value); | |
| 586 for (i = 0; i < right_pad; i++) | |
| 587 strcat (result, " "); | |
| 588 } | |
| 589 string = &p[1]; /* after the '1' */ | |
| 590 done++; /* no need to do old way */ | |
| 591 break; /* out of for() loop */ | |
| 592 } | |
| 593 else | |
| 594 { /* bogus, copy the format as is */ | |
| 595 /* out of for() loop */ | |
| 596 strncat (result, string, 1 + p - string); | |
| 597 string = (*p ? &p[1] : p); | |
| 598 break; | |
| 599 } | |
| 600 } | |
| 601 } | |
| 602 | |
| 603 /* Copy the tail of the string */ | |
| 604 strcat (result, string); | |
| 605 | |
| 606 /* If we have not processed a % string, and we have a value, tail it. */ | |
| 607 if (!done && value[0] != '\0') | |
| 608 { | |
| 609 strcat (result, " "); | |
| 610 strcat (result, value); | |
| 611 } | |
| 612 | |
| 613 return result; | |
| 614 } | |
| 615 | |
| 3094 | 616 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) |
| 428 | 617 |
| 618 static XmString | |
| 619 resource_widget_value (XlwMenuWidget mw, widget_value *val) | |
| 620 { | |
| 621 if (!val->toolkit_data) | |
| 622 { | |
| 623 char *resourced_name = NULL; | |
| 624 char *converted_name, *str; | |
| 625 XmString complete_name; | |
| 626 char massaged_name [1024]; | |
| 627 | |
| 628 if (mw->menu.lookup_labels) | |
| 629 { | |
| 630 /* Convert value style name into resource style name. | |
| 631 eg: "Free Willy" becomes "freeWilly" */ | |
| 632 massage_resource_name (val->name, massaged_name); | |
| 633 | |
| 634 /* If we have a value (parameter) see if we can find a "Named" | |
| 635 resource. */ | |
| 636 if (val->value) | |
| 637 { | |
| 638 char named_name[1024]; | |
| 639 sprintf (named_name, "%sNamed", massaged_name); | |
| 640 XtGetSubresources ((Widget) mw, | |
| 641 (XtPointer) &resourced_name, | |
| 642 named_name, named_name, | |
| 643 nameResource, 1, NULL, 0); | |
| 644 } | |
| 645 | |
| 646 /* If nothing yet, try to load from the massaged name. */ | |
| 647 if (!resourced_name) | |
| 648 { | |
| 649 XtGetSubresources ((Widget) mw, | |
| 650 (XtPointer) &resourced_name, | |
| 651 massaged_name, massaged_name, | |
| 652 nameResource, 1, NULL, 0); | |
| 653 } | |
| 654 } /* if (mw->menu.lookup_labels) */ | |
| 655 | |
| 656 /* Still nothing yet, use the name as the value. */ | |
| 657 if (!resourced_name) | |
| 658 resourced_name = val->name; | |
| 659 | |
| 660 /* Parameterize the string. */ | |
| 661 converted_name = parameterize_string (resourced_name, val->value); | |
| 662 | |
| 663 /* nuke newline characters to prevent menubar screwups */ | |
| 664 for ( str = converted_name ; *str ; str++ ) | |
| 665 { | |
| 666 if (str[0] == '\n') str[0] = ' '; | |
| 667 } | |
| 668 | |
| 669 /* Improve OSF's bottom line. */ | |
| 670 #if (XmVersion >= 1002) | |
| 671 complete_name = XmStringCreateLocalized (converted_name); | |
| 672 #else | |
| 673 complete_name = XmStringCreateLtoR (converted_name, | |
| 674 XmSTRING_DEFAULT_CHARSET); | |
| 675 #endif | |
| 676 XtFree (converted_name); | |
| 677 | |
| 678 val->toolkit_data = complete_name; | |
| 679 val->free_toolkit_data = True; | |
| 680 } | |
| 681 return (XmString) val->toolkit_data; | |
| 682 } | |
| 683 | |
| 684 /* Unused */ | |
| 685 #if 0 | |
| 442 | 686 /* These two routines should be a separate file..djw */ |
| 428 | 687 static char * |
| 688 xlw_create_localized_string (Widget w, | |
| 689 char *name, | |
| 690 char **args, | |
| 691 unsigned int nargs) | |
| 692 { | |
| 693 char *string = NULL; | |
| 694 char *arg = NULL; | |
| 695 | |
| 696 if (nargs > 0) | |
| 697 arg = args[0]; | |
| 698 | |
| 699 XtGetSubresources (w, | |
| 700 (XtPointer)&string, | |
| 701 name, | |
| 702 name, | |
| 703 nameResource, 1, | |
| 704 NULL, 0); | |
| 705 | |
| 706 if (!string) | |
| 707 string = name; | |
| 708 | |
| 709 return parameterize_string (string, arg); | |
| 710 } | |
| 711 | |
| 712 static XmString | |
| 713 xlw_create_localized_xmstring (Widget w, | |
| 714 char *name, | |
| 715 char **args, | |
| 716 unsigned int nargs) | |
| 717 { | |
| 718 char * string = xlw_create_localized_string (w, name, args, nargs); | |
| 719 XmString xm_string = XmStringCreateLtoR (string, XmSTRING_DEFAULT_CHARSET); | |
| 720 XtFree (string); | |
| 721 return xm_string; | |
| 722 } | |
| 723 #endif /* 0 */ | |
| 724 | |
| 725 #else /* !Motif */ | |
| 726 | |
| 727 static char* | |
| 728 resource_widget_value (XlwMenuWidget mw, widget_value *val) | |
| 729 { | |
| 730 if (!val->toolkit_data) | |
| 731 { | |
| 732 char *resourced_name = NULL; | |
| 733 char *complete_name; | |
| 734 char massaged_name [1024]; | |
| 735 | |
| 736 if (mw->menu.lookup_labels) | |
| 737 { | |
| 738 massage_resource_name (val->name, massaged_name); | |
| 739 | |
| 740 XtGetSubresources ((Widget) mw, | |
| 741 (XtPointer) &resourced_name, | |
| 742 massaged_name, massaged_name, | |
| 743 nameResource, 1, NULL, 0); | |
| 744 } | |
| 745 if (!resourced_name) | |
| 746 resourced_name = val->name; | |
| 747 | |
| 748 complete_name = parameterize_string (resourced_name, val->value); | |
| 749 | |
| 750 val->toolkit_data = complete_name; | |
| 751 /* nuke newline characters to prevent menubar screwups */ | |
| 752 for ( ; *complete_name ; complete_name++ ) | |
| 753 { | |
| 754 if (complete_name[0] == '\n') | |
| 755 complete_name[0] = ' '; | |
| 756 } | |
| 757 val->free_toolkit_data = True; | |
| 758 } | |
| 759 return (char *) val->toolkit_data; | |
| 760 } | |
| 761 | |
| 762 #endif /* !Motif */ | |
| 763 | |
| 3094 | 764 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \ |
| 765 ? ((unsigned long) (x)) : ((unsigned long) (y))) | |
| 766 | |
| 767 #ifdef USE_XFT_MENUBARS | |
| 768 static int | |
| 769 x_xft_text_width (Display *dpy, XftFont *xft_font, char *run, int len) | |
| 770 { | |
| 771 static XGlyphInfo glyphinfo; | |
| 772 | |
| 773 XftTextExtents8 (dpy, | |
| 774 xft_font, | |
| 3374 | 775 (FcChar8 *) run, len, &glyphinfo); |
| 3094 | 776 return glyphinfo.xOff; |
| 777 } | |
| 778 #endif | |
| 779 | |
| 428 | 780 /* Code for drawing strings. */ |
| 781 static void | |
| 782 string_draw (XlwMenuWidget mw, | |
| 783 Window window, | |
| 784 int x, int y, | |
| 3094 | 785 #ifdef USE_XFT_MENUBARS |
| 786 XftColor *color, | |
| 787 XftColor *colorBg, | |
| 788 #else | |
| 428 | 789 GC gc, |
| 3094 | 790 #endif |
| 791 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) | |
| 428 | 792 XmString string |
| 793 #else | |
| 794 char *string | |
| 795 #endif | |
| 796 ) | |
| 797 { | |
| 3094 | 798 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) |
| 428 | 799 XmStringDraw (XtDisplay (mw), window, |
| 800 mw->menu.font_list, | |
| 801 string, gc, | |
| 802 x, y, | |
| 803 1000, /* ???? width */ | |
| 804 XmALIGNMENT_BEGINNING, | |
| 805 0, /* ???? layout_direction */ | |
| 806 0); | |
| 807 #else | |
| 3094 | 808 # ifdef USE_XFT_MENUBARS |
| 809 Display *display = XtDisplay (mw); | |
| 810 Visual *visual = DefaultVisualOfScreen (XtScreen (mw)); | |
| 811 Colormap cmap = mw->core.colormap; | |
| 812 XftDraw *xftDraw = XftDrawCreate (display, window, visual, cmap); | |
| 813 XftFont *renderFont = mw->menu.renderFont; | |
| 814 /* draw background rect */ | |
| 815 XftDrawRect (xftDraw, colorBg, | |
| 816 x, y, | |
| 817 x_xft_text_width (display, renderFont, string, strlen (string)), | |
| 818 renderFont->ascent + renderFont->descent); /* XXX */ | |
| 819 /* draw text */ | |
| 3374 | 820 XftDrawString8 (xftDraw, color, renderFont, x, y + mw->menu.font_ascent, |
| 821 (FcChar8 *) string, strlen (string)); | |
| 3094 | 822 XftDrawDestroy (xftDraw); |
| 823 # else | |
| 824 # ifdef USE_XFONTSET | |
| 428 | 825 XmbDrawString (XtDisplay (mw), window, mw->menu.font_set, gc, |
| 826 x, y + mw->menu.font_ascent, string, strlen (string)); | |
| 3094 | 827 # else |
| 428 | 828 XDrawString (XtDisplay (mw), window, gc, |
| 829 x, y + mw->menu.font_ascent, string, strlen (string)); | |
| 3094 | 830 # endif /* USE_XFONTSET */ |
| 831 # endif /* USE_XFT_MENUBARS */ | |
| 832 #endif /* NEED_MOTIF */ | |
| 428 | 833 } |
| 834 | |
| 835 static int | |
| 836 string_draw_range ( | |
| 837 XlwMenuWidget mw, | |
| 838 Window window, | |
| 839 int x, int y, | |
| 3094 | 840 #ifdef USE_XFT_MENUBARS |
| 841 XftColor *color, | |
| 842 XftColor *colorBg, | |
| 843 #else | |
| 428 | 844 GC gc, |
| 3094 | 845 #endif |
| 428 | 846 char *string, |
| 847 int start, | |
| 848 int end | |
| 849 ) | |
| 850 { | |
| 3094 | 851 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) |
| 428 | 852 Dimension width, height; |
| 853 XmString newstring; | |
| 854 int c; | |
| 855 | |
| 856 if (end <= start) | |
| 857 return 0; | |
| 858 c = string[end]; | |
| 859 string[end] = '\0'; | |
| 860 newstring = XmStringLtoRCreate (&string[start], XmFONTLIST_DEFAULT_TAG); | |
| 861 XmStringDraw ( | |
| 862 XtDisplay (mw), window, | |
| 863 mw->menu.font_list, | |
| 864 newstring, gc, | |
| 865 x, y, | |
| 866 1000, /* ???? width */ | |
| 867 XmALIGNMENT_BEGINNING, | |
| 868 0, /* ???? layout_direction */ | |
| 869 0 | |
| 870 ); | |
| 871 XmStringExtent (mw->menu.font_list, newstring, &width, &height); | |
| 872 XmStringFree (newstring); | |
| 873 string[end] = c; | |
| 874 return width; | |
| 875 #else | |
| 876 # ifdef USE_XFONTSET | |
| 877 XRectangle ri, rl; | |
| 878 | |
| 879 if (end <= start) | |
| 880 return 0; | |
| 881 XmbDrawString ( | |
| 882 XtDisplay (mw), window, mw->menu.font_set, gc, | |
| 883 x, y + mw->menu.font_ascent, &string[start], end - start); | |
| 884 XmbTextExtents ( | |
| 885 mw->menu.font_set, &string[start], end - start, &ri, &rl); | |
| 886 return rl.width; | |
| 887 # else | |
| 3094 | 888 #ifdef USE_XFT_MENUBARS |
| 889 if (end <= start) | |
| 890 return 0; | |
| 891 else | |
| 892 { | |
| 893 XGlyphInfo glyphinfo; | |
| 894 Display *display = XtDisplay (mw); | |
| 895 Visual *visual = DefaultVisualOfScreen (XtScreen (mw)); | |
| 896 Colormap cmap = mw->core.colormap; | |
| 897 XftFont *renderFont = mw->menu.renderFont; | |
| 898 /* #### should use parent frame's .xftDraw? */ | |
| 899 XftDraw *xftDraw = XftDrawCreate (display, window, visual, cmap); | |
| 900 /* draw background rect */ | |
| 901 XftDrawRect (xftDraw, colorBg, | |
| 902 x, y, | |
| 903 x_xft_text_width (display, | |
| 904 renderFont, &string[start], end - start), | |
| 905 renderFont->ascent + renderFont->descent); /* XXX */ | |
| 906 /* draw text */ | |
| 907 XftDrawString8 (xftDraw, color, renderFont, | |
| 908 x, y + mw->menu.font_ascent, | |
| 3374 | 909 (FcChar8 *) &string[start], end - start); |
| 3094 | 910 |
| 3374 | 911 XftTextExtents8 (display, renderFont, (FcChar8 *) &string[start], |
| 912 end - start, &glyphinfo); | |
| 3094 | 913 |
| 914 /* #### should use parent frame's .xftDraw */ | |
| 915 XftDrawDestroy (xftDraw); | |
| 916 return glyphinfo.xOff; | |
| 917 } | |
| 918 #else | |
| 428 | 919 XCharStruct xcs; |
| 920 int drop; | |
| 921 | |
| 922 if (end <= start) | |
| 923 return 0; | |
| 3094 | 924 XDrawString ( /* XXX */ |
| 428 | 925 XtDisplay (mw), window, gc, |
| 926 x, y + mw->menu.font_ascent, &string[start], end - start); | |
| 927 XTextExtents ( | |
| 928 mw->menu.font, &string[start], end - start, | |
| 929 &drop, &drop, &drop, &xcs); | |
| 930 return xcs.width; | |
| 3094 | 931 #endif |
| 428 | 932 # endif |
| 933 #endif | |
| 934 } | |
| 935 | |
| 936 static void | |
| 937 string_draw_u (XlwMenuWidget mw, | |
| 938 Window window, | |
| 939 int x, int y, | |
| 3094 | 940 #ifdef USE_XFT_MENUBARS |
| 941 XftColor *color, XftColor *colorBg, GC gc, | |
| 942 #else | |
| 428 | 943 GC gc, |
| 3094 | 944 #endif |
| 945 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) | |
| 428 | 946 XmString string |
| 947 #else | |
| 948 char *string | |
| 949 #endif | |
| 950 ) | |
| 951 { | |
| 952 int i, s = 0; | |
| 953 char *chars; | |
| 954 | |
| 3094 | 955 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) |
| 428 | 956 chars = ""; |
| 957 if (!XmStringGetLtoR (string, XmFONTLIST_DEFAULT_TAG, &chars)) | |
| 958 chars = ""; | |
| 959 #else | |
| 960 chars = string; | |
| 961 #endif | |
| 962 for (i=0; chars[i]; ++i) { | |
| 963 if (chars[i] == '%' && chars[i+1] == '_') { | |
| 964 int w; | |
| 965 | |
| 3094 | 966 #ifdef USE_XFT_MENUBARS |
| 967 x += string_draw_range (mw, window, x, y, color, colorBg, chars, s, i); | |
| 968 w = string_draw_range (mw, window, x, y, color, colorBg, chars, i+2, i+3); | |
| 969 #else | |
| 428 | 970 x += string_draw_range (mw, window, x, y, gc, chars, s, i); |
| 971 w = string_draw_range (mw, window, x, y, gc, chars, i+2, i+3); | |
| 3094 | 972 #endif |
| 428 | 973 |
| 974 /* underline next character */ | |
| 975 XDrawLine (XtDisplay (mw), window, gc, x - 1, | |
| 976 y + mw->menu.font_ascent + 1, | |
| 977 x + w - 1, y + mw->menu.font_ascent + 1 ); | |
| 978 x += w; | |
| 979 s = i + 3; | |
| 980 i += 2; | |
| 981 } | |
| 982 } | |
| 3094 | 983 #ifdef USE_XFT_MENUBARS |
| 984 x += string_draw_range (mw, window, x, y, color, colorBg, chars, s, i); | |
| 985 #else | |
| 428 | 986 x += string_draw_range (mw, window, x, y, gc, chars, s, i); |
| 3094 | 987 #endif |
| 988 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) | |
| 428 | 989 XtFree (chars); |
| 990 #endif | |
| 991 } | |
| 992 | |
| 3094 | 993 static void /* XXX */ |
| 994 binding_draw (XlwMenuWidget mw, Window w, int x, int y, | |
| 995 #ifdef USE_XFT_MENUBARS | |
| 996 XftColor *color, | |
| 997 XftColor *colorBg, | |
| 998 #else | |
| 999 GC gc, | |
| 1000 #endif | |
| 1001 char *value) | |
| 428 | 1002 { |
| 3094 | 1003 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) |
| 428 | 1004 XmString xm_value = XmStringCreateLtoR(value, XmSTRING_DEFAULT_CHARSET); |
| 1005 string_draw (mw, w, x, y, gc, xm_value); | |
| 1006 XmStringFree (xm_value); | |
| 1007 #else | |
| 3094 | 1008 #ifdef USE_XFT_MENUBARS |
| 1009 string_draw (mw, w, x, y, color, colorBg, value); | |
| 1010 #else | |
| 428 | 1011 string_draw (mw, w, x, y, gc, value); |
| 1012 #endif | |
| 3094 | 1013 #endif |
| 428 | 1014 } |
| 1015 | |
| 1016 /* Low level code for drawing 3-D edges. */ | |
| 1017 static void | |
| 1018 shadow_rectangle_draw (Display *dpy, | |
| 1019 Window window, | |
| 1020 GC top_gc, | |
| 1021 GC bottom_gc, | |
| 1022 int x, int y, | |
| 1023 unsigned int width, | |
| 1024 unsigned int height, | |
| 1025 unsigned int thickness) | |
| 1026 { | |
| 1027 XPoint points [4]; | |
| 1028 | |
| 1029 if (!thickness) | |
| 1030 return; | |
| 1031 | |
| 1032 points [0].x = x; | |
| 1033 points [0].y = y; | |
| 1034 points [1].x = x + width; | |
| 1035 points [1].y = y; | |
| 1036 points [2].x = x + width - thickness; | |
| 1037 points [2].y = y + thickness; | |
| 1038 points [3].x = x; | |
| 1039 points [3].y = y + thickness; | |
| 1040 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin); | |
| 1041 points [0].x = x; | |
| 1042 points [0].y = y + thickness; | |
| 1043 points [1].x = x; | |
| 1044 points [1].y = y + height; | |
| 1045 points [2].x = x + thickness; | |
| 1046 points [2].y = y + height - thickness; | |
| 1047 points [3].x = x + thickness; | |
| 1048 points [3].y = y + thickness; | |
| 1049 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin); | |
| 1050 points [0].x = x + width; | |
| 1051 points [0].y = y; | |
| 1052 points [1].x = x + width - thickness; | |
| 1053 points [1].y = y + thickness; | |
| 1054 points [2].x = x + width - thickness; | |
| 1055 points [2].y = y + height - thickness; | |
| 1056 points [3].x = x + width; | |
| 1057 points [3].y = y + height - thickness; | |
| 1058 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin); | |
| 1059 points [0].x = x; | |
| 1060 points [0].y = y + height; | |
| 1061 points [1].x = x + width; | |
| 1062 points [1].y = y + height; | |
| 1063 points [2].x = x + width; | |
| 1064 points [2].y = y + height - thickness; | |
| 1065 points [3].x = x + thickness; | |
| 1066 points [3].y = y + height - thickness; | |
| 1067 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin); | |
| 1068 } | |
| 1069 | |
| 1070 typedef enum e_shadow_type | |
| 1071 { | |
| 1072 /* these are Motif compliant */ | |
| 1073 SHADOW_BACKGROUND, | |
| 1074 SHADOW_OUT, | |
| 1075 SHADOW_IN, | |
| 1076 SHADOW_ETCHED_OUT, | |
| 1077 SHADOW_ETCHED_IN, | |
| 1078 SHADOW_ETCHED_OUT_DASH, | |
| 1079 SHADOW_ETCHED_IN_DASH, | |
| 1080 SHADOW_SINGLE_LINE, | |
| 1081 SHADOW_DOUBLE_LINE, | |
| 1082 SHADOW_SINGLE_DASHED_LINE, | |
| 1083 SHADOW_DOUBLE_DASHED_LINE, | |
| 1084 SHADOW_NO_LINE, | |
| 1085 /* these are all non-Motif */ | |
| 1086 SHADOW_DOUBLE_ETCHED_OUT, | |
| 1087 SHADOW_DOUBLE_ETCHED_IN, | |
| 1088 SHADOW_DOUBLE_ETCHED_OUT_DASH, | |
| 1089 SHADOW_DOUBLE_ETCHED_IN_DASH | |
| 1090 } shadow_type; | |
| 1091 | |
| 1092 static void | |
| 1093 shadow_draw (XlwMenuWidget mw, | |
| 1094 Window window, | |
| 1095 int x, int y, | |
| 1096 unsigned int width, | |
| 1097 unsigned int height, | |
| 1098 shadow_type type) | |
| 1099 { | |
| 1100 Display *dpy = XtDisplay (mw); | |
| 1101 GC top_gc; | |
| 1102 GC bottom_gc; | |
| 1103 int thickness = mw->menu.shadow_thickness; | |
| 1104 #if 0 | |
| 1105 XPoint points [4]; | |
| 1106 #endif /* 0 */ | |
| 1107 Boolean etched = False; | |
| 1108 | |
| 1109 switch (type) | |
| 1110 { | |
| 1111 case SHADOW_BACKGROUND: | |
| 1112 top_gc = bottom_gc = mw->menu.background_gc; | |
| 1113 break; | |
| 1114 case SHADOW_ETCHED_IN: | |
| 1115 top_gc = mw->menu.shadow_bottom_gc; | |
| 1116 bottom_gc = mw->menu.shadow_top_gc; | |
| 1117 etched = True; | |
| 1118 break; | |
| 1119 case SHADOW_ETCHED_OUT: | |
| 1120 top_gc = mw->menu.shadow_top_gc; | |
| 1121 bottom_gc = mw->menu.shadow_bottom_gc; | |
| 1122 etched = True; | |
| 1123 break; | |
| 1124 case SHADOW_IN: | |
| 1125 top_gc = mw->menu.shadow_bottom_gc; | |
| 1126 bottom_gc = mw->menu.shadow_top_gc; | |
| 1127 break; | |
| 1128 case SHADOW_OUT: | |
| 1129 default: | |
| 1130 top_gc = mw->menu.shadow_top_gc; | |
| 1131 bottom_gc = mw->menu.shadow_bottom_gc; | |
| 1132 break; | |
| 1133 } | |
| 1134 | |
| 1135 if (etched) | |
| 1136 { | |
| 1137 unsigned int half = thickness/2; | |
| 1138 shadow_rectangle_draw (dpy, | |
| 1139 window, | |
| 1140 top_gc, | |
| 1141 top_gc, | |
| 1142 x, y, | |
| 1143 width - half, height - half, | |
| 1144 thickness - half); | |
| 1145 shadow_rectangle_draw (dpy, | |
| 1146 window, | |
| 1147 bottom_gc, | |
| 1148 bottom_gc, | |
| 1149 x + half, y + half, | |
| 1150 width - half , height - half, | |
| 1151 half); | |
| 1152 } | |
| 1153 else | |
| 1154 { | |
| 1155 shadow_rectangle_draw (dpy, | |
| 1156 window, | |
| 1157 top_gc, | |
| 1158 bottom_gc, | |
| 1159 x, y, | |
| 1160 width, height, | |
| 1161 thickness); | |
| 1162 } | |
| 1163 } | |
| 1164 | |
| 1165 static void | |
| 1166 arrow_decoration_draw (XlwMenuWidget mw, | |
| 1167 Window window, | |
| 1168 int x, int y, | |
| 1169 unsigned int width, | |
| 1170 Boolean raised) | |
| 1171 { | |
| 1172 Display *dpy = XtDisplay (mw); | |
| 1173 GC top_gc; | |
| 1174 GC bottom_gc; | |
| 1175 GC select_gc; | |
| 1176 int thickness = mw->menu.shadow_thickness; | |
| 1177 XPoint points [4]; | |
| 1178 int half_width; | |
| 1179 int length = (int)((double)width * 0.87); | |
| 1180 int thick_med = (int)((double)thickness * 1.73); | |
| 1181 | |
| 1182 if (width & 0x1) | |
| 1183 half_width = width/2 + 1; | |
| 1184 else | |
| 1185 half_width = width/2; | |
| 1186 | |
| 1187 select_gc = mw->menu.background_gc; | |
| 1188 | |
| 1189 if (raised) | |
| 1190 { | |
| 1191 top_gc = mw->menu.shadow_bottom_gc; | |
| 1192 bottom_gc = mw->menu.shadow_top_gc; | |
| 1193 } | |
| 1194 else | |
| 1195 { | |
| 1196 top_gc = mw->menu.shadow_top_gc; | |
| 1197 bottom_gc = mw->menu.shadow_bottom_gc; | |
| 1198 } | |
| 1199 | |
| 1200 /* Fill internal area. We do this first so that the borders have a | |
| 1201 nice sharp edge. */ | |
| 1202 points [0].x = x + thickness; | |
| 1203 points [0].y = y + thickness; | |
| 1204 points [1].x = x + length - thickness; | |
| 1205 points [1].y = y + half_width; | |
| 1206 points [2].x = x + length - thickness; | |
| 1207 points [2].y = y + half_width + thickness; | |
| 1208 points [3].x = x + thickness; | |
| 1209 points [3].y = y + width - thickness; | |
| 1210 | |
| 1211 XFillPolygon (dpy, | |
| 1212 window, | |
| 1213 select_gc, | |
| 1214 points, | |
| 1215 4, | |
| 1216 Convex, | |
| 1217 CoordModeOrigin); | |
| 1218 | |
| 1219 /* left border */ | |
| 1220 points [0].x = x; | |
| 1221 points [0].y = y; | |
| 1222 points [1].x = x + thickness; | |
| 1223 points [1].y = y + thick_med; | |
| 1224 points [2].x = x + thickness; | |
| 1225 points [2].y = y + width - thick_med; | |
| 1226 points [3].x = x; | |
| 1227 points [3].y = y + width; | |
| 1228 | |
| 1229 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin); | |
| 1230 | |
| 1231 /* top border */ | |
| 1232 points [0].x = x; | |
| 1233 points [0].y = y + width; | |
| 1234 points [1].x = x + length; | |
| 1235 points [1].y = y + half_width; | |
| 1236 points [2].x = x + length - (thickness + thickness); | |
| 1237 points [2].y = y + half_width; | |
| 1238 points [3].x = x + thickness; | |
| 1239 points [3].y = y + width - thick_med; | |
| 1240 | |
| 1241 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin); | |
| 1242 | |
| 1243 /* bottom shadow */ | |
| 1244 points [0].x = x; | |
| 1245 points [0].y = y; | |
| 1246 points [1].x = x + length; | |
| 1247 points [1].y = y + half_width; | |
| 1248 points [2].x = x + length - (thickness + thickness); | |
| 1249 points [2].y = y + half_width; | |
| 1250 points [3].x = x + thickness; | |
| 1251 points [3].y = y + thick_med; | |
| 1252 | |
| 1253 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin); | |
| 1254 } | |
| 1255 | |
| 1256 static void | |
| 1257 toggle_decoration_draw (XlwMenuWidget mw, | |
| 1258 Window window, | |
| 1259 int x, int y, | |
| 1260 unsigned int width, | |
| 1261 Boolean set) | |
| 1262 { | |
| 1263 Display *dpy = XtDisplay (mw); | |
| 1264 int thickness = mw->menu.shadow_thickness; | |
| 1265 shadow_type type; | |
| 1266 GC select_gc = mw->menu.select_gc; | |
| 1267 | |
| 1268 if (set) | |
| 1269 type = SHADOW_IN; | |
| 1270 else | |
| 1271 type = SHADOW_OUT; | |
| 1272 | |
| 1273 /* Fill internal area. */ | |
| 1274 if (set) | |
| 1275 XFillRectangle (dpy, | |
| 1276 window, | |
| 1277 select_gc, | |
| 1278 x + thickness, | |
| 1279 y + thickness, | |
| 1280 width - (2*thickness), | |
| 1281 width - (2*thickness)); | |
| 1282 | |
| 1283 shadow_draw (mw, window, x, y, width, width, type); | |
| 1284 } | |
| 1285 | |
| 1286 static void | |
| 1287 radio_decoration_draw (XlwMenuWidget mw, | |
| 1288 Window window, | |
| 1289 int x, int y, | |
| 1290 unsigned int width, | |
| 1291 Boolean enabled) | |
| 1292 { | |
| 1293 Display *dpy = XtDisplay (mw); | |
| 1294 GC top_gc; | |
| 1295 GC bottom_gc; | |
| 1296 GC select_gc = mw->menu.select_gc; | |
| 1297 int thickness = mw->menu.shadow_thickness; | |
| 1298 XPoint points[6]; | |
| 1299 int half_width; | |
| 1300 #if 0 | |
| 1301 int npoints; | |
| 1302 #endif /* 0 */ | |
| 1303 | |
| 1304 if (width & 0x1) | |
| 1305 width++; | |
| 1306 | |
| 1307 half_width = width/2; | |
| 1308 | |
| 1309 if (enabled) | |
| 1310 { | |
| 1311 top_gc = mw->menu.shadow_bottom_gc; | |
| 1312 bottom_gc = mw->menu.shadow_top_gc; | |
| 1313 } | |
| 1314 else | |
| 1315 { | |
| 1316 top_gc = mw->menu.shadow_top_gc; | |
| 1317 bottom_gc = mw->menu.shadow_bottom_gc; | |
| 1318 } | |
| 1319 | |
| 1320 #if 1 | |
| 1321 /* Draw the bottom first, just in case the regions overlap. | |
| 1322 The top should cast the longer shadow. */ | |
| 1323 points [0].x = x; /* left corner */ | |
| 1324 points [0].y = y + half_width; | |
| 1325 points [1].x = x + half_width; /* bottom corner */ | |
| 1326 points [1].y = y + width; | |
| 1327 points [2].x = x + half_width; /* bottom inside corner */ | |
| 1328 points [2].y = y + width - thickness; | |
| 1329 points [3].x = x + thickness; /* left inside corner */ | |
| 1330 points [3].y = y + half_width; | |
| 1331 | |
| 1332 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin); | |
| 1333 | |
| 1334 points [0].x = x + half_width; /* bottom corner */ | |
| 1335 points [0].y = y + width; | |
| 1336 points [1].x = x + width; /* right corner */ | |
| 1337 points [1].y = y + half_width; | |
| 1338 points [2].x = x + width - thickness; /* right inside corner */ | |
| 1339 points [2].y = y + half_width; | |
| 1340 points [3].x = x + half_width; /* bottom inside corner */ | |
| 1341 points [3].y = y + width - thickness; | |
| 1342 | |
| 1343 XFillPolygon (dpy, window, bottom_gc, points, 4, Convex, CoordModeOrigin); | |
| 1344 | |
| 1345 points [0].x = x; /* left corner */ | |
| 1346 points [0].y = y + half_width; | |
| 1347 points [1].x = x + half_width; /* top corner */ | |
| 1348 points [1].y = y; | |
| 1349 points [2].x = x + half_width; /* top inside corner */ | |
| 1350 points [2].y = y + thickness; | |
| 1351 points [3].x = x + thickness; /* left inside corner */ | |
| 1352 points [3].y = y + half_width; | |
| 1353 | |
| 1354 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin); | |
| 1355 | |
| 1356 points [0].x = x + half_width; /* top corner */ | |
| 1357 points [0].y = y; | |
| 1358 points [1].x = x + width; /* right corner */ | |
| 1359 points [1].y = y + half_width; | |
| 1360 points [2].x = x + width - thickness; /* right inside corner */ | |
| 1361 points [2].y = y + half_width; | |
| 1362 points [3].x = x + half_width; /* top inside corner */ | |
| 1363 points [3].y = y + thickness; | |
| 1364 | |
| 1365 XFillPolygon (dpy, window, top_gc, points, 4, Convex, CoordModeOrigin); | |
| 1366 #else | |
| 1367 /* Draw the bottom first, just in case the regions overlap. | |
| 1368 The top should cast the longer shadow. */ | |
| 1369 npoints = 0; | |
| 1370 points [npoints].x = x; /* left corner */ | |
| 1371 points [npoints++].y = y + half_width; | |
| 1372 points [npoints].x = x + half_width; /* bottom corner */ | |
| 1373 points [npoints++].y = y + width; | |
| 1374 points [npoints].x = x + width; /* right corner */ | |
| 1375 points [npoints++].y = y + half_width; | |
| 1376 points [npoints].x = x + width - thickness; /* right inside corner */ | |
| 1377 points [npoints++].y = y + half_width; | |
| 1378 points [npoints].x = x + half_width; /* bottom inside corner */ | |
| 1379 points [npoints++].y = y + width - thickness; | |
| 1380 points [npoints].x = x + thickness; /* left inside corner */ | |
| 1381 points [npoints++].y = y + half_width; | |
| 1382 | |
| 1383 XFillPolygon (dpy, window, bottom_gc, | |
| 1384 points, npoints, Nonconvex, CoordModeOrigin); | |
| 1385 | |
| 1386 npoints = 0; | |
| 1387 | |
| 1388 points [npoints].x = x; /* left corner */ | |
| 1389 points [npoints++].y = y + half_width; | |
| 1390 points [npoints].x = x + half_width; /* top corner */ | |
| 1391 points [npoints++].y = y; | |
| 1392 points [npoints].x = x + width; /* right corner */ | |
| 1393 points [npoints++].y = y + half_width; | |
| 1394 points [npoints].x = x + width - thickness; /* right inside corner */ | |
| 1395 points [npoints++].y = y + half_width; | |
| 1396 points [npoints].x = x + half_width; /* top inside corner */ | |
| 1397 points [npoints++].y = y + thickness; | |
| 1398 points [npoints].x = x + thickness; /* left inside corner */ | |
| 1399 points [npoints++].y = y + half_width; | |
| 1400 | |
| 1401 XFillPolygon (dpy, window, top_gc, points, npoints, Nonconvex, | |
| 1402 CoordModeOrigin); | |
| 1403 #endif | |
| 1404 | |
| 1405 | |
| 1406 /* Fill internal area. */ | |
| 1407 if (enabled) | |
| 1408 { | |
| 1409 points [0].x = x + thickness; | |
| 1410 points [0].y = y + half_width; | |
| 1411 points [1].x = x + half_width; | |
| 1412 points [1].y = y + thickness; | |
| 1413 points [2].x = x + width - thickness; | |
| 1414 points [2].y = y + half_width; | |
| 1415 points [3].x = x + half_width; | |
| 1416 points [3].y = y + width - thickness; | |
| 1417 XFillPolygon (dpy, | |
| 1418 window, | |
| 1419 select_gc, | |
| 1420 points, | |
| 1421 4, | |
| 1422 Convex, | |
| 1423 CoordModeOrigin); | |
| 1424 } | |
| 1425 } | |
| 1426 | |
| 1427 static void | |
| 1428 separator_decoration_draw (XlwMenuWidget mw, | |
| 1429 Window window, | |
| 1430 int x, int y, | |
| 1431 unsigned int width, | |
| 2286 | 1432 Boolean UNUSED (vertical), |
| 428 | 1433 shadow_type type) |
| 1434 { | |
| 1435 Display *dpy = XtDisplay (mw); | |
| 1436 GC top_gc; | |
| 1437 GC bottom_gc; | |
| 1438 unsigned int offset = 0; | |
| 1439 unsigned int num_separators = 1; | |
| 1440 unsigned int top_line_thickness = 0; | |
| 1441 unsigned int bottom_line_thickness = 0; | |
| 1442 Boolean dashed = False; | |
| 1443 | |
| 1444 switch (type) | |
| 1445 { | |
| 1446 case SHADOW_NO_LINE: /* nothing to do */ | |
| 1447 return; | |
| 1448 case SHADOW_DOUBLE_LINE: | |
| 1449 num_separators = 2; | |
| 1450 case SHADOW_SINGLE_LINE: | |
| 1451 top_gc = bottom_gc = mw->menu.foreground_gc; | |
| 1452 top_line_thickness = 1; | |
| 1453 break; | |
| 1454 case SHADOW_DOUBLE_DASHED_LINE: | |
| 1455 num_separators = 2; | |
| 1456 case SHADOW_SINGLE_DASHED_LINE: | |
| 1457 top_gc = bottom_gc = mw->menu.foreground_gc; | |
| 1458 top_line_thickness = 1; | |
| 1459 dashed = True; | |
| 1460 break; | |
| 1461 case SHADOW_DOUBLE_ETCHED_OUT_DASH: | |
| 1462 num_separators = 2; | |
| 1463 case SHADOW_ETCHED_OUT_DASH: | |
| 1464 top_gc = mw->menu.shadow_top_gc; | |
| 1465 bottom_gc = mw->menu.shadow_bottom_gc; | |
| 1466 top_line_thickness = mw->menu.shadow_thickness/2; | |
| 1467 bottom_line_thickness = mw->menu.shadow_thickness - top_line_thickness; | |
| 1468 dashed = True; | |
| 1469 break; | |
| 1470 case SHADOW_DOUBLE_ETCHED_IN_DASH: | |
| 1471 num_separators = 2; | |
| 1472 case SHADOW_ETCHED_IN_DASH: | |
| 1473 top_gc = mw->menu.shadow_bottom_gc; | |
| 1474 bottom_gc = mw->menu.shadow_top_gc; | |
| 1475 top_line_thickness = mw->menu.shadow_thickness/2; | |
| 1476 bottom_line_thickness = mw->menu.shadow_thickness - top_line_thickness; | |
| 1477 dashed = True; | |
| 1478 break; | |
| 1479 case SHADOW_DOUBLE_ETCHED_OUT: | |
| 1480 num_separators = 2; | |
| 1481 case SHADOW_ETCHED_OUT: | |
| 1482 top_gc = mw->menu.shadow_top_gc; | |
| 1483 bottom_gc = mw->menu.shadow_bottom_gc; | |
| 1484 top_line_thickness = mw->menu.shadow_thickness/2; | |
| 1485 bottom_line_thickness = mw->menu.shadow_thickness - top_line_thickness; | |
| 1486 break; | |
| 1487 case SHADOW_DOUBLE_ETCHED_IN: | |
| 1488 num_separators = 2; | |
| 1489 case SHADOW_ETCHED_IN: | |
| 1490 default: | |
| 1491 top_gc = mw->menu.shadow_bottom_gc; | |
| 1492 bottom_gc = mw->menu.shadow_top_gc; | |
| 1493 top_line_thickness = mw->menu.shadow_thickness/2; | |
| 1494 bottom_line_thickness = mw->menu.shadow_thickness - top_line_thickness; | |
| 1495 break; | |
| 1496 } | |
| 1497 | |
| 1498 if (dashed) | |
| 1499 { | |
| 1500 XGCValues values; | |
| 1501 values.line_style = LineOnOffDash; | |
| 1502 if (top_line_thickness > 0) | |
| 1503 XChangeGC (dpy, top_gc, GCLineStyle, &values); | |
| 1504 if (bottom_line_thickness > 0 && bottom_gc != top_gc) | |
| 1505 XChangeGC (dpy, bottom_gc, GCLineStyle, &values); | |
| 1506 } | |
| 1507 | |
| 1508 while (num_separators--) | |
| 1509 { | |
| 1510 unsigned int i; | |
| 1511 for (i = 0; i < top_line_thickness; i++) | |
| 1512 XDrawLine (dpy, window, top_gc, x, y + i, x + width, y + i); | |
| 1513 | |
| 1514 for (i = 0; i < bottom_line_thickness; i++) | |
| 1515 XDrawLine (dpy, window, bottom_gc, | |
| 1516 x, y + top_line_thickness + offset + i, | |
| 1517 x + width, y + top_line_thickness + offset + i); | |
| 1518 y += (top_line_thickness + offset + bottom_line_thickness + 1); | |
| 1519 } | |
| 1520 | |
| 1521 if (dashed) | |
| 1522 { | |
| 1523 XGCValues values; | |
| 1524 values.line_style = LineSolid; | |
| 1525 if (top_line_thickness > 0) | |
| 1526 XChangeGC (dpy, top_gc, GCLineStyle, &values); | |
| 1527 if (bottom_line_thickness > 0 && bottom_gc != top_gc) | |
| 1528 XChangeGC (dpy, bottom_gc, GCLineStyle, &values); | |
| 1529 } | |
| 1530 } | |
| 1531 | |
| 1532 #define SLOPPY_TYPES 0 /* 0=off, 1=error check, 2=easy to please */ | |
| 1533 #if SLOPPY_TYPES | |
| 1534 #if SLOPPY_TYPES < 2 | |
| 1535 | |
| 1536 static char *wv_types[] = | |
| 1537 { | |
| 1538 "UNSPECIFIED", | |
| 1539 "BUTTON", | |
| 1540 "TOGGLE", | |
| 1541 "RADIO", | |
| 1542 "TEXT", | |
| 1543 "SEPARATOR", | |
| 1544 "CASCADE", | |
| 1545 "PUSHRIGHT", | |
| 1546 "INCREMENTAL" | |
| 1547 }; | |
| 1548 | |
| 1549 static void | |
| 1550 print_widget_value (widget_value *wv, int just_one, int depth) | |
| 1551 { | |
| 1552 char d [200]; | |
| 1553 int i; | |
| 1554 for (i = 0; i < depth; i++) | |
| 1555 d[i] = ' '; | |
| 1556 d[depth]=0; | |
| 1557 if (!wv) | |
| 1558 { | |
| 1559 printf ("%s(null widget value pointer)\n", d); | |
| 1560 return; | |
| 1561 } | |
| 1562 printf ("%stype: %s\n", d, wv_types [wv->type]); | |
| 1563 #if 0 | |
| 1564 printf ("%sname: %s\n", d, (wv->name ? wv->name : "(null)")); | |
| 1565 #else | |
| 1566 if (wv->name) printf ("%sname: %s\n", d, wv->name); | |
| 1567 #endif | |
| 1568 if (wv->value) printf ("%svalue: %s\n", d, wv->value); | |
| 1569 if (wv->key) printf ("%skey: %s\n", d, wv->key); | |
| 1570 printf ("%senabled: %d\n", d, wv->enabled); | |
| 1571 if (wv->contents) | |
| 1572 { | |
| 1573 printf ("\n%scontents: \n", d); | |
| 1574 print_widget_value (wv->contents, 0, depth + 5); | |
| 1575 } | |
| 1576 if (!just_one && wv->next) | |
| 1577 { | |
| 1578 printf ("\n"); | |
| 1579 print_widget_value (wv->next, 0, depth); | |
| 1580 } | |
| 1581 } | |
| 1582 #endif /* SLOPPY_TYPES < 2 */ | |
| 1583 | |
| 1584 static Boolean | |
| 1585 all_dashes_p (char *s) | |
| 1586 { | |
| 1587 char *p; | |
| 1588 if (!s || s[0] == '\0') | |
| 1589 return False; | |
| 1590 for (p = s; *p == '-'; p++); | |
| 1591 | |
| 1592 if (*p == '!' || *p == '\0') | |
| 1593 return True; | |
| 1594 return False; | |
| 1595 } | |
| 1596 #endif /* SLOPPY_TYPES */ | |
| 1597 | |
| 1598 static widget_value_type | |
| 1599 menu_item_type (widget_value *val) | |
| 1600 { | |
| 1601 if (val->type != UNSPECIFIED_TYPE) | |
| 1602 return val->type; | |
| 1603 #if SLOPPY_TYPES | |
| 1604 else if (all_dashes_p (val->name)) | |
| 1605 return SEPARATOR_TYPE; | |
| 1606 else if (val->name && val->name[0] == '\0') /* push right */ | |
| 1607 return PUSHRIGHT_TYPE; | |
| 1608 else if (val->contents) /* cascade */ | |
| 1609 return CASCADE_TYPE; | |
| 1610 else if (val->call_data) /* push button */ | |
| 1611 return BUTTON_TYPE; | |
| 1612 else | |
| 1613 return TEXT_TYPE; | |
| 1614 #else | |
| 442 | 1615 else |
| 428 | 1616 abort(); |
| 1617 return UNSPECIFIED_TYPE; /* Not reached */ | |
| 1618 #endif | |
| 1619 } | |
| 1620 | |
| 1621 static void | |
| 1622 label_button_size (XlwMenuWidget mw, | |
| 1623 widget_value *val, | |
| 2286 | 1624 Boolean UNUSED (in_menubar), |
| 428 | 1625 unsigned int *toggle_width, |
| 1626 unsigned int *label_width, | |
| 1627 unsigned int *bindings_width, | |
| 1628 unsigned int *height) | |
| 1629 { | |
| 1630 *height = (mw->menu.font_ascent + mw->menu.font_descent + | |
| 1631 2 * mw->menu.vertical_margin + | |
| 1632 2 * mw->menu.shadow_thickness); | |
| 1633 /* no left column decoration */ | |
| 430 | 1634 *toggle_width = mw->menu.horizontal_margin + mw->menu.shadow_thickness; |
| 428 | 1635 |
| 1636 *label_width = string_width_u (mw, resource_widget_value (mw, val)); | |
| 1637 *bindings_width = mw->menu.horizontal_margin + mw->menu.shadow_thickness; | |
| 1638 } | |
| 1639 | |
| 1640 static void | |
| 1641 label_button_draw (XlwMenuWidget mw, | |
| 1642 widget_value *val, | |
| 1643 Boolean in_menubar, | |
| 1644 Boolean highlighted, | |
| 1645 Window window, | |
| 1646 int x, int y, | |
| 2286 | 1647 unsigned int UNUSED (width), |
| 1648 unsigned int UNUSED (height), | |
| 428 | 1649 unsigned int label_offset, |
| 2286 | 1650 unsigned int UNUSED (binding_tab)) |
| 428 | 1651 { |
| 1652 int y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin; | |
| 1653 GC gc; | |
| 1654 | |
| 3094 | 1655 #ifdef USE_XFT_MENUBARS |
| 1656 XftColor color, colorBg; | |
| 1657 Display *display = XtDisplay (mw); | |
| 1658 Colormap cmap = mw->core.colormap; | |
| 1659 Visual *visual; | |
| 1660 int ignored, pixel, pixelBg; | |
| 1661 | |
| 1662 visual_info_from_widget ((Widget) mw, &visual, &ignored); | |
| 1663 #endif | |
| 1664 | |
| 428 | 1665 if (!label_offset) |
| 1666 label_offset = mw->menu.shadow_thickness + mw->menu.horizontal_margin; | |
| 1667 | |
| 3094 | 1668 if (highlighted && (in_menubar || val->contents)) |
| 1669 { | |
| 1670 #ifdef USE_XFT_MENUBARS | |
| 1671 pixel = mw->menu.highlight_foreground; | |
| 1672 pixelBg = mw->core.background_pixel; | |
| 1673 #endif | |
| 1674 gc = mw->menu.highlight_gc; | |
| 1675 } | |
| 428 | 1676 else if (in_menubar || val->contents) |
| 3094 | 1677 { |
| 1678 #ifdef USE_XFT_MENUBARS | |
| 1679 pixel = mw->menu.foreground; | |
| 1680 pixelBg = mw->core.background_pixel; | |
| 1681 #endif | |
| 1682 gc = mw->menu.foreground_gc; | |
| 1683 } | |
| 428 | 1684 else |
| 3094 | 1685 { |
| 1686 #ifdef USE_XFT_MENUBARS | |
| 1687 pixel = mw->menu.title_foreground; | |
| 1688 pixelBg = mw->core.background_pixel; | |
| 1689 #endif | |
| 1690 gc = mw->menu.title_gc; | |
| 1691 } | |
| 1692 #ifdef USE_XFT_MENUBARS | |
| 1693 color = xft_convert_color (display, cmap, visual, pixel, 0); | |
| 1694 colorBg = xft_convert_color (display, cmap, visual, pixelBg, 0); | |
| 1695 #endif | |
| 428 | 1696 |
| 1697 /* Draw the label string. */ | |
| 3094 | 1698 string_draw_u (mw, /* XXX */ |
| 1699 window, | |
| 1700 x + label_offset, y + y_offset, | |
| 1701 #ifdef USE_XFT_MENUBARS | |
| 1702 &color, &colorBg, gc, | |
| 1703 #else | |
| 428 | 1704 gc, |
| 3094 | 1705 #endif |
| 428 | 1706 resource_widget_value (mw, val)); |
| 1707 } | |
| 1708 | |
| 1709 static void | |
| 1710 push_button_size (XlwMenuWidget mw, | |
| 1711 widget_value *val, | |
| 1712 Boolean in_menubar, | |
| 1713 unsigned int *toggle_width, | |
| 1714 unsigned int *label_width, | |
| 1715 unsigned int *bindings_width, | |
| 1716 unsigned int *height) | |
| 1717 { | |
| 1718 /* inherit */ | |
| 1719 label_button_size (mw, val, in_menubar, | |
| 1720 toggle_width, label_width, bindings_width, | |
| 1721 height); | |
| 1722 | |
| 1723 /* key bindings to display? */ | |
| 1724 if (!in_menubar && val->key) | |
| 1725 { | |
| 1726 int w; | |
| 3094 | 1727 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) |
| 428 | 1728 XmString key = XmStringCreateLtoR (val->key, XmSTRING_DEFAULT_CHARSET); |
| 1729 w = string_width (mw, key); | |
| 1730 XmStringFree (key); | |
| 1731 #else | |
| 1732 char *key = val->key; | |
| 1733 w = string_width (mw, key); | |
| 1734 #endif | |
| 1735 *bindings_width += w + mw->menu.column_spacing; | |
| 1736 } | |
| 1737 } | |
| 1738 | |
| 1739 static void | |
| 1740 push_button_draw (XlwMenuWidget mw, | |
| 1741 widget_value *val, | |
| 1742 Boolean in_menubar, | |
| 1743 Boolean highlighted, | |
| 1744 Window window, | |
| 1745 int x, int y, | |
| 1746 unsigned int width, | |
| 1747 unsigned int height, | |
| 1748 unsigned int label_offset, | |
| 1749 unsigned int binding_offset) | |
| 1750 { | |
| 1751 int y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin; | |
| 1752 GC gc; | |
| 1753 shadow_type type; | |
| 1754 Boolean menu_pb = in_menubar && (menu_item_type (val) == BUTTON_TYPE); | |
| 1755 | |
| 3094 | 1756 #ifdef USE_XFT_MENUBARS |
| 1757 XftColor color, colorBg; | |
| 1758 Display *display = XtDisplay (mw); | |
| 1759 Colormap cmap = mw->core.colormap; | |
| 1760 Visual *visual; | |
| 1761 int ignored, pixel, pixelBg, dim = 0; | |
| 1762 | |
| 1763 visual_info_from_widget ((Widget) mw, &visual, &ignored); | |
| 1764 #endif | |
| 1765 | |
| 428 | 1766 /* Draw the label string. */ |
| 1767 if (!label_offset) | |
| 1768 label_offset = mw->menu.shadow_thickness + mw->menu.horizontal_margin; | |
| 1769 | |
| 1770 if (highlighted) | |
| 1771 { | |
| 1772 if (val->enabled) | |
| 3094 | 1773 { |
| 1774 #ifdef USE_XFT_MENUBARS | |
| 1775 pixel = mw->menu.highlight_foreground; | |
| 1776 pixelBg = mw->core.background_pixel; | |
| 1777 #endif | |
| 1778 gc = mw->menu.highlight_gc; | |
| 1779 } | |
| 428 | 1780 else |
| 3094 | 1781 { |
| 1782 #ifdef USE_XFT_MENUBARS | |
| 1783 dim = 1; | |
| 1784 pixel = mw->menu.foreground; | |
| 1785 pixelBg = mw->core.background_pixel; | |
| 1786 #endif | |
| 1787 gc = mw->menu.inactive_gc; | |
| 1788 } | |
| 428 | 1789 } |
| 1790 else if (menu_pb) | |
| 1791 { | |
| 1792 if (val->enabled) | |
| 3094 | 1793 { |
| 1794 #ifdef USE_XFT_MENUBARS | |
| 1795 pixel = mw->menu.button_foreground; | |
| 1796 pixelBg = mw->core.background_pixel; | |
| 1797 #endif | |
| 1798 gc = mw->menu.button_gc; | |
| 1799 } | |
| 428 | 1800 else |
| 3094 | 1801 { |
| 1802 #ifdef USE_XFT_MENUBARS | |
| 1803 dim = 1; | |
| 1804 pixel = mw->menu.button_foreground; | |
| 1805 pixelBg = mw->core.background_pixel; | |
| 1806 #endif | |
| 1807 gc = mw->menu.inactive_button_gc; | |
| 1808 } | |
| 428 | 1809 } |
| 1810 else | |
| 1811 { | |
| 1812 if (val->enabled) | |
| 3094 | 1813 { |
| 1814 #ifdef USE_XFT_MENUBARS | |
| 1815 pixel = mw->menu.foreground; | |
| 1816 pixelBg = mw->core.background_pixel; | |
| 1817 #endif | |
| 1818 gc = mw->menu.foreground_gc; | |
| 1819 } | |
| 428 | 1820 else |
| 3094 | 1821 { |
| 1822 #ifdef USE_XFT_MENUBARS | |
| 1823 dim = 1; | |
| 1824 pixel = mw->menu.foreground; | |
| 1825 pixelBg = mw->core.background_pixel; | |
| 1826 #endif | |
| 1827 gc = mw->menu.inactive_gc; | |
| 1828 } | |
| 428 | 1829 } |
| 1830 | |
| 3094 | 1831 #ifdef USE_XFT_MENUBARS |
| 1832 color = xft_convert_color (display, cmap, visual, pixel, dim); | |
| 1833 colorBg = xft_convert_color (display, cmap, visual, pixelBg, 0); | |
| 1834 #endif | |
| 1835 | |
| 428 | 1836 string_draw_u (mw, |
| 3094 | 1837 window, |
| 1838 x + label_offset, y + y_offset, | |
| 1839 #ifdef USE_XFT_MENUBARS | |
| 1840 &color, &colorBg, gc, | |
| 1841 #else | |
| 1842 gc, | |
| 1843 #endif | |
| 428 | 1844 resource_widget_value (mw, val)); |
| 1845 | |
| 1846 /* Draw the keybindings */ | |
| 1847 if (val->key) | |
| 1848 { | |
| 1849 if (!binding_offset) | |
| 1850 { | |
| 1851 unsigned int s_width = | |
| 1852 string_width (mw, resource_widget_value (mw, val)); | |
| 1853 binding_offset = label_offset + s_width + mw->menu.shadow_thickness; | |
| 1854 } | |
| 1855 binding_draw (mw, window, | |
| 1856 x + binding_offset + mw->menu.column_spacing, | |
| 3094 | 1857 y + y_offset, |
| 1858 #ifdef USE_XFT_MENUBARS | |
| 1859 &color, &colorBg, | |
| 1860 #else | |
| 1861 gc, | |
| 1862 #endif | |
| 1863 val->key); | |
| 428 | 1864 } |
| 1865 | |
| 1866 /* Draw the shadow */ | |
| 1867 if (menu_pb) | |
| 1868 { | |
| 1869 if (highlighted) | |
| 1870 type = SHADOW_OUT; | |
| 1871 else | |
| 1872 type = (val->selected ? SHADOW_ETCHED_OUT : SHADOW_ETCHED_IN); | |
| 1873 } | |
| 1874 else | |
| 1875 { | |
| 1876 if (highlighted) | |
| 1877 type = SHADOW_OUT; | |
| 1878 else | |
| 1879 type = SHADOW_BACKGROUND; | |
| 1880 } | |
| 1881 | |
| 1882 shadow_draw (mw, window, x, y, width, height, type); | |
| 1883 } | |
| 1884 | |
| 1885 static unsigned int | |
| 1886 arrow_decoration_height (XlwMenuWidget mw) | |
| 1887 { | |
| 1888 int result = (mw->menu.font_ascent + mw->menu.font_descent) / 2; | |
| 1889 | |
| 1890 result += 2 * mw->menu.shadow_thickness; | |
| 1891 | |
| 1892 if (result > (mw->menu.font_ascent + mw->menu.font_descent)) | |
| 1893 result = mw->menu.font_ascent + mw->menu.font_descent; | |
| 1894 | |
| 1895 return result; | |
| 1896 } | |
| 1897 | |
| 1898 static void | |
| 1899 cascade_button_size (XlwMenuWidget mw, | |
| 1900 widget_value *val, | |
| 1901 Boolean in_menubar, | |
| 1902 unsigned int *toggle_width, | |
| 1903 unsigned int *label_width, | |
| 1904 unsigned int *arrow_width, | |
| 1905 unsigned int *height) | |
| 1906 { | |
| 1907 /* inherit */ | |
| 1908 label_button_size (mw, val, in_menubar, | |
| 1909 toggle_width, label_width, arrow_width, | |
| 1910 height); | |
| 1911 /* we have a pull aside arrow */ | |
| 1912 if (!in_menubar) | |
| 1913 { | |
| 1914 *arrow_width += arrow_decoration_height (mw) + mw->menu.column_spacing; | |
| 1915 } | |
| 1916 } | |
| 1917 | |
| 1918 static void | |
| 1919 cascade_button_draw (XlwMenuWidget mw, | |
| 1920 widget_value *val, | |
| 1921 Boolean in_menubar, | |
| 1922 Boolean highlighted, | |
| 1923 Window window, | |
| 1924 int x, int y, | |
| 1925 unsigned int width, | |
| 1926 unsigned int height, | |
| 1927 unsigned int label_offset, | |
| 1928 unsigned int binding_offset) | |
| 1929 { | |
| 1930 shadow_type type; | |
| 1931 | |
| 1932 /* Draw the label string. */ | |
| 1933 label_button_draw (mw, val, in_menubar, highlighted, | |
| 1934 window, x, y, width, height, label_offset, | |
| 1935 binding_offset); | |
| 1936 | |
| 1937 /* Draw the pull aside arrow */ | |
| 1938 if (!in_menubar && val->contents) | |
| 1939 { | |
| 1940 int y_offset; | |
| 1941 unsigned int arrow_height = arrow_decoration_height (mw); | |
| 1942 | |
| 1943 y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin + | |
| 1944 (mw->menu.font_ascent+mw->menu.font_descent - arrow_height)/2; | |
| 1945 | |
| 1946 if (!binding_offset) | |
| 1947 { | |
| 1948 unsigned int s_width = | |
| 1949 string_width (mw, resource_widget_value (mw, val)); | |
| 1950 | |
| 1951 if (!label_offset) | |
| 1952 label_offset = mw->menu.shadow_thickness + | |
| 1953 mw->menu.horizontal_margin; | |
| 1954 | |
| 1955 binding_offset = label_offset + s_width + mw->menu.shadow_thickness; | |
| 1956 } | |
| 1957 | |
| 1958 arrow_decoration_draw (mw, | |
| 1959 window, | |
| 1960 x + binding_offset + mw->menu.column_spacing, | |
| 1961 y + y_offset, | |
| 1962 arrow_height, | |
| 1963 highlighted); | |
| 1964 } | |
| 1965 | |
| 1966 /* Draw the shadow */ | |
| 1967 if (highlighted) | |
| 1968 type = SHADOW_OUT; | |
| 1969 else | |
| 1970 type = SHADOW_BACKGROUND; | |
| 1971 | |
| 1972 shadow_draw (mw, window, x, y, width, height, type); | |
| 1973 } | |
| 1974 | |
| 1975 static unsigned int | |
| 1976 toggle_decoration_height (XlwMenuWidget mw) | |
| 1977 { | |
| 1978 int rv; | |
| 1979 if (mw->menu.indicator_size > 0) | |
| 1980 rv = mw->menu.indicator_size; | |
| 1981 else | |
| 1982 rv = mw->menu.font_ascent; | |
| 1983 | |
| 1984 if (rv > (mw->menu.font_ascent + mw->menu.font_descent)) | |
| 1985 rv = mw->menu.font_ascent + mw->menu.font_descent; | |
| 1986 | |
| 1987 /* radio button can't be smaller than its border or a filling | |
| 1988 error will occur. */ | |
| 1989 if (rv < 2 * mw->menu.shadow_thickness) | |
| 1990 rv = 2 * mw->menu.shadow_thickness; | |
| 1991 | |
| 1992 return rv; | |
| 1993 } | |
| 1994 | |
| 1995 static void | |
| 1996 toggle_button_size (XlwMenuWidget mw, | |
| 1997 widget_value *val, | |
| 1998 Boolean in_menubar, | |
| 1999 unsigned int *toggle_width, | |
| 2000 unsigned int *label_width, | |
| 2001 unsigned int *bindings_width, | |
| 2002 unsigned int *height) | |
| 2003 { | |
| 2004 /* inherit */ | |
| 2005 push_button_size (mw, val, in_menubar, | |
| 2006 toggle_width, label_width, bindings_width, | |
| 2007 height); | |
| 2008 /* we have a toggle */ | |
| 2009 *toggle_width += toggle_decoration_height (mw) + mw->menu.column_spacing; | |
| 2010 } | |
| 2011 | |
| 2012 static void | |
| 2013 toggle_button_draw (XlwMenuWidget mw, | |
| 2014 widget_value *val, | |
| 2015 Boolean in_menubar, | |
| 2016 Boolean highlighted, | |
| 2017 Window window, | |
| 2018 int x, int y, | |
| 2019 unsigned int width, | |
| 2020 unsigned int height, | |
| 2021 unsigned int label_tab, | |
| 2022 unsigned int binding_tab) | |
| 2023 { | |
| 2024 int x_offset; | |
| 2025 int y_offset; | |
| 2026 unsigned int t_height = toggle_decoration_height (mw); | |
| 2027 | |
| 2028 /* Draw a toggle. */ | |
| 2029 x_offset = mw->menu.shadow_thickness + mw->menu.horizontal_margin; | |
| 2030 y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin; | |
| 2031 y_offset += (mw->menu.font_ascent + mw->menu.font_descent - t_height)/2; | |
| 2032 | |
| 2033 toggle_decoration_draw (mw, window, x + x_offset, y + y_offset, | |
| 2034 t_height, val->selected); | |
| 2035 | |
| 2036 /* Draw the pushbutton parts. */ | |
| 2037 push_button_draw (mw, val, in_menubar, highlighted, window, x, y, width, | |
| 2038 height, label_tab, binding_tab); | |
| 2039 } | |
| 2040 | |
| 2041 static unsigned int | |
| 2042 radio_decoration_height (XlwMenuWidget mw) | |
| 2043 { | |
| 2044 return toggle_decoration_height (mw); | |
| 2045 } | |
| 2046 | |
| 2047 static void | |
| 2048 radio_button_draw (XlwMenuWidget mw, | |
| 2049 widget_value *val, | |
| 2050 Boolean in_menubar, | |
| 2051 Boolean highlighted, | |
| 2052 Window window, | |
| 2053 int x, int y, | |
| 2054 unsigned int width, | |
| 2055 unsigned int height, | |
| 2056 unsigned int label_tab, | |
| 2057 unsigned int binding_tab) | |
| 2058 { | |
| 2059 int x_offset; | |
| 2060 int y_offset; | |
| 2061 unsigned int r_height = radio_decoration_height (mw); | |
| 2062 | |
| 2063 /* Draw a toggle. */ | |
| 2064 x_offset = mw->menu.shadow_thickness + mw->menu.horizontal_margin; | |
| 2065 y_offset = mw->menu.shadow_thickness + mw->menu.vertical_margin; | |
| 2066 y_offset += (mw->menu.font_ascent + mw->menu.font_descent - r_height)/2; | |
| 2067 | |
| 2068 radio_decoration_draw (mw, window, x + x_offset, y + y_offset, r_height, | |
| 2069 val->selected); | |
| 2070 | |
| 2071 /* Draw the pushbutton parts. */ | |
| 2072 push_button_draw (mw, val, in_menubar, highlighted, window, x, y, width, | |
| 2073 height, label_tab, binding_tab); | |
| 2074 } | |
| 2075 | |
| 2076 static struct _shadow_names | |
| 2077 { | |
| 442 | 2078 const char * name; |
| 428 | 2079 shadow_type type; |
| 2080 } shadow_names[] = | |
| 2081 { | |
| 2082 /* Motif */ | |
| 2083 { "singleLine", SHADOW_SINGLE_LINE }, | |
| 2084 { "doubleLine", SHADOW_DOUBLE_LINE }, | |
| 2085 { "singleDashedLine", SHADOW_SINGLE_DASHED_LINE }, | |
| 2086 { "doubleDashedLine", SHADOW_DOUBLE_DASHED_LINE }, | |
| 2087 { "noLine", SHADOW_NO_LINE }, | |
| 2088 { "shadowEtchedIn", SHADOW_ETCHED_IN }, | |
| 2089 { "shadowEtchedOut", SHADOW_ETCHED_OUT }, | |
| 2090 { "shadowEtchedInDash", SHADOW_ETCHED_IN_DASH }, | |
| 2091 { "shadowEtchedOutDash", SHADOW_ETCHED_OUT_DASH }, | |
| 2092 /* non-Motif */ | |
| 2093 { "shadowDoubleEtchedIn", SHADOW_DOUBLE_ETCHED_IN }, | |
| 2094 { "shadowDoubleEtchedOut", SHADOW_DOUBLE_ETCHED_OUT }, | |
| 2095 { "shadowDoubleEtchedInDash", SHADOW_DOUBLE_ETCHED_IN_DASH }, | |
| 2096 { "shadowDoubleEtchedOutDash", SHADOW_DOUBLE_ETCHED_OUT_DASH } | |
| 2097 }; | |
| 2098 | |
| 2099 static shadow_type | |
| 2100 separator_type (char *name) | |
| 2101 { | |
| 2102 if (name) | |
| 2103 { | |
| 2104 int i; | |
| 2105 for (i = 0; i < (int) (XtNumber (shadow_names)); i++ ) | |
| 2106 { | |
| 2107 if (strcmp (name, shadow_names[i].name) == 0) | |
| 2108 return shadow_names[i].type; | |
| 2109 } | |
| 2110 } | |
| 2111 return SHADOW_BACKGROUND; | |
| 2112 } | |
| 2113 | |
| 2114 static unsigned int | |
| 2115 separator_decoration_height (XlwMenuWidget mw, widget_value *val) | |
| 2116 { | |
| 2117 | |
| 2118 switch (separator_type (val->value)) | |
| 2119 { | |
| 2120 case SHADOW_NO_LINE: | |
| 2121 case SHADOW_SINGLE_LINE: | |
| 2122 case SHADOW_SINGLE_DASHED_LINE: | |
| 2123 return 1; | |
| 2124 case SHADOW_DOUBLE_LINE: | |
| 2125 case SHADOW_DOUBLE_DASHED_LINE: | |
| 2126 return 3; | |
| 2127 case SHADOW_DOUBLE_ETCHED_OUT: | |
| 2128 case SHADOW_DOUBLE_ETCHED_IN: | |
| 2129 case SHADOW_DOUBLE_ETCHED_OUT_DASH: | |
| 2130 case SHADOW_DOUBLE_ETCHED_IN_DASH: | |
| 2131 return (1 + 2 * mw->menu.shadow_thickness); | |
| 2132 case SHADOW_ETCHED_OUT: | |
| 2133 case SHADOW_ETCHED_IN: | |
| 2134 default: | |
| 2135 return mw->menu.shadow_thickness; | |
| 2136 } | |
| 2137 } | |
| 2138 | |
| 2139 static void | |
| 2140 separator_size (XlwMenuWidget mw, | |
| 2141 widget_value *val, | |
| 2286 | 2142 Boolean UNUSED (in_menubar), |
| 428 | 2143 unsigned int *toggle_width, |
| 2144 unsigned int *label_width, | |
| 2145 unsigned int *rest_width, | |
| 2146 unsigned int *height) | |
| 2147 { | |
| 2148 *height = separator_decoration_height (mw, val); | |
| 2149 *label_width = 1; | |
| 2150 *toggle_width = *rest_width = 0; | |
| 2151 } | |
| 2152 | |
| 2153 static void | |
| 2154 separator_draw (XlwMenuWidget mw, | |
| 2155 widget_value *val, | |
| 2156 Boolean in_menubar, | |
| 2286 | 2157 Boolean UNUSED (highlighted), |
| 428 | 2158 Window window, |
| 2159 int x, int y, | |
| 2160 unsigned int width, | |
| 2161 unsigned int height, | |
| 2286 | 2162 unsigned int UNUSED (label_tab), |
| 2163 unsigned int UNUSED (binding_tab)) | |
| 428 | 2164 { |
| 2165 unsigned int sep_width; | |
| 2166 | |
| 2167 if (in_menubar) | |
| 2168 sep_width = height; | |
| 2169 else | |
| 2170 sep_width = width; | |
| 2171 | |
| 2172 separator_decoration_draw (mw, | |
| 2173 window, | |
| 2174 x, | |
| 2175 y, | |
| 2176 sep_width, | |
| 2177 in_menubar, | |
| 2178 separator_type(val->value)); | |
| 2179 } | |
| 2180 | |
| 2181 static void | |
| 2286 | 2182 pushright_size (XlwMenuWidget UNUSED (mw), |
| 2183 widget_value *UNUSED (val), | |
| 2184 Boolean UNUSED (in_menubar), | |
| 428 | 2185 unsigned int *toggle_width, |
| 2186 unsigned int *label_width, | |
| 2187 unsigned int *rest_width, | |
| 2188 unsigned int *height) | |
| 2189 { | |
| 2190 *height = *label_width = *toggle_width = *rest_width = 0; | |
| 2191 } | |
| 2192 | |
| 2193 static void | |
| 2194 size_menu_item (XlwMenuWidget mw, | |
| 2195 widget_value *val, | |
| 2196 int horizontal, | |
| 2197 unsigned int *toggle_width, | |
| 2198 unsigned int *label_width, | |
| 2199 unsigned int *rest_width, | |
| 2200 unsigned int *height) | |
| 2201 { | |
| 2202 void (*function_ptr) (XlwMenuWidget _mw, | |
| 2203 widget_value *_val, | |
| 2204 Boolean _in_menubar, | |
| 2205 unsigned int *_toggle_width, | |
| 2206 unsigned int *_label_width, | |
| 2207 unsigned int *_rest_width, | |
| 2208 unsigned int *_height); | |
| 2209 | |
| 2210 switch (menu_item_type (val)) | |
| 2211 { | |
| 2212 case TOGGLE_TYPE: | |
| 2213 case RADIO_TYPE: | |
| 2214 function_ptr = toggle_button_size; | |
| 2215 break; | |
| 2216 case SEPARATOR_TYPE: | |
| 2217 function_ptr = separator_size; | |
| 2218 break; | |
| 2219 case INCREMENTAL_TYPE: | |
| 2220 case CASCADE_TYPE: | |
| 2221 function_ptr = cascade_button_size; | |
| 2222 break; | |
| 2223 case BUTTON_TYPE: | |
| 2224 function_ptr = push_button_size; | |
| 2225 break; | |
| 2226 case PUSHRIGHT_TYPE: | |
| 2227 function_ptr = pushright_size; | |
| 2228 break; | |
| 2229 case TEXT_TYPE: | |
| 2230 default: | |
| 2231 function_ptr = label_button_size; | |
| 2232 break; | |
| 2233 } | |
| 2234 | |
| 2235 (*function_ptr) (mw, | |
| 2236 val, | |
| 2237 horizontal, | |
| 2238 toggle_width, | |
| 2239 label_width, | |
| 2240 rest_width, | |
| 2241 height); | |
| 2242 } | |
| 2243 | |
| 2244 static void | |
| 2245 display_menu_item (XlwMenuWidget mw, | |
| 2246 widget_value *val, | |
| 2247 window_state *ws, | |
| 2248 XPoint *where, | |
| 2249 Boolean highlighted, | |
| 2250 Boolean horizontal, | |
| 2251 Boolean just_compute) | |
| 2252 { | |
| 2253 | |
| 2254 int x = where->x /* + mw->menu.shadow_thickness */ ; | |
| 2255 int y = where->y /* + mw->menu.shadow_thickness */ ; | |
| 2256 unsigned int toggle_width; | |
| 2257 unsigned int label_width; | |
| 2258 unsigned int binding_width; | |
| 2259 unsigned int width; | |
| 2260 unsigned int height; | |
| 2261 unsigned int label_tab; | |
| 2262 unsigned int binding_tab; | |
| 2263 void (*function_ptr) (XlwMenuWidget _mw, | |
| 2264 widget_value *_val, | |
| 2265 Boolean _in_menubar, | |
| 2266 Boolean _highlighted, | |
| 2267 Window _window, | |
| 2268 int _x, int _y, | |
| 2269 unsigned int _width, | |
| 2270 unsigned int _height, | |
| 2271 unsigned int _label_tab, | |
| 2272 unsigned int _binding_tab); | |
| 2273 | |
| 2274 size_menu_item (mw, val, horizontal, | |
| 2275 &toggle_width, &label_width, &binding_width, &height); | |
| 2276 | |
| 2277 if (horizontal) | |
| 2278 { | |
| 2279 width = toggle_width + label_width + binding_width; | |
| 2280 height = ws->height - 2 * mw->menu.shadow_thickness; | |
| 2281 } | |
| 2282 else | |
| 2283 { | |
| 2284 width = ws->width - 2 * mw->menu.shadow_thickness; | |
| 2285 toggle_width = ws->toggle_width; | |
| 2286 label_width = ws->label_width; | |
| 2287 } | |
| 2288 | |
| 2289 where->x += width; | |
| 2290 where->y += height; | |
| 2291 | |
| 2292 if (just_compute) | |
| 2293 return; | |
| 2294 | |
| 2295 label_tab = toggle_width; | |
| 2296 binding_tab = toggle_width + label_width; | |
| 2297 | |
| 2298 switch (menu_item_type (val)) | |
| 2299 { | |
| 2300 case TOGGLE_TYPE: | |
| 2301 function_ptr = toggle_button_draw; | |
| 2302 break; | |
| 2303 case RADIO_TYPE: | |
| 2304 function_ptr = radio_button_draw; | |
| 2305 break; | |
| 2306 case SEPARATOR_TYPE: | |
| 2307 function_ptr = separator_draw; | |
| 2308 break; | |
| 2309 case INCREMENTAL_TYPE: | |
| 2310 case CASCADE_TYPE: | |
| 2311 function_ptr = cascade_button_draw; | |
| 2312 break; | |
| 2313 case BUTTON_TYPE: | |
| 2314 function_ptr = push_button_draw; | |
| 2315 break; | |
| 2316 case TEXT_TYPE: | |
| 2317 function_ptr = label_button_draw; | |
| 2318 break; | |
| 2319 default: /* do no drawing */ | |
| 2320 return; | |
| 2321 } | |
| 2322 | |
| 2323 (*function_ptr) (mw, | |
| 2324 val, | |
| 2325 horizontal, | |
| 2326 highlighted, | |
| 2327 ws->window, | |
| 2328 x, y, | |
| 2329 width, height, | |
| 2330 label_tab, | |
| 2331 binding_tab); | |
| 2332 } | |
| 2333 | |
| 2334 static void | |
| 2335 size_menu (XlwMenuWidget mw, int level) | |
| 2336 { | |
| 2337 unsigned int toggle_width; | |
| 2338 unsigned int label_width; | |
| 2339 unsigned int rest_width; | |
| 2340 unsigned int height; | |
| 2341 unsigned int max_toggle_width = 0; | |
| 2342 unsigned int max_label_width = 0; | |
| 2343 unsigned int max_rest_width = 0; | |
| 2344 unsigned int max_height = 0; | |
| 2345 int horizontal_p = mw->menu.horizontal && (level == 0); | |
| 2346 widget_value* val; | |
| 2347 window_state* ws; | |
| 2348 | |
| 2349 if (level >= mw->menu.old_depth) | |
| 2350 abort (); | |
| 2351 | |
| 2352 ws = &mw->menu.windows [level]; | |
| 2353 | |
| 2354 for (val = mw->menu.old_stack [level]->contents; val; val = val->next) | |
| 2355 { | |
| 2356 size_menu_item (mw, | |
| 2357 val, | |
| 2358 horizontal_p, | |
| 2359 &toggle_width, | |
| 2360 &label_width, | |
| 2361 &rest_width, | |
| 2362 &height); | |
| 2363 if (horizontal_p) | |
| 2364 { | |
| 2365 max_label_width += toggle_width + label_width + rest_width; | |
| 2366 if (height > max_height) | |
| 2367 max_height = height; | |
| 2368 } | |
| 2369 else | |
| 2370 { | |
| 2371 if (max_toggle_width < toggle_width) | |
| 2372 max_toggle_width = toggle_width; | |
| 2373 if (max_label_width < label_width) | |
| 2374 max_label_width = label_width; | |
| 2375 if (max_rest_width < rest_width) | |
| 2376 max_rest_width = rest_width; | |
| 2377 max_height += height; | |
| 2378 } | |
| 2379 } | |
| 2380 | |
| 2381 ws->height = max_height; | |
| 2382 ws->width = max_label_width + max_rest_width + max_toggle_width; | |
| 2383 ws->toggle_width = max_toggle_width; | |
| 2384 ws->label_width = max_label_width; | |
| 2385 | |
| 2386 ws->width += 2 * mw->menu.shadow_thickness; | |
| 2387 ws->height += 2 * mw->menu.shadow_thickness; | |
| 2388 } | |
| 2389 | |
| 2390 static void | |
| 2391 display_menu (XlwMenuWidget mw, int level, Boolean just_compute_p, | |
| 2392 XPoint *highlighted_pos, XPoint *hit, widget_value **hit_return, | |
| 1201 | 2393 widget_value *this_, widget_value *that) |
| 428 | 2394 { |
| 2395 widget_value *val; | |
| 2396 widget_value *following_item; | |
| 2397 window_state *ws; | |
| 2398 XPoint where; | |
| 2399 int horizontal_p = mw->menu.horizontal && (level == 0); | |
| 2400 int highlighted_p; | |
| 2401 int just_compute_this_one_p; | |
| 2402 | |
| 2403 if (level >= mw->menu.old_depth) | |
| 2404 abort (); | |
| 2405 | |
| 2406 if (level < mw->menu.old_depth - 1) | |
| 2407 following_item = mw->menu.old_stack [level + 1]; | |
| 2408 else | |
| 2409 { | |
| 2410 if (lw_menu_accelerate | |
| 2411 && level == mw->menu.old_depth - 1 | |
| 2412 && mw->menu.old_stack [level]->type == CASCADE_TYPE) | |
| 2413 just_compute_p = True; | |
| 2414 following_item = NULL; | |
| 2415 } | |
| 2416 | |
| 2417 #if SLOPPY_TYPES == 1 | |
| 2418 puts("==================================================================="); | |
| 2419 print_widget_value (following_item, 1, 0); | |
| 2420 #endif | |
| 2421 | |
| 2422 if (hit) | |
| 2423 *hit_return = NULL; | |
| 2424 | |
| 2425 where.x = mw->menu.shadow_thickness; | |
| 2426 where.y = mw->menu.shadow_thickness; | |
| 2427 | |
| 2428 ws = &mw->menu.windows [level]; | |
| 2429 for (val = mw->menu.old_stack [level]->contents; val; val = val->next) | |
| 2430 { | |
| 2431 XPoint start; | |
| 2432 | |
| 2433 highlighted_p = (val == following_item); | |
| 2434 /* If this is the partition (the dummy item which says that menus | |
| 2435 after this should be flushright) then figure out how big the | |
| 2436 following items are. This means we walk down the tail of the | |
| 2437 list twice, but that's no big deal - it's short. | |
| 2438 */ | |
| 2439 if (horizontal_p && (menu_item_type (val) == PUSHRIGHT_TYPE)) | |
| 2440 { | |
| 2441 widget_value *rest; | |
| 2442 XPoint flushright_size; | |
| 2443 int new_x; | |
| 2444 flushright_size.x = 0; | |
| 2445 flushright_size.y = 0; | |
| 2446 for (rest = val; rest; rest = rest->next) | |
| 2447 display_menu_item (mw, rest, ws, &flushright_size, | |
| 2448 highlighted_p, horizontal_p, True); | |
| 2449 new_x = ws->width - (flushright_size.x + mw->menu.shadow_thickness); | |
| 2450 if (new_x > where.x) | |
| 2451 where.x = new_x; | |
| 2452 /* We know what we need; don't draw this item. */ | |
| 2453 continue; | |
| 2454 } | |
| 2455 | |
| 2456 if (highlighted_p && highlighted_pos) | |
| 2457 { | |
| 2458 if (horizontal_p) | |
| 2459 highlighted_pos->x = where.x; | |
| 2460 else | |
| 2461 highlighted_pos->y = where.y; | |
| 2462 } | |
| 2463 | |
| 2464 just_compute_this_one_p = | |
| 1201 | 2465 just_compute_p || ((this_ || that) && val != this_ && val != that); |
| 428 | 2466 |
| 2467 start.x = where.x; | |
| 2468 start.y = where.y; | |
| 2469 display_menu_item (mw, val, ws, &where, highlighted_p, horizontal_p, | |
| 2470 just_compute_this_one_p); | |
| 2471 | |
| 2472 if (highlighted_p && highlighted_pos) | |
| 2473 { | |
| 2474 if (horizontal_p) | |
| 2475 highlighted_pos->y = ws->height; | |
| 2476 else | |
| 2477 highlighted_pos->x = ws->width; | |
| 2478 } | |
| 2479 | |
| 2480 if (hit && !*hit_return) | |
| 2481 { | |
| 2482 if (horizontal_p && hit->x > start.x && hit->x <= where.x) | |
| 2483 *hit_return = val; | |
| 2484 else if (!horizontal_p && hit->y > start.y && hit->y <= where.y) | |
| 2485 *hit_return = val; | |
| 2486 } | |
| 2487 | |
| 2488 if (horizontal_p) | |
| 2489 where.y = mw->menu.shadow_thickness; | |
| 2490 else | |
| 2491 where.x = mw->menu.shadow_thickness; | |
| 2492 } | |
| 2493 | |
| 2494 /* Draw slab edges around menu */ | |
| 2495 if (!just_compute_p) | |
| 2496 shadow_draw(mw, ws->window, 0, 0, ws->width, ws->height, SHADOW_OUT); | |
| 2497 } | |
| 2498 | |
| 2499 /* Motion code */ | |
| 2500 static void | |
| 2501 set_new_state (XlwMenuWidget mw, widget_value *val, int level) | |
| 2502 { | |
| 2503 int i; | |
| 2504 | |
| 2505 mw->menu.new_depth = 0; | |
| 2506 for (i = 0; i < level; i++) | |
| 2507 push_new_stack (mw, mw->menu.old_stack [i]); | |
| 2508 if (val) | |
| 2509 push_new_stack (mw, val); | |
| 2510 } | |
| 2511 | |
| 2512 static void | |
| 2513 make_windows_if_needed (XlwMenuWidget mw, int n) | |
| 2514 { | |
| 2515 int i; | |
| 2516 int start_at; | |
| 2517 XSetWindowAttributes xswa; | |
| 2518 Widget p; | |
| 446 | 2519 unsigned long mask; |
| 428 | 2520 int depth; |
| 2521 Visual *visual; | |
| 2522 window_state *windows; | |
| 2523 Window root; | |
| 2524 | |
| 2525 if (mw->menu.windows_length >= n) | |
| 2526 return; | |
| 2527 | |
| 2528 root = RootWindowOfScreen (XtScreen(mw)); | |
| 3094 | 2529 /* use visual_info_from_widget() from lwlib-colors.c */ |
| 428 | 2530 /* grab the visual and depth from the nearest shell ancestor */ |
| 2531 visual = CopyFromParent; | |
| 2532 depth = CopyFromParent; | |
| 2533 p = XtParent(mw); | |
| 2534 while (visual == CopyFromParent && p) | |
| 2535 { | |
| 2536 if (XtIsShell(p)) | |
| 2537 { | |
| 2538 visual = ((ShellWidget)p)->shell.visual; | |
| 2539 depth = p->core.depth; | |
| 2540 } | |
| 2541 p = XtParent(p); | |
| 2542 } | |
| 2543 | |
| 2544 xswa.save_under = True; | |
| 2545 xswa.override_redirect = True; | |
| 2546 xswa.background_pixel = mw->core.background_pixel; | |
| 2547 xswa.border_pixel = mw->core.border_pixel; | |
| 2548 xswa.event_mask = (ExposureMask | ButtonMotionMask | |
| 2549 | ButtonReleaseMask | ButtonPressMask); | |
| 2550 xswa.cursor = mw->menu.cursor_shape; | |
| 2551 xswa.colormap = mw->core.colormap; | |
| 2552 mask = CWSaveUnder | CWOverrideRedirect | CWBackPixel | CWBorderPixel | |
| 2553 | CWEventMask | CWCursor | CWColormap; | |
| 2554 | |
| 2555 if (mw->menu.use_backing_store) | |
| 2556 { | |
| 2557 xswa.backing_store = Always; | |
| 2558 mask |= CWBackingStore; | |
| 2559 } | |
| 2560 | |
| 2561 if (!mw->menu.windows) | |
| 2562 { | |
| 2563 mw->menu.windows = | |
| 2564 (window_state *) XtMalloc (n * sizeof (window_state)); | |
| 2565 start_at = 0; | |
| 2566 } | |
| 2567 else | |
| 2568 { | |
| 2569 mw->menu.windows = | |
| 2570 (window_state *) XtRealloc ((char *) mw->menu.windows, | |
| 2571 n * sizeof (window_state)); | |
| 2572 start_at = mw->menu.windows_length; | |
| 2573 } | |
| 2574 mw->menu.windows_length = n; | |
| 2575 | |
| 2576 windows = mw->menu.windows; | |
| 2577 | |
| 2578 for (i = start_at; i < n; i++) | |
| 2579 { | |
| 2580 windows [i].x = 0; | |
| 2581 windows [i].y = 0; | |
| 2582 windows [i].width = 1; | |
| 2583 windows [i].height = 1; | |
| 2584 windows [i].window = | |
| 2585 XCreateWindow (XtDisplay (mw), | |
| 2586 root, | |
| 2587 0, 0, 1, 1, | |
| 2588 0, depth, CopyFromParent, visual, mask, &xswa); | |
| 2589 } | |
| 2590 } | |
| 2591 | |
| 2592 /* Make the window fit in the screen */ | |
| 2593 static void | |
| 2594 fit_to_screen (XlwMenuWidget mw, window_state *ws, window_state *previous_ws, | |
| 2595 Boolean horizontal_p) | |
| 2596 { | |
| 2597 int screen_width = WidthOfScreen (XtScreen (mw)); | |
| 2598 int screen_height = HeightOfScreen (XtScreen (mw)); | |
| 2599 | |
| 2600 if (ws->x < 0) | |
| 2601 ws->x = 0; | |
| 2602 else if ((int) (ws->x + ws->width) > screen_width) | |
| 2603 { | |
| 2604 if (!horizontal_p) | |
| 2605 ws->x = previous_ws->x - ws->width; | |
| 2606 else | |
| 2607 { | |
| 2608 ws->x = screen_width - ws->width; | |
| 2609 | |
| 2610 /* This check is to make sure we cut off the right side | |
| 2611 instead of the left side if the menu is wider than the | |
| 2612 screen. */ | |
| 2613 if (ws->x < 0) | |
| 2614 ws->x = 0; | |
| 2615 } | |
| 2616 } | |
| 2617 if (ws->y < 0) | |
| 2618 ws->y = 0; | |
| 2619 else if ((int) (ws->y + ws->height) > screen_height) | |
| 2620 { | |
| 2621 if (horizontal_p) | |
| 2622 { | |
| 2623 /* A pulldown must either be entirely above or below the menubar. | |
| 2624 If we're here, the pulldown doesn't fit below the menubar, so | |
| 2625 let's determine if it will fit above the menubar. | |
| 2626 Only put it above if there is more room above than below. | |
| 2627 Note shadow_thickness offset to allow for slab surround. | |
| 2628 */ | |
| 2629 if (ws->y > (screen_height / 2)) | |
| 2630 ws->y = previous_ws->y - ws->height + mw->menu.shadow_thickness; | |
| 2631 } | |
| 2632 else | |
| 2633 { | |
| 2634 ws->y = screen_height - ws->height; | |
| 2635 /* if it's taller than the screen, display the topmost part | |
| 2636 that will fit, beginning at the top of the screen. */ | |
| 2637 if (ws->y < 0) | |
| 2638 ws->y = 0; | |
| 2639 } | |
| 2640 } | |
| 2641 } | |
| 2642 | |
| 2643 /* Updates old_stack from new_stack and redisplays. */ | |
| 2644 static void | |
| 2645 remap_menubar (XlwMenuWidget mw) | |
| 2646 { | |
| 2647 int i; | |
| 2648 int last_same; | |
| 2649 XPoint selection_position; | |
| 2650 int old_depth = mw->menu.old_depth; | |
| 2651 int new_depth = mw->menu.new_depth; | |
| 2652 widget_value **old_stack; | |
| 2653 widget_value **new_stack; | |
| 2654 window_state *windows; | |
| 2655 widget_value *old_selection; | |
| 2656 widget_value *new_selection; | |
| 2657 | |
| 2658 /* Check that enough windows and old_stack are ready. */ | |
| 2659 make_windows_if_needed (mw, new_depth); | |
| 2660 make_old_stack_space (mw, new_depth); | |
| 2661 windows = mw->menu.windows; | |
| 2662 old_stack = mw->menu.old_stack; | |
| 2663 new_stack = mw->menu.new_stack; | |
| 2664 | |
| 2665 /* compute the last identical different entry */ | |
| 2666 for (i = 1; i < old_depth && i < new_depth; i++) | |
| 2667 if (old_stack [i] != new_stack [i]) | |
| 2668 break; | |
| 2669 last_same = i - 1; | |
| 2670 | |
| 2671 if (lw_menu_accelerate | |
| 2672 && last_same | |
| 2673 && last_same == old_depth - 1 | |
| 2674 && old_stack [last_same]->contents) | |
| 2675 last_same--; | |
| 2676 | |
| 2677 /* Memorize the previously selected item to be able to refresh it */ | |
| 2678 old_selection = last_same + 1 < old_depth ? old_stack [last_same + 1] : NULL; | |
| 2679 new_selection = last_same + 1 < new_depth ? new_stack [last_same + 1] : NULL; | |
| 2680 | |
| 2681 /* updates old_state from new_state. It has to be done now because | |
| 2682 display_menu (called below) uses the old_stack to know what to display. */ | |
| 2683 for (i = last_same + 1; i < new_depth; i++) | |
| 2684 old_stack [i] = new_stack [i]; | |
| 2685 | |
| 2686 mw->menu.old_depth = new_depth; | |
| 2687 | |
| 442 | 2688 /* refresh the last selection */ |
| 428 | 2689 selection_position.x = 0; |
| 2690 selection_position.y = 0; | |
| 2691 display_menu (mw, last_same, new_selection == old_selection, | |
| 2692 &selection_position, NULL, NULL, old_selection, new_selection); | |
| 2693 | |
| 2694 /* Now popup the new menus */ | |
| 2695 for (i = last_same + 1; i < new_depth && new_stack [i]->contents; i++) | |
| 2696 { | |
| 2697 window_state *previous_ws = &windows [i - 1]; | |
| 2698 window_state *ws = &windows [i]; | |
| 2699 | |
| 2700 if (lw_menu_accelerate && i == new_depth - 1) | |
| 2701 break; | |
| 2702 | |
| 2703 ws->x = previous_ws->x + selection_position.x; | |
| 2704 ws->y = previous_ws->y + selection_position.y; | |
| 2705 | |
| 2706 /* take into account the slab around the new menu */ | |
| 2707 ws->y -= mw->menu.shadow_thickness; | |
| 2708 | |
| 2709 { | |
| 2710 widget_value *val = mw->menu.old_stack [i]; | |
| 2711 if (val->contents->type == INCREMENTAL_TYPE) | |
| 2712 { | |
| 2713 /* okay, we're now doing a lisp callback to incrementally generate | |
| 2714 more of the menu. */ | |
| 2715 XtCallCallbackList ((Widget)mw, | |
| 2716 mw->menu.open, | |
| 2717 (XtPointer)val->contents); | |
| 2718 } | |
| 2719 } | |
| 2720 | |
| 2721 size_menu (mw, i); | |
| 2722 | |
| 2723 fit_to_screen (mw, ws, previous_ws, mw->menu.horizontal && i == 1); | |
| 2724 | |
| 2725 XClearWindow (XtDisplay (mw), ws->window); | |
| 2726 XMoveResizeWindow (XtDisplay (mw), ws->window, ws->x, ws->y, | |
| 2727 ws->width, ws->height); | |
| 2728 XMapRaised (XtDisplay (mw), ws->window); | |
| 2729 display_menu (mw, i, False, &selection_position, NULL, NULL, NULL, NULL); | |
| 2730 } | |
| 2731 | |
| 2732 /* unmap the menus that popped down */ | |
| 2733 | |
| 2734 last_same = new_depth; | |
| 2735 if (lw_menu_accelerate | |
| 2736 && last_same > 1 | |
| 2737 && new_stack [last_same - 1]->contents) | |
| 2738 last_same--; | |
| 2739 | |
| 2740 for (i = last_same - 1; i < old_depth; i++) | |
| 2741 if (i >= last_same || !new_stack [i]->contents) | |
| 2742 XUnmapWindow (XtDisplay (mw), windows [i].window); | |
| 2743 } | |
| 2744 | |
| 2745 static Boolean | |
| 2746 motion_event_is_in_menu (XlwMenuWidget mw, XMotionEvent *ev, int level, | |
| 2747 XPoint *relative_pos) | |
| 2748 { | |
| 2749 window_state *ws = &mw->menu.windows [level]; | |
| 2750 int x = level == 0 ? ws->x : ws->x + mw->menu.shadow_thickness; | |
| 2751 int y = level == 0 ? ws->y : ws->y + mw->menu.shadow_thickness; | |
| 2752 relative_pos->x = ev->x_root - x; | |
| 2753 relative_pos->y = ev->y_root - y; | |
| 2754 return (x < ev->x_root && ev->x_root < (int) (x + ws->width) && | |
| 2755 y < ev->y_root && ev->y_root < (int) (y + ws->height)); | |
| 2756 } | |
| 2757 | |
| 2758 static Boolean | |
| 2759 map_event_to_widget_value (XlwMenuWidget mw, XMotionEvent *ev, | |
| 2760 widget_value **val_ptr, int *level, | |
| 2761 Boolean *inside_menu) | |
| 2762 { | |
| 2763 int i; | |
| 2764 XPoint relative_pos; | |
| 2765 window_state* ws; | |
| 2766 | |
| 2767 *val_ptr = NULL; | |
| 2768 *inside_menu = False; | |
| 2769 | |
| 2770 /* Find the window */ | |
| 2771 #if 1 | |
| 2772 for (i = mw->menu.old_depth - 1; i >= 0; i--) | |
| 2773 #else | |
| 2774 for (i = 0; i <= mw->menu.old_depth - 1; i++) | |
| 2775 #endif | |
| 2776 { | |
| 2777 ws = &mw->menu.windows [i]; | |
| 2778 if (ws && motion_event_is_in_menu (mw, ev, i, &relative_pos)) | |
| 2779 { | |
| 2780 *inside_menu = True; /* special logic for menubar below... */ | |
| 2781 if ((ev->type == ButtonPress) || | |
| 2782 (ev->state != 0)) | |
| 2783 { | |
| 2784 display_menu (mw, i, True, NULL, &relative_pos, | |
| 2785 val_ptr, NULL, NULL); | |
| 2786 if (*val_ptr) | |
| 2787 { | |
| 2788 *level = i + 1; | |
| 2789 *inside_menu = True; | |
| 2790 return True; | |
| 2791 } | |
| 2792 else if (mw->menu.horizontal || i == 0) | |
| 2793 { | |
| 2794 /* if we're clicking on empty part of the menubar, then | |
| 2795 unpost the stay-up menu */ | |
| 2796 *inside_menu = False; | |
| 2797 } | |
| 2798 } | |
| 2799 } | |
| 2800 } | |
| 2801 return False; | |
| 2802 } | |
| 2803 | |
| 2804 /* Procedures */ | |
| 2805 static void | |
| 2806 make_drawing_gcs (XlwMenuWidget mw) | |
| 2807 { | |
| 2808 XGCValues xgcv; | |
| 3094 | 2809 #ifdef USE_XFT_MENUBARS |
| 2810 unsigned long flags = (GCForeground | GCBackground); | |
| 2811 #else | |
| 428 | 2812 unsigned long flags = (GCFont | GCForeground | GCBackground); |
| 3094 | 2813 #endif |
| 2814 | |
| 2815 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) | |
| 428 | 2816 xgcv.font = default_font_of_font_list (mw->menu.font_list)->fid; |
| 2817 #else | |
| 3094 | 2818 #ifndef USE_XFT_MENUBARS |
| 428 | 2819 xgcv.font = mw->menu.font->fid; |
| 2820 #endif | |
| 3094 | 2821 #endif |
| 428 | 2822 |
| 2823 xgcv.foreground = mw->core.background_pixel; | |
| 2824 xgcv.background = mw->menu.foreground; | |
| 2825 mw->menu.background_gc = XtGetGC ((Widget) mw, flags, &xgcv); | |
| 2826 | |
| 2827 xgcv.foreground = mw->menu.foreground; | |
| 2828 xgcv.background = mw->core.background_pixel; | |
| 2829 mw->menu.foreground_gc = XtGetGC ((Widget) mw, flags, &xgcv); | |
| 2830 | |
| 2831 if (mw->menu.select_color != (Pixel)-1) | |
| 2832 { | |
| 2833 xgcv.foreground = mw->menu.select_color; | |
| 2834 } | |
| 2835 else | |
| 2836 { | |
| 2837 Display *dpy = XtDisplay(mw); | |
| 2838 if (CellsOfScreen(DefaultScreenOfDisplay(dpy)) <= 2) | |
| 2839 { /* mono */ | |
| 2840 xgcv.foreground = mw->menu.foreground; | |
| 2841 } | |
| 2842 else | |
| 2843 { /* color */ | |
| 2844 XColor xcolor; | |
| 3094 | 2845 Visual *visual; |
| 2846 int ignore; | |
| 3157 | 2847 Colormap cmap; |
| 3094 | 2848 visual_info_from_widget ((Widget) mw, &visual, &ignore); |
| 3157 | 2849 cmap = mw->core.colormap; |
| 428 | 2850 xcolor.pixel = mw->core.background_pixel; |
| 2851 XQueryColor (dpy, cmap, &xcolor); | |
| 2852 xcolor.red = (xcolor.red * 17) / 20; | |
| 2853 xcolor.green = (xcolor.green * 17) / 20; | |
| 2854 xcolor.blue = (xcolor.blue * 17) / 20; | |
| 3094 | 2855 if (x_allocate_nearest_color (dpy, cmap, visual, &xcolor)) |
| 428 | 2856 xgcv.foreground = xcolor.pixel; |
| 2857 } | |
| 2858 } | |
| 2859 xgcv.background = mw->core.background_pixel; | |
| 3094 | 2860 mw->menu.select_gc = XtGetGC ((Widget) mw, flags, &xgcv); |
| 428 | 2861 |
| 2862 xgcv.foreground = mw->menu.foreground; | |
| 2863 xgcv.background = mw->core.background_pixel; | |
| 2864 xgcv.fill_style = FillStippled; | |
| 2865 xgcv.stipple = mw->menu.gray_pixmap; | |
| 2866 mw->menu.inactive_gc = XtGetGC ((Widget)mw, | |
| 2867 (flags | GCFillStyle | GCStipple), | |
| 2868 &xgcv); | |
| 2869 | |
| 2870 xgcv.foreground = mw->menu.highlight_foreground; | |
| 2871 xgcv.background = mw->core.background_pixel; | |
| 2872 mw->menu.highlight_gc = XtGetGC ((Widget)mw, flags, &xgcv); | |
| 2873 | |
| 2874 xgcv.foreground = mw->menu.title_foreground; | |
| 2875 xgcv.background = mw->core.background_pixel; | |
| 2876 mw->menu.title_gc = XtGetGC ((Widget)mw, flags, &xgcv); | |
| 2877 | |
| 2878 xgcv.foreground = mw->menu.button_foreground; | |
| 2879 xgcv.background = mw->core.background_pixel; | |
| 2880 mw->menu.button_gc = XtGetGC ((Widget)mw, flags, &xgcv); | |
| 2881 | |
| 2882 xgcv.fill_style = FillStippled; | |
| 2883 xgcv.stipple = mw->menu.gray_pixmap; | |
| 2884 mw->menu.inactive_button_gc = XtGetGC ((Widget)mw, | |
| 2885 (flags | GCFillStyle | GCStipple), | |
| 2886 &xgcv); | |
| 2887 } | |
| 2888 | |
| 2889 static void | |
| 2890 release_drawing_gcs (XlwMenuWidget mw) | |
| 2891 { | |
| 3094 | 2892 |
| 428 | 2893 XtReleaseGC ((Widget) mw, mw->menu.foreground_gc); |
| 2894 XtReleaseGC ((Widget) mw, mw->menu.button_gc); | |
| 2895 XtReleaseGC ((Widget) mw, mw->menu.highlight_gc); | |
| 2896 XtReleaseGC ((Widget) mw, mw->menu.title_gc); | |
| 2897 XtReleaseGC ((Widget) mw, mw->menu.inactive_gc); | |
| 2898 XtReleaseGC ((Widget) mw, mw->menu.inactive_button_gc); | |
| 2899 XtReleaseGC ((Widget) mw, mw->menu.background_gc); | |
| 2900 XtReleaseGC ((Widget) mw, mw->menu.select_gc); | |
| 2901 /* let's get some segvs if we try to use these... */ | |
| 2902 mw->menu.foreground_gc = (GC) -1; | |
| 2903 mw->menu.button_gc = (GC) -1; | |
| 2904 mw->menu.highlight_gc = (GC) -1; | |
| 2905 mw->menu.title_gc = (GC) -1; | |
| 2906 mw->menu.inactive_gc = (GC) -1; | |
| 2907 mw->menu.inactive_button_gc = (GC) -1; | |
| 2908 mw->menu.background_gc = (GC) -1; | |
| 2909 mw->menu.select_gc = (GC) -1; | |
| 2910 } | |
| 2911 | |
| 2912 static void | |
| 2913 make_shadow_gcs (XlwMenuWidget mw) | |
| 2914 { | |
| 2915 XGCValues xgcv; | |
| 2916 unsigned long pm = 0; | |
| 2917 Display *dpy = XtDisplay ((Widget) mw); | |
| 2918 Colormap cmap = mw->core.colormap; | |
| 3094 | 2919 Visual *visual; |
| 2920 int ignored; | |
| 428 | 2921 XColor topc, botc; |
| 2922 int top_frobbed = 0, bottom_frobbed = 0; | |
| 2923 | |
| 3094 | 2924 visual_info_from_widget ((Widget) mw, &visual, &ignored); |
| 2925 /* #### Apparently this is called before any shell has a visual? | |
| 2926 or maybe the widget doesn't have a parent yet? */ | |
| 2927 if (visual == CopyFromParent) | |
| 2928 { | |
| 2929 Screen *screen = DefaultScreenOfDisplay (dpy); | |
| 2930 visual = DefaultVisualOfScreen (screen); | |
| 2931 } | |
| 2932 | |
| 428 | 2933 if (mw->menu.top_shadow_color == (Pixel) (-1)) |
| 2934 mw->menu.top_shadow_color = mw->core.background_pixel; | |
| 2935 if (mw->menu.bottom_shadow_color == (Pixel) (-1)) | |
| 2936 mw->menu.bottom_shadow_color = mw->menu.foreground; | |
| 2937 | |
| 2938 if (mw->menu.top_shadow_color == mw->core.background_pixel || | |
| 2939 mw->menu.top_shadow_color == mw->menu.foreground) | |
| 2940 { | |
| 2941 topc.pixel = mw->core.background_pixel; | |
| 2942 XQueryColor (dpy, cmap, &topc); | |
| 2943 /* don't overflow/wrap! */ | |
| 2944 topc.red = MINL (65535, topc.red * 1.2); | |
| 2945 topc.green = MINL (65535, topc.green * 1.2); | |
| 2946 topc.blue = MINL (65535, topc.blue * 1.2); | |
| 3094 | 2947 if (x_allocate_nearest_color (dpy, cmap, visual, &topc)) |
| 428 | 2948 { |
| 2949 if (topc.pixel == mw->core.background_pixel) | |
| 2950 { | |
| 2951 XFreeColors( dpy, cmap, &topc.pixel, 1, 0); | |
| 2952 topc.red = MINL (65535, topc.red + 0x8000); | |
| 2953 topc.green = MINL (65535, topc.green + 0x8000); | |
| 2954 topc.blue = MINL (65535, topc.blue + 0x8000); | |
| 3094 | 2955 if (x_allocate_nearest_color (dpy, cmap, visual, &topc)) |
| 428 | 2956 { |
| 2957 mw->menu.top_shadow_color = topc.pixel; | |
| 2958 } | |
| 2959 } | |
| 2960 else | |
| 2961 { | |
| 2962 mw->menu.top_shadow_color = topc.pixel; | |
| 2963 } | |
| 2964 | |
| 2965 top_frobbed = 1; | |
| 2966 } | |
| 2967 } | |
| 2968 if (mw->menu.bottom_shadow_color == mw->menu.foreground || | |
| 2969 mw->menu.bottom_shadow_color == mw->core.background_pixel) | |
| 2970 { | |
| 2971 botc.pixel = mw->core.background_pixel; | |
| 2972 XQueryColor (dpy, cmap, &botc); | |
| 2973 botc.red = (botc.red * 3) / 5; | |
| 2974 botc.green = (botc.green * 3) / 5; | |
| 2975 botc.blue = (botc.blue * 3) / 5; | |
| 3094 | 2976 if (x_allocate_nearest_color (dpy, cmap, visual, &botc)) |
| 428 | 2977 { |
| 2978 if (botc.pixel == mw->core.background_pixel) | |
| 2979 { | |
| 2980 XFreeColors (dpy, cmap, &botc.pixel, 1, 0); | |
| 2981 botc.red = MINL (65535, botc.red + 0x4000); | |
| 2982 botc.green = MINL (65535, botc.green + 0x4000); | |
| 2983 botc.blue = MINL (65535, botc.blue + 0x4000); | |
| 3094 | 2984 if (x_allocate_nearest_color (dpy, cmap, visual, &botc)) |
| 428 | 2985 { |
| 2986 mw->menu.bottom_shadow_color = botc.pixel; | |
| 2987 } | |
| 2988 } | |
| 2989 else | |
| 2990 { | |
| 2991 mw->menu.bottom_shadow_color = botc.pixel; | |
| 2992 } | |
| 2993 | |
| 2994 bottom_frobbed = 1; | |
| 2995 } | |
| 2996 } | |
| 2997 | |
| 2998 if (top_frobbed && bottom_frobbed) | |
| 2999 { | |
| 3000 int top_avg = ((topc.red / 3) + (topc.green / 3) + (topc.blue / 3)); | |
| 3001 int bot_avg = ((botc.red / 3) + (botc.green / 3) + (botc.blue / 3)); | |
| 3002 if (bot_avg > top_avg) | |
| 3003 { | |
| 3004 Pixel tmp = mw->menu.top_shadow_color; | |
| 3005 mw->menu.top_shadow_color = mw->menu.bottom_shadow_color; | |
| 3006 mw->menu.bottom_shadow_color = tmp; | |
| 3007 } | |
| 3008 else if (topc.pixel == botc.pixel) | |
| 3009 { | |
| 3010 if (botc.pixel == mw->menu.foreground) | |
| 3011 mw->menu.top_shadow_color = mw->core.background_pixel; | |
| 3012 else | |
| 3013 mw->menu.bottom_shadow_color = mw->menu.foreground; | |
| 3014 } | |
| 3015 } | |
| 3016 | |
| 3017 if (!mw->menu.top_shadow_pixmap && | |
| 3018 mw->menu.top_shadow_color == mw->core.background_pixel) | |
| 3019 { | |
| 3020 mw->menu.top_shadow_pixmap = mw->menu.gray_pixmap; | |
| 3021 mw->menu.top_shadow_color = mw->menu.foreground; | |
| 3022 } | |
| 3023 if (!mw->menu.bottom_shadow_pixmap && | |
| 3024 mw->menu.bottom_shadow_color == mw->core.background_pixel) | |
| 3025 { | |
| 3026 mw->menu.bottom_shadow_pixmap = mw->menu.gray_pixmap; | |
| 3027 mw->menu.bottom_shadow_color = mw->menu.foreground; | |
| 3028 } | |
| 3029 | |
| 3030 xgcv.fill_style = FillOpaqueStippled; | |
| 3031 xgcv.foreground = mw->menu.top_shadow_color; | |
| 3032 xgcv.background = mw->core.background_pixel; | |
| 3033 /* xgcv.stipple = mw->menu.top_shadow_pixmap; gtb */ | |
| 3034 if (mw->menu.top_shadow_pixmap && | |
| 3035 mw->menu.top_shadow_pixmap != XmUNSPECIFIED_PIXMAP) | |
| 3036 xgcv.stipple = mw->menu.top_shadow_pixmap; | |
| 3037 else | |
| 3038 xgcv.stipple = 0; | |
| 3039 pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0); | |
| 3040 mw->menu.shadow_top_gc = | |
| 3041 XtGetGC((Widget)mw, GCForeground|GCBackground|pm, &xgcv); | |
| 3042 | |
| 3043 xgcv.foreground = mw->menu.bottom_shadow_color; | |
| 3044 /* xgcv.stipple = mw->menu.bottom_shadow_pixmap; gtb */ | |
| 3045 if (mw->menu.bottom_shadow_pixmap && | |
| 3046 mw->menu.bottom_shadow_pixmap != XmUNSPECIFIED_PIXMAP) | |
| 3047 xgcv.stipple = mw->menu.bottom_shadow_pixmap; | |
| 3048 else | |
| 3049 xgcv.stipple = 0; | |
| 3050 pm = (xgcv.stipple ? GCStipple|GCFillStyle : 0); | |
| 3051 mw->menu.shadow_bottom_gc = | |
| 3052 XtGetGC ((Widget)mw, GCForeground|GCBackground|pm, &xgcv); | |
| 3053 } | |
| 3054 | |
| 3055 | |
| 3056 static void | |
| 3057 release_shadow_gcs (XlwMenuWidget mw) | |
| 3058 { | |
| 3059 XtReleaseGC ((Widget) mw, mw->menu.shadow_top_gc); | |
| 3060 XtReleaseGC ((Widget) mw, mw->menu.shadow_bottom_gc); | |
| 3061 } | |
| 3062 | |
| 3063 | |
| 3064 static void | |
| 3065 extract_font_extents (XlwMenuWidget mw) | |
| 3066 { | |
| 3094 | 3067 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) |
| 428 | 3068 /* Find the maximal ascent/descent of the fonts in the font list |
| 3069 so that all menu items can be the same height... */ | |
| 3070 mw->menu.font_ascent = 0; | |
| 3071 mw->menu.font_descent = 0; | |
| 3072 | |
| 3073 { | |
| 3074 XmFontContext context; | |
| 3075 #if (XmVersion >= 1002) | |
| 3076 XmFontListEntry fontentry; | |
| 3077 #else | |
| 3078 XmStringCharSet charset; | |
| 3079 #endif | |
| 3080 XFontStruct *font; | |
| 3081 | |
| 3082 if (! XmFontListInitFontContext (&context, mw->menu.font_list)) | |
| 3083 abort (); | |
| 3084 #if (XmVersion >= 1002) | |
| 3085 /* There is a BUG in the 1.2 version of XmFontListGetNextFont() (or more | |
| 3086 specifically, in _XmGetFirstFont()) that can cause a null pointer to be | |
| 3087 passed to XFontsOfFontSet. Use XmFontListNextEntry(), which is the | |
| 3088 newer equivalent, instead. Also, it supports font sets, and the | |
| 3089 older function doesn't. */ | |
| 3090 while ((fontentry = XmFontListNextEntry (context))) | |
| 3091 { | |
| 3092 XmFontType rettype; | |
| 3093 | |
| 3094 XtPointer one_of_them = XmFontListEntryGetFont (fontentry, &rettype); | |
| 3095 if (rettype == XmFONT_IS_FONTSET) | |
| 3096 { | |
| 3097 XFontSet fontset = (XFontSet) one_of_them; | |
| 3098 XFontStruct **fontstruct_list; | |
| 3099 char **fontname_list; | |
| 3100 int fontcount = XFontsOfFontSet (fontset, &fontstruct_list, | |
| 3101 &fontname_list); | |
| 3102 while (--fontcount >= 0) | |
| 3103 { | |
| 3104 font = fontstruct_list[fontcount]; | |
| 3105 if (font->ascent > (int) mw->menu.font_ascent) | |
| 3106 mw->menu.font_ascent = font->ascent; | |
| 3107 if (font->descent > (int) mw->menu.font_descent) | |
| 3108 mw->menu.font_descent = font->descent; | |
| 3109 } | |
| 3110 } | |
| 3111 else /* XmFONT_IS_FONT */ | |
| 3112 { | |
| 3113 font = (XFontStruct *) one_of_them; | |
| 3114 if (font->ascent > (int) mw->menu.font_ascent) | |
| 3115 mw->menu.font_ascent = font->ascent; | |
| 3116 if (font->descent > (int) mw->menu.font_descent) | |
| 3117 mw->menu.font_descent = font->descent; | |
| 3118 } | |
| 3119 } | |
| 3120 #else /* motif 1.1 */ | |
| 3121 while (XmFontListGetNextFont (context, &charset, &font)) | |
| 3122 { | |
| 3123 if (font->ascent > (int) mw->menu.font_ascent) | |
| 3124 mw->menu.font_ascent = font->ascent; | |
| 3125 if (font->descent > (int) mw->menu.font_descent) | |
| 3126 mw->menu.font_descent = font->descent; | |
| 3127 XtFree (charset); | |
| 3128 } | |
| 3129 #endif /* Motif version */ | |
| 3130 XmFontListFreeFontContext (context); | |
| 3131 } | |
| 3132 #else /* Not Motif */ | |
| 3133 # ifdef USE_XFONTSET | |
| 3134 XFontStruct **fontstruct_list; | |
| 3135 char **fontname_list; | |
| 3136 XFontStruct *font; | |
| 3137 int fontcount = XFontsOfFontSet(mw->menu.font_set, &fontstruct_list, | |
| 3138 &fontname_list); | |
| 3139 mw->menu.font_ascent = 0; | |
| 3140 mw->menu.font_descent = 0; | |
| 3141 # if 0 /* nasty, personal debug, Kazz */ | |
| 3142 fprintf(stderr, "fontSet count is %d\n", fontcount); | |
| 3143 # endif | |
| 3144 while (--fontcount >= 0) { | |
| 3145 font = fontstruct_list[fontcount]; | |
| 3146 if (font->ascent > (int) mw->menu.font_ascent) | |
| 3147 mw->menu.font_ascent = font->ascent; | |
| 3148 if (font->descent > (int) mw->menu.font_descent) | |
| 3149 mw->menu.font_descent = font->descent; | |
| 3150 } | |
| 3151 # else /* ! USE_XFONTSET */ | |
| 3094 | 3152 #ifdef USE_XFT_MENUBARS |
| 3153 mw->menu.font_ascent = mw->menu.renderFont->ascent; | |
| 3154 mw->menu.font_descent = mw->menu.renderFont->descent; | |
| 3155 #else | |
| 428 | 3156 mw->menu.font_ascent = mw->menu.font->ascent; |
| 3157 mw->menu.font_descent = mw->menu.font->descent; | |
| 3094 | 3158 #endif |
| 428 | 3159 # endif |
| 3160 #endif /* NEED_MOTIF */ | |
| 3161 } | |
| 3162 | |
| 3094 | 3163 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) |
| 428 | 3164 static XFontStruct * |
| 3165 default_font_of_font_list (XmFontList font_list) | |
| 3166 { | |
| 3167 XFontStruct *font = 0; | |
| 3168 # if 0 | |
| 3169 /* Xm/Label.c does this: */ | |
| 3170 _XmFontListGetDefaultFont (font_list, &font); | |
| 3171 # else /* !0 */ | |
| 3172 { | |
| 3173 XmFontContext context; | |
| 3174 #if (XmVersion >= 1002) | |
| 3175 XmFontListEntry fontentry; | |
| 3176 XmFontType rettype; | |
| 3177 XtPointer one_of_them; | |
| 3178 #else | |
| 3179 XmStringCharSet charset; | |
| 3180 #endif | |
| 3181 | |
| 3182 if (! XmFontListInitFontContext (&context, font_list)) | |
| 3183 abort (); | |
| 3184 #if (XmVersion >= 1002) | |
| 3185 /* There is a BUG in the 1.2 version of XmFontListGetNextFont() (or more | |
| 3186 specifically, in _XmGetFirstFont()) that can cause a null pointer to be | |
| 3187 passed to XFontsOfFontSet. Use XmFontListNextEntry(), which is the | |
| 3188 newer equivalent, instead. */ | |
| 3189 fontentry = XmFontListNextEntry (context); | |
| 3190 one_of_them = XmFontListEntryGetFont (fontentry, &rettype); | |
| 3191 if (rettype == XmFONT_IS_FONTSET) | |
| 3192 { | |
| 3193 XFontSet fontset = (XFontSet) one_of_them; | |
| 3194 XFontStruct **fontstruct_list; | |
| 3195 char **fontname_list; | |
| 3196 (void) XFontsOfFontSet (fontset, &fontstruct_list, &fontname_list); | |
| 3197 font = fontstruct_list[0]; | |
| 3198 } | |
| 3199 else /* XmFONT_IS_FONT */ | |
| 3200 { | |
| 3201 font = (XFontStruct *) one_of_them; | |
| 3202 } | |
| 3203 #else | |
| 3204 if (! XmFontListGetNextFont (context, &charset, &font)) | |
| 3205 abort (); | |
| 3206 XtFree (charset); | |
| 3207 #endif | |
| 3208 XmFontListFreeFontContext (context); | |
| 3209 } | |
| 3210 # endif /* !0 */ | |
| 3211 | |
| 3212 if (! font) abort (); | |
| 3213 return font; | |
| 3214 } | |
| 3215 #endif /* NEED_MOTIF */ | |
| 3216 | |
| 3217 static void | |
| 2286 | 3218 XlwMenuInitialize (Widget UNUSED (request), Widget new_, ArgList UNUSED (args), |
| 3219 Cardinal *UNUSED (num_args)) | |
| 428 | 3220 { |
| 3221 /* Get the GCs and the widget size */ | |
| 1201 | 3222 XlwMenuWidget mw = (XlwMenuWidget)new_; |
| 428 | 3223 Window window = RootWindowOfScreen (DefaultScreenOfDisplay (XtDisplay (mw))); |
| 3224 Display *display = XtDisplay (mw); | |
| 3225 | |
| 3226 /* mw->menu.cursor = XCreateFontCursor (display, mw->menu.cursor_shape); */ | |
| 3227 mw->menu.cursor = mw->menu.cursor_shape; | |
| 3228 | |
| 3229 mw->menu.gray_pixmap = | |
| 3230 XCreatePixmapFromBitmapData (display, window, (char *) gray_bits, | |
| 3231 gray_width, gray_height, 1, 0, 1); | |
| 3232 | |
| 3094 | 3233 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) |
| 442 | 3234 /* #### Even if it's a kludge!!!, we should consider doing the same for |
| 3235 X Font Sets. */ | |
| 428 | 3236 /* The menu.font_list slot came from the *fontList resource (Motif standard.) |
| 3237 The menu.font_list_2 slot came from the *font resource, for backward | |
| 3238 compatibility with older versions of this code, and consistency with the | |
| 442 | 3239 rest of emacs. If both font and fontList are specified, we use fontList. |
| 428 | 3240 If only one is specified, we use that. If neither are specified, we |
| 3241 use the "fallback" value. What a kludge!!! | |
| 3242 | |
| 3243 Note that this has the bug that a more general wildcard like "*fontList:" | |
| 3244 will override a more specific resource like "Emacs*menubar.font:". But | |
| 3245 I can't think of a way around that. | |
| 3246 */ | |
| 3247 if (mw->menu.font_list) /* if *fontList is specified, use that */ | |
| 3248 ; | |
| 3249 else if (mw->menu.font_list_2) /* else if *font is specified, use that */ | |
| 3250 mw->menu.font_list = mw->menu.font_list_2; | |
| 3251 else /* otherwise use default */ | |
| 3252 mw->menu.font_list = mw->menu.fallback_font_list; | |
| 3253 #endif | |
| 3254 | |
| 3094 | 3255 #ifdef USE_XFT_MENUBARS |
| 3685 | 3256 /* #### kludge for name change */ |
| 3257 if (!mw->menu.fcFontName) | |
| 3258 mw->menu.fcFontName = mw->menu.xftFontName; | |
| 3094 | 3259 /* to do this right, we should add a new Xt Resource type + |
| 3260 conversion function | |
| 3261 */ | |
| 3262 mw->menu.renderFont = | |
| 3397 | 3263 xft_open_font_by_name (XtDisplay (mw), mw->menu.fcFontName); |
| 3094 | 3264 #endif |
| 3265 | |
| 428 | 3266 make_drawing_gcs (mw); |
| 3267 make_shadow_gcs (mw); | |
| 3268 extract_font_extents (mw); | |
| 3269 | |
| 3270 mw->menu.popped_up = False; | |
| 3271 mw->menu.pointer_grabbed = False; | |
| 3272 mw->menu.next_release_must_exit = False; | |
| 3273 | |
| 3274 mw->menu.old_depth = 1; | |
| 3275 mw->menu.old_stack = XtNew (widget_value*); | |
| 3276 mw->menu.old_stack_length = 1; | |
| 3277 mw->menu.old_stack [0] = mw->menu.contents; | |
| 3278 | |
| 3279 mw->menu.new_depth = 0; | |
| 3280 mw->menu.new_stack = 0; | |
| 3281 mw->menu.new_stack_length = 0; | |
| 3282 push_new_stack (mw, mw->menu.contents); | |
| 3283 | |
| 3284 mw->menu.windows = XtNew (window_state); | |
| 3285 mw->menu.windows_length = 1; | |
| 3286 mw->menu.windows [0].x = 0; | |
| 3287 mw->menu.windows [0].y = 0; | |
| 3288 mw->menu.windows [0].width = 0; | |
| 3289 mw->menu.windows [0].height = 0; | |
| 3290 size_menu (mw, 0); | |
| 3291 | |
| 3292 mw->core.width = mw->menu.windows [0].width; | |
| 3293 mw->core.height = mw->menu.windows [0].height; | |
| 3294 } | |
| 3295 | |
| 3296 static void | |
| 3297 XlwMenuClassInitialize (void) | |
| 3298 { | |
| 3299 initialize_massaged_resource_char(); | |
| 3300 } | |
| 3301 | |
| 3302 static void | |
| 3303 XlwMenuRealize (Widget w, Mask *valueMask, XSetWindowAttributes *attributes) | |
| 3304 { | |
| 3305 XlwMenuWidget mw = (XlwMenuWidget)w; | |
| 3306 XSetWindowAttributes xswa; | |
| 446 | 3307 unsigned long mask; |
| 428 | 3308 |
| 3309 (*xlwMenuWidgetClass->core_class.superclass->core_class.realize) | |
| 3310 (w, valueMask, attributes); | |
| 3311 | |
| 3312 xswa.save_under = True; | |
| 3313 xswa.cursor = mw->menu.cursor_shape; | |
| 3314 mask = CWSaveUnder | CWCursor; | |
| 3315 if (mw->menu.use_backing_store) | |
| 3316 { | |
| 3317 xswa.backing_store = Always; | |
| 3318 mask |= CWBackingStore; | |
| 3319 } | |
| 3320 XChangeWindowAttributes (XtDisplay (w), XtWindow (w), mask, &xswa); | |
| 3321 | |
| 3322 mw->menu.windows [0].window = XtWindow (w); | |
| 3323 mw->menu.windows [0].x = w->core.x; | |
| 3324 mw->menu.windows [0].y = w->core.y; | |
| 3325 mw->menu.windows [0].width = w->core.width; | |
| 3326 mw->menu.windows [0].height = w->core.height; | |
| 3327 } | |
| 3328 | |
| 3329 /* Only the toplevel menubar/popup is a widget so it's the only one that | |
| 3330 receives expose events through Xt. So we repaint all the other panes | |
| 3331 when receiving an Expose event. */ | |
| 3332 static void | |
| 2286 | 3333 XlwMenuRedisplay (Widget w, XEvent *UNUSED (ev), Region UNUSED (region)) |
| 428 | 3334 { |
| 3335 XlwMenuWidget mw = (XlwMenuWidget)w; | |
| 3336 int i; | |
| 3337 | |
| 3338 if (mw->core.being_destroyed) return; | |
| 3339 | |
| 3340 for (i = 0; i < mw->menu.old_depth; i++) | |
| 3341 display_menu (mw, i, False, NULL, NULL, NULL, NULL, NULL); | |
| 3342 set_new_state (mw, NULL, mw->menu.old_depth); /* #### - ??? */ | |
| 3343 remap_menubar (mw); /* #### - do these two lines do anything? */ | |
| 3344 } | |
| 3345 | |
| 3346 static void | |
| 3347 XlwMenuDestroy (Widget w) | |
| 3348 { | |
| 3349 int i; | |
| 3350 XlwMenuWidget mw = (XlwMenuWidget) w; | |
| 3351 | |
| 3352 if (mw->menu.pointer_grabbed) | |
| 3353 { | |
| 3354 XtUngrabPointer (w, CurrentTime); | |
| 3355 mw->menu.pointer_grabbed = False; | |
| 3356 } | |
| 3357 | |
| 3358 release_drawing_gcs (mw); | |
| 3359 release_shadow_gcs (mw); | |
| 3360 | |
| 3361 /* this doesn't come from the resource db but is created explicitly | |
| 3362 so we must free it ourselves. */ | |
| 3363 XFreePixmap (XtDisplay (mw), mw->menu.gray_pixmap); | |
| 3364 mw->menu.gray_pixmap = (Pixmap) -1; | |
| 3365 | |
| 4173 | 3366 #ifdef USE_XFT_MENUBARS |
| 3367 XftFontClose (XtDisplay (mw), mw->menu.renderFont); | |
| 3368 #endif | |
| 3369 | |
| 428 | 3370 /* Don't free mw->menu.contents because that comes from our creator. |
| 3371 The `*_stack' elements are just pointers into `contents' so leave | |
| 3372 that alone too. But free the stacks themselves. */ | |
| 3373 if (mw->menu.old_stack) XtFree ((char *) mw->menu.old_stack); | |
| 3374 if (mw->menu.new_stack) XtFree ((char *) mw->menu.new_stack); | |
| 3375 | |
| 3376 /* Remember, you can't free anything that came from the resource | |
| 3377 database. This includes: | |
| 3378 mw->menu.cursor | |
| 3379 mw->menu.top_shadow_pixmap | |
| 3380 mw->menu.bottom_shadow_pixmap | |
| 3381 mw->menu.font | |
| 3382 mw->menu.font_set | |
| 3383 Also the color cells of top_shadow_color, bottom_shadow_color, | |
| 3384 foreground, and button_foreground will never be freed until this | |
| 3385 client exits. Nice, eh? | |
| 3386 */ | |
| 3387 | |
| 3388 /* start from 1 because the one in slot 0 is w->core.window */ | |
| 3389 for (i = 1; i < mw->menu.windows_length; i++) | |
| 3390 XDestroyWindow (XtDisplay (mw), mw->menu.windows [i].window); | |
| 3391 if (mw->menu.windows) | |
| 3392 XtFree ((char *) mw->menu.windows); | |
| 3393 } | |
| 3394 | |
| 3395 static Boolean | |
| 2286 | 3396 XlwMenuSetValues (Widget current, Widget UNUSED (request), Widget new_, |
| 3397 ArgList UNUSED (args), Cardinal *UNUSED (num_args)) | |
| 428 | 3398 { |
| 3399 XlwMenuWidget oldmw = (XlwMenuWidget)current; | |
| 1201 | 3400 XlwMenuWidget newmw = (XlwMenuWidget)new_; |
| 428 | 3401 Boolean redisplay = False; |
| 3402 int i; | |
| 3403 | |
| 3404 if (newmw->menu.contents | |
| 3405 && newmw->menu.contents->contents | |
| 3406 && newmw->menu.contents->contents->change >= VISIBLE_CHANGE) | |
| 3407 redisplay = True; | |
| 3408 | |
| 3409 if (newmw->core.background_pixel != oldmw->core.background_pixel | |
| 3410 || newmw->menu.foreground != oldmw->menu.foreground | |
| 3411 /* For the XEditResource protocol, which may want to change the font. */ | |
| 3094 | 3412 #if defined(NEED_MOTIF) && !defined(USE_XFT_MENUBARS) |
| 428 | 3413 || newmw->menu.font_list != oldmw->menu.font_list |
| 3414 || newmw->menu.font_list_2 != oldmw->menu.font_list_2 | |
| 3415 || newmw->menu.fallback_font_list != oldmw->menu.fallback_font_list | |
| 3416 #else | |
| 3094 | 3417 #ifdef USE_XFT_MENUBARS |
| 3418 || newmw->menu.renderFont != oldmw->menu.renderFont | |
| 3419 #else | |
| 428 | 3420 || newmw->menu.font != oldmw->menu.font |
| 3421 #endif | |
| 3094 | 3422 #endif |
| 428 | 3423 ) |
| 3424 { | |
| 3425 release_drawing_gcs (newmw); | |
| 3426 make_drawing_gcs (newmw); | |
| 3427 redisplay = True; | |
| 3428 | |
| 3429 for (i = 0; i < oldmw->menu.windows_length; i++) | |
| 3430 { | |
| 3431 XSetWindowBackground (XtDisplay (oldmw), | |
| 3432 oldmw->menu.windows [i].window, | |
| 3433 newmw->core.background_pixel); | |
| 3434 /* clear windows and generate expose events */ | |
| 3435 XClearArea (XtDisplay (oldmw), oldmw->menu.windows[i].window, | |
| 3436 0, 0, 0, 0, True); | |
| 3437 } | |
| 3438 } | |
| 3439 | |
| 3440 return redisplay; | |
| 3441 } | |
| 3442 | |
| 3443 static void | |
| 3444 XlwMenuResize (Widget w) | |
| 3445 { | |
| 3446 XlwMenuWidget mw = (XlwMenuWidget)w; | |
| 3447 | |
| 3448 mw->menu.windows [0].width = mw->core.width; | |
| 3449 mw->menu.windows [0].height = mw->core.height; | |
| 3450 } | |
| 3451 | |
| 3452 /* Action procedures */ | |
| 3453 static void | |
| 3454 handle_single_motion_event (XlwMenuWidget mw, XMotionEvent *ev, | |
| 3455 Boolean select_p) | |
| 3456 { | |
| 3457 widget_value *val; | |
| 3458 Boolean stay_up; | |
| 3459 int level; | |
| 3460 | |
| 3461 if (!map_event_to_widget_value (mw, ev, &val, &level, &stay_up)) | |
| 3462 { | |
| 3463 /* we wind up here when: (a) the event is in the menubar, (b) the | |
| 3464 event isn't in the menubar or any of the panes, (c) the event is on | |
| 3465 a disabled menu item */ | |
| 3466 pop_new_stack_if_no_contents (mw); | |
| 3467 if (select_p && !stay_up) { | |
| 3468 /* pop down all menus and exit */ | |
| 3469 mw->menu.next_release_must_exit = True; | |
| 3470 set_new_state(mw, (val = NULL), 1); | |
| 3471 } | |
| 3472 } | |
| 3473 else | |
| 3474 { | |
| 3475 /* we wind up here when: (a) the event pops up a pull_right menu, | |
| 3476 (b) a menu item that is not disabled is highlighted */ | |
| 3477 if (select_p && mw->menu.bounce_down | |
| 3478 && close_to_reference_time((Widget)mw, | |
| 3479 mw->menu.menu_bounce_time, | |
| 3480 (XEvent *)ev)) | |
| 3481 { | |
| 3482 /* motion can cause more than one event. Don't bounce right back | |
| 3483 up if we've just bounced down. */ | |
| 3484 val = NULL; | |
| 3485 } | |
| 3486 else if (select_p && mw->menu.bounce_down && | |
| 3487 mw->menu.last_selected_val && | |
| 3488 (mw->menu.last_selected_val == val)) | |
| 3489 { | |
| 3490 val = NULL; /* assigned to mw->last_selected_val below */ | |
| 3491 mw->menu.menu_bounce_time = ev->time; | |
| 3492 /* popdown last menu if we're selecting the same menu item as we did | |
| 3493 last time and the XlwMenu.bounceDown resource is set, if the | |
| 3494 item is on the menubar itself, then exit. */ | |
| 3495 if (level == (mw->menu.popped_up ? 0 : 1)) | |
| 3496 mw->menu.next_release_must_exit = True; | |
| 3497 } | |
| 3498 else | |
| 3499 mw->menu.menu_bounce_time = 0; | |
| 3500 set_new_state (mw, val, level); | |
| 3501 } | |
| 3502 mw->menu.last_selected_val = val; | |
| 3503 remap_menubar (mw); | |
| 3504 | |
| 3505 /* Sync with the display. Makes it feel better on X terms. */ | |
| 3506 XFlush (XtDisplay (mw)); | |
| 3507 } | |
| 3508 | |
| 3509 static void | |
| 3510 handle_motion_event (XlwMenuWidget mw, XMotionEvent *ev, | |
| 3511 Boolean select_p) | |
| 3512 { | |
| 3513 int x = ev->x_root; | |
| 3514 int y = ev->y_root; | |
| 3515 unsigned int state = ev->state; | |
| 3516 XMotionEvent *event= ev, dummy; | |
| 3517 | |
| 3518 /* allow motion events to be generated again */ | |
| 3519 dummy.window = ev->window; | |
| 3520 if (ev->is_hint | |
| 3521 && XQueryPointer (XtDisplay (mw), dummy.window, | |
| 3522 &dummy.root, &dummy.subwindow, | |
| 3523 &dummy.x_root, &dummy.y_root, | |
| 3524 &dummy.x, &dummy.y, | |
| 3525 &dummy.state) | |
| 3526 && dummy.state == state | |
| 3527 && (dummy.x_root != x || dummy.y_root != y)) | |
| 3528 { | |
| 3529 /* don't handle the event twice or that breaks bounce_down. --Stig */ | |
| 3530 dummy.type = ev->type; | |
| 3531 event = &dummy; | |
| 3532 } | |
| 3533 | |
| 3534 lw_menu_accelerate = False; | |
| 3535 handle_single_motion_event (mw, event, select_p); | |
| 3536 } | |
| 3537 | |
| 3538 Time x_focus_timestamp_really_sucks_fix_me_better; | |
| 3539 | |
| 3540 static void | |
| 2286 | 3541 Start (Widget w, XEvent *ev, String *UNUSED (params), |
| 3542 Cardinal *UNUSED (num_params)) | |
| 428 | 3543 { |
| 3544 XlwMenuWidget mw = (XlwMenuWidget)w; | |
| 3545 | |
| 3546 lw_menubar_widget = w; | |
| 3547 | |
| 3548 lw_menu_active = True; | |
| 3549 | |
| 3550 if (!mw->menu.pointer_grabbed) | |
| 3551 { | |
| 3552 mw->menu.menu_post_time = ev->xbutton.time; | |
| 3553 mw->menu.menu_bounce_time = 0; | |
| 3554 mw->menu.next_release_must_exit = True; | |
| 3555 mw->menu.last_selected_val = NULL; | |
| 3556 x_focus_timestamp_really_sucks_fix_me_better = | |
| 3557 ((XButtonPressedEvent*)ev)->time; | |
| 3558 XtCallCallbackList ((Widget)mw, mw->menu.open, NULL); | |
| 3559 | |
| 3560 /* notes the absolute position of the menubar window */ | |
| 3561 mw->menu.windows [0].x = ev->xmotion.x_root - ev->xmotion.x; | |
| 3562 mw->menu.windows [0].y = ev->xmotion.y_root - ev->xmotion.y; | |
| 3563 | |
| 3564 XtGrabPointer ((Widget)mw, False, | |
| 3565 (ButtonMotionMask | ButtonReleaseMask | ButtonPressMask), | |
| 3566 GrabModeAsync, GrabModeAsync, | |
| 3567 None, mw->menu.cursor_shape, | |
| 3568 ((XButtonPressedEvent*)ev)->time); | |
| 3569 mw->menu.pointer_grabbed = True; | |
| 3570 } | |
| 3571 | |
| 3572 /* handles the down like a move, slots are mostly compatible */ | |
| 3573 handle_motion_event (mw, &ev->xmotion, True); | |
| 3574 } | |
| 3575 | |
| 3576 static void | |
| 2286 | 3577 Drag (Widget w, XEvent *ev, String *UNUSED (params), |
| 3578 Cardinal *UNUSED (num_params)) | |
| 428 | 3579 { |
| 3580 XlwMenuWidget mw = (XlwMenuWidget)w; | |
| 3581 handle_motion_event (mw, &ev->xmotion, False); | |
| 3582 } | |
| 3583 | |
| 3584 static void | |
| 2286 | 3585 Select (Widget w, XEvent *ev, String *UNUSED (params), |
| 3586 Cardinal *UNUSED (num_params)) | |
| 428 | 3587 { |
| 3588 XlwMenuWidget mw = (XlwMenuWidget)w; | |
| 3589 widget_value *selected_item = mw->menu.old_stack [mw->menu.old_depth - 1]; | |
| 3590 | |
| 3591 lw_menu_accelerate = False; | |
| 3592 | |
| 3593 /* If user releases the button quickly, without selecting anything, | |
| 3594 after the initial down-click that brought the menu up, | |
| 3595 do nothing. */ | |
| 3596 if ((selected_item == 0 || selected_item->call_data == 0) | |
| 3597 && (!mw->menu.next_release_must_exit | |
| 3598 || close_to_reference_time(w, mw->menu.menu_post_time, ev))) | |
| 3599 { | |
| 3600 mw->menu.next_release_must_exit = False; | |
| 3601 return; | |
| 3602 } | |
| 3603 | |
| 3604 /* pop down everything */ | |
| 3605 mw->menu.new_depth = 1; | |
| 3606 remap_menubar (mw); | |
| 3607 | |
| 3608 /* Destroy() only gets called for popup menus. Menubar widgets aren't | |
| 3609 destroyed when their menu panes get nuked. */ | |
| 3610 if (mw->menu.pointer_grabbed) | |
| 3611 { | |
| 3612 XtUngrabPointer ((Widget)w, ev->xmotion.time); | |
| 3613 mw->menu.pointer_grabbed = False; | |
| 3614 } | |
| 3615 | |
| 3616 if (mw->menu.popped_up) | |
| 3617 { | |
| 3618 mw->menu.popped_up = False; | |
| 3619 XtPopdown (XtParent (mw)); | |
| 3620 } | |
| 3621 | |
| 3622 lw_menu_active = False; | |
| 3623 | |
| 3624 x_focus_timestamp_really_sucks_fix_me_better = | |
| 3625 ((XButtonPressedEvent*)ev)->time; | |
| 3626 | |
| 3627 /* callback */ | |
| 3628 XtCallCallbackList ((Widget) mw, mw->menu.select, (XtPointer) selected_item); | |
| 3629 } | |
| 3630 | |
| 3631 /* Action procedures for keyboard accelerators */ | |
| 3632 | |
| 3633 /* set the menu */ | |
| 3634 void | |
| 3635 xlw_set_menu (Widget w, widget_value *val) | |
| 3636 { | |
| 3637 lw_menubar_widget = w; | |
| 3638 set_new_state ((XlwMenuWidget)w, val, 1); | |
| 3639 } | |
| 3640 | |
| 3641 /* prepare the menu structure via the call-backs */ | |
| 3642 void | |
| 3643 xlw_map_menu (Time t) | |
| 3644 { | |
| 3645 XlwMenuWidget mw = (XlwMenuWidget)lw_menubar_widget; | |
| 3646 | |
| 3647 lw_menu_accelerate = True; | |
| 3648 | |
| 3649 if (!mw->menu.pointer_grabbed) | |
| 3650 { | |
| 3651 XWindowAttributes ret; | |
| 3462 | 3652 Window parent,root = 0UL; |
| 3653 Window *waste = NULL; | |
| 428 | 3654 unsigned int num_waste; |
| 3655 | |
| 3656 lw_menu_active = True; | |
| 3657 | |
| 3658 mw->menu.menu_post_time = t; | |
| 3659 mw->menu.menu_bounce_time = 0; | |
| 3660 | |
| 3661 mw->menu.next_release_must_exit = True; | |
| 3662 mw->menu.last_selected_val = NULL; | |
| 3663 | |
| 3664 XtCallCallbackList ((Widget)mw, mw->menu.open, NULL); | |
| 3665 | |
| 3666 /* do this for keyboards too! */ | |
| 3667 /* notes the absolute position of the menubar window */ | |
| 3668 /* | |
| 3669 mw->menu.windows [0].x = ev->xmotion.x_root - ev->xmotion.x; | |
| 3670 mw->menu.windows [0].y = ev->xmotion.y_root - ev->xmotion.y; | |
| 3671 */ | |
| 3672 | |
| 3673 /* get the geometry of the menubar */ | |
| 3674 | |
| 3675 /* there has to be a better way than this. */ | |
| 3676 | |
| 3677 mw->menu.windows [0].x = 0; | |
| 3678 mw->menu.windows [0].y = 0; | |
| 3679 | |
| 3680 parent = XtWindow (lw_menubar_widget); | |
| 3681 do | |
| 3682 { | |
| 3683 XGetWindowAttributes (XtDisplay (lw_menubar_widget), parent, &ret); | |
| 3684 mw->menu.windows [0].x += ret.x; | |
| 3685 mw->menu.windows [0].y += ret.y; | |
| 3686 | |
| 3687 if (parent) | |
| 3688 XQueryTree (XtDisplay (lw_menubar_widget), parent, &root, &parent, &waste, | |
| 3689 &num_waste); | |
| 3690 if (waste) | |
| 3691 { | |
| 3692 XFree (waste); | |
| 3693 } | |
| 3694 } | |
| 3695 while (parent != root); | |
| 3696 | |
| 3697 XtGrabPointer ((Widget)mw, False, | |
| 3698 (ButtonMotionMask | ButtonReleaseMask | ButtonPressMask), | |
| 3699 GrabModeAsync, GrabModeAsync, | |
| 3700 None, mw->menu.cursor_shape, t); | |
| 3701 mw->menu.pointer_grabbed = True; | |
| 3702 } | |
| 3703 } | |
| 3704 | |
| 3705 /* display the stupid menu already */ | |
| 3706 void | |
| 2286 | 3707 xlw_display_menu (Time UNUSED (t)) |
| 428 | 3708 { |
| 3709 XlwMenuWidget mw = (XlwMenuWidget)lw_menubar_widget; | |
| 3710 | |
| 3711 lw_menu_accelerate = True; | |
| 3712 | |
| 3713 remap_menubar (mw); | |
| 3714 | |
| 3715 /* Sync with the display. Makes it feel better on X terms. */ | |
| 3716 XFlush (XtDisplay (mw)); | |
| 3717 } | |
| 3718 | |
| 3719 /* push a sub menu */ | |
| 3720 void | |
| 3721 xlw_push_menu (widget_value *val) | |
| 3722 { | |
| 3723 push_new_stack ((XlwMenuWidget)lw_menubar_widget, val); | |
| 3724 } | |
| 3725 | |
| 3726 /* pop a sub menu */ | |
| 3727 int | |
| 3728 xlw_pop_menu (void) | |
| 3729 { | |
| 3730 if (((XlwMenuWidget)lw_menubar_widget)->menu.new_depth > 0) | |
| 3731 ((XlwMenuWidget)lw_menubar_widget)->menu.new_depth --; | |
| 3732 else | |
| 3733 return 0; | |
| 3734 return 1; | |
| 3735 } | |
| 3736 | |
| 3737 void | |
| 3738 xlw_kill_menus (widget_value *val) | |
| 3739 { | |
| 3740 XlwMenuWidget mw = (XlwMenuWidget)lw_menubar_widget; | |
| 3741 | |
| 3742 lw_menu_accelerate = False; | |
| 3743 | |
| 3744 mw->menu.new_depth = 1; | |
| 3745 remap_menubar (mw); | |
| 3746 | |
| 3747 if (mw->menu.pointer_grabbed) | |
| 3748 { | |
| 3749 XtUngrabPointer (lw_menubar_widget, CurrentTime); | |
| 3750 mw->menu.pointer_grabbed = False; | |
| 3751 } | |
| 3752 | |
| 3753 lw_menu_active = False; | |
| 3754 XtCallCallbackList (lw_menubar_widget, mw->menu.select, (XtPointer)val); | |
| 3755 } | |
| 3756 | |
| 3757 /* set the menu item */ | |
| 3758 void | |
| 3759 xlw_set_item (widget_value *val) | |
| 3760 { | |
| 3761 if (((XlwMenuWidget)lw_menubar_widget)->menu.new_depth > 0) | |
| 3762 ((XlwMenuWidget) lw_menubar_widget)->menu.new_depth --; | |
| 3763 push_new_stack ((XlwMenuWidget) lw_menubar_widget, val); | |
| 3764 } | |
| 3765 | |
| 3766 /* get either the current entry or a list of all entries in the current submenu */ | |
| 3767 widget_value * | |
| 3768 xlw_get_entries (int allp) | |
| 3769 { | |
| 3770 XlwMenuWidget mw = (XlwMenuWidget)lw_menubar_widget; | |
| 3771 if (allp) | |
| 3772 { | |
| 3773 if (mw->menu.new_depth >= 2) | |
| 3774 return mw->menu.new_stack [mw->menu.new_depth - 2]->contents; | |
| 3775 else | |
| 3776 return mw->menu.new_stack[0]; | |
| 3777 } | |
| 3778 else | |
| 3779 if (mw->menu.new_depth >= 1) | |
| 3780 return mw->menu.new_stack [mw->menu.new_depth - 1]; | |
| 3781 | |
| 3782 return NULL; | |
| 3783 } | |
| 3784 | |
| 3785 int | |
| 3786 xlw_menu_level (void) | |
| 3787 { | |
| 3788 return ((XlwMenuWidget)lw_menubar_widget)->menu.new_depth; | |
| 3789 } | |
| 3790 | |
| 3791 | |
| 3792 /* Special code to pop-up a menu */ | |
| 3793 void | |
| 3794 xlw_pop_up_menu (XlwMenuWidget mw, XButtonPressedEvent *event) | |
| 3795 { | |
| 3796 int x = event->x_root; | |
| 3797 int y = event->y_root; | |
| 3798 int w; | |
| 3799 int h; | |
| 3800 int borderwidth = mw->menu.shadow_thickness; | |
| 3801 Screen* screen = XtScreen (mw); | |
| 3802 | |
| 3803 mw->menu.menu_post_time = event->time; | |
| 3804 mw->menu.menu_bounce_time = 0; | |
| 3805 mw->menu.next_release_must_exit = True; | |
| 3806 mw->menu.last_selected_val = NULL; | |
| 3807 | |
| 3808 XtCallCallbackList ((Widget) mw, mw->menu.open, NULL); | |
| 3809 | |
| 3810 size_menu (mw, 0); | |
| 3811 | |
| 3812 w = mw->menu.windows [0].width; | |
| 3813 h = mw->menu.windows [0].height; | |
| 3814 | |
| 3815 x -= borderwidth; | |
| 3816 y -= borderwidth; | |
| 3817 | |
| 3818 if (x < borderwidth) | |
| 3819 x = borderwidth; | |
| 3820 | |
| 3821 if (x > WidthOfScreen (screen) - w - 2 * borderwidth) | |
| 3822 x = WidthOfScreen (screen) - w - 2 * borderwidth; | |
| 3823 | |
| 3824 if (y < borderwidth) | |
| 3825 y = borderwidth; | |
| 3826 | |
| 3827 if (y > HeightOfScreen (screen) - h - 2 * borderwidth) | |
| 3828 y = HeightOfScreen (screen) - h - 2 * borderwidth; | |
| 3829 | |
| 3830 mw->menu.popped_up = True; | |
| 3831 XtConfigureWidget (XtParent (mw), x, y, w, h, | |
| 3832 XtParent (mw)->core.border_width); | |
| 3833 XtPopup (XtParent (mw), XtGrabExclusive); | |
| 3834 display_menu (mw, 0, False, NULL, NULL, NULL, NULL, NULL); | |
| 3835 if (!mw->menu.pointer_grabbed) | |
| 3836 { | |
| 3837 XtGrabPointer ((Widget)mw, False, | |
| 3838 (ButtonMotionMask | ButtonReleaseMask | ButtonPressMask), | |
| 3839 GrabModeAsync, GrabModeAsync, | |
| 3840 None, mw->menu.cursor_shape, event->time); | |
| 3841 mw->menu.pointer_grabbed = True; | |
| 3842 } | |
| 3843 | |
| 3844 mw->menu.windows [0].x = x + borderwidth; | |
| 3845 mw->menu.windows [0].y = y + borderwidth; | |
| 3846 | |
| 3847 handle_motion_event (mw, (XMotionEvent *) event, True); | |
| 3848 } | |
| 3849 | |
| 3850 /* #### unused */ | |
| 3851 #if 0 | |
| 3852 /* | |
| 3853 * This is a horrible function which should not be needed. | |
| 3854 * use it to put the resize method back the way the XlwMenu | |
| 3855 * class initializer put it. Motif screws with this when | |
| 3856 * the XlwMenu class gets instantiated. | |
| 3857 */ | |
| 3858 void | |
| 3859 xlw_unmunge_class_resize (Widget w) | |
| 3860 { | |
| 3861 if (w->core.widget_class->core_class.resize != XlwMenuResize) | |
| 3862 w->core.widget_class->core_class.resize = XlwMenuResize; | |
| 3863 } | |
| 3864 #endif /* 0 */ | |
| 3865 |
