Mercurial > hg > xemacs-beta
comparison lwlib/xlwtabs.c @ 3094:ad2f4ae9895b
[xemacs-hg @ 2005-11-26 11:45:47 by stephent]
Xft merge. <87k6ev4p8q.fsf@tleepslib.sk.tsukuba.ac.jp>
author | stephent |
---|---|
date | Sat, 26 Nov 2005 11:46:25 +0000 |
parents | facf3239ba30 |
children | 174eb4da74fb |
comparison
equal
deleted
inserted
replaced
3093:769dc945b085 | 3094:ad2f4ae9895b |
---|---|
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> |
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 |
75 /* #### This may be risky, lwlib-internal.h redefines abort() */ | |
76 #include "lwlib-fonts.h" | |
77 #include "lwlib-colors.h" | |
70 #include "lwlib-internal.h" | 78 #include "lwlib-internal.h" |
71 #include "../src/xmu.h" | 79 #include "../src/xmu.h" |
72 #include "xlwtabsP.h" | 80 #include "xlwtabsP.h" |
73 #include "xlwgcs.h" | 81 #include "xlwgcs.h" |
74 | 82 |
83 #define XFT_USE_HEIGHT_NOT_ASCENT_DESCENT 0 | |
84 | |
85 /* #### These should probably be resources. */ | |
75 #define MIN_WID 10 | 86 #define MIN_WID 10 |
76 #define MIN_HGT 10 | 87 #define MIN_HGT 10 |
77 #define INDENT 3 /* tabs indented from edge by this much */ | 88 #define INDENT 3 /* tabs indented from edge by this much */ |
78 #define SPACING 0 /* distance between tabs */ | 89 #define SPACING 0 /* distance between tabs */ |
79 #define SHADWID 1 /* default shadow width */ | 90 #define SHADWID 1 /* default shadow width */ |
136 | 147 |
137 {XtNselectInsensitive, XtCSelectInsensitive, XtRBoolean, sizeof(Boolean), | 148 {XtNselectInsensitive, XtCSelectInsensitive, XtRBoolean, sizeof(Boolean), |
138 offset(selectInsensitive), XtRImmediate, (XtPointer) True}, | 149 offset(selectInsensitive), XtRImmediate, (XtPointer) True}, |
139 {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *), | 150 {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *), |
140 offset(font), XtRString, (XtPointer) XtDefaultFont}, | 151 offset(font), XtRString, (XtPointer) XtDefaultFont}, |
152 #ifdef USE_XFT_TABS | |
153 /* #### Maybe use "-*-helvetica-bold-r-*-*-*-120-*-*-*-*-iso8859-1" here? */ | |
154 {XtNxftFont, XtCXftFont, XtRString, sizeof (String), | |
155 offset(renderFontSpec), XtRString, | |
156 (XtPointer) "AirCut-16" /* XtDefaultFont */}, | |
157 #endif | |
141 {XtNinternalWidth, XtCWidth, XtRDimension, sizeof(Dimension), | 158 {XtNinternalWidth, XtCWidth, XtRDimension, sizeof(Dimension), |
142 offset(internalWidth), XtRImmediate, (XtPointer)4 }, | 159 offset(internalWidth), XtRImmediate, (XtPointer)4 }, |
143 {XtNinternalHeight, XtCHeight, XtRDimension, sizeof(Dimension), | 160 {XtNinternalHeight, XtCHeight, XtRDimension, sizeof(Dimension), |
144 offset(internalHeight), XtRImmediate, (XtPointer)4 }, | 161 offset(internalHeight), XtRImmediate, (XtPointer)4 }, |
145 {XtNborderWidth, XtCBorderWidth, XtRDimension, sizeof(Dimension), | 162 {XtNborderWidth, XtCBorderWidth, XtRDimension, sizeof(Dimension), |
398 #define TabVisible(tab) \ | 415 #define TabVisible(tab) \ |
399 (XtIsManaged(tab) && \ | 416 (XtIsManaged(tab) && \ |
400 ((TabsConstraints)((tab)->core.constraints))->tabs.visible) | 417 ((TabsConstraints)((tab)->core.constraints))->tabs.visible) |
401 | 418 |
402 | 419 |
420 | |
421 static int debug_tabs = 0; /* increase for more verbosity */ | |
422 | |
423 #ifdef USE_XFT_TABS | |
424 /* #### duplicated from xlwmenu.c -- CLEAN THIS SHIT UP! | |
425 Undeclared so define at top. */ | |
426 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \ | |
427 ? ((unsigned long) (x)) : ((unsigned long) (y))) | |
428 | |
429 static int | |
430 x_xft_text_width (Display *dpy, XftFont *xft_font, FcChar8 *run, int len) | |
431 { | |
432 static XGlyphInfo glyphinfo; /* #### static? */ | |
433 | |
434 XftTextExtents8 (dpy, | |
435 xft_font, | |
436 run, len, &glyphinfo); | |
437 return glyphinfo.xOff; | |
438 } | |
439 #endif | |
440 | |
403 /**************************************************************** | 441 /**************************************************************** |
404 * | 442 * |
405 * Member Procedures | 443 * Member Procedures |
406 * | 444 * |
407 ****************************************************************/ | 445 ****************************************************************/ |
434 /* height is easy, it's the same for all tabs: | 472 /* height is easy, it's the same for all tabs: |
435 * TODO: font height + height of tallest bitmap. | 473 * TODO: font height + height of tallest bitmap. |
436 */ | 474 */ |
437 newTw->tabs.tab_height = 2 * newTw->tabs.internalHeight + SHADWID ; | 475 newTw->tabs.tab_height = 2 * newTw->tabs.internalHeight + SHADWID ; |
438 | 476 |
439 if( newTw->tabs.font != NULL ) | 477 #ifdef USE_XFT_TABS |
478 /* must get font here | |
479 to do this right, we should add a new Xt Resource type + | |
480 conversion function | |
481 */ | |
482 newTw->tabs.renderFont = | |
483 xft_open_font_by_name (XtDisplay ((Widget) newTw), | |
484 newTw->tabs.renderFontSpec); | |
485 if (newTw->tabs.renderFont != NULL) | |
486 #if XFT_USE_HEIGHT_NOT_ASCENT_DESCENT | |
487 newTw->tabs.tab_height += newTw->tabs.renderFont->height; | |
488 #else | |
489 newTw->tabs.tab_height += newTw->tabs.renderFont->ascent + | |
490 newTw->tabs.renderFont->descent; | |
491 #endif /* XFT_USE_HEIGHT_NOT_ASCENT_DESCENT */ | |
492 #else /* ! USE_XFT_TABS */ | |
493 if (newTw->tabs.font != NULL) | |
440 newTw->tabs.tab_height += newTw->tabs.font->max_bounds.ascent + | 494 newTw->tabs.tab_height += newTw->tabs.font->max_bounds.ascent + |
441 newTw->tabs.font->max_bounds.descent ; | 495 newTw->tabs.font->max_bounds.descent; |
442 | 496 #endif /* ! USE_XFT_TABS */ |
443 /* GC allocation is deferred until XtRealize() */ | |
444 | 497 |
445 /* if size not explicitly set, set it to our preferred size now. */ | 498 /* if size not explicitly set, set it to our preferred size now. */ |
446 | 499 |
447 if( request->core.width == 0 || request->core.height == 0 ) | 500 if( request->core.width == 0 || request->core.height == 0 ) |
448 { | 501 { |
612 TabsWidget tw = (TabsWidget) new_ ; | 665 TabsWidget tw = (TabsWidget) new_ ; |
613 Boolean needRedraw = False ; | 666 Boolean needRedraw = False ; |
614 Widget *childP ; | 667 Widget *childP ; |
615 int i ; | 668 int i ; |
616 | 669 |
617 | 670 if( |
618 if( tw->tabs.font != curtw->tabs.font || | 671 #ifdef USE_XFT_TABS |
619 tw->tabs.internalWidth != curtw->tabs.internalWidth || | 672 tw->tabs.renderFont != curtw->tabs.renderFont || |
620 tw->tabs.internalHeight != curtw->tabs.internalHeight ) | 673 #else |
674 tw->tabs.font != curtw->tabs.font || | |
675 #endif | |
676 tw->tabs.internalWidth != curtw->tabs.internalWidth || | |
677 tw->tabs.internalHeight != curtw->tabs.internalHeight) | |
621 { | 678 { |
622 tw->tabs.tab_height = 2 * tw->tabs.internalHeight + SHADWID ; | 679 tw->tabs.tab_height = 2 * tw->tabs.internalHeight + SHADWID; |
623 | 680 |
624 if( tw->tabs.font != NULL ) | 681 #ifdef USE_XFT_TABS |
682 if (tw->tabs.renderFont != NULL) | |
683 #if XFT_USE_HEIGHT_NOT_ASCENT_DESCENT | |
684 tw->tabs.tab_height += tw->tabs.renderFont->height; | |
685 #else | |
686 tw->tabs.tab_height += tw->tabs.renderFont->ascent + | |
687 tw->tabs.renderFont->descent; | |
688 #endif /* XFT_USE_HEIGHT_NOT_ASCENT_DESCENT */ | |
689 #else /* ! USE_XFT_TABS */ | |
690 if (tw->tabs.font != NULL) | |
625 tw->tabs.tab_height += tw->tabs.font->max_bounds.ascent + | 691 tw->tabs.tab_height += tw->tabs.font->max_bounds.ascent + |
626 tw->tabs.font->max_bounds.descent ; | 692 tw->tabs.font->max_bounds.descent; |
693 #endif /* ! USE_XFT_TABS */ | |
627 | 694 |
628 /* Tab size has changed. Resize all tabs and request a new size */ | 695 /* Tab size has changed. Resize all tabs and request a new size */ |
629 for(i=0, childP=tw->composite.children; | 696 for(i=0, childP=tw->composite.children; |
630 i < (int) tw->composite.num_children; | 697 i < (int) tw->composite.num_children; |
631 ++i, ++childP) | 698 ++i, ++childP) |
638 | 705 |
639 /* TODO: if any color changes, need to recompute GCs and redraw */ | 706 /* TODO: if any color changes, need to recompute GCs and redraw */ |
640 | 707 |
641 if( tw->core.background_pixel != curtw->core.background_pixel || | 708 if( tw->core.background_pixel != curtw->core.background_pixel || |
642 tw->core.background_pixmap != curtw->core.background_pixmap || | 709 tw->core.background_pixmap != curtw->core.background_pixmap || |
643 tw->tabs.font != curtw->tabs.font ) | 710 #ifdef USE_XFT_TABS |
711 tw->tabs.renderFont != curtw->tabs.renderFont | |
712 #else | |
713 tw->tabs.font != curtw->tabs.font | |
714 #endif | |
715 ) | |
644 if( XtIsRealized(new_) ) | 716 if( XtIsRealized(new_) ) |
645 { | 717 { |
646 TabsFreeGCs(tw) ; | 718 TabsFreeGCs(tw) ; |
647 TabsAllocGCs(tw) ; | 719 TabsAllocGCs(tw) ; |
648 needRedraw = True ; | 720 needRedraw = True ; |
753 } | 825 } |
754 | 826 |
755 | 827 |
756 | 828 |
757 /* | 829 /* |
758 * Return preferred size. Happily accept anything >= our preferred size. | 830 * Return status, with preferred size in PREFERRED. |
759 * (TODO: is that the right thing to do? Should we always return "almost" | 831 * |
760 * if offered more than we need?) | 832 * According to the X Toolkit Intrinsics manual |
833 * XtGeometryYes = accept INTENDED without change | |
834 * XtGeometryNo = request to stay _exactly_ the same | |
835 * XtGeometryAlmost = suggest PREFERRED as a compromise | |
836 * and the PREFERRED argument must be filled in completely (ie, any fields | |
837 * whose bits are set in the request_mode mask must correspond to the | |
838 * preferred geometry, which must be consistent with the return value). | |
839 * | |
840 * Assuming horizontal orientation, in XEmacs, we should always accept if | |
841 * the width is more than we need. There's no problem if there are only a | |
842 * couple of tabs packed to the left. OTOH there's probably something wrong | |
843 * if we're offered a height more than 1.5x or 2x the preferred height. | |
844 * (#### Do tab controls do vertical?) | |
761 */ | 845 */ |
762 | 846 |
847 /* compute the height above which we complain */ | |
848 #define TAB_HEIGHT_TOLERANCE(x) (2*x) | |
849 | |
763 static XtGeometryResult | 850 static XtGeometryResult |
764 TabsQueryGeometry(Widget w, | 851 TabsQueryGeometry (Widget w, |
765 XtWidgetGeometry *intended, XtWidgetGeometry *preferred) | 852 XtWidgetGeometry *intended, |
766 { | 853 XtWidgetGeometry *preferred) /* RETURN */ |
767 register TabsWidget tw = (TabsWidget)w ; | 854 { |
768 XtGeometryMask mode = intended->request_mode ; | 855 TabsWidget tw = (TabsWidget) w; |
769 | 856 XtGeometryMask mode = intended->request_mode; |
770 preferred->request_mode = CWWidth | CWHeight ; | 857 |
771 PreferredSize(tw, &preferred->width, &preferred->height, NULL,NULL) ; | 858 preferred->request_mode = CWWidth | CWHeight; |
772 | 859 PreferredSize (tw, &preferred->width, &preferred->height, NULL, NULL); |
773 if( (!(mode & CWWidth) || intended->width == w->core.width) && | 860 |
774 (!(mode & CWHeight) || intended->height == w->core.height) ) | 861 /* If width is big enough, accept it. */ |
775 return XtGeometryNo ; | 862 if ((mode & CWWidth) && intended->width >= preferred->width) |
776 | 863 preferred->width = intended->width; |
777 if( (!(mode & CWWidth) || intended->width >= preferred->width) && | 864 |
778 (!(mode & CWHeight) || intended->height >= preferred->height) ) | 865 /* If height is within range, accept it. |
866 #### If too tall, we could offer a compromise at TAB_HEIGHT_TOLERANCE. | |
867 Should we? */ | |
868 if ((mode & CWHeight) && intended->height >= preferred->height | |
869 && intended->height <= TAB_HEIGHT_TOLERANCE (preferred->height)) | |
870 preferred->height = intended->height; | |
871 | |
872 /* Compute return value. */ | |
873 if (preferred->width == ((mode & CWWidth) ? intended->width | |
874 : w->core.width) | |
875 && preferred->height == ((mode & CWHeight) ? intended->height | |
876 : w->core.height)) | |
779 return XtGeometryYes; | 877 return XtGeometryYes; |
780 | 878 else if (preferred->width == w->core.width |
781 return XtGeometryAlmost; | 879 && preferred->height == w->core.height) |
880 return XtGeometryNo; | |
881 else | |
882 return XtGeometryAlmost; | |
782 } | 883 } |
783 | 884 |
784 | 885 |
785 | 886 |
786 /* | 887 /* |
787 * Geometry Manager; called when a child wants to be resized. | 888 * Geometry Manager; called when TAB (a child) wants to be resized. |
889 * | |
890 * According to the X Toolkit Intrinsics manual | |
891 * XtGeometryDone = accept REQUEST and do it (#### check this) | |
892 * XtGeometryYes = accept REQUEST without change | |
893 * XtGeometryNo = refuse REQUEST (ie, stay _exactly_ the same) | |
894 * XtGeometryAlmost = suggest REPLY as a compromise | |
788 */ | 895 */ |
789 | 896 |
790 static XtGeometryResult | 897 static XtGeometryResult |
791 TabsGeometryManager(Widget w, XtWidgetGeometry *req, XtWidgetGeometry *reply) | 898 TabsGeometryManager (Widget tab, |
792 { | 899 XtWidgetGeometry *request, |
793 TabsWidget tw = (TabsWidget) XtParent(w); | 900 XtWidgetGeometry *reply) /* RETURN */ |
794 Dimension s = SHADWID ; | 901 { |
795 TabsConstraints tab = (TabsConstraints)w->core.constraints; | 902 TabsWidget control = (TabsWidget) XtParent(tab); |
796 XtGeometryResult result ; | 903 Dimension s = SHADWID; |
797 Dimension rw, rh ; | 904 TabsConstraints constraint = (TabsConstraints) tab->core.constraints; |
798 | 905 XtGeometryResult result, best_offer = XtGeometryYes; |
799 /* Position request always denied */ | 906 Dimension rw, rh; |
800 | 907 |
801 if( ((req->request_mode & CWX) && req->x != w->core.x) || | 908 static int debug_count = 0; |
802 ((req->request_mode & CWY) && req->y != w->core.y) || | 909 static int debug_mask = 1; |
803 !tab->tabs.resizable ) | 910 |
804 return XtGeometryNo ; | 911 /* Position request cannot be satisfied, so if tabs are not resizable, |
805 | 912 no nontrivial request can be satisfied: return XGeometryNo. */ |
806 /* Make all three fields in the request valid */ | 913 if (!constraint->tabs.resizable) |
807 if( !(req->request_mode & CWWidth) ) | 914 return XtGeometryNo; |
808 req->width = w->core.width; | 915 |
809 if( !(req->request_mode & CWHeight) ) | 916 fprintf (stderr, "Urk! label is resizable!\n"); |
810 req->height = w->core.height; | 917 |
811 if( !(req->request_mode & CWBorderWidth) ) | 918 /* Assume we will refuse these; toggle iff we accept them. |
812 req->border_width = w->core.border_width; | 919 Reply won't specify any fields not in the request. */ |
813 | 920 reply->request_mode = request->request_mode; |
814 if( req->width == w->core.width && | 921 reply->x = tab->core.x; |
815 req->height == w->core.height && | 922 reply->y = tab->core.y; |
816 req->border_width == w->core.border_width ) | 923 |
817 return XtGeometryNo ; | 924 /* If a position request would result in a change, best offer is |
818 | 925 XtGeometryAlmost. Otherwise toggle reply->request_mode. */ |
819 rw = req->width + 2 * req->border_width ; | 926 if ((request->request_mode & CWX) && request->x != tab->core.x) |
820 rh = req->height + 2 * req->border_width ; | 927 best_offer = XtGeometryAlmost; |
928 else | |
929 reply->request_mode &= ~CWX; | |
930 if ((request->request_mode & CWY) && request->y != tab->core.y) | |
931 best_offer = XtGeometryAlmost; | |
932 else | |
933 reply->request_mode &= ~CWY; | |
934 | |
935 /* Make all three fields in the reply valid */ | |
936 reply->width = (request->request_mode & CWWidth) | |
937 ? request->width : tab->core.width; | |
938 reply->height = (request->request_mode & CWHeight) | |
939 ? request->height : tab->core.height; | |
940 reply->border_width = (request->request_mode & CWBorderWidth) | |
941 ? request->border_width : tab->core.border_width; | |
942 | |
943 /* check if we can already offer a compromise */ | |
944 if (best_offer == XtGeometryAlmost && | |
945 reply->width == tab->core.width && | |
946 reply->height == tab->core.height && | |
947 reply->border_width == tab->core.border_width) | |
948 { | |
949 reply->request_mode &= ~(CWWidth | CWHeight | CWBorderWidth); | |
950 return best_offer; | |
951 } | |
952 | |
953 #ifndef DONT_DEBUG_REQUESTS | |
954 #define DBG_REQUEST_PRINT(name,field,size) \ | |
955 do { \ | |
956 if (reply->field > size) \ | |
957 { \ | |
958 if (++debug_count == debug_mask) \ | |
959 { \ | |
960 debug_mask <<= 1; \ | |
961 fprintf (stderr, "ridiculous %s request #%d: %d > %d\n", \ | |
962 name, debug_count, reply->field, size); \ | |
963 } \ | |
964 reply->field = tab->core.field; \ | |
965 } \ | |
966 } while (0) | |
967 | |
968 DBG_REQUEST_PRINT ("width",width,1024); | |
969 DBG_REQUEST_PRINT ("height",height,768); | |
970 DBG_REQUEST_PRINT ("border_width",border_width,30); | |
971 #undef DBG_REQUEST_PRINT | |
972 #endif | |
973 | |
974 rw = reply->width + 2 * reply->border_width; | |
975 rh = reply->height + 2 * reply->border_width; | |
821 | 976 |
822 /* find out how big the children want to be now */ | 977 /* find out how big the children want to be now */ |
823 MaxChild(tw, w, rw, rh) ; | 978 MaxChild (control, tab, rw, rh); |
824 | 979 |
825 | 980 |
826 /* Size changes must see if the new size can be accommodated. | 981 /* Size changes must see if the new size can be accommodated. |
827 * The Tabs widget keeps all of its children the same | 982 * The Tabs widget keeps all of its children the same height, but |
828 * size. A request to shrink will be accepted only if the | 983 * widths may vary. |
984 * A request to shrink will be accepted only if the | |
829 * new size is still big enough for all other children. A | 985 * new size is still big enough for all other children. A |
830 * request to shrink that is not big enough for all children | 986 * request to shrink that is not big enough for all children |
831 * returns an "almost" response with the new proposed size | 987 * returns an "almost" response with the new proposed size |
832 * or a "no" response if unable to shrink at all. | 988 * or a "no" response if unable to shrink at all. |
833 * | 989 * |
834 * A request to grow will be accepted only if the Tabs parent can | 990 * A request to grow will be accepted only if the Tabs control can |
835 * grow to accommodate. | 991 * grow to accommodate. |
836 * | 992 * |
837 * TODO: | 993 * TODO: |
838 * We could get fancy here and re-arrange the tabs if it is | 994 * 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 | 995 * necessary to compromise with the parent, but we'll save that |
840 * for another day. | 996 * for another day. |
841 */ | 997 */ |
842 | 998 |
843 if (req->request_mode & (CWWidth | CWHeight | CWBorderWidth)) | 999 if (request->request_mode & (CWWidth | CWHeight | CWBorderWidth)) |
844 { | 1000 { |
845 Dimension cw,ch ; /* children's preferred size */ | 1001 Dimension cw,ch ; /* children's preferred size */ |
846 Dimension aw,ah ; /* available size we can give child */ | 1002 Dimension aw,ah ; /* available size we can give child */ |
847 Dimension th ; /* space used by tabs */ | 1003 Dimension th ; /* space used by tabs */ |
848 Dimension wid,hgt ; /* Tabs widget size */ | 1004 Dimension wid,hgt ; /* Tabs widget size */ |
849 | 1005 int check_nrows; |
850 cw = tw->tabs.max_cw ; | 1006 |
851 ch = tw->tabs.max_ch ; | 1007 cw = control->tabs.max_cw ; |
1008 ch = control->tabs.max_ch ; | |
852 | 1009 |
853 /* find out what *my* resulting preferred size would be */ | 1010 /* find out what *my* resulting preferred size would be */ |
854 | 1011 /* #### this whole API is wrong; what should happen is |
855 PreferredSize2(tw, cw, ch, &wid, &hgt) ; | 1012 1. app should hint as to #rows and/or aspect ratio |
1013 2. tab control should attempt to layout in current space | |
1014 3. if not all tabs fit, should request resize to achieve | |
1015 layout hints | |
1016 Probably can and should cache preferred size in widget, with | |
1017 cache cleared when labels or core size changes. */ | |
1018 PreferredSize2(control, cw, ch, &wid, &hgt) ; | |
856 | 1019 |
857 /* Would my size change? If so, ask to be resized. */ | 1020 /* Would my size change? If so, ask to be resized. */ |
858 | 1021 |
859 if( wid != tw->core.width || hgt != tw->core.height ) | 1022 if (wid != control->core.width || hgt != control->core.height) |
860 { | 1023 { |
861 Dimension oldWid = tw->core.width, oldHgt = tw->core.height ; | 1024 Dimension oldWid = control->core.width, |
1025 oldHgt = control->core.height; | |
862 XtWidgetGeometry myrequest, myreply ; | 1026 XtWidgetGeometry myrequest, myreply ; |
863 | 1027 |
864 myrequest.width = wid ; | 1028 myrequest.width = wid ; |
865 myrequest.height = hgt ; | 1029 myrequest.height = hgt ; |
866 myrequest.request_mode = CWWidth | CWHeight ; | 1030 myrequest.request_mode = CWWidth | CWHeight ; |
868 assert (wid > 0 && hgt > 0); | 1032 assert (wid > 0 && hgt > 0); |
869 /* If child is only querying, or if we're going to have to | 1033 /* 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. | 1034 * offer the child a compromise, then make this a query only. |
871 */ | 1035 */ |
872 | 1036 |
873 if( (req->request_mode & XtCWQueryOnly) || rw < cw || rh < ch ) | 1037 if ((request->request_mode & XtCWQueryOnly) || rw < cw || rh < ch) |
874 myrequest.request_mode |= XtCWQueryOnly ; | 1038 myrequest.request_mode |= XtCWQueryOnly; |
875 | 1039 |
876 result = XtMakeGeometryRequest((Widget)tw, &myrequest, &myreply) ; | 1040 result = XtMakeGeometryRequest ((Widget) control, |
1041 &myrequest, &myreply); | |
877 | 1042 |
878 /* !$@# Athena Box widget changes the core size even if QueryOnly | 1043 /* !$@# 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 | 1044 * 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 | 1045 * around the bug, we need to restore the core size after every |
881 * query geometry request. This is only partly effective, | 1046 * query geometry request. This is only partly effective, |
882 * as there may be other boxes further up the tree. | 1047 * as there may be other boxes further up the tree. |
883 */ | 1048 */ |
884 if( myrequest.request_mode & XtCWQueryOnly ) { | 1049 if (myrequest.request_mode & XtCWQueryOnly) { |
885 tw->core.width = oldWid ; | 1050 control->core.width = oldWid; |
886 tw->core.height = oldHgt ; | 1051 control->core.height = oldHgt; |
887 } | 1052 } |
888 | 1053 |
889 /* based on the parent's response, determine what the | 1054 /* based on the parent's response, determine what the |
890 * resulting Tabs widget size would be. | 1055 * resulting Tabs widget size would be. |
891 */ | 1056 */ |
892 | 1057 |
893 switch( result ) { | 1058 switch (result) { |
894 case XtGeometryYes: | 1059 case XtGeometryYes: |
895 case XtGeometryDone: | 1060 case XtGeometryDone: |
896 tw->tabs.needs_layout = True ; | 1061 control->tabs.needs_layout = True; |
897 break ; | 1062 break; |
898 | 1063 |
899 case XtGeometryNo: | 1064 case XtGeometryNo: |
900 wid = tw->core.width ; | 1065 wid = control->core.width; |
901 hgt = tw->core.height ; | 1066 hgt = control->core.height; |
902 break ; | 1067 break; |
903 | 1068 |
904 case XtGeometryAlmost: | 1069 case XtGeometryAlmost: |
905 wid = myreply.width ; | 1070 wid = myreply.width; |
906 hgt = myreply.height ; | 1071 hgt = myreply.height; |
907 tw->tabs.needs_layout = True ; | 1072 control->tabs.needs_layout = True; |
908 break ; | 1073 break; |
909 } | 1074 } |
910 } | 1075 } |
911 | 1076 |
912 /* Within the constraints imposed by the parent, what is | 1077 /* Within the constraints imposed by the parent, what is |
913 * the max size we can give the child? | 1078 * the max size we can give the child? |
914 */ | 1079 */ |
915 (void) TabLayout(tw, wid, hgt, &th, True) ; | 1080 check_nrows = TabLayout (control, wid, hgt, &th, True); |
916 aw = wid - 2*s ; | 1081 aw = wid - 2*s; |
917 ah = hgt - th - 2*s ; | 1082 if (check_nrows == 1) |
1083 { | |
1084 ah = hgt - th - 2*s; | |
1085 } | |
1086 else | |
1087 { | |
1088 /* this rarely gets triggered, but when it does it seems to | |
1089 get triggered forever after */ | |
1090 int n = control->composite.num_children; | |
1091 ah = control->tabs.tab_height; | |
1092 if (debug_tabs > 0) | |
1093 fprintf (stderr, "Kludging around %d != 1 rows," | |
1094 " #children = %d, total height %d, using %d.\n", | |
1095 check_nrows, n, th, ah); | |
1096 } | |
918 | 1097 |
919 /* OK, make our decision. If requested size is >= max sibling | 1098 /* OK, make our decision. If requested size is >= max sibling |
920 * preferred size, AND requested size <= available size, then | 1099 * preferred size, AND requested size <= available size, then |
921 * we accept. Otherwise, we offer a compromise. | 1100 * we accept. Otherwise, we offer a compromise. |
922 */ | 1101 */ |
923 | 1102 |
924 if( rw == aw && rh == ah ) | 1103 if (rw == aw && rh == ah) |
925 { | 1104 { |
926 /* Acceptable. If this wasn't a query, change *all* children | 1105 /* Acceptable. If this wasn't a query, change *all* children |
927 * to this size. | 1106 * to this size. |
928 */ | 1107 */ |
929 if( req->request_mode & XtCWQueryOnly ) | 1108 if (request->request_mode & XtCWQueryOnly) |
930 return XtGeometryYes ; | 1109 { |
1110 control->tabs.needs_layout = False; | |
1111 return XtGeometryYes ; | |
1112 } | |
931 else | 1113 else |
932 { | 1114 { |
933 Widget *childP = tw->composite.children ; | 1115 Widget *childP = control->composite.children; |
934 int i,bw ; | 1116 int i, bw; |
935 w->core.border_width = req->border_width ; | 1117 tab->core.border_width = request->border_width; |
936 for(i=TabsNumChildren (tw); --i >= 0; ++childP) | 1118 for (i = TabsNumChildren (control); --i >= 0; ++childP) |
937 if( TabVisible(*childP) ) | 1119 if (TabVisible (*childP)) |
938 { | 1120 { |
939 bw = (*childP)->core.border_width ; | 1121 bw = (*childP)->core.border_width; |
940 XtConfigureWidget(*childP, s,tw->tabs.tab_total+s, | 1122 XtConfigureWidget (*childP, s, control->tabs.tab_total+s, |
941 rw-2*bw, rh-2*bw, bw) ; | 1123 rw-2*bw, rh-2*bw, bw); |
942 } | 1124 } |
943 #ifdef COMMENT | 1125 #ifdef COMMENT |
944 /* TODO: under what conditions will we need to redraw? */ | 1126 /* TODO: under what conditions will we need to redraw? */ |
945 XClearWindow(XtDisplay((Widget)tw), XtWindow((Widget)tw)) ; | 1127 XClearWindow (XtDisplay ((Widget) control), |
946 XtClass(tw)->core_class.expose((Widget)tw,NULL,NULL) ; | 1128 XtWindow ((Widget) control)); |
1129 XtClass (control)->core_class.expose ((Widget)control, | |
1130 NULL, NULL); | |
947 #endif /* COMMENT */ | 1131 #endif /* COMMENT */ |
948 return XtGeometryDone ; | 1132 return XtGeometryDone; |
949 } | 1133 } |
950 } | 1134 } |
951 | 1135 |
952 /* Cannot grant child's request. Describe what we *can* do | 1136 /* Cannot grant child's request. Describe what we *can* do |
953 * and return counter-offer. | 1137 * and return counter-offer. |
954 */ | 1138 */ |
955 reply->width = aw - 2 * req->border_width ; | 1139 control->tabs.needs_layout = False; |
956 reply->height = ah - 2 * req->border_width ; | 1140 reply->width = aw - 2 * request->border_width ; |
957 reply->border_width = req->border_width ; | 1141 reply->height = ah - 2 * request->border_width ; |
958 reply->request_mode = CWWidth | CWHeight | CWBorderWidth ; | 1142 reply->request_mode &= |
1143 ~((reply->border_width == tab->core.border_width | |
1144 ? CWBorderWidth : 0) | |
1145 |(reply->width == tab->core.width ? CWWidth : 0) | |
1146 |(reply->height == tab->core.height ? CWHeight : 0)); | |
959 return XtGeometryAlmost ; | 1147 return XtGeometryAlmost ; |
960 } | 1148 } |
961 | 1149 |
962 return XtGeometryYes ; | 1150 return XtGeometryYes ; |
963 } | 1151 } |
1426 DrawTab(TabsWidget tw, Widget child, Bool labels) | 1614 DrawTab(TabsWidget tw, Widget child, Bool labels) |
1427 { | 1615 { |
1428 GC gc ; | 1616 GC gc ; |
1429 int x,y ; | 1617 int x,y ; |
1430 | 1618 |
1619 if (debug_tabs > 1) fprintf (stderr, "DrawTab called.\n"); | |
1620 | |
1431 if( !XtIsRealized((Widget)tw)) | 1621 if( !XtIsRealized((Widget)tw)) |
1432 return ; | 1622 return ; |
1433 | 1623 |
1434 DrawBorder(tw, child, False) ; | 1624 DrawBorder(tw, child, False) ; |
1435 | 1625 |
1438 TabsConstraints tab = (TabsConstraints)child->core.constraints; | 1628 TabsConstraints tab = (TabsConstraints)child->core.constraints; |
1439 Display *dpy = XtDisplay((Widget)tw) ; | 1629 Display *dpy = XtDisplay((Widget)tw) ; |
1440 Window win = XtWindow((Widget)tw) ; | 1630 Window win = XtWindow((Widget)tw) ; |
1441 String lbl = tab->tabs.label != NULL ? | 1631 String lbl = tab->tabs.label != NULL ? |
1442 tab->tabs.label : XtName(child) ; | 1632 tab->tabs.label : XtName(child) ; |
1443 | 1633 #ifdef USE_XFT_TABS |
1444 if( XtIsSensitive(child) ) | 1634 XftColor color; |
1635 XftColor colorBG; | |
1636 Colormap cmap = tw->core.colormap; | |
1637 Visual *visual; | |
1638 int ignored; | |
1639 | |
1640 visual_info_from_widget ((Widget) tw, &visual, &ignored); | |
1641 colorBG = xft_convert_color (dpy, cmap, visual, | |
1642 tw->core.background_pixel, 0); | |
1643 #endif | |
1644 | |
1645 if (debug_tabs > 2) | |
1646 fprintf (stderr, "(Re)drawing labels.\n"); | |
1647 | |
1648 if (XtIsSensitive(child)) | |
1445 { | 1649 { |
1446 gc = tw->tabs.foregroundGC ; | 1650 gc = tw->tabs.foregroundGC; |
1447 XSetForeground(dpy, gc, tab->tabs.foreground) ; | 1651 #ifdef USE_XFT_TABS |
1652 color = xft_convert_color (dpy, cmap, visual, | |
1653 tab->tabs.foreground, 0); | |
1654 #else | |
1655 XSetForeground(dpy, gc, tab->tabs.foreground); | |
1656 #endif | |
1448 } | 1657 } |
1449 else | 1658 else |
1450 { | 1659 { |
1451 /* grey pixel allocation deferred until now */ | 1660 /* grey pixel allocation deferred until now */ |
1452 if( !tab->tabs.greyAlloc ) | 1661 if (!tab->tabs.greyAlloc) |
1453 { | 1662 { |
1454 if( tw->tabs.be_nice_to_cmap || tw->core.depth == 1 ) | 1663 if (tw->tabs.be_nice_to_cmap || tw->core.depth == 1) |
1455 tab->tabs.grey = tab->tabs.foreground ; | 1664 tab->tabs.grey = tab->tabs.foreground; |
1456 else | 1665 else |
1457 tab->tabs.grey = AllocGreyPixel((Widget)tw, | 1666 tab->tabs.grey = AllocGreyPixel ((Widget) tw, |
1458 tab->tabs.foreground, | 1667 tab->tabs.foreground, |
1459 tw->core.background_pixel, | 1668 tw->core.background_pixel, |
1460 tw->tabs.insensitive_contrast ) ; | 1669 tw->tabs.insensitive_contrast); |
1461 tab->tabs.greyAlloc = True ; | 1670 tab->tabs.greyAlloc = True; |
1462 } | 1671 } |
1463 gc = tw->tabs.greyGC ; | 1672 gc = tw->tabs.greyGC; |
1464 XSetForeground(dpy, gc, tab->tabs.grey) ; | 1673 #ifdef USE_XFT_TABS |
1674 color = xft_convert_color (dpy, cmap, visual, tab->tabs.grey, 0); | |
1675 #else | |
1676 XSetForeground(dpy, gc, tab->tabs.grey); | |
1677 #endif | |
1465 } | 1678 } |
1466 | 1679 |
1467 x = tab->tabs.x ; | 1680 x = tab->tabs.x; |
1468 y = tab->tabs.y ; | 1681 y = tab->tabs.y; |
1469 if( child == tw->tabs.topWidget ) | 1682 if (child == tw->tabs.topWidget) |
1470 y -= TABLDELTA ; | 1683 y -= TABLDELTA; |
1471 | 1684 |
1472 if( tab->tabs.left_bitmap != None && tab->tabs.lbm_width > 0 ) | 1685 if (tab->tabs.left_bitmap != None && tab->tabs.lbm_width > 0) |
1473 { | 1686 { |
1474 if( tab->tabs.lbm_depth == 1 ) | 1687 if (tab->tabs.lbm_depth == 1) |
1475 XCopyPlane(dpy, tab->tabs.left_bitmap, win,gc, | 1688 XCopyPlane(dpy, tab->tabs.left_bitmap, win,gc, |
1476 0,0, tab->tabs.lbm_width, tab->tabs.lbm_height, | 1689 0,0, tab->tabs.lbm_width, tab->tabs.lbm_height, |
1477 x+tab->tabs.lbm_x, y+tab->tabs.lbm_y, 1L) ; | 1690 x+tab->tabs.lbm_x, y+tab->tabs.lbm_y, 1L); |
1478 else | 1691 else |
1479 XCopyArea(dpy, tab->tabs.left_bitmap, win,gc, | 1692 XCopyArea(dpy, tab->tabs.left_bitmap, win,gc, |
1480 0,0, tab->tabs.lbm_width, tab->tabs.lbm_height, | 1693 0,0, tab->tabs.lbm_width, tab->tabs.lbm_height, |
1481 x+tab->tabs.lbm_x, y+tab->tabs.lbm_y) ; | 1694 x+tab->tabs.lbm_x, y+tab->tabs.lbm_y); |
1482 } | 1695 } |
1483 | 1696 |
1484 if( lbl != NULL && tw->tabs.font != NULL ) | 1697 if (lbl != NULL && |
1485 XDrawString(dpy,win,gc, | 1698 #ifdef USE_XFT_TABS |
1486 x+tab->tabs.l_x, y+tab->tabs.l_y, | 1699 tw->tabs.renderFont != NULL |
1487 lbl, (int)strlen(lbl)) ; | 1700 #else |
1488 } | 1701 tw->tabs.font != NULL |
1489 | 1702 #endif |
1490 if( child == tw->tabs.hilight ) | 1703 ) |
1491 DrawHighlight(tw, child, False) ; | 1704 { |
1705 #ifdef USE_XFT_TABS | |
1706 XftDraw *xftDraw = XftDrawCreate (dpy, win, visual, cmap); | |
1707 XftFont *renderFont = tw->tabs.renderFont; | |
1708 XGlyphInfo glyphinfo; | |
1709 XftColor colorDBG; | |
1710 XftColorAllocName (dpy, visual, cmap, "wheat", &colorDBG); | |
1711 XftTextExtents8 (dpy, renderFont, lbl, (int) strlen (lbl), | |
1712 &glyphinfo); | |
1713 /* #### unnecessary? for the moment, give visual extent */ | |
1714 /* draw background rect */ | |
1715 #if 1 | |
1716 if (debug_tabs > 2) | |
1717 { | |
1718 fprintf (stderr, "background color: pixel=%08lx, r=%04x," | |
1719 " g=%04x, b=%04x, alpha=%04x.\n", | |
1720 colorDBG.pixel, colorDBG.color.red, | |
1721 colorDBG.color.green, colorDBG.color.blue, | |
1722 colorDBG.color.alpha); | |
1723 fprintf (stderr, "label geometry: x=%d, y=%d, xOff=%d," | |
1724 " yOff=%d, width=%d, height=%d\n", | |
1725 glyphinfo.x, glyphinfo.y, glyphinfo.xOff, | |
1726 glyphinfo.yOff, glyphinfo.width, glyphinfo.height); | |
1727 } | |
1728 XftDrawRect (xftDraw, &colorDBG, | |
1729 /* left, top, width, height */ | |
1730 x+tab->tabs.l_x-glyphinfo.x, | |
1731 y+tab->tabs.l_y-glyphinfo.y, | |
1732 glyphinfo.width, glyphinfo.height); | |
1733 #endif | |
1734 /* draw text */ | |
1735 if (debug_tabs > 2) | |
1736 { | |
1737 FcValue name; | |
1738 FcValue size; | |
1739 FcPatternGet (renderFont->pattern, FC_FAMILY, 0, &name); | |
1740 FcPatternGet (renderFont->pattern, FC_SIZE, 0, &size); | |
1741 fprintf (stderr, "label: %s.\n", lbl); | |
1742 fprintf (stderr, "foreground color: pixel=%08lx, r=%04x," | |
1743 " g=%04x, b=%04x, alpha=%04x.\n", | |
1744 color.pixel, color.color.red, color.color.green, | |
1745 color.color.blue, color.color.alpha); | |
1746 fprintf (stderr, "extent: x=%d, y=%d, xOffset=%d," | |
1747 " yOffset=%d, height=%d, width=%d.\n", | |
1748 glyphinfo.x, glyphinfo.y, glyphinfo.xOff, | |
1749 glyphinfo.yOff, glyphinfo.height, glyphinfo.width); | |
1750 fprintf (stderr, "font: name=%s-%.1f," | |
1751 " height=%d, ascent=%d, descent=%d.\n", | |
1752 name.u.s, size.u.d, renderFont->height, | |
1753 renderFont->ascent, renderFont->descent); | |
1754 } | |
1755 XftDrawString8 (xftDraw, &color, renderFont, | |
1756 x+tab->tabs.l_x, y+tab->tabs.l_y, | |
1757 lbl, (int) strlen (lbl)); | |
1758 XftDrawDestroy (xftDraw); | |
1759 #else | |
1760 XDrawString(dpy,win,gc, | |
1761 x+tab->tabs.l_x, y+tab->tabs.l_y, | |
1762 lbl, (int)strlen(lbl)); | |
1763 #endif | |
1764 } | |
1765 } | |
1766 | |
1767 if (child == tw->tabs.hilight) | |
1768 DrawHighlight(tw, child, False); | |
1492 } | 1769 } |
1493 | 1770 |
1494 | 1771 |
1495 /* draw frame all the way around the child windows. */ | 1772 /* draw frame all the way around the child windows. */ |
1496 | 1773 |
1687 TabWidth(Widget w) | 1964 TabWidth(Widget w) |
1688 { | 1965 { |
1689 TabsConstraints tab = (TabsConstraints) w->core.constraints ; | 1966 TabsConstraints tab = (TabsConstraints) w->core.constraints ; |
1690 TabsWidget tw = (TabsWidget)XtParent(w) ; | 1967 TabsWidget tw = (TabsWidget)XtParent(w) ; |
1691 String lbl = tab->tabs.label != NULL ? | 1968 String lbl = tab->tabs.label != NULL ? |
1692 tab->tabs.label : XtName(w) ; | 1969 tab->tabs.label : XtName(w); |
1693 XFontStruct *font = tw->tabs.font ; | 1970 #ifdef USE_XFT_TABS |
1694 int iw = tw->tabs.internalWidth ; | 1971 XftFont *font = tw->tabs.renderFont; |
1972 #else | |
1973 XFontStruct *font = tw->tabs.font; | |
1974 #endif | |
1975 int iw = tw->tabs.internalWidth; | |
1695 | 1976 |
1696 tab->tabs.width = iw + SHADWID*2 ; | 1977 tab->tabs.width = iw + SHADWID*2 ; |
1697 tab->tabs.l_x = tab->tabs.lbm_x = SHADWID + iw ; | 1978 tab->tabs.l_x = tab->tabs.lbm_x = SHADWID + iw ; |
1698 | 1979 |
1699 if( tab->tabs.left_bitmap != None ) | 1980 if( tab->tabs.left_bitmap != None ) |
1703 tab->tabs.lbm_y = (tw->tabs.tab_height - tab->tabs.lbm_height)/2 ; | 1984 tab->tabs.lbm_y = (tw->tabs.tab_height - tab->tabs.lbm_height)/2 ; |
1704 } | 1985 } |
1705 | 1986 |
1706 if( lbl != NULL && font != NULL ) | 1987 if( lbl != NULL && font != NULL ) |
1707 { | 1988 { |
1708 tab->tabs.width += XTextWidth( font, lbl, (int)strlen(lbl) ) + iw ; | 1989 #ifdef USE_XFT_TABS |
1990 tab->tabs.width += x_xft_text_width (XtDisplay(tw), font, | |
1991 lbl, (int)strlen(lbl)) + iw; | |
1992 tab->tabs.l_y = (tw->tabs.tab_height | |
1993 + tw->tabs.renderFont->ascent | |
1994 /* #### how can this subtraction be correct? */ | |
1995 - tw->tabs.renderFont->descent)/2; | |
1996 if (debug_tabs > 2) | |
1997 fprintf (stderr, "tab: height=%d, width=%d, baseline=%d.\n", | |
1998 tw->tabs.tab_height, tab->tabs.width, tab->tabs.l_y); | |
1999 if (debug_tabs > 1) | |
2000 fprintf (stderr, "font: height=%d, ascent=%d, descent=%d.\n", | |
2001 tw->tabs.renderFont->height, | |
2002 tw->tabs.renderFont->ascent, | |
2003 tw->tabs.renderFont->descent); | |
2004 #else | |
2005 tab->tabs.width += XTextWidth (font, lbl, (int)strlen(lbl)) + iw; | |
1709 tab->tabs.l_y = (tw->tabs.tab_height + | 2006 tab->tabs.l_y = (tw->tabs.tab_height + |
1710 tw->tabs.font->max_bounds.ascent - | 2007 tw->tabs.font->max_bounds.ascent - |
1711 tw->tabs.font->max_bounds.descent)/2 ; | 2008 tw->tabs.font->max_bounds.descent)/2; |
2009 #endif | |
1712 } | 2010 } |
1713 } | 2011 } |
1714 | 2012 |
1715 | 2013 |
1716 | 2014 |
1721 * | 2019 * |
1722 * Tabs are indented from the edges by INDENT. | 2020 * Tabs are indented from the edges by INDENT. |
1723 * | 2021 * |
1724 * TODO: if they require more than two rows and the total height:width | 2022 * TODO: if they require more than two rows and the total height:width |
1725 * ratio is more than 2:1, then try something else. | 2023 * ratio is more than 2:1, then try something else. |
2024 * Gaak! This is actually already done in PreferredSize()! | |
2025 * | |
2026 * TODO SOONER: for reasons unclear, some applications (specifically | |
2027 * XEmacs) give a nominal geometry (in the core record) which doesn't | |
2028 * make much sense (eg, may be smaller than some of the tab children). | |
2029 * This results in bizarre values for DISPLAY_ROWS and REPLY_HEIGHT. | |
2030 * Specify a way to say "tell me what you really want" (eg, with WID | |
2031 * and/or HGT == 0 or == Dimension_MAX), and use it where appropriate. | |
2032 * LATE-BREAKING LOSE: This happens in PreferredSize(), not XEmacs! | |
2033 * | |
2034 * TODO EVEN SOONER: some applications lay out the tab control by | |
2035 * repeatedly querying until a fixed width and height has been filled | |
2036 * by the tabs (XEmacs). There should be an API to cache this? | |
1726 */ | 2037 */ |
1727 | 2038 |
1728 static int | 2039 static int |
1729 TabLayout(TabsWidget tw, | 2040 TabLayout(TabsWidget tw, |
1730 Dimension wid, | 2041 Dimension wid, /* if 0, use core.width as guess */ |
1731 Dimension hgt, | 2042 Dimension hgt, /* if 0, use core.height as guess */ |
1732 Dimension *reply_height, Bool query_only) | 2043 Dimension *reply_height, Bool query_only) |
1733 { | 2044 { |
1734 int i, row, done = 0, display_rows = 0 ; | 2045 int i, row, done = 0, display_rows = 0 ; |
1735 int num_children = tw->composite.num_children ; | 2046 int num_children = tw->composite.num_children ; |
1736 Widget *childP ; | 2047 Widget *childP ; |
1737 Dimension w ; | 2048 Dimension w ; |
1738 Position x,y ; | 2049 Position x,y ; /* #### gaak, these are dimensions! */ |
1739 TabsConstraints tab ; | 2050 TabsConstraints tab ; |
1740 | 2051 |
1741 /* Algorithm: loop through children, assign X positions. If a tab | 2052 /* Algorithm: loop through children, assign X positions. If a tab |
1742 * would extend beyond the right edge, start a new row. After all | 2053 * would extend beyond the right edge, start a new row. After all |
1743 * rows are assigned, make a second pass and assign Y positions. | 2054 * rows are assigned, make a second pass and assign Y positions. |
1748 /* Loop through the tabs and see how much space they need. */ | 2059 /* Loop through the tabs and see how much space they need. */ |
1749 | 2060 |
1750 row = 0 ; | 2061 row = 0 ; |
1751 x = INDENT ; | 2062 x = INDENT ; |
1752 y = 0 ; | 2063 y = 0 ; |
1753 wid -= INDENT ; | 2064 /* If wid or hgt is 0, we want to guess our own dimensions. |
2065 Currently the guessing functions are broken.... | |
2066 #### When PreferredSize*() get fixed, fix this too. */ | |
2067 if (debug_tabs > 0) | |
2068 fprintf (stderr, "arg=%d,", wid); | |
2069 wid = (wid ? wid : tw->core.width) - INDENT ; | |
2070 hgt = hgt ? hgt : tw->core.height; | |
2071 if (debug_tabs > 0) | |
2072 fprintf (stderr, "wid=%d: x,w,y=", wid); | |
1754 for(i=num_children, childP=tw->composite.children; --i >= 0; ++childP) | 2073 for(i=num_children, childP=tw->composite.children; --i >= 0; ++childP) |
1755 if( XtIsManaged(*childP) ) | 2074 if( XtIsManaged(*childP) ) |
1756 { | 2075 { |
1757 tab = (TabsConstraints) (*childP)->core.constraints ; | 2076 tab = (TabsConstraints) (*childP)->core.constraints ; |
1758 w = tab->tabs.width ; | 2077 w = tab->tabs.width ; |
1759 | 2078 |
2079 if (debug_tabs > 0) | |
2080 fprintf (stderr, "%d,%d,%d;", x, w, y); | |
1760 if( x + w > wid ) { /* new row */ | 2081 if( x + w > wid ) { /* new row */ |
1761 if (y + tw->tabs.tab_height > hgt && !done) | 2082 /* #### algorithm is not robust to wid < child's width */ |
2083 ++row; | |
2084 x = INDENT ; | |
2085 y += tw->tabs.tab_height ; | |
2086 if (y > hgt && !done) | |
1762 { | 2087 { |
1763 display_rows = row; | 2088 display_rows = row; |
1764 done = 1; | 2089 done = 1; |
1765 } | 2090 } |
1766 ++row; | |
1767 x = INDENT ; | |
1768 y += tw->tabs.tab_height ; | |
1769 } | 2091 } |
1770 if( !query_only ) { | 2092 if( !query_only ) { |
1771 tab->tabs.x = x ; | 2093 tab->tabs.x = x ; |
1772 tab->tabs.y = y ; | 2094 tab->tabs.y = y ; |
1773 tab->tabs.row = row ; | 2095 tab->tabs.row = row ; |
1775 x += w + SPACING ; | 2097 x += w + SPACING ; |
1776 if (!query_only && !done) | 2098 if (!query_only && !done) |
1777 tab->tabs.visible = 1; | 2099 tab->tabs.visible = 1; |
1778 | 2100 |
1779 } | 2101 } |
2102 if (debug_tabs > 0) | |
2103 fprintf (stderr, "\n"); | |
1780 /* If there was only one row, increase the height by TABDELTA */ | 2104 /* If there was only one row, increase the height by TABDELTA */ |
1781 if( ++display_rows == 1 ) | 2105 if( ++display_rows == 1 ) |
1782 { | 2106 { |
1783 row++; | |
1784 y = TABDELTA ; | 2107 y = TABDELTA ; |
1785 if( !query_only ) | 2108 if( !query_only ) |
1786 for(i=num_children, childP=tw->composite.children; | 2109 for(i=num_children, childP=tw->composite.children; |
1787 --i >= 0 ; ++childP) | 2110 --i >= 0 ; ++childP) |
1788 if( XtIsManaged(*childP) ) | 2111 if( XtIsManaged(*childP) ) |
1789 { | 2112 { |
1790 tab = (TabsConstraints) (*childP)->core.constraints ; | 2113 tab = (TabsConstraints) (*childP)->core.constraints ; |
1791 tab->tabs.y = y ; | 2114 tab->tabs.y = y ; |
1792 } | 2115 } |
1793 } | 2116 } |
2117 row++; | |
1794 y += tw->tabs.tab_height ; | 2118 y += tw->tabs.tab_height ; |
1795 } | 2119 } |
1796 else | 2120 else |
1797 display_rows = row = y = 0 ; | 2121 display_rows = row = y = 0 ; |
1798 | 2122 |
1800 tw->tabs.tab_total = y ; | 2124 tw->tabs.tab_total = y ; |
1801 tw->tabs.numRows = display_rows ; | 2125 tw->tabs.numRows = display_rows ; |
1802 tw->tabs.realRows = row; | 2126 tw->tabs.realRows = row; |
1803 } | 2127 } |
1804 | 2128 |
2129 if (debug_tabs > 0 && (row > 1 || display_rows > 1)) | |
2130 fprintf (stderr, "tab: %d display rows, #children = %d," | |
2131 " total height %d, total rows %d%s.\n", | |
2132 display_rows, num_children, y, row, | |
2133 query_only ? " (query)" : ""); | |
2134 | |
1805 if( reply_height != NULL ) | 2135 if( reply_height != NULL ) |
1806 *reply_height = y ; | 2136 *reply_height = y ; |
1807 | 2137 |
1808 return display_rows ; | 2138 return display_rows ; |
1809 } | 2139 } |
1820 MaxChild(tw, NULL, 0,0) ; | 2150 MaxChild(tw, NULL, 0,0) ; |
1821 } | 2151 } |
1822 | 2152 |
1823 | 2153 |
1824 | 2154 |
1825 /* Find max preferred child size. Returned sizes include child | 2155 /* Find max preferred child size and store in control widget. |
1826 * border widths. If except is non-null, don't ask that one. | 2156 * If except is non-null, don't ask that one. |
1827 */ | 2157 */ |
1828 | 2158 |
1829 static void | 2159 static void |
1830 MaxChild(TabsWidget tw, Widget except, Dimension cw, Dimension ch) | 2160 MaxChild(TabsWidget tw, Widget except, Dimension cw, Dimension ch) |
1831 { | 2161 { |
2007 { | 2337 { |
2008 Dimension th ; /* space used by tabs */ | 2338 Dimension th ; /* space used by tabs */ |
2009 int nrows ; | 2339 int nrows ; |
2010 | 2340 |
2011 if( tw->composite.num_children > 0 ) | 2341 if( tw->composite.num_children > 0 ) |
2012 nrows = TabLayout(tw, wid, hgt, &th, True) ; | 2342 /* used to be wid, hgt not 0, 0 but that's obviously wrong |
2343 since TabLayout wants dimensions of control parent but | |
2344 wid, hgt are dimensions of some child */ | |
2345 nrows = TabLayout(tw, 0, 0, &th, True) ; | |
2013 else { | 2346 else { |
2014 th = 0 ; | 2347 th = 0 ; |
2015 nrows = 0 ; | 2348 nrows = 0 ; |
2016 } | 2349 } |
2017 | 2350 |
2089 TabsAllocFgGC(TabsWidget tw) | 2422 TabsAllocFgGC(TabsWidget tw) |
2090 { | 2423 { |
2091 Widget w = (Widget) tw; | 2424 Widget w = (Widget) tw; |
2092 XGCValues values ; | 2425 XGCValues values ; |
2093 | 2426 |
2094 values.background = tw->core.background_pixel ; | 2427 values.background = tw->core.background_pixel; |
2095 values.font = tw->tabs.font->fid ; | 2428 values.font = |
2096 values.line_style = LineOnOffDash ; | 2429 #ifdef USE_XFT_TABS |
2097 values.line_style = LineSolid ; | 2430 None; |
2431 #else | |
2432 tw->tabs.font->fid; | |
2433 #endif | |
2434 values.line_style = LineOnOffDash; | |
2435 values.line_style = LineSolid; | |
2098 | 2436 |
2099 tw->tabs.foregroundGC = | 2437 tw->tabs.foregroundGC = |
2100 XtAllocateGC(w, w->core.depth, | 2438 XtAllocateGC(w, w->core.depth, |
2101 GCBackground|GCFont|GCLineStyle, &values, | 2439 #ifndef USE_XFT_TABS |
2102 GCForeground, | 2440 GCFont| |
2103 GCSubwindowMode|GCGraphicsExposures|GCDashOffset| | 2441 #endif |
2104 GCDashList|GCArcMode) ; | 2442 GCBackground|GCLineStyle, |
2443 &values, | |
2444 GCForeground, | |
2445 #ifdef USE_XFT_TABS | |
2446 GCFont| | |
2447 #endif | |
2448 GCSubwindowMode|GCGraphicsExposures|GCDashOffset| | |
2449 GCDashList|GCArcMode); | |
2105 } | 2450 } |
2106 | 2451 |
2107 static void | 2452 static void |
2108 TabsAllocGreyGC(TabsWidget tw) | 2453 TabsAllocGreyGC(TabsWidget tw) |
2109 { | 2454 { |
2110 Widget w = (Widget) tw; | 2455 Widget w = (Widget) tw; |
2111 XGCValues values ; | 2456 XGCValues values ; |
2112 | 2457 |
2113 values.background = tw->core.background_pixel ; | 2458 values.background = tw->core.background_pixel; |
2114 values.font = tw->tabs.font->fid ; | 2459 values.font = |
2460 #ifdef USE_XFT_TABS | |
2461 None; | |
2462 #else | |
2463 tw->tabs.font->fid; | |
2464 #endif | |
2115 #ifdef HAVE_XMU | 2465 #ifdef HAVE_XMU |
2116 if( tw->tabs.be_nice_to_cmap || w->core.depth == 1) | 2466 if (tw->tabs.be_nice_to_cmap || w->core.depth == 1) |
2117 { | 2467 { |
2118 values.fill_style = FillStippled ; | 2468 values.fill_style = FillStippled; |
2119 tw->tabs.grey50 = | 2469 tw->tabs.grey50 = |
2120 values.stipple = XmuCreateStippledPixmap(XtScreen(w), 1L, 0L, 1) ; | 2470 values.stipple = XmuCreateStippledPixmap(XtScreen(w), 1L, 0L, 1); |
2121 | 2471 |
2122 tw->tabs.greyGC = | 2472 tw->tabs.greyGC = |
2123 XtAllocateGC(w, w->core.depth, | 2473 XtAllocateGC(w, w->core.depth, |
2124 GCBackground|GCFont|GCStipple|GCFillStyle, &values, | 2474 #ifndef USE_XFT_TABS |
2475 GCFont| | |
2476 #endif | |
2477 GCBackground|GCStipple|GCFillStyle, &values, | |
2125 GCForeground, | 2478 GCForeground, |
2479 #ifdef USE_XFT_TABS | |
2480 GCFont| | |
2481 #endif | |
2126 GCSubwindowMode|GCGraphicsExposures|GCDashOffset| | 2482 GCSubwindowMode|GCGraphicsExposures|GCDashOffset| |
2127 GCDashList|GCArcMode) ; | 2483 GCDashList|GCArcMode); |
2128 } | 2484 } |
2129 else | 2485 else |
2130 #endif | 2486 #endif |
2131 { | 2487 { |
2132 tw->tabs.greyGC = | 2488 tw->tabs.greyGC = |
2133 XtAllocateGC(w, w->core.depth, | 2489 XtAllocateGC(w, w->core.depth, |
2134 GCFont, &values, | 2490 #ifdef USE_XFT_TABS |
2491 0L, | |
2492 #else | |
2493 GCFont, | |
2494 #endif | |
2495 &values, | |
2135 GCForeground, | 2496 GCForeground, |
2497 #ifdef USE_XFT_TABS | |
2498 GCFont| | |
2499 #endif | |
2136 GCBackground|GCSubwindowMode|GCGraphicsExposures|GCDashOffset| | 2500 GCBackground|GCSubwindowMode|GCGraphicsExposures|GCDashOffset| |
2137 GCDashList|GCArcMode) ; | 2501 GCDashList|GCArcMode); |
2138 } | 2502 } |
2139 } | 2503 } |