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