Mercurial > hg > xemacs-beta
annotate lwlib/xlwtabs.c @ 4758:75975fd0b7fc
Implement more of the fontconfig API.
Improve implementation, avoiding nonsyntactic macros and compiler warnings.
Clean up some documentation.
Guard against freeing NULL pointers returned from fonconfig.
author | Stephen J. Turnbull <stephen@xemacs.org> |
---|---|
date | Wed, 18 Nov 2009 22:44:28 +0900 |
parents | 726060ee587c |
children | 5460287a3327 |
rev | line source |
---|---|
428 | 1 /* Tabs Widget for XEmacs. |
2 Copyright (C) 1999 Edward A. Falk | |
442 | 3 |
428 | 4 This file is part of XEmacs. |
442 | 5 |
428 | 6 XEmacs is free software; you can redistribute it and/or modify it |
7 under the terms of the GNU General Public License as published by the | |
8 Free Software Foundation; either version 2, or (at your option) any | |
9 later version. | |
442 | 10 |
428 | 11 XEmacs is distributed in the hope that it will be useful, but WITHOUT |
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 for more details. | |
442 | 15 |
428 | 16 You should have received a copy of the GNU General Public License |
17 along with XEmacs; see the file COPYING. If not, write to | |
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
19 Boston, MA 02111-1307, USA. */ | |
442 | 20 |
428 | 21 /* |
22 * Tabs.c - Index Tabs composite widget | |
23 * | |
24 * Author: Edward A. Falk | |
25 * falk@falconer.vip.best.com | |
26 * | |
27 * Date: July 29, 1997 | |
28 * | |
29 * | |
30 * Overall layout of this widget is as follows: | |
31 * | |
32 * ________ ,---------. _________ | |
33 * | label || Label || Label | \ tabs | |
34 * |________|| ||_________| / | |
35 * |+----------------------------+| \ | |
36 * || || | | |
37 * || child widget window || > frame | |
38 * |+----------------------------+| | | |
39 * +------------------------------+ / | |
40 * | |
41 * The height of the tabs includes the shadow width, top and bottom | |
42 * margins, and the height of the text. | |
43 * | |
44 * The height of the frame includes the top and bottom shadow width and the | |
45 * size of the child widget window. | |
46 * | |
47 * The tabs overlap the frame and each other vertically by the shadow | |
48 * width, so that when the topmost tab is drawn, it obliterates part of | |
49 * the frame. | |
50 */ | |
51 | |
3094 | 52 /* Synched up with: Tabs.c 1.27. |
53 | |
54 This file contains essential XEmacs-related fixes to the original | |
55 version of the Tabs widget. Be VERY careful about syncing if you ever | |
56 update to a more recent version. In general this is probably now a | |
57 bad idea. | |
58 | |
59 #### We need to check that various windows (the whole widget, or a single | |
60 tab) are of "reasonable" size, ie, we need to try for more sanity in the | |
61 geometry management routines. | |
62 */ | |
63 | |
434 | 64 /* |
65 * TODO: min child height = tab height | |
428 | 66 */ |
67 | |
68 #include <config.h> | |
69 #include <stdio.h> | |
70 | |
71 #include <X11/Xlib.h> | |
72 #include <X11/IntrinsicP.h> | |
73 #include <X11/StringDefs.h> | |
448 | 74 |
3094 | 75 /* #### This may be risky, lwlib-internal.h redefines abort() */ |
76 #include "lwlib-fonts.h" | |
77 #include "lwlib-colors.h" | |
448 | 78 #include "lwlib-internal.h" |
428 | 79 #include "../src/xmu.h" |
80 #include "xlwtabsP.h" | |
81 #include "xlwgcs.h" | |
82 | |
3094 | 83 #define XFT_USE_HEIGHT_NOT_ASCENT_DESCENT 0 |
84 | |
85 /* #### These should probably be resources. */ | |
428 | 86 #define MIN_WID 10 |
87 #define MIN_HGT 10 | |
88 #define INDENT 3 /* tabs indented from edge by this much */ | |
89 #define SPACING 0 /* distance between tabs */ | |
90 #define SHADWID 1 /* default shadow width */ | |
91 #define TABDELTA 2 /* top tab grows this many pixels */ | |
92 #define TABLDELTA 2 /* top tab label offset this many pixels */ | |
93 | |
94 | |
95 /**************************************************************** | |
96 * | |
97 * IndexTabs Resources | |
98 * | |
99 ****************************************************************/ | |
100 | |
101 static char defaultTranslations[] = "\ | |
102 <BtnUp>: select() \n\ | |
103 <FocusIn>: highlight() \n\ | |
104 <FocusOut>: unhighlight() \n\ | |
105 <Key>Page_Up: page(up) \n\ | |
106 <Key>KP_Page_Up: page(up) \n\ | |
107 <Key>Prior: page(up) \n\ | |
108 <Key>KP_Prior: page(up) \n\ | |
109 <Key>Page_Down: page(down) \n\ | |
110 <Key>KP_Page_Down: page(down) \n\ | |
111 <Key>Next: page(down) \n\ | |
112 <Key>KP_Next: page(down) \n\ | |
113 <Key>Home: page(home) \n\ | |
114 <Key>KP_Home: page(home) \n\ | |
115 <Key>End: page(end) \n\ | |
116 <Key>KP_End: page(end) \n\ | |
117 <Key>Up: highlight(up) \n\ | |
118 <Key>KP_Up: highlight(up) \n\ | |
119 <Key>Down: highlight(down) \n\ | |
120 <Key>KP_Down: highlight(down) \n\ | |
121 <Key> : page(select) \n\ | |
122 " ; | |
123 | |
124 static char accelTable[] = " #augment\n\ | |
125 <Key>Page_Up: page(up) \n\ | |
126 <Key>KP_Page_Up: page(up) \n\ | |
127 <Key>Prior: page(up) \n\ | |
128 <Key>KP_Prior: page(up) \n\ | |
129 <Key>Page_Down: page(down) \n\ | |
130 <Key>KP_Page_Down: page(down) \n\ | |
131 <Key>Next: page(down) \n\ | |
132 <Key>KP_Next: page(down) \n\ | |
133 <Key>Home: page(home) \n\ | |
134 <Key>KP_Home: page(home) \n\ | |
135 <Key>End: page(end) \n\ | |
136 <Key>KP_End: page(end) \n\ | |
137 <Key>Up: highlight(up) \n\ | |
138 <Key>KP_Up: highlight(up) \n\ | |
139 <Key>Down: highlight(down) \n\ | |
140 <Key>KP_Down: highlight(down) \n\ | |
141 <Key> : page(select) \n\ | |
142 " ; | |
446 | 143 static XtAccelerators defaultAccelerators ; /* #### Never used */ |
428 | 144 |
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
145 static XtResource resources[] = { |
4522
fc7067b7f407
Backout last patch; forgot to specify file.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4521
diff
changeset
|
146 #define offset(field) XtOffsetOf(TabsRec, tabs.field) |
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 #define res(name,_class,intrepr,type,member,extrepr,value) \ |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
148 Xt_RESOURCE (name, _class, intrepr, type, offset(member), extrepr, value) |
428 | 149 |
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 res (XtNselectInsensitive, XtCSelectInsensitive, XtRBoolean, Boolean, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
151 selectInsensitive, 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
|
152 res (XtNfont, XtCFont, XtRFontStruct, XFontStruct *, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
153 font, XtRString, XtDefaultFont), |
3094 | 154 #ifdef USE_XFT_TABS |
3397 | 155 /* #### Maybe use "-*-helvetica-bold-r-*-*-*-120-*-*-*-*-iso8859-1" here? |
156 or XtDefaultFont? */ | |
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
157 res (XtNfcFontName, XtCFcFontName, XtRString, String, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
158 fcFontName, XtRString, NULL), |
3397 | 159 /* #### This needs to be fixed to give a proper type and converter for |
160 XftFonts. See also xlwmenu.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
|
161 res (XtNxftFont, XtCXftFont, XtRString, String, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
162 xftFontName, XtRString, "Helvetica-12"), |
3094 | 163 #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
|
164 res (XtNinternalWidth, XtCWidth, XtRDimension, Dimension, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
165 internalWidth, XtRImmediate, 4), |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
166 res (XtNinternalHeight, XtCHeight, XtRDimension, Dimension, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
167 internalHeight, XtRImmediate, 4), |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
168 Xt_RESOURCE (XtNborderWidth, XtCBorderWidth, XtRDimension, Dimension, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
169 XtOffsetOf(RectObjRec,rectangle.border_width), 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
|
170 res (XtNtopWidget, XtCTopWidget, XtRWidget, Widget, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
171 topWidget, 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
|
172 res (XtNcallback, XtCCallback, XtRCallback, XtPointer, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
173 callbacks, XtRCallback, NULL), |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
174 res (XtNpopdownCallback, XtCCallback, XtRCallback, XtPointer, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
175 popdownCallbacks, XtRCallback, NULL), |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
176 res (XtNbeNiceToColormap, XtCBeNiceToColormap, XtRBoolean, Boolean, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
177 be_nice_to_cmap, 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
|
178 res (XtNtopShadowContrast, XtCTopShadowContrast, XtRInt, int, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
179 top_shadow_contrast, XtRImmediate, 20), |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
180 res (XtNbottomShadowContrast, XtCBottomShadowContrast, XtRInt, int, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
181 bot_shadow_contrast, XtRImmediate, 40), |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
182 res (XtNinsensitiveContrast, XtCInsensitiveContrast, XtRInt, int, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
183 insensitive_contrast, XtRImmediate, 33), |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
184 Xt_RESOURCE (XtNaccelerators, XtCAccelerators, XtRAcceleratorTable, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
185 XtTranslations, XtOffsetOf(TabsRec,core.accelerators), |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
186 XtRString, accelTable), |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
187 #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
|
188 #undef res |
4522
fc7067b7f407
Backout last patch; forgot to specify file.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4521
diff
changeset
|
189 }; |
428 | 190 |
191 | |
192 /* constraint resources */ | |
193 | |
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
194 static XtResource tabsConstraintResources[] = { |
4522
fc7067b7f407
Backout last patch; forgot to specify file.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4521
diff
changeset
|
195 #define offset(field) XtOffsetOf(TabsConstraintsRec, tabs.field) |
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
196 #define res(name,_class,intrepr,type,member,extrepr,value) \ |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
197 Xt_RESOURCE (name, _class, intrepr, type, offset(member), extrepr, value) |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
198 res (XtNtabLabel, XtCLabel, XtRString, String, label, XtRString, NULL), |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
199 res (XtNtabLeftBitmap, XtCLeftBitmap, XtRBitmap, Pixmap, left_bitmap, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
200 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
|
201 res (XtNtabForeground, XtCForeground, XtRPixel, Pixel, foreground, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
202 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
|
203 res (XtNresizable, XtCResizable, XtRBoolean, Boolean, resizable, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
204 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
|
205 #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
|
206 #undef res |
4522
fc7067b7f407
Backout last patch; forgot to specify file.
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4521
diff
changeset
|
207 } ; |
428 | 208 |
209 | |
210 | |
211 | |
212 #if !NeedFunctionPrototypes | |
213 | |
214 /* FORWARD REFERENCES: */ | |
215 | |
216 /* member functions */ | |
217 | |
218 static void TabsClassInit(); | |
219 static void TabsInit(); | |
220 static void TabsResize(); | |
221 static void TabsExpose(); | |
222 static void TabsDestroy(); | |
223 static void TabsRealize(); | |
224 static Boolean TabsSetValues(); | |
434 | 225 static Boolean TabsAcceptFocus(); |
428 | 226 static XtGeometryResult TabsQueryGeometry(); |
227 static XtGeometryResult TabsGeometryManager(); | |
228 static void TabsChangeManaged(); | |
229 static void TabsConstraintInitialize() ; | |
230 static Boolean TabsConstraintSetValues() ; | |
231 | |
232 /* action procs */ | |
233 | |
234 static void TabsSelect() ; | |
235 static void TabsPage() ; | |
236 static void TabsHighlight() ; | |
237 static void TabsUnhighlight() ; | |
238 | |
239 /* internal privates */ | |
240 | |
241 static void TabsAllocGCs() ; /* get rendering GCs */ | |
242 static void TabsFreeGCs() ; /* return rendering GCs */ | |
243 static void DrawTabs() ; /* draw all tabs */ | |
244 static void DrawTab() ; /* draw one index tab */ | |
245 static void DrawFrame() ; /* draw frame around contents */ | |
246 static void DrawTrim() ; /* draw trim around a tab */ | |
247 static void DrawBorder() ; /* draw border */ | |
248 static void DrawHighlight() ; /* draw highlight */ | |
249 static void UndrawTab() ; /* undraw interior of a tab */ | |
250 static void TabWidth() ; /* recompute tab size */ | |
251 static void GetPreferredSizes() ; /* query all children for their sizes */ | |
252 static void MaxChild() ; /* find max preferred child size */ | |
253 static int PreferredSize() ; /* compute preferred size */ | |
254 static int PreferredSize2() ; /* compute preferred size */ | |
255 static int PreferredSize3() ; /* compute preferred size */ | |
256 static void MakeSizeRequest() ; /* try to change size */ | |
257 static void getBitmapInfo() ; | |
258 static int TabLayout() ; /* lay out tabs */ | |
259 static void TabsShuffleRows() ; /* bring current tab to bottom row */ | |
260 | |
261 static void TabsAllocFgGC() ; | |
262 static void TabsAllocGreyGC() ; | |
263 | |
264 #else | |
265 | |
266 static void TabsClassInit(void) ; | |
3025 | 267 static void TabsInit( Widget req, Widget new_, ArgList, Cardinal *nargs) ; |
428 | 268 static void TabsConstraintInitialize(Widget, Widget, ArgList, Cardinal *) ; |
269 static void TabsRealize(Widget, Mask *, XSetWindowAttributes *) ; | |
270 static void TabsDestroy( Widget w) ; | |
271 static void TabsResize( Widget w) ; | |
272 static void TabsExpose( Widget w, XEvent *event, Region region) ; | |
273 static Boolean TabsSetValues(Widget, Widget, Widget, ArgList, Cardinal *) ; | |
434 | 274 static Boolean TabsAcceptFocus(Widget, Time *); |
428 | 275 static Boolean TabsConstraintSetValues(Widget, Widget, Widget, |
276 ArgList, Cardinal *) ; | |
277 static XtGeometryResult TabsQueryGeometry(Widget, | |
278 XtWidgetGeometry *, XtWidgetGeometry *) ; | |
279 static XtGeometryResult TabsGeometryManager(Widget, | |
280 XtWidgetGeometry *, XtWidgetGeometry *) ; | |
281 static void TabsChangeManaged( Widget w) ; | |
282 | |
283 static void TabsSelect(Widget, XEvent *, String *, Cardinal *) ; | |
284 static void TabsPage(Widget, XEvent *, String *, Cardinal *) ; | |
285 static void TabsHighlight(Widget, XEvent *, String *, Cardinal *) ; | |
286 static void TabsUnhighlight(Widget, XEvent *, String *, Cardinal *) ; | |
287 | |
288 static void DrawTabs( TabsWidget tw, Bool labels) ; | |
289 static void DrawTab( TabsWidget tw, Widget child, Bool labels) ; | |
290 static void DrawFrame( TabsWidget tw) ; | |
291 static void DrawTrim( TabsWidget, int x, int y, | |
292 int wid, int hgt, Bool bottom, Bool undraw) ; | |
293 static void DrawBorder( TabsWidget tw, Widget child, Bool undraw) ; | |
294 static void DrawHighlight( TabsWidget tw, Widget child, Bool undraw) ; | |
295 static void UndrawTab( TabsWidget tw, Widget child) ; | |
296 | |
297 static void TabWidth( Widget w) ; | |
448 | 298 static int TabLayout( TabsWidget, Dimension wid, Dimension hgt, Dimension *r_hgt, |
428 | 299 Bool query_only) ; |
300 static void GetPreferredSizes(TabsWidget) ; | |
434 | 301 static void MaxChild(TabsWidget, Widget except, Dimension, Dimension) ; |
428 | 302 static void TabsShuffleRows( TabsWidget tw) ; |
303 static int PreferredSize( TabsWidget, | |
304 Dimension *reply_width, Dimension *reply_height, | |
305 Dimension *reply_cw, Dimension *reply_ch) ; | |
448 | 306 static int PreferredSize2( TabsWidget, Dimension cw, Dimension ch, |
428 | 307 Dimension *rw, Dimension *rh) ; |
448 | 308 static int PreferredSize3( TabsWidget, Dimension wid, Dimension hgt, |
428 | 309 Dimension *rw, Dimension *rh) ; |
310 static void MakeSizeRequest(TabsWidget) ; | |
311 | |
312 static void TabsAllocGCs(TabsWidget) ; | |
313 static void TabsFreeGCs(TabsWidget) ; | |
314 static void getBitmapInfo( TabsWidget tw, TabsConstraints tab) ; | |
315 static void TabsAllocFgGC( TabsWidget tw) ; | |
316 static void TabsAllocGreyGC( TabsWidget tw) ; | |
317 | |
318 #endif | |
319 | |
320 #define AddRect(i,xx,yy,w,h) \ | |
321 do{rects[(i)].x=(xx); rects[i].y=(yy); \ | |
322 rects[i].width=(w); rects[i].height=(h);}while(0) | |
323 | |
324 static XtActionsRec actionsList[] = | |
325 { | |
4528
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
326 { (String) "select", TabsSelect }, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
327 { (String) "page", TabsPage }, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
328 { (String) "highlight", TabsHighlight }, |
726060ee587c
First draft of g++ 4.3 warning removal patch. Builds. *Needs ChangeLogs.*
Stephen J. Turnbull <stephen@xemacs.org>
parents:
4522
diff
changeset
|
329 { (String) "unhighlight", TabsUnhighlight }, |
428 | 330 } ; |
331 | |
332 | |
333 /**************************************************************** | |
334 * | |
335 * Full class record constant | |
336 * | |
337 ****************************************************************/ | |
338 | |
339 #ifndef NEED_MOTIF | |
340 #define SuperClass (&constraintClassRec) | |
341 #else | |
342 #define SuperClass (&xmManagerClassRec) | |
343 #endif | |
344 | |
345 TabsClassRec tabsClassRec = { | |
346 { | |
347 /* core_class fields */ | |
348 /* superclass */ (WidgetClass) 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
|
349 /* class_name */ (String) "Tabs", |
428 | 350 /* widget_size */ sizeof(TabsRec), |
351 /* class_initialize */ TabsClassInit, | |
352 /* class_part_init */ NULL, /* TODO? */ | |
353 /* class_inited */ FALSE, | |
354 /* initialize */ TabsInit, | |
355 /* initialize_hook */ NULL, | |
356 /* realize */ TabsRealize, | |
357 /* actions */ actionsList, | |
358 /* num_actions */ XtNumber(actionsList), | |
359 /* resources */ resources, | |
360 /* num_resources */ XtNumber(resources), | |
361 /* xrm_class */ NULLQUARK, | |
362 /* compress_motion */ TRUE, | |
434 | 363 #if XtSpecificationRelease < 6 |
364 /* compress_exposure */ XtExposeCompressMaximal, | |
365 #else | |
366 /* compress_exposure */ XtExposeCompressMaximal|XtExposeNoRegion, | |
367 #endif | |
428 | 368 /* compress_enterleave*/ TRUE, |
434 | 369 /* visible_interest */ TRUE, |
428 | 370 /* destroy */ TabsDestroy, |
371 /* resize */ TabsResize, | |
372 /* expose */ TabsExpose, | |
373 /* set_values */ TabsSetValues, | |
374 /* set_values_hook */ NULL, | |
375 /* set_values_almost */ XtInheritSetValuesAlmost, | |
376 /* get_values_hook */ NULL, | |
434 | 377 /* accept_focus */ TabsAcceptFocus, |
428 | 378 /* version */ XtVersion, |
379 /* callback_private */ NULL, | |
380 /* tm_table */ defaultTranslations, | |
381 /* query_geometry */ TabsQueryGeometry, | |
382 /* display_accelerator*/ XtInheritDisplayAccelerator, | |
383 /* extension */ NULL | |
384 }, | |
385 { | |
386 /* composite_class fields */ | |
387 /* geometry_manager */ TabsGeometryManager, | |
388 /* change_managed */ TabsChangeManaged, | |
389 /* insert_child */ XtInheritInsertChild, /* TODO? */ | |
390 /* delete_child */ XtInheritDeleteChild, /* TODO? */ | |
391 /* extension */ NULL | |
392 }, | |
393 { | |
394 /* constraint_class fields */ | |
395 /* subresources */ tabsConstraintResources, | |
396 /* subresource_count */ XtNumber(tabsConstraintResources), | |
397 /* constraint_size */ sizeof(TabsConstraintsRec), | |
398 /* initialize */ TabsConstraintInitialize, | |
399 /* destroy */ NULL, | |
400 /* set_values */ TabsConstraintSetValues, | |
401 /* extension */ NULL, | |
402 }, | |
403 #ifdef NEED_MOTIF | |
404 /* Manager Class fields */ | |
405 { | |
406 /* translations */ NULL, | |
407 /* syn_resources */ NULL, | |
408 /* num_syn_resources */ 0, | |
409 /* syn_constraint_resources */ NULL, | |
410 /* num_syn_constraint_resources */ 0, | |
411 /* parent_process */ XmInheritParentProcess, | |
412 /* extension */ NULL | |
413 }, | |
414 #endif | |
415 { | |
416 /* Tabs class fields */ | |
417 /* extension */ NULL, | |
418 } | |
419 }; | |
420 | |
421 WidgetClass tabsWidgetClass = (WidgetClass)&tabsClassRec; | |
422 | |
446 | 423 #define TabsNumChildren(tw) (((TabsWidget)tw)->composite.num_children) |
424 #define TabVisible(tab) \ | |
425 (XtIsManaged(tab) && \ | |
426 ((TabsConstraints)((tab)->core.constraints))->tabs.visible) | |
428 | 427 |
428 | |
3094 | 429 |
430 static int debug_tabs = 0; /* increase for more verbosity */ | |
431 | |
432 #ifdef USE_XFT_TABS | |
433 /* #### duplicated from xlwmenu.c -- CLEAN THIS SHIT UP! | |
434 Undeclared so define at top. */ | |
435 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \ | |
436 ? ((unsigned long) (x)) : ((unsigned long) (y))) | |
437 | |
438 static int | |
439 x_xft_text_width (Display *dpy, XftFont *xft_font, FcChar8 *run, int len) | |
440 { | |
441 static XGlyphInfo glyphinfo; /* #### static? */ | |
442 | |
443 XftTextExtents8 (dpy, | |
444 xft_font, | |
445 run, len, &glyphinfo); | |
446 return glyphinfo.xOff; | |
447 } | |
448 #endif | |
449 | |
428 | 450 /**************************************************************** |
451 * | |
452 * Member Procedures | |
453 * | |
454 ****************************************************************/ | |
455 | |
456 static void | |
457 TabsClassInit(void) | |
458 { | |
459 defaultAccelerators = XtParseAcceleratorTable(accelTable) ; | |
460 /* TODO: register converter for labels? */ | |
461 } | |
462 | |
463 | |
464 | |
465 /* Init a newly created tabs widget. Compute height of tabs | |
466 * and optionally compute size of widget. */ | |
467 | |
468 /* ARGSUSED */ | |
469 | |
470 static void | |
3025 | 471 TabsInit(Widget request, Widget new_, ArgList UNUSED (args), |
2286 | 472 Cardinal *UNUSED (num_args)) |
428 | 473 { |
3025 | 474 TabsWidget newTw = (TabsWidget)new_; |
428 | 475 |
476 newTw->tabs.numRows = 0 ; | |
446 | 477 newTw->tabs.realRows = 0; |
428 | 478 |
479 GetPreferredSizes(newTw) ; | |
480 | |
481 /* height is easy, it's the same for all tabs: | |
482 * TODO: font height + height of tallest bitmap. | |
483 */ | |
484 newTw->tabs.tab_height = 2 * newTw->tabs.internalHeight + SHADWID ; | |
485 | |
3094 | 486 #ifdef USE_XFT_TABS |
3685 | 487 /* #### kludge for name change */ |
488 if (!newTw->tabs.fcFontName) | |
489 newTw->tabs.fcFontName = newTw->tabs.xftFontName; | |
3094 | 490 /* must get font here |
3685 | 491 #### to do this right, we should add a new Xt Resource type + |
492 conversion function */ | |
3094 | 493 newTw->tabs.renderFont = |
494 xft_open_font_by_name (XtDisplay ((Widget) newTw), | |
3397 | 495 newTw->tabs.fcFontName); |
3094 | 496 if (newTw->tabs.renderFont != NULL) |
497 #if XFT_USE_HEIGHT_NOT_ASCENT_DESCENT | |
498 newTw->tabs.tab_height += newTw->tabs.renderFont->height; | |
499 #else | |
500 newTw->tabs.tab_height += newTw->tabs.renderFont->ascent + | |
501 newTw->tabs.renderFont->descent; | |
502 #endif /* XFT_USE_HEIGHT_NOT_ASCENT_DESCENT */ | |
503 #else /* ! USE_XFT_TABS */ | |
504 if (newTw->tabs.font != NULL) | |
428 | 505 newTw->tabs.tab_height += newTw->tabs.font->max_bounds.ascent + |
3094 | 506 newTw->tabs.font->max_bounds.descent; |
507 #endif /* ! USE_XFT_TABS */ | |
428 | 508 |
509 /* if size not explicitly set, set it to our preferred size now. */ | |
510 | |
511 if( request->core.width == 0 || request->core.height == 0 ) | |
512 { | |
513 Dimension w,h ; | |
514 PreferredSize(newTw, &w, &h, NULL,NULL) ; | |
3025 | 515 if( request->core.width == 0 ) new_->core.width = w ; |
516 if( request->core.height == 0 ) new_->core.height = h ; | |
517 XtClass(new_)->core_class.resize(new_) ; | |
428 | 518 } |
519 | |
520 /* defer GC allocation, etc., until Realize() time. */ | |
521 newTw->tabs.foregroundGC = | |
522 newTw->tabs.backgroundGC = | |
523 newTw->tabs.greyGC = | |
524 newTw->tabs.topGC = | |
525 newTw->tabs.botGC = None ; | |
526 | |
527 newTw->tabs.grey50 = None ; | |
528 | |
529 newTw->tabs.needs_layout = False ; | |
434 | 530 |
428 | 531 newTw->tabs.hilight = NULL ; |
532 | |
533 #ifdef NEED_MOTIF | |
534 newTw->manager.navigation_type = XmTAB_GROUP ; | |
535 newTw->manager.traversal_on = True ; | |
536 #endif | |
537 } | |
538 | |
539 | |
540 /* Init the constraint part of a new tab child. Compute the | |
541 * size of the tab. | |
542 */ | |
543 /* ARGSUSED */ | |
544 static void | |
3025 | 545 TabsConstraintInitialize(Widget UNUSED (request), Widget new_, |
2286 | 546 ArgList UNUSED (args), Cardinal *UNUSED (num_args)) |
428 | 547 { |
3025 | 548 TabsConstraints tab = (TabsConstraints) new_->core.constraints ; |
428 | 549 tab->tabs.greyAlloc = False ; /* defer allocation of pixel */ |
446 | 550 tab->tabs.visible = False ; |
428 | 551 |
3025 | 552 getBitmapInfo((TabsWidget)XtParent(new_), tab) ; |
553 TabWidth(new_) ; | |
428 | 554 } |
555 | |
556 | |
557 | |
558 /* Called when tabs widget first realized. Create the window | |
559 * and allocate the GCs | |
560 */ | |
561 | |
562 static void | |
563 TabsRealize(Widget w, Mask *valueMask, XSetWindowAttributes *attributes) | |
564 { | |
565 TabsWidget tw = (TabsWidget) w; | |
566 | |
567 attributes->bit_gravity = NorthWestGravity; | |
568 *valueMask |= CWBitGravity; | |
569 | |
570 SuperClass->core_class.realize(w, valueMask, attributes); | |
571 | |
572 TabsAllocGCs(tw) ; | |
573 } | |
574 | |
575 | |
576 | |
577 static void | |
578 TabsDestroy(Widget w) | |
579 { | |
4173 | 580 TabsWidget tw = (TabsWidget) w; |
581 #ifdef USE_XFT_TABS | |
582 XftFontClose (XtDisplay (w), tw->tabs.renderFont); | |
583 #endif /* ! USE_XFT_TABS */ | |
584 TabsFreeGCs (tw) ; | |
428 | 585 } |
586 | |
587 | |
588 /* Parent has resized us. This will require that the tabs be | |
589 * laid out again. | |
590 */ | |
591 | |
592 static void | |
593 TabsResize(Widget w) | |
594 { | |
595 TabsWidget tw = (TabsWidget) w; | |
596 int i ; | |
597 int num_children = tw->composite.num_children ; | |
598 Widget *childP ; | |
2286 | 599 /* TabsConstraints tab ; */ /* #### unused */ |
428 | 600 Dimension cw,ch,bw ; |
601 | |
602 /* Our size has now been dictated by the parent. Lay out the | |
603 * tabs, lay out the frame, lay out the children. Remember | |
604 * that the tabs overlap each other and the frame by shadowWidth. | |
605 * Also, the top tab is larger than the others, so if there's only | |
606 * one row, the widget must be made taller to accommodate this. | |
607 * | |
608 * Once the tabs are laid out, if there is more than one | |
609 * row, we may need to shuffle the rows to bring the top tab | |
610 * to the bottom row. | |
611 */ | |
612 | |
434 | 613 tw->tabs.needs_layout = False ; |
614 | |
428 | 615 if( num_children > 0 && tw->composite.children != NULL ) |
616 { | |
617 /* Loop through the tabs and assign rows & x positions */ | |
618 (void) TabLayout(tw, tw->core.width, tw->core.height, NULL, False) ; | |
446 | 619 num_children = TabsNumChildren (tw); |
428 | 620 |
621 /* assign a top widget, bring it to bottom row. */ | |
622 TabsShuffleRows(tw) ; | |
623 | |
624 /* now assign child positions & sizes. Positions are all the | |
625 * same: just inside the frame. Sizes are also all the same. | |
626 */ | |
627 | |
628 tw->tabs.child_width = cw = tw->core.width - 2 * SHADWID ; | |
629 tw->tabs.child_height = ch = | |
448 | 630 tw->core.height < (tw->tabs.tab_total + 2 * SHADWID) ? 0 : |
631 tw->core.height - tw->tabs.tab_total - 2 * SHADWID ; | |
428 | 632 |
633 for(i=0, childP=tw->composite.children; | |
434 | 634 i < num_children; |
428 | 635 ++i, ++childP) |
448 | 636 if( XtIsManaged(*childP) ) |
428 | 637 { |
2286 | 638 /* tab = (TabsConstraints) (*childP)->core.constraints ; */ |
434 | 639 bw = (*childP)->core.border_width ; |
448 | 640 /* Don't do anything if we can't see any of the child. */ |
641 if (ch >= bw*2 && ch > 0 && cw >= bw*2 && cw > 0) | |
642 XtConfigureWidget(*childP, SHADWID,tw->tabs.tab_total+SHADWID, | |
643 cw-bw*2,ch-bw*2, bw) ; | |
428 | 644 } |
434 | 645 if( XtIsRealized(w) ) { |
646 XClearWindow(XtDisplay((Widget)tw), XtWindow((Widget)tw)) ; | |
647 /* should not be necessary to explicitly repaint after a | |
648 * resize, but XEmacs folks tell me it is. | |
649 */ | |
650 XtClass(tw)->core_class.expose((Widget)tw,NULL,None) ; | |
651 } | |
428 | 652 } |
653 } /* Resize */ | |
654 | |
655 | |
656 | |
657 /* Redraw entire Tabs widget */ | |
658 | |
659 /* ARGSUSED */ | |
660 static void | |
2286 | 661 TabsExpose(Widget w, XEvent *UNUSED (event), Region UNUSED (region)) |
428 | 662 { |
663 TabsWidget tw = (TabsWidget) w; | |
664 | |
665 if( tw->tabs.needs_layout ) | |
666 XtClass(w)->core_class.resize(w) ; | |
667 | |
668 DrawTabs(tw, True) ; | |
669 } | |
670 | |
671 | |
672 /* Called when any Tabs widget resources are changed. */ | |
673 | |
674 /* ARGSUSED */ | |
675 static Boolean | |
3025 | 676 TabsSetValues(Widget current, Widget UNUSED (request), Widget new_, |
2286 | 677 ArgList UNUSED (args), Cardinal *UNUSED (num_args)) |
428 | 678 { |
430 | 679 TabsWidget curtw = (TabsWidget) current ; |
3025 | 680 TabsWidget tw = (TabsWidget) new_ ; |
430 | 681 Boolean needRedraw = False ; |
682 Widget *childP ; | |
683 int i ; | |
428 | 684 |
3094 | 685 if( |
686 #ifdef USE_XFT_TABS | |
687 tw->tabs.renderFont != curtw->tabs.renderFont || | |
688 #else | |
689 tw->tabs.font != curtw->tabs.font || | |
690 #endif | |
691 tw->tabs.internalWidth != curtw->tabs.internalWidth || | |
692 tw->tabs.internalHeight != curtw->tabs.internalHeight) | |
430 | 693 { |
3094 | 694 tw->tabs.tab_height = 2 * tw->tabs.internalHeight + SHADWID; |
428 | 695 |
3094 | 696 #ifdef USE_XFT_TABS |
697 if (tw->tabs.renderFont != NULL) | |
698 #if XFT_USE_HEIGHT_NOT_ASCENT_DESCENT | |
699 tw->tabs.tab_height += tw->tabs.renderFont->height; | |
700 #else | |
701 tw->tabs.tab_height += tw->tabs.renderFont->ascent + | |
702 tw->tabs.renderFont->descent; | |
703 #endif /* XFT_USE_HEIGHT_NOT_ASCENT_DESCENT */ | |
704 #else /* ! USE_XFT_TABS */ | |
705 if (tw->tabs.font != NULL) | |
430 | 706 tw->tabs.tab_height += tw->tabs.font->max_bounds.ascent + |
3094 | 707 tw->tabs.font->max_bounds.descent; |
708 #endif /* ! USE_XFT_TABS */ | |
428 | 709 |
430 | 710 /* Tab size has changed. Resize all tabs and request a new size */ |
711 for(i=0, childP=tw->composite.children; | |
647 | 712 i < (int) tw->composite.num_children; |
430 | 713 ++i, ++childP) |
714 if( XtIsManaged(*childP) ) | |
715 TabWidth(*childP) ; | |
716 PreferredSize(tw, &tw->core.width, &tw->core.height, NULL,NULL) ; | |
717 needRedraw = True ; | |
718 tw->tabs.needs_layout = True ; | |
719 } | |
428 | 720 |
430 | 721 /* TODO: if any color changes, need to recompute GCs and redraw */ |
428 | 722 |
430 | 723 if( tw->core.background_pixel != curtw->core.background_pixel || |
432 | 724 tw->core.background_pixmap != curtw->core.background_pixmap || |
3094 | 725 #ifdef USE_XFT_TABS |
726 tw->tabs.renderFont != curtw->tabs.renderFont | |
727 #else | |
728 tw->tabs.font != curtw->tabs.font | |
729 #endif | |
730 ) | |
3025 | 731 if( XtIsRealized(new_) ) |
430 | 732 { |
733 TabsFreeGCs(tw) ; | |
734 TabsAllocGCs(tw) ; | |
735 needRedraw = True ; | |
736 } | |
428 | 737 |
430 | 738 if( tw->core.sensitive != curtw->core.sensitive ) |
739 needRedraw = True ; | |
428 | 740 |
430 | 741 /* If top widget changes, need to change stacking order, redraw tabs. |
742 * Window system will handle the redraws. | |
743 */ | |
428 | 744 |
442 | 745 if( tw->tabs.topWidget != curtw->tabs.topWidget ) |
432 | 746 { |
430 | 747 if( XtIsRealized(tw->tabs.topWidget) ) |
748 { | |
749 Widget w = tw->tabs.topWidget ; | |
750 TabsConstraints tab = (TabsConstraints) w->core.constraints ; | |
428 | 751 |
430 | 752 XRaiseWindow(XtDisplay(w), XtWindow(w)) ; |
428 | 753 #ifdef NEED_MOTIF |
430 | 754 XtVaSetValues(curtw->tabs.topWidget, XmNtraversalOn, False, 0) ; |
755 XtVaSetValues(w, XmNtraversalOn, True, 0) ; | |
428 | 756 #endif |
757 | |
647 | 758 if( tab->tabs.row != (int) tw->tabs.numRows-1 ) |
430 | 759 TabsShuffleRows(tw) ; |
428 | 760 |
430 | 761 needRedraw = True ; |
762 } | |
763 else | |
764 tw->tabs.needs_layout = True ; | |
432 | 765 } |
428 | 766 |
430 | 767 return needRedraw ; |
428 | 768 } |
769 | |
770 | |
771 /* Called when any child constraint resources change. */ | |
772 | |
773 /* ARGSUSED */ | |
774 static Boolean | |
3025 | 775 TabsConstraintSetValues(Widget current, Widget UNUSED (request), Widget new_, |
2286 | 776 ArgList UNUSED (args), Cardinal *UNUSED (num_args)) |
428 | 777 { |
3025 | 778 TabsWidget tw = (TabsWidget) XtParent(new_) ; |
428 | 779 TabsConstraints ctab = (TabsConstraints) current->core.constraints ; |
3025 | 780 TabsConstraints tab = (TabsConstraints) new_->core.constraints ; |
428 | 781 |
782 | |
783 /* if label changes, need to re-layout the entire widget */ | |
784 /* if foreground changes, need to redraw tab label */ | |
785 | |
786 /* TODO: only need resize of new bitmap has different dimensions | |
787 * from old bitmap. | |
788 */ | |
789 | |
790 if( tab->tabs.label != ctab->tabs.label || /* Tab size has changed. */ | |
791 tab->tabs.left_bitmap != ctab->tabs.left_bitmap ) | |
792 { | |
3025 | 793 TabWidth(new_) ; |
428 | 794 tw->tabs.needs_layout = True ; |
795 | |
796 if( tab->tabs.left_bitmap != ctab->tabs.left_bitmap ) | |
797 getBitmapInfo(tw, tab) ; | |
798 | |
799 /* If there are no subclass ConstraintSetValues procedures remaining | |
800 * to be invoked, and if the preferred size has changed, ask | |
801 * for a resize. | |
802 */ | |
803 if( XtClass((Widget)tw) == tabsWidgetClass ) | |
804 MakeSizeRequest(tw) ; | |
805 } | |
806 | |
807 | |
808 /* The child widget itself never needs a redisplay, but the parent | |
809 * Tabs widget might. | |
810 */ | |
811 | |
3025 | 812 if( XtIsRealized(new_) ) |
428 | 813 { |
814 if( tw->tabs.needs_layout ) { | |
815 XClearWindow(XtDisplay((Widget)tw), XtWindow((Widget)tw)) ; | |
816 XtClass(tw)->core_class.expose((Widget)tw,NULL,None) ; | |
817 } | |
818 | |
819 else if( tab->tabs.foreground != ctab->tabs.foreground ) | |
3025 | 820 DrawTab(tw, new_, True) ; |
428 | 821 } |
822 | |
823 return False ; | |
824 } | |
825 | |
826 | |
434 | 827 static Boolean |
2286 | 828 TabsAcceptFocus(Widget w, Time *UNUSED (t)) |
434 | 829 { |
830 if( !w->core.being_destroyed && XtIsRealized(w) && | |
831 XtIsSensitive(w) && XtIsManaged(w) && w->core.visible ) | |
832 { | |
833 Widget p ; | |
834 for(p = XtParent(w); !XtIsShell(p); p = XtParent(p)) ; | |
835 XtSetKeyboardFocus(p,w) ; | |
836 return True ; | |
837 } | |
838 else | |
839 return False ; | |
840 } | |
841 | |
842 | |
428 | 843 |
844 /* | |
3094 | 845 * Return status, with preferred size in PREFERRED. |
846 * | |
847 * According to the X Toolkit Intrinsics manual | |
848 * XtGeometryYes = accept INTENDED without change | |
849 * XtGeometryNo = request to stay _exactly_ the same | |
850 * XtGeometryAlmost = suggest PREFERRED as a compromise | |
851 * and the PREFERRED argument must be filled in completely (ie, any fields | |
852 * whose bits are set in the request_mode mask must correspond to the | |
853 * preferred geometry, which must be consistent with the return value). | |
854 * | |
855 * Assuming horizontal orientation, in XEmacs, we should always accept if | |
856 * the width is more than we need. There's no problem if there are only a | |
857 * couple of tabs packed to the left. OTOH there's probably something wrong | |
858 * if we're offered a height more than 1.5x or 2x the preferred height. | |
859 * (#### Do tab controls do vertical?) | |
428 | 860 */ |
861 | |
3094 | 862 /* compute the height above which we complain */ |
863 #define TAB_HEIGHT_TOLERANCE(x) (2*x) | |
864 | |
428 | 865 static XtGeometryResult |
3094 | 866 TabsQueryGeometry (Widget w, |
867 XtWidgetGeometry *intended, | |
868 XtWidgetGeometry *preferred) /* RETURN */ | |
428 | 869 { |
3094 | 870 TabsWidget tw = (TabsWidget) w; |
871 XtGeometryMask mode = intended->request_mode; | |
872 | |
873 preferred->request_mode = CWWidth | CWHeight; | |
874 PreferredSize (tw, &preferred->width, &preferred->height, NULL, NULL); | |
428 | 875 |
3094 | 876 /* If width is big enough, accept it. */ |
877 if ((mode & CWWidth) && intended->width >= preferred->width) | |
878 preferred->width = intended->width; | |
428 | 879 |
3094 | 880 /* If height is within range, accept it. |
881 #### If too tall, we could offer a compromise at TAB_HEIGHT_TOLERANCE. | |
882 Should we? */ | |
883 if ((mode & CWHeight) && intended->height >= preferred->height | |
884 && intended->height <= TAB_HEIGHT_TOLERANCE (preferred->height)) | |
885 preferred->height = intended->height; | |
428 | 886 |
3094 | 887 /* Compute return value. */ |
888 if (preferred->width == ((mode & CWWidth) ? intended->width | |
889 : w->core.width) | |
890 && preferred->height == ((mode & CWHeight) ? intended->height | |
891 : w->core.height)) | |
428 | 892 return XtGeometryYes; |
3094 | 893 else if (preferred->width == w->core.width |
894 && preferred->height == w->core.height) | |
895 return XtGeometryNo; | |
896 else | |
897 return XtGeometryAlmost; | |
428 | 898 } |
899 | |
900 | |
901 | |
902 /* | |
3094 | 903 * Geometry Manager; called when TAB (a child) wants to be resized. |
904 * | |
905 * According to the X Toolkit Intrinsics manual | |
906 * XtGeometryDone = accept REQUEST and do it (#### check this) | |
907 * XtGeometryYes = accept REQUEST without change | |
908 * XtGeometryNo = refuse REQUEST (ie, stay _exactly_ the same) | |
909 * XtGeometryAlmost = suggest REPLY as a compromise | |
428 | 910 */ |
911 | |
912 static XtGeometryResult | |
3094 | 913 TabsGeometryManager (Widget tab, |
914 XtWidgetGeometry *request, | |
915 XtWidgetGeometry *reply) /* RETURN */ | |
428 | 916 { |
3094 | 917 TabsWidget control = (TabsWidget) XtParent(tab); |
918 Dimension s = SHADWID; | |
919 TabsConstraints constraint = (TabsConstraints) tab->core.constraints; | |
920 XtGeometryResult result, best_offer = XtGeometryYes; | |
921 Dimension rw, rh; | |
922 | |
923 static int debug_count = 0; | |
924 static int debug_mask = 1; | |
925 | |
926 /* Position request cannot be satisfied, so if tabs are not resizable, | |
927 no nontrivial request can be satisfied: return XGeometryNo. */ | |
928 if (!constraint->tabs.resizable) | |
929 return XtGeometryNo; | |
930 | |
931 fprintf (stderr, "Urk! label is resizable!\n"); | |
428 | 932 |
3094 | 933 /* Assume we will refuse these; toggle iff we accept them. |
934 Reply won't specify any fields not in the request. */ | |
935 reply->request_mode = request->request_mode; | |
936 reply->x = tab->core.x; | |
937 reply->y = tab->core.y; | |
428 | 938 |
3094 | 939 /* If a position request would result in a change, best offer is |
940 XtGeometryAlmost. Otherwise toggle reply->request_mode. */ | |
941 if ((request->request_mode & CWX) && request->x != tab->core.x) | |
942 best_offer = XtGeometryAlmost; | |
943 else | |
944 reply->request_mode &= ~CWX; | |
945 if ((request->request_mode & CWY) && request->y != tab->core.y) | |
946 best_offer = XtGeometryAlmost; | |
947 else | |
948 reply->request_mode &= ~CWY; | |
428 | 949 |
3094 | 950 /* Make all three fields in the reply valid */ |
951 reply->width = (request->request_mode & CWWidth) | |
952 ? request->width : tab->core.width; | |
953 reply->height = (request->request_mode & CWHeight) | |
954 ? request->height : tab->core.height; | |
955 reply->border_width = (request->request_mode & CWBorderWidth) | |
956 ? request->border_width : tab->core.border_width; | |
957 | |
958 /* check if we can already offer a compromise */ | |
959 if (best_offer == XtGeometryAlmost && | |
960 reply->width == tab->core.width && | |
961 reply->height == tab->core.height && | |
962 reply->border_width == tab->core.border_width) | |
963 { | |
964 reply->request_mode &= ~(CWWidth | CWHeight | CWBorderWidth); | |
965 return best_offer; | |
966 } | |
428 | 967 |
3094 | 968 #ifndef DONT_DEBUG_REQUESTS |
969 #define DBG_REQUEST_PRINT(name,field,size) \ | |
970 do { \ | |
971 if (reply->field > size) \ | |
972 { \ | |
973 if (++debug_count == debug_mask) \ | |
974 { \ | |
975 debug_mask <<= 1; \ | |
976 fprintf (stderr, "ridiculous %s request #%d: %d > %d\n", \ | |
977 name, debug_count, reply->field, size); \ | |
978 } \ | |
979 reply->field = tab->core.field; \ | |
980 } \ | |
981 } while (0) | |
428 | 982 |
3094 | 983 DBG_REQUEST_PRINT ("width",width,1024); |
984 DBG_REQUEST_PRINT ("height",height,768); | |
985 DBG_REQUEST_PRINT ("border_width",border_width,30); | |
986 #undef DBG_REQUEST_PRINT | |
987 #endif | |
988 | |
989 rw = reply->width + 2 * reply->border_width; | |
990 rh = reply->height + 2 * reply->border_width; | |
434 | 991 |
992 /* find out how big the children want to be now */ | |
3094 | 993 MaxChild (control, tab, rw, rh); |
428 | 994 |
995 | |
996 /* Size changes must see if the new size can be accommodated. | |
3094 | 997 * The Tabs widget keeps all of its children the same height, but |
998 * widths may vary. | |
999 * A request to shrink will be accepted only if the | |
428 | 1000 * new size is still big enough for all other children. A |
1001 * request to shrink that is not big enough for all children | |
434 | 1002 * returns an "almost" response with the new proposed size |
1003 * or a "no" response if unable to shrink at all. | |
1004 * | |
3094 | 1005 * A request to grow will be accepted only if the Tabs control can |
428 | 1006 * grow to accommodate. |
1007 * | |
1008 * TODO: | |
1009 * We could get fancy here and re-arrange the tabs if it is | |
1010 * necessary to compromise with the parent, but we'll save that | |
1011 * for another day. | |
1012 */ | |
1013 | |
3094 | 1014 if (request->request_mode & (CWWidth | CWHeight | CWBorderWidth)) |
428 | 1015 { |
1016 Dimension cw,ch ; /* children's preferred size */ | |
1017 Dimension aw,ah ; /* available size we can give child */ | |
1018 Dimension th ; /* space used by tabs */ | |
1019 Dimension wid,hgt ; /* Tabs widget size */ | |
3094 | 1020 int check_nrows; |
428 | 1021 |
3094 | 1022 cw = control->tabs.max_cw ; |
1023 ch = control->tabs.max_ch ; | |
428 | 1024 |
434 | 1025 /* find out what *my* resulting preferred size would be */ |
3094 | 1026 /* #### this whole API is wrong; what should happen is |
1027 1. app should hint as to #rows and/or aspect ratio | |
1028 2. tab control should attempt to layout in current space | |
1029 3. if not all tabs fit, should request resize to achieve | |
1030 layout hints | |
1031 Probably can and should cache preferred size in widget, with | |
1032 cache cleared when labels or core size changes. */ | |
1033 PreferredSize2(control, cw, ch, &wid, &hgt) ; | |
434 | 1034 |
1035 /* Would my size change? If so, ask to be resized. */ | |
428 | 1036 |
3094 | 1037 if (wid != control->core.width || hgt != control->core.height) |
428 | 1038 { |
3094 | 1039 Dimension oldWid = control->core.width, |
1040 oldHgt = control->core.height; | |
428 | 1041 XtWidgetGeometry myrequest, myreply ; |
1042 | |
1043 myrequest.width = wid ; | |
1044 myrequest.height = hgt ; | |
1045 myrequest.request_mode = CWWidth | CWHeight ; | |
448 | 1046 |
1047 assert (wid > 0 && hgt > 0); | |
428 | 1048 /* If child is only querying, or if we're going to have to |
1049 * offer the child a compromise, then make this a query only. | |
1050 */ | |
1051 | |
3094 | 1052 if ((request->request_mode & XtCWQueryOnly) || rw < cw || rh < ch) |
1053 myrequest.request_mode |= XtCWQueryOnly; | |
428 | 1054 |
3094 | 1055 result = XtMakeGeometryRequest ((Widget) control, |
1056 &myrequest, &myreply); | |
428 | 1057 |
434 | 1058 /* !$@# Athena Box widget changes the core size even if QueryOnly |
428 | 1059 * is set. I'm convinced this is a bug. At any rate, to work |
1060 * around the bug, we need to restore the core size after every | |
1061 * query geometry request. This is only partly effective, | |
1062 * as there may be other boxes further up the tree. | |
1063 */ | |
3094 | 1064 if (myrequest.request_mode & XtCWQueryOnly) { |
1065 control->core.width = oldWid; | |
1066 control->core.height = oldHgt; | |
428 | 1067 } |
1068 | |
1069 /* based on the parent's response, determine what the | |
1070 * resulting Tabs widget size would be. | |
1071 */ | |
1072 | |
3094 | 1073 switch (result) { |
428 | 1074 case XtGeometryYes: |
1075 case XtGeometryDone: | |
3094 | 1076 control->tabs.needs_layout = True; |
1077 break; | |
428 | 1078 |
1079 case XtGeometryNo: | |
3094 | 1080 wid = control->core.width; |
1081 hgt = control->core.height; | |
1082 break; | |
428 | 1083 |
1084 case XtGeometryAlmost: | |
3094 | 1085 wid = myreply.width; |
1086 hgt = myreply.height; | |
1087 control->tabs.needs_layout = True; | |
1088 break; | |
428 | 1089 } |
1090 } | |
1091 | |
1092 /* Within the constraints imposed by the parent, what is | |
1093 * the max size we can give the child? | |
1094 */ | |
3094 | 1095 check_nrows = TabLayout (control, wid, hgt, &th, True); |
1096 aw = wid - 2*s; | |
1097 if (check_nrows == 1) | |
1098 { | |
1099 ah = hgt - th - 2*s; | |
1100 } | |
1101 else | |
1102 { | |
1103 /* this rarely gets triggered, but when it does it seems to | |
1104 get triggered forever after */ | |
1105 int n = control->composite.num_children; | |
1106 ah = control->tabs.tab_height; | |
3397 | 1107 if (debug_tabs > 1) |
3094 | 1108 fprintf (stderr, "Kludging around %d != 1 rows," |
1109 " #children = %d, total height %d, using %d.\n", | |
1110 check_nrows, n, th, ah); | |
1111 } | |
428 | 1112 |
1113 /* OK, make our decision. If requested size is >= max sibling | |
1114 * preferred size, AND requested size <= available size, then | |
1115 * we accept. Otherwise, we offer a compromise. | |
1116 */ | |
1117 | |
3094 | 1118 if (rw == aw && rh == ah) |
428 | 1119 { |
1120 /* Acceptable. If this wasn't a query, change *all* children | |
1121 * to this size. | |
1122 */ | |
3094 | 1123 if (request->request_mode & XtCWQueryOnly) |
1124 { | |
1125 control->tabs.needs_layout = False; | |
1126 return XtGeometryYes ; | |
1127 } | |
428 | 1128 else |
1129 { | |
3094 | 1130 Widget *childP = control->composite.children; |
1131 int i, bw; | |
1132 tab->core.border_width = request->border_width; | |
1133 for (i = TabsNumChildren (control); --i >= 0; ++childP) | |
1134 if (TabVisible (*childP)) | |
428 | 1135 { |
3094 | 1136 bw = (*childP)->core.border_width; |
1137 XtConfigureWidget (*childP, s, control->tabs.tab_total+s, | |
1138 rw-2*bw, rh-2*bw, bw); | |
428 | 1139 } |
1140 #ifdef COMMENT | |
1141 /* TODO: under what conditions will we need to redraw? */ | |
3094 | 1142 XClearWindow (XtDisplay ((Widget) control), |
1143 XtWindow ((Widget) control)); | |
1144 XtClass (control)->core_class.expose ((Widget)control, | |
1145 NULL, NULL); | |
428 | 1146 #endif /* COMMENT */ |
3094 | 1147 return XtGeometryDone; |
428 | 1148 } |
1149 } | |
1150 | |
1151 /* Cannot grant child's request. Describe what we *can* do | |
1152 * and return counter-offer. | |
1153 */ | |
3094 | 1154 control->tabs.needs_layout = False; |
1155 reply->width = aw - 2 * request->border_width ; | |
1156 reply->height = ah - 2 * request->border_width ; | |
1157 reply->request_mode &= | |
1158 ~((reply->border_width == tab->core.border_width | |
1159 ? CWBorderWidth : 0) | |
1160 |(reply->width == tab->core.width ? CWWidth : 0) | |
1161 |(reply->height == tab->core.height ? CWHeight : 0)); | |
428 | 1162 return XtGeometryAlmost ; |
1163 } | |
1164 | |
1165 return XtGeometryYes ; | |
1166 } | |
1167 | |
1168 | |
1169 | |
1170 | |
1171 /* The number of children we manage has changed; recompute | |
1172 * size from scratch. | |
1173 */ | |
1174 | |
1175 static void | |
1176 TabsChangeManaged(Widget w) | |
1177 { | |
1178 TabsWidget tw = (TabsWidget)w ; | |
1179 Widget *childP = tw->composite.children ; | |
1180 int i ; | |
1181 | |
1182 if( tw->tabs.topWidget != NULL && | |
1183 ( !XtIsManaged(tw->tabs.topWidget) || | |
1184 tw->tabs.topWidget->core.being_destroyed ) ) | |
1185 tw->tabs.topWidget = NULL ; | |
1186 | |
440 | 1187 /* Check whether the highlight tab is still valid. */ |
1188 if( tw->tabs.hilight != NULL && | |
1189 ( !XtIsManaged(tw->tabs.hilight) || | |
1190 tw->tabs.hilight->core.being_destroyed ) ) | |
1191 tw->tabs.hilight = NULL ; | |
1192 | |
428 | 1193 GetPreferredSizes(tw) ; |
1194 MakeSizeRequest(tw) ; | |
1195 | |
1196 XtClass(w)->core_class.resize(w) ; | |
1197 if( XtIsRealized(w) ) | |
1198 { | |
1199 Display *dpy = XtDisplay(w) ; | |
1200 XClearWindow(dpy, XtWindow(w)) ; | |
1201 XtClass(w)->core_class.expose(w,NULL,NULL) ; | |
1202 | |
1203 /* make sure the top widget stays on top. This requires | |
1204 * making sure that all new children are realized first. | |
1205 */ | |
1206 if( tw->tabs.topWidget != NULL && XtIsRealized(tw->tabs.topWidget) ) | |
1207 { | |
446 | 1208 for(i=TabsNumChildren (tw); --i >= 0; ++childP) |
428 | 1209 if( !XtIsRealized(*childP) ) |
1210 XtRealizeWidget(*childP) ; | |
1211 | |
1212 XRaiseWindow(dpy, XtWindow(tw->tabs.topWidget)) ; | |
1213 } | |
1214 } | |
1215 | |
1216 #ifdef NEED_MOTIF | |
1217 /* Only top widget may receive input */ | |
1218 | |
1219 for(childP = tw->composite.children, i=tw->composite.num_children; | |
1220 --i >= 0; | |
1221 ++childP) | |
1222 { | |
1223 XtVaSetValues(*childP, XmNtraversalOn, False, 0) ; | |
1224 } | |
1225 | |
1226 if( tw->tabs.topWidget != NULL ) | |
1227 XtVaSetValues(tw->tabs.topWidget, XmNtraversalOn, True, 0) ; | |
1228 #endif | |
1229 } | |
1230 | |
1231 | |
1232 | |
1233 | |
1234 /**************************************************************** | |
1235 * | |
1236 * Action Procedures | |
1237 * | |
1238 ****************************************************************/ | |
1239 | |
1240 | |
1241 /* User clicks on a tab, figure out which one it was. */ | |
1242 | |
1243 /* ARGSUSED */ | |
1244 static void | |
2286 | 1245 TabsSelect(Widget w, XEvent *event, String *UNUSED (params), |
1246 Cardinal *UNUSED (num_params)) | |
428 | 1247 { |
1248 TabsWidget tw = (TabsWidget) w ; | |
1249 Widget *childP ; | |
1250 Position x,y ; | |
1251 Dimension h = tw->tabs.tab_height ; | |
1252 int i ; | |
1253 | |
1254 #ifdef NEED_MOTIF | |
1255 XmProcessTraversal (w, XmTRAVERSE_CURRENT) ; | |
1256 #endif | |
1257 | |
1258 /* TODO: is there an Xmu function or something to do this instead? */ | |
1259 switch( event->type ) { | |
1260 case ButtonPress: | |
1261 case ButtonRelease: | |
1262 x = event->xbutton.x ; y = event->xbutton.y ; break ; | |
1263 case KeyPress: | |
1264 case KeyRelease: | |
1265 x = event->xkey.x ; y = event->xkey.y ; break ; | |
1266 default: | |
1267 return ; | |
1268 } | |
1269 | |
1270 /* TODO: determine which tab was clicked, if any. Set that | |
1271 * widget to be top of stacking order with XawTabsSetTop(). | |
1272 */ | |
1273 for(i=0, childP=tw->composite.children; | |
647 | 1274 i < (int) TabsNumChildren (tw); |
428 | 1275 ++i, ++childP) |
446 | 1276 if( TabVisible(*childP) ) |
428 | 1277 { |
1278 TabsConstraints tab = (TabsConstraints)(*childP)->core.constraints; | |
1279 if( x > tab->tabs.x && x < tab->tabs.x + tab->tabs.width && | |
1280 y > tab->tabs.y && y < tab->tabs.y + h ) | |
1281 { | |
1282 if( *childP != tw->tabs.topWidget && | |
1283 (XtIsSensitive(*childP) || tw->tabs.selectInsensitive) ) | |
1284 XawTabsSetTop(*childP, True) ; | |
1285 break ; | |
1286 } | |
1287 } | |
1288 } | |
1289 | |
1290 | |
1291 /* User hits a key */ | |
1292 | |
1293 static void | |
2286 | 1294 TabsPage(Widget w, XEvent *UNUSED (event), String *params, |
1295 Cardinal *num_params) | |
428 | 1296 { |
1297 TabsWidget tw = (TabsWidget) w ; | |
430 | 1298 Widget newtop = NULL; |
428 | 1299 Widget *childP ; |
1300 int idx ; | |
446 | 1301 int nc = TabsNumChildren (tw) ; |
428 | 1302 |
1303 if( nc <= 0 ) | |
1304 return ; | |
1305 | |
1306 if( *num_params < 1 ) { | |
1307 XtAppWarning(XtWidgetToApplicationContext(w), | |
1308 "Tabs: page() action called with no arguments") ; | |
1309 return ; | |
1310 } | |
1311 | |
1312 if( tw->tabs.topWidget == NULL ) | |
1313 tw->tabs.topWidget = tw->composite.children[0] ; | |
1314 | |
1315 for(idx=0, childP=tw->composite.children; idx < nc; ++idx, ++childP ) | |
1316 if( tw->tabs.topWidget == *childP ) | |
1317 break ; | |
1318 | |
1319 switch( params[0][0] ) { | |
1320 case 'u': /* up */ | |
1321 case 'U': | |
432 | 1322 if( --idx < 0 ) |
1323 idx = nc-1 ; | |
1324 newtop = tw->composite.children[idx] ; | |
428 | 1325 break ; |
1326 | |
1327 case 'd': /* down */ | |
1328 case 'D': | |
1329 if( ++idx >= nc ) | |
1330 idx = 0 ; | |
1331 newtop = tw->composite.children[idx] ; | |
1332 break ; | |
1333 | |
1334 case 'h': | |
1335 case 'H': | |
432 | 1336 default: |
428 | 1337 newtop = tw->composite.children[0] ; |
1338 break ; | |
1339 | |
1340 case 'e': | |
1341 case 'E': | |
1342 newtop = tw->composite.children[nc-1] ; | |
1343 break ; | |
1344 | |
1345 case 's': /* selected */ | |
1346 case 'S': | |
1347 if( (newtop = tw->tabs.hilight) == NULL ) | |
1348 return ; | |
1349 break ; | |
1350 } | |
1351 | |
1352 XawTabsSetTop(newtop, True) ; | |
1353 } | |
1354 | |
1355 | |
1356 /* User hits up/down key */ | |
1357 | |
1358 static void | |
2286 | 1359 TabsHighlight(Widget w, XEvent *UNUSED (event), String *params, |
1360 Cardinal *num_params) | |
428 | 1361 { |
1362 TabsWidget tw = (TabsWidget) w ; | |
430 | 1363 Widget newhl = NULL; |
428 | 1364 Widget *childP ; |
1365 int idx ; | |
446 | 1366 int nc = TabsNumChildren (tw) ; |
428 | 1367 |
1368 if( nc <= 0 ) | |
1369 return ; | |
1370 | |
1371 if( *num_params < 1 ) | |
1372 { | |
1373 if( tw->tabs.hilight != NULL ) | |
1374 DrawHighlight(tw, tw->tabs.hilight, False) ; | |
1375 return ; | |
1376 } | |
1377 | |
1378 if( tw->tabs.hilight == NULL ) | |
1379 newhl = tw->composite.children[0] ; | |
1380 | |
1381 else | |
1382 { | |
432 | 1383 /* find index of currently highlit child */ |
428 | 1384 for(idx=0, childP=tw->composite.children; idx < nc; ++idx, ++childP ) |
1385 if( tw->tabs.hilight == *childP ) | |
1386 break ; | |
1387 | |
1388 switch( params[0][0] ) { | |
1389 case 'u': /* up */ | |
1390 case 'U': | |
432 | 1391 if( --idx < 0 ) |
1392 idx = nc-1 ; | |
1393 newhl = tw->composite.children[idx] ; | |
428 | 1394 break ; |
1395 | |
1396 case 'd': /* down */ | |
1397 case 'D': | |
1398 if( ++idx >= nc ) | |
1399 idx = 0 ; | |
1400 newhl = tw->composite.children[idx] ; | |
1401 break ; | |
1402 | |
1403 case 'h': | |
1404 case 'H': | |
1405 newhl = tw->composite.children[0] ; | |
1406 break ; | |
1407 | |
1408 case 'e': | |
1409 case 'E': | |
1410 newhl = tw->composite.children[nc-1] ; | |
1411 break ; | |
432 | 1412 |
1413 default: | |
1414 newhl = tw->tabs.hilight ; | |
1415 break ; | |
428 | 1416 } |
1417 } | |
1418 | |
1419 XawTabsSetHighlight(w, newhl) ; | |
1420 } | |
1421 | |
1422 | |
1423 | |
1424 static void | |
2286 | 1425 TabsUnhighlight(Widget w, XEvent *UNUSED (event), String *UNUSED (params), |
1426 Cardinal *UNUSED (num_params)) | |
428 | 1427 { |
1428 TabsWidget tw = (TabsWidget) w ; | |
1429 int nc = tw->composite.num_children ; | |
1430 | |
1431 if( nc <= 0 ) | |
1432 return ; | |
1433 | |
1434 if( tw->tabs.hilight != NULL ) | |
1435 DrawHighlight(tw, tw->tabs.hilight, True) ; | |
1436 } | |
1437 | |
1438 | |
1439 | |
1440 | |
1441 | |
1442 /**************************************************************** | |
1443 * | |
1444 * Public Procedures | |
1445 * | |
1446 ****************************************************************/ | |
1447 | |
1448 | |
1449 /* Set the top tab, optionally call all callbacks. */ | |
1450 void | |
1451 XawTabsSetTop(Widget w, Bool callCallbacks) | |
1452 { | |
1453 TabsWidget tw = (TabsWidget)w->core.parent ; | |
1454 TabsConstraints tab ; | |
1455 Widget oldtop = tw->tabs.topWidget ; | |
1456 | |
1457 if( !XtIsSubclass(w->core.parent, tabsWidgetClass) ) | |
1458 { | |
434 | 1459 char line[256] ; |
1460 sprintf(line, "XawTabsSetTop: widget \"%.64s\" is not the child of a tabs widget.", XtName(w)) ; | |
428 | 1461 XtAppWarning(XtWidgetToApplicationContext(w), line) ; |
1462 return ; | |
1463 } | |
1464 | |
1465 if( callCallbacks ) | |
1466 XtCallCallbackList(w, tw->tabs.popdownCallbacks, | |
434 | 1467 (XtPointer)tw->tabs.topWidget) ; |
428 | 1468 |
1469 if( !XtIsRealized(w) ) { | |
1470 tw->tabs.topWidget = w ; | |
1471 tw->tabs.needs_layout = True ; | |
440 | 1472 tw->tabs.hilight = NULL; /* The highlight tab might disappear. */ |
428 | 1473 return ; |
1474 } | |
1475 | |
1476 XRaiseWindow(XtDisplay(w), XtWindow(w)) ; | |
1477 #ifdef NEED_MOTIF | |
1478 XtVaSetValues(oldtop, XmNtraversalOn, False, 0) ; | |
1479 XtVaSetValues(w, XmNtraversalOn, True, 0) ; | |
1480 #endif | |
1481 | |
1482 tab = (TabsConstraints) w->core.constraints ; | |
440 | 1483 |
1484 /* Unhighlight before we start messing with the stacking order. */ | |
1485 if( tw->tabs.hilight != NULL ) | |
1486 { | |
1487 DrawHighlight(tw, tw->tabs.hilight, True) ; | |
1488 tw->tabs.hilight = NULL; | |
1489 } | |
1490 | |
428 | 1491 if( tab->tabs.row == 0 ) |
1492 { | |
1493 /* Easy case; undraw current top, undraw new top, assign new | |
1494 * top, redraw all borders. | |
1495 * We *could* just erase and execute a full redraw, but I like to | |
1496 * reduce screen flicker. | |
1497 */ | |
1498 UndrawTab(tw, oldtop) ; /* undraw old */ | |
1499 DrawBorder(tw, oldtop, True) ; | |
1500 UndrawTab(tw, w) ; /* undraw new */ | |
1501 DrawBorder(tw, w, True) ; | |
1502 tw->tabs.topWidget = w ; | |
1503 DrawTab(tw, oldtop, True) ; /* redraw old */ | |
1504 DrawTab(tw, w, True) ; /* redraw new */ | |
1505 DrawTabs(tw, False) ; | |
1506 } | |
1507 else | |
1508 { | |
1509 tw->tabs.topWidget = w ; | |
1510 TabsShuffleRows(tw) ; | |
1511 XClearWindow(XtDisplay((Widget)tw), XtWindow((Widget)tw)) ; | |
1512 XtClass(tw)->core_class.expose((Widget)tw,NULL,None) ; | |
1513 } | |
1514 | |
1515 XawTabsSetHighlight((Widget)tw, w) ; | |
1516 | |
1517 if( callCallbacks ) | |
1518 XtCallCallbackList(w, tw->tabs.callbacks, (XtPointer)w) ; | |
1519 } | |
1520 | |
1521 | |
1522 /* Set the top tab, optionally call all callbacks. */ | |
1523 void | |
1524 XawTabsSetHighlight(Widget t, Widget w) | |
1525 { | |
1526 TabsWidget tw = (TabsWidget)t ; | |
1527 | |
1528 if( !XtIsSubclass(t, tabsWidgetClass) ) | |
1529 return ; | |
1530 | |
1531 if( XtIsRealized(t) && w != tw->tabs.hilight ) | |
1532 { | |
1533 if( w != NULL ) | |
1534 DrawHighlight(tw, w, False) ; | |
1535 } | |
1536 | |
1537 tw->tabs.hilight = w ; | |
1538 } | |
1539 | |
1540 | |
1541 | |
1542 | |
1543 /**************************************************************** | |
1544 * | |
1545 * Private Procedures | |
1546 * | |
1547 ****************************************************************/ | |
1548 | |
1549 | |
1550 static void | |
1551 TabsAllocGCs(TabsWidget tw) | |
1552 { | |
1553 TabsAllocFgGC(tw) ; | |
1554 TabsAllocGreyGC(tw) ; | |
1555 tw->tabs.backgroundGC = AllocBackgroundGC((Widget)tw, None) ; | |
1556 tw->tabs.topGC = AllocTopShadowGC((Widget)tw, | |
1557 tw->tabs.top_shadow_contrast, tw->tabs.be_nice_to_cmap) ; | |
1558 tw->tabs.botGC = AllocBotShadowGC((Widget)tw, | |
1559 tw->tabs.bot_shadow_contrast, tw->tabs.be_nice_to_cmap) ; | |
1560 } | |
1561 | |
1562 | |
1563 static void | |
1564 TabsFreeGCs(TabsWidget tw) | |
1565 { | |
1566 Widget w = (Widget) tw; | |
1567 | |
1568 XtReleaseGC(w, tw->tabs.foregroundGC) ; | |
1569 XtReleaseGC(w, tw->tabs.greyGC) ; | |
1570 XtReleaseGC(w, tw->tabs.backgroundGC) ; | |
1571 XtReleaseGC(w, tw->tabs.topGC) ; | |
1572 XtReleaseGC(w, tw->tabs.botGC) ; | |
1573 #ifdef HAVE_XMU | |
1574 XmuReleaseStippledPixmap(XtScreen(w), tw->tabs.grey50) ; | |
1575 #endif | |
1576 } | |
1577 | |
1578 | |
1579 | |
1580 | |
1581 | |
1582 /* Redraw entire Tabs widget */ | |
1583 | |
1584 static void | |
1585 DrawTabs(TabsWidget tw, Bool labels) | |
1586 { | |
1587 Widget *childP ; | |
1588 int i,j ; | |
1589 Dimension s = SHADWID ; | |
1590 Dimension th = tw->tabs.tab_height ; | |
1591 Position y ; | |
1592 TabsConstraints tab ; | |
1593 | |
1594 if( !XtIsRealized((Widget)tw)) | |
1595 return ; | |
442 | 1596 |
428 | 1597 /* draw tabs and frames by row except for the top tab, which |
1598 * is drawn last. (This is inefficiently written, but should not | |
1599 * be too slow as long as there are not a lot of rows.) | |
1600 */ | |
1601 | |
1602 y = tw->tabs.numRows == 1 ? TABDELTA : 0 ; | |
647 | 1603 for(i=0; i < (int) tw->tabs.numRows; ++i, y += th) |
428 | 1604 { |
446 | 1605 for( j=TabsNumChildren (tw), childP=tw->composite.children; |
428 | 1606 --j >= 0; ++childP ) |
446 | 1607 if( TabVisible(*childP) ) |
428 | 1608 { |
1609 tab = (TabsConstraints)(*childP)->core.constraints; | |
1610 if( tab->tabs.row == i && *childP != tw->tabs.topWidget ) | |
1611 DrawTab(tw, *childP, labels) ; | |
1612 } | |
647 | 1613 if( i != (int) tw->tabs.numRows -1 ) |
428 | 1614 DrawTrim(tw, 0,y+th, tw->core.width, th+s, False,False) ; |
1615 } | |
1616 | |
1617 DrawFrame(tw) ; | |
1618 | |
1619 /* and now the top tab */ | |
1620 if( tw->tabs.topWidget != NULL ) | |
1621 DrawTab(tw, tw->tabs.topWidget, labels) ; | |
1622 } | |
1623 | |
1624 | |
1625 | |
1626 /* Draw one tab. Corners are rounded very slightly. */ | |
1627 | |
1628 static void | |
1629 DrawTab(TabsWidget tw, Widget child, Bool labels) | |
1630 { | |
1631 GC gc ; | |
1632 int x,y ; | |
1633 | |
3397 | 1634 if (debug_tabs > 2) fprintf (stderr, "DrawTab called.\n"); |
3094 | 1635 |
428 | 1636 if( !XtIsRealized((Widget)tw)) |
1637 return ; | |
1638 | |
1639 DrawBorder(tw, child, False) ; | |
1640 | |
1641 if( labels ) | |
1642 { | |
1643 TabsConstraints tab = (TabsConstraints)child->core.constraints; | |
1644 Display *dpy = XtDisplay((Widget)tw) ; | |
1645 Window win = XtWindow((Widget)tw) ; | |
1646 String lbl = tab->tabs.label != NULL ? | |
1647 tab->tabs.label : XtName(child) ; | |
3094 | 1648 #ifdef USE_XFT_TABS |
1649 XftColor color; | |
1650 XftColor colorBG; | |
1651 Colormap cmap = tw->core.colormap; | |
1652 Visual *visual; | |
1653 int ignored; | |
428 | 1654 |
3094 | 1655 visual_info_from_widget ((Widget) tw, &visual, &ignored); |
1656 colorBG = xft_convert_color (dpy, cmap, visual, | |
1657 tw->core.background_pixel, 0); | |
1658 #endif | |
1659 | |
1660 if (debug_tabs > 2) | |
1661 fprintf (stderr, "(Re)drawing labels.\n"); | |
1662 | |
1663 if (XtIsSensitive(child)) | |
428 | 1664 { |
3094 | 1665 gc = tw->tabs.foregroundGC; |
1666 #ifdef USE_XFT_TABS | |
1667 color = xft_convert_color (dpy, cmap, visual, | |
1668 tab->tabs.foreground, 0); | |
1669 #else | |
1670 XSetForeground(dpy, gc, tab->tabs.foreground); | |
1671 #endif | |
428 | 1672 } |
1673 else | |
1674 { | |
1675 /* grey pixel allocation deferred until now */ | |
3094 | 1676 if (!tab->tabs.greyAlloc) |
428 | 1677 { |
3094 | 1678 if (tw->tabs.be_nice_to_cmap || tw->core.depth == 1) |
1679 tab->tabs.grey = tab->tabs.foreground; | |
428 | 1680 else |
3094 | 1681 tab->tabs.grey = AllocGreyPixel ((Widget) tw, |
428 | 1682 tab->tabs.foreground, |
1683 tw->core.background_pixel, | |
3094 | 1684 tw->tabs.insensitive_contrast); |
1685 tab->tabs.greyAlloc = True; | |
428 | 1686 } |
3094 | 1687 gc = tw->tabs.greyGC; |
1688 #ifdef USE_XFT_TABS | |
1689 color = xft_convert_color (dpy, cmap, visual, tab->tabs.grey, 0); | |
1690 #else | |
1691 XSetForeground(dpy, gc, tab->tabs.grey); | |
1692 #endif | |
428 | 1693 } |
1694 | |
3094 | 1695 x = tab->tabs.x; |
1696 y = tab->tabs.y; | |
1697 if (child == tw->tabs.topWidget) | |
1698 y -= TABLDELTA; | |
428 | 1699 |
3094 | 1700 if (tab->tabs.left_bitmap != None && tab->tabs.lbm_width > 0) |
428 | 1701 { |
3094 | 1702 if (tab->tabs.lbm_depth == 1) |
428 | 1703 XCopyPlane(dpy, tab->tabs.left_bitmap, win,gc, |
434 | 1704 0,0, tab->tabs.lbm_width, tab->tabs.lbm_height, |
3094 | 1705 x+tab->tabs.lbm_x, y+tab->tabs.lbm_y, 1L); |
428 | 1706 else |
1707 XCopyArea(dpy, tab->tabs.left_bitmap, win,gc, | |
434 | 1708 0,0, tab->tabs.lbm_width, tab->tabs.lbm_height, |
3094 | 1709 x+tab->tabs.lbm_x, y+tab->tabs.lbm_y); |
428 | 1710 } |
1711 | |
3094 | 1712 if (lbl != NULL && |
1713 #ifdef USE_XFT_TABS | |
1714 tw->tabs.renderFont != NULL | |
1715 #else | |
1716 tw->tabs.font != NULL | |
1717 #endif | |
1718 ) | |
1719 { | |
1720 #ifdef USE_XFT_TABS | |
1721 XftDraw *xftDraw = XftDrawCreate (dpy, win, visual, cmap); | |
1722 XftFont *renderFont = tw->tabs.renderFont; | |
1723 XGlyphInfo glyphinfo; | |
1724 XftColor colorDBG; | |
1725 XftColorAllocName (dpy, visual, cmap, "wheat", &colorDBG); | |
3374 | 1726 XftTextExtents8 (dpy, renderFont, (FcChar8 *) lbl, |
1727 (int) strlen (lbl), &glyphinfo); | |
3094 | 1728 /* #### unnecessary? for the moment, give visual extent */ |
1729 /* draw background rect */ | |
1730 if (debug_tabs > 2) | |
1731 { | |
1732 fprintf (stderr, "background color: pixel=%08lx, r=%04x," | |
1733 " g=%04x, b=%04x, alpha=%04x.\n", | |
1734 colorDBG.pixel, colorDBG.color.red, | |
1735 colorDBG.color.green, colorDBG.color.blue, | |
1736 colorDBG.color.alpha); | |
1737 fprintf (stderr, "label geometry: x=%d, y=%d, xOff=%d," | |
1738 " yOff=%d, width=%d, height=%d\n", | |
1739 glyphinfo.x, glyphinfo.y, glyphinfo.xOff, | |
1740 glyphinfo.yOff, glyphinfo.width, glyphinfo.height); | |
1741 } | |
3397 | 1742 if (debug_tabs > 2) |
1743 XftDrawRect (xftDraw, &colorDBG, | |
1744 /* left, top, width, height */ | |
1745 x+tab->tabs.l_x-glyphinfo.x, | |
1746 y+tab->tabs.l_y-glyphinfo.y, | |
1747 glyphinfo.width, glyphinfo.height); | |
1748 | |
3094 | 1749 /* draw text */ |
3397 | 1750 if (debug_tabs > 1) |
3094 | 1751 { |
1752 fprintf (stderr, "label: %s.\n", lbl); | |
1753 fprintf (stderr, "foreground color: pixel=%08lx, r=%04x," | |
1754 " g=%04x, b=%04x, alpha=%04x.\n", | |
1755 color.pixel, color.color.red, color.color.green, | |
1756 color.color.blue, color.color.alpha); | |
1757 fprintf (stderr, "extent: x=%d, y=%d, xOffset=%d," | |
1758 " yOffset=%d, height=%d, width=%d.\n", | |
1759 glyphinfo.x, glyphinfo.y, glyphinfo.xOff, | |
1760 glyphinfo.yOff, glyphinfo.height, glyphinfo.width); | |
3397 | 1761 } |
1762 if (debug_tabs > 0) | |
1763 { | |
1764 FcValue name; | |
1765 FcValue size; | |
1766 FcPatternGet (renderFont->pattern, FC_FAMILY, 0, &name); | |
1767 FcPatternGet (renderFont->pattern, FC_SIZE, 0, &size); | |
3094 | 1768 fprintf (stderr, "font: name=%s-%.1f," |
1769 " height=%d, ascent=%d, descent=%d.\n", | |
1770 name.u.s, size.u.d, renderFont->height, | |
1771 renderFont->ascent, renderFont->descent); | |
1772 } | |
1773 XftDrawString8 (xftDraw, &color, renderFont, | |
1774 x+tab->tabs.l_x, y+tab->tabs.l_y, | |
3374 | 1775 (FcChar8 *) lbl, (int) strlen (lbl)); |
3094 | 1776 XftDrawDestroy (xftDraw); |
1777 #else | |
1778 XDrawString(dpy,win,gc, | |
1779 x+tab->tabs.l_x, y+tab->tabs.l_y, | |
1780 lbl, (int)strlen(lbl)); | |
1781 #endif | |
1782 } | |
428 | 1783 } |
1784 | |
3094 | 1785 if (child == tw->tabs.hilight) |
1786 DrawHighlight(tw, child, False); | |
428 | 1787 } |
1788 | |
1789 | |
1790 /* draw frame all the way around the child windows. */ | |
1791 | |
1792 static void | |
1793 DrawFrame(TabsWidget tw) | |
1794 { | |
1795 GC topgc = tw->tabs.topGC ; | |
1796 GC botgc = tw->tabs.botGC ; | |
1797 Dimension s = SHADWID ; | |
1798 Dimension ch = tw->tabs.child_height ; | |
448 | 1799 if (ch > 0) |
1800 Draw3dBox((Widget)tw, 0,tw->tabs.tab_total, | |
1801 tw->core.width, ch+2*s, s, topgc, botgc) ; | |
1802 else | |
1803 { | |
1804 Widget w = tw->tabs.topWidget ; | |
1805 if (w != NULL) | |
1806 { | |
1807 TabsConstraints tab = (TabsConstraints) w->core.constraints ; | |
1808 Draw3dBox((Widget)tw, 0,tw->core.height - 2*s, | |
1809 tab->tabs.x, 2*s, s, topgc, botgc); | |
1810 Draw3dBox((Widget)tw, tab->tabs.x + tab->tabs.width, | |
1811 tw->core.height - 2*s, | |
1812 tw->core.width - tab->tabs.x - tab->tabs.width, 2*s, s, | |
1813 topgc, botgc); | |
1814 } | |
1815 else | |
1816 Draw3dBox((Widget)tw, 0,tw->core.height - 2*s, | |
1817 tw->core.width, 2*s, s, topgc, botgc) ; | |
1818 } | |
428 | 1819 } |
1820 | |
1821 | |
1822 /* draw trim around a tab or underneath a row of tabs */ | |
1823 | |
1824 static void | |
1825 DrawTrim(TabsWidget tw, /* widget */ | |
1826 int x, /* upper-left corner */ | |
1827 int y, | |
1828 int wid, /* total size */ | |
1829 int hgt, | |
1830 Bool bottom, /* draw bottom? */ | |
1831 Bool undraw) /* undraw all */ | |
1832 { | |
1833 Display *dpy = XtDisplay((Widget)tw) ; | |
1834 Window win = XtWindow((Widget)tw) ; | |
1835 GC bggc = tw->tabs.backgroundGC ; | |
1836 GC topgc = undraw ? bggc : tw->tabs.topGC ; | |
1837 GC botgc = undraw ? bggc : tw->tabs.botGC ; | |
1838 if( bottom ) | |
1839 XDrawLine(dpy,win,bggc, x,y+hgt-1, x+wid-1,y+hgt-1) ; /* bottom */ | |
1840 XDrawLine(dpy,win,topgc, x,y+2, x,y+hgt-2) ; /* left */ | |
1841 XDrawPoint(dpy,win,topgc, x+1,y+1) ; /* corner */ | |
1842 XDrawLine(dpy,win,topgc, x+2,y, x+wid-3,y) ; /* top */ | |
1843 XDrawLine(dpy,win,botgc, x+wid-2,y+1, x+wid-2,y+hgt-2) ; /* right */ | |
1844 XDrawLine(dpy,win,botgc, x+wid-1,y+2, x+wid-1,y+hgt-2) ; /* right */ | |
1845 } | |
1846 | |
1847 | |
1848 /* Draw one tab border. */ | |
1849 | |
1850 static void | |
1851 DrawBorder(TabsWidget tw, Widget child, Bool undraw) | |
1852 { | |
1853 TabsConstraints tab = (TabsConstraints)child->core.constraints; | |
1854 Position x = tab->tabs.x ; | |
1855 Position y = tab->tabs.y ; | |
1856 Dimension twid = tab->tabs.width ; | |
1857 Dimension thgt = tw->tabs.tab_height ; | |
1858 | |
1859 /* top tab requires a little special attention; it overlaps | |
1860 * neighboring tabs slightly, so the background must be cleared | |
1861 * in the region of the overlap to partially erase those neighbors. | |
1862 * TODO: is this worth doing with regions instead? | |
1863 */ | |
1864 if( child == tw->tabs.topWidget ) | |
1865 { | |
1866 Display *dpy = XtDisplay((Widget)tw) ; | |
1867 Window win = XtWindow((Widget)tw) ; | |
1868 GC bggc = tw->tabs.backgroundGC ; | |
1869 XRectangle rects[3] ; | |
1870 x -= TABDELTA ; | |
1871 y -= TABDELTA ; | |
1872 twid += TABDELTA*2 ; | |
1873 thgt += TABDELTA ; | |
1874 AddRect(0, x,y+1,twid,TABDELTA) ; | |
1875 AddRect(1, x+1,y,TABDELTA,thgt) ; | |
1876 AddRect(2, x+twid-TABDELTA-1,y,TABDELTA,thgt) ; | |
1877 XFillRectangles(dpy,win,bggc, rects, 3) ; | |
1878 } | |
1879 | |
1880 DrawTrim(tw, x,y,twid,thgt+1, child == tw->tabs.topWidget, undraw) ; | |
1881 } | |
1882 | |
1883 | |
1884 /* Draw highlight around tab that has focus */ | |
1885 | |
1886 static void | |
1887 DrawHighlight(TabsWidget tw, Widget child, Bool undraw) | |
1888 { | |
1889 TabsConstraints tab = (TabsConstraints)child->core.constraints; | |
1890 Display *dpy = XtDisplay((Widget)tw) ; | |
1891 Window win = XtWindow((Widget)tw) ; | |
1892 GC gc ; | |
1893 Position x = tab->tabs.x ; | |
1894 Position y = tab->tabs.y ; | |
1895 Dimension wid = tab->tabs.width ; | |
1896 Dimension hgt = tw->tabs.tab_height ; | |
1897 XPoint points[6] ; | |
1898 | |
1899 /* top tab does not have a highlight */ | |
1900 | |
1901 if( child == tw->tabs.topWidget ) | |
1902 return ; | |
1903 | |
1904 if( undraw ) | |
1905 gc = tw->tabs.backgroundGC ; | |
1906 | |
1907 else if( XtIsSensitive(child) ) | |
1908 { | |
1909 gc = tw->tabs.foregroundGC ; | |
1910 XSetForeground(dpy, gc, tab->tabs.foreground) ; | |
1911 } | |
1912 else | |
1913 { | |
1914 gc = tw->tabs.greyGC ; | |
1915 XSetForeground(dpy, gc, tab->tabs.grey) ; | |
1916 } | |
1917 | |
1918 points[0].x = x+1 ; points[0].y = y+hgt-1 ; | |
1919 points[1].x = x+1 ; points[1].y = y+2 ; | |
1920 points[2].x = x+2 ; points[2].y = y+1 ; | |
1921 points[3].x = x+wid-4 ; points[3].y = y+1 ; | |
1922 points[4].x = x+wid-3 ; points[4].y = y+2 ; | |
1923 points[5].x = x+wid-3 ; points[5].y = y+hgt-1 ; | |
1924 | |
1925 XDrawLines(dpy,win,gc, points,6, CoordModeOrigin) ; | |
1926 } | |
1927 | |
1928 | |
1929 /* Undraw one tab interior */ | |
1930 | |
1931 static void | |
1932 UndrawTab(TabsWidget tw, Widget child) | |
1933 { | |
1934 TabsConstraints tab = (TabsConstraints)child->core.constraints; | |
1935 Position x = tab->tabs.x ; | |
1936 Position y = tab->tabs.y ; | |
1937 Dimension twid = tab->tabs.width ; | |
1938 Dimension thgt = tw->tabs.tab_height ; | |
1939 Display *dpy = XtDisplay((Widget)tw) ; | |
1940 Window win = XtWindow((Widget)tw) ; | |
1941 GC bggc = tw->tabs.backgroundGC ; | |
1942 | |
1943 XFillRectangle(dpy,win,bggc, x,y, twid,thgt) ; | |
1944 } | |
1945 | |
1946 | |
1947 | |
1948 | |
1949 | |
1950 /* GEOMETRY UTILITIES */ | |
1951 | |
434 | 1952 /* Overview: |
1953 * | |
1954 * MaxChild(): ask all children (except possibly one) their | |
1955 * preferred sizes, set max_cw, max_ch accordingly. | |
1956 * | |
1957 * GetPreferredSizes(): ask all children their preferred sizes, | |
1958 * set max_cw, max_ch accordingly. | |
1959 * | |
1960 * PreferredSize(): given max_cw, max_ch, return tabs widget | |
1961 * preferred size. Iterate with other widths in order to get | |
1962 * a reasonable aspect ratio. | |
1963 * | |
1964 * PreferredSize2(): Given child dimensions, return Tabs | |
1965 * widget dimensions. | |
1966 * | |
1967 * PreferredSize3(): Same, except given child dimensions plus | |
1968 * shadow. | |
1969 */ | |
428 | 1970 |
434 | 1971 |
1972 /* Compute the width of one child's tab. Positions will be computed | |
428 | 1973 * elsewhere. |
1974 * | |
1975 * height: font height + vertical_space*2 + shadowWid*2 | |
1976 * width: string width + horizontal_space*2 + shadowWid*2 | |
1977 * | |
1978 * All tabs are the same height, so that is computed elsewhere. | |
1979 */ | |
1980 | |
1981 static void | |
1982 TabWidth(Widget w) | |
1983 { | |
1984 TabsConstraints tab = (TabsConstraints) w->core.constraints ; | |
1985 TabsWidget tw = (TabsWidget)XtParent(w) ; | |
1986 String lbl = tab->tabs.label != NULL ? | |
3094 | 1987 tab->tabs.label : XtName(w); |
1988 #ifdef USE_XFT_TABS | |
1989 XftFont *font = tw->tabs.renderFont; | |
1990 #else | |
1991 XFontStruct *font = tw->tabs.font; | |
1992 #endif | |
1993 int iw = tw->tabs.internalWidth; | |
428 | 1994 |
1995 tab->tabs.width = iw + SHADWID*2 ; | |
1996 tab->tabs.l_x = tab->tabs.lbm_x = SHADWID + iw ; | |
1997 | |
1998 if( tab->tabs.left_bitmap != None ) | |
1999 { | |
2000 tab->tabs.width += tab->tabs.lbm_width + iw ; | |
2001 tab->tabs.l_x += tab->tabs.lbm_width + iw ; | |
2002 tab->tabs.lbm_y = (tw->tabs.tab_height - tab->tabs.lbm_height)/2 ; | |
2003 } | |
2004 | |
2005 if( lbl != NULL && font != NULL ) | |
2006 { | |
3094 | 2007 #ifdef USE_XFT_TABS |
2008 tab->tabs.width += x_xft_text_width (XtDisplay(tw), font, | |
3374 | 2009 (FcChar8 *) lbl, |
2010 (int)strlen(lbl)) + iw; | |
3094 | 2011 tab->tabs.l_y = (tw->tabs.tab_height |
2012 + tw->tabs.renderFont->ascent | |
2013 /* #### how can this subtraction be correct? */ | |
2014 - tw->tabs.renderFont->descent)/2; | |
2015 if (debug_tabs > 2) | |
2016 fprintf (stderr, "tab: height=%d, width=%d, baseline=%d.\n", | |
2017 tw->tabs.tab_height, tab->tabs.width, tab->tabs.l_y); | |
2018 if (debug_tabs > 1) | |
2019 fprintf (stderr, "font: height=%d, ascent=%d, descent=%d.\n", | |
2020 tw->tabs.renderFont->height, | |
2021 tw->tabs.renderFont->ascent, | |
2022 tw->tabs.renderFont->descent); | |
2023 #else | |
2024 tab->tabs.width += XTextWidth (font, lbl, (int)strlen(lbl)) + iw; | |
428 | 2025 tab->tabs.l_y = (tw->tabs.tab_height + |
434 | 2026 tw->tabs.font->max_bounds.ascent - |
3094 | 2027 tw->tabs.font->max_bounds.descent)/2; |
2028 #endif | |
428 | 2029 } |
2030 } | |
2031 | |
2032 | |
2033 | |
2034 /* Lay out tabs to fit in given width. Compute x,y position and | |
2035 * row number for each tab. Return number of rows and total height | |
2036 * required by all tabs. If there is only one row, add TABDELTA | |
2037 * height to the total. Rows are assigned bottom to top. | |
2038 * | |
2039 * Tabs are indented from the edges by INDENT. | |
2040 * | |
2041 * TODO: if they require more than two rows and the total height:width | |
2042 * ratio is more than 2:1, then try something else. | |
3094 | 2043 * Gaak! This is actually already done in PreferredSize()! |
2044 * | |
2045 * TODO SOONER: for reasons unclear, some applications (specifically | |
2046 * XEmacs) give a nominal geometry (in the core record) which doesn't | |
2047 * make much sense (eg, may be smaller than some of the tab children). | |
2048 * This results in bizarre values for DISPLAY_ROWS and REPLY_HEIGHT. | |
2049 * Specify a way to say "tell me what you really want" (eg, with WID | |
2050 * and/or HGT == 0 or == Dimension_MAX), and use it where appropriate. | |
2051 * LATE-BREAKING LOSE: This happens in PreferredSize(), not XEmacs! | |
2052 * | |
2053 * TODO EVEN SOONER: some applications lay out the tab control by | |
2054 * repeatedly querying until a fixed width and height has been filled | |
2055 * by the tabs (XEmacs). There should be an API to cache this? | |
428 | 2056 */ |
2057 | |
2058 static int | |
448 | 2059 TabLayout(TabsWidget tw, |
3094 | 2060 Dimension wid, /* if 0, use core.width as guess */ |
2061 Dimension hgt, /* if 0, use core.height as guess */ | |
448 | 2062 Dimension *reply_height, Bool query_only) |
428 | 2063 { |
446 | 2064 int i, row, done = 0, display_rows = 0 ; |
428 | 2065 int num_children = tw->composite.num_children ; |
2066 Widget *childP ; | |
2067 Dimension w ; | |
3094 | 2068 Position x,y ; /* #### gaak, these are dimensions! */ |
428 | 2069 TabsConstraints tab ; |
2070 | |
2071 /* Algorithm: loop through children, assign X positions. If a tab | |
2072 * would extend beyond the right edge, start a new row. After all | |
2073 * rows are assigned, make a second pass and assign Y positions. | |
2074 */ | |
2075 | |
2076 if( num_children > 0 ) | |
2077 { | |
2078 /* Loop through the tabs and see how much space they need. */ | |
2079 | |
2080 row = 0 ; | |
2081 x = INDENT ; | |
2082 y = 0 ; | |
3094 | 2083 /* If wid or hgt is 0, we want to guess our own dimensions. |
2084 Currently the guessing functions are broken.... | |
2085 #### When PreferredSize*() get fixed, fix this too. */ | |
3397 | 2086 if (debug_tabs > 1) |
3094 | 2087 fprintf (stderr, "arg=%d,", wid); |
2088 wid = (wid ? wid : tw->core.width) - INDENT ; | |
2089 hgt = hgt ? hgt : tw->core.height; | |
3397 | 2090 if (debug_tabs > 1) |
3094 | 2091 fprintf (stderr, "wid=%d: x,w,y=", wid); |
428 | 2092 for(i=num_children, childP=tw->composite.children; --i >= 0; ++childP) |
2093 if( XtIsManaged(*childP) ) | |
2094 { | |
2095 tab = (TabsConstraints) (*childP)->core.constraints ; | |
2096 w = tab->tabs.width ; | |
446 | 2097 |
3397 | 2098 if (debug_tabs > 1) |
3094 | 2099 fprintf (stderr, "%d,%d,%d;", x, w, y); |
428 | 2100 if( x + w > wid ) { /* new row */ |
3094 | 2101 /* #### algorithm is not robust to wid < child's width */ |
2102 ++row; | |
2103 x = INDENT ; | |
2104 y += tw->tabs.tab_height ; | |
2105 if (y > hgt && !done) | |
446 | 2106 { |
2107 display_rows = row; | |
2108 done = 1; | |
2109 } | |
428 | 2110 } |
2111 if( !query_only ) { | |
2112 tab->tabs.x = x ; | |
2113 tab->tabs.y = y ; | |
2114 tab->tabs.row = row ; | |
2115 } | |
2116 x += w + SPACING ; | |
446 | 2117 if (!query_only && !done) |
2118 tab->tabs.visible = 1; | |
2119 | |
428 | 2120 } |
3397 | 2121 if (debug_tabs > 1) |
3094 | 2122 fprintf (stderr, "\n"); |
442 | 2123 /* If there was only one row, increase the height by TABDELTA */ |
446 | 2124 if( ++display_rows == 1 ) |
428 | 2125 { |
2126 y = TABDELTA ; | |
2127 if( !query_only ) | |
2128 for(i=num_children, childP=tw->composite.children; | |
2129 --i >= 0 ; ++childP) | |
2130 if( XtIsManaged(*childP) ) | |
2131 { | |
2132 tab = (TabsConstraints) (*childP)->core.constraints ; | |
2133 tab->tabs.y = y ; | |
2134 } | |
2135 } | |
3094 | 2136 row++; |
428 | 2137 y += tw->tabs.tab_height ; |
2138 } | |
2139 else | |
446 | 2140 display_rows = row = y = 0 ; |
428 | 2141 |
2142 if( !query_only ) { | |
2143 tw->tabs.tab_total = y ; | |
446 | 2144 tw->tabs.numRows = display_rows ; |
2145 tw->tabs.realRows = row; | |
428 | 2146 } |
2147 | |
3397 | 2148 if (debug_tabs > 1 && (row > 1 || display_rows > 1)) |
3094 | 2149 fprintf (stderr, "tab: %d display rows, #children = %d," |
2150 " total height %d, total rows %d%s.\n", | |
2151 display_rows, num_children, y, row, | |
2152 query_only ? " (query)" : ""); | |
2153 | |
428 | 2154 if( reply_height != NULL ) |
2155 *reply_height = y ; | |
2156 | |
446 | 2157 return display_rows ; |
428 | 2158 } |
2159 | |
2160 | |
2161 | |
2162 /* Find max preferred child size. Returned sizes include child | |
434 | 2163 * border widths. |
428 | 2164 */ |
2165 | |
2166 static void | |
2167 GetPreferredSizes(TabsWidget tw) | |
2168 { | |
434 | 2169 MaxChild(tw, NULL, 0,0) ; |
428 | 2170 } |
2171 | |
2172 | |
2173 | |
3094 | 2174 /* Find max preferred child size and store in control widget. |
2175 * If except is non-null, don't ask that one. | |
434 | 2176 */ |
428 | 2177 |
2178 static void | |
434 | 2179 MaxChild(TabsWidget tw, Widget except, Dimension cw, Dimension ch) |
428 | 2180 { |
434 | 2181 int i ; |
2182 Widget *childP = tw->composite.children ; | |
2183 XtWidgetGeometry preferred ; | |
428 | 2184 |
2185 for(i=tw->composite.num_children; --i >=0; ++childP) | |
448 | 2186 if( TabVisible (*childP) /*XtIsManaged(*childP)*/ && *childP != except ) |
428 | 2187 { |
434 | 2188 (void) XtQueryGeometry(*childP, NULL, &preferred) ; |
2189 cw = Max(cw, preferred.width + preferred.border_width * 2 ) ; | |
2190 ch = Max(ch, preferred.height + preferred.border_width * 2 ) ; | |
428 | 2191 } |
2192 | |
2193 tw->tabs.max_cw = cw ; | |
2194 tw->tabs.max_ch = ch ; | |
2195 } | |
2196 | |
2197 | |
2198 | |
2199 /* rotate row numbers to bring current widget to bottom row, | |
2200 * compute y positions for all tabs | |
2201 */ | |
2202 | |
2203 static void | |
2204 TabsShuffleRows(TabsWidget tw) | |
2205 { | |
2206 TabsConstraints tab ; | |
2207 int move ; | |
446 | 2208 int real_rows, display_rows ; |
428 | 2209 Widget *childP ; |
2210 Dimension th = tw->tabs.tab_height ; | |
2211 Position bottom ; | |
2212 int i ; | |
2213 | |
2214 /* There must be a top widget. If not, assign one. */ | |
2215 if( tw->tabs.topWidget == NULL && tw->composite.children != NULL ) | |
446 | 2216 for(i=TabsNumChildren (tw), childP=tw->composite.children; |
428 | 2217 --i >= 0; |
2218 ++childP) | |
2219 if( XtIsManaged(*childP) ) { | |
2220 tw->tabs.topWidget = *childP ; | |
2221 break ; | |
2222 } | |
2223 | |
2224 if( tw->tabs.topWidget != NULL ) | |
2225 { | |
446 | 2226 display_rows = tw->tabs.numRows ; |
2227 real_rows = tw->tabs.realRows ; | |
448 | 2228 assert( display_rows <= real_rows ) ; |
428 | 2229 |
446 | 2230 if( real_rows > 1 ) |
428 | 2231 { |
2232 tab = (TabsConstraints) tw->tabs.topWidget->core.constraints ; | |
2233 assert( tab != NULL ) ; | |
2234 | |
446 | 2235 /* How far to move top row. The selected tab must be on |
2236 the bottom row of the *visible* rows. */ | |
2237 move = (real_rows + 1 - display_rows) - tab->tabs.row ; | |
2238 if (move < 0) | |
2239 move = real_rows - move; | |
428 | 2240 bottom = tw->tabs.tab_total - th ; |
2241 | |
446 | 2242 for(i=tw->composite.num_children, childP=tw->composite.children; |
428 | 2243 --i >= 0; |
2244 ++childP) | |
2245 if( XtIsManaged(*childP) ) | |
2246 { | |
2247 tab = (TabsConstraints) (*childP)->core.constraints ; | |
446 | 2248 tab->tabs.row = (tab->tabs.row + move) % real_rows ; |
428 | 2249 tab->tabs.y = bottom - tab->tabs.row * th ; |
446 | 2250 tab->tabs.visible = (tab->tabs.row < display_rows); |
428 | 2251 } |
2252 } | |
2253 } | |
2254 } | |
2255 | |
2256 | |
434 | 2257 /* Find preferred size. Ask children, find size of largest, |
428 | 2258 * add room for tabs & return. This can get a little involved, |
2259 * as we don't want to have too many rows of tabs; we may widen | |
2260 * the widget to reduce # of rows. | |
434 | 2261 * |
2262 * This function requires that max_cw, max_ch already be set. | |
428 | 2263 */ |
2264 static int | |
2265 PreferredSize( | |
2266 TabsWidget tw, | |
2267 Dimension *reply_width, /* total widget size */ | |
2268 Dimension *reply_height, | |
2269 Dimension *reply_cw, /* child widget size */ | |
2270 Dimension *reply_ch) | |
2271 { | |
2272 Dimension cw,ch ; /* child width, height */ | |
2273 Dimension wid,hgt ; | |
2274 Dimension rwid,rhgt ; | |
2275 int nrow ; | |
2276 | |
2277 wid = cw = tw->tabs.max_cw ; | |
2278 hgt = ch = tw->tabs.max_ch ; | |
2279 | |
2280 nrow = PreferredSize2(tw, wid,hgt, &rwid, &rhgt) ; | |
2281 | |
2282 /* Check for absurd results (more than 2 rows, high aspect | |
2283 * ratio). Try wider size if needed. | |
2284 * TODO: make sure this terminates. | |
2285 */ | |
2286 | |
2287 if( nrow > 2 && rhgt > rwid ) | |
2288 { | |
2289 Dimension w0, w1 ; | |
434 | 2290 int maxloop = 20 ; |
428 | 2291 |
2292 /* step 1: start doubling size until it's too big */ | |
2293 do { | |
2294 w0 = wid ; | |
2295 wid = Max(wid*2, wid+20) ; | |
2296 nrow = PreferredSize2(tw, wid,hgt, &rwid,&rhgt) ; | |
2297 } while( nrow > 2 && rhgt > rwid ) ; | |
2298 w1 = wid ; | |
2299 | |
2300 /* step 2: use Newton's method to find ideal size. Stop within | |
2301 * 8 pixels. | |
2302 */ | |
434 | 2303 while( --maxloop > 0 && w1 > w0 + 8 ) |
428 | 2304 { |
2305 wid = (w0+w1)/2 ; | |
2306 nrow = PreferredSize2(tw, wid,hgt, &rwid,&rhgt) ; | |
2307 if( nrow > 2 && rhgt > rwid ) | |
2308 w0 = wid ; | |
2309 else | |
2310 w1 = wid ; | |
2311 } | |
2312 wid = w1 ; | |
2313 } | |
2314 | |
2315 *reply_width = rwid ; | |
2316 *reply_height = rhgt ; | |
2317 if( reply_cw != NULL ) *reply_cw = cw ; | |
2318 if( reply_ch != NULL ) *reply_ch = ch ; | |
2319 return nrow ; | |
2320 } | |
2321 | |
2322 | |
2323 /* Find preferred size, given size of children. */ | |
2324 | |
2325 static int | |
2326 PreferredSize2( | |
2327 TabsWidget tw, | |
448 | 2328 Dimension cw, /* child width, height */ |
2329 Dimension ch, | |
428 | 2330 Dimension *reply_width, /* total widget size */ |
2331 Dimension *reply_height) | |
2332 { | |
2333 Dimension s = SHADWID ; | |
448 | 2334 int ret; |
428 | 2335 |
2336 /* make room for shadow frame */ | |
2337 cw += s*2 ; | |
2338 ch += s*2 ; | |
2339 | |
448 | 2340 ret = PreferredSize3(tw, cw, ch, reply_width, reply_height) ; |
2341 | |
2342 assert (*reply_width > 0 && *reply_height > 0); | |
2343 return ret; | |
428 | 2344 } |
2345 | |
2346 | |
2347 /* Find preferred size, given size of children+shadow. */ | |
2348 | |
2349 static int | |
2350 PreferredSize3( | |
2351 TabsWidget tw, | |
448 | 2352 Dimension wid, /* child width, height */ |
2353 Dimension hgt, | |
428 | 2354 Dimension *reply_width, /* total widget size */ |
2355 Dimension *reply_height) | |
2356 { | |
2357 Dimension th ; /* space used by tabs */ | |
2358 int nrows ; | |
2359 | |
2360 if( tw->composite.num_children > 0 ) | |
3094 | 2361 /* used to be wid, hgt not 0, 0 but that's obviously wrong |
2362 since TabLayout wants dimensions of control parent but | |
2363 wid, hgt are dimensions of some child */ | |
2364 nrows = TabLayout(tw, 0, 0, &th, True) ; | |
428 | 2365 else { |
2366 th = 0 ; | |
2367 nrows = 0 ; | |
2368 } | |
2369 | |
2370 *reply_width = Max(wid, MIN_WID) ; | |
2371 *reply_height = Max(th+hgt, MIN_HGT) ; | |
2372 | |
2373 return nrows ; | |
2374 } | |
2375 | |
2376 | |
2377 static void | |
2378 MakeSizeRequest(TabsWidget tw) | |
2379 { | |
2380 Widget w = (Widget)tw ; | |
2381 XtWidgetGeometry request, reply ; | |
2382 XtGeometryResult result ; | |
2383 Dimension cw,ch ; | |
2384 | |
2385 request.request_mode = CWWidth | CWHeight ; | |
2386 PreferredSize(tw, &request.width, &request.height, &cw, &ch) ; | |
2387 | |
2388 if( request.width == tw->core.width && | |
2389 request.height == tw->core.height ) | |
2390 return ; | |
2391 | |
2392 result = XtMakeGeometryRequest(w, &request, &reply) ; | |
2393 | |
2394 if( result == XtGeometryAlmost ) | |
2395 { | |
2396 /* Bugger. Didn't get what we want, but were offered a | |
2397 * compromise. If the width was too small, recompute | |
2398 * based on the too-small width and try again. | |
2399 * If the height was too small, make a wild-ass guess | |
2400 * at a wider width and try again. | |
2401 */ | |
2402 | |
2403 if( reply.width < request.width && reply.height >= request.height ) | |
2404 { | |
2405 Dimension s = SHADWID ; | |
2406 ch += s*2 ; | |
2407 PreferredSize3(tw, reply.width,ch, &request.width, &request.height); | |
2408 result = XtMakeGeometryRequest(w, &request, &reply) ; | |
2409 if( result == XtGeometryAlmost ) | |
2410 (void) XtMakeGeometryRequest(w, &reply, NULL) ; | |
2411 } | |
2412 | |
2413 else | |
2414 (void) XtMakeGeometryRequest(w, &reply, NULL) ; | |
2415 } | |
2416 } | |
2417 | |
2418 | |
2419 static void | |
2420 getBitmapInfo(TabsWidget tw, TabsConstraints tab) | |
2421 { | |
2422 Window root ; | |
2423 int x,y ; | |
2424 unsigned int bw ; | |
2425 | |
2426 if( tab->tabs.left_bitmap == None || | |
2427 !XGetGeometry(XtDisplay(tw), tab->tabs.left_bitmap, &root, &x, &y, | |
434 | 2428 &tab->tabs.lbm_width, &tab->tabs.lbm_height, |
428 | 2429 &bw, &tab->tabs.lbm_depth) ) |
2430 tab->tabs.lbm_width = tab->tabs.lbm_height = 0 ; | |
2431 } | |
2432 | |
2433 | |
2434 | |
2435 | |
2436 /* Code copied & modified from Gcs.c. This version has dynamic | |
2437 * foreground. | |
2438 */ | |
2439 | |
2440 static void | |
2441 TabsAllocFgGC(TabsWidget tw) | |
2442 { | |
2443 Widget w = (Widget) tw; | |
2444 XGCValues values ; | |
2445 | |
3094 | 2446 values.background = tw->core.background_pixel; |
2447 values.font = | |
2448 #ifdef USE_XFT_TABS | |
2449 None; | |
2450 #else | |
2451 tw->tabs.font->fid; | |
2452 #endif | |
2453 values.line_style = LineOnOffDash; | |
2454 values.line_style = LineSolid; | |
428 | 2455 |
2456 tw->tabs.foregroundGC = | |
2457 XtAllocateGC(w, w->core.depth, | |
3094 | 2458 #ifndef USE_XFT_TABS |
2459 GCFont| | |
2460 #endif | |
2461 GCBackground|GCLineStyle, | |
2462 &values, | |
2463 GCForeground, | |
2464 #ifdef USE_XFT_TABS | |
2465 GCFont| | |
2466 #endif | |
2467 GCSubwindowMode|GCGraphicsExposures|GCDashOffset| | |
2468 GCDashList|GCArcMode); | |
428 | 2469 } |
2470 | |
2471 static void | |
2472 TabsAllocGreyGC(TabsWidget tw) | |
2473 { | |
2474 Widget w = (Widget) tw; | |
2475 XGCValues values ; | |
2476 | |
3094 | 2477 values.background = tw->core.background_pixel; |
2478 values.font = | |
2479 #ifdef USE_XFT_TABS | |
2480 None; | |
2481 #else | |
2482 tw->tabs.font->fid; | |
2483 #endif | |
428 | 2484 #ifdef HAVE_XMU |
3094 | 2485 if (tw->tabs.be_nice_to_cmap || w->core.depth == 1) |
428 | 2486 { |
3094 | 2487 values.fill_style = FillStippled; |
428 | 2488 tw->tabs.grey50 = |
3094 | 2489 values.stipple = XmuCreateStippledPixmap(XtScreen(w), 1L, 0L, 1); |
428 | 2490 |
2491 tw->tabs.greyGC = | |
2492 XtAllocateGC(w, w->core.depth, | |
3094 | 2493 #ifndef USE_XFT_TABS |
2494 GCFont| | |
2495 #endif | |
2496 GCBackground|GCStipple|GCFillStyle, &values, | |
428 | 2497 GCForeground, |
3094 | 2498 #ifdef USE_XFT_TABS |
2499 GCFont| | |
2500 #endif | |
428 | 2501 GCSubwindowMode|GCGraphicsExposures|GCDashOffset| |
3094 | 2502 GCDashList|GCArcMode); |
428 | 2503 } |
2504 else | |
2505 #endif | |
2506 { | |
2507 tw->tabs.greyGC = | |
2508 XtAllocateGC(w, w->core.depth, | |
3094 | 2509 #ifdef USE_XFT_TABS |
2510 0L, | |
2511 #else | |
2512 GCFont, | |
2513 #endif | |
2514 &values, | |
428 | 2515 GCForeground, |
3094 | 2516 #ifdef USE_XFT_TABS |
2517 GCFont| | |
2518 #endif | |
428 | 2519 GCBackground|GCSubwindowMode|GCGraphicsExposures|GCDashOffset| |
3094 | 2520 GCDashList|GCArcMode); |
428 | 2521 } |
2522 } |