diff options
author | jan.nijtmans <nijtmans@users.sourceforge.net> | 2019-06-05 21:25:58 (GMT) |
---|---|---|
committer | jan.nijtmans <nijtmans@users.sourceforge.net> | 2019-06-05 21:25:58 (GMT) |
commit | 72a4eea4cdef1059da99c87ce25a4c2db0972743 (patch) | |
tree | 6790e6d682322d159d06bb18662acb801d63725c /generic/tkFrame.c | |
parent | ebee84d3759fbe688f9a527facf83e5dc30ae5a0 (diff) | |
parent | 329a1085f6a67610625d3e03c3650852ae5575b6 (diff) | |
download | tk-72a4eea4cdef1059da99c87ce25a4c2db0972743.zip tk-72a4eea4cdef1059da99c87ce25a4c2db0972743.tar.gz tk-72a4eea4cdef1059da99c87ce25a4c2db0972743.tar.bz2 |
merge trunk
Diffstat (limited to 'generic/tkFrame.c')
-rw-r--r-- | generic/tkFrame.c | 272 |
1 files changed, 246 insertions, 26 deletions
diff --git a/generic/tkFrame.c b/generic/tkFrame.c index d15f9a3..0edd4c2 100644 --- a/generic/tkFrame.c +++ b/generic/tkFrame.c @@ -94,6 +94,16 @@ typedef struct { * pixels of extra space to leave above and * below child area. */ int padY; /* Integer value corresponding to padYPtr. */ + Tcl_Obj *bgimgPtr; /* Value of -backgroundimage option: specifies + * image to display on window's background, or + * NULL if none. */ + Tk_Image bgimg; /* Derived from bgimgPtr by calling + * Tk_GetImage, or NULL if bgimgPtr is + * NULL. */ + int tile; /* Whether to tile the bgimg. */ +#ifndef TK_NO_DOUBLE_BUFFERING + GC copyGC; /* GC for copying when double-buffering. */ +#endif /* TK_NO_DOUBLE_BUFFERING */ } Frame; /* @@ -219,21 +229,33 @@ static const Tk_OptionSpec commonOptSpec[] = { }; static const Tk_OptionSpec frameOptSpec[] = { + {TK_OPTION_STRING, "-backgroundimage", "backgroundImage", "BackgroundImage", + DEF_FRAME_BG_IMAGE, offsetof(Frame, bgimgPtr), -1, + TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_SYNONYM, "-bd", NULL, NULL, NULL, 0, -1, 0, "-borderwidth", 0}, + {TK_OPTION_SYNONYM, "-bgimg", NULL, NULL, + NULL, 0, -1, 0, "-backgroundimage", 0}, {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", DEF_FRAME_BORDER_WIDTH, -1, offsetof(Frame, borderWidth), 0, 0, 0}, {TK_OPTION_STRING, "-class", "class", "Class", DEF_FRAME_CLASS, -1, offsetof(Frame, className), 0, 0, 0}, {TK_OPTION_RELIEF, "-relief", "relief", "Relief", DEF_FRAME_RELIEF, -1, offsetof(Frame, relief), 0, 0, 0}, + {TK_OPTION_BOOLEAN, "-tile", "tile", "Tile", + DEF_FRAME_BG_TILE, -1, offsetof(Frame, tile), 0, 0, 0}, {TK_OPTION_END, NULL, NULL, NULL, NULL, 0, 0, 0, commonOptSpec, 0} }; static const Tk_OptionSpec toplevelOptSpec[] = { + {TK_OPTION_STRING, "-backgroundimage", "backgroundImage", "BackgroundImage", + DEF_FRAME_BG_IMAGE, offsetof(Frame, bgimgPtr), -1, + TK_OPTION_NULL_OK, 0, 0}, {TK_OPTION_SYNONYM, "-bd", NULL, NULL, NULL, 0, -1, 0, "-borderwidth", 0}, + {TK_OPTION_SYNONYM, "-bgimg", NULL, NULL, + NULL, 0, -1, 0, "-backgroundimage", 0}, {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth", DEF_FRAME_BORDER_WIDTH, -1, offsetof(Frame, borderWidth), 0, 0, 0}, {TK_OPTION_STRING, "-class", "class", "Class", @@ -246,6 +268,8 @@ static const Tk_OptionSpec toplevelOptSpec[] = { {TK_OPTION_STRING, "-screen", "screen", "Screen", DEF_TOPLEVEL_SCREEN, -1, offsetof(Frame, screenName), TK_OPTION_NULL_OK, 0, 0}, + {TK_OPTION_BOOLEAN, "-tile", "tile", "Tile", + DEF_FRAME_BG_TILE, -1, offsetof(Frame, tile), 0, 0, 0}, {TK_OPTION_STRING, "-use", "use", "Use", DEF_TOPLEVEL_USE, -1, offsetof(Frame, useThis), TK_OPTION_NULL_OK, 0, 0}, @@ -311,6 +335,12 @@ static int CreateFrame(ClientData clientData, Tcl_Interp *interp, static void DestroyFrame(void *memPtr); static void DestroyFramePartly(Frame *framePtr); static void DisplayFrame(ClientData clientData); +static void DrawFrameBackground(Tk_Window tkwin, Pixmap pixmap, + int highlightWidth, int borderWidth, + Tk_Image bgimg, int bgtile); +static void FrameBgImageProc(ClientData clientData, + int x, int y, int width, int height, + int imgWidth, int imgHeight); static void FrameCmdDeletedProc(ClientData clientData); static void FrameEventProc(ClientData clientData, XEvent *eventPtr); @@ -870,9 +900,17 @@ DestroyFrame( Tk_FreeGC(framePtr->display, labelframePtr->textGC); } } +#ifndef TK_NO_DOUBLE_BUFFERING + if (framePtr->copyGC != NULL) { + Tk_FreeGC(framePtr->display, framePtr->copyGC); + } +#endif /* TK_NO_DOUBLE_BUFFERING */ if (framePtr->colormap != None) { Tk_FreeColormap(framePtr->display, framePtr->colormap); } + if (framePtr->bgimg) { + Tk_FreeImage(framePtr->bgimg); + } ckfree(framePtr); } @@ -947,6 +985,7 @@ ConfigureFrame( char *oldMenuName; Tk_Window oldWindow = NULL; Labelframe *labelframePtr = (Labelframe *) framePtr; + Tk_Image image = NULL; /* * Need the old menubar name for the menu code to delete it. @@ -970,6 +1009,20 @@ ConfigureFrame( } return TCL_ERROR; } + + if (framePtr->bgimgPtr) { + image = Tk_GetImage(interp, framePtr->tkwin, + Tcl_GetString(framePtr->bgimgPtr), FrameBgImageProc, framePtr); + if (image == NULL) { + Tk_RestoreSavedOptions(&savedOptions); + return TCL_ERROR; + } + } + if (framePtr->bgimg) { + Tk_FreeImage(framePtr->bgimg); + } + framePtr->bgimg = image; + Tk_FreeSavedOptions(&savedOptions); /* @@ -1111,6 +1164,15 @@ FrameWorldChanged( anyWindowLabel = (framePtr->type == TYPE_LABELFRAME) && (labelframePtr->labelWin != NULL); +#ifndef TK_NO_DOUBLE_BUFFERING + gcValues.graphics_exposures = False; + gc = Tk_GetGC(tkwin, GCGraphicsExposures, &gcValues); + if (framePtr->copyGC != NULL) { + Tk_FreeGC(framePtr->display, framePtr->copyGC); + } + framePtr->copyGC = gc; +#endif /* TK_NO_DOUBLE_BUFFERING */ + if (framePtr->type == TYPE_LABELFRAME) { /* * The textGC is needed even in the labelWin case, so it's always @@ -1455,6 +1517,20 @@ DisplayFrame( return; } +#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(framePtr->display, Tk_WindowId(tkwin), + Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); +#else + pixmap = Tk_WindowId(tkwin); +#endif /* TK_NO_DOUBLE_BUFFERING */ + if (framePtr->type != TYPE_LABELFRAME) { /* * Pass to platform specific draw function. In general, it just draws @@ -1462,8 +1538,12 @@ DisplayFrame( */ noLabel: - TkpDrawFrame(tkwin, framePtr->border, hlWidth, + TkpDrawFrameEx(tkwin, pixmap, framePtr->border, hlWidth, framePtr->borderWidth, framePtr->relief); + if (framePtr->bgimg) { + DrawFrameBackground(tkwin, pixmap, hlWidth, framePtr->borderWidth, + framePtr->bgimg, framePtr->tile); + } } else { Labelframe *labelframePtr = (Labelframe *) framePtr; @@ -1472,20 +1552,6 @@ DisplayFrame( 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(framePtr->display, Tk_WindowId(tkwin), - Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin)); -#else - pixmap = Tk_WindowId(tkwin); -#endif /* TK_NO_DOUBLE_BUFFERING */ - /* * Clear the pixmap. */ @@ -1597,22 +1663,54 @@ DisplayFrame( labelframePtr->labelBox.height); } } + } #ifndef TK_NO_DOUBLE_BUFFERING - /* - * Everything's been redisplayed; now copy the pixmap onto the screen - * and free up the pixmap. - */ + /* + * Everything's been redisplayed; now copy the pixmap onto the screen and + * free up the pixmap. + */ - XCopyArea(framePtr->display, pixmap, Tk_WindowId(tkwin), - labelframePtr->textGC, hlWidth, hlWidth, - (unsigned) (Tk_Width(tkwin) - 2 * hlWidth), - (unsigned) (Tk_Height(tkwin) - 2 * hlWidth), - hlWidth, hlWidth); - Tk_FreePixmap(framePtr->display, pixmap); + XCopyArea(framePtr->display, pixmap, Tk_WindowId(tkwin), + framePtr->copyGC, hlWidth, hlWidth, + (unsigned) (Tk_Width(tkwin) - 2 * hlWidth), + (unsigned) (Tk_Height(tkwin) - 2 * hlWidth), + hlWidth, hlWidth); + Tk_FreePixmap(framePtr->display, pixmap); #endif /* TK_NO_DOUBLE_BUFFERING */ - } +} + +/* + *---------------------------------------------------------------------- + * + * TkpDrawFrame -- + * + * This procedure draws the rectangular frame area. + * + * Results: + * None. + * + * Side effects: + * Draws inside the tkwin area. + * + *---------------------------------------------------------------------- + */ +void +TkpDrawFrame( + Tk_Window tkwin, + Tk_3DBorder border, + int highlightWidth, + int borderWidth, + int relief) +{ + /* + * Legacy shim to allow for external callers. Internal ones use + * non-exposed TkpDrawFrameEx directly so they can use double-buffering. + */ + + TkpDrawFrameEx(tkwin, Tk_WindowId(tkwin), border, + highlightWidth, borderWidth, relief); } /* @@ -2032,6 +2130,128 @@ TkToplevelWindowForCommand( } /* + *---------------------------------------------------------------------- + * + * FrameBgImageProc -- + * + * This function is invoked by the image code whenever the manager for an + * image does something that affects the size or contents of an image + * displayed on a frame's background. + * + * Results: + * None. + * + * Side effects: + * Arranges for the button to get redisplayed. + * + *---------------------------------------------------------------------- + */ + +static void +FrameBgImageProc( + ClientData clientData, /* Pointer to widget record. */ + int x, int y, /* Upper left pixel (within image) that must + * be redisplayed. */ + int width, int height, /* Dimensions of area to redisplay (might be + * <= 0). */ + int imgWidth, int imgHeight)/* New dimensions of image. */ +{ + register Frame *framePtr = clientData; + + /* + * Changing the background image never alters the dimensions of the frame. + */ + + if (framePtr->tkwin && Tk_IsMapped(framePtr->tkwin) && + !(framePtr->flags & REDRAW_PENDING)) { + Tcl_DoWhenIdle(DisplayFrame, framePtr); + framePtr->flags |= REDRAW_PENDING; + } +} + +/* + *---------------------------------------------------------------------- + * + * DrawFrameBackground -- + * + * This function draws the background image of a rectangular frame area. + * + * Results: + * None. + * + * Side effects: + * Draws inside the tkwin area. + * + *---------------------------------------------------------------------- + */ + +static void +DrawFrameBackground( + Tk_Window tkwin, + Pixmap pixmap, + int highlightWidth, + int borderWidth, + Tk_Image bgimg, + int bgtile) +{ + int width, height; /* Area to paint on. */ + int imageWidth, imageHeight; /* Dimensions of image. */ + const int bw = highlightWidth + borderWidth; + + Tk_SizeOfImage(bgimg, &imageWidth, &imageHeight); + width = Tk_Width(tkwin) - 2*bw; + height = Tk_Height(tkwin) - 2*bw; + + if (bgtile) { + /* + * Draw the image tiled in the widget (inside the border). + */ + + int x, y; + + for (x = bw; x - bw < width; x += imageWidth) { + int w = imageWidth; + if (x - bw + imageWidth > width) { + w = (width + bw) - x; + } + for (y = bw; y < height + bw; y += imageHeight) { + int h = imageHeight; + if (y - bw + imageHeight > height) { + h = (height + bw) - y; + } + Tk_RedrawImage(bgimg, 0, 0, w, h, pixmap, x, y); + } + } + } else { + /* + * Draw the image centred in the widget (inside the border). + */ + + int x, y, xOff, yOff, w, h; + + if (width > imageWidth) { + x = 0; + xOff = (Tk_Width(tkwin) - imageWidth) / 2; + w = imageWidth; + } else { + x = (imageWidth - width) / 2; + xOff = bw; + w = width; + } + if (height > imageHeight) { + y = 0; + yOff = (Tk_Height(tkwin) - imageHeight) / 2; + h = imageHeight; + } else { + y = (imageHeight - height) / 2; + yOff = bw; + h = height; + } + Tk_RedrawImage(bgimg, x, y, w, h, pixmap, xOff, yOff); + } +} + +/* * Local Variables: * mode: c * c-basic-offset: 4 |