/*
* 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 : */