/* * 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: */ typedef struct tkoFrame { Tk_Window *win; Tcl_Object object; Tcl_Interp *interp; Display *display; enum FrameType type; /* Type of widget, such as TYPE_FRAME. */ 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. */ 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; } 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 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_tko_option( 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[]); /* * Functions */ static int FrameConstructor( int type, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]); static void FrameMetaDestroy( tkoFrame * frame); static void FrameMetaDelete( ClientData clientData) { Tcl_EventuallyFree(clientData, (Tcl_FreeProc *) FrameMetaDestroy); } static void FrameComputeGeometry( tkoFrame * frame); static void FrameDisplay( ClientData clientData); 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 */ /* * frameMeta -- * * The structure is used to identify our own data inoo objects. */ static Tcl_ObjectMetadataType frameMeta = { TCL_OO_METADATA_VERSION_CURRENT, "FrameMeta", FrameMetaDelete, NULL }; /* * 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, 0, NULL, \ NULL, NULL, TKO_SET_3DBORDER, &frameMeta, offsetof(tkoFrame, border)}, \ { "-bg" , "-background", NULL, NULL, 0, NULL, NULL, NULL,0,NULL,0}, \ { "-bd" , "-borderwidth", NULL, NULL, 0, NULL, NULL, NULL,0,NULL,0}, \ { "-cursor" , "cursor", "Cursor", DEF_FRAME_CURSOR, 0, NULL, \ NULL, NULL, TKO_SET_CURSOR, &frameMeta, offsetof(tkoFrame, cursor)}, \ { "-height" , "height", "Height", DEF_FRAME_HEIGHT, 0, NULL, \ NULL, NULL, TKO_SET_PIXEL, &frameMeta, offsetof(tkoFrame, height)}, \ { "-highlightbackground", "highlightbackground", "highlightBackground", DEF_FRAME_HIGHLIGHT_BG, 0, NULL, \ NULL, NULL, TKO_SET_XCOLOR, &frameMeta, offsetof(tkoFrame, highlightBgColorPtr)}, \ { "-highlightcolor", "highlightColor", "HighlightColor", DEF_FRAME_HIGHLIGHT, 0,NULL, \ NULL, NULL, TKO_SET_XCOLOR, &frameMeta, offsetof(tkoFrame, highlightColorPtr)}, \ { "-highlightthickness" , "highlightThickness", "HighlightThickness", DEF_FRAME_HIGHLIGHT_WIDTH, 0,NULL, \ NULL, NULL, TKO_SET_PIXEL, &frameMeta, offsetof(tkoFrame, highlightWidth)}, \ { "-padx" , "padX", "Pad", DEF_FRAME_PADX, 0,NULL, \ NULL, NULL, TKO_SET_PIXEL, &frameMeta, offsetof(tkoFrame, padX)}, \ { "-pady" , "padY", "Pad", DEF_FRAME_PADY, 0,NULL, \ NULL, NULL, TKO_SET_PIXEL, &frameMeta, offsetof(tkoFrame, padY)}, \ { "-takefocus" , "takeFocus", "TakeFocus", DEF_FRAME_TAKE_FOCUS, 0,NULL, \ NULL, NULL, TKO_SET_STRING, NULL, 0}, \ { "-width" , "width", "Width", DEF_FRAME_WIDTH, 0,NULL, \ NULL, NULL, TKO_SET_PIXEL, &frameMeta, offsetof(tkoFrame, width)}, \ { NULL,NULL,NULL,NULL,0,NULL, NULL,NULL,0,NULL,0} /* tko::frame options */ static tkoWidgetOptionDefine frameOptions[] = { {"-class", "class", "Class", "TkoFrame", TKO_OPTION_READONLY,NULL, NULL, NULL, TKO_SET_CLASS, NULL, 0}, {"-visual", "visual", "Visual", DEF_FRAME_VISUAL, TKO_OPTION_READONLY,NULL, NULL, NULL, TKO_SET_VISUAL, NULL, 0}, {"-colormap", "colormap", "Colormap", DEF_FRAME_COLORMAP, TKO_OPTION_READONLY,NULL, NULL, NULL, TKO_SET_COLORMAP, NULL, 0}, {"-container", "container", "Container", DEF_FRAME_CONTAINER, TKO_OPTION_READONLY,NULL, NULL, NULL, TKO_SET_CONTAINER, &frameMeta, offsetof(tkoFrame, isContainer)}, {"-borderwidth", "borderWidth", "BorderWidth", DEF_FRAME_BORDER_WIDTH, 0,NULL, NULL, NULL, TKO_SET_PIXEL, &frameMeta, offsetof(tkoFrame, borderWidth)}, {"-relief", "relief", "Relief", DEF_FRAME_RELIEF, 0,NULL, NULL, NULL, TKO_SET_RELIEF, &frameMeta, offsetof(tkoFrame, relief)}, FRAME_COMMONDEFINE }; /* tko::toplevel options */ static tkoWidgetOptionDefine toplevelOptions[] = { {"-screen", "screen", "Screen", "", TKO_OPTION_READONLY,NULL, NULL, NULL, TKO_SET_STRING, NULL, 0}, {"-class", "class", "Class", "TkoToplevel", TKO_OPTION_READONLY,NULL, NULL, NULL, TKO_SET_CLASS, NULL, 0}, {"-container", "container", "Container", DEF_FRAME_CONTAINER, TKO_OPTION_READONLY,NULL, NULL, NULL, TKO_SET_CONTAINER, &frameMeta, offsetof(tkoFrame, isContainer)}, {"-use", "use", "Use", DEF_TOPLEVEL_USE, TKO_OPTION_READONLY,NULL, NULL, NULL, TKO_SET_USENULL, &frameMeta, offsetof(tkoFrame, useThis)}, {"-visual", "visual", "Visual", DEF_FRAME_VISUAL, TKO_OPTION_READONLY,NULL, NULL, NULL, TKO_SET_VISUAL, NULL, 0}, {"-colormap", "colormap", "Colormap", DEF_FRAME_COLORMAP, TKO_OPTION_READONLY,NULL, NULL, NULL, TKO_SET_COLORMAP, NULL, 0}, {"-borderwidth", "borderWidth", "BorderWidth", DEF_FRAME_BORDER_WIDTH, 0,NULL, NULL, NULL, TKO_SET_PIXEL, &frameMeta, offsetof(tkoFrame, borderWidth)}, {"-menu", "menu", "Menu", DEF_TOPLEVEL_MENU, 0,NULL, NULL, NULL, TKO_SET_STRINGNULL, &frameMeta, offsetof(tkoFrame, menuName)}, {"-relief", "relief", "Relief", DEF_FRAME_RELIEF, 0,NULL, NULL, NULL, TKO_SET_RELIEF, &frameMeta, offsetof(tkoFrame, relief)}, FRAME_COMMONDEFINE }; /* tko::labelframe options */ static tkoWidgetOptionDefine labelframeOptions[] = { {"-class", "class", "Class", "TkoLabelframe", TKO_OPTION_READONLY,NULL, NULL, NULL, TKO_SET_CLASS, NULL, 0}, {"-visual", "visual", "Visual", DEF_FRAME_VISUAL, TKO_OPTION_READONLY,NULL, NULL, NULL, TKO_SET_VISUAL, NULL, 0}, {"-colormap", "colormap", "Colormap", DEF_FRAME_COLORMAP, TKO_OPTION_READONLY,NULL, NULL, NULL, TKO_SET_COLORMAP, NULL, 0}, {"-borderwidth", "borderWidth", "BorderWidth", DEF_LABELFRAME_BORDER_WIDTH, 0,NULL, NULL, NULL, TKO_SET_PIXEL, &frameMeta, offsetof(tkoFrame, borderWidth)}, {"-fg", "-foreground", NULL, NULL, 0, NULL, NULL, NULL, 0, NULL, 0}, {"-font", "font", "Font", DEF_LABELFRAME_FONT, 0,NULL, NULL, NULL, TKO_SET_FONT, &frameMeta, offsetof(tkoLabelframe, tkfont)}, {"-foreground", "foreground", "Foreground", DEF_LABELFRAME_FG, 0, NULL, NULL, NULL, TKO_SET_XCOLOR, &frameMeta, offsetof(tkoLabelframe, textColorPtr)}, {"-labelanchor", "labelAnchor", "LabelAnchor", DEF_LABELFRAME_LABELANCHOR, 0, NULL, NULL, FrameMethod_labelanchor, 0, NULL, 0}, {"-labelwidget", "labelWidget", "LabelWidget", "",0, NULL, NULL, FrameMethod_labelwidget, 0, NULL, 0}, {"-relief", "relief", "Relief", DEF_LABELFRAME_RELIEF, 0, NULL, NULL, NULL, TKO_SET_RELIEF, &frameMeta, offsetof(tkoFrame, relief)}, {"-text", "text", "Text", DEF_LABELFRAME_TEXT, 0, NULL, NULL, NULL, TKO_SET_TCLOBJ, &frameMeta, offsetof(tkoLabelframe, textPtr)}, FRAME_COMMONDEFINE }; /* * Definition of object methods created in Tko_FrameInit() function. */ /* 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} }; /* 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} }; /* 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: * TODO * * Side effects: * TODO */ int Tko_FrameInit( Tcl_Interp * interp) { /* Tcl interpreter. */ Tcl_Class clazz; Tcl_Object object; /* Create class like tk command and remove oo functions from widget commands */ static const char *initScript = "::oo::class create ::tko::frame {superclass ::tko::widget; variable tko; {*}$::tko::unknown}\n" "::oo::class create ::tko::labelframe {superclass ::tko::widget; variable tko; {*}$::tko::unknown}\n" "::oo::class create ::tko::toplevel {superclass ::tko::widget; variable tko; {*}$::tko::unknown}\n"; /* Create widget class. */ if(Tcl_GlobalEval(interp, initScript) != TCL_OK) { return TCL_ERROR; } /* * ::tko::toplevel */ /* Get class object */ if((object = Tcl_GetObjectFromObj(interp, TkoObj.tko_toplevel)) == NULL || (clazz = Tcl_GetObjectAsClass(object)) == NULL) { return TCL_ERROR; } /* Add methods and options */ if(TkoWidgetClassDefine(interp, clazz, Tcl_GetObjectName(interp, object), toplevelMethods, toplevelOptions) != TCL_OK) { return TCL_ERROR; } /* * ::tko::frame */ /* Get class object */ if((object = Tcl_GetObjectFromObj(interp, TkoObj.tko_frame)) == NULL || (clazz = Tcl_GetObjectAsClass(object)) == NULL) { return TCL_ERROR; } /* Add methods and options */ if(TkoWidgetClassDefine(interp, clazz, Tcl_GetObjectName(interp, object), frameMethods, frameOptions) != TCL_OK) { return TCL_ERROR; } /* * ::tko::labelframe */ /* Get class object */ if((object = Tcl_GetObjectFromObj(interp, TkoObj.tko_labelframe)) == NULL || (clazz = Tcl_GetObjectAsClass(object)) == NULL) { return TCL_ERROR; } /* Add methods and options */ if(TkoWidgetClassDefine(interp, clazz, Tcl_GetObjectName(interp, object), labelframeMethods, labelframeOptions) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } /* * FrameConstructorFrame -- * * Results: * TODO * * Side effects: * TODO */ static int FrameConstructorFrame( ClientData clientData, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]) { return FrameConstructor(TYPE_FRAME, interp, context, objc, objv); } /* * FrameConstructorLabelframe -- * * Results: * TODO * * Side effects: * TODO */ static int FrameConstructorLabelframe( ClientData clientData, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]) { return FrameConstructor(TYPE_LABELFRAME, interp, context, objc, objv); } /* * FrameConstructorToplevel -- * * Results: * TODO * * Side effects: * TODO */ static int FrameConstructorToplevel( ClientData clientData, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]) { return FrameConstructor(TYPE_TOPLEVEL, interp, context, objc, objv); } /* * FrameDestructor -- * * Results: * TODO * * Side effects: * TODO */ static int FrameDestructor( ClientData clientData, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]) { int skip; Tcl_Object object; tkoFrame *frame; Tk_Window tkWin = NULL; tkoLabelframe *labelframe; if((object = Tcl_ObjectContextObject(context)) == NULL) { return TCL_ERROR; } skip = Tcl_ObjectContextSkippedArgs(context); if((frame = (tkoFrame *) Tcl_ObjectGetMetadata(object, &frameMeta)) != NULL) { Tcl_Preserve(frame); labelframe = (tkoLabelframe *) frame; if(frame->win) { tkWin = *(frame->win); frame->win = NULL; } if(tkWin) { Tk_DeleteEventHandler(tkWin, frame->mask, FrameEventProc, frame); } if(frame->cursor != None) { if(frame->display != None) { Tk_FreeCursor(frame->display, frame->cursor); } frame->cursor = None; } frame->flags = 0; Tcl_CancelIdleCall(FrameDisplay, frame); Tcl_CancelIdleCall(FrameMap, frame); if(frame->menuName != NULL && tkWin) { TkSetWindowMenuBar(frame->interp, tkWin, frame->menuName, NULL); frame->menuName = NULL; } if(frame->type == TYPE_LABELFRAME && labelframe->labelWin) { Tk_ManageGeometry(labelframe->labelWin, NULL, NULL); if(tkWin && (tkWin != Tk_Parent(labelframe->labelWin))) { Tk_UnmaintainGeometry(labelframe->labelWin, tkWin); } Tk_UnmapWindow(labelframe->labelWin); labelframe->labelWin = NULL; } Tcl_Release(frame); Tcl_ObjectSetMetadata(object, &frameMeta, NULL); } /* ignore errors */ Tcl_ObjectContextInvokeNext(interp, context, objc, objv, skip); return TCL_OK; } /* * FrameMethod_tko_configure -- * * Results: * TODO * * Side effects: * TODO */ static int FrameMethod_tko_configure( ClientData clientData, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]) { char *oldMenuName; Tcl_Object object; tkoFrame *frame; tkoLabelframe *labelframe; Tk_Window oldWindow; Tk_Window tkwin; if((object = Tcl_ObjectContextObject(context)) == NULL || (frame = (tkoFrame *) Tcl_ObjectGetMetadata(object, &frameMeta)) == NULL || frame->win == NULL || (tkwin = *(frame->win)) == NULL) { return TCL_ERROR; } labelframe = (tkoLabelframe *) frame; /* * Need the old menubar name for the menu code to delete it. */ if(frame->menuName == NULL) { oldMenuName = NULL; } else { oldMenuName = ckalloc(strlen(frame->menuName) + 1); strcpy(oldMenuName, frame->menuName); } if(frame->type == TYPE_LABELFRAME) { oldWindow = labelframe->labelWin; } /*TODO ??? if (oldMenuName != NULL) { * ckfree(oldMenuName); * } */ /* * A few of the options require additional processing. */ if((((oldMenuName == NULL) && (frame->menuName != NULL)) || ((oldMenuName != NULL) && (frame->menuName == NULL)) || ((oldMenuName != NULL) && (frame->menuName != NULL) && strcmp(oldMenuName, frame->menuName) != 0)) && frame->type == TYPE_TOPLEVEL) { TkSetWindowMenuBar(frame->interp, tkwin, oldMenuName, frame->menuName); } if(oldMenuName != NULL) { ckfree(oldMenuName); } if(frame->border != NULL) { Tk_SetBackgroundFromBorder(tkwin, frame->border); } else { Tk_SetWindowBackgroundPixmap(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); if(Tcl_ObjectContextInvokeNext(interp, context, objc, objv, Tcl_ObjectContextSkippedArgs(context)) != TCL_OK) { return TCL_ERROR; } return TCL_OK; } /* * FrameMethod_labelanchor -- * * Process -labelanchor option. * * Results: * TODO * * Side effects: * TODO */ static int FrameMethod_labelanchor( ClientData clientData, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]) { int index, code; Tcl_Object object; tkoLabelframe *labelframe; Tcl_Obj *value; static const char *const labelAnchorStrings[] = { "e", "en", "es", "n", "ne", "nw", "s", "se", "sw", "w", "wn", "ws", NULL }; if((object = Tcl_ObjectContextObject(context)) == NULL || (labelframe = (tkoLabelframe *) Tcl_ObjectGetMetadata(object, &frameMeta)) == NULL || (value = TkoWidgetOptionGet(interp, object, objv[objc - 1])) == NULL) { return TCL_ERROR; } 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: * TODO * * Side effects: * TODO */ static int FrameMethod_labelwidget( ClientData clientData, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]) { Tk_Window oldWindow = NULL; Tk_Window newWindow = NULL; Tk_Window tkwin = NULL; Tk_Window ancestor, parent, sibling = NULL; Tcl_Object object; tkoLabelframe *labelframe; Tcl_Obj *value; if((object = Tcl_ObjectContextObject(context)) == NULL || (labelframe = (tkoLabelframe *) Tcl_ObjectGetMetadata(object, &frameMeta)) == NULL || (value = TkoWidgetOptionGet(interp, object, objv[objc - 1])) == NULL) { return TCL_ERROR; } if(labelframe->frame.win == NULL || (tkwin = *(labelframe->frame.win)) == NULL) { return TCL_ERROR; } if(value == NULL || Tcl_GetCharLength(value) == 0) { newWindow = NULL; } else if(TkGetWindowFromObj(interp, 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 = 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 == tkwin) { goto badLabelWindow; } } if(oldWindow != NULL) { Tk_DeleteEventHandler(oldWindow, StructureNotifyMask, FrameStructureProc, labelframe); Tk_ManageGeometry(oldWindow, NULL, NULL); Tk_UnmaintainGeometry(oldWindow, 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; } // FrameWorldChanged(labelframe); 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; } /* * FrameConstructor -- * * Common part of all widget contructors. * * Results: * TODO * * Side effects: * TODO */ static int FrameConstructor( int type, Tcl_Interp * interp, Tcl_ObjectContext context, int objc, Tcl_Obj * const objv[]) { Tcl_Object object; tkoFrame *frame; int skip; Tcl_Obj *myObjv[2]; /* Get current object. Should not fail? */ if((object = Tcl_ObjectContextObject(context)) == NULL) { return TCL_ERROR; } skip = Tcl_ObjectContextSkippedArgs(context); /* Check objv[] arguments: ... optionlist arglist */ if(objc - skip != 2) { Tcl_WrongNumArgs(interp, 1, objv, "optionlist arglist"); return TCL_ERROR; } if(type == TYPE_FRAME) { frame = ckalloc(sizeof(tkoFrame)); memset(frame, 0, sizeof(tkoFrame)); myObjv[0] = Tcl_ObjGetVar2(interp, TkoObj.tko_options, TkoObj.tko_frame, TCL_GLOBAL_ONLY); myObjv[1] = objv[objc - 1]; } else if(type == TYPE_LABELFRAME) { tkoLabelframe *labelframe; frame = ckalloc(sizeof(tkoLabelframe)); memset(frame, 0, sizeof(tkoLabelframe)); myObjv[0] = Tcl_ObjGetVar2(interp, TkoObj.tko_options, TkoObj.tko_labelframe, TCL_GLOBAL_ONLY); myObjv[1] = objv[objc - 1]; labelframe = (tkoLabelframe *) frame; labelframe->textPtr = NULL; labelframe->tkfont = NULL; labelframe->textColorPtr = NULL; labelframe->labelAnchor = LABELANCHOR_NW; labelframe->labelWin = NULL; labelframe->textGC = None; labelframe->textLayout = NULL; /*labelframe->labelBox */ labelframe->labelReqWidth = 0; labelframe->labelReqHeight = 0; labelframe->labelTextX = 0; labelframe->labelTextY = 0; } else if(type == TYPE_TOPLEVEL) { myObjv[1] = Tcl_NewStringObj("-screen {}", -1); Tcl_IncrRefCount(myObjv[1]); if(Tcl_ListObjAppendList(interp, myObjv[1], objv[objc - 1]) != TCL_OK) { Tcl_DecrRefCount(myObjv[1]); return TCL_ERROR; } frame = ckalloc(sizeof(tkoFrame)); memset(frame, 0, sizeof(tkoFrame)); myObjv[0] = Tcl_ObjGetVar2(interp, TkoObj.tko_options, TkoObj.tko_toplevel, TCL_GLOBAL_ONLY); } else { Tcl_WrongNumArgs(interp, 1, objv, "internal type error"); return TCL_ERROR; } if(myObjv[0] == NULL) { return TCL_ERROR; } frame->win = NULL; frame->object = object; frame->interp = interp; frame->display = None; 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 = None; frame->isContainer = 0; frame->useThis = NULL; frame->flags = 0; frame->padX = 0; frame->padY = 0; frame->mask = ExposureMask | StructureNotifyMask | FocusChangeMask; if(type == TYPE_TOPLEVEL) { frame->mask |= ActivateMask; } Tcl_ObjectSetMetadata(object, &frameMeta, (ClientData) frame); myObjv[0] = Tcl_DuplicateObj(myObjv[0]); Tcl_IncrRefCount(myObjv[0]); Tcl_ListObjAppendList(interp, myObjv[0], objv[objc - 2]); if(Tcl_ObjectContextInvokeNext(interp, context, 2, myObjv, 0) != TCL_OK) { Tcl_DecrRefCount(myObjv[0]); if(type == TYPE_TOPLEVEL) { Tcl_DecrRefCount(myObjv[1]); } return TCL_ERROR; } Tcl_DecrRefCount(myObjv[0]); if(type == TYPE_TOPLEVEL) { Tcl_DecrRefCount(myObjv[1]); } frame->win = TkoWidgetWindow(object); if(frame->win == NULL || *(frame->win) == NULL) { return TCL_ERROR; } if((frame->display = Tk_Display(*(frame->win))) == None) { return TCL_ERROR; } 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(*(frame->win), 200, 200); } /* * Store backreference to frame widget in window structure. */ Tk_SetClassProcs(*(frame->win), &frameClass, frame); /* * Mark Tk frames as suitable candidates for [wm manage]. */ ((TkWindow *) * (frame->win))->flags |= TK_WM_MANAGEABLE; Tk_CreateEventHandler(*(frame->win), frame->mask, FrameEventProc, frame); if(type == TYPE_TOPLEVEL) { Tcl_DoWhenIdle(FrameMap, frame); } return TCL_OK; } /* * FrameMetaDestroy -- * * This function is invoked by Tcl_EventuallyFree or Tcl_Release to clean * up the internal structure of a frame at a safe time (when no-one is * using it anymore). * * Results: * None. * * Side effects: * Everything associated with the frame is freed up. */ static void FrameMetaDestroy( tkoFrame * frame) { /* Info about frame widget. */ tkoLabelframe *labelframe = (tkoLabelframe *) frame; if(frame->menuName != NULL) { ckfree(frame->menuName); } if(frame->useThis) { Tcl_DecrRefCount(frame->useThis); } if(frame->type == TYPE_LABELFRAME) { if(labelframe->textLayout) { Tk_FreeTextLayout(labelframe->textLayout); } if(labelframe->textGC != None && frame->display != None) { Tk_FreeGC(frame->display, labelframe->textGC); } } if(frame->border) { Tk_Free3DBorder(frame->border); } if(frame->colormap != None && frame->display != None) { Tk_FreeColormap(frame->display, frame->colormap); } if(frame->highlightBgColorPtr != NULL) { Tk_FreeColor(frame->highlightBgColorPtr); } if(frame->highlightColorPtr != NULL) { Tk_FreeColor(frame->highlightColorPtr); } ckfree(frame); } /* * 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 instanceData) { /* Information about widget. */ tkoFrame *frame = instanceData; tkoLabelframe *labelframe = instanceData; XGCValues gcValues; GC gc; int anyTextLabel, anyWindowLabel; int bWidthLeft, bWidthRight, bWidthTop, bWidthBottom; const char *labelText; if(frame->win == NULL || *(frame->win) == NULL) return; anyTextLabel = (frame->type == TYPE_LABELFRAME) && (labelframe->textPtr != NULL) && (labelframe->labelWin == NULL); anyWindowLabel = (frame->type == TYPE_LABELFRAME) && (labelframe->labelWin != NULL); 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(*(frame->win), GCForeground | GCFont | GCGraphicsExposures, &gcValues); if(labelframe->textGC != None) { Tk_FreeGC(frame->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(*(frame->win), 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(*(frame->win), minwidth, minheight); } if((frame->width > 0) || (frame->height > 0)) { Tk_GeometryRequest(*(frame->win), frame->width, frame->height); } if(Tk_IsMapped(*(frame->win))) { 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( register tkoFrame * frame) { /* Information about widget. */ int otherWidth, otherHeight, otherWidthT, otherHeightT, padding; int maxWidth, maxHeight; tkoLabelframe *labelframe = (tkoLabelframe *) frame; if(frame->win == NULL || *(frame->win) == NULL) return; /* * We have nothing to do here unless there is a label. */ if(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(*(frame->win)); maxWidth = Tk_Width(*(frame->win)); 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(*(frame->win)) - labelframe->labelBox.width; otherHeight = Tk_Height(*(frame->win)) - labelframe->labelBox.height; otherWidthT = Tk_Width(*(frame->win)) - labelframe->labelReqWidth; otherHeightT = Tk_Height(*(frame->win)) - 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. */) { tkoFrame *frame = clientData; int bdX1, bdY1, bdX2, bdY2, hlWidth; Pixmap pixmap; TkRegion clipRegion = NULL; if(frame->win == NULL || *(frame->win) == NULL) return; frame->flags &= ~REDRAW_PENDING; if(!Tk_IsMapped(*(frame->win))) { 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(*(frame->win))); if(frame->flags & GOT_FOCUS) { fgGC = Tk_GCForColor(frame->highlightColorPtr, Tk_WindowId(*(frame->win))); TkpDrawHighlightBorder(*(frame->win), fgGC, bgGC, hlWidth, Tk_WindowId(*(frame->win))); } else { TkpDrawHighlightBorder(*(frame->win), bgGC, bgGC, hlWidth, Tk_WindowId(*(frame->win))); } } /* * If -background is set to "", no interior is drawn. */ if(frame->border == NULL) { return; } 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: TkpDrawFrame(*(frame->win), frame->border, hlWidth, frame->borderWidth, frame->relief); } else { tkoLabelframe *labelframe = (tkoLabelframe *) frame; if((labelframe->textPtr == NULL) && (labelframe->labelWin == NULL)) { goto noLabel; } #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(frame->display, Tk_WindowId(*(frame->win)), Tk_Width(*(frame->win)), Tk_Height(*(frame->win)), Tk_Depth(*(frame->win))); #else pixmap = Tk_WindowId(tkWin); #endif /* TK_NO_DOUBLE_BUFFERING */ /* * Clear the pixmap. */ Tk_Fill3DRectangle(*(frame->win), pixmap, frame->border, 0, 0, Tk_Width(*(frame->win)), Tk_Height(*(frame->win)), 0, TK_RELIEF_FLAT); /* * Calculate how the label affects the border's position. */ bdX1 = bdY1 = hlWidth; bdX2 = Tk_Width(*(frame->win)) - hlWidth; bdY2 = Tk_Height(*(frame->win)) - 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(*(frame->win), pixmap, frame->border, bdX1, bdY1, bdX2 - bdX1, bdY2 - bdY1, frame->borderWidth, frame->relief); if(labelframe->labelWin == NULL) { /* * Clear behind the label */ Tk_Fill3DRectangle(*(frame->win), 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(frame->display, labelframe->textGC, clipRegion); } Tk_DrawTextLayout(frame->display, pixmap, labelframe->textGC, labelframe->textLayout, labelframe->labelTextX + LABELSPACING, labelframe->labelTextY + LABELSPACING, 0, -1); if(clipRegion != NULL) { XSetClipMask(frame->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(*(frame->win) == 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, *(frame->win), 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(frame->display, pixmap, Tk_WindowId(*(frame->win)), labelframe->textGC, hlWidth, hlWidth, (unsigned)(Tk_Width(*(frame->win)) - 2 * hlWidth), (unsigned)(Tk_Height(*(frame->win)) - 2 * hlWidth), hlWidth, hlWidth); Tk_FreePixmap(frame->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. */ tkoFrame *frame = clientData; if(eventPtr->type == DestroyNotify || frame->win == NULL || *(frame->win) == 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) { TkpSetMainMenubar(frame->interp, *(frame->win), 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. */ tkoFrame *frame = clientData; if(frame->win == NULL || *(frame->win) == 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(frame->win == NULL || *(frame->win) == NULL) { Tcl_Release(frame); return; } } Tk_MapWindow(*(frame->win)); 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 = 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 *arrayName = TkoWidgetOptionVar(frame->object); labelframe->labelWin = NULL; if(arrayName == NULL) return; Tcl_ObjSetVar2(frame->interp, arrayName, TkoObj._labelwidget, TkoObj.empty, TCL_GLOBAL_ONLY); 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 = clientData; 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 = 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); } } /* vim: set ts=4 sw=4 sts=4 ff=unix et : */
