Mercurial > hg > xemacs-beta
comparison lwlib/xlwtabs.c @ 5118:e0db3c197671 ben-lisp-object
merge up to latest default branch, doesn't compile yet
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Sat, 26 Dec 2009 21:18:49 -0600 |
parents | 5460287a3327 |
children | a6c778975d7d |
comparison
equal
deleted
inserted
replaced
5117:3742ea8250b5 | 5118:e0db3c197671 |
---|---|
15 | 15 |
16 You should have received a copy of the GNU General Public License | 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 | 17 along with XEmacs; see the file COPYING. If not, write to |
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
19 Boston, MA 02111-1307, USA. */ | 19 Boston, MA 02111-1307, USA. */ |
20 | |
21 /* Synched up with: Tabs.c 1.27. | |
22 | |
23 #### This file contains essential XEmacs related fixes to the original | |
24 verison of the Tabs widget. Be VERY careful about syncing if you ever | |
25 update to a more recent version. In general this is probably now a | |
26 bad idea. */ | |
27 | 20 |
28 /* | 21 /* |
29 * Tabs.c - Index Tabs composite widget | 22 * Tabs.c - Index Tabs composite widget |
30 * | 23 * |
31 * Author: Edward A. Falk | 24 * Author: Edward A. Falk |
54 * The tabs overlap the frame and each other vertically by the shadow | 47 * The tabs overlap the frame and each other vertically by the shadow |
55 * width, so that when the topmost tab is drawn, it obliterates part of | 48 * width, so that when the topmost tab is drawn, it obliterates part of |
56 * the frame. | 49 * the frame. |
57 */ | 50 */ |
58 | 51 |
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 | |
59 /* | 64 /* |
60 * TODO: min child height = tab height | 65 * TODO: min child height = tab height |
61 */ | 66 */ |
62 | 67 |
63 #include <config.h> | 68 #include <config.h> |
64 #include <stdio.h> | 69 #include <stdio.h> |
65 | 70 |
66 #include <X11/Xlib.h> | 71 #include <X11/Xlib.h> |
67 #include <X11/IntrinsicP.h> | 72 #include <X11/IntrinsicP.h> |
68 #include <X11/StringDefs.h> | 73 #include <X11/StringDefs.h> |
69 | 74 #include <X11/Xmu/Drawing.h> |
75 #include <X11/Xmu/Misc.h> | |
76 | |
77 /* #### This may be risky, lwlib-internal.h redefines abort() */ | |
78 #include "lwlib-fonts.h" | |
79 #include "lwlib-colors.h" | |
70 #include "lwlib-internal.h" | 80 #include "lwlib-internal.h" |
71 #include "../src/xmu.h" | |
72 #include "xlwtabsP.h" | 81 #include "xlwtabsP.h" |
73 #include "xlwgcs.h" | 82 #include "xlwgcs.h" |
74 | 83 |
84 #define XFT_USE_HEIGHT_NOT_ASCENT_DESCENT 0 | |
85 | |
86 /* #### These should probably be resources. */ | |
75 #define MIN_WID 10 | 87 #define MIN_WID 10 |
76 #define MIN_HGT 10 | 88 #define MIN_HGT 10 |
77 #define INDENT 3 /* tabs indented from edge by this much */ | 89 #define INDENT 3 /* tabs indented from edge by this much */ |
78 #define SPACING 0 /* distance between tabs */ | 90 #define SPACING 0 /* distance between tabs */ |
79 #define SHADWID 1 /* default shadow width */ | 91 #define SHADWID 1 /* default shadow width */ |
129 <Key>KP_Down: highlight(down) \n\ | 141 <Key>KP_Down: highlight(down) \n\ |
130 <Key> : page(select) \n\ | 142 <Key> : page(select) \n\ |
131 " ; | 143 " ; |
132 static XtAccelerators defaultAccelerators ; /* #### Never used */ | 144 static XtAccelerators defaultAccelerators ; /* #### Never used */ |
133 | 145 |
146 static XtResource resources[] = { | |
134 #define offset(field) XtOffsetOf(TabsRec, tabs.field) | 147 #define offset(field) XtOffsetOf(TabsRec, tabs.field) |
135 static XtResource resources[] = { | 148 #define res(name,_class,intrepr,type,member,extrepr,value) \ |
136 | 149 Xt_RESOURCE (name, _class, intrepr, type, offset(member), extrepr, value) |
137 {XtNselectInsensitive, XtCSelectInsensitive, XtRBoolean, sizeof(Boolean), | 150 |
138 offset(selectInsensitive), XtRImmediate, (XtPointer) True}, | 151 res (XtNselectInsensitive, XtCSelectInsensitive, XtRBoolean, Boolean, |
139 {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *), | 152 selectInsensitive, XtRImmediate, True), |
140 offset(font), XtRString, (XtPointer) XtDefaultFont}, | 153 res (XtNfont, XtCFont, XtRFontStruct, XFontStruct *, |
141 {XtNinternalWidth, XtCWidth, XtRDimension, sizeof(Dimension), | 154 font, XtRString, XtDefaultFont), |
142 offset(internalWidth), XtRImmediate, (XtPointer)4 }, | 155 #ifdef USE_XFT_TABS |
143 {XtNinternalHeight, XtCHeight, XtRDimension, sizeof(Dimension), | 156 /* #### Maybe use "-*-helvetica-bold-r-*-*-*-120-*-*-*-*-iso8859-1" here? |
144 offset(internalHeight), XtRImmediate, (XtPointer)4 }, | 157 or XtDefaultFont? */ |
145 {XtNborderWidth, XtCBorderWidth, XtRDimension, sizeof(Dimension), | 158 res (XtNfcFontName, XtCFcFontName, XtRString, String, |
146 XtOffsetOf(RectObjRec,rectangle.border_width), XtRImmediate, (XtPointer)0}, | 159 fcFontName, XtRString, NULL), |
147 {XtNtopWidget, XtCTopWidget, XtRWidget, sizeof(Widget), | 160 /* #### This needs to be fixed to give a proper type and converter for |
148 offset(topWidget), XtRImmediate, NULL}, | 161 XftFonts. See also xlwmenu.c. */ |
149 {XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer), | 162 res (XtNxftFont, XtCXftFont, XtRString, String, |
150 offset(callbacks), XtRCallback, NULL}, | 163 xftFontName, XtRString, "Helvetica-12"), |
151 {XtNpopdownCallback, XtCCallback, XtRCallback, sizeof(XtPointer), | 164 #endif |
152 offset(popdownCallbacks), XtRCallback, NULL}, | 165 res (XtNinternalWidth, XtCWidth, XtRDimension, Dimension, |
153 {XtNbeNiceToColormap, XtCBeNiceToColormap, XtRBoolean, sizeof(Boolean), | 166 internalWidth, XtRImmediate, 4), |
154 offset(be_nice_to_cmap), XtRImmediate, (XtPointer) True}, | 167 res (XtNinternalHeight, XtCHeight, XtRDimension, Dimension, |
155 {XtNtopShadowContrast, XtCTopShadowContrast, XtRInt, sizeof(int), | 168 internalHeight, XtRImmediate, 4), |
156 offset(top_shadow_contrast), XtRImmediate, (XtPointer) 20}, | 169 Xt_RESOURCE (XtNborderWidth, XtCBorderWidth, XtRDimension, Dimension, |
157 {XtNbottomShadowContrast, XtCBottomShadowContrast, XtRInt, sizeof(int), | 170 XtOffsetOf(RectObjRec,rectangle.border_width), XtRImmediate, 0), |
158 offset(bot_shadow_contrast), XtRImmediate, (XtPointer) 40}, | 171 res (XtNtopWidget, XtCTopWidget, XtRWidget, Widget, |
159 {XtNinsensitiveContrast, XtCInsensitiveContrast, XtRInt, sizeof(int), | 172 topWidget, XtRImmediate, NULL), |
160 offset(insensitive_contrast), XtRImmediate, (XtPointer) 33}, | 173 res (XtNcallback, XtCCallback, XtRCallback, XtPointer, |
161 {XtNaccelerators, XtCAccelerators, XtRAcceleratorTable,sizeof(XtTranslations), | 174 callbacks, XtRCallback, NULL), |
162 XtOffsetOf(TabsRec,core.accelerators), XtRString, accelTable}, | 175 res (XtNpopdownCallback, XtCCallback, XtRCallback, XtPointer, |
176 popdownCallbacks, XtRCallback, NULL), | |
177 res (XtNbeNiceToColormap, XtCBeNiceToColormap, XtRBoolean, Boolean, | |
178 be_nice_to_cmap, XtRImmediate, True), | |
179 res (XtNtopShadowContrast, XtCTopShadowContrast, XtRInt, int, | |
180 top_shadow_contrast, XtRImmediate, 20), | |
181 res (XtNbottomShadowContrast, XtCBottomShadowContrast, XtRInt, int, | |
182 bot_shadow_contrast, XtRImmediate, 40), | |
183 res (XtNinsensitiveContrast, XtCInsensitiveContrast, XtRInt, int, | |
184 insensitive_contrast, XtRImmediate, 33), | |
185 Xt_RESOURCE (XtNaccelerators, XtCAccelerators, XtRAcceleratorTable, | |
186 XtTranslations, XtOffsetOf(TabsRec,core.accelerators), | |
187 XtRString, accelTable), | |
188 #undef offset | |
189 #undef res | |
163 }; | 190 }; |
191 | |
192 | |
193 /* constraint resources */ | |
194 | |
195 static XtResource tabsConstraintResources[] = { | |
196 #define offset(field) XtOffsetOf(TabsConstraintsRec, tabs.field) | |
197 #define res(name,_class,intrepr,type,member,extrepr,value) \ | |
198 Xt_RESOURCE (name, _class, intrepr, type, offset(member), extrepr, value) | |
199 res (XtNtabLabel, XtCLabel, XtRString, String, label, XtRString, NULL), | |
200 res (XtNtabLeftBitmap, XtCLeftBitmap, XtRBitmap, Pixmap, left_bitmap, | |
201 XtRImmediate, None), | |
202 res (XtNtabForeground, XtCForeground, XtRPixel, Pixel, foreground, | |
203 XtRString, XtDefaultForeground), | |
204 res (XtNresizable, XtCResizable, XtRBoolean, Boolean, resizable, | |
205 XtRImmediate, True), | |
164 #undef offset | 206 #undef offset |
165 | 207 #undef res |
166 | |
167 | |
168 /* constraint resources */ | |
169 | |
170 #define offset(field) XtOffsetOf(TabsConstraintsRec, tabs.field) | |
171 static XtResource tabsConstraintResources[] = { | |
172 {XtNtabLabel, XtCLabel, XtRString, sizeof(String), | |
173 offset(label), XtRString, NULL}, | |
174 {XtNtabLeftBitmap, XtCLeftBitmap, XtRBitmap, sizeof(Pixmap), | |
175 offset(left_bitmap), XtRImmediate, None}, | |
176 {XtNtabForeground, XtCForeground, XtRPixel, sizeof(Pixel), | |
177 offset(foreground), XtRString, (XtPointer) XtDefaultForeground}, | |
178 {XtNresizable, XtCResizable, XtRBoolean, sizeof(Boolean), | |
179 offset(resizable), XtRImmediate, (XtPointer) True}, | |
180 } ; | 208 } ; |
181 #undef offset | |
182 | 209 |
183 | 210 |
184 | 211 |
185 | 212 |
186 #if !NeedFunctionPrototypes | 213 #if !NeedFunctionPrototypes |
295 do{rects[(i)].x=(xx); rects[i].y=(yy); \ | 322 do{rects[(i)].x=(xx); rects[i].y=(yy); \ |
296 rects[i].width=(w); rects[i].height=(h);}while(0) | 323 rects[i].width=(w); rects[i].height=(h);}while(0) |
297 | 324 |
298 static XtActionsRec actionsList[] = | 325 static XtActionsRec actionsList[] = |
299 { | 326 { |
300 {"select", TabsSelect}, | 327 { (String) "select", TabsSelect }, |
301 {"page", TabsPage}, | 328 { (String) "page", TabsPage }, |
302 {"highlight", TabsHighlight}, | 329 { (String) "highlight", TabsHighlight }, |
303 {"unhighlight", TabsUnhighlight}, | 330 { (String) "unhighlight", TabsUnhighlight }, |
304 } ; | 331 } ; |
305 | 332 |
306 | 333 |
307 /**************************************************************** | 334 /**************************************************************** |
308 * | 335 * |
318 | 345 |
319 TabsClassRec tabsClassRec = { | 346 TabsClassRec tabsClassRec = { |
320 { | 347 { |
321 /* core_class fields */ | 348 /* core_class fields */ |
322 /* superclass */ (WidgetClass) SuperClass, | 349 /* superclass */ (WidgetClass) SuperClass, |
323 /* class_name */ "Tabs", | 350 /* class_name */ (String) "Tabs", |
324 /* widget_size */ sizeof(TabsRec), | 351 /* widget_size */ sizeof(TabsRec), |
325 /* class_initialize */ TabsClassInit, | 352 /* class_initialize */ TabsClassInit, |
326 /* class_part_init */ NULL, /* TODO? */ | 353 /* class_part_init */ NULL, /* TODO? */ |
327 /* class_inited */ FALSE, | 354 /* class_inited */ FALSE, |
328 /* initialize */ TabsInit, | 355 /* initialize */ TabsInit, |
398 #define TabVisible(tab) \ | 425 #define TabVisible(tab) \ |
399 (XtIsManaged(tab) && \ | 426 (XtIsManaged(tab) && \ |
400 ((TabsConstraints)((tab)->core.constraints))->tabs.visible) | 427 ((TabsConstraints)((tab)->core.constraints))->tabs.visible) |
401 | 428 |
402 | 429 |
430 | |
431 static int debug_tabs = 0; /* increase for more verbosity */ | |
432 | |
433 #ifdef USE_XFT_TABS | |
434 /* #### duplicated from xlwmenu.c -- CLEAN THIS SHIT UP! | |
435 Undeclared so define at top. */ | |
436 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \ | |
437 ? ((unsigned long) (x)) : ((unsigned long) (y))) | |
438 | |
439 static int | |
440 x_xft_text_width (Display *dpy, XftFont *xft_font, FcChar8 *run, int len) | |
441 { | |
442 static XGlyphInfo glyphinfo; /* #### static? */ | |
443 | |
444 XftTextExtents8 (dpy, | |
445 xft_font, | |
446 run, len, &glyphinfo); | |
447 return glyphinfo.xOff; | |
448 } | |
449 #endif | |
450 | |
403 /**************************************************************** | 451 /**************************************************************** |
404 * | 452 * |
405 * Member Procedures | 453 * Member Procedures |
406 * | 454 * |
407 ****************************************************************/ | 455 ****************************************************************/ |
434 /* height is easy, it's the same for all tabs: | 482 /* height is easy, it's the same for all tabs: |
435 * TODO: font height + height of tallest bitmap. | 483 * TODO: font height + height of tallest bitmap. |
436 */ | 484 */ |
437 newTw->tabs.tab_height = 2 * newTw->tabs.internalHeight + SHADWID ; | 485 newTw->tabs.tab_height = 2 * newTw->tabs.internalHeight + SHADWID ; |
438 | 486 |
439 if( newTw->tabs.font != NULL ) | 487 #ifdef USE_XFT_TABS |
488 /* #### kludge for name change */ | |
489 if (!newTw->tabs.fcFontName) | |
490 newTw->tabs.fcFontName = newTw->tabs.xftFontName; | |
491 /* must get font here | |
492 #### to do this right, we should add a new Xt Resource type + | |
493 conversion function */ | |
494 newTw->tabs.renderFont = | |
495 xft_open_font_by_name (XtDisplay ((Widget) newTw), | |
496 newTw->tabs.fcFontName); | |
497 if (newTw->tabs.renderFont != NULL) | |
498 #if XFT_USE_HEIGHT_NOT_ASCENT_DESCENT | |
499 newTw->tabs.tab_height += newTw->tabs.renderFont->height; | |
500 #else | |
501 newTw->tabs.tab_height += newTw->tabs.renderFont->ascent + | |
502 newTw->tabs.renderFont->descent; | |
503 #endif /* XFT_USE_HEIGHT_NOT_ASCENT_DESCENT */ | |
504 #else /* ! USE_XFT_TABS */ | |
505 if (newTw->tabs.font != NULL) | |
440 newTw->tabs.tab_height += newTw->tabs.font->max_bounds.ascent + | 506 newTw->tabs.tab_height += newTw->tabs.font->max_bounds.ascent + |
441 newTw->tabs.font->max_bounds.descent ; | 507 newTw->tabs.font->max_bounds.descent; |
442 | 508 #endif /* ! USE_XFT_TABS */ |
443 /* GC allocation is deferred until XtRealize() */ | |
444 | 509 |
445 /* if size not explicitly set, set it to our preferred size now. */ | 510 /* if size not explicitly set, set it to our preferred size now. */ |
446 | 511 |
447 if( request->core.width == 0 || request->core.height == 0 ) | 512 if( request->core.width == 0 || request->core.height == 0 ) |
448 { | 513 { |
511 | 576 |
512 | 577 |
513 static void | 578 static void |
514 TabsDestroy(Widget w) | 579 TabsDestroy(Widget w) |
515 { | 580 { |
516 TabsFreeGCs((TabsWidget)w) ; | 581 TabsWidget tw = (TabsWidget) w; |
582 #ifdef USE_XFT_TABS | |
583 XftFontClose (XtDisplay (w), tw->tabs.renderFont); | |
584 #endif /* ! USE_XFT_TABS */ | |
585 TabsFreeGCs (tw) ; | |
517 } | 586 } |
518 | 587 |
519 | 588 |
520 /* Parent has resized us. This will require that the tabs be | 589 /* Parent has resized us. This will require that the tabs be |
521 * laid out again. | 590 * laid out again. |
612 TabsWidget tw = (TabsWidget) new_ ; | 681 TabsWidget tw = (TabsWidget) new_ ; |
613 Boolean needRedraw = False ; | 682 Boolean needRedraw = False ; |
614 Widget *childP ; | 683 Widget *childP ; |
615 int i ; | 684 int i ; |
616 | 685 |
617 | 686 if( |
618 if( tw->tabs.font != curtw->tabs.font || | 687 #ifdef USE_XFT_TABS |
619 tw->tabs.internalWidth != curtw->tabs.internalWidth || | 688 tw->tabs.renderFont != curtw->tabs.renderFont || |
620 tw->tabs.internalHeight != curtw->tabs.internalHeight ) | 689 #else |
690 tw->tabs.font != curtw->tabs.font || | |
691 #endif | |
692 tw->tabs.internalWidth != curtw->tabs.internalWidth || | |
693 tw->tabs.internalHeight != curtw->tabs.internalHeight) | |
621 { | 694 { |
622 tw->tabs.tab_height = 2 * tw->tabs.internalHeight + SHADWID ; | 695 tw->tabs.tab_height = 2 * tw->tabs.internalHeight + SHADWID; |
623 | 696 |
624 if( tw->tabs.font != NULL ) | 697 #ifdef USE_XFT_TABS |
698 if (tw->tabs.renderFont != NULL) | |
699 #if XFT_USE_HEIGHT_NOT_ASCENT_DESCENT | |
700 tw->tabs.tab_height += tw->tabs.renderFont->height; | |
701 #else | |
702 tw->tabs.tab_height += tw->tabs.renderFont->ascent + | |
703 tw->tabs.renderFont->descent; | |
704 #endif /* XFT_USE_HEIGHT_NOT_ASCENT_DESCENT */ | |
705 #else /* ! USE_XFT_TABS */ | |
706 if (tw->tabs.font != NULL) | |
625 tw->tabs.tab_height += tw->tabs.font->max_bounds.ascent + | 707 tw->tabs.tab_height += tw->tabs.font->max_bounds.ascent + |
626 tw->tabs.font->max_bounds.descent ; | 708 tw->tabs.font->max_bounds.descent; |
709 #endif /* ! USE_XFT_TABS */ | |
627 | 710 |
628 /* Tab size has changed. Resize all tabs and request a new size */ | 711 /* Tab size has changed. Resize all tabs and request a new size */ |
629 for(i=0, childP=tw->composite.children; | 712 for(i=0, childP=tw->composite.children; |
630 i < (int) tw->composite.num_children; | 713 i < (int) tw->composite.num_children; |
631 ++i, ++childP) | 714 ++i, ++childP) |
638 | 721 |
639 /* TODO: if any color changes, need to recompute GCs and redraw */ | 722 /* TODO: if any color changes, need to recompute GCs and redraw */ |
640 | 723 |
641 if( tw->core.background_pixel != curtw->core.background_pixel || | 724 if( tw->core.background_pixel != curtw->core.background_pixel || |
642 tw->core.background_pixmap != curtw->core.background_pixmap || | 725 tw->core.background_pixmap != curtw->core.background_pixmap || |
643 tw->tabs.font != curtw->tabs.font ) | 726 #ifdef USE_XFT_TABS |
727 tw->tabs.renderFont != curtw->tabs.renderFont | |
728 #else | |
729 tw->tabs.font != curtw->tabs.font | |
730 #endif | |
731 ) | |
644 if( XtIsRealized(new_) ) | 732 if( XtIsRealized(new_) ) |
645 { | 733 { |
646 TabsFreeGCs(tw) ; | 734 TabsFreeGCs(tw) ; |
647 TabsAllocGCs(tw) ; | 735 TabsAllocGCs(tw) ; |
648 needRedraw = True ; | 736 needRedraw = True ; |
753 } | 841 } |
754 | 842 |
755 | 843 |
756 | 844 |
757 /* | 845 /* |
758 * Return preferred size. Happily accept anything >= our preferred size. | 846 * Return status, with preferred size in PREFERRED. |
759 * (TODO: is that the right thing to do? Should we always return "almost" | 847 * |
760 * if offered more than we need?) | 848 * According to the X Toolkit Intrinsics manual |
849 * XtGeometryYes = accept INTENDED without change | |
850 * XtGeometryNo = request to stay _exactly_ the same | |
851 * XtGeometryAlmost = suggest PREFERRED as a compromise | |
852 * and the PREFERRED argument must be filled in completely (ie, any fields | |
853 * whose bits are set in the request_mode mask must correspond to the | |
854 * preferred geometry, which must be consistent with the return value). | |
855 * | |
856 * Assuming horizontal orientation, in XEmacs, we should always accept if | |
857 * the width is more than we need. There's no problem if there are only a | |
858 * couple of tabs packed to the left. OTOH there's probably something wrong | |
859 * if we're offered a height more than 1.5x or 2x the preferred height. | |
860 * (#### Do tab controls do vertical?) | |
761 */ | 861 */ |
762 | 862 |
863 /* compute the height above which we complain */ | |
864 #define TAB_HEIGHT_TOLERANCE(x) (2*x) | |
865 | |
763 static XtGeometryResult | 866 static XtGeometryResult |
764 TabsQueryGeometry(Widget w, | 867 TabsQueryGeometry (Widget w, |
765 XtWidgetGeometry *intended, XtWidgetGeometry *preferred) | 868 XtWidgetGeometry *intended, |
766 { | 869 XtWidgetGeometry *preferred) /* RETURN */ |
767 register TabsWidget tw = (TabsWidget)w ; | 870 { |
768 XtGeometryMask mode = intended->request_mode ; | 871 TabsWidget tw = (TabsWidget) w; |
769 | 872 XtGeometryMask mode = intended->request_mode; |
770 preferred->request_mode = CWWidth | CWHeight ; | 873 |
771 PreferredSize(tw, &preferred->width, &preferred->height, NULL,NULL) ; | 874 preferred->request_mode = CWWidth | CWHeight; |
772 | 875 PreferredSize (tw, &preferred->width, &preferred->height, NULL, NULL); |
773 if( (!(mode & CWWidth) || intended->width == w->core.width) && | 876 |
774 (!(mode & CWHeight) || intended->height == w->core.height) ) | 877 /* If width is big enough, accept it. */ |
775 return XtGeometryNo ; | 878 if ((mode & CWWidth) && intended->width >= preferred->width) |
776 | 879 preferred->width = intended->width; |
777 if( (!(mode & CWWidth) || intended->width >= preferred->width) && | 880 |
778 (!(mode & CWHeight) || intended->height >= preferred->height) ) | 881 /* If height is within range, accept it. |
882 #### If too tall, we could offer a compromise at TAB_HEIGHT_TOLERANCE. | |
883 Should we? */ | |
884 if ((mode & CWHeight) && intended->height >= preferred->height | |
885 && intended->height <= TAB_HEIGHT_TOLERANCE (preferred->height)) | |
886 preferred->height = intended->height; | |
887 | |
888 /* Compute return value. */ | |
889 if (preferred->width == ((mode & CWWidth) ? intended->width | |
890 : w->core.width) | |
891 && preferred->height == ((mode & CWHeight) ? intended->height | |
892 : w->core.height)) | |
779 return XtGeometryYes; | 893 return XtGeometryYes; |
780 | 894 else if (preferred->width == w->core.width |
781 return XtGeometryAlmost; | 895 && preferred->height == w->core.height) |
896 return XtGeometryNo; | |
897 else | |
898 return XtGeometryAlmost; | |
782 } | 899 } |
783 | 900 |
784 | 901 |
785 | 902 |
786 /* | 903 /* |
787 * Geometry Manager; called when a child wants to be resized. | 904 * Geometry Manager; called when TAB (a child) wants to be resized. |
905 * | |
906 * According to the X Toolkit Intrinsics manual | |
907 * XtGeometryDone = accept REQUEST and do it (#### check this) | |
908 * XtGeometryYes = accept REQUEST without change | |
909 * XtGeometryNo = refuse REQUEST (ie, stay _exactly_ the same) | |
910 * XtGeometryAlmost = suggest REPLY as a compromise | |
788 */ | 911 */ |
789 | 912 |
790 static XtGeometryResult | 913 static XtGeometryResult |
791 TabsGeometryManager(Widget w, XtWidgetGeometry *req, XtWidgetGeometry *reply) | 914 TabsGeometryManager (Widget tab, |
792 { | 915 XtWidgetGeometry *request, |
793 TabsWidget tw = (TabsWidget) XtParent(w); | 916 XtWidgetGeometry *reply) /* RETURN */ |
794 Dimension s = SHADWID ; | 917 { |
795 TabsConstraints tab = (TabsConstraints)w->core.constraints; | 918 TabsWidget control = (TabsWidget) XtParent(tab); |
796 XtGeometryResult result ; | 919 Dimension s = SHADWID; |
797 Dimension rw, rh ; | 920 TabsConstraints constraint = (TabsConstraints) tab->core.constraints; |
798 | 921 XtGeometryResult result, best_offer = XtGeometryYes; |
799 /* Position request always denied */ | 922 Dimension rw, rh; |
800 | 923 |
801 if( ((req->request_mode & CWX) && req->x != w->core.x) || | 924 static int debug_count = 0; |
802 ((req->request_mode & CWY) && req->y != w->core.y) || | 925 static int debug_mask = 1; |
803 !tab->tabs.resizable ) | 926 |
804 return XtGeometryNo ; | 927 /* Position request cannot be satisfied, so if tabs are not resizable, |
805 | 928 no nontrivial request can be satisfied: return XGeometryNo. */ |
806 /* Make all three fields in the request valid */ | 929 if (!constraint->tabs.resizable) |
807 if( !(req->request_mode & CWWidth) ) | 930 return XtGeometryNo; |
808 req->width = w->core.width; | 931 |
809 if( !(req->request_mode & CWHeight) ) | 932 fprintf (stderr, "Urk! label is resizable!\n"); |
810 req->height = w->core.height; | 933 |
811 if( !(req->request_mode & CWBorderWidth) ) | 934 /* Assume we will refuse these; toggle iff we accept them. |
812 req->border_width = w->core.border_width; | 935 Reply won't specify any fields not in the request. */ |
813 | 936 reply->request_mode = request->request_mode; |
814 if( req->width == w->core.width && | 937 reply->x = tab->core.x; |
815 req->height == w->core.height && | 938 reply->y = tab->core.y; |
816 req->border_width == w->core.border_width ) | 939 |
817 return XtGeometryNo ; | 940 /* If a position request would result in a change, best offer is |
818 | 941 XtGeometryAlmost. Otherwise toggle reply->request_mode. */ |
819 rw = req->width + 2 * req->border_width ; | 942 if ((request->request_mode & CWX) && request->x != tab->core.x) |
820 rh = req->height + 2 * req->border_width ; | 943 best_offer = XtGeometryAlmost; |
944 else | |
945 reply->request_mode &= ~CWX; | |
946 if ((request->request_mode & CWY) && request->y != tab->core.y) | |
947 best_offer = XtGeometryAlmost; | |
948 else | |
949 reply->request_mode &= ~CWY; | |
950 | |
951 /* Make all three fields in the reply valid */ | |
952 reply->width = (request->request_mode & CWWidth) | |
953 ? request->width : tab->core.width; | |
954 reply->height = (request->request_mode & CWHeight) | |
955 ? request->height : tab->core.height; | |
956 reply->border_width = (request->request_mode & CWBorderWidth) | |
957 ? request->border_width : tab->core.border_width; | |
958 | |
959 /* check if we can already offer a compromise */ | |
960 if (best_offer == XtGeometryAlmost && | |
961 reply->width == tab->core.width && | |
962 reply->height == tab->core.height && | |
963 reply->border_width == tab->core.border_width) | |
964 { | |
965 reply->request_mode &= ~(CWWidth | CWHeight | CWBorderWidth); | |
966 return best_offer; | |
967 } | |
968 | |
969 #ifndef DONT_DEBUG_REQUESTS | |
970 #define DBG_REQUEST_PRINT(name,field,size) \ | |
971 do { \ | |
972 if (reply->field > size) \ | |
973 { \ | |
974 if (++debug_count == debug_mask) \ | |
975 { \ | |
976 debug_mask <<= 1; \ | |
977 fprintf (stderr, "ridiculous %s request #%d: %d > %d\n", \ | |
978 name, debug_count, reply->field, size); \ | |
979 } \ | |
980 reply->field = tab->core.field; \ | |
981 } \ | |
982 } while (0) | |
983 | |
984 DBG_REQUEST_PRINT ("width",width,1024); | |
985 DBG_REQUEST_PRINT ("height",height,768); | |
986 DBG_REQUEST_PRINT ("border_width",border_width,30); | |
987 #undef DBG_REQUEST_PRINT | |
988 #endif | |
989 | |
990 rw = reply->width + 2 * reply->border_width; | |
991 rh = reply->height + 2 * reply->border_width; | |
821 | 992 |
822 /* find out how big the children want to be now */ | 993 /* find out how big the children want to be now */ |
823 MaxChild(tw, w, rw, rh) ; | 994 MaxChild (control, tab, rw, rh); |
824 | 995 |
825 | 996 |
826 /* Size changes must see if the new size can be accommodated. | 997 /* Size changes must see if the new size can be accommodated. |
827 * The Tabs widget keeps all of its children the same | 998 * The Tabs widget keeps all of its children the same height, but |
828 * size. A request to shrink will be accepted only if the | 999 * widths may vary. |
1000 * A request to shrink will be accepted only if the | |
829 * new size is still big enough for all other children. A | 1001 * new size is still big enough for all other children. A |
830 * request to shrink that is not big enough for all children | 1002 * request to shrink that is not big enough for all children |
831 * returns an "almost" response with the new proposed size | 1003 * returns an "almost" response with the new proposed size |
832 * or a "no" response if unable to shrink at all. | 1004 * or a "no" response if unable to shrink at all. |
833 * | 1005 * |
834 * A request to grow will be accepted only if the Tabs parent can | 1006 * A request to grow will be accepted only if the Tabs control can |
835 * grow to accommodate. | 1007 * grow to accommodate. |
836 * | 1008 * |
837 * TODO: | 1009 * TODO: |
838 * We could get fancy here and re-arrange the tabs if it is | 1010 * We could get fancy here and re-arrange the tabs if it is |
839 * necessary to compromise with the parent, but we'll save that | 1011 * necessary to compromise with the parent, but we'll save that |
840 * for another day. | 1012 * for another day. |
841 */ | 1013 */ |
842 | 1014 |
843 if (req->request_mode & (CWWidth | CWHeight | CWBorderWidth)) | 1015 if (request->request_mode & (CWWidth | CWHeight | CWBorderWidth)) |
844 { | 1016 { |
845 Dimension cw,ch ; /* children's preferred size */ | 1017 Dimension cw,ch ; /* children's preferred size */ |
846 Dimension aw,ah ; /* available size we can give child */ | 1018 Dimension aw,ah ; /* available size we can give child */ |
847 Dimension th ; /* space used by tabs */ | 1019 Dimension th ; /* space used by tabs */ |
848 Dimension wid,hgt ; /* Tabs widget size */ | 1020 Dimension wid,hgt ; /* Tabs widget size */ |
849 | 1021 int check_nrows; |
850 cw = tw->tabs.max_cw ; | 1022 |
851 ch = tw->tabs.max_ch ; | 1023 cw = control->tabs.max_cw ; |
1024 ch = control->tabs.max_ch ; | |
852 | 1025 |
853 /* find out what *my* resulting preferred size would be */ | 1026 /* find out what *my* resulting preferred size would be */ |
854 | 1027 /* #### this whole API is wrong; what should happen is |
855 PreferredSize2(tw, cw, ch, &wid, &hgt) ; | 1028 1. app should hint as to #rows and/or aspect ratio |
1029 2. tab control should attempt to layout in current space | |
1030 3. if not all tabs fit, should request resize to achieve | |
1031 layout hints | |
1032 Probably can and should cache preferred size in widget, with | |
1033 cache cleared when labels or core size changes. */ | |
1034 PreferredSize2(control, cw, ch, &wid, &hgt) ; | |
856 | 1035 |
857 /* Would my size change? If so, ask to be resized. */ | 1036 /* Would my size change? If so, ask to be resized. */ |
858 | 1037 |
859 if( wid != tw->core.width || hgt != tw->core.height ) | 1038 if (wid != control->core.width || hgt != control->core.height) |
860 { | 1039 { |
861 Dimension oldWid = tw->core.width, oldHgt = tw->core.height ; | 1040 Dimension oldWid = control->core.width, |
1041 oldHgt = control->core.height; | |
862 XtWidgetGeometry myrequest, myreply ; | 1042 XtWidgetGeometry myrequest, myreply ; |
863 | 1043 |
864 myrequest.width = wid ; | 1044 myrequest.width = wid ; |
865 myrequest.height = hgt ; | 1045 myrequest.height = hgt ; |
866 myrequest.request_mode = CWWidth | CWHeight ; | 1046 myrequest.request_mode = CWWidth | CWHeight ; |
868 assert (wid > 0 && hgt > 0); | 1048 assert (wid > 0 && hgt > 0); |
869 /* If child is only querying, or if we're going to have to | 1049 /* If child is only querying, or if we're going to have to |
870 * offer the child a compromise, then make this a query only. | 1050 * offer the child a compromise, then make this a query only. |
871 */ | 1051 */ |
872 | 1052 |
873 if( (req->request_mode & XtCWQueryOnly) || rw < cw || rh < ch ) | 1053 if ((request->request_mode & XtCWQueryOnly) || rw < cw || rh < ch) |
874 myrequest.request_mode |= XtCWQueryOnly ; | 1054 myrequest.request_mode |= XtCWQueryOnly; |
875 | 1055 |
876 result = XtMakeGeometryRequest((Widget)tw, &myrequest, &myreply) ; | 1056 result = XtMakeGeometryRequest ((Widget) control, |
1057 &myrequest, &myreply); | |
877 | 1058 |
878 /* !$@# Athena Box widget changes the core size even if QueryOnly | 1059 /* !$@# Athena Box widget changes the core size even if QueryOnly |
879 * is set. I'm convinced this is a bug. At any rate, to work | 1060 * is set. I'm convinced this is a bug. At any rate, to work |
880 * around the bug, we need to restore the core size after every | 1061 * around the bug, we need to restore the core size after every |
881 * query geometry request. This is only partly effective, | 1062 * query geometry request. This is only partly effective, |
882 * as there may be other boxes further up the tree. | 1063 * as there may be other boxes further up the tree. |
883 */ | 1064 */ |
884 if( myrequest.request_mode & XtCWQueryOnly ) { | 1065 if (myrequest.request_mode & XtCWQueryOnly) { |
885 tw->core.width = oldWid ; | 1066 control->core.width = oldWid; |
886 tw->core.height = oldHgt ; | 1067 control->core.height = oldHgt; |
887 } | 1068 } |
888 | 1069 |
889 /* based on the parent's response, determine what the | 1070 /* based on the parent's response, determine what the |
890 * resulting Tabs widget size would be. | 1071 * resulting Tabs widget size would be. |
891 */ | 1072 */ |
892 | 1073 |
893 switch( result ) { | 1074 switch (result) { |
894 case XtGeometryYes: | 1075 case XtGeometryYes: |
895 case XtGeometryDone: | 1076 case XtGeometryDone: |
896 tw->tabs.needs_layout = True ; | 1077 control->tabs.needs_layout = True; |
897 break ; | 1078 break; |
898 | 1079 |
899 case XtGeometryNo: | 1080 case XtGeometryNo: |
900 wid = tw->core.width ; | 1081 wid = control->core.width; |
901 hgt = tw->core.height ; | 1082 hgt = control->core.height; |
902 break ; | 1083 break; |
903 | 1084 |
904 case XtGeometryAlmost: | 1085 case XtGeometryAlmost: |
905 wid = myreply.width ; | 1086 wid = myreply.width; |
906 hgt = myreply.height ; | 1087 hgt = myreply.height; |
907 tw->tabs.needs_layout = True ; | 1088 control->tabs.needs_layout = True; |
908 break ; | 1089 break; |
909 } | 1090 } |
910 } | 1091 } |
911 | 1092 |
912 /* Within the constraints imposed by the parent, what is | 1093 /* Within the constraints imposed by the parent, what is |
913 * the max size we can give the child? | 1094 * the max size we can give the child? |
914 */ | 1095 */ |
915 (void) TabLayout(tw, wid, hgt, &th, True) ; | 1096 check_nrows = TabLayout (control, wid, hgt, &th, True); |
916 aw = wid - 2*s ; | 1097 aw = wid - 2*s; |
917 ah = hgt - th - 2*s ; | 1098 if (check_nrows == 1) |
1099 { | |
1100 ah = hgt - th - 2*s; | |
1101 } | |
1102 else | |
1103 { | |
1104 /* this rarely gets triggered, but when it does it seems to | |
1105 get triggered forever after */ | |
1106 int n = control->composite.num_children; | |
1107 ah = control->tabs.tab_height; | |
1108 if (debug_tabs > 1) | |
1109 fprintf (stderr, "Kludging around %d != 1 rows," | |
1110 " #children = %d, total height %d, using %d.\n", | |
1111 check_nrows, n, th, ah); | |
1112 } | |
918 | 1113 |
919 /* OK, make our decision. If requested size is >= max sibling | 1114 /* OK, make our decision. If requested size is >= max sibling |
920 * preferred size, AND requested size <= available size, then | 1115 * preferred size, AND requested size <= available size, then |
921 * we accept. Otherwise, we offer a compromise. | 1116 * we accept. Otherwise, we offer a compromise. |
922 */ | 1117 */ |
923 | 1118 |
924 if( rw == aw && rh == ah ) | 1119 if (rw == aw && rh == ah) |
925 { | 1120 { |
926 /* Acceptable. If this wasn't a query, change *all* children | 1121 /* Acceptable. If this wasn't a query, change *all* children |
927 * to this size. | 1122 * to this size. |
928 */ | 1123 */ |
929 if( req->request_mode & XtCWQueryOnly ) | 1124 if (request->request_mode & XtCWQueryOnly) |
930 return XtGeometryYes ; | 1125 { |
1126 control->tabs.needs_layout = False; | |
1127 return XtGeometryYes ; | |
1128 } | |
931 else | 1129 else |
932 { | 1130 { |
933 Widget *childP = tw->composite.children ; | 1131 Widget *childP = control->composite.children; |
934 int i,bw ; | 1132 int i, bw; |
935 w->core.border_width = req->border_width ; | 1133 tab->core.border_width = request->border_width; |
936 for(i=TabsNumChildren (tw); --i >= 0; ++childP) | 1134 for (i = TabsNumChildren (control); --i >= 0; ++childP) |
937 if( TabVisible(*childP) ) | 1135 if (TabVisible (*childP)) |
938 { | 1136 { |
939 bw = (*childP)->core.border_width ; | 1137 bw = (*childP)->core.border_width; |
940 XtConfigureWidget(*childP, s,tw->tabs.tab_total+s, | 1138 XtConfigureWidget (*childP, s, control->tabs.tab_total+s, |
941 rw-2*bw, rh-2*bw, bw) ; | 1139 rw-2*bw, rh-2*bw, bw); |
942 } | 1140 } |
943 #ifdef COMMENT | 1141 #ifdef COMMENT |
944 /* TODO: under what conditions will we need to redraw? */ | 1142 /* TODO: under what conditions will we need to redraw? */ |
945 XClearWindow(XtDisplay((Widget)tw), XtWindow((Widget)tw)) ; | 1143 XClearWindow (XtDisplay ((Widget) control), |
946 XtClass(tw)->core_class.expose((Widget)tw,NULL,NULL) ; | 1144 XtWindow ((Widget) control)); |
1145 XtClass (control)->core_class.expose ((Widget)control, | |
1146 NULL, NULL); | |
947 #endif /* COMMENT */ | 1147 #endif /* COMMENT */ |
948 return XtGeometryDone ; | 1148 return XtGeometryDone; |
949 } | 1149 } |
950 } | 1150 } |
951 | 1151 |
952 /* Cannot grant child's request. Describe what we *can* do | 1152 /* Cannot grant child's request. Describe what we *can* do |
953 * and return counter-offer. | 1153 * and return counter-offer. |
954 */ | 1154 */ |
955 reply->width = aw - 2 * req->border_width ; | 1155 control->tabs.needs_layout = False; |
956 reply->height = ah - 2 * req->border_width ; | 1156 reply->width = aw - 2 * request->border_width ; |
957 reply->border_width = req->border_width ; | 1157 reply->height = ah - 2 * request->border_width ; |
958 reply->request_mode = CWWidth | CWHeight | CWBorderWidth ; | 1158 reply->request_mode &= |
1159 ~((reply->border_width == tab->core.border_width | |
1160 ? CWBorderWidth : 0) | |
1161 |(reply->width == tab->core.width ? CWWidth : 0) | |
1162 |(reply->height == tab->core.height ? CWHeight : 0)); | |
959 return XtGeometryAlmost ; | 1163 return XtGeometryAlmost ; |
960 } | 1164 } |
961 | 1165 |
962 return XtGeometryYes ; | 1166 return XtGeometryYes ; |
963 } | 1167 } |
1365 XtReleaseGC(w, tw->tabs.foregroundGC) ; | 1569 XtReleaseGC(w, tw->tabs.foregroundGC) ; |
1366 XtReleaseGC(w, tw->tabs.greyGC) ; | 1570 XtReleaseGC(w, tw->tabs.greyGC) ; |
1367 XtReleaseGC(w, tw->tabs.backgroundGC) ; | 1571 XtReleaseGC(w, tw->tabs.backgroundGC) ; |
1368 XtReleaseGC(w, tw->tabs.topGC) ; | 1572 XtReleaseGC(w, tw->tabs.topGC) ; |
1369 XtReleaseGC(w, tw->tabs.botGC) ; | 1573 XtReleaseGC(w, tw->tabs.botGC) ; |
1370 #ifdef HAVE_XMU | |
1371 XmuReleaseStippledPixmap(XtScreen(w), tw->tabs.grey50) ; | 1574 XmuReleaseStippledPixmap(XtScreen(w), tw->tabs.grey50) ; |
1372 #endif | |
1373 } | 1575 } |
1374 | 1576 |
1375 | 1577 |
1376 | 1578 |
1377 | 1579 |
1426 DrawTab(TabsWidget tw, Widget child, Bool labels) | 1628 DrawTab(TabsWidget tw, Widget child, Bool labels) |
1427 { | 1629 { |
1428 GC gc ; | 1630 GC gc ; |
1429 int x,y ; | 1631 int x,y ; |
1430 | 1632 |
1633 if (debug_tabs > 2) fprintf (stderr, "DrawTab called.\n"); | |
1634 | |
1431 if( !XtIsRealized((Widget)tw)) | 1635 if( !XtIsRealized((Widget)tw)) |
1432 return ; | 1636 return ; |
1433 | 1637 |
1434 DrawBorder(tw, child, False) ; | 1638 DrawBorder(tw, child, False) ; |
1435 | 1639 |
1438 TabsConstraints tab = (TabsConstraints)child->core.constraints; | 1642 TabsConstraints tab = (TabsConstraints)child->core.constraints; |
1439 Display *dpy = XtDisplay((Widget)tw) ; | 1643 Display *dpy = XtDisplay((Widget)tw) ; |
1440 Window win = XtWindow((Widget)tw) ; | 1644 Window win = XtWindow((Widget)tw) ; |
1441 String lbl = tab->tabs.label != NULL ? | 1645 String lbl = tab->tabs.label != NULL ? |
1442 tab->tabs.label : XtName(child) ; | 1646 tab->tabs.label : XtName(child) ; |
1443 | 1647 #ifdef USE_XFT_TABS |
1444 if( XtIsSensitive(child) ) | 1648 XftColor color; |
1649 XftColor colorBG; | |
1650 Colormap cmap = tw->core.colormap; | |
1651 Visual *visual; | |
1652 int ignored; | |
1653 | |
1654 visual_info_from_widget ((Widget) tw, &visual, &ignored); | |
1655 colorBG = xft_convert_color (dpy, cmap, visual, | |
1656 tw->core.background_pixel, 0); | |
1657 #endif | |
1658 | |
1659 if (debug_tabs > 2) | |
1660 fprintf (stderr, "(Re)drawing labels.\n"); | |
1661 | |
1662 if (XtIsSensitive(child)) | |
1445 { | 1663 { |
1446 gc = tw->tabs.foregroundGC ; | 1664 gc = tw->tabs.foregroundGC; |
1447 XSetForeground(dpy, gc, tab->tabs.foreground) ; | 1665 #ifdef USE_XFT_TABS |
1666 color = xft_convert_color (dpy, cmap, visual, | |
1667 tab->tabs.foreground, 0); | |
1668 #else | |
1669 XSetForeground(dpy, gc, tab->tabs.foreground); | |
1670 #endif | |
1448 } | 1671 } |
1449 else | 1672 else |
1450 { | 1673 { |
1451 /* grey pixel allocation deferred until now */ | 1674 /* grey pixel allocation deferred until now */ |
1452 if( !tab->tabs.greyAlloc ) | 1675 if (!tab->tabs.greyAlloc) |
1453 { | 1676 { |
1454 if( tw->tabs.be_nice_to_cmap || tw->core.depth == 1 ) | 1677 if (tw->tabs.be_nice_to_cmap || tw->core.depth == 1) |
1455 tab->tabs.grey = tab->tabs.foreground ; | 1678 tab->tabs.grey = tab->tabs.foreground; |
1456 else | 1679 else |
1457 tab->tabs.grey = AllocGreyPixel((Widget)tw, | 1680 tab->tabs.grey = AllocGreyPixel ((Widget) tw, |
1458 tab->tabs.foreground, | 1681 tab->tabs.foreground, |
1459 tw->core.background_pixel, | 1682 tw->core.background_pixel, |
1460 tw->tabs.insensitive_contrast ) ; | 1683 tw->tabs.insensitive_contrast); |
1461 tab->tabs.greyAlloc = True ; | 1684 tab->tabs.greyAlloc = True; |
1462 } | 1685 } |
1463 gc = tw->tabs.greyGC ; | 1686 gc = tw->tabs.greyGC; |
1464 XSetForeground(dpy, gc, tab->tabs.grey) ; | 1687 #ifdef USE_XFT_TABS |
1688 color = xft_convert_color (dpy, cmap, visual, tab->tabs.grey, 0); | |
1689 #else | |
1690 XSetForeground(dpy, gc, tab->tabs.grey); | |
1691 #endif | |
1465 } | 1692 } |
1466 | 1693 |
1467 x = tab->tabs.x ; | 1694 x = tab->tabs.x; |
1468 y = tab->tabs.y ; | 1695 y = tab->tabs.y; |
1469 if( child == tw->tabs.topWidget ) | 1696 if (child == tw->tabs.topWidget) |
1470 y -= TABLDELTA ; | 1697 y -= TABLDELTA; |
1471 | 1698 |
1472 if( tab->tabs.left_bitmap != None && tab->tabs.lbm_width > 0 ) | 1699 if (tab->tabs.left_bitmap != None && tab->tabs.lbm_width > 0) |
1473 { | 1700 { |
1474 if( tab->tabs.lbm_depth == 1 ) | 1701 if (tab->tabs.lbm_depth == 1) |
1475 XCopyPlane(dpy, tab->tabs.left_bitmap, win,gc, | 1702 XCopyPlane(dpy, tab->tabs.left_bitmap, win,gc, |
1476 0,0, tab->tabs.lbm_width, tab->tabs.lbm_height, | 1703 0,0, tab->tabs.lbm_width, tab->tabs.lbm_height, |
1477 x+tab->tabs.lbm_x, y+tab->tabs.lbm_y, 1L) ; | 1704 x+tab->tabs.lbm_x, y+tab->tabs.lbm_y, 1L); |
1478 else | 1705 else |
1479 XCopyArea(dpy, tab->tabs.left_bitmap, win,gc, | 1706 XCopyArea(dpy, tab->tabs.left_bitmap, win,gc, |
1480 0,0, tab->tabs.lbm_width, tab->tabs.lbm_height, | 1707 0,0, tab->tabs.lbm_width, tab->tabs.lbm_height, |
1481 x+tab->tabs.lbm_x, y+tab->tabs.lbm_y) ; | 1708 x+tab->tabs.lbm_x, y+tab->tabs.lbm_y); |
1482 } | 1709 } |
1483 | 1710 |
1484 if( lbl != NULL && tw->tabs.font != NULL ) | 1711 if (lbl != NULL && |
1485 XDrawString(dpy,win,gc, | 1712 #ifdef USE_XFT_TABS |
1486 x+tab->tabs.l_x, y+tab->tabs.l_y, | 1713 tw->tabs.renderFont != NULL |
1487 lbl, (int)strlen(lbl)) ; | 1714 #else |
1488 } | 1715 tw->tabs.font != NULL |
1489 | 1716 #endif |
1490 if( child == tw->tabs.hilight ) | 1717 ) |
1491 DrawHighlight(tw, child, False) ; | 1718 { |
1719 #ifdef USE_XFT_TABS | |
1720 XftDraw *xftDraw = XftDrawCreate (dpy, win, visual, cmap); | |
1721 XftFont *renderFont = tw->tabs.renderFont; | |
1722 XGlyphInfo glyphinfo; | |
1723 XftColor colorDBG; | |
1724 XftColorAllocName (dpy, visual, cmap, "wheat", &colorDBG); | |
1725 XftTextExtents8 (dpy, renderFont, (FcChar8 *) lbl, | |
1726 (int) strlen (lbl), &glyphinfo); | |
1727 /* #### unnecessary? for the moment, give visual extent */ | |
1728 /* draw background rect */ | |
1729 if (debug_tabs > 2) | |
1730 { | |
1731 fprintf (stderr, "background color: pixel=%08lx, r=%04x," | |
1732 " g=%04x, b=%04x, alpha=%04x.\n", | |
1733 colorDBG.pixel, colorDBG.color.red, | |
1734 colorDBG.color.green, colorDBG.color.blue, | |
1735 colorDBG.color.alpha); | |
1736 fprintf (stderr, "label geometry: x=%d, y=%d, xOff=%d," | |
1737 " yOff=%d, width=%d, height=%d\n", | |
1738 glyphinfo.x, glyphinfo.y, glyphinfo.xOff, | |
1739 glyphinfo.yOff, glyphinfo.width, glyphinfo.height); | |
1740 } | |
1741 if (debug_tabs > 2) | |
1742 XftDrawRect (xftDraw, &colorDBG, | |
1743 /* left, top, width, height */ | |
1744 x+tab->tabs.l_x-glyphinfo.x, | |
1745 y+tab->tabs.l_y-glyphinfo.y, | |
1746 glyphinfo.width, glyphinfo.height); | |
1747 | |
1748 /* draw text */ | |
1749 if (debug_tabs > 1) | |
1750 { | |
1751 fprintf (stderr, "label: %s.\n", lbl); | |
1752 fprintf (stderr, "foreground color: pixel=%08lx, r=%04x," | |
1753 " g=%04x, b=%04x, alpha=%04x.\n", | |
1754 color.pixel, color.color.red, color.color.green, | |
1755 color.color.blue, color.color.alpha); | |
1756 fprintf (stderr, "extent: x=%d, y=%d, xOffset=%d," | |
1757 " yOffset=%d, height=%d, width=%d.\n", | |
1758 glyphinfo.x, glyphinfo.y, glyphinfo.xOff, | |
1759 glyphinfo.yOff, glyphinfo.height, glyphinfo.width); | |
1760 } | |
1761 if (debug_tabs > 0) | |
1762 { | |
1763 FcValue name; | |
1764 FcValue size; | |
1765 FcPatternGet (renderFont->pattern, FC_FAMILY, 0, &name); | |
1766 FcPatternGet (renderFont->pattern, FC_SIZE, 0, &size); | |
1767 fprintf (stderr, "font: name=%s-%.1f," | |
1768 " height=%d, ascent=%d, descent=%d.\n", | |
1769 name.u.s, size.u.d, renderFont->height, | |
1770 renderFont->ascent, renderFont->descent); | |
1771 } | |
1772 XftDrawString8 (xftDraw, &color, renderFont, | |
1773 x+tab->tabs.l_x, y+tab->tabs.l_y, | |
1774 (FcChar8 *) lbl, (int) strlen (lbl)); | |
1775 XftDrawDestroy (xftDraw); | |
1776 #else | |
1777 XDrawString(dpy,win,gc, | |
1778 x+tab->tabs.l_x, y+tab->tabs.l_y, | |
1779 lbl, (int)strlen(lbl)); | |
1780 #endif | |
1781 } | |
1782 } | |
1783 | |
1784 if (child == tw->tabs.hilight) | |
1785 DrawHighlight(tw, child, False); | |
1492 } | 1786 } |
1493 | 1787 |
1494 | 1788 |
1495 /* draw frame all the way around the child windows. */ | 1789 /* draw frame all the way around the child windows. */ |
1496 | 1790 |
1687 TabWidth(Widget w) | 1981 TabWidth(Widget w) |
1688 { | 1982 { |
1689 TabsConstraints tab = (TabsConstraints) w->core.constraints ; | 1983 TabsConstraints tab = (TabsConstraints) w->core.constraints ; |
1690 TabsWidget tw = (TabsWidget)XtParent(w) ; | 1984 TabsWidget tw = (TabsWidget)XtParent(w) ; |
1691 String lbl = tab->tabs.label != NULL ? | 1985 String lbl = tab->tabs.label != NULL ? |
1692 tab->tabs.label : XtName(w) ; | 1986 tab->tabs.label : XtName(w); |
1693 XFontStruct *font = tw->tabs.font ; | 1987 #ifdef USE_XFT_TABS |
1694 int iw = tw->tabs.internalWidth ; | 1988 XftFont *font = tw->tabs.renderFont; |
1989 #else | |
1990 XFontStruct *font = tw->tabs.font; | |
1991 #endif | |
1992 int iw = tw->tabs.internalWidth; | |
1695 | 1993 |
1696 tab->tabs.width = iw + SHADWID*2 ; | 1994 tab->tabs.width = iw + SHADWID*2 ; |
1697 tab->tabs.l_x = tab->tabs.lbm_x = SHADWID + iw ; | 1995 tab->tabs.l_x = tab->tabs.lbm_x = SHADWID + iw ; |
1698 | 1996 |
1699 if( tab->tabs.left_bitmap != None ) | 1997 if( tab->tabs.left_bitmap != None ) |
1703 tab->tabs.lbm_y = (tw->tabs.tab_height - tab->tabs.lbm_height)/2 ; | 2001 tab->tabs.lbm_y = (tw->tabs.tab_height - tab->tabs.lbm_height)/2 ; |
1704 } | 2002 } |
1705 | 2003 |
1706 if( lbl != NULL && font != NULL ) | 2004 if( lbl != NULL && font != NULL ) |
1707 { | 2005 { |
1708 tab->tabs.width += XTextWidth( font, lbl, (int)strlen(lbl) ) + iw ; | 2006 #ifdef USE_XFT_TABS |
2007 tab->tabs.width += x_xft_text_width (XtDisplay(tw), font, | |
2008 (FcChar8 *) lbl, | |
2009 (int)strlen(lbl)) + iw; | |
2010 tab->tabs.l_y = (tw->tabs.tab_height | |
2011 + tw->tabs.renderFont->ascent | |
2012 /* #### how can this subtraction be correct? */ | |
2013 - tw->tabs.renderFont->descent)/2; | |
2014 if (debug_tabs > 2) | |
2015 fprintf (stderr, "tab: height=%d, width=%d, baseline=%d.\n", | |
2016 tw->tabs.tab_height, tab->tabs.width, tab->tabs.l_y); | |
2017 if (debug_tabs > 1) | |
2018 fprintf (stderr, "font: height=%d, ascent=%d, descent=%d.\n", | |
2019 tw->tabs.renderFont->height, | |
2020 tw->tabs.renderFont->ascent, | |
2021 tw->tabs.renderFont->descent); | |
2022 #else | |
2023 tab->tabs.width += XTextWidth (font, lbl, (int)strlen(lbl)) + iw; | |
1709 tab->tabs.l_y = (tw->tabs.tab_height + | 2024 tab->tabs.l_y = (tw->tabs.tab_height + |
1710 tw->tabs.font->max_bounds.ascent - | 2025 tw->tabs.font->max_bounds.ascent - |
1711 tw->tabs.font->max_bounds.descent)/2 ; | 2026 tw->tabs.font->max_bounds.descent)/2; |
2027 #endif | |
1712 } | 2028 } |
1713 } | 2029 } |
1714 | 2030 |
1715 | 2031 |
1716 | 2032 |
1721 * | 2037 * |
1722 * Tabs are indented from the edges by INDENT. | 2038 * Tabs are indented from the edges by INDENT. |
1723 * | 2039 * |
1724 * TODO: if they require more than two rows and the total height:width | 2040 * TODO: if they require more than two rows and the total height:width |
1725 * ratio is more than 2:1, then try something else. | 2041 * ratio is more than 2:1, then try something else. |
2042 * Gaak! This is actually already done in PreferredSize()! | |
2043 * | |
2044 * TODO SOONER: for reasons unclear, some applications (specifically | |
2045 * XEmacs) give a nominal geometry (in the core record) which doesn't | |
2046 * make much sense (eg, may be smaller than some of the tab children). | |
2047 * This results in bizarre values for DISPLAY_ROWS and REPLY_HEIGHT. | |
2048 * Specify a way to say "tell me what you really want" (eg, with WID | |
2049 * and/or HGT == 0 or == Dimension_MAX), and use it where appropriate. | |
2050 * LATE-BREAKING LOSE: This happens in PreferredSize(), not XEmacs! | |
2051 * | |
2052 * TODO EVEN SOONER: some applications lay out the tab control by | |
2053 * repeatedly querying until a fixed width and height has been filled | |
2054 * by the tabs (XEmacs). There should be an API to cache this? | |
1726 */ | 2055 */ |
1727 | 2056 |
1728 static int | 2057 static int |
1729 TabLayout(TabsWidget tw, | 2058 TabLayout(TabsWidget tw, |
1730 Dimension wid, | 2059 Dimension wid, /* if 0, use core.width as guess */ |
1731 Dimension hgt, | 2060 Dimension hgt, /* if 0, use core.height as guess */ |
1732 Dimension *reply_height, Bool query_only) | 2061 Dimension *reply_height, Bool query_only) |
1733 { | 2062 { |
1734 int i, row, done = 0, display_rows = 0 ; | 2063 int i, row, done = 0, display_rows = 0 ; |
1735 int num_children = tw->composite.num_children ; | 2064 int num_children = tw->composite.num_children ; |
1736 Widget *childP ; | 2065 Widget *childP ; |
1737 Dimension w ; | 2066 Dimension w ; |
1738 Position x,y ; | 2067 Position x,y ; /* #### gaak, these are dimensions! */ |
1739 TabsConstraints tab ; | 2068 TabsConstraints tab ; |
1740 | 2069 |
1741 /* Algorithm: loop through children, assign X positions. If a tab | 2070 /* Algorithm: loop through children, assign X positions. If a tab |
1742 * would extend beyond the right edge, start a new row. After all | 2071 * would extend beyond the right edge, start a new row. After all |
1743 * rows are assigned, make a second pass and assign Y positions. | 2072 * rows are assigned, make a second pass and assign Y positions. |
1748 /* Loop through the tabs and see how much space they need. */ | 2077 /* Loop through the tabs and see how much space they need. */ |
1749 | 2078 |
1750 row = 0 ; | 2079 row = 0 ; |
1751 x = INDENT ; | 2080 x = INDENT ; |
1752 y = 0 ; | 2081 y = 0 ; |
1753 wid -= INDENT ; | 2082 /* If wid or hgt is 0, we want to guess our own dimensions. |
2083 Currently the guessing functions are broken.... | |
2084 #### When PreferredSize*() get fixed, fix this too. */ | |
2085 if (debug_tabs > 1) | |
2086 fprintf (stderr, "arg=%d,", wid); | |
2087 wid = (wid ? wid : tw->core.width) - INDENT ; | |
2088 hgt = hgt ? hgt : tw->core.height; | |
2089 if (debug_tabs > 1) | |
2090 fprintf (stderr, "wid=%d: x,w,y=", wid); | |
1754 for(i=num_children, childP=tw->composite.children; --i >= 0; ++childP) | 2091 for(i=num_children, childP=tw->composite.children; --i >= 0; ++childP) |
1755 if( XtIsManaged(*childP) ) | 2092 if( XtIsManaged(*childP) ) |
1756 { | 2093 { |
1757 tab = (TabsConstraints) (*childP)->core.constraints ; | 2094 tab = (TabsConstraints) (*childP)->core.constraints ; |
1758 w = tab->tabs.width ; | 2095 w = tab->tabs.width ; |
1759 | 2096 |
2097 if (debug_tabs > 1) | |
2098 fprintf (stderr, "%d,%d,%d;", x, w, y); | |
1760 if( x + w > wid ) { /* new row */ | 2099 if( x + w > wid ) { /* new row */ |
1761 if (y + tw->tabs.tab_height > hgt && !done) | 2100 /* #### algorithm is not robust to wid < child's width */ |
2101 ++row; | |
2102 x = INDENT ; | |
2103 y += tw->tabs.tab_height ; | |
2104 if (y > hgt && !done) | |
1762 { | 2105 { |
1763 display_rows = row; | 2106 display_rows = row; |
1764 done = 1; | 2107 done = 1; |
1765 } | 2108 } |
1766 ++row; | |
1767 x = INDENT ; | |
1768 y += tw->tabs.tab_height ; | |
1769 } | 2109 } |
1770 if( !query_only ) { | 2110 if( !query_only ) { |
1771 tab->tabs.x = x ; | 2111 tab->tabs.x = x ; |
1772 tab->tabs.y = y ; | 2112 tab->tabs.y = y ; |
1773 tab->tabs.row = row ; | 2113 tab->tabs.row = row ; |
1775 x += w + SPACING ; | 2115 x += w + SPACING ; |
1776 if (!query_only && !done) | 2116 if (!query_only && !done) |
1777 tab->tabs.visible = 1; | 2117 tab->tabs.visible = 1; |
1778 | 2118 |
1779 } | 2119 } |
2120 if (debug_tabs > 1) | |
2121 fprintf (stderr, "\n"); | |
1780 /* If there was only one row, increase the height by TABDELTA */ | 2122 /* If there was only one row, increase the height by TABDELTA */ |
1781 if( ++display_rows == 1 ) | 2123 if( ++display_rows == 1 ) |
1782 { | 2124 { |
1783 row++; | |
1784 y = TABDELTA ; | 2125 y = TABDELTA ; |
1785 if( !query_only ) | 2126 if( !query_only ) |
1786 for(i=num_children, childP=tw->composite.children; | 2127 for(i=num_children, childP=tw->composite.children; |
1787 --i >= 0 ; ++childP) | 2128 --i >= 0 ; ++childP) |
1788 if( XtIsManaged(*childP) ) | 2129 if( XtIsManaged(*childP) ) |
1789 { | 2130 { |
1790 tab = (TabsConstraints) (*childP)->core.constraints ; | 2131 tab = (TabsConstraints) (*childP)->core.constraints ; |
1791 tab->tabs.y = y ; | 2132 tab->tabs.y = y ; |
1792 } | 2133 } |
1793 } | 2134 } |
2135 row++; | |
1794 y += tw->tabs.tab_height ; | 2136 y += tw->tabs.tab_height ; |
1795 } | 2137 } |
1796 else | 2138 else |
1797 display_rows = row = y = 0 ; | 2139 display_rows = row = y = 0 ; |
1798 | 2140 |
1800 tw->tabs.tab_total = y ; | 2142 tw->tabs.tab_total = y ; |
1801 tw->tabs.numRows = display_rows ; | 2143 tw->tabs.numRows = display_rows ; |
1802 tw->tabs.realRows = row; | 2144 tw->tabs.realRows = row; |
1803 } | 2145 } |
1804 | 2146 |
2147 if (debug_tabs > 1 && (row > 1 || display_rows > 1)) | |
2148 fprintf (stderr, "tab: %d display rows, #children = %d," | |
2149 " total height %d, total rows %d%s.\n", | |
2150 display_rows, num_children, y, row, | |
2151 query_only ? " (query)" : ""); | |
2152 | |
1805 if( reply_height != NULL ) | 2153 if( reply_height != NULL ) |
1806 *reply_height = y ; | 2154 *reply_height = y ; |
1807 | 2155 |
1808 return display_rows ; | 2156 return display_rows ; |
1809 } | 2157 } |
1820 MaxChild(tw, NULL, 0,0) ; | 2168 MaxChild(tw, NULL, 0,0) ; |
1821 } | 2169 } |
1822 | 2170 |
1823 | 2171 |
1824 | 2172 |
1825 /* Find max preferred child size. Returned sizes include child | 2173 /* Find max preferred child size and store in control widget. |
1826 * border widths. If except is non-null, don't ask that one. | 2174 * If except is non-null, don't ask that one. |
1827 */ | 2175 */ |
1828 | 2176 |
1829 static void | 2177 static void |
1830 MaxChild(TabsWidget tw, Widget except, Dimension cw, Dimension ch) | 2178 MaxChild(TabsWidget tw, Widget except, Dimension cw, Dimension ch) |
1831 { | 2179 { |
2007 { | 2355 { |
2008 Dimension th ; /* space used by tabs */ | 2356 Dimension th ; /* space used by tabs */ |
2009 int nrows ; | 2357 int nrows ; |
2010 | 2358 |
2011 if( tw->composite.num_children > 0 ) | 2359 if( tw->composite.num_children > 0 ) |
2012 nrows = TabLayout(tw, wid, hgt, &th, True) ; | 2360 /* used to be wid, hgt not 0, 0 but that's obviously wrong |
2361 since TabLayout wants dimensions of control parent but | |
2362 wid, hgt are dimensions of some child */ | |
2363 nrows = TabLayout(tw, 0, 0, &th, True) ; | |
2013 else { | 2364 else { |
2014 th = 0 ; | 2365 th = 0 ; |
2015 nrows = 0 ; | 2366 nrows = 0 ; |
2016 } | 2367 } |
2017 | 2368 |
2089 TabsAllocFgGC(TabsWidget tw) | 2440 TabsAllocFgGC(TabsWidget tw) |
2090 { | 2441 { |
2091 Widget w = (Widget) tw; | 2442 Widget w = (Widget) tw; |
2092 XGCValues values ; | 2443 XGCValues values ; |
2093 | 2444 |
2094 values.background = tw->core.background_pixel ; | 2445 values.background = tw->core.background_pixel; |
2095 values.font = tw->tabs.font->fid ; | 2446 values.font = |
2096 values.line_style = LineOnOffDash ; | 2447 #ifdef USE_XFT_TABS |
2097 values.line_style = LineSolid ; | 2448 None; |
2449 #else | |
2450 tw->tabs.font->fid; | |
2451 #endif | |
2452 values.line_style = LineOnOffDash; | |
2453 values.line_style = LineSolid; | |
2098 | 2454 |
2099 tw->tabs.foregroundGC = | 2455 tw->tabs.foregroundGC = |
2100 XtAllocateGC(w, w->core.depth, | 2456 XtAllocateGC(w, w->core.depth, |
2101 GCBackground|GCFont|GCLineStyle, &values, | 2457 #ifndef USE_XFT_TABS |
2102 GCForeground, | 2458 GCFont| |
2103 GCSubwindowMode|GCGraphicsExposures|GCDashOffset| | 2459 #endif |
2104 GCDashList|GCArcMode) ; | 2460 GCBackground|GCLineStyle, |
2461 &values, | |
2462 GCForeground, | |
2463 #ifdef USE_XFT_TABS | |
2464 GCFont| | |
2465 #endif | |
2466 GCSubwindowMode|GCGraphicsExposures|GCDashOffset| | |
2467 GCDashList|GCArcMode); | |
2105 } | 2468 } |
2106 | 2469 |
2107 static void | 2470 static void |
2108 TabsAllocGreyGC(TabsWidget tw) | 2471 TabsAllocGreyGC(TabsWidget tw) |
2109 { | 2472 { |
2110 Widget w = (Widget) tw; | 2473 Widget w = (Widget) tw; |
2111 XGCValues values ; | 2474 XGCValues values ; |
2112 | 2475 |
2113 values.background = tw->core.background_pixel ; | 2476 values.background = tw->core.background_pixel; |
2114 values.font = tw->tabs.font->fid ; | 2477 values.font = |
2115 #ifdef HAVE_XMU | 2478 #ifdef USE_XFT_TABS |
2116 if( tw->tabs.be_nice_to_cmap || w->core.depth == 1) | 2479 None; |
2480 #else | |
2481 tw->tabs.font->fid; | |
2482 #endif | |
2483 if (tw->tabs.be_nice_to_cmap || w->core.depth == 1) | |
2117 { | 2484 { |
2118 values.fill_style = FillStippled ; | 2485 values.fill_style = FillStippled; |
2119 tw->tabs.grey50 = | 2486 tw->tabs.grey50 = |
2120 values.stipple = XmuCreateStippledPixmap(XtScreen(w), 1L, 0L, 1) ; | 2487 values.stipple = XmuCreateStippledPixmap(XtScreen(w), 1L, 0L, 1); |
2121 | 2488 |
2122 tw->tabs.greyGC = | 2489 tw->tabs.greyGC = |
2123 XtAllocateGC(w, w->core.depth, | 2490 XtAllocateGC(w, w->core.depth, |
2124 GCBackground|GCFont|GCStipple|GCFillStyle, &values, | 2491 #ifndef USE_XFT_TABS |
2492 GCFont| | |
2493 #endif | |
2494 GCBackground|GCStipple|GCFillStyle, &values, | |
2125 GCForeground, | 2495 GCForeground, |
2496 #ifdef USE_XFT_TABS | |
2497 GCFont| | |
2498 #endif | |
2126 GCSubwindowMode|GCGraphicsExposures|GCDashOffset| | 2499 GCSubwindowMode|GCGraphicsExposures|GCDashOffset| |
2127 GCDashList|GCArcMode) ; | 2500 GCDashList|GCArcMode); |
2128 } | 2501 } |
2129 else | 2502 else |
2130 #endif | |
2131 { | 2503 { |
2132 tw->tabs.greyGC = | 2504 tw->tabs.greyGC = |
2133 XtAllocateGC(w, w->core.depth, | 2505 XtAllocateGC(w, w->core.depth, |
2134 GCFont, &values, | 2506 #ifdef USE_XFT_TABS |
2507 0L, | |
2508 #else | |
2509 GCFont, | |
2510 #endif | |
2511 &values, | |
2135 GCForeground, | 2512 GCForeground, |
2513 #ifdef USE_XFT_TABS | |
2514 GCFont| | |
2515 #endif | |
2136 GCBackground|GCSubwindowMode|GCGraphicsExposures|GCDashOffset| | 2516 GCBackground|GCSubwindowMode|GCGraphicsExposures|GCDashOffset| |
2137 GCDashList|GCArcMode) ; | 2517 GCDashList|GCArcMode); |
2138 } | 2518 } |
2139 } | 2519 } |