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 }