diff options
Diffstat (limited to 'generic/tkCanvWind.c')
-rw-r--r-- | generic/tkCanvWind.c | 331 |
1 files changed, 285 insertions, 46 deletions
diff --git a/generic/tkCanvWind.c b/generic/tkCanvWind.c index 4dd8ee3..fab0015 100644 --- a/generic/tkCanvWind.c +++ b/generic/tkCanvWind.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkCanvWind.c,v 1.3 1999/04/16 01:51:12 stanton Exp $ + * RCS: @(#) $Id: tkCanvWind.c,v 1.4 1999/12/14 06:52:26 hobbs Exp $ */ #include <stdio.h> @@ -41,7 +41,12 @@ typedef struct WindowItem { * Information used for parsing configuration specs: */ -static Tk_CustomOption tagsOption = {Tk_CanvasTagsParseProc, +static Tk_CustomOption stateOption = { + (Tk_OptionParseProc *) TkStateParseProc, + TkStatePrintProc, (ClientData) 2 +}; +static Tk_CustomOption tagsOption = { + (Tk_OptionParseProc *) Tk_CanvasTagsParseProc, Tk_CanvasTagsPrintProc, (ClientData) NULL }; @@ -50,6 +55,9 @@ static Tk_ConfigSpec configSpecs[] = { "center", Tk_Offset(WindowItem, anchor), TK_CONFIG_DONT_SET_DEFAULT}, {TK_CONFIG_PIXELS, "-height", (char *) NULL, (char *) NULL, "0", Tk_Offset(WindowItem, height), TK_CONFIG_DONT_SET_DEFAULT}, + {TK_CONFIG_CUSTOM, "-state", (char *) NULL, (char *) NULL, + (char *) NULL, Tk_Offset(Tk_Item, state), TK_CONFIG_NULL_OK, + &stateOption}, {TK_CONFIG_CUSTOM, "-tags", (char *) NULL, (char *) NULL, (char *) NULL, 0, TK_CONFIG_NULL_OK, &tagsOption}, {TK_CONFIG_PIXELS, "-width", (char *) NULL, (char *) NULL, @@ -68,10 +76,10 @@ static void ComputeWindowBbox _ANSI_ARGS_((Tk_Canvas canvas, WindowItem *winItemPtr)); static int ConfigureWinItem _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv, int flags)); + Tcl_Obj *CONST argv[], int flags)); static int CreateWinItem _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, struct Tk_Item *itemPtr, - int argc, char **argv)); + int argc, Tcl_Obj *CONST argv[])); static void DeleteWinItem _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, Display *display)); static void DisplayWinItem _ANSI_ARGS_((Tk_Canvas canvas, @@ -84,7 +92,7 @@ static void TranslateWinItem _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double deltaX, double deltaY)); static int WinItemCoords _ANSI_ARGS_((Tcl_Interp *interp, Tk_Canvas canvas, Tk_Item *itemPtr, int argc, - char **argv)); + Tcl_Obj *CONST argv[])); static void WinItemLostSlaveProc _ANSI_ARGS_(( ClientData clientData, Tk_Window tkwin)); static void WinItemRequestProc _ANSI_ARGS_((ClientData clientData, @@ -93,8 +101,17 @@ static void WinItemStructureProc _ANSI_ARGS_(( ClientData clientData, XEvent *eventPtr)); static int WinItemToArea _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *rectPtr)); +static int WinItemToPostscript _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Canvas canvas, Tk_Item *itemPtr, int prepass)); static double WinItemToPoint _ANSI_ARGS_((Tk_Canvas canvas, Tk_Item *itemPtr, double *pointPtr)); +#ifdef X_GetImage +static int xerrorhandler _ANSI_ARGS_((ClientData clientData, + XErrorEvent *e)); +#endif +static int CanvasPsWindow _ANSI_ARGS_((Tcl_Interp *interp, + Tk_Window tkwin, Tk_Canvas canvas, double x, + double y, int width, int height)); /* * The structure below defines the window item type by means of procedures @@ -110,10 +127,10 @@ Tk_ItemType tkWindowType = { WinItemCoords, /* coordProc */ DeleteWinItem, /* deleteProc */ DisplayWinItem, /* displayProc */ - 1, /* alwaysRedraw */ + 1|TK_CONFIG_OBJS, /* flags */ WinItemToPoint, /* pointProc */ WinItemToArea, /* areaProc */ - (Tk_ItemPostscriptProc *) NULL, /* postscriptProc */ + WinItemToPostscript, /* postscriptProc */ ScaleWinItem, /* scaleProc */ TranslateWinItem, /* translateProc */ (Tk_ItemIndexProc *) NULL, /* indexProc */ @@ -121,7 +138,7 @@ Tk_ItemType tkWindowType = { (Tk_ItemSelectionProc *) NULL, /* selectionProc */ (Tk_ItemInsertProc *) NULL, /* insertProc */ (Tk_ItemDCharsProc *) NULL, /* dTextProc */ - (Tk_ItemType *) NULL /* nextPtr */ + (Tk_ItemType *) NULL, /* nextPtr */ }; @@ -164,11 +181,24 @@ CreateWinItem(interp, canvas, itemPtr, argc, argv) Tk_Item *itemPtr; /* Record to hold new item; header * has been initialized by caller. */ int argc; /* Number of arguments in argv. */ - char **argv; /* Arguments describing rectangle. */ + Tcl_Obj *CONST argv[]; /* Arguments describing window. */ { WindowItem *winItemPtr = (WindowItem *) itemPtr; + int i; + + if (argc==1) { + i = 1; + } else { + char *arg = Tcl_GetStringFromObj(argv[1], NULL); + if (((argc>1) && (arg[0] == '-') + && (arg[1] >= 'a') && (arg[1] <= 'z'))) { + i = 1; + } else { + i = 2; + } + } - if (argc < 2) { + if (argc < i) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tk_PathName(Tk_CanvasTkwin(canvas)), " create ", itemPtr->typePtr->name, " x y ?options?\"", @@ -190,18 +220,16 @@ CreateWinItem(interp, canvas, itemPtr, argc, argv) * Process the arguments to fill in the item record. */ - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &winItemPtr->x) != TCL_OK) - || (Tk_CanvasGetCoord(interp, canvas, argv[1], - &winItemPtr->y) != TCL_OK)) { - return TCL_ERROR; + if ((WinItemCoords(interp, canvas, itemPtr, i, argv) != TCL_OK)) { + goto error; } - - if (ConfigureWinItem(interp, canvas, itemPtr, argc-2, argv+2, 0) - != TCL_OK) { - DeleteWinItem(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); - return TCL_ERROR; + if (ConfigureWinItem(interp, canvas, itemPtr, argc-i, argv+i, 0) == TCL_OK) { + return TCL_OK; } - return TCL_OK; + + error: + DeleteWinItem(canvas, itemPtr, Tk_Display(Tk_CanvasTkwin(canvas))); + return TCL_ERROR; } /* @@ -230,19 +258,33 @@ WinItemCoords(interp, canvas, itemPtr, argc, argv) * read or modified. */ int argc; /* Number of coordinates supplied in * argv. */ - char **argv; /* Array of coordinates: x1, y1, + Tcl_Obj *CONST argv[]; /* Array of coordinates: x1, y1, * x2, y2, ... */ { WindowItem *winItemPtr = (WindowItem *) itemPtr; - char x[TCL_DOUBLE_SPACE], y[TCL_DOUBLE_SPACE]; if (argc == 0) { - Tcl_PrintDouble(interp, winItemPtr->x, x); - Tcl_PrintDouble(interp, winItemPtr->y, y); - Tcl_AppendResult(interp, x, " ", y, (char *) NULL); - } else if (argc == 2) { - if ((Tk_CanvasGetCoord(interp, canvas, argv[0], &winItemPtr->x) - != TCL_OK) || (Tk_CanvasGetCoord(interp, canvas, argv[1], + Tcl_Obj *obj = Tcl_NewObj(); + Tcl_Obj *subobj = Tcl_NewDoubleObj(winItemPtr->x); + Tcl_ListObjAppendElement(interp, obj, subobj); + subobj = Tcl_NewDoubleObj(winItemPtr->y); + Tcl_ListObjAppendElement(interp, obj, subobj); + Tcl_SetObjResult(interp, obj); + } else if (argc < 3) { + if (argc==1) { + if (Tcl_ListObjGetElements(interp, argv[0], &argc, + (Tcl_Obj ***) &argv) != TCL_OK) { + return TCL_ERROR; + } else if (argc != 2) { + char buf[64 + TCL_INTEGER_SPACE]; + + sprintf(buf, "wrong # coordinates: expected 2, got %d", argc); + Tcl_SetResult(interp, buf, TCL_VOLATILE); + return TCL_ERROR; + } + } + if ((Tk_CanvasGetCoordFromObj(interp, canvas, argv[0], &winItemPtr->x) + != TCL_OK) || (Tk_CanvasGetCoordFromObj(interp, canvas, argv[1], &winItemPtr->y) != TCL_OK)) { return TCL_ERROR; } @@ -281,7 +323,7 @@ ConfigureWinItem(interp, canvas, itemPtr, argc, argv, flags) Tk_Canvas canvas; /* Canvas containing itemPtr. */ Tk_Item *itemPtr; /* Window item to reconfigure. */ int argc; /* Number of elements in argv. */ - char **argv; /* Arguments describing things to configure. */ + Tcl_Obj *CONST argv[]; /* Arguments describing things to configure. */ int flags; /* Flags to pass to Tk_ConfigureWidget. */ { WindowItem *winItemPtr = (WindowItem *) itemPtr; @@ -290,8 +332,8 @@ ConfigureWinItem(interp, canvas, itemPtr, argc, argv, flags) oldWindow = winItemPtr->tkwin; canvasTkwin = Tk_CanvasTkwin(canvas); - if (Tk_ConfigureWidget(interp, canvasTkwin, configSpecs, argc, argv, - (char *) winItemPtr, flags) != TCL_OK) { + if (Tk_ConfigureWidget(interp, canvasTkwin, configSpecs, argc, (char **) argv, + (char *) winItemPtr, flags|TK_CONFIG_OBJS) != TCL_OK) { return TCL_ERROR; } @@ -417,11 +459,15 @@ ComputeWindowBbox(canvas, winItemPtr) * recomputed. */ { int width, height, x, y; + Tk_State state = winItemPtr->header.state; x = (int) (winItemPtr->x + ((winItemPtr->x >= 0) ? 0.5 : - 0.5)); y = (int) (winItemPtr->y + ((winItemPtr->y >= 0) ? 0.5 : - 0.5)); - if (winItemPtr->tkwin == NULL) { + if (state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if ((winItemPtr->tkwin == NULL) || (state == TK_STATE_HIDDEN)) { /* * There is no window for this item yet. Just give it a 1x1 * bounding box. Don't give it a 0x0 bounding box; there are @@ -542,11 +588,18 @@ DisplayWinItem(canvas, itemPtr, display, drawable, regionX, regionY, int width, height; short x, y; Tk_Window canvasTkwin = Tk_CanvasTkwin(canvas); + Tk_State state = itemPtr->state; if (winItemPtr->tkwin == NULL) { return; } - + if(state == TK_STATE_NULL) { + state = ((TkCanvas *)canvas)->canvas_state; + } + if (state == TK_STATE_HIDDEN) { + Tk_UnmapWindow(winItemPtr->tkwin); + return; + } Tk_CanvasWindowCoords(canvas, (double) winItemPtr->header.x1, (double) winItemPtr->header.y1, &x, &y); width = winItemPtr->header.x2 - winItemPtr->header.x1; @@ -593,7 +646,7 @@ DisplayWinItem(canvas, itemPtr, display, drawable, regionX, regionY, * WinItemToPoint -- * * Computes the distance from a given point to a given - * rectangle, in canvas units. + * window, in canvas units. * * Results: * The return value is 0 if the point whose x and y coordinates @@ -622,7 +675,7 @@ WinItemToPoint(canvas, itemPtr, pointPtr) y2 = winItemPtr->header.y2; /* - * Point is outside rectangle. + * Point is outside window. */ if (pointPtr[0] < x1) { @@ -692,16 +745,203 @@ WinItemToArea(canvas, itemPtr, rectPtr) /* *-------------------------------------------------------------- * + * xerrorhandler -- + * + * This is a dummy function to catch X11 errors during an + * attempt to print a canvas window. + * + * Results: + * None. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +#ifdef X_GetImage +static int +xerrorhandler(clientData, e) + ClientData clientData; + XErrorEvent *e; +{ + return 0; +} +#endif + + +/* + *-------------------------------------------------------------- + * + * WinItemToPostscript -- + * + * This procedure is called to generate Postscript for + * window items. + * + * Results: + * The return value is a standard Tcl result. If an error + * occurs in generating Postscript then an error message is + * left in interp->result, replacing whatever used to be there. + * If no error occurs, then Postscript for the item is appended + * to the result. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +static int +WinItemToPostscript(interp, canvas, itemPtr, prepass) + Tcl_Interp *interp; /* Leave Postscript or error message + * here. */ + Tk_Canvas canvas; /* Information about overall canvas. */ + Tk_Item *itemPtr; /* Item for which Postscript is + * wanted. */ + int prepass; /* 1 means this is a prepass to + * collect font information; 0 means + * final Postscript is being created.*/ +{ + WindowItem *winItemPtr = (WindowItem *)itemPtr; + + double x, y; + int width, height; + Tk_Window tkwin = winItemPtr->tkwin; + + if (prepass || winItemPtr->tkwin == NULL) { + return TCL_OK; + } + + width = Tk_Width(tkwin); + height = Tk_Height(tkwin); + + /* + * Compute the coordinates of the lower-left corner of the window, + * taking into account the anchor position for the window. + */ + + x = winItemPtr->x; + y = Tk_CanvasPsY(canvas, winItemPtr->y); + + switch (winItemPtr->anchor) { + case TK_ANCHOR_NW: y -= height; break; + case TK_ANCHOR_N: x -= width/2.0; y -= height; break; + case TK_ANCHOR_NE: x -= width; y -= height; break; + case TK_ANCHOR_E: x -= width; y -= height/2.0; break; + case TK_ANCHOR_SE: x -= width; break; + case TK_ANCHOR_S: x -= width/2.0; break; + case TK_ANCHOR_SW: break; + case TK_ANCHOR_W: y -= height/2.0; break; + case TK_ANCHOR_CENTER: x -= width/2.0; y -= height/2.0; break; + } + + return CanvasPsWindow(interp, tkwin, canvas, x, y, width, height); +} + +static int +CanvasPsWindow(interp, tkwin, canvas, x, y, width, height) + Tcl_Interp *interp; /* Leave Postscript or error message + * here. */ + Tk_Window tkwin; /* window to be printed */ + Tk_Canvas canvas; /* Information about overall canvas. */ + double x, y; /* origin of window. */ + int width, height; /* width/height of window. */ +{ + char buffer[256]; + TkWindow *winPtr; + XImage *ximage; + int result; + Tcl_DString buffer1, buffer2; +#ifdef X_GetImage + Tk_ErrorHandler handle; +#endif + + sprintf(buffer, "\n%%%% %s item (%s, %d x %d)\n%.15g %.15g translate\n", + Tk_Class(tkwin), Tk_PathName(tkwin), width, height, x, y); + Tcl_AppendResult(interp, buffer, (char *) NULL); + + /* first try if the widget has its own "postscript" command. If it + * exists, this will produce much better postscript than + * when a pixmap is used. + */ + + Tcl_DStringInit(&buffer1); + Tcl_DStringInit(&buffer2); + Tcl_DStringGetResult(interp, &buffer2); + sprintf (buffer, "%s postscript -prolog 0\n", Tk_PathName(tkwin)); + result = Tcl_Eval(interp, buffer); + Tcl_DStringGetResult(interp, &buffer1); + Tcl_DStringResult(interp, &buffer2); + Tcl_DStringFree(&buffer2); + + if (result == TCL_OK) { + Tcl_AppendResult(interp, + "50 dict begin\nsave\ngsave\n", + (char *) NULL); + sprintf (buffer, + "0 %d moveto %d 0 rlineto 0 -%d rlineto -%d", + height, width, height, width); + Tcl_AppendResult(interp, buffer, (char *) NULL); + Tcl_AppendResult(interp, " 0 rlineto closepath\n", + "1.000 1.000 1.000 setrgbcolor AdjustColor\nfill\ngrestore\n", + Tcl_DStringValue(&buffer1), "\nrestore\nend\n\n\n", + (char *) NULL); + Tcl_DStringFree(&buffer1); + + for (winPtr = ((TkWindow *) tkwin)->childList; winPtr != NULL; + winPtr = winPtr->nextPtr) { + if (Tk_IsMapped(winPtr)) { +/* printf("child window: %s\n", winPtr->pathName);*/ + } + } + return result; + } + Tcl_DStringFree(&buffer1); + + /* + * If the window is off the screen it will generate an BadMatch/XError + * We catch any BadMatch errors here + */ +#ifdef X_GetImage + handle = Tk_CreateErrorHandler(Tk_Display(tkwin), BadMatch, + X_GetImage, -1, xerrorhandler, (ClientData) tkwin); +#endif + + /* + * Generate an XImage from the window. We can then read pixel + * values out of the XImage. + */ + + ximage = XGetImage(Tk_Display(tkwin), Tk_WindowId(tkwin), 0, 0, + (unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap); + +#ifdef X_GetImage + Tk_DeleteErrorHandler(handle); +#endif + + if (ximage == (XImage*) NULL) { + return TCL_OK; + } + + result = TkPostscriptImage(interp, tkwin, + ((TkCanvas *)canvas)->psInfo, ximage, 0, 0, width, height); + + XDestroyImage(ximage); + return result; +} + +/* + *-------------------------------------------------------------- + * * ScaleWinItem -- * - * This procedure is invoked to rescale a rectangle or oval - * item. + * This procedure is invoked to rescale a window item. * * Results: * None. * * Side effects: - * The rectangle or oval referred to by itemPtr is rescaled + * The window referred to by itemPtr is rescaled * so that the following transformation is applied to all * point coordinates: * x' = originX + scaleX*(x-originX) @@ -712,9 +952,9 @@ WinItemToArea(canvas, itemPtr, rectPtr) static void ScaleWinItem(canvas, itemPtr, originX, originY, scaleX, scaleY) - Tk_Canvas canvas; /* Canvas containing rectangle. */ - Tk_Item *itemPtr; /* Rectangle to be scaled. */ - double originX, originY; /* Origin about which to scale rect. */ + Tk_Canvas canvas; /* Canvas containing window. */ + Tk_Item *itemPtr; /* Window to be scaled. */ + double originX, originY; /* Origin about which to scale window. */ double scaleX; /* Amount to scale in X direction. */ double scaleY; /* Amount to scale in Y direction. */ { @@ -736,16 +976,15 @@ ScaleWinItem(canvas, itemPtr, originX, originY, scaleX, scaleY) * * TranslateWinItem -- * - * This procedure is called to move a rectangle or oval by a - * given amount. + * This procedure is called to move a window by a given amount. * * Results: * None. * * Side effects: - * The position of the rectangle or oval is offset by - * (xDelta, yDelta), and the bounding box is updated in the - * generic part of the item structure. + * The position of the window is offset by (xDelta, yDelta), + * and the bounding box is updated in the generic part of the + * item structure. * *-------------------------------------------------------------- */ |