/* * Motif * * Copyright (c) 1987-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these librararies and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA * */ /* * TabStack.c - Source code for the XmTabStack Widget Class. * * This file contains the source code that implements the XmTabStack * WidgetClass. The XmTabStack is a manager widget where each child of * the TabStack is associated with a label and/or pixmap that is * positioned on the side to simulate a folder tab. * */ #include #include #include #include "XmI.h" #include #include #include #include #include #include #include #include #include #undef TEAR_OFF_TABS #ifdef TEAR_OFF_TABS #include #include #include #include #endif #ifdef _ARGS #undef _ARGS #endif #ifndef _NO_PROTO #define _ARGS(a) a #else #define _ARGS(a) () #endif extern int _XiGetTabIndex _ARGS((Widget, int, int)); extern int _GetTabWidth _ARGS((Widget, int)); extern int _XmTabBoxGetTabHeight _ARGS((Widget, int)); extern Widget _XmTabBoxCanvas _ARGS((Widget)); extern void _XmTabBoxGetNumRowColumns _ARGS((Widget, int, int*, int*)); extern int _XmTabBoxGetMaxTabWidth _ARGS((Widget)); extern int _XmTabBoxGetMaxTabHeight _ARGS((Widget)); extern void _XmTabBoxSelectTab _ARGS((Widget, int)); extern void _XmTabBoxGetNumRowsColumns _ARGS((Widget, int, int *, int *)); extern void _XmTabBoxStackedGeometry _ARGS((Widget, int, XRectangle *)); extern int _XmTabbedStackListCount _ARGS((XmTabbedStackList)); #ifndef _NO_PROTO static void ClassInitialize (void); #else static void ClassInitialize (); #endif #ifdef TEAR_OFF_TABS static void ClassPartInitialize _ARGS((WidgetClass)); #endif static void Initialize _ARGS((Widget, Widget, ArgList, Cardinal*)); static void Destroy _ARGS((Widget)); static void Resize _ARGS((Widget)); static void Realize _ARGS((Widget, XtValueMask *, XSetWindowAttributes *)); static void Redisplay _ARGS((Widget, XEvent*, Region)); static Boolean SetValues _ARGS((Widget, Widget, Widget, ArgList, Cardinal*)); static XtGeometryResult QueryGeometry _ARGS((Widget, XtWidgetGeometry*, XtWidgetGeometry*)); static XtGeometryResult GeometryManager _ARGS((Widget, XtWidgetGeometry*, XtWidgetGeometry*)); static void ChangeManaged _ARGS((Widget)); static void ConstraintInitialize _ARGS((Widget, Widget, ArgList, Cardinal*)); static void ConstraintDestroy _ARGS((Widget)); static Boolean ConstraintSetValues _ARGS((Widget, Widget, Widget, ArgList, Cardinal*)); static Boolean CvtStringToXmTabSide _ARGS((Display*, XrmValue*, Cardinal*, XrmValue*, XrmValue*, XtPointer*)); static Boolean CvtStringToXmPixmapPlacement _ARGS((Display*, XrmValue*, Cardinal*, XrmValue*, XrmValue*, XtPointer*)); static Boolean CvtStringToXiPixel _ARGS((Display*, XrmValue*, Cardinal*, XrmValue*, XrmValue*, XtPointer*)); static Boolean CvtStringToXiPixmap _ARGS((Display*, XrmValue*, Cardinal*, XrmValue*, XrmValue*, XtPointer*)); static void PickSizes _ARGS((XmTabStackWidget, int, int, XRectangle*, XRectangle*)); static void Layout _ARGS((XmTabStackWidget)); static void DrawShadows _ARGS((XmTabStackWidget, GC, GC, int, int, int, int)); static void DrawStackedShadows _ARGS((XmTabStackWidget, GC, GC, int, int, int, int)); static void TabSelectedCallback _ARGS((Widget, XtPointer, XtPointer)); static void CheckSetRenderTable(Widget wid, int offs, XrmValue *value); #ifdef TEAR_OFF_TABS static void TearOffCallback _ARGS((Widget, XtPointer, XtPointer)); static void XmTabStackMenu _ARGS((Widget, XEvent*, String*, Cardinal*)); static void BuildMenu _ARGS((XmTabStackWidget)); static void XmTabBoxDragTab _ARGS((Widget, XEvent*, String*, Cardinal*)); static Atom TabAtom _ARGS((Widget)); static void HandleTabDrop _ARGS((Widget, XtPointer, XtPointer)); static void TabTransferProc _ARGS((Widget, XtPointer, Atom*, Atom*, XtPointer, unsigned long*, int)); static Boolean TabConvertProc _ARGS((Widget, Atom*, Atom*, Atom*, XtPointer*, unsigned long*, int*, unsigned long*, XtPointer, XtRequestId)); static void XiMoveTabPanel _ARGS((Widget, Widget)); #define WidgetAtom(w) XmInternAtom(XtDisplay(w), "WIDGET", False) #endif #define ValidPixmap(p) ((p) != (Pixmap)NULL && \ (p) != (Pixmap)XmUNSPECIFIED_PIXMAP && \ (p) != (Pixmap)XmPIXMAP_DYNAMIC) #define SetSolidGC(d,g,p) \ { \ XGCValues _macro_gc_values; \ _macro_gc_values.foreground = (p); \ _macro_gc_values.fill_style = FillSolid; \ XChangeGC((d),(g), GCForeground | GCFillStyle, &_macro_gc_values); \ } #define SetTiledGC(d,g,p) \ { \ XGCValues _macro_gc_values; \ _macro_gc_values.tile = (p); \ _macro_gc_values.fill_style = FillTiled; \ XChangeGC((d),(g), GCTile | GCFillStyle, &_macro_gc_values); \ } #define XiBackgroundSpecified(c) \ (XmTabStackC_tab_background(c) != XmCOLOR_DYNAMIC || \ ValidPixmap(XmTabStackC_tab_background_pixmap(c))) #define SetChildGC(c,g) \ { \ if( ValidPixmap(XmTabStackC_tab_background_pixmap(c)) ) \ { \ SetTiledGC(XtDisplay(c), (g), XmTabStackC_tab_background_pixmap(c)); \ } \ else \ { \ SetSolidGC(XtDisplay(c), (g), XmTabStackC_tab_background(c)); \ }\ } #define XiSelectSpecified(t) \ (XmTabStack_select_color((t)) != XmCOLOR_DYNAMIC || \ ValidPixmap(XmTabStack_select_pixmap((t)))) #define SetSelectGC(t,g) \ { \ if( ValidPixmap(XmTabStack_select_pixmap((t))) ) \ { \ SetTiledGC(XtDisplay(t), (g), XmTabStack_select_pixmap((t))); \ } \ else \ { \ SetSolidGC(XtDisplay(t), (g), XmTabStack_select_color((t))); \ }\ } #ifndef AssignMax #define AssignMax(x,y) if((y)>(x)) (x)=(y); else #endif #ifndef AssignMin #define AssignMin(x,y) if((y)<(x)) (x)=(y); else #endif #ifndef Max #define Max(x,y) (((x)>(y))?(x):(y)) #endif #define LocalTabBox(t) (XtParent(XmTabStack_tab_box((t))) == (Widget)(t)) #define IsTabBox(t,k) (XmTabStack_tab_box((t)) == (k)) #define IsValidChild(t, k) (XtIsManaged(k) && !(k)->core.being_destroyed && \ !IsTabBox(t,k)) //#define BBPart(w) (*(XmBulletinBoardPart*)((char*)(w) + XmTabStack_offsets[XmBulletinBoardIndex])) #define BBPart(w) (((XmBulletinBoardWidget)(w))->bulletin_board) #ifdef TEAR_OFF_TABS static XtActionsRec actions[] = { { "XmTabStackMenu", (XtActionProc) XmTabStackMenu }, { "XmTabBoxDragTab", (XtActionProc) XmTabBoxDragTab }, }; static char drag_translations[] = ": XmTabBoxArmTab() XmTabBoxDragTab()\n\ : XmTabStackMenu()\n\ osfMenu: XmTabStackMenu()"; #endif static XtConvertArgRec XmColorConvertArgs[] = { {XtWidgetBaseOffset, (XtPointer)XtOffsetOf(WidgetRec, core.self), sizeof(Widget)}, }; static String tab_stack_filter[] = { XmNx, XmNy, XmNwidth, XmNheight, XmNdestroyCallback, XmNsensitive, XmNuserData, XmNnavigationType, XmNmarginWidth, XmNmarginHeight, XmNtabList, XmNtabOrientation, XmNorientation, XmNtabEdge, XmNselectCallback, XmNunselectCallback, NULL }; #ifdef TEAR_OFF_TABS /* * Bitmap used for Drag Icon */ #define tab_pix_width 32 #define tab_pix_height 32 #define tab_pix_x_hot 0 #define tab_pix_y_hot 0 static unsigned char tab_pix_bits[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0xa9, 0xea, 0x03, 0x00, 0x54, 0xd5, 0xfb, 0xff, 0xff, 0xbf, 0x00, 0x00, 0x00, 0xe0, 0xaa, 0xaa, 0xaa, 0xba, 0x54, 0x55, 0x55, 0xf5, 0xaa, 0xaa, 0xaa, 0xba, 0x54, 0x55, 0x55, 0xf5, 0xaa, 0xaa, 0xaa, 0xba, 0x54, 0x55, 0x55, 0xf5, 0xaa, 0xaa, 0xaa, 0xba, 0x54, 0x55, 0x55, 0xf5, 0xaa, 0xaa, 0xaa, 0xba, 0x54, 0x55, 0x55, 0xf5, 0xaa, 0xaa, 0xaa, 0xba, 0x54, 0x55, 0x55, 0xf5, 0xaa, 0xaa, 0xaa, 0xba, 0x54, 0x55, 0x55, 0xf5, 0xaa, 0xaa, 0xaa, 0xba, 0x54, 0x55, 0x55, 0xf5, 0xaa, 0xaa, 0xaa, 0xba, 0x54, 0x55, 0x55, 0xf5, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static unsigned char tab_mask_bits[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xfe, 0x1f, 0xec, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; /* static unsigned char invalid_bits[] = { 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x0e, 0x70, 0x00, 0x00, 0x01, 0x80, 0x00, 0xff, 0x00, 0x00, 0xe3, 0x3f, 0xe0, 0x07, 0xec, 0x13, 0x1c, 0x3c, 0xd8, 0x0b, 0xfe, 0x7f, 0xb0, 0x08, 0x01, 0x20, 0xf0, 0x86, 0xaa, 0x1a, 0xa0, 0x42, 0x55, 0x0d, 0xc2, 0xa2, 0xaa, 0x06, 0xc7, 0x62, 0x55, 0x83, 0xc5, 0xa1, 0xaa, 0xc1, 0x86, 0x51, 0xd5, 0x60, 0x8d, 0xb1, 0x6a, 0xb0, 0x8a, 0x51, 0x35, 0x58, 0x8d, 0xb1, 0x1a, 0xac, 0x8a, 0x51, 0x0d, 0x56, 0x8d, 0xb1, 0x06, 0xab, 0x8a, 0x61, 0x83, 0x55, 0x85, 0xa2, 0xc1, 0xaa, 0xc6, 0xe2, 0x60, 0x55, 0xc5, 0x42, 0xb0, 0xaa, 0xc2, 0x04, 0x58, 0x55, 0xe1, 0x0a, 0xac, 0xaa, 0xb0, 0x0c, 0x56, 0x55, 0xf0, 0x1e, 0xfc, 0x3f, 0xf8, 0x20, 0xe0, 0x07, 0x04, 0xc0, 0x00, 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0x00, 0x0e, 0x70, 0x00, 0x00, 0xf0, 0x0f, 0x00, }; static unsigned char invalid_mask_bits[] = { 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x1f, 0xe0, 0xff, 0xff, 0x1f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0xe0, 0xff, 0xff, 0x07, 0xc0, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xf0, 0x0f, 0x00, }; */ static unsigned char invalid_bits[] = { 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x0e, 0x70, 0x00, 0x00, 0x01, 0x80, 0x00, 0xc0, 0x00, 0x00, 0x03, 0x20, 0xe0, 0x07, 0x04, 0x10, 0x1c, 0x38, 0x08, 0x08, 0x02, 0x40, 0x10, 0x08, 0x01, 0x20, 0x10, 0x86, 0x00, 0x10, 0x20, 0x42, 0x00, 0x08, 0x42, 0x22, 0x00, 0x04, 0x45, 0x22, 0x00, 0x82, 0x44, 0x21, 0x00, 0x41, 0x84, 0x11, 0x80, 0x20, 0x88, 0x11, 0x40, 0x10, 0x88, 0x11, 0x20, 0x08, 0x88, 0x11, 0x10, 0x04, 0x88, 0x11, 0x08, 0x02, 0x88, 0x11, 0x04, 0x01, 0x88, 0x21, 0x82, 0x00, 0x84, 0x22, 0x41, 0x00, 0x44, 0xa2, 0x20, 0x00, 0x44, 0x42, 0x10, 0x00, 0x42, 0x04, 0x08, 0x00, 0x21, 0x08, 0x04, 0x80, 0x10, 0x08, 0x02, 0x40, 0x10, 0x10, 0x1c, 0x38, 0x08, 0x20, 0xe0, 0x07, 0x04, 0xc0, 0x00, 0x00, 0x03, 0x00, 0x01, 0x80, 0x00, 0x00, 0x0e, 0x70, 0x00, 0x00, 0xf0, 0x0f, 0x00, }; static unsigned char invalid_mask_bits[] = { 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x00, 0xc0, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x07, 0xf0, 0x1f, 0xf8, 0x0f, 0xf8, 0x03, 0xc0, 0x1f, 0xf8, 0x01, 0xe0, 0x1f, 0xfe, 0x00, 0xf0, 0x3f, 0x7e, 0x00, 0xf8, 0x7f, 0x3e, 0x00, 0xfc, 0x7d, 0x3e, 0x00, 0xfe, 0x7c, 0x3f, 0x00, 0x7f, 0xfc, 0x1f, 0x80, 0x3f, 0xf8, 0x1f, 0xc0, 0x1f, 0xf8, 0x1f, 0xe0, 0x0f, 0xf8, 0x1f, 0xf0, 0x07, 0xf8, 0x1f, 0xf8, 0x03, 0xf8, 0x1f, 0xfc, 0x01, 0xf8, 0x3f, 0xfe, 0x00, 0xfc, 0x3e, 0x7f, 0x00, 0x7c, 0xbe, 0x3f, 0x00, 0x7c, 0xfe, 0x1f, 0x00, 0x7e, 0xfc, 0x0f, 0x00, 0x3f, 0xf8, 0x07, 0x80, 0x1f, 0xf8, 0x03, 0xc0, 0x1f, 0xf0, 0x1f, 0xf8, 0x0f, 0xe0, 0xff, 0xff, 0x07, 0xc0, 0xff, 0xff, 0x03, 0x00, 0xff, 0xff, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xf0, 0x0f, 0x00, }; #endif static XtResource resources[] = { /* Inherit (but changed default) resources */ { XmNshadowThickness, XmCShadowThickness, XmRDimension, sizeof(Dimension), XtOffsetOf(XmManagerRec, manager.shadow_thickness), XmRImmediate, (XtPointer) 2 }, { XmNautoUnmanage, XmCAutoUnmanage, XmRBoolean, sizeof(Boolean), XtOffsetOf(XmBulletinBoardRec, bulletin_board.auto_unmanage), XmRImmediate, (XtPointer) False }, /* TabBox Resources */ #ifdef TEAR_OFF_TABS { XmNallowTearOffTabs, XmCAllowTearOffTabs, XmRBoolean, sizeof(Boolean), XtOffsetOf(XmTabStackRec, tab_stack.allow_tear_offs), XmRImmediate, (XtPointer) True }, { XmNtearOffLabelString, XmCTearOffLabelString, XmRXmString, sizeof(XmString), XtOffsetOf(XmTabStackRec, tab_stack.tear_off_label), XmRString, (XtPointer) "Tear Off Tab" }, #endif { XmNtabAutoSelect, XmCTabAutoSelect, XmRBoolean, sizeof(Boolean), XtOffsetOf(XmTabStackRec, tab_stack.tab_auto_select), XmRImmediate, (XtPointer) True }, { XmNtabStyle, XmCTabStyle, XmRTabStyle, sizeof(XmTabStyle), XtOffsetOf(XmTabStackRec, tab_stack.tab_style), XmRImmediate, (XtPointer) XmTABS_BEVELED }, { XmNtabMode, XmCTabMode, XmRTabMode, sizeof(XmTabMode), XtOffsetOf(XmTabStackRec, tab_stack.tab_mode), XmRImmediate, (XtPointer) XmTABS_BASIC }, { XmNtabMarginWidth, XmCMarginWidth, XmRHorizontalDimension, sizeof(Dimension), XtOffsetOf(XmTabStackRec, tab_stack.tab_margin_width), XmRImmediate, (XtPointer) 3 }, { XmNtabMarginHeight, XmCMarginHeight, XmRVerticalDimension, sizeof(Dimension), XtOffsetOf(XmTabStackRec, tab_stack.tab_margin_height), XmRImmediate, (XtPointer) 3 }, { "pri.vate", "Pri.vate", XmRBoolean, sizeof(Boolean), XtOffsetOf(XmTabStackRec, tab_stack.check_set_render_table), XmRImmediate, (XtPointer) False }, { XmNfontList, XmCFontList, XmRFontList, sizeof (XmFontList), XtOffsetOf(XmTabStackRec, tab_stack.font_list), XmRCallProc, (XtPointer) CheckSetRenderTable }, { XmNrenderTable, XmCRenderTable, XmRRenderTable, sizeof(XmRenderTable), XtOffsetOf(XmTabStackRec, tab_stack.font_list), XmRCallProc, (XtPointer) CheckSetRenderTable }, { XmNhighlightThickness, XmCHighlightThickness, XmRDimension, sizeof(Dimension), XtOffsetOf(XmTabStackRec, tab_stack.highlight_thickness), XmRImmediate, (XtPointer) 2 }, { XmNtabSide, XmCTabSide, XmRXmTabSide, sizeof(XmTabSide), XtOffsetOf(XmTabStackRec, tab_stack.tab_side), XmRImmediate, (XtPointer) XmTABS_ON_TOP }, { XmNtabOrientation, XmCTabOrientation, XmRTabOrientation, sizeof(XmTabOrientation), XtOffsetOf(XmTabStackRec, tab_stack.tab_orientation), XmRImmediate, (XtPointer) XmTAB_ORIENTATION_DYNAMIC }, { XmNuniformTabSize, XmCUniformTabSize, XmRBoolean, sizeof(Boolean), XtOffsetOf(XmTabStackRec, tab_stack.uniform_tab_size), XmRImmediate, (XtPointer) True }, { XmNtabSelectColor, XmCTabSelectColor, XmRXmPixel, sizeof(Pixel), XtOffsetOf(XmTabStackRec, tab_stack.select_color), XmRImmediate, (XtPointer) XmCOLOR_DYNAMIC }, { XmNtabSelectPixmap, XmCTabSelectPixmap, XmRXmPixmap, sizeof(Pixmap), XtOffsetOf(XmTabStackRec, tab_stack.select_pixmap), XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP }, { XmNstackedEffect, XmCStackedEffect, XmRBoolean, sizeof(Boolean), XtOffsetOf(XmTabStackRec, tab_stack.stacked_effect), XmRImmediate, (XtPointer) True }, { XmNtabCornerPercent, XmCTabCornerPercent, XmRInt, sizeof(int), XtOffsetOf(XmTabStackRec, tab_stack.tab_corner_percent), XmRImmediate, (XtPointer) 40 }, { XmNtabLabelSpacing, XmCTabLabelSpacing, XmRHorizontalDimension, sizeof(Dimension), XtOffsetOf(XmTabStackRec, tab_stack.tab_label_spacing), XmRImmediate, (XtPointer) 2 }, { XmNtabOffset, XmCTabOffset, XmRHorizontalDimension, sizeof(Dimension), XtOffsetOf(XmTabStackRec, tab_stack.tab_offset), XmRImmediate, (XtPointer) 10 }, { XmNuseImageCache, XmCUseImageCache, XmRBoolean, sizeof(Boolean), XtOffsetOf(XmTabStackRec, tab_stack.use_image_cache), XmRImmediate, (XtPointer) True }, { XmNtabSelectedCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffsetOf(XmTabStackRec, tab_stack.tab_select_callback), XmRImmediate, (XtPointer) NULL }, /* appears to be intentionally undocumented; interface not yet public */ { XmNtabBoxWidget, XmCWidget, XmRWidget, sizeof(Widget), XtOffsetOf(XmTabStackRec, tab_stack.tab_box), XmRImmediate, (XtPointer) NULL } }; static XmSyntheticResource get_resources[] = { { XmNtabMarginWidth, sizeof(Dimension), XtOffsetOf(XmTabStackRec, tab_stack.tab_margin_width), XmeFromHorizontalPixels, (XmImportProc) XmeToHorizontalPixels }, { XmNtabMarginHeight, sizeof(Dimension), XtOffsetOf(XmTabStackRec, tab_stack.tab_margin_height), XmeFromVerticalPixels, (XmImportProc) XmeToVerticalPixels }, { XmNtabLabelSpacing, sizeof(Dimension), XtOffsetOf(XmTabStackRec, tab_stack.tab_label_spacing), XmeFromHorizontalPixels, (XmImportProc) XmeToHorizontalPixels }, { XmNtabOffset, sizeof(Dimension), XtOffsetOf(XmTabStackRec, tab_stack.tab_offset), XmeFromHorizontalPixels, (XmImportProc) XmeToHorizontalPixels } }; static XtResource constraint_resources[] = { { XmNtabLabelString, XmCTabLabelString, XmRXmString, sizeof(XmString), XtOffsetOf(XmTabStackConstraintRec, tab_stack.tab_label_string), XmRImmediate, (XtPointer) NULL }, { XmNtabAlignment, XmCAlignment, XmRAlignment, sizeof(unsigned char), XtOffsetOf(XmTabStackConstraintRec, tab_stack.tab_alignment), XmRImmediate, (XtPointer) XmALIGNMENT_CENTER }, { XmNtabStringDirection, XmCStringDirection, XmRStringDirection, sizeof(unsigned char), XtOffsetOf(XmTabStackConstraintRec, tab_stack.tab_string_direction), XmRImmediate, (XtPointer) XmSTRING_DIRECTION_DEFAULT }, { XmNtabLabelPixmap, XmCTabLabelPixmap, XmRManForegroundPixmap, sizeof(Pixmap), XtOffsetOf(XmTabStackConstraintRec, tab_stack.tab_label_pixmap), XmRImmediate, (XtPointer) XmUNSPECIFIED_PIXMAP }, { XmNtabPixmapPlacement, XmCTabPixmapPlacement, XmRXmPixmapPlacement, sizeof(XmPixmapPlacement), XtOffsetOf(XmTabStackConstraintRec, tab_stack.tab_pixmap_placement), XmRImmediate, (XtPointer) XmPIXMAP_RIGHT }, { XmNfreeTabPixmap, XmCFreeTabPixmap, XmRBoolean, sizeof(Boolean), XtOffsetOf(XmTabStackConstraintRec, tab_stack.free_tab_pixmap), XmRImmediate, (XtPointer) False }, { XmNtabBackground, XmCBackground, XmRXmPixel, sizeof(Pixel), XtOffsetOf(XmTabStackConstraintRec, tab_stack.tab_background), XmRImmediate, (XtPointer) XmCOLOR_DYNAMIC }, { XmNtabBackgroundPixmap, XmCBackgroundPixmap, XmRXmPixmap, sizeof(Pixmap), XtOffsetOf(XmTabStackConstraintRec, tab_stack.tab_background_pixmap), XmRImmediate, (XtPointer) XmPIXMAP_DYNAMIC }, { XmNtabForeground, XmCForeground, XmRXmPixel, sizeof(Pixel), XtOffsetOf(XmTabStackConstraintRec, tab_stack.tab_foreground), XmRImmediate, (XtPointer) XmCOLOR_DYNAMIC }, #ifdef TEAR_OFF_TABS { XmNtabTearOffEnabled, XmCTabTearOffEnabled, XmRBoolean, sizeof(Boolean), XtOffsetOf(XmTabStackConstraintRec, tab_stack.tear_off_enabled), XmRImmediate, (XtPointer) True } #endif }; static void Get_tabLabelString(Widget, int, XtArgVal *); static XmSyntheticResource cont_get_resources[] = { { XmNtabLabelString, sizeof(XmString), XtOffsetOf(XmTabStackConstraintRec, tab_stack.tab_label_string), Get_tabLabelString, (XmImportProc) NULL } }; /* ARGSUSED */ static void Get_tabLabelString (Widget widget, int offset, XtArgVal *value) { (*value) = (XtArgVal) XmStringCopy(XmTabStackC_tab_label_string(widget)); } XmTabStackClassRec xmTabStackClassRec = { { /* Core Fields */ /* superclass */ (WidgetClass) &xmBulletinBoardClassRec, /* class_name */ "XmTabStack", /* widget_size */ sizeof(XmTabStackRec), /* class_initialize */ ClassInitialize, #ifdef TEAR_OFF_TABS /* class_part_initial */ ClassPartInitialize, #else /* class_part_initial */ NULL, #endif /* class_inited */ False, /* initialize */ Initialize, /* initialize hook */ NULL, /* realize */ Realize, #ifdef TEAR_OFF_TABS /* actions */ actions, /* num_actions */ XtNumber(actions), #else /* actions */ NULL, /* num_actions */ 0, #endif /* resources */ (XtResource*)resources, /* num_resources */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ True, /* compress_exposure */ XtExposeCompressMultiple, /* compress enter/exit*/ True, /* visible_interest */ False, /* destroy */ Destroy, /* resize */ Resize, /* expose */ Redisplay, /* set_values */ SetValues, /* set values hook */ NULL, /* set values almost */ XtInheritSetValuesAlmost, /* get values hook */ NULL, /* accept_focus */ NULL, /* version */ XtVersion, /* callback offsetlst */ NULL, /* default trans */ XtInheritTranslations, /* query geo proc */ QueryGeometry, /* display accelerator*/ NULL, /* extension record */ (XtPointer) NULL }, { /* Composite Fields */ /* geometry_manager */ GeometryManager, /* change_managed */ ChangeManaged, /* insert_child */ XtInheritInsertChild, /* delete_child */ XtInheritDeleteChild, /* extension */ (XtPointer) NULL }, { /* Constraint Fields */ /* resources */ constraint_resources, /* num_resources */ XtNumber(constraint_resources), /* constraint_size */ sizeof (XmTabStackConstraintRec), /* initialize */ ConstraintInitialize, /* destroy */ ConstraintDestroy, /* set_values */ ConstraintSetValues, /* extension */ (XtPointer) NULL }, { /* OSF/Motif Manager Fields */ /* translations */ XtInheritTranslations, /* syn_resources */ get_resources, /* num_syn_resources */ XtNumber(get_resources), /* syn_resources */ cont_get_resources, /* num_syn_resources */ XtNumber(cont_get_resources), /* parent_process */ XmInheritParentProcess, /* extension */ (XtPointer) NULL }, { /* OSF/Motif BulletinBoard */ /* always_install_acc */ False, /* geo_matrix_create */ XmInheritGeoMatrixCreate, /* focus_moved_proc */ XmInheritFocusMovedProc, /* extension */ (XtPointer) NULL }, { /* EPak Stack Box Fields */ #ifdef TEAR_OFF_TABS /* drag_translations */ drag_translations, #else /* drag_translations */ "", #endif /* extension */ (XtPointer) NULL } }; WidgetClass xmTabStackWidgetClass = (WidgetClass) &xmTabStackClassRec; /* * Note these aren't static, even though they should be. TabBox.c * uses the instance data too. */ /* * Function: * ClassInitialize(void) * Description: * This function sets all the type converters needed for the * XmTabStack widget class. * Input: * None. * Output: * None. */ static void #ifndef _NO_PROTO ClassInitialize(void) #else ClassInitialize() #endif { XmTabStackClassRec* wc = &xmTabStackClassRec; /* * Initialize the XmTabBox class to add its type converters which we * also use. */ XtInitializeWidgetClass(xmTabBoxWidgetClass); XtSetTypeConverter(XmRString, XmRXmTabSide, CvtStringToXmTabSide, NULL, 0, XtCacheNone, NULL); XtSetTypeConverter(XmRString, XmRXmPixmapPlacement, CvtStringToXmPixmapPlacement, NULL, 0, XtCacheNone, NULL); XtSetTypeConverter(XmRString, XmRXmPixel, CvtStringToXiPixel, XmColorConvertArgs, XtNumber(XmColorConvertArgs), XtCacheNone, NULL); XtSetTypeConverter(XmRString, XmRXmPixmap, CvtStringToXiPixmap, XmColorConvertArgs, XtNumber(XmColorConvertArgs), XtCacheNone, NULL); } #ifdef TEAR_OFF_TABS static void #ifndef _NO_PROTO ClassPartInitialize(WidgetClass widget_class) #else ClassPartInitialize(widget_class) WidgetClass widget_class; #endif { XmTabStackWidgetClass tab = (XmTabStackWidgetClass) widget_class; _XmFastSubclassInit (w_class, XmTABSTACK_BIT); if( XmTabStack_class(tab).drag_translations != NULL ) { if( (String)XmTabStack_class(tab).drag_translations == XtInheritTranslations ) { XmTabStack_class(tab).drag_translations = (String) ((XmTabStackWidgetClass) tab->core_class.superclass)-> tab_stack_class.drag_translations; } else { XmTabStack_class(tab).drag_translations = (String) XtParseTranslationTable((String) XmTabStack_class(tab). drag_translations); } } } #endif /* * Function: * Initialize(request, set, arg_list, arg_cnt) * Description: * This function initializes the widget data structure for an * instance of the XmTabStack. * Input: * request : Widget - the user's requested resources * set : Widget - the initial resource values * arg_list : ArgList - the argument list passed in with creation * arg_cnt : Cardinal* - the number of arguments * Output: * None. */ static void #ifndef _NO_PROTO Initialize(Widget request, Widget set, ArgList arg_list, Cardinal *arg_cnt) #else Initialize(request, set, arg_list, arg_cnt) Widget request, set; ArgList arg_list; Cardinal *arg_cnt; #endif { XmTabStackWidget ts = (XmTabStackWidget) set; Arg args[50]; ArgList filtered_args, merged_args; Cardinal n = 0, num_filtered_args; XmTabOrientation orientation = XmTabStack_tab_orientation(ts); XmTabStack__inited(ts) = False; /* By default call XmNtabSelectedCallback callbacks when tab is selected */ XmTabStack_do_notify(ts) = True; /* * Lets make sure that our font list is not NULL. If it is we will * set it to the appropriate default. */ if( XmTabStack_font_list(ts) == NULL ) { XmTabStack_font_list(ts) = XmeGetDefaultRenderTable(set, XmLABEL_FONTLIST); } XmTabStack_font_list(ts) = XmFontListCopy(XmTabStack_font_list(ts)); XmTabStack__gc(ts) = NULL; /* * For our stack we need to create a TabBox, to do this we need to set * up some arguments depending on which side the caller wants the tabs * on. */ switch( XmTabStack_tab_side(ts) ) { case XmTABS_ON_TOP: default: XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n; if( orientation == XmTAB_ORIENTATION_DYNAMIC ) { XtSetArg(args[n], XmNtabOrientation, XmTABS_LEFT_TO_RIGHT); ++n; } else { XtSetArg(args[n], XmNtabOrientation, orientation); ++n; } XtSetArg(args[n], XmNtabEdge, XmTAB_EDGE_BOTTOM_RIGHT); ++n; break; case XmTABS_ON_BOTTOM: XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n; if( orientation == XmTAB_ORIENTATION_DYNAMIC ) { XtSetArg(args[n], XmNtabOrientation, XmTABS_LEFT_TO_RIGHT); ++n; } else { XtSetArg(args[n], XmNtabOrientation, orientation); ++n; } XtSetArg(args[n], XmNtabEdge, XmTAB_EDGE_TOP_LEFT); ++n; break; case XmTABS_ON_RIGHT: XtSetArg(args[n], XmNorientation, XmVERTICAL); ++n; if( orientation == XmTAB_ORIENTATION_DYNAMIC ) { XtSetArg(args[n], XmNtabOrientation, XmTABS_TOP_TO_BOTTOM); ++n; } else { XtSetArg(args[n], XmNtabOrientation, orientation); ++n; } XtSetArg(args[n], XmNtabEdge, XmTAB_EDGE_TOP_LEFT); ++n; break; case XmTABS_ON_LEFT: XtSetArg(args[n], XmNorientation, XmVERTICAL); ++n; if( orientation == XmTAB_ORIENTATION_DYNAMIC ) { XtSetArg(args[n], XmNtabOrientation, XmTABS_BOTTOM_TO_TOP); ++n; } else { XtSetArg(args[n], XmNtabOrientation, orientation); ++n; } XtSetArg(args[n], XmNtabEdge, XmTAB_EDGE_BOTTOM_RIGHT); ++n; break; } /* * Lets do a real quick check here. If we are in a stacked mode * and XmNuniformTabSize is False, then lets set it to true. * * We have to add the XtSetArg for the default value of XmNuniformTabSize * here because we may override it later. */ XtSetArg(args[n], XmNuniformTabSize, XmTabStack_uniform_tab_size(ts)); ++n; if( !XmTabStack_uniform_tab_size(ts) && (XmTabStack_tab_mode(ts) == XmTABS_STACKED || XmTabStack_tab_mode(ts) == XmTABS_STACKED_STATIC) ) { /* * Well it appears that we need to issue a warning here, because * the user tried to set XmNuniformTabSize to False, while in a * stacked mode. */ XmTabStack_uniform_tab_size(ts) = True; XmeWarning(set, XmNillegalUniformTabSizeMsg); XtSetArg(args[n], XmNuniformTabSize, True); ++n; } /* * Lets make sure we pass certain resource down to our children, like * color and font specification. This way if they were set via app * defaults the correct thing will happen. */ XtSetArg(args[n], XmNrenderTable, XmTabStack_font_list(ts)); ++n; XtSetArg(args[n], XmNbackground, ts->core.background_pixel); ++n; XtSetArg(args[n], XmNshadowThickness, ts->manager.shadow_thickness); ++n; XtSetArg(args[n], XmNtabMode, XmTabStack_tab_mode(ts)); ++n; XtSetArg(args[n], XmNtabStyle, XmTabStack_tab_style(ts)); ++n; XtSetArg(args[n], XmNtabAutoSelect, XmTabStack_tab_auto_select(ts)); ++n; XtSetArg(args[n], XmNtabSelectColor, XmTabStack_select_color(ts)); ++n; XtSetArg(args[n], XmNtabSelectPixmap, XmTabStack_select_pixmap(ts));++n; XtSetArg(args[n], XmNtabMarginWidth, XmTabStack_tab_margin_width(ts)); ++n; XtSetArg(args[n], XmNtabMarginHeight, XmTabStack_tab_margin_height(ts));++n; XtSetArg(args[n], XmNtabLabelSpacing, XmTabStack_tab_label_spacing(ts));++n; XtSetArg(args[n], XmNtabCornerPercent, XmTabStack_tab_corner_percent(ts)); ++n; XtSetArg(args[n], XmNtabOffset, XmTabStack_tab_offset(ts)); ++n; XtSetArg(args[n], XmNhighlightThickness, XmTabStack_highlight_thickness(ts)); ++n; XtSetArg(args[n], XmNuseImageCache, XmTabStack_use_image_cache(ts)); ++n; XtSetArg(args[n], XmNunitType, XmPIXELS); ++n; /* * We also want to filter the other arguments that the user has * assigned to us. We will then merge these with the argument * list we created and pass this to the children we create. */ _XmFilterArgs(arg_list, *arg_cnt, tab_stack_filter, &filtered_args, &num_filtered_args); merged_args = XtMergeArgLists(filtered_args, num_filtered_args, args, n); if( XmTabStack_tab_box(ts) == NULL ) { XmTabStack_tab_box(ts) = XtCreateManagedWidget("tabBox", xmTabBoxWidgetClass, set, merged_args, n + num_filtered_args); } else { XtSetValues(XmTabStack_tab_box(ts), merged_args, n + num_filtered_args); } #ifdef TEAR_OFF_TABS if( XmTabStack_tear_off_label(ts) != NULL ) { XmTabStack_tear_off_label(ts) = XmStringCopy(XmTabStack_tear_off_label(ts)); } canvas = XmTabBox__canvas(XmTabStack_tab_box((XmTabBoxWidget)ts)); n = 0; XmTabStack__menu(ts) = XmCreatePopupMenu(canvas, "tabMenu", args, n); XtOverrideTranslations(canvas, (XtTranslations)((XmTabStackWidgetClass)(ts->core.widget_class)) ->tab_stack_class.drag_translations); target = TabAtom(set); n = 0; XtSetArg(args[n], XmNdropSiteActivity, XmDROP_SITE_ACTIVE); ++n; XtSetArg(args[n], XmNdropSiteOperations, XmDROP_MOVE); ++n; XtSetArg(args[n], XmNdropSiteType, XmDROP_SITE_COMPOSITE); ++n; XtSetArg(args[n], XmNimportTargets, &target); ++n; XtSetArg(args[n], XmNnumImportTargets, 1); ++n; XtSetArg(args[n], XmNdropProc, HandleTabDrop); ++n; XmDropSiteRegister(set, args, n); n = 0; XtSetArg(args[n], XmNlabelString, XmTabStack_tear_off_label(ts)); ++n; XmTabStack__tear_off_button(ts) = XtCreateManagedWidget("tearOffTab", xmPushButtonWidgetClass, XmTabStack__menu(ts), args, n); XtAddCallback(XmTabStack__tear_off_button(ts), XmNactivateCallback, TearOffCallback, NULL); n = 0; (void) XtCreateManagedWidget("separator", xmSeparatorWidgetClass, XmTabStack__menu(ts), NULL, 0); #endif /* * Add a callback to the XmTabBox so that we know when to display * the correct child. */ XtAddCallback(XmTabStack_tab_box(ts), XmNselectCallback, TabSelectedCallback, NULL); /* * Now that we are done with these argument list lets deallocate * them. */ XtFree((XtPointer)filtered_args); XtFree((XtPointer)merged_args); /* * Lets initialize some of the instances values. */ XmTabStack__size(ts).x = -1; XmTabStack__active_child(ts) = (Widget) NULL; XmTabStack__tab_list(ts) = (XmTabbedStackList) NULL; XmTabStack__source_icon(ts) = NULL; XmTabStack__invalid_icon(ts) = NULL; XmTabStack__source_pixmap(ts) = XmUNSPECIFIED_PIXMAP; XmTabStack__source_mask(ts) = XmUNSPECIFIED_PIXMAP; XmTabStack__invalid_pixmap(ts) = XmUNSPECIFIED_PIXMAP; XmTabStack__invalid_mask(ts) = XmUNSPECIFIED_PIXMAP; XmTabStack__set_tab_list(ts) = False; /* * Finally if the caller did not assign us a geometry lets pick * an appropriate default. */ if( request->core.width == 0 ) { ts->core.width = 2 * (ts->manager.shadow_thickness + BBPart(ts).margin_width) + 50; } if( request->core.height == 0 ) { ts->core.height = 2 * (ts->manager.shadow_thickness + BBPart(ts).margin_height) + 50; } /* Used to select tabs before they are realized */ XmTabStack__selected_tab(ts) = NULL; XmTabStack__selected_notify(ts) = False; /* * Now that the widget is initialized lets flag that fact. */ XmTabStack__inited(ts) = True; } /* * Function: * Destroy(widget) * Description: * Deallocates all the memory allocated during the lifetime of the * given widget instance. * Input: * widget : Widget - the widget being destroyed. * Output: * None. */ static void #ifndef _NO_PROTO Destroy(Widget widget) #else Destroy(widget) Widget widget; #endif { XmTabStackWidget tab = (XmTabStackWidget) widget; /* * If we have a tab list lets deallocate it. */ if( XmTabStack__tab_list(tab) != NULL ) { XmTabbedStackListFree(XmTabStack__tab_list(tab)); } XmFontListFree(XmTabStack_font_list(tab)); if( XmTabStack__gc(tab) != NULL ) { XFreeGC(XtDisplay(tab), XmTabStack__gc(tab)); } #ifdef TEAR_OFF_TABS if( XmTabStack_tear_off_label(tab) != NULL ) { XmStringFree(XmTabStack_tear_off_label(tab)); } if( ValidPixmap(XmTabStack__source_pixmap(tab)) ) { XFreePixmap(XtDisplay(widget), XmTabStack__source_pixmap(tab)); } if( ValidPixmap(XmTabStack__source_mask(tab)) ) { XFreePixmap(XtDisplay(widget), XmTabStack__source_mask(tab)); } if( ValidPixmap(XmTabStack__invalid_pixmap(tab)) ) { XFreePixmap(XtDisplay(widget), XmTabStack__invalid_pixmap(tab)); } if( ValidPixmap(XmTabStack__invalid_mask(tab)) ) { XFreePixmap(XtDisplay(widget), XmTabStack__invalid_mask(tab)); } #endif } /* * Function: * Realize(widget, XtValueMask *, XSetWindowAttributes *) * Description: * A realize method is used to address a timing issue that blocks * XmTabStackSelectTab() from working before a selected tab widget * has been realized... * Input: * widget : Widget - the widget being resized. * * * Output: * None. */ static void #ifndef _NO_PROTO Realize(Widget w, XtValueMask *mask, XSetWindowAttributes *attr) #else Realize(w, mask, attr) Widget w; #endif { XmTabStackWidget tab = (XmTabStackWidget) w; /* Call superclass realize method... */ XtRealizeProc realize; _XmProcessLock(); realize = xmTabStackWidgetClass->core_class.superclass->core_class.realize; _XmProcessUnlock(); (*realize) (w, mask, attr); /* Now that we are realized, let's select that tab, finally... */ if ((XmTabStack__selected_tab(tab) != NULL) && !XmTabStack__selected_tab(tab)->core.being_destroyed) { XmTabStackSelectTab(XmTabStack__selected_tab(tab), XmTabStack__selected_notify(tab)); } /* * Lets create a GC that we will use for drawing. */ XmTabStack__gc(tab) = XCreateGC(XtDisplay(tab), XtWindow(tab), 0, NULL); } /* * Function: * Resize(widget) * Description: * Handles everything when the XmTabStack is resized. This means * that is shifts the children around to their new locations and * sizes. * Input: * widget : Widget - the widget being resized. * Output: * None. */ static void #ifndef _NO_PROTO Resize(Widget widget) #else Resize(widget) Widget widget; #endif { XmTabStackWidget tab = (XmTabStackWidget) widget; Widget active = XmTabStack__active_child(tab); XRectangle *size = &(XmTabStack__size(tab)); Boolean stacked = False; int cnt = _XmTabbedStackListCount(XmTabStack__tab_list(tab)); GC gc = tab->manager.background_GC; if( XmTabStack_tab_mode(tab) == XmTABS_STACKED || XmTabStack_tab_mode(tab) == XmTABS_STACKED_STATIC ) { stacked = True; } /* * First lets relayout all our children. */ Layout(tab); /* * If we are realized then we want to do something about our * shadows, like erase the old one and redraw them at their * new location. */ if( XtIsRealized(widget) ) { if( stacked || size->x != -1 ) { if( active != NULL && XiBackgroundSpecified(active) ) { gc = XmTabStack__gc(tab); SetChildGC(active, gc); } if( (!stacked || cnt < 1) && size->x != -1 ) { DrawShadows(tab, gc, gc, size->x, size->y, size->width, size->height); } } if( stacked && active != NULL && cnt > 0 ) { XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, active->core.x - BBPart(tab).margin_width, active->core.y - BBPart(tab).margin_height, XtWidth(active) + 2*BBPart(tab).margin_width, XtHeight(active)+ 2*BBPart(tab).margin_height); } else { DrawShadows(tab, tab->manager.top_shadow_GC, tab->manager.bottom_shadow_GC, 0, 0, XtWidth(widget), XtHeight(widget)); } size->x = size->y = 0; size->width = XtWidth(widget); size->height = XtHeight(widget); } } /* * Function: * Redisplay(widget, event, region) * Description: * Draws all the visuals for the TabStack. * Input: * widget : Widget - the widget that needs redisplayed * event : XEvent* - the event causing the redisplay * region : Region - the region that is being redisplayed. * Output: * None. */ static void #ifndef _NO_PROTO Redisplay(Widget widget, XEvent *event, Region region) #else Redisplay(widget, event, region) Widget widget; XEvent *event; Region region; #endif { XmTabStackWidget tab = (XmTabStackWidget) widget; XRectangle *size = &(XmTabStack__size(tab)); Widget active = XmTabStack__active_child(tab); int cnt = _XmTabbedStackListCount(XmTabStack__tab_list(tab)); Boolean stacked = False; if( XmTabStack_stacked_effect(tab) && active != NULL && (XmTabStack_tab_mode(tab) == XmTABS_STACKED || XmTabStack_tab_mode(tab) == XmTABS_STACKED_STATIC) ) { stacked = True; } /* * Now lets look at our active child and if they have a background * set lets color ourselves that background. */ if( (active != NULL) && (XiBackgroundSpecified(active) || XiSelectSpecified(tab)) ) { GC gc = XmTabStack__gc(tab); if( XiSelectSpecified(tab) ) { SetSelectGC(tab, gc); } else { SetChildGC(active, gc); } if( stacked ) { XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, active->core.x - BBPart(tab).margin_width, active->core.y - BBPart(tab).margin_height, XtWidth(active) + 2 * (BBPart(tab).margin_width), XtHeight(active) + 2 * (BBPart(tab).margin_height)); } else { if( event == NULL || event->xany.type != Expose ) { XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, 0, 0, XtWidth(tab), XtHeight(tab)); } else { XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, event->xexpose.x, event->xexpose.y, event->xexpose.width, event->xexpose.height); } } } /* * next if we have any gadget children lets be sure to * redisplay them. */ XmeRedisplayGadgets(widget, event, region); /* * Now lets redray our shadows. */ if( stacked && cnt > 0 ) { DrawStackedShadows(tab, tab->manager.top_shadow_GC, tab->manager.bottom_shadow_GC, 0, 0, XtWidth(active) + (2 * BBPart(tab).margin_width), XtHeight(active) + (2 * BBPart(tab).margin_height)); } else { DrawShadows(tab, tab->manager.top_shadow_GC, tab->manager.bottom_shadow_GC, 0, 0, XtWidth(widget), XtHeight(widget)); } size->x = size->y = 0; size->width = XtWidth(widget); size->height = XtHeight(widget); } /* * Function: * SetValues(current, request, set, arg_list, arg_cnt) * Description: * Handles changes to the widget induced by resource settings. * Input: * current : Widget - the current state of the widget * request : Widget - the request made by the caller * set : Widget - the widget as it will appear * arg_list : ArgList - the argument list to implement the changes * arg_cnt : Cardinal* - the number of arguments * Output: * Boolean - True if a redisplay is needed, else False. */ #define rfield(f) (XmTabStack_##f(r_tab)) #define cfield(f) (XmTabStack_##f(c_tab)) #define sfield(f) (XmTabStack_##f(s_tab)) #define bcfield(f) \ (((XmBulletinBoardWidget) c_tab)->bulletin_board.f) #define bsfield(f) \ (((XmBulletinBoardWidget) s_tab)->bulletin_board.f) //#define bcfield(f) ((XmBulletinBoardPart*) \ // ((char*)c_tab + XmTabStack_offsets[XmBulletinBoardIndex]))->f //#define bsfield(f) ((XmBulletinBoardPart*) \ // ((char*)s_tab + XmTabStack_offsets[XmBulletinBoardIndex]))->f static Boolean #ifndef _NO_PROTO SetValues(Widget current, Widget request, Widget set, ArgList arg_list, Cardinal *arg_cnt) #else SetValues(current, request, set, arg_list, arg_cnt) Widget current, request, set; ArgList arg_list; Cardinal *arg_cnt; #endif { XmTabStackWidget c_tab = (XmTabStackWidget) current, s_tab = (XmTabStackWidget) set; Arg args[25]; ArgList filtered_args, merged_args; int n = 0; Cardinal num_filtered_args; Boolean need_redraw = False, need_resize = False, need_layout = False; if( c_tab->manager.shadow_thickness != s_tab->manager.shadow_thickness ) { need_resize = True; need_layout = True; } if( bcfield(margin_width) != bsfield(margin_width) || bcfield(margin_height) != bsfield(margin_height) || cfield(tab_side) != sfield(tab_side) || cfield(tab_orientation) != sfield(tab_orientation) ) { need_layout = True; need_resize = True; } if( cfield(select_color) != sfield(select_color) || cfield(select_pixmap) != sfield(select_pixmap) ) { need_redraw = True; } if( cfield(font_list) != sfield(font_list) ) { XmFontListFree(cfield(font_list)); if( sfield(font_list) == NULL ) { sfield(font_list) = XmeGetDefaultRenderTable(set, XmLABEL_FONTLIST); } sfield(font_list) = XmFontListCopy(sfield(font_list)); } if( cfield(tab_side) != sfield(tab_side) || cfield(tab_orientation) != sfield(tab_orientation) ) { switch( sfield(tab_side) ) { case XmTABS_ON_TOP: default: XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n; XtSetArg(args[n], XmNtabEdge, XmTAB_EDGE_BOTTOM_RIGHT); ++n; if( sfield(tab_orientation) == XmTAB_ORIENTATION_DYNAMIC ) { XtSetArg(args[n], XmNtabOrientation, XmTABS_LEFT_TO_RIGHT); } else { XtSetArg(args[n], XmNtabOrientation, sfield(tab_orientation)); } n++; break; case XmTABS_ON_BOTTOM: XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n; XtSetArg(args[n], XmNtabEdge, XmTAB_EDGE_TOP_LEFT); ++n; if( sfield(tab_orientation) == XmTAB_ORIENTATION_DYNAMIC ) { XtSetArg(args[n], XmNtabOrientation, XmTABS_LEFT_TO_RIGHT); } else { XtSetArg(args[n], XmNtabOrientation, sfield(tab_orientation)); } n++; break; case XmTABS_ON_RIGHT: XtSetArg(args[n], XmNorientation, XmVERTICAL); ++n; XtSetArg(args[n], XmNtabEdge, XmTAB_EDGE_TOP_LEFT); ++n; if( sfield(tab_orientation) == XmTAB_ORIENTATION_DYNAMIC ) { XtSetArg(args[n], XmNtabOrientation, XmTABS_TOP_TO_BOTTOM); } else { XtSetArg(args[n], XmNtabOrientation, sfield(tab_orientation)); } n++; break; case XmTABS_ON_LEFT: XtSetArg(args[n], XmNorientation, XmVERTICAL); ++n; XtSetArg(args[n], XmNtabEdge, XmTAB_EDGE_BOTTOM_RIGHT); ++n; if( sfield(tab_orientation) == XmTAB_ORIENTATION_DYNAMIC ) { XtSetArg(args[n], XmNtabOrientation, XmTABS_BOTTOM_TO_TOP); } else { XtSetArg(args[n], XmNtabOrientation, sfield(tab_orientation)); } n++; break; } need_layout = True; need_resize = True; need_redraw = True; } if( !sfield(uniform_tab_size) && sfield(uniform_tab_size) != cfield(uniform_tab_size) && (XmTabStack_tab_mode(s_tab) == XmTABS_STACKED || XmTabStack_tab_mode(s_tab) == XmTABS_STACKED_STATIC) ) { XmeWarning(set, XmNillegalUniformTabSizeMsg); XtSetArg(args[n], XmNuniformTabSize, True); ++n; } if( (sfield(tab_mode) == XmTABS_STACKED || sfield(tab_mode) == XmTABS_STACKED_STATIC) && sfield(tab_mode) != cfield(tab_mode) && !sfield(uniform_tab_size) ) { XmeWarning(set, XmNillegalUniformTabSizeMsg); XtSetArg(args[n], XmNuniformTabSize, True); ++n; } if( XmTabStack__inited(s_tab) && (XmTabStack_tab_box(s_tab) != NULL )) { _XmFilterArgs(arg_list, *arg_cnt, tab_stack_filter, &filtered_args, &num_filtered_args); merged_args = XtMergeArgLists(filtered_args, num_filtered_args, args, n); XtSetValues(XmTabStack_tab_box(s_tab), merged_args, n + num_filtered_args); n = 0; XtFree((XtPointer)filtered_args); XtFree((XtPointer)merged_args); } #ifdef TEAR_OFF_TABS if( cfield(tear_off_label) != sfield(tear_off_label) ) { if( cfield(tear_off_label) != NULL ) { XmStringFree(cfield(tear_off_label)); } if( sfield(tear_off_label) != NULL ) { sfield(tear_off_label) = XmStringCopy(sfield(tear_off_label)); } XtVaSetValues(sfield(_tear_off_button), XmNlabelString, sfield(tear_off_label), NULL); } #endif /* TEAR_OFF_TABS */ if( need_layout ) { Resize(set); } if( need_redraw ) { Widget canvas = _XmTabBoxCanvas(XmTabStack_tab_box(s_tab)); if( XtIsRealized(canvas) ) { XClearArea(XtDisplay(set), XtWindow(canvas), 0, 0, 0, 0, True); } } if( need_resize ) { XtWidgetGeometry unused, allowed; unused.request_mode = 0; QueryGeometry(set, &unused, &allowed); if( BBPart(s_tab).resize_policy != XmRESIZE_NONE ) { /* * Lets just adjust the values depending on our resize * policy. */ if( BBPart(s_tab).resize_policy == XmRESIZE_GROW ) { if( allowed.width < s_tab->core.width ) { allowed.width = s_tab->core.width; } if( allowed.height < s_tab->core.height ) { allowed.height = s_tab->core.height; } } if( XtWidth(request) == XtWidth(current) ) { s_tab->core.width = allowed.width; } if( XtHeight(request) == XtHeight(current) ) { s_tab->core.height = allowed.height; } } } return( need_redraw || need_layout || need_resize ); } #undef cfield #undef rfield #undef sfield #undef bcfield #undef bsfield static XtGeometryResult #ifndef _NO_PROTO QueryGeometry(Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *allowed) #else QueryGeometry(widget, request, allowed) Widget widget; XtWidgetGeometry *request, *allowed; #endif { XmTabStackWidget tab = (XmTabStackWidget)widget; WidgetList kid; XtWidgetGeometry tab_wanted; Cardinal i; Boolean have_width, have_height; int kid_width = 0, kid_height = 0, width, height; /* * First lets check to see if the caller is interested in the * same things we are, i.e. if the caller does not care about * the width or height then we will accept whatever they * give us. */ if( request->request_mode != 0 && !(request->request_mode & (CWWidth | CWHeight)) ) { return( XtGeometryYes ); } *allowed = *request; allowed->request_mode = CWWidth | CWHeight; /* * If we get this far we know that they care about our Dimensions * so lets grab the desired width/height of our kids and see what * they want. We calculate our kids width by taking the max of * all the widths and heights and then adding room for the margins. */ for( i = 0, kid = tab->composite.children; i < tab->composite.num_children; ++i ) { if( !IsValidChild(tab, kid[i]) ) continue; AssignMax(kid_width, (int)XmTabStackC_width(kid[i])); AssignMax(kid_height, (int)XmTabStackC_height(kid[i])); } /* * Now that we know the bounding box of all the children lets add the * margin to that area. */ width = kid_width += 2 * BBPart(tab).margin_width + tab->manager.shadow_thickness; height = kid_height += 2 * BBPart(tab).margin_height + tab->manager.shadow_thickness; if (XmTabStack_tab_side(tab) == XmTABS_ON_TOP || XmTabStack_tab_side(tab) == XmTABS_ON_BOTTOM) { width += tab->manager.shadow_thickness; } else /* if (XmTabStack_tab_side(tab) == XmTABS_ON_LEFT || XmTabStack_tab_side(tab) == XmTABS_ON_RIGHT) */ { height += tab->manager.shadow_thickness; } if( LocalTabBox(tab) ) { /* * Now lets find out what size the TabBox wants to be. */ if( XmTabStack_tab_mode(tab) == XmTABS_STACKED || XmTabStack_tab_mode(tab) == XmTABS_STACKED_STATIC ) { XRectangle tab_rect; switch( XmTabStack_tab_side(tab) ) { case XmTABS_ON_TOP: case XmTABS_ON_BOTTOM: _XmTabBoxStackedGeometry(XmTabStack_tab_box(tab), width, &tab_rect); break; case XmTABS_ON_RIGHT: case XmTABS_ON_LEFT: _XmTabBoxStackedGeometry(XmTabStack_tab_box(tab), height, &tab_rect); break; } tab_wanted.width = tab_rect.width; tab_wanted.height = tab_rect.height; } else { XtQueryGeometry(XmTabStack_tab_box(tab), NULL, &tab_wanted); } /* * Now we need to look at the placement of the TabBox and * determine how we should merge its desired size in with the * size of the children. */ switch( XmTabStack_tab_side(tab) ) { case XmTABS_ON_TOP: case XmTABS_ON_BOTTOM: default: /* * For these cases we need to take the max of the width of the * children and the TabBox and then add the TabBox's height * to the children's. */ AssignMax(width, (int)tab_wanted.width); height += tab_wanted.height; break; case XmTABS_ON_RIGHT: case XmTABS_ON_LEFT: /* * For these cases we need to take the max of the height of the * children and the TabBox and then add the TabBox's width * to the children's. */ width += tab_wanted.width; AssignMax(height, (int)tab_wanted.height); break; } } /* * Lets first check the simple case. This is the case where the * caller is interested in the geometry that we would like to * be. */ if( request->request_mode == 0 ) { /* * Well it seems that the caller is just interested in the * size that we want to be, so lets stuff that away to our * return structure and send that back. */ allowed->width = width; allowed->height = height; /* * Before we give a result lets see if the geometry that * we would give back is our current geometry and if it is * we will return XtGeometryNo to indicate that we want to * stay the way we are. */ if( XmCompareXtWidgetGeometryToWidget(allowed, widget) ) { return( XtGeometryNo ); } return( XtGeometryYes ); } /* * If we got here that means that the caller wants to specify * either our width or height and see how we would react to such * a change. So lets what they want. */ have_width = ((request->request_mode & CWWidth) != 0); have_height = ((request->request_mode & CWHeight) != 0); if( have_width && have_height ) { /* * It seems that the caller wants to specify our with and * height. If this is the case then we want to tell them that * we prefer our desired geometry. */ allowed->width = width; allowed->height = height; if( XmCompareXtWidgetGeometryToWidget(allowed, widget) ) { return( XtGeometryNo ); } if( XmCompareXtWidgetGeometry(request, allowed) ) { return( XtGeometryYes ); } return( XtGeometryAlmost ); } /* * Finally the hard part. Here it seems that the caller wants to * freeze either our width or height and have us adjust the other * dimension. */ if( have_width ) { /* * Ok it seems that the caller wants to freeze our width so lets * find out what we can do about this. This case is only interesting * if the tabs are on the top or the bottom. Because if they are * on the sides this case diverts to the we want our preferred geomtry * case because we don't want to shrink our kids below their * preferred size and we don't want to shrink the tabs height. */ switch( XmTabStack_tab_side(tab) ) { case XmTABS_ON_RIGHT: case XmTABS_ON_LEFT: /* * This is the boring case and degrades to the "we want our * preferred geometry" case. */ allowed->width = width; allowed->height = height; break; case XmTABS_ON_TOP: case XmTABS_ON_BOTTOM: default: /* * Here is the interesting case. The uses has frozen our width * but not our height. Now as long as the width they specified * is greater than the width of the kids we are in business, else * we degrade to give me what I want. */ if( (int)request->width < kid_width ) { /* * The degraded case: "Give me what I want" */ allowed->width = width; allowed->height = height; } else { XtWidgetGeometry ask, got; /* * We actually get to have some fun now. What we now * do is ask the TabBox what it is willing to do * "heightwise" if we freeze its width. */ ask.request_mode = CWWidth; ask.width = request->width; got.request_mode = 0; switch( XtQueryGeometry(XmTabStack_tab_box(tab), &ask, &got) ) { case XtGeometryYes: case XtGeometryAlmost: default: if( !(got.request_mode & CWWidth) ) { got.width = tab_wanted.width; } if( !(got.request_mode & CWHeight) ) { got.height = tab_wanted.height; } /* * Now we have the height that the TabBox is willing * to take if we freeze its width so lets * store this information back into our return * structure. */ allowed->width = Max(kid_width, (int)got.width); allowed->height = kid_height + got.height; break; case XtGeometryNo: allowed->width = width; allowed->height = height; break; } } break; } } else if( have_height ) { /* * It seems that the caller want to freeze our height and see how * we react "widthwise". This case degrades to the default if * the tabs are on the right or left. */ switch( XmTabStack_tab_side(tab) ) { case XmTABS_ON_TOP: case XmTABS_ON_BOTTOM: default: allowed->width = width; allowed->height = height; break; case XmTABS_ON_RIGHT: case XmTABS_ON_LEFT: /* * First we will do a quick check to make sure that the height * they are asking about will fit all the children at least, and * if not we will reject it out of hand. */ if( (int)request->height < kid_height ) { allowed->width = width; allowed->height = height; } else { XtWidgetGeometry ask, got; /* * Now letws see how the TabBox reacts to the new size. */ ask.request_mode = CWHeight; ask.request_mode = request->height; got.request_mode = 0; switch( XtQueryGeometry(XmTabStack_tab_box(tab), &ask, &got) ) { case XtGeometryYes: case XtGeometryAlmost: default: if( !(got.request_mode & CWWidth) ) { got.width = tab_wanted.width; } if( !(got.request_mode & CWHeight) ) { got.height = tab_wanted.height; } /* * Now we have the info we need so lets stuff that back * into our return structure. */ allowed->width = kid_width + got.width; allowed->height = Max(kid_height, (int)got.height); break; case XtGeometryNo: allowed->width = width; allowed->height = height; break; } } break; } } if( XmCompareXtWidgetGeometryToWidget(allowed, widget) ) { return( XtGeometryNo ); } else if( XmCompareXtWidgetGeometry(request, allowed) ) { return( XtGeometryYes ); } return( XtGeometryNo ); } #if 0 #define XiReturn(i,r) \ printf("%d: RESULT: XtGeometry", i); \ switch( r ) \ { \ case XtGeometryYes: \ default: \ printf("Yes"); \ break; \ case XtGeometryNo: \ printf("No"); \ break; \ case XtGeometryAlmost: \ printf("Almost"); \ break; \ case XtGeometryDone: \ printf("Done"); \ break; \ } \ if( request->request_mode & XtCWQueryOnly ) printf("(QUERY)\n"); \ else printf("\n"); \ printf(" WIDGET: %s\n", XtName(widget)); \ printf(" X : "); \ if( allowed->request_mode & CWX ) printf("%d\n", allowed->x); \ else printf("N/A\n"); \ printf(" Y : "); \ if( allowed->request_mode & CWY ) printf("%d\n", allowed->y); \ else printf("N/A\n"); \ printf(" WIDTH : "); \ if( allowed->request_mode & CWWidth ) printf("%d\n", allowed->width); \ else printf("N/A\n"); \ printf(" HEIGHT : "); \ if( allowed->request_mode & CWHeight ) printf("%d\n", allowed->height); \ else printf("N/A\n"); \ printf(" BORDER : "); \ if( allowed->request_mode & CWBorderWidth ) \ printf("%d\n", allowed->border_width); \ else printf("N/A\n"); \ printf("\n"); \ return(r); #else #define XiReturn(i,r) return( r ) #endif static XtGeometryResult #ifndef _NO_PROTO GeometryNo(XmTabStackWidget tab, Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *allowed) #else GeometryNo(tab, widget, request, allowed) XmTabStackWidget tab; Widget widget; XtWidgetGeometry *request, *allowed; #endif { XRectangle box, kid; /* * If we are not dealing with the tab box child then we really want * to return No, so lets to that. */ if( widget != XmTabStack_tab_box(tab) ) { return( XtGeometryNo ); } /* * If we got here that means that we know we are dealing with our * tab box child, and we are about to deny a size request from that * child. The problem is that we do not want to do this. Actually * we want to resize the tab box child to fix in the space provided. */ PickSizes(tab, XtWidth(tab), XtHeight(tab), &box, &kid); allowed->request_mode = CWWidth | CWHeight; allowed->width = box.width; allowed->height = box.height; if( XmCompareXtWidgetGeometryToWidget(allowed, XmTabStack_tab_box(tab)) ) { return( XtGeometryNo ); } if( XmCompareXtWidgetGeometry(request, allowed) ) { if( !(request->request_mode & XtCWQueryOnly) ) { Resize((Widget)tab); if( XtIsRealized((Widget)tab) ) Redisplay((Widget)tab,NULL,False); } return( XtGeometryYes ); } return( XtGeometryAlmost ); } /* * Function: * GeometryManager(widget, request, allowed) * Description: * This function handles geometry requests. These requests are * sent from the children. * Input: * widget : Widget - the widget making the request. * request : XtWidgetGeometry* - the size the child wants * allowed : XtWidgetGeometry* - the size the child gets * Output: * XtGeometryResult - specifies information about the allowed geometry * result. */ static XtGeometryResult #ifndef _NO_PROTO GeometryManager(Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *allowed) #else GeometryManager(widget, request, allowed) Widget widget; XtWidgetGeometry *request, *allowed; #endif { XmTabStackWidget tab = (XmTabStackWidget) XtParent(widget); int save_width, save_height, save_border; Dimension child_save_width, child_save_height; XtWidgetGeometry want, got; XRectangle box, kids; #if 0 printf("REQUEST: "); if( request->request_mode & XtCWQueryOnly ) printf("QUERY"); printf("\n"); printf(" WIDGET: %s\n", XtName(widget)); printf(" X : "); if( request->request_mode & CWX ) printf("%d\n", request->x); else printf("N/A\n"); printf(" Y : "); if( request->request_mode & CWY ) printf("%d\n", request->y); else printf("N/A\n"); printf(" WIDTH : "); if( request->request_mode & CWWidth ) printf("%d\n", request->width); else printf("N/A\n"); printf(" HEIGHT : "); if( request->request_mode & CWHeight ) printf("%d\n", request->height); else printf("N/A\n"); printf(" BORDER : "); if( request->request_mode & CWBorderWidth ) printf("%d\n", request->border_width); else printf("N/A\n"); printf("\n"); #endif if( XmTabStack__set_tab_list(tab) && (request->request_mode & CWBorderWidth) ) { XmTabStack__set_tab_list(tab) = False; XtVaSetValues(XmTabStack_tab_box(tab), XmNtabList, XmTabStack__tab_list(tab), NULL); #ifdef TEAR_OFF_TABS BuildMenu(tab); #endif XiReturn( 1, XtGeometryNo ); } *allowed = *request; /* * Ok playing with geometry is real easy. This is because we only * let our children change their dimensions and not their location. * So if the caller wants to muck with their X or Y we ignore it. * * Also stacking order does not matter because only one child is * visible at a time. */ allowed->request_mode &= ~(CWX | CWY | CWStackMode | CWSibling); /* * If the child wants does not want to change its dimensions (width, * height or border width) then we are done. */ if( !(allowed->request_mode & (CWWidth | CWHeight | CWBorderWidth)) ) { /* * It turns out that we have weeded out everything from their * request which means that we are not excepting any of their * changes and we can just return XtGeometryNo. */ XiReturn( 2, XtGeometryNo ); } /* * Lets find out what size we want to be if we accept this kids * request. */ save_width = XtWidth(widget); save_height = XtHeight(widget); save_border = widget->core.border_width; if( allowed->request_mode & CWWidth ) { widget->core.width = allowed->width; XmTabStackC_width(widget) = allowed->width; } if( allowed->request_mode & CWHeight ) { widget->core.height = allowed->height; XmTabStackC_height(widget) = allowed->height; } if( allowed->request_mode & CWBorderWidth ) { widget->core.border_width = allowed->border_width; } child_save_width = widget->core.width; child_save_height = widget->core.height; want.request_mode = 0; QueryGeometry((Widget)tab, &want, &got); widget->core.width = save_width; widget->core.height = save_height; widget->core.border_width = save_border; XmTabStackC_width(widget) = save_width; XmTabStackC_height(widget) = save_height; /* * Lets store away the width and height we want. */ save_width = XtWidth(tab); save_height = XtHeight(tab); if( got.request_mode & CWWidth ) { save_width = got.width; } if( got.request_mode & CWHeight ) { save_height = got.height; } /* * Lets first check to see if we can satify this request without * changing our size and if so we will just return yes. We will * also use this chance to check our resize policy. */ #ifdef DKB if( save_width == XtWidth(tab) && save_height == XtHeight(tab) ) { /* * We can satify this request without changing our size so * lets retrun XtGeometryNo, to let the kid know it should * stay the same size. */ XiReturn( 3, GeometryNo(tab, widget, request, allowed) ); } #endif /* * If we got here that means that the our child wants us to change * our size, so lets see if our resize polify will allow this * chnage. */ if( BBPart(tab).resize_policy == XmRESIZE_NONE || (BBPart(tab).resize_policy == XmRESIZE_GROW && (save_width < (int)XtWidth(tab) ||save_height < (int)XtHeight(tab))) ) { /* * Well we cannot allow this change so what we want is our child * to stay the same size it is, so lets return XtGeometryNo. */ XiReturn( 4, GeometryNo(tab, widget, request, allowed) ); } /* * Now we know what size we want to be if we accept this kids request * so now lets if we can be this size. */ want.request_mode = CWWidth | CWHeight | XtCWQueryOnly; want.width = save_width; want.height = save_height; switch( XtMakeGeometryRequest((Widget)tab, &want, &got) ) { case XtGeometryYes: default: /* * Well our parent said yes, so we can accept the request from * our kid, so what we will do is now check if they really want * us to do it or if this was a query. */ if( (request->request_mode & XtCWQueryOnly) == 0 ) { /* * This was not a query so we now really want to make the * request to our parent. We don't care about the return * value from this call because the parent already said that * they would accept this. */ XtMakeResizeRequest((Widget)tab, save_width, save_height, NULL, NULL); XmTabStackC_width(widget) = child_save_width; XmTabStackC_height(widget) = child_save_height; Resize((Widget)tab); if( XtIsRealized((Widget)tab) ) Redisplay((Widget)tab,NULL,False); } XiReturn( 5, XtGeometryYes ); case XtGeometryNo: /* * Our parent said no, so we must also say no. */ XiReturn( 6, GeometryNo(tab, widget, request, allowed) ); case XtGeometryAlmost: /* * Out parent said almost, so we need to figure out how this * affects our children, i.e. what is our children's dimensions * with this change. */ break; case XtGeometryDone: XmTabStackC_width(widget) = child_save_width; XmTabStackC_height(widget) = child_save_height; XiReturn( 99, XtGeometryDone ); break; } /* * This is the almost case. To get here we have had to ask our parent for * a size change, and our parent said we could not be the size that * we want to be, but we could be a "close" size. So what we have to * do is figure out how this affects our children and return the * proper response. */ /* * First lets see if we can allow the size change that our parent * has said OK to. This means that we have fake a layout to find * out what size our tabbox and children will be. */ if( BBPart(tab).resize_policy == XmRESIZE_GROW && (got.width < XtWidth(tab) || got.height < XtHeight(tab)) ) { /* * It turns out that our resize policy want allow us to make * this compromise so lets just return no. */ XiReturn( 7, GeometryNo(tab, widget, request, allowed) ); } /* * Ok we could accept this compromise, so lets see how it effects * the size of our kids. */ PickSizes(tab, got.width, got.height, &box, &kids); allowed->request_mode |= (CWWidth | CWHeight); if( widget == XmTabStack_tab_box(tab) ) { /* * In this case we are dealing with our tab box child, so * lets set the almost result to size we picked. */ allowed->width = box.width; allowed->height = box.height; } else { /* * In this case we are dealing with our children, so lets * set the almost return value. */ allowed->width = kids.width; allowed->height = kids.height; } XiReturn( 8, XtGeometryAlmost ); } static void #ifndef _NO_PROTO ChangeManaged(Widget widget) #else ChangeManaged(widget) Widget widget; #endif { XmTabStackWidget tab = (XmTabStackWidget) widget; WidgetList kid; Widget active; int idx = 0; Cardinal i; XmTabbedStackList tl = NULL; XmTabAttributeRec attr; XtWidgetGeometry request, geom; XmString xmstr; Boolean changed_size = False; Boolean select_new_kid = False; if( !XmTabStack__inited(tab) ) return; /* * Lets first find out if our active child is still managed, and * if it is not then lets NULLify our active child. */ if( XmTabStack__active_child(tab) != NULL && !XtIsManaged(XmTabStack__active_child(tab)) ) { XmTabStack__active_child(tab) = (Widget) NULL; } /* * If we do not have an active child then lets find the first * managed child and make it active. We will walk the whole list * of children and make sure that the active child is the only * child that is visible. */ for( i = 0, kid = tab->composite.children; i < tab->composite.num_children; ++i, ++kid ) { if( IsTabBox(tab, *kid) ) continue; if( !XtIsManaged(*kid) ) { /* * If this child is not managed then lets zero out * the widgets managed width and height so that * when it becomes managed again we will grab the * new managed width/height. */ XmTabStackC_width(*kid) = 0; XmTabStackC_height(*kid) = 0; XmTabStackC_index(*kid) = -1; continue; } XmTabStackC_index(*kid) = idx++; if( XmTabStack__active_child(tab) == NULL ) { select_new_kid = True; XmTabStack__active_child(tab) = *kid; } /* * Now that we know that we are dealing with a managed child * lets add them to the tab list we are building up to * pass off to the TabBox. */ if( tl == NULL ) { tl = XmTabbedStackListCreate(); } if( XmTabStackC_tab_label_string(*kid) == NULL ) { xmstr = attr.label_string = XmStringCreateLocalized(XtName(*kid)); attr.value_mode = XmTAB_VALUE_COPY; } else { xmstr = NULL; attr.label_string = XmTabStackC_tab_label_string(*kid); attr.value_mode = XmTAB_VALUE_SHARE; } attr.string_direction = XmTabStackC_tab_string_direction(*kid); attr.label_pixmap = XmTabStackC_tab_label_pixmap(*kid); attr.label_alignment = XmTabStackC_tab_alignment(*kid); attr.pixmap_placement = XmTabStackC_tab_pixmap_placement(*kid); attr.foreground = XmTabStackC_tab_foreground(*kid); attr.background = XmTabStackC_tab_background(*kid); attr.background_pixmap = XmTabStackC_tab_background_pixmap(*kid); attr.sensitive = XtIsSensitive(*kid); XmTabbedStackListAppend(tl, XmTAB_ALL_FLAGS, &attr); if( xmstr != NULL ) XmStringFree(xmstr); /* * Next lets check if this kid has its managed width and * height set and if not lets set it. */ if( XmTabStackC_width(*kid) == 0 ) { XmTabStackC_width(*kid) = XtWidth(*kid); XmTabStackC_height(*kid) = XtHeight(*kid); } } if( (active = XmTabStack__active_child(tab)) != NULL ) { XtVaSetValues(XmTabStack_tab_box(tab), XmNtabList, tl, XmNselectedIndex, XmTabStackC_index(active), XmNtraversalIndex, XmTabStackC_index(active), NULL); } else { XtVaSetValues(XmTabStack_tab_box(tab), XmNtabList, tl, NULL); } if( XmTabStack__tab_list(tab) != NULL ) { XmTabbedStackListFree(XmTabStack__tab_list(tab)); } XmTabStack__tab_list(tab) = tl; #ifdef TEAR_OFF_TABS BuildMenu(tab); #endif /* * Now lets see how this new kid affects our geometry and request * a new size. */ request.request_mode = 0; QueryGeometry((Widget)tab, &request, &geom); /* * Now that we know the size that we want to be lets see if we are * that size and if not lets request a new size. But before we do this * lets check our resize policy to see if we want to change size. */ if( (geom.width != XtWidth(tab) || geom.height != XtHeight(tab)) && BBPart(tab).resize_policy != XmRESIZE_NONE ) { Dimension width, height; if( BBPart(tab).resize_policy != XmRESIZE_GROW || (geom.width >= XtWidth(tab) && geom.height >= XtHeight(tab)) ) { switch( XtMakeResizeRequest((Widget)tab, geom.width, geom.height, &width, &height) ) { case XtGeometryYes: changed_size = True; case XtGeometryNo: default: break; case XtGeometryAlmost: /* * Our parent gave us an alternate suggestion so lets do what * mom or dad says and take it. */ if( BBPart(tab).resize_policy != XmRESIZE_GROW || (width >= XtWidth(tab) && height >= XtHeight(tab)) ) { XtMakeResizeRequest((Widget)tab, width, height, NULL, NULL); changed_size = True; } break; } } } Resize((Widget)tab); if( !changed_size && XtIsRealized((Widget)tab) ) { Redisplay((Widget)tab, NULL, False); } /* * If new tab is selected as a result of a manage set changed, then notify * the next tab stack widget through callbacks that it is now selected... */ if (select_new_kid) { XmTabStackCallbackStruct cbdata; cbdata.reason = XmCR_TAB_SELECTED; cbdata.event = NULL; cbdata.selected_child = XmTabStack__active_child(tab); XtCallCallbackList((Widget)tab, XmTabStack_tab_select_callback(tab), (XtPointer) &cbdata); } } /* ARGSUSED */ static void #ifndef _NO_PROTO ConstraintInitialize(Widget request, Widget set, ArgList arg_list, Cardinal *arg_cnt) #else ConstraintInitialize(request, set, arg_list, arg_cnt) Widget request, set; ArgList arg_list; Cardinal *arg_cnt; #endif { XmTabStackWidget tab = (XmTabStackWidget) XtParent(set); if( XmTabStackC_tab_label_string(set) != NULL ) { XmTabStackC_tab_label_string(set) = XmStringCopy(XmTabStackC_tab_label_string(set)); } if( XmTabStackC_tab_string_direction(set) == XmSTRING_DIRECTION_DEFAULT ) { XmTabStackC_tab_string_direction(set) = tab->manager.string_direction; } XmTabStackC_width(set) = 0; XmTabStackC_height(set) = 0; XmTabStackC_index(set) = -1; } static void #ifndef _NO_PROTO ConstraintDestroy(Widget widget) #else ConstraintDestroy(widget) Widget widget; #endif { if( XmTabStackC_tab_label_string(widget) != NULL ) { XmStringFree(XmTabStackC_tab_label_string(widget)); } if( XmTabStackC_free_tab_pixmap(widget) && ValidPixmap(XmTabStackC_tab_label_pixmap(widget)) ) { XFreePixmap(XtDisplay(widget), XmTabStackC_tab_label_pixmap(widget)); } } #define cfield(f) (XmTabStackC_##f(current)) #define rfield(f) (XmTabStackC_##f(request)) #define sfield(f) (XmTabStackC_##f(set)) /* ARGSUSED */ static Boolean #ifndef _NO_PROTO ConstraintSetValues(Widget current, Widget request, Widget set, ArgList arg_list, Cardinal *arg_cnt) #else ConstraintSetValues(current, request, set, arg_list, arg_cnt) Widget current, request, set; ArgList arg_list; Cardinal *arg_cnt; #endif { XmTabStackWidget tab = (XmTabStackWidget) XtParent(set); XmTabAttributeRec attr; WidgetList kid; Cardinal i; /* * If any of the following have changed that means we need to * build a new TabList and send it to our child. */ if( cfield(tab_label_string) != sfield(tab_label_string) || cfield(tab_alignment) != sfield(tab_alignment) || cfield(tab_string_direction ) != sfield(tab_string_direction) || cfield(tab_label_pixmap ) != sfield(tab_label_pixmap) || cfield(tab_pixmap_placement ) != sfield(tab_pixmap_placement) || cfield(tab_background ) != sfield(tab_background) || cfield(tab_background_pixmap) != sfield(tab_background_pixmap) || cfield(tab_foreground ) != sfield(tab_foreground) || XtIsSensitive(current) != XtIsSensitive(set) ) { XmTabbedStackList tl = NULL; XmString xmstr; if( cfield(tab_label_string) != sfield(tab_label_string) ) { if( cfield(tab_label_string) != NULL ) { XmStringFree(cfield(tab_label_string)); } sfield(tab_label_string) = XmStringCopy(sfield(tab_label_string)); } for( i = 0, kid = tab->composite.children; i < tab->composite.num_children; ++i, ++kid ) { if( !IsValidChild(tab, *kid) ) continue; if( tl == NULL ) tl = XmTabbedStackListCreate(); if( XmTabStackC_tab_label_string(*kid) == NULL ) { xmstr = attr.label_string = XmStringCreateLocalized(XtName(*kid)); attr.value_mode = XmTAB_VALUE_COPY; } else { xmstr = NULL; attr.label_string = XmTabStackC_tab_label_string(*kid); attr.value_mode = XmTAB_VALUE_SHARE; } attr.string_direction = XmTabStackC_tab_string_direction(*kid); attr.label_pixmap = XmTabStackC_tab_label_pixmap(*kid); attr.label_alignment = XmTabStackC_tab_alignment(*kid); attr.pixmap_placement = XmTabStackC_tab_pixmap_placement(*kid); attr.foreground = XmTabStackC_tab_foreground(*kid); attr.background = XmTabStackC_tab_background(*kid); attr.background_pixmap = XmTabStackC_tab_background_pixmap(*kid); attr.sensitive = XtIsSensitive(*kid); XmTabbedStackListAppend(tl, XmTAB_ALL_FLAGS, &attr); if( xmstr != NULL ) XmStringFree(xmstr); } if( XmTabStack__tab_list(tab) != NULL ) { XmTabbedStackListFree(XmTabStack__tab_list(tab)); } XmTabStack__tab_list(tab) = tl; if( XtIsManaged(set) && XtIsRealized(set) ) { set->core.border_width++; XmTabStack__set_tab_list(tab) = True; } } /* * If the background color for our tab changes and this is the * active tab then we need cause a refresh to happen in the stack. */ if( (cfield(tab_background ) != sfield(tab_background) || cfield(tab_background_pixmap) != sfield(tab_background_pixmap)) && XtIsRealized((Widget)tab) ) { XClearArea(XtDisplay(tab), XtWindow(tab), 0, 0, 0, 0, True); } return( False ); } #undef cfield #undef rfield #undef sfield #define XiCvtDone(type, value) \ { \ if( to->addr != NULL ) \ { \ if( to->size < sizeof(type) ) \ { \ to->size = sizeof(type); \ return( False ); \ } \ *(type*)(to->addr) = (value); \ } \ else \ { \ static type static_val; \ static_val = (value); \ to->addr = (XtPointer) &static_val; \ } \ to->size = sizeof(type); \ return( True ); \ } /* ARGSUSED */ static Boolean #ifndef _NO_PROTO CvtStringToXiPixel(Display *dpy, XrmValue *arg_list, Cardinal *arg_cnt, XrmValue *from, XrmValue *to, XtPointer *data) #else CvtStringToXiPixel(dpy, arg_list, arg_cnt, from, to, data) Display *dpy; XrmValue *arg_list; Cardinal *arg_cnt; XrmValue *from, *to; XtPointer *data; #endif { static Pixel result = XmCOLOR_DYNAMIC; String str = (String) from->addr; Widget widget; widget = *((Widget*) arg_list[0].addr); if( XmCompareISOLatin1(str, "color_dynamic") == 0 || XmCompareISOLatin1(str, "dynamic") == 0 ) { XiCvtDone(Pixel, result); } return( XtConvertAndStore(widget, XmRString, from, XmRPixel, to) ); } /* ARGSUSED */ static Boolean #ifndef _NO_PROTO CvtStringToXiPixmap(Display *dpy, XrmValue *arg_list, Cardinal *arg_cnt, XrmValue *from, XrmValue *to, XtPointer *data) #else CvtStringToXiPixmap(dpy, arg_list, arg_cnt, from, to, data) Display *dpy; XrmValue *arg_list; Cardinal *arg_cnt; XrmValue *from, *to; XtPointer *data; #endif { static Pixmap result = XmPIXMAP_DYNAMIC; String str = (String) from->addr; Widget widget; widget = *((Widget*) arg_list[0].addr); if( XmCompareISOLatin1(str, "pixmap_dynamic") == 0 || XmCompareISOLatin1(str, "dynamic") == 0 ) { XiCvtDone(Pixel, result); } return( XtConvertAndStore(widget, XmRString, from, XmRPrimForegroundPixmap, to) ); } /* ARGSUSED */ static Boolean #ifndef _NO_PROTO CvtStringToXmTabSide(Display *dpy, XrmValue *arg_list, Cardinal *arg_cnt, XrmValue *from, XrmValue *to, XtPointer *data) #else CvtStringToXmTabSide(dpy, arg_list, arg_cnt, from, to, data) Display *dpy; XrmValue *arg_list; Cardinal *arg_cnt; XrmValue *from, *to; XtPointer *data; #endif { static int result = XmTABS_ON_TOP; String str = (String) (from->addr); if( XmCompareISOLatin1(str, "TOP") == 0 || XmCompareISOLatin1(str, "XmTABS_ON_TOP") == 0 ) { result = XmTABS_ON_TOP; } else if( XmCompareISOLatin1(str, "BOTTOM") == 0 || XmCompareISOLatin1(str, "XmTABS_ON_BOTTOM") == 0 ) { result = XmTABS_ON_BOTTOM; } else if( XmCompareISOLatin1(str, "LEFT") == 0 || XmCompareISOLatin1(str, "XmTABS_ON_LEFT") == 0 ) { result = XmTABS_ON_LEFT; } else if( XmCompareISOLatin1(str, "RIGHT") == 0 || XmCompareISOLatin1(str, "XmTABS_ON_RIGHT") == 0 ) { result = XmTABS_ON_RIGHT; } else { XtDisplayStringConversionWarning(dpy, str, XmRXmTabSide); return( False ); } XiCvtDone(int, result); } /* ARGSUSED */ static Boolean #ifndef _NO_PROTO CvtStringToXmPixmapPlacement(Display *dpy, XrmValue *arg_list, Cardinal *arg_cnt, XrmValue *from, XrmValue *to, XtPointer *data) #else CvtStringToXmPixmapPlacement(dpy, arg_list, arg_cnt, from, to, data) Display *dpy; XrmValue *arg_list; Cardinal *arg_cnt; XrmValue *from, *to; XtPointer *data; #endif { static XmPixmapPlacement result = XmPIXMAP_RIGHT; String str = (String) (from->addr); if( XmCompareISOLatin1(str, "TOP") == 0 || XmCompareISOLatin1(str, "XmPIXMAP_TOP") == 0 ) { result = XmPIXMAP_TOP; } else if( XmCompareISOLatin1(str, "BOTTOM") == 0 || XmCompareISOLatin1(str, "XmPIXMAP_BOTTOM") == 0 ) { result = XmPIXMAP_BOTTOM; } else if( XmCompareISOLatin1(str, "RIGHT") == 0 || XmCompareISOLatin1(str, "XmPIXMAP_RIGHT") == 0 ) { result = XmPIXMAP_RIGHT; } else if( XmCompareISOLatin1(str, "LEFT") == 0 || XmCompareISOLatin1(str, "XmPIXMAP_LEFT") == 0 ) { result = XmPIXMAP_LEFT; } else if( XmCompareISOLatin1(str, "NONE") == 0 || XmCompareISOLatin1(str, "XmPIXMAP_NONE") == 0 ) { result = XmPIXMAP_NONE; } else if( XmCompareISOLatin1(str, "ONLY") == 0 || XmCompareISOLatin1(str, "XmPIXMAP_ONLY") == 0 ) { result = XmPIXMAP_ONLY; } else { XtDisplayStringConversionWarning(dpy, str, XmRXmPixmapPlacement); return( False ); } XiCvtDone(XmPixmapPlacement, result); } static void #ifndef _NO_PROTO DrawShadows(XmTabStackWidget tab, GC top_GC, GC bottom_GC, int x, int y, int width, int height) #else DrawShadows(tab, top_GC, bottom_GC, x, y, width, height) XmTabStackWidget tab; GC top_GC, bottom_GC; int x, y, width, height; #endif { XRectangle top_rects[2], bottom_rects[2]; XPoint bevel; int num_top_rects = 0, num_bottom_rects = 0, shadow = tab->manager.shadow_thickness; /* * The only bit of redisplaying that we really have to do is draw * the three sides of the shadow that the XmTabBox does not draw. */ switch( XmTabStack_tab_side(tab) ) { case XmTABS_ON_TOP: default: top_rects[0].x = x; top_rects[0].y = y; top_rects[0].width = shadow; top_rects[0].height = height; num_top_rects = 1; bottom_rects[0].x = x; bottom_rects[0].y = y + height - shadow; bottom_rects[0].width = width; bottom_rects[0].height = shadow; bottom_rects[1].x = x + width - shadow; bottom_rects[1].y = y; bottom_rects[1].width = shadow; bottom_rects[1].height = height; num_bottom_rects = 2; bevel.x = x; bevel.y = y + height - shadow; break; case XmTABS_ON_BOTTOM: top_rects[0].x = x; top_rects[0].y = y; top_rects[0].width = shadow; top_rects[0].height = height; top_rects[1].x = x; top_rects[1].y = y; top_rects[1].width = width; top_rects[1].height = shadow; num_top_rects = 2; bottom_rects[0].x = x + width - shadow; bottom_rects[0].y = y; bottom_rects[0].width = shadow; bottom_rects[0].height = height; num_bottom_rects = 1; bevel.x = x + width - shadow; bevel.y = y; break; case XmTABS_ON_LEFT: top_rects[0].x = x; top_rects[0].y = y; top_rects[0].width = width; top_rects[0].height = shadow; num_top_rects = 1; bottom_rects[0].x = x; bottom_rects[0].y = y + height - shadow; bottom_rects[0].width = width; bottom_rects[0].height = shadow; bottom_rects[1].x = x + width - shadow; bottom_rects[1].y = y; bottom_rects[1].width = shadow; bottom_rects[1].height = height; num_bottom_rects = 2; bevel.x = x + width - shadow; bevel.y = y; break; case XmTABS_ON_RIGHT: top_rects[0].x = x; top_rects[0].y = y; top_rects[0].width = shadow; top_rects[0].height = height; top_rects[1].x = x; top_rects[1].y = y; top_rects[1].width = width; top_rects[1].height = shadow; num_top_rects = 2; bottom_rects[0].x = x; bottom_rects[0].y = y + height - shadow; bottom_rects[0].width = width; bottom_rects[0].height = shadow; num_bottom_rects = 1; bevel.x = x; bevel.y = y + height - shadow; break; } XFillRectangles(XtDisplay(tab), XtWindow(tab), top_GC, top_rects, num_top_rects); XFillRectangles(XtDisplay(tab), XtWindow(tab), bottom_GC, bottom_rects, num_bottom_rects); XmDrawBevel(XtDisplay(tab), XtWindow(tab), top_GC, bottom_GC, bevel.x, bevel.y, shadow, XmBEVEL_BOTH); } static void #ifndef _NO_PROTO PickSizes(XmTabStackWidget tab, int tab_width, int tab_height, XRectangle *box, XRectangle *kid) #else PickSizes(tab, tab_width, tab_height, box, kid) XmTabStackWidget tab; int tab_width, tab_height; XRectangle *box, *kid; #endif { int max, width, height, row_width, offset = 0, num_rows, num_cols; XtWidgetGeometry ask, got; Boolean stacked = False; /* * The first thing that we need to do is find out how much space we * will have for our children. This is the space that is not * taken up by our XmTabBox Child. We give first priority to the * XmTabBoxChild. */ switch( XmTabStack_tab_side(tab) ) { case XmTABS_ON_TOP: case XmTABS_ON_BOTTOM: default: /* * For this case the amount of width is fixed so we want to know, * given a fixed width what height are you interested in. */ ask.request_mode = CWWidth | CWHeight; ask.width = tab_width; ask.height = 0; XtQueryGeometry(XmTabStack_tab_box(tab), &ask, &got); /* * Now that we have a response back from the kid we need to make * sure that the height it wants is not larger than we can * accomidate. If it is then we will scale it down. */ max = tab_height - 2 * BBPart(tab).margin_height - tab->manager.shadow_thickness; if( (int)got.height > max ) got.height = max; width = tab_width - 2 * ((int)BBPart(tab).margin_width+ (int)tab->manager.shadow_thickness); height = max - (int)got.height; AssignMax(width, 1); AssignMax(height, 1); break; case XmTABS_ON_RIGHT: case XmTABS_ON_LEFT: /* * For this case the amount of height is fixed so we want to know, * given a fixed height what width are you interested in. */ ask.request_mode = CWWidth | CWHeight; ask.width = 0; ask.height = tab_height; XtQueryGeometry(XmTabStack_tab_box(tab), &ask, &got); /* * Now that we have a response back from the kid we need to make * sure that the width it wants is not larger than we can * accomidate. If it is then we will scale it down. */ max = tab_width - 2 * BBPart(tab).margin_width - tab->manager.shadow_thickness; if( (int)got.width > max ) got.height = max; height = tab_height - 2 * ((int)BBPart(tab).margin_height + (int)tab->manager.shadow_thickness); width = max - (int)got.width; AssignMax(width, 1); AssignMax(height, 1); break; } if( XmTabStack_stacked_effect(tab) && (XmTabStack_tab_mode(tab) == XmTABS_STACKED || XmTabStack_tab_mode(tab) == XmTABS_STACKED_STATIC) ) { Dimension doffset; stacked = True; XtVaGetValues(XmTabStack_tab_box(tab), XmNtabOffset, &doffset, NULL); offset = doffset; } /* * Now that we know the size of the XmTabBox we can now layout it and * our other children. We will start out with the XmTabBox. */ switch( XmTabStack_tab_side(tab) ) { case XmTABS_ON_TOP: default: box->x = 0; box->y = 0; box->width = tab_width; box->height = got.height; kid->x = BBPart(tab).margin_width + tab->manager.shadow_thickness; kid->y = got.height + BBPart(tab).margin_height; break; case XmTABS_ON_BOTTOM: box->x = 0; box->y = tab_height - (int)got.height; box->width = tab_width; box->height = got.height; kid->x = BBPart(tab).margin_width + tab->manager.shadow_thickness; kid->y = BBPart(tab).margin_height + tab->manager.shadow_thickness; break; case XmTABS_ON_LEFT: box->x = 0; box->y = 0; box->width = got.width; box->height = tab_height; kid->x = got.width + BBPart(tab).margin_height; kid->y = BBPart(tab).margin_height + tab->manager.shadow_thickness; break; case XmTABS_ON_RIGHT: box->x = tab_width - (int)got.width; box->y = 0; box->width = got.width; box->height = tab_height; kid->x = BBPart(tab).margin_width + tab->manager.shadow_thickness; kid->y = BBPart(tab).margin_height + tab->manager.shadow_thickness; break; } /* * If we are doing a stacked layout we need to change the size of * our children to make room for some special effects. "Hey, Special * Effects ..." */ if( stacked ) { /* * What we need to do is make the size of our child, the size of * a row of tabs minus the shadows. */ switch( XmTabStack_tab_side(tab) ) { case XmTABS_ON_TOP: case XmTABS_ON_BOTTOM: default: _XmTabBoxGetNumRowsColumns(XmTabStack_tab_box(tab), tab_width, &num_rows, &num_cols); if( num_rows <= 1 || num_cols < 1 ) { width = tab_width - 2 * (BBPart(tab).margin_width + tab->manager.shadow_thickness); } else { int tmp; if (LayoutIsRtoL(tab)) kid->x += offset * (num_rows-1); tmp = (((int)tab_width) - ((num_rows-1) * offset))/ num_cols; row_width = num_cols * tmp; width = row_width - 2 * (BBPart(tab).margin_width + tab->manager.shadow_thickness); } break; case XmTABS_ON_LEFT: case XmTABS_ON_RIGHT: _XmTabBoxGetNumRowsColumns(XmTabStack_tab_box(tab), tab_height, &num_rows, &num_cols); if( num_rows <= 1 || num_cols < 1 ) { height = tab_height - 2 * (BBPart(tab).margin_height + tab->manager.shadow_thickness); } else { int tmp = (((int)tab_height) - ((num_rows-1) * offset))/ num_cols; row_width = num_cols * tmp; height = row_width - 2 * (BBPart(tab).margin_height + tab->manager.shadow_thickness); } break; } } kid->width = width; kid->height = height; } static void #ifndef _NO_PROTO Layout(XmTabStackWidget tab) #else Layout(tab) XmTabStackWidget tab; #endif { XRectangle box, child; WidgetList kid; int i, neg_x; /* * Lets start by finding out what size everything should be. */ PickSizes(tab, XtWidth(tab), XtHeight(tab), &box, &child); /* * Now that we know the sizes lets start by placing the tab box. */ if( LocalTabBox(tab) ) { _XmConfigureWidget(XmTabStack_tab_box(tab), box.x, box.y, box.width, box.height, 0); } /* * ... And now place the kiddies. */ for( i = 0, kid = tab->composite.children; i < tab->composite.num_children; ++i, ++kid ) { if( *kid == XmTabStack_tab_box(tab) || !XtIsManaged(*kid) ) continue; if( XmTabStack__active_child(tab) == *kid ) { _XmConfigureWidget(*kid, child.x, child.y, child.width, child.height, (*kid)->core.border_width); } else { neg_x = -((int)child.width) - 2 * (int)((*kid)->core.border_width); _XmConfigureWidget(*kid, (Position)neg_x, child.y, child.width, child.height, (*kid)->core.border_width); } } } /* * Function: * TabSelectedCallback(widget, client, cbdata) * Description: * This callback is activated when the user selects a tab. This * callback brings the active child to the front and hides the * old active child. * Input: * widget : Widget - the XmTabBox Widget * client : XtPointer - unused * cbdata : XtPointer - the callback data from the XmTabBox * Output: * None. */ /* ARGSUSED */ static void #ifndef _NO_PROTO TabSelectedCallback(Widget widget, XtPointer client, XtPointer cbdata) #else TabSelectedCallback(widget, client, cbdata) Widget widget; XtPointer client, cbdata; #endif { XmTabBoxCallbackStruct *info = (XmTabBoxCallbackStruct*) cbdata; XmTabStackWidget tab = (XmTabStackWidget) XtParent(widget); XmTabStackCallbackStruct data; WidgetList kid = tab->composite.children; Widget old, active = NULL; Cardinal i, idx = 0; int neg_x, x, y, width, height; /* * It seems that a tab has been selected so we need to swap our * active widgets. Lets start by grabbing a pointer to our soon * to be active widget. To do this we have to walk our child list * and find our info->tab_index managed widget. */ for( i = 0; i < tab->composite.num_children; ++i, ++kid ) { if( !XtIsManaged(*kid) || IsTabBox(tab, *kid) ) continue; if( idx == info->tab_index ) { active = *kid; break; } idx++; } /* * Lets do a quick check here to make sure we found something. If not * something is probably seriously wrong so we will just bail. */ if( active == NULL ) { return; } old = XmTabStack__active_child(tab); /* * We know that our new active widget is going to be placed at the * same location and of the same dimensions as our currently active * child so lets more the new active child to those coords. */ _XmConfigureWidget(active, old->core.x, old->core.y, XtWidth(old), XtHeight(old), active->core.border_width); neg_x = -((int)XtWidth(old)) - 2 * (int)((*kid)->core.border_width); _XmMoveWidget(old, (Position)neg_x, old->core.y); /* * Now lets set the active child. */ XmTabStack__active_child(tab) = active; x = active->core.x - BBPart(tab).margin_width; y = active->core.y - BBPart(tab).margin_height; width = XtWidth(active) + (2 * BBPart(tab).margin_width); height = XtHeight(active) + (2 * BBPart(tab).margin_height); /* * Now if the active child has a background specified, or if the old * active child had one, then we need to redraw our background. */ if( XiBackgroundSpecified(old) || XiBackgroundSpecified(active) || XiSelectSpecified(tab) ) { if( XiSelectSpecified(tab) ) { SetSelectGC(tab, XmTabStack__gc(tab)); XFillRectangle(XtDisplay(tab), XtWindow(tab), XmTabStack__gc(tab), x, y, width, height); } else if( XiBackgroundSpecified(active) ) { SetChildGC(active, XmTabStack__gc(tab)); XFillRectangle(XtDisplay(tab), XtWindow(tab), XmTabStack__gc(tab), x, y, width, height); } else { XFillRectangle(XtDisplay(tab), XtWindow(tab), tab->manager.background_GC, x, y, width, height); } } /* * Now, if we are stacked, lets check to see if are old child * and our newly selected child are on the same row, and if * not, and we are not a perfect square (all rows and columns filled) * then we need to redraw our stacked shadows. */ if( ((XmTabStack_tab_mode(tab) == XmTABS_STACKED || XmTabStack_tab_mode(tab) == XmTABS_STACKED_STATIC) && XmTabStack_stacked_effect(tab)) && (info->old_index >= 0 && info->tab_index >= 0 && XmTabBoxGetTabRow(XmTabStack_tab_box(tab), info->old_index) != XmTabBoxGetTabRow(XmTabStack_tab_box(tab), info->tab_index)) ) { DrawStackedShadows(tab, tab->manager.top_shadow_GC, tab->manager.bottom_shadow_GC, 0, 0, XtWidth(active) + (2 * BBPart(tab).margin_width), XtHeight(active) + (2 * BBPart(tab).margin_height)); } /* * And finally lets call the select callback for the XmTabStack * so that the user knows something has changed. */ if (XmTabStack_do_notify(tab)) { data.reason = XmCR_TAB_SELECTED; data.event = info->event; data.selected_child = active; XtCallCallbackList((Widget)tab, XmTabStack_tab_select_callback(tab), (XtPointer)&data); } } /* * XmRCallProc routine for checking font_list before setting it to NULL * If "check_set_render_table" is True, then function has * been called twice on same widget, thus resource needs to be set NULL, * otherwise leave it alone. */ /*ARGSUSED*/ static void CheckSetRenderTable(Widget wid, int offs, XrmValue *value) { XmTabStackWidget lw = (XmTabStackWidget)wid; /* Check if been here before */ if (lw->tab_stack.check_set_render_table) value->addr = NULL; else { lw->tab_stack.check_set_render_table = True; value->addr = (char*)&(lw->tab_stack.font_list); } } #ifdef UNUSED_FUNCTION /* ARGSUSED */ static Widget #ifndef _NO_PROTO IndexToTab(XmTabStackWidget tab, int idx) #else IndexToTab(tab, idx) XmTabStackWidget tab; int idx; #endif { WidgetList kid = tab->composite.children; int i; if( tab == NULL || idx < 0 ) return( (Widget)NULL ); for( i = 0; kid != NULL; kid++ ) { if( !IsValidChild(tab, *kid) ) continue; if( i == idx ) { return( *kid ); } ++i; } return( (Widget)NULL ); } #endif static int #ifndef _NO_PROTO TabToIndex(XmTabStackWidget tab, Widget child) #else TabToIndex(tab, child) XmTabStackWidget tab; Widget child; #endif { WidgetList kid; int i; if( tab == NULL || child == NULL ) return( -1 ); kid = tab->composite.children; for( i = 0; kid != NULL; kid++ ) { if( !IsValidChild(tab, *kid) ) continue; if( *kid == child ) return( i ); ++i; } return( -1 ); } Widget #ifndef _NO_PROTO XmCreateTabStack(Widget parent, String name, ArgList arg_list, Cardinal arg_cnt) #else XmCreateTabStack(parent, name, arg_list, arg_cnt) Widget parent; String name; ArgList arg_list; Cardinal arg_cnt; #endif { return( XtCreateWidget(name, xmTabStackWidgetClass, parent, arg_list, arg_cnt) ); } Widget XmVaCreateTabStack( Widget parent, char *name, ...) { register Widget w; va_list var; int count; Va_start(var,name); count = XmeCountVaListSimple(var); va_end(var); Va_start(var, name); w = XmeVLCreateWidget(name, xmTabStackWidgetClass, parent, False, var, count); va_end(var); return w; } Widget XmVaCreateManagedTabStack( Widget parent, char *name, ...) { Widget w = NULL; va_list var; int count; Va_start(var, name); count = XmeCountVaListSimple(var); va_end(var); Va_start(var, name); w = XmeVLCreateWidget(name, xmTabStackWidgetClass, parent, True, var, count); va_end(var); return w; } void #ifndef _NO_PROTO XmTabStackSelectTab(Widget widget, Boolean notify) #else XmTabStackSelectTab(widget, notify) Widget widget; Boolean notify; #endif { XmTabStackWidget tab = (XmTabStackWidget) XtParent(widget); _XmWidgetToAppContext(widget); _XmAppLock(app); if (!XmIsTabStack((Widget)tab)) { _XmAppUnlock(app); return; } if (!XtIsRealized((Widget)tab)) { /* wherehouse the selected widget id to use later in realize proc */ XmTabStack__selected_tab(tab) = widget; XmTabStack__selected_notify(tab) = notify; } else { /* * _XmTabBoxSelectTab will call our internal callback routine, * TabSelectedCallback() which in turn calls the XmNtabSelectedCallback * callbacks if the "do_notify" flag is set... The do_notify flag is * normally TRUE, but can be switched off through this interface. */ XmTabStack_do_notify(tab) = notify; _XmTabBoxSelectTab(XmTabStack_tab_box(tab), TabToIndex(tab, widget)); XmTabStack_do_notify(tab) = True; } _XmAppUnlock(app); } static void #ifndef _NO_PROTO DrawStackedShadows(XmTabStackWidget tab, GC top_GC, GC bottom_GC, int x, int y, int base_width, int base_height) #else DrawStackedShadows(tab, top_GC, bottom_GC, x, y, base_width, base_height) XmTabStackWidget tab; GC top_GC, bottom_GC; int x, y, base_width, base_height; #endif { Widget parent = XtParent(tab); int i, num_rows, num_cols, offset, shadow, y2, x2, idx; Dimension doffset; GC gc; XRectangle rts[2]; Pixel pixel = XmUNSPECIFIED_PIXEL; Pixmap pixmap = None; shadow = tab->manager.shadow_thickness; num_rows = XmTabBoxGetNumRows(XmTabStack_tab_box(tab)); num_cols = XmTabBoxGetNumColumns(XmTabStack_tab_box(tab)); XtVaGetValues(XmTabStack_tab_box(tab), XmNtabOffset, &doffset, NULL); offset = doffset; if( !XmIsManager(parent) ) { XtVaGetValues(parent, XmNbackground, &pixel, XmNbackgroundPixmap, &pixmap, NULL); } switch( XmTabStack_tab_side(tab) ) { case XmTABS_ON_TOP: default: if (LayoutIsRtoLM(tab)) { x = 0; y = XmTabStack_tab_box(tab)->core.height; XFillRectangle(XtDisplay(tab), XtWindow(tab), bottom_GC, x + shadow + offset * (num_rows - 1), y + base_height, base_width + shadow, shadow); x += offset * (num_rows - 1); x2 = x + offset; y2 = y + base_height; for( i = 0; i < num_rows; ++i ) { if (i == 0) { XFillRectangle(XtDisplay(tab), XtWindow(tab), tab->manager.top_shadow_GC, x, y, shadow, y2 - y); XmDrawBevel(XtDisplay(tab), XtWindow(tab), top_GC, bottom_GC, x, y2, shadow, XmBEVEL_BOTH); y2 -= offset; x -= offset; x2 -= offset; } else { if( (idx = _XiGetTabIndex(XmTabStack_tab_box(tab), i, (num_cols-1))) >= 0 ) { Widget child = XmTabStackIndexToWidget((Widget)tab, idx); if( child == NULL || !XiBackgroundSpecified(child) ) { gc = tab->manager.background_GC; } else { gc = XmTabStack__gc(tab); SetChildGC(child, gc); } XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, x, y, x2 - x, y2 - y); if( XmIsManager(parent) ) { gc = ((XmManagerWidget)parent)->manager.background_GC; } else { gc = XmTabStack__gc(tab); if( ValidPixmap(pixmap) ) { SetTiledGC(XtDisplay(tab), gc, pixmap); } else { SetSolidGC(XtDisplay(tab), gc, pixel); } } XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, x, y2, x2 - x, (int)XtHeight(tab) - y2); XFillRectangle(XtDisplay(tab), XtWindow(tab), tab->manager.top_shadow_GC, x, y, shadow, y2 - y); XFillRectangle(XtDisplay(tab), XtWindow(tab), tab->manager.bottom_shadow_GC, x, y2 - shadow, x2 - x, shadow); XmDrawBevel(XtDisplay(tab), XtWindow(tab), top_GC, bottom_GC, x, y2 - shadow, shadow, XmBEVEL_BOTH); x2 -= offset; } x -= offset; y2 -= offset; } } /* for */ if( XmIsManager(parent) ) { gc = ((XmManagerWidget)parent)->manager.background_GC; } else { gc = XmTabStack__gc(tab); if( ValidPixmap(pixmap) ) { SetTiledGC(XtDisplay(tab), gc, pixmap); } else { SetSolidGC(XtDisplay(tab), gc, pixel); } } XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, offset * (num_rows-1) + base_width + 2*shadow, 0, XtWidth(tab) - offset * (num_rows-1) + base_width + 2*shadow, XtHeight(tab)); if( _XiGetTabIndex(XmTabStack_tab_box(tab), num_rows-1, num_cols-1) < 0 ) { XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, 0, 0, offset, XtHeight(tab)); } XFillRectangle(XtDisplay(tab), XtWindow(tab), bottom_GC, offset * (num_rows - 1) + base_width + shadow, y, shadow, base_height + shadow); } else { x = 0; y = XmTabStack_tab_box(tab)->core.height; XFillRectangle(XtDisplay(tab), XtWindow(tab), top_GC, x, y, shadow, base_height + shadow); XFillRectangle(XtDisplay(tab), XtWindow(tab), bottom_GC, x + shadow, y + base_height, base_width + shadow, shadow); XmDrawBevel(XtDisplay(tab), XtWindow(tab), top_GC, bottom_GC, x, y + base_height, shadow, XmBEVEL_BOTTOM); x += base_width + shadow; x2 = x + offset; y2 = y + base_height; for( i = 0; i < num_rows; ++i ) { if( i == 0 ) { XFillRectangle(XtDisplay(tab), XtWindow(tab), tab->manager.bottom_shadow_GC, x, y, shadow, y2 - y); x += shadow; x2 = x + offset; } else { if( (idx = _XiGetTabIndex(XmTabStack_tab_box(tab), i, (num_cols-1))) >= 0 ) { Widget child = XmTabStackIndexToWidget((Widget)tab, idx); if( child == NULL || !XiBackgroundSpecified(child) ) { gc = tab->manager.background_GC; } else { gc = XmTabStack__gc(tab); SetChildGC(child, gc); } XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, x, y, x2 - x, y2 - y); if( XmIsManager(parent) ) { gc = ((XmManagerWidget)parent)->manager.background_GC; } else { gc = XmTabStack__gc(tab); if( ValidPixmap(pixmap) ) { SetTiledGC(XtDisplay(tab), gc, pixmap); } else { SetSolidGC(XtDisplay(tab), gc, pixel); } } XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, x, y2, x2 - x, (int)XtHeight(tab) - y2); XFillRectangle(XtDisplay(tab), XtWindow(tab), tab->manager.bottom_shadow_GC, x2 - shadow, y, shadow, y2 - y); XFillRectangle(XtDisplay(tab), XtWindow(tab), tab->manager.bottom_shadow_GC, x, y2 - shadow, x2 - x, shadow); x = x2; } x2 += offset; } y2 -= offset; } if( XmIsManager(parent) ) { gc = ((XmManagerWidget)parent)->manager.background_GC; } else { gc = XmTabStack__gc(tab); if( ValidPixmap(pixmap) ) { SetTiledGC(XtDisplay(tab), gc, pixmap); } else { SetSolidGC(XtDisplay(tab), gc, pixel); } } if( x < (int)XtWidth(tab) ) { XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, x, 0, (int)XtWidth(tab) - x, XtHeight(tab)); } } break; case XmTABS_ON_BOTTOM: if( LayoutIsRtoL(tab) ) { XFillRectangle(XtDisplay(tab), XtWindow(tab), bottom_GC, offset * (num_rows - 1) + base_width + shadow, 0, shadow, XtHeight(tab)); XFillRectangle(XtDisplay(tab), XtWindow(tab), top_GC, offset * (num_rows - 1), 0, base_width + shadow, shadow); x = offset * (num_rows - 1); y = 0; x2 = x + offset; y2 = y + offset; for( i = 0; i < num_rows; ++i ) { if (i == 0) { XFillRectangle(XtDisplay(tab), XtWindow(tab), tab->manager.top_shadow_GC, x, y + shadow, shadow, base_height); x -= offset; x2 -= offset; } else { if( (idx = _XiGetTabIndex(XmTabStack_tab_box(tab), i, (num_cols-1))) >= 0 ) { Widget child = XmTabStackIndexToWidget((Widget)tab, idx); if( child == NULL || !XiBackgroundSpecified(child) ) { gc = tab->manager.background_GC; } else { gc = XmTabStack__gc(tab); SetChildGC(child, gc); } XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, x, y2 + shadow, x2 - x, base_height - y2); if( XmIsManager(parent) ) { gc = ((XmManagerWidget)parent)->manager.background_GC; } else { gc = XmTabStack__gc(tab); if( ValidPixmap(pixmap) ) { SetTiledGC(XtDisplay(tab), gc, pixmap); } else { SetSolidGC(XtDisplay(tab), gc, pixel); } } XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, x, y, x2 - x, y2 - y); XFillRectangle(XtDisplay(tab), XtWindow(tab), tab->manager.top_shadow_GC, x, y2 + shadow, shadow, base_height - y2); XFillRectangle(XtDisplay(tab), XtWindow(tab), tab->manager.top_shadow_GC, x, y2, x2 - x, shadow); x2 -= offset; } x -= offset; y2 += offset; } } if( XmIsManager(parent) ) { gc = ((XmManagerWidget)parent)->manager.background_GC; } else { gc = XmTabStack__gc(tab); if( ValidPixmap(pixmap) ) { SetTiledGC(XtDisplay(tab), gc, pixmap); } else { SetSolidGC(XtDisplay(tab), gc, pixel); } } i = offset * (num_rows-1) + base_width + shadow*2; if( i < (int)XtWidth(tab) ) { XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, i, 0, (int)XtWidth(tab) - i, XtHeight(tab)); } if( _XiGetTabIndex(XmTabStack_tab_box(tab), num_rows-1, num_cols-1) < 0 ) { XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, 0, 0, offset, XtHeight(tab)); } } else { rts[0].x = 0; rts[0].y = 0; rts[0].width = shadow; rts[0].height = XtHeight(tab); rts[1].x = shadow; rts[1].y = 0; rts[1].width = base_width + shadow; rts[1].height = shadow; XFillRectangles(XtDisplay(tab), XtWindow(tab), top_GC, rts, 2); x += base_width + shadow; XmDrawBevel(XtDisplay(tab), XtWindow(tab), tab->manager.top_shadow_GC, tab->manager.bottom_shadow_GC, x, 0, shadow, XmBEVEL_BOTTOM); x2 = x + offset; y += shadow; y2 = y + base_height; for( i = 0; i < num_rows; ++i ) { if( i == 0 ) { XFillRectangle(XtDisplay(tab), XtWindow(tab), tab->manager.bottom_shadow_GC, x, y, shadow, y2 - y); x += shadow; x2 = x + offset; } else { if( (idx = _XiGetTabIndex(XmTabStack_tab_box(tab), i, (num_cols-1))) >= 0 ) { Widget child = XmTabStackIndexToWidget((Widget)tab, idx); if( child == NULL || !XiBackgroundSpecified(child) ) { gc = tab->manager.background_GC; } else { gc = XmTabStack__gc(tab); SetChildGC(child, gc); } XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, x, y, x2 - x, y2 - y); if( XmIsManager(parent) ) { gc = ((XmManagerWidget)parent)->manager.background_GC; } else { gc = XmTabStack__gc(tab); if( ValidPixmap(pixmap) ) { SetTiledGC(XtDisplay(tab), gc, pixmap); } else { SetSolidGC(XtDisplay(tab), gc, pixel); } } XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, x, 0, x2 - x, y); XFillRectangle(XtDisplay(tab), XtWindow(tab), tab->manager.bottom_shadow_GC, x2 - shadow, y, shadow, y2 - y); XFillRectangle(XtDisplay(tab), XtWindow(tab), tab->manager.top_shadow_GC, x, y, x2 - x, shadow); XmDrawBevel(XtDisplay(tab), XtWindow(tab), tab->manager.top_shadow_GC, tab->manager.bottom_shadow_GC, x2 - shadow, y, shadow, XmBEVEL_BOTTOM); x = x2; } x2 += offset; } y += offset; } if( XmIsManager(parent) ) { gc = ((XmManagerWidget)parent)->manager.background_GC; } else { gc = XmTabStack__gc(tab); if( ValidPixmap(pixmap) ) { SetTiledGC(XtDisplay(tab), gc, pixmap); } else { SetSolidGC(XtDisplay(tab), gc, pixel); } } if( x < (int)XtWidth(tab) ) { XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, x, 0, (int)XtWidth(tab) - x, XtHeight(tab)); } } break; case XmTABS_ON_RIGHT: rts[0].x = 0; rts[0].y = 0; rts[0].width = XtWidth(tab); rts[0].height = shadow; rts[1].x = 0; rts[1].y = shadow; rts[1].width = shadow; rts[1].height = base_width + shadow; XFillRectangles(XtDisplay(tab), XtWindow(tab), top_GC, rts, 2); y += base_height + shadow; XmDrawBevel(XtDisplay(tab), XtWindow(tab), tab->manager.top_shadow_GC, tab->manager.bottom_shadow_GC, 0, y, shadow, XmBEVEL_BOTTOM); y2 = y + offset; x += shadow; x2 = y + base_width; for( i = 0; i < num_rows; ++i ) { if( i == 0 ) { XFillRectangle(XtDisplay(tab), XtWindow(tab), tab->manager.bottom_shadow_GC, x, y, x2 - x, shadow); y += shadow; y2 = y + offset; } else { if( (idx = _XiGetTabIndex(XmTabStack_tab_box(tab), i, (num_cols-1))) >= 0 ) { Widget child = XmTabStackIndexToWidget((Widget)tab, idx); if( child == NULL || !XiBackgroundSpecified(child) ) { gc = tab->manager.background_GC; } else { gc = XmTabStack__gc(tab); SetChildGC(child, gc); } XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, x, y, x2 - x, y2 - y); if( XmIsManager(parent) ) { gc = ((XmManagerWidget)parent)->manager.background_GC; } else { gc = XmTabStack__gc(tab); if( ValidPixmap(pixmap) ) { SetTiledGC(XtDisplay(tab), gc, pixmap); } else { SetSolidGC(XtDisplay(tab), gc, pixel); } } XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, 0, y, x, y2 - y); XFillRectangle(XtDisplay(tab), XtWindow(tab), tab->manager.bottom_shadow_GC, x, y2 - shadow, x2 - x, shadow); XFillRectangle(XtDisplay(tab), XtWindow(tab), tab->manager.top_shadow_GC, x, y, shadow, y2 - y); XmDrawBevel(XtDisplay(tab), XtWindow(tab), tab->manager.top_shadow_GC, tab->manager.bottom_shadow_GC, x, y2 - shadow, shadow, XmBEVEL_BOTTOM); y = y2; } y2 += offset; } x += offset; } if( XmIsManager(parent) ) { gc = ((XmManagerWidget)parent)->manager.background_GC; } else { gc = XmTabStack__gc(tab); if( ValidPixmap(pixmap) ) { SetTiledGC(XtDisplay(tab), gc, pixmap); } else { SetSolidGC(XtDisplay(tab), gc, pixel); } } if( x < (int)XtWidth(tab) ) { XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, 0, y, XtWidth(tab), (int)XtHeight(tab) - y); } break; case XmTABS_ON_LEFT: y = 0; x = XtWidth(XmTabStack_tab_box(tab)); XFillRectangle(XtDisplay(tab), XtWindow(tab), top_GC, x, y, base_width + shadow, shadow); XFillRectangle(XtDisplay(tab), XtWindow(tab), bottom_GC, x + base_width, y + shadow, shadow, base_height + shadow); XmDrawBevel(XtDisplay(tab), XtWindow(tab), top_GC, bottom_GC, x + base_width, y, shadow, XmBEVEL_BOTTOM); y += base_height + shadow; y2 = y + offset; x2 = x + base_width; for( i = 0; i < num_rows; ++i ) { if( i == 0 ) { XFillRectangle(XtDisplay(tab), XtWindow(tab), tab->manager.bottom_shadow_GC, x, y, x2 - x, shadow); y += shadow; y2 = y + offset; } else { if( (idx = _XiGetTabIndex(XmTabStack_tab_box(tab), i, (num_cols-1))) >= 0 ) { Widget child = XmTabStackIndexToWidget((Widget)tab, idx); if( child == NULL || !XiBackgroundSpecified(child) ) { gc = tab->manager.background_GC; } else { gc = XmTabStack__gc(tab); SetChildGC(child, gc); } XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, x, y, x2 - x, y2 - y); if( XmIsManager(parent) ) { gc = ((XmManagerWidget)parent)->manager.background_GC; } else { gc = XmTabStack__gc(tab); if( ValidPixmap(pixmap) ) { SetTiledGC(XtDisplay(tab), gc, pixmap); } else { SetSolidGC(XtDisplay(tab), gc, pixel); } } XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, x2, y, (int)XtWidth(tab) - x2, y2 - y); XFillRectangle(XtDisplay(tab), XtWindow(tab), tab->manager.bottom_shadow_GC, x, y2 - shadow, x2 - x, shadow); XFillRectangle(XtDisplay(tab), XtWindow(tab), tab->manager.bottom_shadow_GC, x2 - shadow, y, shadow, y2 - y); y = y2; } y2 += offset; } x2 -= offset; } if( XmIsManager(parent) ) { gc = ((XmManagerWidget)parent)->manager.background_GC; } else { gc = XmTabStack__gc(tab); if( ValidPixmap(pixmap) ) { SetTiledGC(XtDisplay(tab), gc, pixmap); } else { SetSolidGC(XtDisplay(tab), gc, pixel); } } if( x < (int)XtWidth(tab) ) { XFillRectangle(XtDisplay(tab), XtWindow(tab), gc, 0, y, XtWidth(tab), (int)XtHeight(tab) - y); } break; } } /* note: intentionally undocumented. It may be here for historical reasons ** so keep it around; but the function isn't useful. It's used internally ** and was probably intended not to be publicized. */ Widget #ifndef _NO_PROTO XmTabStackIndexToWidget(Widget widget, int idx) #else XmTabStackIndexToWidget(widget, idx) Widget widget; int idx; #endif { XmTabStackWidget tab = (XmTabStackWidget) widget; Cardinal i, cnt; WidgetList kid; _XmWidgetToAppContext(widget); _XmAppLock(app); if( !XmIsTabStack(widget) || idx < 0 ) { _XmAppUnlock(app); return( NULL ); } for( i = 0, cnt = 0, kid = tab->composite.children; i < tab->composite.num_children; ++i, ++kid ) { if( IsTabBox(tab, *kid) || !XtIsManaged(*kid) ) continue; if( cnt++ == idx ) { _XmAppUnlock(app); return( *kid ); } } _XmAppUnlock(app); return( NULL ); } Widget #ifndef _NO_PROTO XmTabStackGetSelectedTab(Widget widget) #else XmTabStackGetSelectedTab(widget) Widget widget; #endif { XmTabStackWidget tab = (XmTabStackWidget) widget; _XmWidgetToAppContext(widget); _XmAppLock(app); if (!XmIsTabStack(widget)) { _XmAppUnlock(app); return(NULL); } if (!XtIsRealized((Widget)tab) && XmTabStack__selected_tab(tab)) { _XmAppUnlock(app); return (XmTabStack__selected_tab(tab)); } _XmAppUnlock(app); return (XmTabStack__active_child(tab)); } #ifdef TEAR_OFF_TABS static void #ifndef _NO_PROTO TearOffCallback(Widget widget, XtPointer client, XtPointer cbdata) #else TearOffCallback(widget, client, cbdata) Widget widget; XtPointer client, cbdata; #endif { XtPointer data; XtVaGetValues(widget, XmNuserData, &data, NULL); if( data == NULL ) return; } static void #ifndef _NO_PROTO MenuSelectCallback(Widget widget, XtPointer client, XtPointer cbdata) #else MenuSelectCallback(widget, client, cbdata) Widget widget; XtPointer client, cbdata; #endif { XtPointer data; XtVaGetValues(widget, XmNuserData, &data, NULL); XmTabStackSelectTab((Widget)data); } static void #ifndef _NO_PROTO BuildMenu(XmTabStackWidget tab) #else BuildMenu(tab) XmTabStackWidget tab; #endif { WidgetList kids, buttons; Cardinal kidCnt, validKids, i, j, buttonCnt, validButtons; Widget menu = XmTabStack__menu(tab), tmp; Boolean done; /* * First thing we need to do is get the list of child for the * menu. */ XtVaGetValues(tab, XmNchildren, &kids, XmNnumChildren, &kidCnt, NULL); for( i = 0, validKids = 0; i < kidCnt; ++i ) { if( IsValidChild(tab, kids[i]) ) validKids++; } XtVaGetValues(menu, XmNchildren, &buttons, XmNnumChildren, &buttonCnt, NULL); for( i = 0, validButtons = 0; i < buttonCnt; ++i ) { if( XmIsPushButton(buttons[i]) ) validButtons++; } for( i = validButtons; i <= validKids; ++i ) { tmp = XtVaCreateWidget("menuItem", xmPushButtonWidgetClass, menu, NULL); XtAddCallback(tmp, XmNactivateCallback, MenuSelectCallback, NULL); } XtVaGetValues(menu, XmNchildren, &buttons, XmNnumChildren, &buttonCnt, NULL); for( j = 0; j < buttonCnt; ++j ) { if( !XmIsSeparator(buttons[j]) && buttons[j] != XmTabStack__tear_off_button(tab) ) break; } for( i = 0, done = False; i < kidCnt; ++i) { if( !IsValidChild(tab, kids[i]) ) continue; XtVaSetValues(buttons[j], XmNlabelString, XmTabStackC_tab_label_string(kids[i]), XmNuserData, (XtPointer) kids[i], NULL); XtManageChild(buttons[j]); for( j++; j < buttonCnt; ++j ) { if( !XmIsSeparator(buttons[j]) && buttons[j] != XmTabStack__tear_off_button(tab) ) break; } } for( ; j < buttonCnt; ++j ) { if( XmIsSeparator(buttons[j]) ) continue; XtUnmanageChild(buttons[j]); } } static void #ifndef _NO_PROTO TabTransferProc(Widget widget, XtPointer closure, Atom *selType, Atom *type, XtPointer value, unsigned long *length, int format) #else TabTransferProc(widget, closure, selType, type, value, length, format) Widget widget; XtPointer closure; Atom *selType, *type; XtPointer value; unsigned long *length; int format; #endif { Widget child, tmp, tab = (Widget)closure; Colormap c_cmap, p_cmap; Cardinal c_depth, p_depth; if( *length != sizeof(Widget) || *type != WidgetAtom(widget) ) { XtVaSetValues(widget, XmNtransferStatus, XmTRANSFER_FAILURE, NULL); return; } child = *((Widget*)value); /* * Lets just do a quick validity check here. Also if the child is * already a child of the tab stack then lets fail. */ if( child->core.self != child || tab->core.self != tab || XtParent(child) == tab ) { XtVaSetValues(widget, XmNtransferStatus, XmTRANSFER_FAILURE, NULL); return; } /* * Now lets check some specific values to make sure that the * transfer will not cause an X Error. */ XtVaGetValues(child, XmNcolormap, &c_cmap, XmNdepth, &c_depth, NULL); XtVaGetValues(tab, XmNcolormap, &p_cmap, XmNdepth, &p_depth, NULL); if( c_cmap != p_cmap || c_depth != p_depth ) { XtVaSetValues(widget, XmNtransferStatus, XmTRANSFER_FAILURE, NULL); return; } /* * The final safty check is to see if we are trying to move a parent * into a child. */ for( tmp = tab; tmp != NULL && tmp != child; tmp = XtParent(tmp) ); if( tmp == child ) { XtVaSetValues(widget, XmNtransferStatus, XmTRANSFER_FAILURE, NULL); return; } /* * If we got here that means that we really want to move this * panel so lets do it. */ XiMoveTabPanel(child, tab); XtVaSetValues(widget, XmNtransferStatus, XmTRANSFER_SUCCESS, NULL); } static void #ifndef _NO_PROTO HandleTabDrop(Widget widget, XtPointer client, XtPointer cbdata) #else HandleTabDrop(widget, client, cbdata) Widget widget; XtPointer client, cbdata; #endif { XmDropProcCallback drop = (XmDropProcCallback) cbdata; XmDropTransferEntryRec transferEntries[2]; XmDropTransferEntry transferList; Arg args[10]; int n = 0; if( drop->dropAction != XmDROP || drop->operation != XmDROP_MOVE ) { XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_FAILURE); ++n; } else { transferEntries[0].target = TabAtom(widget); transferEntries[0].client_data = (XtPointer) widget; transferList = transferEntries; XtSetArg(args[n], XmNdropTransfers, transferList); ++n; XtSetArg(args[n], XmNnumDropTransfers, 1); ++n; XtSetArg(args[n], XmNtransferProc, TabTransferProc); ++n; XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_SUCCESS); ++n; } XmDropTransferStart(drop->dragContext, args, n); } static Boolean #ifndef _NO_PROTO TabConvertProc(Widget widget, Atom *selection, Atom *target, Atom *typeRtn, XtPointer *valueRtn, unsigned long *lengthRtn, int *formatRtn, unsigned long *max_lengthRtn, XtPointer client_data, XtRequestId request_id) #else TabConvertProc(widget, selection, target, typeRtn, valueRtn, lengthRtn, formatRtn, max_lengthRtn, client_data, request_id) Widget widget; Atom *selection, *target, *typeRtn; XtPointer *valueRtn; unsigned long *lengthRtn; int *formatRtn; unsigned long *max_lengthRtn; XtPointer client_data; XtRequestId request_id; #endif { Widget child, *passed_child; XtPointer child_data; XtVaGetValues(widget, XmNclientData, &child_data, NULL); child = (Widget) child_data; if( *target != TabAtom(widget) ) return( False ); passed_child = XtNew(Widget); *passed_child = child; *typeRtn = WidgetAtom(widget); *valueRtn = (XtPointer) passed_child; *lengthRtn = sizeof(Widget); *formatRtn = 8; return( True ); } static Atom #ifndef _NO_PROTO TabAtom(Widget widget) #else TabAtom(widget) Widget widget; #endif { char pid_buf[64]; sprintf(pid_buf, "ICS_TAB_PID_%d\n", (int)getpid()); return( XmInternAtom(XtDisplay(widget), pid_buf, False) ); } Widget #ifndef _NO_PROTO XmTabStackXYToWidget(Widget widget, int x, int y) #else XmTabStackXYToWidget(widget, x, y) Widget widget; int x, y; #endif { Widget tab_stack, tab_box; _XmWidgetToAppContext(widget); _XmAppLock(app); if( XmIsTabStack(widget) ) { tab_stack = widget; tab_box = XmTabStack_tab_box((XmTabStackWidget)widget); } else if( XmIsTabBox(widget) ) { tab_stack = XtParent(widget); tab_box = widget; } else if( XtParent(widget) != NULL && XmIsTabBox(XtParent(widget)) ) { tab_box = XtParent(widget); tab_stack = XtParent(tab_box); } else { _XmAppUnlock(app); return( NULL ); } _XmAppUnlock(app); return( XmTabStackIndexToWidget(tab_stack, XmTabBoxXYToIndex(tab_box, x, y)) ); } #define XiDeleteChild(c) \ { \ _XmProcessLock(); \ (*((CompositeWidgetClass)((c)->core.parent->core.widget_class))-> \ composite_class.delete_child)(c); \ _XmProcessUnlock(); \ } #define XiInsertChild(p,c) \ { \ (c)->core.parent = (p); \ _XmProcessLock(); \ (*((CompositeWidgetClass)(p)->core.widget_class)-> \ composite_class.insert_child)(c); \ _XmProcessUnlock(); \ } static void #ifndef _NO_PROTO XiMoveTabPanel(Widget panel, Widget to) #else XiMoveTabPanel(panel, to) Widget panel, to; #endif { Widget from = XtParent(panel); int width, height; /* * The object here is to move the panel from "from" to "to", so lets * start by removing the panel from "from". This is done by first * unmanaging the panel and then calling "from"s delete method. */ XmDropSiteStartUpdate(from); XmDropSiteStartUpdate(to); width = XmTabStackC_width(panel); height = XmTabStackC_height(panel); XtUnmanageChild(panel); XtVaSetValues(panel, XmNwidth, width, XmNheight, height, NULL); XiDeleteChild(panel); XtUnrealizeWidget(panel); /* * And now lets add that child to "to" by calling its insert method * and then managing the puppy. */ XiInsertChild(to, panel); XtManageChild(panel); XmDropSiteEndUpdate(from); XmDropSiteEndUpdate(to); } static void #ifndef _NO_PROTO DragCallback(Widget widget, XtPointer client, XtPointer cbdata) #else DragCallback(widget, client, cbdata) Widget widget; XtPointer client, cbdata; #endif { XmAnyCallbackStruct *info = (XmAnyCallbackStruct*)cbdata; XmTabStackWidget tab = (XmTabStackWidget) client; switch( info->reason ) { case XmCR_DRAG_DROP_FINISH: break; case XmCR_DRAG_MOTION: break; case XmCR_DROP_FINISH: break; case XmCR_DROP_SITE_ENTER: { XmDropSiteEnterCallback enter = (XmDropSiteEnterCallback)cbdata; switch( enter->dropSiteStatus ) { case XmINVALID_DROP_SITE: default: XtVaSetValues(widget, XmNstateCursorIcon, XmTabStack__invalid_icon(tab), NULL); break; case XmVALID_DROP_SITE: XtVaSetValues(widget, XmNstateCursorIcon, NULL, NULL); break; } } break; case XmCR_DROP_SITE_LEAVE: XtVaSetValues(widget, XmNstateCursorIcon, XmTabStack__invalid_icon(tab), NULL); break; case XmCR_DROP_START: { XmDropSiteEnterCallback enter = (XmDropSiteEnterCallback)cbdata; switch( enter->dropSiteStatus ) { case XmINVALID_DROP_SITE: default: XtVaSetValues(widget, XmNstateCursorIcon, XmTabStack__invalid_icon(tab), NULL); break; case XmVALID_DROP_SITE: XtVaSetValues(widget, XmNstateCursorIcon, NULL, NULL); break; } } break; case XmCR_OPERATION_CHANGED: { XmOperationChangedCallback change = (XmOperationChangedCallback) cbdata; switch( change->operation ) { case XmDROP_MOVE: XtVaSetValues(widget, XmNstateCursorIcon, NULL, NULL); break; default: XtVaSetValues(widget, XmNstateCursorIcon, XmTabStack__invalid_icon(tab), NULL); break; } } break; case XmCR_TOP_LEVEL_ENTER: break; case XmCR_TOP_LEVEL_LEAVE: break; default: break; } } static void #ifndef _NO_PROTO XmTabStackMenu(Widget widget, XEvent *event, String *params, Cardinal *num_params) #else XmTabStackMenu(widget, event, params, num_params) Widget widget; XEvent *event; String *params; Cardinal *num_params; #endif { Widget parent = XtParent(widget), child; XmTabStackWidget tab = (XmTabStackWidget)XtParent(parent); /* * Lets start by finding out if we are popping this menu up from * a tab. */ child = XmTabStackXYToWidget((Widget) tab, event->xbutton.x, event->xbutton.y); /* * If we are not popping this menu up, and we are not in a tab * then we want to desensitise the tear off option. */ XtSetSensitive(XmTabStack__tear_off_button(tab), (child != NULL)); XtVaSetValues(XmTabStack__tear_off_button(tab), XmNuserData, child, NULL); XmMenuPosition(XmTabStack__menu(tab), (XButtonPressedEvent*)event); XtManageChild(XmTabStack__menu(tab)); } static void #ifndef _NO_PROTO XmTabBoxDragTab(Widget widget, XEvent *event, String *params, Cardinal *num_params) #else XmTabBoxDragTab(widget, event, params, num_params) Widget widget; XEvent *event; String *params; Cardinal *num_params; #endif { Widget parent = XtParent(widget), drag, child, source_icon, invalid_icon; XmTabStackWidget tab = (XmTabStackWidget)XtParent(parent); Arg args[10]; Cardinal n = 0; Atom target; int idx; Pixmap source_pixmap, source_mask, invalid_pixmap, invalid_mask; #ifdef TEAR_OFF_TABS if( !XmTabStack_allow_tear_offs(tab) || event == NULL || event->xany.type != ButtonPress || (child = IndexToTab(tab, XmTabBoxGetIndex(parent, event->xbutton.x, event->xbutton.y))) == NULL || !XmTabStackC_tear_off_enabled(child) ) { return; } #endif /* TEAR_OFF_TABS */ if( XmTabStack__source_icon(tab) == NULL ) { source_pixmap = XCreateBitmapFromData(XtDisplay(widget), XtWindow(widget), (char*)tab_pix_bits, tab_pix_width, tab_pix_height); source_mask = XCreateBitmapFromData(XtDisplay(widget), XtWindow(widget), (char*)tab_mask_bits, tab_pix_width, tab_pix_height); invalid_pixmap = XCreateBitmapFromData(XtDisplay(widget), XtWindow(widget), (char*)invalid_bits, tab_pix_width, tab_pix_height); invalid_mask = XCreateBitmapFromData(XtDisplay(widget), XtWindow(widget), (char*)invalid_mask_bits, tab_pix_width, tab_pix_height); XtSetArg(args[n], XmNdepth, 1); n++; XtSetArg(args[n], XmNwidth, tab_pix_width); n++; XtSetArg(args[n], XmNheight, tab_pix_height); n++; XtSetArg(args[n], XmNpixmap, source_pixmap); n++; XtSetArg(args[n], XmNmask, source_mask); n++; source_icon = XmCreateDragIcon(parent, "tabSourceIcon", args, n); n=0; XtSetArg(args[n], XmNdepth, 1); n++; XtSetArg(args[n], XmNwidth, tab_pix_width); n++; XtSetArg(args[n], XmNheight, tab_pix_height); n++; XtSetArg(args[n], XmNpixmap, invalid_pixmap); n++; XtSetArg(args[n], XmNmask, invalid_mask); n++; invalid_icon = XmCreateDragIcon(parent, "tabInvalidIcon", args, n);n=0; XmTabStack__source_pixmap(tab) = source_pixmap; XmTabStack__source_mask(tab) = source_mask; XmTabStack__invalid_pixmap(tab) = invalid_pixmap; XmTabStack__invalid_mask(tab) = invalid_mask; XmTabStack__source_icon(tab) = source_icon; XmTabStack__invalid_icon(tab) = invalid_icon; } else { source_icon = XmTabStack__source_icon(tab); invalid_icon = XmTabStack__invalid_icon(tab); } target = TabAtom(widget); XtSetArg(args[n], XmNblendModel, XmBLEND_ALL); ++n; XtSetArg(args[n], XmNsourceCursorIcon, source_icon); ++n; XtSetArg(args[n], XmNsourcePixmapIcon, source_icon); ++n; XtSetArg(args[n], XmNdragOperations, XmDROP_MOVE); ++n; XtSetArg(args[n], XmNexportTargets, &target); ++n; XtSetArg(args[n], XmNnumExportTargets, 1); ++n; XtSetArg(args[n], XmNconvertProc, TabConvertProc); ++n; XtSetArg(args[n], XmNclientData, child); ++n; drag = XmDragStart(parent, event, args, n); n = 0; XtAddCallback(drag, XmNdragDropFinishCallback, DragCallback, (XtPointer) tab); XtAddCallback(drag, XmNdragMotionCallback, DragCallback, (XtPointer) tab); XtAddCallback(drag, XmNdropFinishCallback, DragCallback, (XtPointer) tab); XtAddCallback(drag, XmNdropSiteEnterCallback, DragCallback, (XtPointer) tab); XtAddCallback(drag, XmNdropSiteLeaveCallback, DragCallback, (XtPointer) tab); XtAddCallback(drag, XmNdropStartCallback, DragCallback, (XtPointer) tab); XtAddCallback(drag, XmNoperationChangedCallback, DragCallback, (XtPointer) tab); XtAddCallback(drag, XmNtopLevelEnterCallback, DragCallback, (XtPointer) tab); XtAddCallback(drag, XmNtopLevelLeaveCallback, DragCallback, (XtPointer) tab); } #endif