summaryrefslogtreecommitdiffstats
path: root/generic/ttk/ttkWidget.c
diff options
context:
space:
mode:
authorhobbs <hobbs>2010-08-26 02:06:08 (GMT)
committerhobbs <hobbs>2010-08-26 02:06:08 (GMT)
commitb29adcfbfc2e03e058536524f1aa3378b948e7ed (patch)
treefa90e1e6d32590addfbb0a1599a40b1f7f99ea3b /generic/ttk/ttkWidget.c
parent7dec1714e5d5efd6b7d095657c1434fa68af0f87 (diff)
downloadtk-b29adcfbfc2e03e058536524f1aa3378b948e7ed.zip
tk-b29adcfbfc2e03e058536524f1aa3378b948e7ed.tar.gz
tk-b29adcfbfc2e03e058536524f1aa3378b948e7ed.tar.bz2
Major backport of 8.6 Ttk for 8.5.9. Most changes were only being
committed to head (8.6), although they could apply for 8.5 as well. This re-sync makes future work easier to maintain and adds some useful work for 8.5 users. Notable changes: - Lots of code cleanup - Some bug fixes never backported - Addition of ttk::spinbox - minor color changes - Improved Vista/7 styling - Move to tile version 0.8.6 (pseudo-package) - ABI and API compatible (even $w identify) - minor new features (extended $w identify)
Diffstat (limited to 'generic/ttk/ttkWidget.c')
-rw-r--r--generic/ttk/ttkWidget.c295
1 files changed, 149 insertions, 146 deletions
diff --git a/generic/ttk/ttkWidget.c b/generic/ttk/ttkWidget.c
index 6bc085b..9efcc57 100644
--- a/generic/ttk/ttkWidget.c
+++ b/generic/ttk/ttkWidget.c
@@ -1,4 +1,4 @@
-/* $Id: ttkWidget.c,v 1.11.2.2 2009/05/14 00:53:04 patthoyts Exp $
+/* $Id: ttkWidget.c,v 1.11.2.3 2010/08/26 02:06:10 hobbs Exp $
* Copyright (c) 2003, Joe English
*
* Core widget utilities.
@@ -61,7 +61,7 @@ static void SizeChanged(WidgetCore *corePtr)
static Drawable BeginDrawing(Tk_Window tkwin)
{
return Tk_GetPixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
- Tk_Width(tkwin), Tk_Height(tkwin),Tk_Depth(tkwin));
+ Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
}
/* EndDrawing --
@@ -115,7 +115,7 @@ void TtkRedisplayWidget(WidgetCore *corePtr)
}
if (!(corePtr->flags & REDISPLAY_PENDING)) {
- Tcl_DoWhenIdle(DrawWidget, (ClientData) corePtr);
+ Tcl_DoWhenIdle(DrawWidget, corePtr);
corePtr->flags |= REDISPLAY_PENDING;
}
}
@@ -146,78 +146,94 @@ void TtkWidgetChangeState(WidgetCore *corePtr,
}
}
-/* TtkWidgetEnsembleCommand --
- * Invoke an ensemble defined by a WidgetCommandSpec.
- */
-int TtkWidgetEnsembleCommand(
- const WidgetCommandSpec *commands, /* Ensemble definition */
- int cmdIndex, /* Index of command word */
- Tcl_Interp *interp, /* Interpreter to use */
- int objc, Tcl_Obj *const objv[], /* Argument vector */
- void *clientData) /* User data (widget record pointer) */
-{
- int index;
-
- if (objc <= cmdIndex) {
- Tcl_WrongNumArgs(interp, cmdIndex, objv, "option ?arg arg...?");
- return TCL_ERROR;
- }
- if (Tcl_GetIndexFromObjStruct(interp, objv[cmdIndex], commands,
- sizeof(commands[0]), "command", 0, &index) != TCL_OK)
- {
- return TCL_ERROR;
- }
- return commands[index].command(interp, objc, objv, clientData);
-}
-
-/*
- * WidgetInstanceObjCmd --
+/* WidgetInstanceObjCmd --
* Widget instance command implementation.
*/
static int
WidgetInstanceObjCmd(
- ClientData clientData, /* Widget record pointer */
- Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj * const objv[]) /* Argument objects. */
+ ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
- WidgetCore *corePtr = (WidgetCore *)clientData;
- const WidgetCommandSpec *commands = corePtr->widgetSpec->commands;
- int status = TCL_OK;
+ WidgetCore *corePtr = clientData;
+ const Ttk_Ensemble *commands = corePtr->widgetSpec->commands;
+ int status;
Tcl_Preserve(clientData);
- status = TtkWidgetEnsembleCommand(commands,1, interp,objc,objv,clientData);
+ status = Ttk_InvokeEnsemble(commands,1, clientData,interp,objc,objv);
Tcl_Release(clientData);
return status;
}
-/*
- * Command deletion callback for widget instance commands.
+/*------------------------------------------------------------------------
+ * +++ Widget destruction.
+ *
+ * A widget can be destroyed when the application explicitly
+ * destroys the window or one of its ancestors via [destroy]
+ * or Tk_DestroyWindow(); when the application deletes the widget
+ * instance command; when there is an error in the widget constructor;
+ * or when another application calls XDestroyWindow on the window ID.
+ *
+ * The window receives a <DestroyNotify> event in all cases,
+ * so we do the bulk of the cleanup there. See [#2207435] for
+ * further notes (esp. re: Tk_FreeConfigOptions).
+ *
+ * Widget code that reenters the interp should only do so
+ * when the widtget is Tcl_Preserve()d, and should check
+ * the WIDGET_DESTROYED flag bit upon return.
+ */
+
+/* WidgetInstanceObjCmdDeleted --
+ * Widget instance command deletion callback.
*/
static void
WidgetInstanceObjCmdDeleted(ClientData clientData)
{
- WidgetCore *corePtr = (WidgetCore *) clientData;
+ WidgetCore *corePtr = clientData;
corePtr->widgetCmd = NULL;
if (corePtr->tkwin != NULL)
Tk_DestroyWindow(corePtr->tkwin);
}
-/*
- * WidgetCleanup --
- * Final cleanup for widget.
- *
- * @@@ TODO: check all code paths leading to widget destruction,
- * @@@ describe here.
- * @@@ Call widget-specific cleanup routine at an appropriate point.
+/* FreeWidget --
+ * Final cleanup for widget; called via Tcl_EventuallyFree().
*/
static void
-WidgetCleanup(char *memPtr)
+FreeWidget(char *memPtr)
{
ckfree(memPtr);
}
+/* DestroyWidget --
+ * Main widget destructor; called from <DestroyNotify> event handler.
+ */
+static void
+DestroyWidget(WidgetCore *corePtr)
+{
+ corePtr->flags |= WIDGET_DESTROYED;
+
+ corePtr->widgetSpec->cleanupProc(corePtr);
+
+ Tk_FreeConfigOptions(
+ (ClientData)corePtr, corePtr->optionTable, corePtr->tkwin);
+
+ if (corePtr->layout) {
+ Ttk_FreeLayout(corePtr->layout);
+ }
+
+ if (corePtr->flags & REDISPLAY_PENDING) {
+ Tcl_CancelIdleCall(DrawWidget, corePtr);
+ }
+
+ corePtr->tkwin = NULL;
+ if (corePtr->widgetCmd) {
+ Tcl_Command cmd = corePtr->widgetCmd;
+ corePtr->widgetCmd = 0;
+ /* NB: this can reenter the interpreter via a command traces */
+ Tcl_DeleteCommandFromToken(corePtr->interp, cmd);
+ }
+ Tcl_EventuallyFree(corePtr, FreeWidget);
+}
+
/*
* CoreEventProc --
* Event handler for basic events.
@@ -247,7 +263,7 @@ static const unsigned CoreEventMask
static void CoreEventProc(ClientData clientData, XEvent *eventPtr)
{
- WidgetCore *corePtr = (WidgetCore *) clientData;
+ WidgetCore *corePtr = clientData;
switch (eventPtr->type)
{
@@ -260,35 +276,10 @@ static void CoreEventProc(ClientData clientData, XEvent *eventPtr)
}
break;
case DestroyNotify :
- corePtr->flags |= WIDGET_DESTROYED;
-
- Tk_DeleteEventHandler(corePtr->tkwin,
- CoreEventMask,CoreEventProc,clientData);
-
- if (corePtr->flags & REDISPLAY_PENDING) {
- Tcl_CancelIdleCall(DrawWidget, clientData);
- }
-
- corePtr->widgetSpec->cleanupProc(corePtr);
-
- Tk_UndefineCursor(corePtr->tkwin); /* workaround for #2207435 */
- Tk_FreeConfigOptions(
- clientData, corePtr->optionTable, corePtr->tkwin);
- corePtr->tkwin = NULL;
-
- if (corePtr->layout) {
- Ttk_FreeLayout(corePtr->layout);
- }
-
- /* NB: this can reenter the interpreter via a command traces */
- if (corePtr->widgetCmd) {
- Tcl_Command cmd = corePtr->widgetCmd;
- corePtr->widgetCmd = 0;
- Tcl_DeleteCommandFromToken(corePtr->interp, cmd);
- }
- Tcl_EventuallyFree(clientData, WidgetCleanup);
+ Tk_DeleteEventHandler(
+ corePtr->tkwin, CoreEventMask,CoreEventProc,clientData);
+ DestroyWidget(corePtr);
break;
-
case FocusIn:
case FocusOut:
/* Don't process "virtual crossing" events */
@@ -339,14 +330,16 @@ static void CoreEventProc(ClientData clientData, XEvent *eventPtr)
*/
static void WidgetWorldChanged(ClientData clientData)
{
- WidgetCore *corePtr = (WidgetCore*)clientData;
+ WidgetCore *corePtr = clientData;
SizeChanged(corePtr);
TtkRedisplayWidget(corePtr);
}
-static struct Tk_ClassProcs widgetClassProcs = {
- sizeof(Tk_ClassProcs),
- WidgetWorldChanged
+static Tk_ClassProcs widgetClassProcs = {
+ sizeof(Tk_ClassProcs), /* size */
+ WidgetWorldChanged, /* worldChangedProc */
+ NULL, /* createProc */
+ NULL /* modalProc */
};
/*
@@ -355,55 +348,45 @@ static struct Tk_ClassProcs widgetClassProcs = {
* ClientData is a WidgetSpec *.
*/
int TtkWidgetConstructorObjCmd(
- ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
+ ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
- WidgetSpec *widgetSpec = (WidgetSpec *)clientData;
+ WidgetSpec *widgetSpec = clientData;
const char *className = widgetSpec->className;
- WidgetCore *corePtr;
- ClientData recordPtr;
+ Tk_OptionTable optionTable =
+ Tk_CreateOptionTable(interp, widgetSpec->optionSpecs);
Tk_Window tkwin;
- Tk_OptionTable optionTable;
+ void *recordPtr;
+ WidgetCore *corePtr;
+ Tk_SavedOptions savedOptions;
int i;
- if (objc < 2 || objc % 1 == 1) {
- Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?");
+ if (objc < 2 || objc % 2 == 1) {
+ Tcl_WrongNumArgs(interp, 1, objv, "pathName ?-option value ...?");
return TCL_ERROR;
}
- tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp),
- Tcl_GetStringFromObj(objv[1], NULL), (char *) NULL);
- if (tkwin == NULL)
- return TCL_ERROR;
-
- /*
- * Check if a -class resource has been specified:
+ /* Check if a -class option has been specified.
* We have to do this before the InitOptions() call,
* since InitOptions() is affected by the widget class.
*/
for (i = 2; i < objc; i += 2) {
- const char *resourceName = Tcl_GetString(objv[i]);
- if (!strcmp(resourceName, "-class")) {
+ if (!strcmp(Tcl_GetString(objv[i]), "-class")) {
className = Tcl_GetString(objv[i+1]);
break;
}
}
- Tk_SetClass(tkwin, className);
-
- /*
- * Set the BackgroundPixmap to ParentRelative here, so
- * subclasses don't need to worry about setting the background.
- */
- Tk_SetWindowBackgroundPixmap(tkwin, ParentRelative);
-
- optionTable = Tk_CreateOptionTable(interp, widgetSpec->optionSpecs);
+ tkwin = Tk_CreateWindowFromPath(
+ interp, Tk_MainWindow(interp), Tcl_GetString(objv[1]), NULL);
+ if (tkwin == NULL)
+ return TCL_ERROR;
/*
* Allocate and initialize the widget record.
*/
recordPtr = ckalloc(widgetSpec->recordSize);
memset(recordPtr, 0, widgetSpec->recordSize);
- corePtr = (WidgetCore *)recordPtr;
+ corePtr = recordPtr;
corePtr->tkwin = tkwin;
corePtr->interp = interp;
@@ -411,52 +394,57 @@ int TtkWidgetConstructorObjCmd(
corePtr->widgetCmd = Tcl_CreateObjCommand(interp, Tk_PathName(tkwin),
WidgetInstanceObjCmd, recordPtr, WidgetInstanceObjCmdDeleted);
corePtr->optionTable = optionTable;
+ corePtr->layout = NULL;
+ corePtr->flags = 0;
+ corePtr->state = 0;
+ Tk_SetClass(tkwin, className);
Tk_SetClassProcs(tkwin, &widgetClassProcs, recordPtr);
+ Tk_SetWindowBackgroundPixmap(tkwin, ParentRelative);
- if (Tk_InitOptions(interp, recordPtr, optionTable, tkwin) != TCL_OK)
- goto error_nocleanup;
+ widgetSpec->initializeProc(interp, recordPtr);
- if (widgetSpec->initializeProc(interp, recordPtr) != TCL_OK)
- goto error_nocleanup;
+ Tk_CreateEventHandler(tkwin, CoreEventMask, CoreEventProc, recordPtr);
- if (Tk_SetOptions(interp, recordPtr, optionTable, objc - 2,
- objv + 2, tkwin, NULL/*savePtr*/, (int *)NULL/*maskPtr*/) != TCL_OK)
+ /*
+ * Initial configuration.
+ */
+
+ Tcl_Preserve(corePtr);
+ if (Tk_InitOptions(interp, recordPtr, optionTable, tkwin) != TCL_OK) {
goto error;
+ }
+ if (Tk_SetOptions(interp, recordPtr, optionTable,
+ objc - 2, objv + 2, tkwin, &savedOptions, NULL) != TCL_OK) {
+ Tk_RestoreSavedOptions(&savedOptions);
+ goto error;
+ } else {
+ Tk_FreeSavedOptions(&savedOptions);
+ }
if (widgetSpec->configureProc(interp, recordPtr, ~0) != TCL_OK)
goto error;
-
if (widgetSpec->postConfigureProc(interp, recordPtr, ~0) != TCL_OK)
goto error;
if (WidgetDestroyed(corePtr))
goto error;
- if (UpdateLayout(interp, corePtr) != TCL_OK)
- goto error;
+ Tcl_Release(corePtr);
SizeChanged(corePtr);
- Tk_CreateEventHandler(tkwin, CoreEventMask, CoreEventProc, recordPtr);
-
Tk_MakeWindowExist(tkwin);
Tcl_SetObjResult(interp, Tcl_NewStringObj(Tk_PathName(tkwin), -1));
-
return TCL_OK;
error:
- widgetSpec->cleanupProc(recordPtr);
-error_nocleanup:
- if (corePtr->layout) {
- Ttk_FreeLayout(corePtr->layout);
- corePtr->layout = 0;
+ if (WidgetDestroyed(corePtr)) {
+ Tcl_SetResult(interp, "Widget has been destroyed", TCL_STATIC);
+ } else {
+ Tk_DestroyWindow(tkwin);
}
- Tk_FreeConfigOptions(recordPtr, optionTable, tkwin);
- Tk_DestroyWindow(tkwin);
- corePtr->tkwin = 0;
- Tcl_DeleteCommandFromToken(interp, corePtr->widgetCmd);
- ckfree(recordPtr);
+ Tcl_Release(corePtr);
return TCL_ERROR;
}
@@ -532,9 +520,8 @@ Ttk_Layout TtkWidgetGetOrientedLayout(
/* TtkNullInitialize --
* Default widget initializeProc (no-op)
*/
-int TtkNullInitialize(Tcl_Interp *interp, void *recordPtr)
+void TtkNullInitialize(Tcl_Interp *interp, void *recordPtr)
{
- return TCL_OK;
}
/* TtkNullPostConfigure --
@@ -604,7 +591,7 @@ int TtkWidgetSize(void *recordPtr, int *widthPtr, int *heightPtr)
/* $w cget -option
*/
int TtkWidgetCgetCommand(
-Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[], void *recordPtr)
+ void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
WidgetCore *corePtr = recordPtr;
Tcl_Obj *result;
@@ -624,14 +611,14 @@ Tcl_Interp *interp, int objc, Tcl_Obj * CONST objv[], void *recordPtr)
/* $w configure ?-option ?value ....??
*/
int TtkWidgetConfigureCommand(
-Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], void *recordPtr)
+ void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
WidgetCore *corePtr = recordPtr;
Tcl_Obj *result;
if (objc == 2) {
result = Tk_GetOptionInfo(interp, recordPtr,
- corePtr->optionTable, (Tcl_Obj *) NULL, corePtr->tkwin);
+ corePtr->optionTable, NULL, corePtr->tkwin);
} else if (objc == 3) {
result = Tk_GetOptionInfo(interp, recordPtr,
corePtr->optionTable, objv[2], corePtr->tkwin);
@@ -661,6 +648,10 @@ Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], void *recordPtr)
Tk_FreeSavedOptions(&savedOptions);
status = corePtr->widgetSpec->postConfigureProc(interp,recordPtr,mask);
+ if (WidgetDestroyed(corePtr)) {
+ Tcl_SetResult(interp, "Widget has been destroyed", TCL_STATIC);
+ status = TCL_ERROR;
+ }
if (status != TCL_OK) {
return status;
}
@@ -689,7 +680,7 @@ Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], void *recordPtr)
*/
int TtkWidgetStateCommand(
- Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], void *recordPtr)
+ void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
WidgetCore *corePtr = recordPtr;
Ttk_StateSpec spec;
@@ -729,7 +720,7 @@ int TtkWidgetStateCommand(
*/
int TtkWidgetInstateCommand(
- Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], void *recordPtr)
+ void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
WidgetCore *corePtr = recordPtr;
Ttk_State state = corePtr->state;
@@ -756,27 +747,39 @@ int TtkWidgetInstateCommand(
}
/* $w identify $x $y
+ * $w identify element $x $y
* Returns: name of element at $x, $y
*/
int TtkWidgetIdentifyCommand(
- Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[], void *recordPtr)
+ void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
{
WidgetCore *corePtr = recordPtr;
- Ttk_LayoutNode *node;
- int x, y;
+ Ttk_Element element;
+ static const char *whatTable[] = { "element", NULL };
+ int x, y, what;
- if (objc != 4) {
- Tcl_WrongNumArgs(interp, 2, objv, "x y");
+ if (objc < 4 || objc > 5) {
+ Tcl_WrongNumArgs(interp, 2, objv, "?what? x y");
return TCL_ERROR;
}
+ if (objc == 5) {
+ /* $w identify element $x $y */
+ if (Tcl_GetIndexFromObj(interp,objv[2],whatTable,"option",0,&what)
+ != TCL_OK)
+ {
+ return TCL_ERROR;
+ }
+ }
- if (Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK
- || Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK)
+ if ( Tcl_GetIntFromObj(interp, objv[objc-2], &x) != TCL_OK
+ || Tcl_GetIntFromObj(interp, objv[objc-1], &y) != TCL_OK
+ ) {
return TCL_ERROR;
+ }
- node = Ttk_LayoutIdentify(corePtr->layout, x, y);
- if (node) {
- const char *elementName = Ttk_LayoutNodeName(node);
+ element = Ttk_IdentifyElement(corePtr->layout, x, y);
+ if (element) {
+ const char *elementName = Ttk_ElementName(element);
Tcl_SetObjResult(interp,Tcl_NewStringObj(elementName,-1));
}