summaryrefslogtreecommitdiffstats
path: root/tktable/generic/tkTableWin.c
diff options
context:
space:
mode:
Diffstat (limited to 'tktable/generic/tkTableWin.c')
-rw-r--r--tktable/generic/tkTableWin.c955
1 files changed, 955 insertions, 0 deletions
diff --git a/tktable/generic/tkTableWin.c b/tktable/generic/tkTableWin.c
new file mode 100644
index 0000000..2a59088
--- /dev/null
+++ b/tktable/generic/tkTableWin.c
@@ -0,0 +1,955 @@
+/*
+ * tkTableWin.c --
+ *
+ * This module implements embedded windows for table widgets.
+ * Much of this code is adapted from tkGrid.c and tkTextWind.c.
+ *
+ * Copyright (c) 1998-2002 Jeffrey Hobbs
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ * RCS: @(#) $Id: tkTableWin.c,v 1.2 2016/01/12 18:59:57 joye Exp $
+ */
+
+#include "tkTable.h"
+
+static int StickyParseProc _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, Tk_Window tkwin,
+ CONST84 char *value, char *widgRec, int offset));
+static const char * StickyPrintProc _ANSI_ARGS_((ClientData clientData,
+ Tk_Window tkwin, char *widgRec, int offset,
+ Tcl_FreeProc **freeProcPtr));
+
+static void EmbWinLostSlaveProc _ANSI_ARGS_((ClientData clientData,
+ Tk_Window tkwin));
+static void EmbWinRequestProc _ANSI_ARGS_((ClientData clientData,
+ Tk_Window tkwin));
+
+static void EmbWinCleanup _ANSI_ARGS_((Table *tablePtr,
+ TableEmbWindow *ewPtr));
+static int EmbWinConfigure _ANSI_ARGS_((Table *tablePtr,
+ TableEmbWindow *ewPtr,
+ int objc, Tcl_Obj *CONST objv[]));
+static void EmbWinStructureProc _ANSI_ARGS_((ClientData clientData,
+ XEvent *eventPtr));
+static void EmbWinUnmapNow _ANSI_ARGS_((Tk_Window ewTkwin,
+ Tk_Window tkwin));
+
+static Tk_GeomMgr tableGeomType = {
+ "table", /* name */
+ EmbWinRequestProc, /* requestProc */
+ EmbWinLostSlaveProc, /* lostSlaveProc */
+};
+
+/* windows subcommands */
+static CONST84 char *winCmdNames[] = {
+ "cget", "configure", "delete", "move", "names", (char *) NULL
+};
+enum winCommand {
+ WIN_CGET, WIN_CONFIGURE, WIN_DELETE, WIN_MOVE, WIN_NAMES
+};
+
+/* Flag values for "sticky"ness The 16 combinations subsume the packer's
+ * notion of anchor and fill.
+ *
+ * STICK_NORTH This window sticks to the top of its cavity.
+ * STICK_EAST This window sticks to the right edge of its cavity.
+ * STICK_SOUTH This window sticks to the bottom of its cavity.
+ * STICK_WEST This window sticks to the left edge of its cavity.
+ */
+
+#define STICK_NORTH (1<<0)
+#define STICK_EAST (1<<1)
+#define STICK_SOUTH (1<<2)
+#define STICK_WEST (1<<3)
+
+/*
+ * The default specification for configuring embedded windows
+ * Done like this to make the command line parsing easy
+ */
+
+static Tk_CustomOption stickyOption = { StickyParseProc, StickyPrintProc,
+ (ClientData) NULL };
+static Tk_CustomOption tagBdOpt = { TableOptionBdSet, TableOptionBdGet,
+ (ClientData) BD_TABLE_WIN };
+
+static Tk_ConfigSpec winConfigSpecs[] = {
+ {TK_CONFIG_BORDER, "-background", "background", "Background", NULL,
+ Tk_Offset(TableEmbWindow, bg),
+ TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK },
+ {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *)NULL, (char *)NULL, 0, 0},
+ {TK_CONFIG_SYNONYM, "-bg", "background", (char *)NULL, (char *)NULL, 0, 0},
+ {TK_CONFIG_CUSTOM, "-borderwidth", "borderWidth", "BorderWidth", "",
+ 0 /* no offset */,
+ TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK, &tagBdOpt },
+ {TK_CONFIG_STRING, "-create", (char *)NULL, (char *)NULL, (char *)NULL,
+ Tk_Offset(TableEmbWindow, create),
+ TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK },
+ {TK_CONFIG_PIXELS, "-padx", (char *)NULL, (char *)NULL, (char *)NULL,
+ Tk_Offset(TableEmbWindow, padX), TK_CONFIG_DONT_SET_DEFAULT },
+ {TK_CONFIG_PIXELS, "-pady", (char *)NULL, (char *)NULL, (char *)NULL,
+ Tk_Offset(TableEmbWindow, padY), TK_CONFIG_DONT_SET_DEFAULT },
+ {TK_CONFIG_CUSTOM, "-sticky", (char *)NULL, (char *)NULL, (char *)NULL,
+ Tk_Offset(TableEmbWindow, sticky), TK_CONFIG_DONT_SET_DEFAULT,
+ &stickyOption},
+ {TK_CONFIG_RELIEF, "-relief", "relief", "Relief", NULL,
+ Tk_Offset(TableEmbWindow, relief), 0 },
+ {TK_CONFIG_WINDOW, "-window", (char *)NULL, (char *)NULL, (char *)NULL,
+ Tk_Offset(TableEmbWindow, tkwin),
+ TK_CONFIG_DONT_SET_DEFAULT|TK_CONFIG_NULL_OK },
+ {TK_CONFIG_END, (char *)NULL, (char *)NULL, (char *)NULL,
+ (char *)NULL, 0, 0 }
+};
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * StickyPrintProc --
+ * Converts the internal boolean combination of "sticky" bits onto
+ * a TCL string element containing zero or more of n, s, e, or w.
+ *
+ * Results:
+ * A string is placed into the "result" pointer.
+ *
+ * Side effects:
+ * none.
+ *
+ *----------------------------------------------------------------------
+ */
+static const char *
+StickyPrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
+ ClientData clientData; /* Ignored. */
+ Tk_Window tkwin; /* Window for text widget. */
+ char *widgRec; /* Pointer to TkTextEmbWindow
+ * structure. */
+ int offset; /* Ignored. */
+ Tcl_FreeProc **freeProcPtr; /* Pointer to variable to fill in with
+ * information about how to reclaim
+ * storage for return string. */
+{
+ int flags = ((TableEmbWindow *) widgRec)->sticky;
+ int count = 0;
+ char *result = (char *) ckalloc(5*sizeof(char));
+
+ if (flags&STICK_NORTH) result[count++] = 'n';
+ if (flags&STICK_EAST) result[count++] = 'e';
+ if (flags&STICK_SOUTH) result[count++] = 's';
+ if (flags&STICK_WEST) result[count++] = 'w';
+
+ *freeProcPtr = TCL_DYNAMIC;
+ result[count] = '\0';
+ return result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * StringParseProc --
+ * Converts an ascii string representing a widgets stickyness
+ * into the boolean result.
+ *
+ * Results:
+ * The boolean combination of the "sticky" bits is retuned. If an
+ * error occurs, such as an invalid character, -1 is returned instead.
+ *
+ * Side effects:
+ * none
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+StickyParseProc(clientData, interp, tkwin, value, widgRec, offset)
+ ClientData clientData; /* Not used.*/
+ Tcl_Interp *interp; /* Used for reporting errors. */
+ Tk_Window tkwin; /* Window for text widget. */
+ CONST84 char *value; /* Value of option. */
+ char *widgRec; /* Pointer to TkTextEmbWindow
+ * structure. */
+ int offset; /* Offset into item (ignored). */
+{
+ register TableEmbWindow *ewPtr = (TableEmbWindow *) widgRec;
+ int sticky = 0;
+ char c;
+
+ while ((c = *value++) != '\0') {
+ switch (c) {
+ case 'n': case 'N': sticky |= STICK_NORTH; break;
+ case 'e': case 'E': sticky |= STICK_EAST; break;
+ case 's': case 'S': sticky |= STICK_SOUTH; break;
+ case 'w': case 'W': sticky |= STICK_WEST; break;
+ case ' ': case ',': case '\t': case '\r': case '\n': break;
+ default:
+ Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
+ "bad sticky value \"", --value,
+ "\": must contain n, s, e or w",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+ }
+ ewPtr->sticky = sticky;
+ return TCL_OK;
+}
+
+/*
+ * ckallocs space for a new embedded window structure and clears the structure
+ * returns the pointer to the new structure
+ */
+static TableEmbWindow *
+TableNewEmbWindow(Table *tablePtr)
+{
+ TableEmbWindow *ewPtr = (TableEmbWindow *) ckalloc(sizeof(TableEmbWindow));
+ memset((VOID *) ewPtr, 0, sizeof(TableEmbWindow));
+
+ /*
+ * Set the values that aren't 0/NULL by default
+ */
+ ewPtr->tablePtr = tablePtr;
+ ewPtr->relief = -1;
+ ewPtr->padX = -1;
+ ewPtr->padY = -1;
+
+ return ewPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * EmbWinCleanup --
+ * Releases resources used by an embedded window before it is freed up.
+ *
+ * Results:
+ * Window will no longer be valid.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+static void
+EmbWinCleanup(Table *tablePtr, TableEmbWindow *ewPtr)
+{
+ Tk_FreeOptions(winConfigSpecs, (char *) ewPtr, tablePtr->display, 0);
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * EmbWinDisplay --
+ *
+ * This procedure is invoked by TableDisplay for
+ * mapping windows into cells.
+ *
+ * Results:
+ * Displays or moves window on table screen.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+void
+EmbWinDisplay(Table *tablePtr, Drawable window, TableEmbWindow *ewPtr,
+ TableTag *tagPtr, int x, int y, int width, int height)
+{
+ Tk_Window tkwin = tablePtr->tkwin;
+ Tk_Window ewTkwin = ewPtr->tkwin;
+ int diffx=0; /* Cavity width - slave width. */
+ int diffy=0; /* Cavity hight - slave height. */
+ int sticky = ewPtr->sticky;
+ int padx, pady;
+
+ if (ewPtr->bg) tagPtr->bg = ewPtr->bg;
+ if (ewPtr->relief != -1) tagPtr->relief = ewPtr->relief;
+ if (ewPtr->borders) {
+ tagPtr->borderStr = ewPtr->borderStr;
+ tagPtr->borders = ewPtr->borders;
+ tagPtr->bd[0] = ewPtr->bd[0];
+ tagPtr->bd[1] = ewPtr->bd[1];
+ tagPtr->bd[2] = ewPtr->bd[2];
+ tagPtr->bd[3] = ewPtr->bd[3];
+ }
+
+ padx = (ewPtr->padX < 0) ? tablePtr->padX : ewPtr->padX;
+ pady = (ewPtr->padY < 0) ? tablePtr->padY : ewPtr->padY;
+
+ x += padx;
+ width -= padx*2;
+ y += pady;
+ height -= pady*2;
+
+ if (width > Tk_ReqWidth(ewPtr->tkwin)) {
+ diffx = width - Tk_ReqWidth(ewPtr->tkwin);
+ width = Tk_ReqWidth(ewPtr->tkwin);
+ }
+ if (height > Tk_ReqHeight(ewPtr->tkwin)) {
+ diffy = height - Tk_ReqHeight(ewPtr->tkwin);
+ height = Tk_ReqHeight(ewPtr->tkwin);
+ }
+ if (sticky&STICK_EAST && sticky&STICK_WEST) {
+ width += diffx;
+ }
+ if (sticky&STICK_NORTH && sticky&STICK_SOUTH) {
+ height += diffy;
+ }
+ if (!(sticky&STICK_WEST)) {
+ x += (sticky&STICK_EAST) ? diffx : diffx/2;
+ }
+ if (!(sticky&STICK_NORTH)) {
+ y += (sticky&STICK_SOUTH) ? diffy : diffy/2;
+ }
+
+ /*
+ * If we fall below a specific minimum width/height requirement,
+ * we just unmap the window
+ */
+ if (width < 2 || height < 2) {
+ if (ewPtr->displayed) {
+ EmbWinUnmapNow(ewTkwin, tkwin);
+ }
+ return;
+ }
+
+ if (tkwin == Tk_Parent(ewTkwin)) {
+ if ((x != Tk_X(ewTkwin)) || (y != Tk_Y(ewTkwin))
+ || (width != Tk_Width(ewTkwin))
+ || (height != Tk_Height(ewTkwin))) {
+ Tk_MoveResizeWindow(ewTkwin, x, y, width, height);
+ }
+ Tk_MapWindow(ewTkwin);
+ } else {
+ Tk_MaintainGeometry(ewTkwin, tkwin, x, y, width, height);
+ }
+ ewPtr->displayed = 1;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * EmbWinUnmapNow --
+ * Handles unmapping the window depending on parent.
+ * tkwin should be tablePtr->tkwin.
+ * ewTkwin should be ewPtr->tkwin.
+ *
+ * Results:
+ * Removes the window.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+static void
+EmbWinUnmapNow(Tk_Window ewTkwin, Tk_Window tkwin)
+{
+ if (tkwin != Tk_Parent(ewTkwin)) {
+ Tk_UnmaintainGeometry(ewTkwin, tkwin);
+ }
+ Tk_UnmapWindow(ewTkwin);
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * EmbWinUnmap --
+ * This procedure is invoked by TableAdjustParams for
+ * unmapping windows managed moved offscreen.
+ * rlo, ... should be in real coords.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Unmaps embedded windows.
+ *
+ *--------------------------------------------------------------
+ */
+void
+EmbWinUnmap(Table *tablePtr, int rlo, int rhi, int clo, int chi)
+{
+ register TableEmbWindow *ewPtr;
+ Tcl_HashEntry *entryPtr;
+ int row, col, trow, tcol;
+ char buf[INDEX_BUFSIZE];
+
+ /*
+ * Transform numbers from real to user user coords
+ */
+ rlo += tablePtr->rowOffset;
+ rhi += tablePtr->rowOffset;
+ clo += tablePtr->colOffset;
+ chi += tablePtr->colOffset;
+ for (row = rlo; row <= rhi; row++) {
+ for (col = clo; col <= chi; col++) {
+ TableTrueCell(tablePtr, row, col, &trow, &tcol);
+ TableMakeArrayIndex(trow, tcol, buf);
+ entryPtr = Tcl_FindHashEntry(tablePtr->winTable, buf);
+ if (entryPtr != NULL) {
+ ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr);
+ if (ewPtr->displayed) {
+ ewPtr->displayed = 0;
+ if (ewPtr->tkwin != NULL && tablePtr->tkwin != NULL) {
+ EmbWinUnmapNow(ewPtr->tkwin, tablePtr->tkwin);
+ }
+ }
+ }
+ }
+ }
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * EmbWinRequestProc --
+ * This procedure is invoked by Tk_GeometryRequest for
+ * windows managed by the Table.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Arranges for tkwin, and all its managed siblings, to
+ * be re-arranged at the next idle point.
+ *
+ *--------------------------------------------------------------
+ */
+static void
+EmbWinRequestProc(clientData, tkwin)
+ ClientData clientData; /* Table's information about
+ * window that got new preferred
+ * geometry. */
+ Tk_Window tkwin; /* Other Tk-related information
+ * about the window. */
+{
+ register TableEmbWindow *ewPtr = (TableEmbWindow *) clientData;
+
+ /*
+ * Resize depends on the sticky
+ */
+ if (ewPtr->displayed && ewPtr->hPtr != NULL) {
+ Table *tablePtr = ewPtr->tablePtr;
+ int row, col, x, y, width, height;
+
+ TableParseArrayIndex(&row, &col,
+ Tcl_GetHashKey(tablePtr->winTable, ewPtr->hPtr));
+ if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset,
+ col-tablePtr->colOffset, &x, &y, &width, &height,
+ 0)) {
+ TableInvalidate(tablePtr, x, y, width, height, 0);
+ }
+ }
+}
+
+static void
+EmbWinRemove(TableEmbWindow *ewPtr)
+{
+ Table *tablePtr = ewPtr->tablePtr;
+
+ if (ewPtr->tkwin != NULL) {
+ Tk_DeleteEventHandler(ewPtr->tkwin, StructureNotifyMask,
+ EmbWinStructureProc, (ClientData) ewPtr);
+ ewPtr->tkwin = NULL;
+ }
+ ewPtr->displayed = 0;
+ if (tablePtr->tkwin != NULL) {
+ int row, col, x, y, width, height;
+
+ TableParseArrayIndex(&row, &col,
+ Tcl_GetHashKey(tablePtr->winTable, ewPtr->hPtr));
+ /* this will cause windows removed from the table to actually
+ * cause the associated embdedded window hash data to be removed */
+ Tcl_DeleteHashEntry(ewPtr->hPtr);
+ if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset,
+ col-tablePtr->colOffset, &x, &y, &width, &height,
+ 0))
+ TableInvalidate(tablePtr, x, y, width, height, 1);
+ }
+ /* this will cause windows removed from the table to actually
+ * cause the associated embdedded window hash data to be removed */
+ EmbWinCleanup(tablePtr, ewPtr);
+ ckfree((char *) ewPtr);
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * EmbWinLostSlaveProc --
+ * This procedure 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 table-related information about the slave.
+ *
+ *--------------------------------------------------------------
+ */
+
+static void
+EmbWinLostSlaveProc(clientData, tkwin)
+ ClientData clientData; /* Table structure for slave window that
+ * was stolen away. */
+ Tk_Window tkwin; /* Tk's handle for the slave window. */
+{
+ register TableEmbWindow *ewPtr = (TableEmbWindow *) clientData;
+
+#if 0
+ Tcl_CancelIdleCall(EmbWinDelayedUnmap, (ClientData) ewPtr);
+#endif
+ EmbWinUnmapNow(tkwin, ewPtr->tablePtr->tkwin);
+ EmbWinRemove(ewPtr);
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * EmbWinStructureProc --
+ * This procedure is invoked by the Tk event loop whenever
+ * StructureNotify events occur for a window that's embedded
+ * in a table widget. This procedure's only purpose is to
+ * clean up when windows are deleted.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The window is disassociated from the window segment, and
+ * the portion of the table is redisplayed.
+ *
+ *--------------------------------------------------------------
+ */
+static void
+EmbWinStructureProc(clientData, eventPtr)
+ ClientData clientData; /* Pointer to record describing window item. */
+ XEvent *eventPtr; /* Describes what just happened. */
+{
+ register TableEmbWindow *ewPtr = (TableEmbWindow *) clientData;
+
+ if (eventPtr->type != DestroyNotify) {
+ return;
+ }
+
+ EmbWinRemove(ewPtr);
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * EmbWinDelete --
+ * This procedure is invoked by ... whenever
+ * an embedded window is being deleted.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The embedded window is deleted, if it exists, and any resources
+ * associated with it are released.
+ *
+ *--------------------------------------------------------------
+ */
+void
+EmbWinDelete(register Table *tablePtr, TableEmbWindow *ewPtr)
+{
+ Tcl_HashEntry *entryPtr = ewPtr->hPtr;
+
+ if (ewPtr->tkwin != NULL) {
+ Tk_Window tkwin = ewPtr->tkwin;
+ /*
+ * Delete the event handler for the window before destroying
+ * the window, so that EmbWinStructureProc doesn't get called
+ * (we'll already do everything that it would have done, and
+ * it will just get confused).
+ */
+
+ ewPtr->tkwin = NULL;
+ Tk_DeleteEventHandler(tkwin, StructureNotifyMask,
+ EmbWinStructureProc, (ClientData) ewPtr);
+ Tk_DestroyWindow(tkwin);
+ }
+ if (tablePtr->tkwin != NULL && entryPtr != NULL) {
+ int row, col, x, y, width, height;
+ TableParseArrayIndex(&row, &col,
+ Tcl_GetHashKey(tablePtr->winTable, entryPtr));
+ Tcl_DeleteHashEntry(entryPtr);
+
+ if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset,
+ col-tablePtr->colOffset,
+ &x, &y, &width, &height, 0))
+ TableInvalidate(tablePtr, x, y, width, height, 0);
+ }
+#if 0
+ Tcl_CancelIdleCall(EmbWinDelayedUnmap, (ClientData) ewPtr);
+#endif
+ EmbWinCleanup(tablePtr, ewPtr);
+ ckfree((char *) ewPtr);
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * EmbWinConfigure --
+ * This procedure is called to handle configuration options
+ * for an embedded window.
+ *
+ * Results:
+ * The return value is a standard Tcl result. If TCL_ERROR is
+ * returned, then the interp's result contains an error message..
+ *
+ * Side effects:
+ * Configuration information for the embedded window changes,
+ * such as alignment, stretching, or name of the embedded
+ * window.
+ *
+ *--------------------------------------------------------------
+ */
+static int
+EmbWinConfigure(tablePtr, ewPtr, objc, objv)
+ Table *tablePtr; /* Information about table widget that
+ * contains embedded window. */
+ TableEmbWindow *ewPtr; /* Embedded window to be configured. */
+ int objc; /* Number of objs in objv. */
+ Tcl_Obj *CONST objv[]; /* Obj type options. */
+{
+ Tcl_Interp *interp = tablePtr->interp;
+ Tk_Window oldWindow;
+ int i, result;
+ CONST84 char **argv;
+
+ oldWindow = ewPtr->tkwin;
+
+ /* Stringify */
+ argv = (CONST84 char **) ckalloc((objc + 1) * sizeof(char *));
+ for (i = 0; i < objc; i++)
+ argv[i] = Tcl_GetString(objv[i]);
+ argv[i] = NULL;
+ result = Tk_ConfigureWidget(interp, tablePtr->tkwin,
+ winConfigSpecs, objc, argv, (char *) ewPtr,
+ TK_CONFIG_ARGV_ONLY);
+ ckfree((char *) argv);
+ if (result != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ if (oldWindow != ewPtr->tkwin) {
+ ewPtr->displayed = 0;
+ if (oldWindow != NULL) {
+ Tk_DeleteEventHandler(oldWindow, StructureNotifyMask,
+ EmbWinStructureProc, (ClientData) ewPtr);
+ Tk_ManageGeometry(oldWindow, (Tk_GeomMgr *) NULL,
+ (ClientData) NULL);
+ EmbWinUnmapNow(oldWindow, tablePtr->tkwin);
+ }
+ if (ewPtr->tkwin != NULL) {
+ Tk_Window ancestor, parent;
+
+ /*
+ * Make sure that the table is either the parent of the
+ * embedded window or a descendant of that parent. Also,
+ * don't allow a top-level window to be managed inside
+ * a table.
+ */
+
+ parent = Tk_Parent(ewPtr->tkwin);
+ for (ancestor = tablePtr->tkwin; ;
+ ancestor = Tk_Parent(ancestor)) {
+ if (ancestor == parent) {
+ break;
+ }
+ if (Tk_IsTopLevel(ancestor)) {
+ badMaster:
+ Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
+ "can't embed ",
+ Tk_PathName(ewPtr->tkwin), " in ",
+ Tk_PathName(tablePtr->tkwin),
+ (char *)NULL);
+ ewPtr->tkwin = NULL;
+ return TCL_ERROR;
+ }
+ }
+ if (Tk_IsTopLevel(ewPtr->tkwin) ||
+ (ewPtr->tkwin == tablePtr->tkwin)) {
+ goto badMaster;
+ }
+
+ /*
+ * Take over geometry management for the window, plus create
+ * an event handler to find out when it is deleted.
+ */
+
+ Tk_ManageGeometry(ewPtr->tkwin, &tableGeomType, (ClientData)ewPtr);
+ Tk_CreateEventHandler(ewPtr->tkwin, StructureNotifyMask,
+ EmbWinStructureProc, (ClientData) ewPtr);
+ }
+ }
+ return TCL_OK;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * Table_WinMove --
+ * This procedure is invoked by ... whenever
+ * an embedded window is being moved.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * If an embedded window is in the dest cell, it is deleted.
+ *
+ *--------------------------------------------------------------
+ */
+int
+Table_WinMove(register Table *tablePtr, char *CONST srcPtr,
+ char *CONST destPtr, int flags)
+{
+ int srow, scol, row, col, new;
+ Tcl_HashEntry *entryPtr;
+ TableEmbWindow *ewPtr;
+
+ if (TableGetIndex(tablePtr, srcPtr, &srow, &scol) != TCL_OK ||
+ TableGetIndex(tablePtr, destPtr, &row, &col) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ entryPtr = Tcl_FindHashEntry(tablePtr->winTable, srcPtr);
+ if (entryPtr == NULL) {
+ if (flags & INV_NO_ERR_MSG) {
+ return TCL_OK;
+ } else {
+ Tcl_AppendStringsToObj(Tcl_GetObjResult(tablePtr->interp),
+ "no window at index \"", srcPtr, "\"", (char *) NULL);
+ return TCL_ERROR;
+ }
+ }
+ /* avoid moving it to the same location */
+ if (srow == row && scol == col) {
+ return TCL_OK;
+ }
+ /* get the window pointer */
+ ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr);
+ /* and free the old hash table entry */
+ Tcl_DeleteHashEntry(entryPtr);
+
+ entryPtr = Tcl_CreateHashEntry(tablePtr->winTable, destPtr, &new);
+ if (!new) {
+ /* window already there - just delete it */
+ TableEmbWindow *ewPtrDel;
+ ewPtrDel = (TableEmbWindow *) Tcl_GetHashValue(entryPtr);
+ /* This prevents the deletion of it's own entry, since we need it */
+ ewPtrDel->hPtr = NULL;
+ EmbWinDelete(tablePtr, ewPtrDel);
+ }
+ /* set the new entry's value */
+ Tcl_SetHashValue(entryPtr, (ClientData) ewPtr);
+ ewPtr->hPtr = entryPtr;
+
+ if (flags & INV_FORCE) {
+ int x, y, w, h;
+ /* Invalidate old cell */
+ if (TableCellVCoords(tablePtr, srow-tablePtr->rowOffset,
+ scol-tablePtr->colOffset, &x, &y, &w, &h, 0)) {
+ TableInvalidate(tablePtr, x, y, w, h, 0);
+ }
+ /* Invalidate new cell */
+ if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset,
+ col-tablePtr->colOffset, &x, &y, &w, &h, 0)) {
+ TableInvalidate(tablePtr, x, y, w, h, 0);
+ }
+ }
+ return TCL_OK;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * Table_WinDelete --
+ * This procedure is invoked by ... whenever
+ * an embedded window is being delete.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * Window info will be deleted.
+ *
+ *--------------------------------------------------------------
+ */
+int
+Table_WinDelete(register Table *tablePtr, char *CONST idxPtr)
+{
+ Tcl_HashEntry *entryPtr;
+
+ entryPtr = Tcl_FindHashEntry(tablePtr->winTable, idxPtr);
+ if (entryPtr != NULL) {
+ /* get the window pointer & clean up data associated with it */
+ EmbWinDelete(tablePtr, (TableEmbWindow *) Tcl_GetHashValue(entryPtr));
+ }
+ return TCL_OK;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * Table_WindowCmd --
+ * This procedure is invoked to process the window method
+ * that corresponds to a widget managed by this module.
+ * See the user documentation for details on what it does.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * See the user documentation.
+ *
+ *--------------------------------------------------------------
+ */
+int
+Table_WindowCmd(ClientData clientData, register Tcl_Interp *interp,
+ int objc, Tcl_Obj *CONST objv[])
+{
+ register Table *tablePtr = (Table *)clientData;
+ int result = TCL_OK, cmdIndex, row, col, x, y, width, height, i, new;
+ TableEmbWindow *ewPtr;
+ Tcl_HashEntry *entryPtr;
+ Tcl_HashSearch search;
+ char buf[INDEX_BUFSIZE], *keybuf, *winname;
+
+ if (objc < 3) {
+ Tcl_WrongNumArgs(interp, 2, objv, "option ?arg arg ...?");
+ return TCL_ERROR;
+ }
+
+ /* parse the next argument */
+ if (Tcl_GetIndexFromObj(interp, objv[2], winCmdNames,
+ "option", 0, &cmdIndex) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ switch ((enum winCommand) cmdIndex) {
+ case WIN_CGET:
+ if (objc != 5) {
+ Tcl_WrongNumArgs(interp, 3, objv, "index option");
+ return TCL_ERROR;
+ }
+ entryPtr = Tcl_FindHashEntry(tablePtr->winTable,
+ Tcl_GetString(objv[3]));
+ if (entryPtr == NULL) {
+ Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
+ "no window at index \"",
+ Tcl_GetString(objv[3]), "\"", (char *)NULL);
+ return TCL_ERROR;
+ } else {
+ ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr);
+ result = Tk_ConfigureValue(interp, tablePtr->tkwin, winConfigSpecs,
+ (char *) ewPtr,
+ Tcl_GetString(objv[4]), 0);
+ }
+ return result; /* CGET */
+
+ case WIN_CONFIGURE:
+ if (objc < 4) {
+ Tcl_WrongNumArgs(interp, 3, objv, "index ?arg arg ...?");
+ return TCL_ERROR;
+ }
+ if (TableGetIndexObj(tablePtr, objv[3], &row, &col) == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+ TableMakeArrayIndex(row, col, buf);
+ entryPtr = Tcl_CreateHashEntry(tablePtr->winTable, buf, &new);
+
+ if (new) {
+ /* create the structure */
+ ewPtr = TableNewEmbWindow(tablePtr);
+
+ /* insert it into the table */
+ Tcl_SetHashValue(entryPtr, (ClientData) ewPtr);
+ ewPtr->hPtr = entryPtr;
+
+ /* configure the window structure */
+ result = EmbWinConfigure(tablePtr, ewPtr, objc-4, objv+4);
+ if (result == TCL_ERROR) {
+ /* release the structure */
+ EmbWinCleanup(tablePtr, ewPtr);
+ ckfree((char *) ewPtr);
+
+ /* and free the hash table entry */
+ Tcl_DeleteHashEntry(entryPtr);
+ }
+ } else {
+ /* window exists, do a reconfig if we have enough args */
+ /* get the window pointer from the table */
+ ewPtr = (TableEmbWindow *) Tcl_GetHashValue(entryPtr);
+
+ /* 5 args means that there are values to replace */
+ if (objc > 5) {
+ /* and do a reconfigure */
+ result = EmbWinConfigure(tablePtr, ewPtr, objc-4, objv+4);
+ }
+ }
+ if (result == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * If there were less than 6 args, we need
+ * to do a printout of the config, even for new windows
+ */
+ if (objc < 6) {
+ result = Tk_ConfigureInfo(interp, tablePtr->tkwin, winConfigSpecs,
+ (char *) ewPtr, (objc == 5)?
+ Tcl_GetString(objv[4]) : NULL, 0);
+ } else {
+ /* Otherwise we reconfigured so invalidate
+ * the table for a redraw */
+ if (TableCellVCoords(tablePtr, row-tablePtr->rowOffset,
+ col-tablePtr->colOffset,
+ &x, &y, &width, &height, 0)) {
+ TableInvalidate(tablePtr, x, y, width, height, 1);
+ }
+ }
+ return result; /* CONFIGURE */
+
+ case WIN_DELETE:
+ if (objc < 4) {
+ Tcl_WrongNumArgs(interp, 3, objv, "index ?index ...?");
+ return TCL_ERROR;
+ }
+ for (i = 3; i < objc; i++) {
+ Table_WinDelete(tablePtr, Tcl_GetString(objv[i]));
+ }
+ break;
+
+ case WIN_MOVE:
+ if (objc != 5) {
+ Tcl_WrongNumArgs(interp, 3, objv, "srcIndex destIndex");
+ return TCL_ERROR;
+ }
+ result = Table_WinMove(tablePtr, Tcl_GetString(objv[3]),
+ Tcl_GetString(objv[4]), INV_FORCE);
+ break;
+
+ case WIN_NAMES: {
+ Tcl_Obj *objPtr = Tcl_NewObj();
+
+ /* just print out the window names */
+ if (objc < 3 || objc > 4) {
+ Tcl_WrongNumArgs(interp, 3, objv, "?pattern?");
+ return TCL_ERROR;
+ }
+ winname = (objc == 4) ? Tcl_GetString(objv[3]) : NULL;
+ entryPtr = Tcl_FirstHashEntry(tablePtr->winTable, &search);
+ while (entryPtr != NULL) {
+ keybuf = Tcl_GetHashKey(tablePtr->winTable, entryPtr);
+ if (objc == 3 || Tcl_StringMatch(keybuf, winname)) {
+ Tcl_ListObjAppendElement(NULL, objPtr,
+ Tcl_NewStringObj(keybuf, -1));
+ }
+ entryPtr = Tcl_NextHashEntry(&search);
+ }
+ Tcl_SetObjResult(interp, TableCellSortObj(interp, objPtr));
+ break;
+ }
+ }
+ return TCL_OK;
+}