/* * tkoFrame.c -- * * This module implements "frame", "labelframe" and "toplevel" widgets * for the Tk toolkit. Frames are windows with a background color and * possibly a 3-D effect, but not much else in the way of attributes. * * Copyright (c) 1990-1994 The Regents of the University of California. * Copyright (c) 1994-1997 Sun Microsystems, Inc. * Copyright (c) 2019 Rene Zaumseil * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tkoWidget.h" /* * The following enum is used to define the type of the frame. */ enum FrameType { TYPE_FRAME, TYPE_TOPLEVEL, TYPE_LABELFRAME }; /* * tkoFrame -- * * A data structure of the following type is kept for each * frame that currently exists for this process. * * ATTENTION!!! * tkWinWM.c will call TkInstallFromMenu() from file tkFrame.c for toplevels. * Inside these function a struct Frame and memeber menuName will be used. * We noe have to ensure that our structure has the same form as Frame. * Therefore we place some dummy arguments in the structure. */ typedef struct tkoFrame { Tko_Widget widget; enum FrameType type; /* Type of widget, such as TYPE_FRAME. */ char *dummy1; char *menuName; /* Textual description of menu to use for * menubar. Malloc-ed, may be NULL. */ Colormap colormap; /* If not None, identifies a colormap * allocated for this window, which must be * freed when the window is deleted. */ Tk_3DBorder border; /* Structure used to draw 3-D border and * background. NULL means no background or * border. */ int borderWidth; /* Width of 3-D border (if any). */ int relief; /* 3-d effect: TK_RELIEF_RAISED etc. */ int highlightWidth; /* Width in pixels of highlight to draw around * widget when it has the focus. 0 means don't * draw a highlight. */ XColor *highlightBgColorPtr; /* Color for drawing traversal highlight area * when highlight is off. */ XColor *highlightColorPtr; /* Color for drawing traversal highlight. */ int width; /* Width to request for window. <= 0 means * don't request any size. */ int height; /* Height to request for window. <= 0 means * don't request any size. */ Tk_Cursor cursor; /* Current cursor for window, or None. */ Tk_Window tkWinCreate; char *dummy2; int isContainer; /* 1 means this window is a container, 0 means * that it isn't. */ Tcl_Obj *useThis; /* If the window is embedded, this points to * the name of the window in which it is * embedded (malloc'ed). For non-embedded * windows this is NULL. */ int flags; /* Various flags; see below for * definitions. */ int padX; /* Integer value corresponding to padXPtr. */ int padY; /* Integer value corresponding to padYPtr. */ unsigned int mask; Tk_Image bgimg; /* Derived from -backgroundimage by calling * Tk_GetImage, or NULL. */ int tile; /* Whether to tile the bgimg. */ #ifndef TK_NO_DOUBLE_BUFFERING GC copyGC; /* GC for copying when double-buffering. */ #endif /* TK_NO_DOUBLE_BUFFERING */ } tkoFrame; /* * tkoLabelframe -- * * A data structure of the following type is kept for each labelframe widget * managed by this file: */ typedef struct tkoLabelframe { tkoFrame frame; /* A pointer to the generic frame structure. * This must be the first element of the * tkoLabelframe. */ /* * tkoLabelframe specific configuration settings. */ Tcl_Obj *textPtr; /* Value of -text option: specifies text to * display in button. */ Tk_Font tkfont; /* Value of -font option: specifies font to * use for display text. */ XColor *textColorPtr; /* Value of -fg option: specifies foreground * color in normal mode. */ int labelAnchor; /* Value of -labelanchor option: specifies * where to place the label. */ Tk_Window labelWin; /* Value of -labelwidget option: Window to use * as label for the frame. */ /* * tkoLabelframe specific fields for use with configuration settings above. */ GC textGC; /* GC for drawing text in normal mode. */ Tk_TextLayout textLayout; /* Stored text layout information. */ XRectangle labelBox; /* The label's actual size and position. */ int labelReqWidth; /* The label's requested width. */ int labelReqHeight; /* The label's requested height. */ int labelTextX, labelTextY; /* Position of the text to be drawn. */ } tkoLabelframe; /* * The following macros define how many extra pixels to leave around a label's * text. */ #define LABELSPACING 1 #define LABELMARGIN 4 /* * Flag bits for frames: * * REDRAW_PENDING: Non-zero means a DoWhenIdle handler has * already been queued to redraw this window. * GOT_FOCUS: Non-zero means this widget currently has the * input focus. */ #define REDRAW_PENDING 1 #define GOT_FOCUS 4 /* * The following enum is used to define a type for the -labelanchor option of * the Labelframe widget. These values are used as indices into the string * table below. */ enum labelanchor { LABELANCHOR_E, LABELANCHOR_EN, LABELANCHOR_ES, LABELANCHOR_N, LABELANCHOR_NE, LABELANCHOR_NW, LABELANCHOR_S, LABELANCHOR_SE, LABELANCHOR_SW, LABELANCHOR_W, LABELANCHOR_WN, LABELANCHOR_WS }; /* * Methods */ static int FrameConstructorFrame( ClientData clientData, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]); static int FrameConstructorLabelframe( ClientData clientData, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]); static int FrameConstructorToplevel( ClientData clientData, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]); static int FrameConstructor( enum FrameType type, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]); static int FrameDestructor( ClientData clientData, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]); static int FrameMethod_tko_configure( ClientData clientData, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]); static int FrameMethod_labelanchor( ClientData clientData, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]); static int FrameMethod_labelwidget( ClientData clientData, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]); static int FrameMethod_backgroundimage( ClientData clientData, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]); static int FrameMethod_menu( ClientData clientData, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]); /* * Functions */ static void FrameComputeGeometry( tkoFrame * frame); static void FrameDisplay( ClientData clientData); static void FrameDrawBackground( Tk_Window tkwin, Pixmap pixmap, int highlightWidth, int borderWidth, Tk_Image bgimg, int bgtile); static void FrameBgImageProc( ClientData clientData, int x, int y, int width, int height, int imgWidth, int imgHeight); static void FrameEventProc( ClientData clientData, XEvent * eventPtr); static void FrameLostSlaveProc( ClientData clientData, Tk_Window tkWin); static void FrameRequestProc( ClientData clientData, Tk_Window tkWin); static void FrameStructureProc( ClientData clientData, XEvent * eventPtr); static void FrameWorldChanged( ClientData instanceData); static void FrameLabelwinRemove( tkoLabelframe * labelframe); static void FrameMap( ClientData clientData); /* * Data */ /* * frameClass -- * * The structure below defines frame class behavior by means of functions that * can be invoked from generic window code. */ static const Tk_ClassProcs frameClass = { sizeof(Tk_ClassProcs), /* size */ FrameWorldChanged, /* worldChangedProc */ NULL, /* createProc */ NULL /* modalProc */ }; /* * frameGeomType -- * * The structure below defines the official type record for the labelframe's * geometry manager: */ static const Tk_GeomMgr frameGeomType = { "labelframe", /* name */ FrameRequestProc, /* requestProc */ FrameLostSlaveProc /* lostSlaveProc */ }; /* * Definition of options created in object constructor. * Order of used options in definition is important: * -class -visual -colormap -container -use */ /* Common options for all defined widgets. */ #define FRAME_COMMONDEFINE \ { "-background" , "background", "Background", DEF_FRAME_BG_COLOR, TKO_OPTION_NULL, \ NULL, TKO_SET_3DBORDER, offsetof(tkoFrame, border)}, \ { "-backgroundimage", "backgroundImage", "BackgroundImage", DEF_FRAME_BG_IMAGE, 0, \ FrameMethod_backgroundimage ,TKO_SET_NONE, 0}, \ { "-bg" , "-background", NULL, NULL, 0, NULL,TKO_SET_NONE,0}, \ { "-bgimg", "-backgroundimage", NULL, NULL, 0, NULL,TKO_SET_NONE,0}, \ { "-bd" , "-borderwidth", NULL, NULL, 0, NULL, TKO_SET_NONE,0}, \ { "-cursor" , "cursor", "Cursor", DEF_FRAME_CURSOR, 0, \ NULL, TKO_SET_CURSOR, offsetof(tkoFrame, cursor)}, \ { "-height" , "height", "Height", DEF_FRAME_HEIGHT, 0, \ NULL, TKO_SET_PIXEL, offsetof(tkoFrame, height)}, \ { "-highlightbackground", "highlightbackground", "highlightBackground", DEF_FRAME_HIGHLIGHT_BG, 0, \ NULL, TKO_SET_XCOLOR, offsetof(tkoFrame, highlightBgColorPtr)}, \ { "-highlightcolor", "highlightColor", "HighlightColor", DEF_FRAME_HIGHLIGHT, 0, \ NULL, TKO_SET_XCOLOR, offsetof(tkoFrame, highlightColorPtr)}, \ { "-highlightthickness" , "highlightThickness", "HighlightThickness", DEF_FRAME_HIGHLIGHT_WIDTH, 0, \ NULL, TKO_SET_PIXEL, offsetof(tkoFrame, highlightWidth)}, \ { "-padx" , "padX", "Pad", DEF_FRAME_PADX, 0, \ NULL, TKO_SET_PIXEL, offsetof(tkoFrame, padX)}, \ { "-pady" , "padY", "Pad", DEF_FRAME_PADY, 0, \ NULL, TKO_SET_PIXEL, offsetof(tkoFrame, padY)}, \ { "-takefocus" , "takeFocus", "TakeFocus", DEF_FRAME_TAKE_FOCUS, 0, \ NULL, TKO_SET_STRING, 0}, \ { "-tile", "tile", "Tile", DEF_FRAME_BG_TILE, 0, \ NULL, TKO_SET_BOOLEAN, offsetof(tkoFrame, tile)}, \ { "-width" , "width", "Width", DEF_FRAME_WIDTH, 0, \ NULL, TKO_SET_PIXEL, offsetof(tkoFrame, width)}, \ { NULL,NULL,NULL,NULL,0,NULL,TKO_SET_NONE,0} /* * frameOptions -- * List of tko::frame options. */ static const Tko_WidgetOptionDefine frameOptions[] = { {"-class", "class", "Class", "TkoFrame", TKO_OPTION_READONLY, NULL, TKO_SET_CLASS, 0}, {"-visual", "visual", "Visual", DEF_FRAME_VISUAL, TKO_OPTION_READONLY, NULL, TKO_SET_VISUAL, 0}, {"-colormap", "colormap", "Colormap", DEF_FRAME_COLORMAP, TKO_OPTION_READONLY, NULL, TKO_SET_COLORMAP, 0}, {"-container", "container", "Container", DEF_FRAME_CONTAINER, TKO_OPTION_READONLY, NULL, TKO_SET_CONTAINER, offsetof(tkoFrame, isContainer)}, {"-borderwidth", "borderWidth", "BorderWidth", DEF_FRAME_BORDER_WIDTH, 0, NULL, TKO_SET_PIXEL, offsetof(tkoFrame, borderWidth)}, {"-relief", "relief", "Relief", DEF_FRAME_RELIEF, 0, NULL, TKO_SET_RELIEF, offsetof(tkoFrame, relief)}, FRAME_COMMONDEFINE }; /* * toplevelOptions -- * List of tko::toplevel options. */ static const Tko_WidgetOptionDefine toplevelOptions[] = { {"-screen", "screen", "Screen", "", TKO_OPTION_READONLY, NULL, TKO_SET_STRING, 0}, {"-class", "class", "Class", "TkoToplevel", TKO_OPTION_READONLY, NULL, TKO_SET_CLASS, 0}, {"-container", "container", "Container", DEF_FRAME_CONTAINER, TKO_OPTION_READONLY, NULL, TKO_SET_CONTAINER, offsetof(tkoFrame, isContainer)}, {"-use", "use", "Use", DEF_TOPLEVEL_USE, TKO_OPTION_READONLY|TKO_OPTION_NULL, NULL, TKO_SET_USE, offsetof(tkoFrame, useThis)}, {"-visual", "visual", "Visual", DEF_FRAME_VISUAL, TKO_OPTION_READONLY, NULL, TKO_SET_VISUAL, 0}, {"-colormap", "colormap", "Colormap", DEF_FRAME_COLORMAP, TKO_OPTION_READONLY, NULL, TKO_SET_COLORMAP, 0}, {"-borderwidth", "borderWidth", "BorderWidth", DEF_FRAME_BORDER_WIDTH, 0, NULL, TKO_SET_PIXEL, offsetof(tkoFrame, borderWidth)}, {"-menu", "menu", "Menu", DEF_TOPLEVEL_MENU, TKO_OPTION_NULL, FrameMethod_menu, TKO_SET_NONE, 0}, {"-relief", "relief", "Relief", DEF_FRAME_RELIEF, 0, NULL, TKO_SET_RELIEF, offsetof(tkoFrame, relief)}, FRAME_COMMONDEFINE }; /* * labelframeOptions -- * List of tko::labelframe options. */ static const Tko_WidgetOptionDefine labelframeOptions[] = { {"-class", "class", "Class", "TkoLabelframe", TKO_OPTION_READONLY, NULL, TKO_SET_CLASS, 0}, {"-visual", "visual", "Visual", DEF_FRAME_VISUAL, TKO_OPTION_READONLY, NULL, TKO_SET_VISUAL, 0}, {"-colormap", "colormap", "Colormap", DEF_FRAME_COLORMAP, TKO_OPTION_READONLY, NULL, TKO_SET_COLORMAP, 0}, {"-borderwidth", "borderWidth", "BorderWidth", DEF_LABELFRAME_BORDER_WIDTH, 0, NULL, TKO_SET_PIXEL, offsetof(tkoFrame, borderWidth)}, {"-fg", "-foreground", NULL, NULL, 0, NULL, TKO_SET_NONE, 0}, {"-font", "font", "Font", DEF_LABELFRAME_FONT, 0, NULL, TKO_SET_FONT, offsetof(tkoLabelframe, tkfont)}, {"-foreground", "foreground", "Foreground", DEF_LABELFRAME_FG, 0, NULL, TKO_SET_XCOLOR, offsetof(tkoLabelframe, textColorPtr)}, {"-labelanchor", "labelAnchor", "LabelAnchor", DEF_LABELFRAME_LABELANCHOR, 0, FrameMethod_labelanchor, TKO_SET_NONE, 0}, {"-labelwidget", "labelWidget", "LabelWidget", "",0, FrameMethod_labelwidget, TKO_SET_NONE, 0}, {"-relief", "relief", "Relief", DEF_LABELFRAME_RELIEF, 0, NULL, TKO_SET_RELIEF, offsetof(tkoFrame, relief)}, {"-text", "text", "Text", DEF_LABELFRAME_TEXT, 0, NULL, TKO_SET_TCLOBJ, offsetof(tkoLabelframe, textPtr)}, FRAME_COMMONDEFINE }; /* * Definition of object methods created in Tko_FrameInit() function. */ /* * frameMethods -- * List of used public and private tko::frame methods. */ static Tcl_MethodType frameMethods[] = { {TCL_OO_METHOD_VERSION_CURRENT, NULL, FrameConstructorFrame, NULL, NULL}, {TCL_OO_METHOD_VERSION_CURRENT, NULL, FrameDestructor, NULL, NULL}, {-1, NULL, NULL, NULL, NULL}, {TCL_OO_METHOD_VERSION_CURRENT, "_tko_configure", FrameMethod_tko_configure, NULL, NULL}, {-1, NULL, NULL, NULL, NULL} }; /* * labelframeMethods -- * List of used public and private tko::labelframe methods. */ static Tcl_MethodType labelframeMethods[] = { {TCL_OO_METHOD_VERSION_CURRENT, NULL, FrameConstructorLabelframe, NULL, NULL}, {TCL_OO_METHOD_VERSION_CURRENT, NULL, FrameDestructor, NULL, NULL}, {-1, NULL, NULL, NULL, NULL}, {TCL_OO_METHOD_VERSION_CURRENT, "_tko_configure", FrameMethod_tko_configure, NULL, NULL}, {-1, NULL, NULL, NULL, NULL} }; /* * toplevelMethods -- * List of used public and private tko::toplevel methods. */ static Tcl_MethodType toplevelMethods[] = { {TCL_OO_METHOD_VERSION_CURRENT, NULL, FrameConstructorToplevel, NULL, NULL}, {TCL_OO_METHOD_VERSION_CURRENT, NULL, FrameDestructor, NULL, NULL}, {-1, NULL, NULL, NULL, NULL}, {TCL_OO_METHOD_VERSION_CURRENT, "_tko_configure", FrameMethod_tko_configure, NULL, NULL}, {-1, NULL, NULL, NULL, NULL} }; /* * Tko_FrameInit -- * * Create tko frame widget class objects. * * Results: * A standard Tcl result. * * Side effects: * Create new oo::class's. */ int Tko_FrameInit( Tcl_Interp * interp) { /* Tcl interpreter. */ Tcl_Obj *tmpPtr; int ret; /* * ::tko::toplevel */ tmpPtr = Tcl_NewStringObj("::tko::toplevel", -1); Tcl_IncrRefCount(tmpPtr); ret = Tko_WidgetClassDefine(interp, tmpPtr, toplevelMethods, toplevelOptions); Tcl_DecrRefCount(tmpPtr); if (ret != TCL_OK) { return TCL_ERROR; } /* * ::tko::frame */ tmpPtr = Tcl_NewStringObj("::tko::frame", -1); Tcl_IncrRefCount(tmpPtr); ret = Tko_WidgetClassDefine(interp, tmpPtr, frameMethods, frameOptions); Tcl_DecrRefCount(tmpPtr); if (ret != TCL_OK) { return TCL_ERROR; } /* * ::tko::labelframe */ tmpPtr = Tcl_NewStringObj("::tko::labelframe", -1); Tcl_IncrRefCount(tmpPtr); ret = Tko_WidgetClassDefine(interp, tmpPtr, labelframeMethods, labelframeOptions); Tcl_DecrRefCount(tmpPtr); if (ret != TCL_OK) { return TCL_ERROR; } return TCL_OK; } /* * FrameConstructorFrame -- * * Results: * A standard Tcl result. * * Side effects: * Call common constructor for frames. */ static int FrameConstructorFrame( ClientData dummy, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]) { (void)dummy; return FrameConstructor(TYPE_FRAME, interp, context, objc, objv); } /* * FrameConstructorLabelframe -- * * Results: * A standard Tcl result. * * Side effects: * Call common constructor for labelframes. */ static int FrameConstructorLabelframe( ClientData dummy, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]) { (void)dummy; return FrameConstructor(TYPE_LABELFRAME, interp, context, objc, objv); } /* * FrameConstructorToplevel -- * * Results: * A standard Tcl result. * * Side effects: * Call common constructor for toplevels. */ static int FrameConstructorToplevel( ClientData dummy, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]) { (void)dummy; return FrameConstructor(TYPE_TOPLEVEL, interp, context, objc, objv); } /* * FrameConstructor -- * * Common part of all widget contructors. * * Results: * A standard Tcl result. * * Side effects: * Create new widget and options. * Set readonly options and default option values. */ static int FrameConstructor( enum FrameType type, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]) { Tcl_Object object; Tko_Widget *widget; tkoFrame *frame; Tcl_Obj *myArglist; int skip; Tko_WidgetCreateMode createMode; /* Get current object. Should not fail? */ if ((object = Tcl_ObjectContextObject(context)) == NULL) { return TCL_ERROR; } if (type == TYPE_FRAME) { frame = (tkoFrame *)ckalloc(sizeof(tkoFrame)); assert(frame); memset(frame, 0, sizeof(tkoFrame)); createMode = TKO_CREATE_WIDGET; } else if (type == TYPE_LABELFRAME) { tkoLabelframe *labelframe; labelframe = (tkoLabelframe *)ckalloc(sizeof(tkoLabelframe)); assert(labelframe); memset(labelframe, 0, sizeof(tkoLabelframe)); frame = (tkoFrame *)labelframe; labelframe->textPtr = NULL; labelframe->tkfont = NULL; labelframe->textColorPtr = NULL; labelframe->labelAnchor = LABELANCHOR_NW; labelframe->labelWin = NULL; labelframe->textGC = NULL; labelframe->textLayout = NULL; /*labelframe->labelBox */ labelframe->labelReqWidth = 0; labelframe->labelReqHeight = 0; labelframe->labelTextX = 0; labelframe->labelTextY = 0; createMode = TKO_CREATE_WIDGET; } else if (type == TYPE_TOPLEVEL) { frame = (tkoFrame *)ckalloc(sizeof(tkoFrame)); assert(frame); memset(frame, 0, sizeof(tkoFrame)); createMode = TKO_CREATE_TOPLEVEL; } else { Tcl_WrongNumArgs(interp, 1, objv, "internal type error"); return TCL_ERROR; } widget = (Tko_Widget *)frame; frame->type = type; frame->menuName = NULL; frame->colormap = None; frame->border = NULL; frame->borderWidth = 0; frame->relief = TK_RELIEF_FLAT; frame->highlightWidth = 0; frame->highlightBgColorPtr = NULL; frame->highlightColorPtr = NULL; frame->width = 0; frame->height = 0; frame->cursor = NULL; frame->isContainer = 0; frame->useThis = NULL; frame->flags = 0; frame->padX = 0; frame->padY = 0; frame->mask = ExposureMask | StructureNotifyMask | FocusChangeMask; frame->bgimg = NULL; #ifndef TK_NO_DOUBLE_BUFFERING frame->copyGC = NULL; #endif frame->tile = 0; if (type == TYPE_TOPLEVEL) { frame->mask |= ActivateMask; } skip = Tcl_ObjectContextSkippedArgs(context); if (objc - skip > 0) { myArglist = Tcl_NewListObj(objc - skip, &objv[skip]); } else { myArglist = Tcl_NewListObj(0, NULL); } if (Tko_WidgetCreate(&(frame->widget), interp, object, createMode, myArglist) != TCL_OK) { Tcl_DecrRefCount(myArglist); return TCL_ERROR; } Tcl_DecrRefCount(myArglist); frame->tkWinCreate = widget->tkWin; if (frame->isContainer && frame->useThis != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj ("windows cannot have both the -use and the -container" " option set", -1)); Tcl_SetErrorCode(interp, "TK", "FRAME", "CONTAINMENT", NULL); return TCL_ERROR; } /* * For top-level windows, provide an initial geometry request of 200x200, * just so the window looks nicer on the screen if it doesn't request a * size for itself. */ if (type == TYPE_TOPLEVEL) { Tk_GeometryRequest(widget->tkWin, 200, 200); } /* * Store backreference to frame widget in window structure. */ Tk_SetClassProcs(widget->tkWin, &frameClass, frame); /* * Mark Tk frames as suitable candidates for [wm manage]. */ ((TkWindow *) widget->tkWin)->flags |= TK_WM_MANAGEABLE; Tk_CreateEventHandler(widget->tkWin, frame->mask, FrameEventProc, frame); if (type == TYPE_TOPLEVEL) { Tcl_DoWhenIdle(FrameMap, frame); } return TCL_OK; } /* * FrameDestructor -- * * Results: * A standard Tcl result. * * Side effects: * Delete widget ressources. */ static int FrameDestructor( ClientData dummy, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]) { Tko_Widget *widget; (void)dummy; (void)interp; (void)objc; (void)objv; if((widget = (Tko_Widget *)Tko_WidgetClientData(context)) != NULL) { tkoFrame *frame = (tkoFrame *)widget; tkoLabelframe *labelframe = (tkoLabelframe *) widget; Tcl_Preserve(widget); if(widget->tkWin) { Tk_DeleteEventHandler(widget->tkWin, frame->mask, FrameEventProc, frame); } if(widget->display != NULL) { #ifndef TK_NO_DOUBLE_BUFFERING if (frame->copyGC != NULL) { Tk_FreeGC(widget->display, frame->copyGC); } frame->copyGC = NULL; #endif /* TK_NO_DOUBLE_BUFFERING */ if(frame->cursor != NULL) { Tk_FreeCursor(widget->display, frame->cursor); } frame->cursor = NULL; } if (frame->bgimg != NULL) { Tk_FreeImage(frame->bgimg); } frame->bgimg = NULL; frame->flags = 0; Tcl_CancelIdleCall(FrameDisplay, frame); Tcl_CancelIdleCall(FrameMap, frame); if(frame->menuName != NULL && frame->tkWinCreate) { Tk_SetWindowMenubar(frame->widget.interp, frame->tkWinCreate, frame->menuName, NULL); ckfree(frame->menuName); frame->menuName = NULL; } if(frame->type == TYPE_LABELFRAME && labelframe->labelWin) { Tk_ManageGeometry(labelframe->labelWin, NULL, NULL); if(widget->tkWin && (widget->tkWin != Tk_Parent(labelframe->labelWin))) { Tk_UnmaintainGeometry(labelframe->labelWin, widget->tkWin); } Tk_UnmapWindow(labelframe->labelWin); labelframe->labelWin = NULL; } if (frame->useThis) { Tcl_DecrRefCount(frame->useThis); } if (frame->type == TYPE_LABELFRAME) { if (labelframe->textLayout) { Tk_FreeTextLayout(labelframe->textLayout); } if (labelframe->textGC != NULL && widget->display != NULL) { Tk_FreeGC(widget->display, labelframe->textGC); } } if (frame->border) { Tk_Free3DBorder(frame->border); } if (frame->colormap != None && widget->display != NULL) { Tk_FreeColormap(widget->display, frame->colormap); } if (frame->highlightBgColorPtr != NULL) { Tk_FreeColor(frame->highlightBgColorPtr); } if (frame->highlightColorPtr != NULL) { Tk_FreeColor(frame->highlightColorPtr); } Tko_WidgetDestroy(context); Tcl_Release(frame); } return TCL_OK; } /* * FrameMethod_tko_configure -- * * Results: * A standard Tcl result. * * Side effects: * After configure step. */ static int FrameMethod_tko_configure( ClientData dummy, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]) { Tko_Widget *widget; tkoFrame *frame; (void)dummy; (void)interp; (void)objc; (void)objv; if((widget = (Tko_Widget *)Tko_WidgetClientData(context)) == NULL || widget->tkWin == NULL) { return TCL_ERROR; } frame = (tkoFrame *)widget; if(frame->border != NULL) { Tk_SetBackgroundFromBorder(widget->tkWin, frame->border); } else { Tk_SetWindowBackgroundPixmap(widget->tkWin, None); } if(frame->highlightWidth < 0) { frame->highlightWidth = 0; } if(frame->padX < 0) { frame->padX = 0; } if(frame->padY < 0) { frame->padY = 0; } FrameWorldChanged(frame); return TCL_OK; } /* * FrameMethod_labelanchor -- * * Process -labelanchor option. * * Results: * A standard Tcl result. * * Side effects: * Set new option value. */ static int FrameMethod_labelanchor( ClientData dummy, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]) { int index, code; tkoFrame *frame; tkoLabelframe *labelframe; Tcl_Obj *value; static const char *const labelAnchorStrings[] = { "e", "en", "es", "n", "ne", "nw", "s", "se", "sw", "w", "wn", "ws", NULL }; (void)dummy; if((frame = (tkoFrame *)Tko_WidgetClientData(context)) == NULL || (value = Tko_WidgetOptionGet(&frame->widget, objv[objc - 1])) == NULL) { return TCL_ERROR; } labelframe = (tkoLabelframe *)frame; code = Tcl_GetIndexFromObj(interp, value, labelAnchorStrings, "labelanchor", 0, &index); if(code != TCL_OK) { return TCL_ERROR; } labelframe->labelAnchor = (Tk_Anchor) index; return TCL_OK; } /* * FrameMethod_labelwidget -- * * Process -labelwidget option. * * Results: * A standard Tcl result. * * Side effects: * Set new option value. */ static int FrameMethod_labelwidget( ClientData dummy, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]) { Tko_Widget *widget; Tk_Window oldWindow = NULL; Tk_Window newWindow = NULL; Tk_Window ancestor, parent, sibling = NULL; tkoLabelframe *labelframe; Tcl_Obj *value; (void)dummy; if((widget = (Tko_Widget *)Tko_WidgetClientData(context)) == NULL || widget->tkWin == NULL || (value = Tko_WidgetOptionGet(widget, objv[objc - 1])) == NULL) { return TCL_ERROR; } labelframe = (tkoLabelframe *)widget; if(value == NULL || Tcl_GetCharLength(value) == 0) { newWindow = NULL; } else if(TkGetWindowFromObj(interp, widget->tkWin, value, &newWindow) != TCL_OK) { return TCL_ERROR; } /* * If a -labelwidget is specified, check that it is valid and set up * geometry management for it. */ oldWindow = labelframe->labelWin; if(oldWindow != newWindow) { if(newWindow != NULL) { /* * Make sure that the frame is either the parent of the window * used as label or a descendant of that parent. Also, don't * allow a top-level window to be managed inside the frame. */ parent = Tk_Parent(newWindow); for(ancestor = widget->tkWin;; ancestor = Tk_Parent(ancestor)) { if(ancestor == parent) { break; } sibling = ancestor; if(Tk_IsTopLevel(ancestor)) { goto badLabelWindow; } } if(Tk_IsTopLevel(newWindow)) { goto badLabelWindow; } if(newWindow == widget->tkWin) { goto badLabelWindow; } } if(oldWindow != NULL) { Tk_DeleteEventHandler(oldWindow, StructureNotifyMask, FrameStructureProc, labelframe); Tk_ManageGeometry(oldWindow, NULL, NULL); Tk_UnmaintainGeometry(oldWindow, widget->tkWin); Tk_UnmapWindow(oldWindow); } if(newWindow != NULL) { Tk_CreateEventHandler(newWindow, StructureNotifyMask, FrameStructureProc, labelframe); Tk_ManageGeometry(newWindow, &frameGeomType, labelframe); /* * If the frame is not parent to the label, make sure the * label is above its sibling in the stacking order. */ if(sibling != NULL) { Tk_RestackWindow(newWindow, Above, sibling); } } labelframe->labelWin = newWindow; } return TCL_OK; badLabelWindow: Tcl_SetObjResult(interp, Tcl_ObjPrintf("can't use %s as label in this frame", Tk_PathName(labelframe->labelWin))); Tcl_SetErrorCode(interp, "TK", "GEOMETRY", "HIERARCHY", NULL); labelframe->labelWin = NULL; return TCL_ERROR; } /* * FrameMethod_backgroundimage -- * * Process -backgroundimage option. * * Results: * A standard Tcl result. * * Side effects: * Set new option value. */ static int FrameMethod_backgroundimage( ClientData dummy, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]) { Tko_Widget *widget; tkoFrame *frame; Tcl_Obj *value; Tk_Image image; (void)dummy; if((widget = (Tko_Widget *)Tko_WidgetClientData(context)) == NULL || widget->tkWin == NULL || (value = Tko_WidgetOptionGet(widget, objv[objc - 1])) == NULL) { return TCL_ERROR; } frame = (tkoFrame *)widget; /* check on widget destroyed */ if(widget->tkWin == NULL) return TCL_OK; /* try to create new image */ if(value == NULL || Tcl_GetCharLength(value) == 0) { image = NULL; } else { image = Tk_GetImage(interp, widget->tkWin, Tcl_GetString(value), FrameBgImageProc, frame); if (image == NULL) { return TCL_ERROR; } } if (frame->bgimg) { Tk_FreeImage(frame->bgimg); } frame->bgimg = image; return TCL_OK; } /* * FrameMethod_menu -- * * Process -menu option. * * Results: * A standard Tcl result. * * Side effects: * Set new option value. */ static int FrameMethod_menu( ClientData dummy, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]) { Tko_Widget *widget; tkoFrame *frame; Tcl_Obj *value; char *newMenu; int length; (void)dummy; if((widget = (Tko_Widget *)Tko_WidgetClientData(context)) == NULL || widget->tkWin == NULL || (value = Tko_WidgetOptionGet(widget, objv[objc - 1])) == NULL) { return TCL_ERROR; } frame = (tkoFrame *)widget; newMenu = Tcl_GetStringFromObj(value, &length); if (length==0) { newMenu = NULL; } if ((((newMenu == NULL) && (frame->menuName != NULL)) || ((newMenu != NULL) && (frame->menuName == NULL)) || ((newMenu != NULL) && (frame->menuName != NULL) && strcmp(newMenu, frame->menuName) != 0)) && frame->type == TYPE_TOPLEVEL) { Tk_SetWindowMenubar(interp, widget->tkWin, frame->menuName, newMenu); if (frame->menuName) { ckfree(frame->menuName); } if (length) { frame->menuName = (char *)ckalloc(length + 1); assert(frame->menuName); strncpy(frame->menuName,newMenu,length); frame->menuName[length] = '\0'; } else { frame->menuName = NULL; } } return TCL_OK; } /* * FrameWorldChanged -- * * This function is called when the world has changed in some way and the * widget needs to recompute all its graphics contexts and determine its * new geometry. * * Results: * None. * * Side effects: * Frame will be relayed out and redisplayed. */ static void FrameWorldChanged( ClientData clientData) { /* Information about widget. */ Tko_Widget *widget = (Tko_Widget *)clientData; tkoFrame *frame = (tkoFrame *)clientData; tkoLabelframe *labelframe = (tkoLabelframe *)clientData; XGCValues gcValues; GC gc; int anyTextLabel, anyWindowLabel; int bWidthLeft, bWidthRight, bWidthTop, bWidthBottom; const char *labelText; if (widget->tkWin == NULL) { return; } anyTextLabel = (frame->type == TYPE_LABELFRAME) && (labelframe->textPtr != NULL) && (labelframe->labelWin == NULL); anyWindowLabel = (frame->type == TYPE_LABELFRAME) && (labelframe->labelWin != NULL); #ifndef TK_NO_DOUBLE_BUFFERING gcValues.graphics_exposures = False; gc = Tk_GetGC(widget->tkWin, GCGraphicsExposures, &gcValues); if (frame->copyGC != NULL) { Tk_FreeGC(widget->display, frame->copyGC); } frame->copyGC = gc; #endif /* TK_NO_DOUBLE_BUFFERING */ if(frame->type == TYPE_LABELFRAME) { /* * The textGC is needed even in the labelWin case, so it's always * created for a labelframe. */ gcValues.font = Tk_FontId(labelframe->tkfont); gcValues.foreground = labelframe->textColorPtr->pixel; gcValues.graphics_exposures = False; gc = Tk_GetGC(widget->tkWin, GCForeground | GCFont | GCGraphicsExposures, &gcValues); if(labelframe->textGC != NULL) { Tk_FreeGC(widget->display, labelframe->textGC); } labelframe->textGC = gc; /* * Calculate label size. */ labelframe->labelReqWidth = labelframe->labelReqHeight = 0; if(anyTextLabel) { labelText = Tcl_GetString(labelframe->textPtr); if(labelframe->textLayout) { Tk_FreeTextLayout(labelframe->textLayout); } labelframe->textLayout = Tk_ComputeTextLayout(labelframe->tkfont, labelText, -1, 0, TK_JUSTIFY_CENTER, 0, &labelframe->labelReqWidth, &labelframe->labelReqHeight); labelframe->labelReqWidth += 2 * LABELSPACING; labelframe->labelReqHeight += 2 * LABELSPACING; } else if(anyWindowLabel) { labelframe->labelReqWidth = Tk_ReqWidth(labelframe->labelWin); labelframe->labelReqHeight = Tk_ReqHeight(labelframe->labelWin); } /* * Make sure label size is at least as big as the border. This * simplifies later calculations and gives a better appearance with * thick borders. */ if((labelframe->labelAnchor >= LABELANCHOR_N) && (labelframe->labelAnchor <= LABELANCHOR_SW)) { if(labelframe->labelReqHeight < frame->borderWidth) { labelframe->labelReqHeight = frame->borderWidth; } } else { if(labelframe->labelReqWidth < frame->borderWidth) { labelframe->labelReqWidth = frame->borderWidth; } } } /* * Calculate individual border widths. */ bWidthBottom = bWidthTop = bWidthRight = bWidthLeft = frame->borderWidth + frame->highlightWidth; bWidthLeft += frame->padX; bWidthRight += frame->padX; bWidthTop += frame->padY; bWidthBottom += frame->padY; if(anyTextLabel || anyWindowLabel) { switch (labelframe->labelAnchor) { case LABELANCHOR_E: case LABELANCHOR_EN: case LABELANCHOR_ES: bWidthRight += labelframe->labelReqWidth - frame->borderWidth; break; case LABELANCHOR_N: case LABELANCHOR_NE: case LABELANCHOR_NW: bWidthTop += labelframe->labelReqHeight - frame->borderWidth; break; case LABELANCHOR_S: case LABELANCHOR_SE: case LABELANCHOR_SW: bWidthBottom += labelframe->labelReqHeight - frame->borderWidth; break; default: bWidthLeft += labelframe->labelReqWidth - frame->borderWidth; break; } } Tk_SetInternalBorderEx(widget->tkWin, bWidthLeft, bWidthRight, bWidthTop, bWidthBottom); FrameComputeGeometry(frame); /* * A labelframe should request size for its label. */ if(frame->type == TYPE_LABELFRAME) { int minwidth = labelframe->labelReqWidth; int minheight = labelframe->labelReqHeight; int padding = frame->highlightWidth; if(frame->borderWidth > 0) { padding += frame->borderWidth + LABELMARGIN; } padding *= 2; if((labelframe->labelAnchor >= LABELANCHOR_N) && (labelframe->labelAnchor <= LABELANCHOR_SW)) { minwidth += padding; minheight += frame->borderWidth + frame->highlightWidth; } else { minheight += padding; minwidth += frame->borderWidth + frame->highlightWidth; } Tk_SetMinimumRequestSize(widget->tkWin, minwidth, minheight); } if((frame->width > 0) || (frame->height > 0)) { Tk_GeometryRequest(widget->tkWin, frame->width, frame->height); } if(Tk_IsMapped(widget->tkWin)) { if(!(frame->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(FrameDisplay, frame); } frame->flags |= REDRAW_PENDING; } } /* * FrameComputeGeometry -- * * This function is called to compute various geometrical information for * a frame, such as where various things get displayed. It's called when * the window is reconfigured. * * Results: * None. * * Side effects: * Display-related numbers get changed in *frame. */ static void FrameComputeGeometry( tkoFrame * frame) { int otherWidth, otherHeight, otherWidthT, otherHeightT, padding; int maxWidth, maxHeight; Tko_Widget *widget = (Tko_Widget *)frame; tkoLabelframe *labelframe = (tkoLabelframe *) frame; /* * We have nothing to do here unless there is a label. */ if (widget->tkWin == NULL || frame->type != TYPE_LABELFRAME) { return; } if(labelframe->textPtr == NULL && labelframe->labelWin == NULL) { return; } /* * Calculate the available size for the label */ labelframe->labelBox.width = labelframe->labelReqWidth; labelframe->labelBox.height = labelframe->labelReqHeight; padding = frame->highlightWidth; if(frame->borderWidth > 0) { padding += frame->borderWidth + LABELMARGIN; } padding *= 2; maxHeight = Tk_Height(widget->tkWin); maxWidth = Tk_Width(widget->tkWin); if((labelframe->labelAnchor >= LABELANCHOR_N) && (labelframe->labelAnchor <= LABELANCHOR_SW)) { maxWidth -= padding; if(maxWidth < 1) { maxWidth = 1; } } else { maxHeight -= padding; if(maxHeight < 1) { maxHeight = 1; } } if(labelframe->labelBox.width > maxWidth) { labelframe->labelBox.width = maxWidth; } if(labelframe->labelBox.height > maxHeight) { labelframe->labelBox.height = maxHeight; } /* * Calculate label and text position. The text's position is based on the * requested size (= the text's real size) to get proper alignment if the * text does not fit. */ otherWidth = Tk_Width(widget->tkWin) - labelframe->labelBox.width; otherHeight = Tk_Height(widget->tkWin) - labelframe->labelBox.height; otherWidthT = Tk_Width(widget->tkWin) - labelframe->labelReqWidth; otherHeightT = Tk_Height(widget->tkWin) - labelframe->labelReqHeight; padding = frame->highlightWidth; switch (labelframe->labelAnchor) { case LABELANCHOR_E: case LABELANCHOR_EN: case LABELANCHOR_ES: labelframe->labelTextX = otherWidthT - padding; labelframe->labelBox.x = otherWidth - padding; break; case LABELANCHOR_N: case LABELANCHOR_NE: case LABELANCHOR_NW: labelframe->labelTextY = padding; labelframe->labelBox.y = padding; break; case LABELANCHOR_S: case LABELANCHOR_SE: case LABELANCHOR_SW: labelframe->labelTextY = otherHeightT - padding; labelframe->labelBox.y = otherHeight - padding; break; default: labelframe->labelTextX = padding; labelframe->labelBox.x = padding; break; } if(frame->borderWidth > 0) { padding += frame->borderWidth + LABELMARGIN; } switch (labelframe->labelAnchor) { case LABELANCHOR_NW: case LABELANCHOR_SW: labelframe->labelTextX = padding; labelframe->labelBox.x = padding; break; case LABELANCHOR_N: case LABELANCHOR_S: labelframe->labelTextX = otherWidthT / 2; labelframe->labelBox.x = otherWidth / 2; break; case LABELANCHOR_NE: case LABELANCHOR_SE: labelframe->labelTextX = otherWidthT - padding; labelframe->labelBox.x = otherWidth - padding; break; case LABELANCHOR_EN: case LABELANCHOR_WN: labelframe->labelTextY = padding; labelframe->labelBox.y = padding; break; case LABELANCHOR_E: case LABELANCHOR_W: labelframe->labelTextY = otherHeightT / 2; labelframe->labelBox.y = otherHeight / 2; break; default: labelframe->labelTextY = otherHeightT - padding; labelframe->labelBox.y = otherHeight - padding; break; } } /* * FrameDisplay -- * * This function is invoked to display a frame widget. * * Results: * None. * * Side effects: * Commands are output to X to display the frame in its current mode. */ static void FrameDisplay( ClientData clientData /* Information about widget. */) { Tko_Widget *widget = (Tko_Widget *)clientData; tkoFrame *frame = (tkoFrame *)clientData; int bdX1, bdY1, bdX2, bdY2, hlWidth; Pixmap pixmap; TkRegion clipRegion = NULL; if (widget->tkWin == NULL) { return; } frame->flags &= ~REDRAW_PENDING; if(!Tk_IsMapped(widget->tkWin)) { return; } /* * Highlight shall always be drawn if it exists, so do that first. */ hlWidth = frame->highlightWidth; if(hlWidth != 0) { GC fgGC, bgGC; bgGC = Tk_GCForColor(frame->highlightBgColorPtr, Tk_WindowId(widget->tkWin)); if(frame->flags & GOT_FOCUS) { fgGC = Tk_GCForColor(frame->highlightColorPtr, Tk_WindowId(widget->tkWin)); Tk_DrawHighlightBorder(widget->tkWin, fgGC, bgGC, hlWidth, Tk_WindowId(widget->tkWin)); } else { Tk_DrawHighlightBorder(widget->tkWin, bgGC, bgGC, hlWidth, Tk_WindowId(widget->tkWin)); } } /* * If -background is set to "", no interior is drawn. */ if(frame->border == NULL) { return; } #ifndef TK_NO_DOUBLE_BUFFERING /* * In order to avoid screen flashes, this function redraws the frame into * off-screen memory, then copies it back on-screen in a single operation. * This means there's no point in time where the on-screen image has been * cleared. */ pixmap = Tk_GetPixmap(widget->display, Tk_WindowId(widget->tkWin), Tk_Width(widget->tkWin), Tk_Height(widget->tkWin), Tk_Depth(widget->tkWin)); #else pixmap = Tk_WindowId(widget->tkWin); #endif /* TK_NO_DOUBLE_BUFFERING */ if(frame->type != TYPE_LABELFRAME) { /* * Pass to platform specific draw function. In general, it just draws * a simple rectangle, but it may "theme" the background. */ noLabel: TkpDrawFrameEx(widget->tkWin, pixmap, frame->border, hlWidth, frame->borderWidth, frame->relief); if (frame->bgimg) { FrameDrawBackground(widget->tkWin, pixmap, hlWidth, frame->borderWidth, frame->bgimg, frame->tile); } } else { tkoLabelframe *labelframe = (tkoLabelframe *) frame; if((labelframe->textPtr == NULL) && (labelframe->labelWin == NULL)) { goto noLabel; } /* * Clear the pixmap. */ Tk_Fill3DRectangle(widget->tkWin, pixmap, frame->border, 0, 0, Tk_Width(widget->tkWin), Tk_Height(widget->tkWin), 0, TK_RELIEF_FLAT); /* * Calculate how the label affects the border's position. */ bdX1 = bdY1 = hlWidth; bdX2 = Tk_Width(widget->tkWin) - hlWidth; bdY2 = Tk_Height(widget->tkWin) - hlWidth; switch (labelframe->labelAnchor) { case LABELANCHOR_E: case LABELANCHOR_EN: case LABELANCHOR_ES: bdX2 -= (labelframe->labelBox.width - frame->borderWidth) / 2; break; case LABELANCHOR_N: case LABELANCHOR_NE: case LABELANCHOR_NW: /* * Since the glyphs of the text tend to be in the lower part we * favor a lower border position by rounding up. */ bdY1 += (labelframe->labelBox.height - frame->borderWidth + 1) / 2; break; case LABELANCHOR_S: case LABELANCHOR_SE: case LABELANCHOR_SW: bdY2 -= (labelframe->labelBox.height - frame->borderWidth) / 2; break; default: bdX1 += (labelframe->labelBox.width - frame->borderWidth) / 2; break; } /* * Draw border */ Tk_Draw3DRectangle(widget->tkWin, pixmap, frame->border, bdX1, bdY1, bdX2 - bdX1, bdY2 - bdY1, frame->borderWidth, frame->relief); if(labelframe->labelWin == NULL) { /* * Clear behind the label */ Tk_Fill3DRectangle(widget->tkWin, pixmap, frame->border, labelframe->labelBox.x, labelframe->labelBox.y, labelframe->labelBox.width, labelframe->labelBox.height, 0, TK_RELIEF_FLAT); /* * Draw label. If there is not room for the entire label, use * clipping to get a nice appearance. */ if((labelframe->labelBox.width < labelframe->labelReqWidth) || (labelframe->labelBox.height < labelframe->labelReqHeight)) { clipRegion = TkCreateRegion(); TkUnionRectWithRegion(&labelframe->labelBox, clipRegion, clipRegion); TkSetRegion(widget->display, labelframe->textGC, clipRegion); } Tk_DrawTextLayout(widget->display, pixmap, labelframe->textGC, labelframe->textLayout, labelframe->labelTextX + LABELSPACING, labelframe->labelTextY + LABELSPACING, 0, -1); if(clipRegion != NULL) { XSetClipMask(widget->display, labelframe->textGC, None); TkDestroyRegion(clipRegion); } } else { /* * Reposition and map the window (but in different ways depending * on whether the frame is the window's parent). */ if(widget->tkWin == Tk_Parent(labelframe->labelWin)) { if((labelframe->labelBox.x != Tk_X(labelframe->labelWin)) || (labelframe->labelBox.y != Tk_Y(labelframe->labelWin)) || (labelframe->labelBox.width != Tk_Width(labelframe->labelWin)) || (labelframe->labelBox.height != Tk_Height(labelframe->labelWin))) { Tk_MoveResizeWindow(labelframe->labelWin, labelframe->labelBox.x, labelframe->labelBox.y, labelframe->labelBox.width, labelframe->labelBox.height); } Tk_MapWindow(labelframe->labelWin); } else { Tk_MaintainGeometry(labelframe->labelWin, widget->tkWin, labelframe->labelBox.x, labelframe->labelBox.y, labelframe->labelBox.width, labelframe->labelBox.height); } } } #ifndef TK_NO_DOUBLE_BUFFERING /* * Everything's been redisplayed; now copy the pixmap onto the screen * and free up the pixmap. */ XCopyArea(widget->display, pixmap, Tk_WindowId(widget->tkWin), frame->copyGC, hlWidth, hlWidth, (unsigned)(Tk_Width(widget->tkWin) - 2 * hlWidth), (unsigned)(Tk_Height(widget->tkWin) - 2 * hlWidth), hlWidth, hlWidth); Tk_FreePixmap(widget->display, pixmap); #endif /* TK_NO_DOUBLE_BUFFERING */ } /* * FrameEventProc -- * * This function is invoked by the Tk dispatcher on structure changes to * a frame. For frames with 3D borders, this function is also invoked for * exposures. * * Results: * None. * * Side effects: * When the window gets deleted, internal structures get cleaned up. * When it gets exposed, it is redisplayed. */ static void FrameEventProc( ClientData clientData, /* Information about window. */ register XEvent * eventPtr) { /* Information about event. */ Tko_Widget *widget = (Tko_Widget *)clientData; tkoFrame *frame = (tkoFrame *)clientData; if(eventPtr->type == DestroyNotify || widget->tkWin == NULL || widget->tkWin == NULL) return; if((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) { goto redraw; } else if(eventPtr->type == ConfigureNotify) { FrameComputeGeometry(frame); goto redraw; } else if(eventPtr->type == FocusIn) { if(eventPtr->xfocus.detail != NotifyInferior) { frame->flags |= GOT_FOCUS; if(frame->highlightWidth > 0) { goto redraw; } } } else if(eventPtr->type == FocusOut) { if(eventPtr->xfocus.detail != NotifyInferior) { frame->flags &= ~GOT_FOCUS; if(frame->highlightWidth > 0) { goto redraw; } } } else if(eventPtr->type == ActivateNotify) { Tk_SetMainMenubar(frame->widget.interp, widget->tkWin, frame->menuName); } return; redraw: if(!(frame->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(FrameDisplay, frame); frame->flags |= REDRAW_PENDING; } } /* * FrameMap -- * * This function is invoked as a when-idle handler to map a newly-created * top-level frame. * * Results: * None. * * Side effects: * The frame given by the clientData argument is mapped. */ static void FrameMap( ClientData clientData) { /* Pointer to frame structure. */ Tko_Widget *widget = (Tko_Widget *)clientData; tkoFrame *frame = (tkoFrame *)clientData; if (widget->tkWin == NULL) { return; } /* * Wait for all other background events to be processed before mapping * window. This ensures that the window's correct geometry will have been * determined before it is first mapped, so that the window manager * doesn't get a false idea of its desired geometry. */ Tcl_Preserve(frame); while(1) { if(Tcl_DoOneEvent(TCL_IDLE_EVENTS) == 0) { break; } /* * After each event, make sure that the window still exists and quit * if the window has been destroyed. */ if(widget->tkWin == NULL) { Tcl_Release(frame); return; } } Tk_MapWindow(widget->tkWin); Tcl_Release(frame); } /* * FrameStructureProc -- * * This function is invoked whenever StructureNotify events occur for a * window that's managed as label for the frame. This procudure's only * purpose is to clean up when windows are deleted. * * Results: * None. * * Side effects: * The window is disassociated from the frame when it is deleted. */ static void FrameStructureProc( ClientData clientData, /* Pointer to record describing frame. */ XEvent * eventPtr) { /* Describes what just happened. */ tkoLabelframe *labelframe = (tkoLabelframe *)clientData; /* * This should only happen in a labelframe but it doesn't hurt to be * careful. */ if((eventPtr->type == DestroyNotify) && (labelframe->frame.type == TYPE_LABELFRAME)) { FrameLabelwinRemove(labelframe); } } /* * FrameLabelwinRemove -- * * Results: * None. * * Side effects: */ static void FrameLabelwinRemove( tkoLabelframe * labelframe) { tkoFrame *frame = (tkoFrame *) labelframe; Tcl_Obj *tmpPtr; labelframe->labelWin = NULL; tmpPtr = Tcl_NewStringObj("-labelwidget", -1); Tcl_IncrRefCount(tmpPtr); Tko_WidgetOptionSet(&frame->widget, tmpPtr, Tcl_NewStringObj("", 0)); Tcl_DecrRefCount(tmpPtr); FrameWorldChanged(labelframe); } /* * FrameRequestProc -- * * This function is invoked whenever a window that's associated with a * frame changes its requested dimensions. * * Results: * None. * * Side effects: * The size and location on the screen of the window may change depending * on the options specified for the frame. */ static void FrameRequestProc( ClientData clientData, /* Pointer to record for frame. */ Tk_Window tkWin) { /* Window that changed its desired size. */ tkoFrame *frame = (tkoFrame *)clientData; (void)tkWin; FrameWorldChanged(frame); } /* * FrameLostSlaveProc -- * * This function is invoked by Tk whenever some other geometry claims * control over a slave that used to be managed by us. * * Results: * None. * * Side effects: * Forgets all frame-related information about the slave. */ static void FrameLostSlaveProc( ClientData clientData, /* Frame structure for slave window that was * stolen away. */ Tk_Window tkWin /* Tk's handle for the slave window. */) { tkoLabelframe *labelframe = (tkoLabelframe *)clientData; /* * This should only happen in a labelframe but it doesn't hurt to be * careful. */ if(labelframe->frame.type == TYPE_LABELFRAME) { Tk_DeleteEventHandler(labelframe->labelWin, StructureNotifyMask, FrameStructureProc, labelframe); if(tkWin != Tk_Parent(labelframe->labelWin)) { Tk_UnmaintainGeometry(labelframe->labelWin, tkWin); } Tk_UnmapWindow(labelframe->labelWin); FrameLabelwinRemove(labelframe); } } /* *---------------------------------------------------------------------- * * FrameBgImageProc -- * * This function is invoked by the image code whenever the manager for an * image does something that affects the size or contents of an image * displayed on a frame's background. * * Results: * None. * * Side effects: * Arranges for the button to get redisplayed. * *---------------------------------------------------------------------- */ static void FrameBgImageProc( ClientData clientData, /* Pointer to widget record. */ int x, int y, /* Upper left pixel (within image) that must * be redisplayed. */ int width, int height, /* Dimensions of area to redisplay (might be * <= 0). */ int imgWidth, int imgHeight)/* New dimensions of image. */ { Tko_Widget *widget = (Tko_Widget *)clientData; tkoFrame *frame = (tkoFrame *)clientData; (void)x; (void)y; (void)width; (void)height; (void)imgWidth; (void)imgHeight; if (widget->tkWin == NULL) return; /* * Changing the background image never alters the dimensions of the frame. */ if (Tk_IsMapped(widget->tkWin) && !(frame->flags & REDRAW_PENDING)) { Tcl_DoWhenIdle(FrameDisplay, frame); frame->flags |= REDRAW_PENDING; } } /* *---------------------------------------------------------------------- * * FrameDrawBackground -- * * This function draws the background image of a rectangular frame area. * * Results: * None. * * Side effects: * Draws inside the tkwin area. * *---------------------------------------------------------------------- */ static void FrameDrawBackground( Tk_Window tkwin, Pixmap pixmap, int highlightWidth, int borderWidth, Tk_Image bgimg, int bgtile) { int width, height; /* Area to paint on. */ int imageWidth, imageHeight; /* Dimensions of image. */ const int bw = highlightWidth + borderWidth; Tk_SizeOfImage(bgimg, &imageWidth, &imageHeight); width = Tk_Width(tkwin) - 2*bw; height = Tk_Height(tkwin) - 2*bw; if (bgtile) { /* * Draw the image tiled in the widget (inside the border). */ int x, y; for (x = bw; x - bw < width; x += imageWidth) { int w = imageWidth; if (x - bw + imageWidth > width) { w = (width + bw) - x; } for (y = bw; y < height + bw; y += imageHeight) { int h = imageHeight; if (y - bw + imageHeight > height) { h = (height + bw) - y; } Tk_RedrawImage(bgimg, 0, 0, w, h, pixmap, x, y); } } } else { /* * Draw the image centred in the widget (inside the border). */ int x, y, xOff, yOff, w, h; if (width > imageWidth) { x = 0; xOff = (Tk_Width(tkwin) - imageWidth) / 2; w = imageWidth; } else { x = (imageWidth - width) / 2; xOff = bw; w = width; } if (height > imageHeight) { y = 0; yOff = (Tk_Height(tkwin) - imageHeight) / 2; h = imageHeight; } else { y = (imageHeight - height) / 2; yOff = bw; h = height; } Tk_RedrawImage(bgimg, x, y, w, h, pixmap, xOff, yOff); } } /* vim: set ts=4 sw=4 sts=4 ff=unix et : */