diff options
Diffstat (limited to 'unix/tkUnixDraw.c')
-rw-r--r-- | unix/tkUnixDraw.c | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/unix/tkUnixDraw.c b/unix/tkUnixDraw.c new file mode 100644 index 0000000..65bf2e4 --- /dev/null +++ b/unix/tkUnixDraw.c @@ -0,0 +1,171 @@ +/* + * tkUnixDraw.c -- + * + * This file contains X specific drawing routines. + * + * Copyright (c) 1995 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tkUnixDraw.c 1.9 97/03/21 11:16:18 + */ + +#include "tkPort.h" +#include "tkInt.h" + +/* + * The following structure is used to pass information to + * ScrollRestrictProc from TkScrollWindow. + */ + +typedef struct ScrollInfo { + int done; /* Flag is 0 until filtering is done. */ + Display *display; /* Display to filter. */ + Window window; /* Window to filter. */ + TkRegion region; /* Region into which damage is accumulated. */ + int dx, dy; /* Amount by which window was shifted. */ +} ScrollInfo; + +/* + * Forward declarations for procedures declared later in this file: + */ + +static Tk_RestrictAction ScrollRestrictProc _ANSI_ARGS_(( + ClientData arg, XEvent *eventPtr)); + +/* + *---------------------------------------------------------------------- + * + * TkScrollWindow -- + * + * Scroll a rectangle of the specified window and accumulate + * damage information in the specified Region. + * + * Results: + * Returns 0 if no damage additional damage was generated. Sets + * damageRgn to contain the damaged areas and returns 1 if + * GraphicsExpose events were detected. + * + * Side effects: + * Scrolls the bits in the window and enters the event loop + * looking for damage events. + * + *---------------------------------------------------------------------- + */ + +int +TkScrollWindow(tkwin, gc, x, y, width, height, dx, dy, damageRgn) + Tk_Window tkwin; /* The window to be scrolled. */ + GC gc; /* GC for window to be scrolled. */ + int x, y, width, height; /* Position rectangle to be scrolled. */ + int dx, dy; /* Distance rectangle should be moved. */ + TkRegion damageRgn; /* Region to accumulate damage in. */ +{ + Tk_RestrictProc *oldProc; + ClientData oldArg, dummy; + ScrollInfo info; + + XCopyArea(Tk_Display(tkwin), Tk_WindowId(tkwin), Tk_WindowId(tkwin), gc, + x, y, (unsigned int) width, (unsigned int) height, x + dx, y + dy); + + info.done = 0; + info.window = Tk_WindowId(tkwin); + info.display = Tk_Display(tkwin); + info.region = damageRgn; + info.dx = dx; + info.dy = dy; + + /* + * Sync the event stream so all of the expose events will be on the + * Tk event queue before we start filtering. This avoids busy waiting + * while we filter events. + */ + + TkpSync(info.display); + oldProc = Tk_RestrictEvents(ScrollRestrictProc, (ClientData) &info, + &oldArg); + while (!info.done) { + Tcl_ServiceEvent(TCL_WINDOW_EVENTS); + } + Tk_RestrictEvents(oldProc, oldArg, &dummy); + + return XEmptyRegion((Region) damageRgn) ? 0 : 1; +} + +/* + *---------------------------------------------------------------------- + * + * ScrollRestrictProc -- + * + * A Tk_RestrictProc used by TkScrollWindow to gather up Expose + * information into a single damage region. It accumulates damage + * events on the specified window until a NoExpose or the last + * GraphicsExpose event is detected. + * + * Results: + * None. + * + * Side effects: + * Discards Expose events after accumulating damage information + * for a particular window. + * + *---------------------------------------------------------------------- + */ + +static Tk_RestrictAction +ScrollRestrictProc(arg, eventPtr) + ClientData arg; + XEvent *eventPtr; +{ + ScrollInfo *info = (ScrollInfo *) arg; + XRectangle rect; + + /* + * Defer events which aren't for the specified window. + */ + + if (info->done || (eventPtr->xany.display != info->display) + || (eventPtr->xany.window != info->window)) { + return TK_DEFER_EVENT; + } + + if (eventPtr->type == NoExpose) { + info->done = 1; + } else if (eventPtr->type == GraphicsExpose) { + rect.x = eventPtr->xgraphicsexpose.x; + rect.y = eventPtr->xgraphicsexpose.y; + rect.width = eventPtr->xgraphicsexpose.width; + rect.height = eventPtr->xgraphicsexpose.height; + XUnionRectWithRegion(&rect, (Region) info->region, + (Region) info->region); + + if (eventPtr->xgraphicsexpose.count == 0) { + info->done = 1; + } + } else if (eventPtr->type == Expose) { + + /* + * This case is tricky. This event was already queued before + * the XCopyArea was issued. If this area overlaps the area + * being copied, then some of the copied area may be invalid. + * The easiest way to handle this case is to mark both the + * original area and the shifted area as damaged. + */ + + rect.x = eventPtr->xexpose.x; + rect.y = eventPtr->xexpose.y; + rect.width = eventPtr->xexpose.width; + rect.height = eventPtr->xexpose.height; + XUnionRectWithRegion(&rect, (Region) info->region, + (Region) info->region); + rect.x += info->dx; + rect.y += info->dy; + XUnionRectWithRegion(&rect, (Region) info->region, + (Region) info->region); + } else { + return TK_DEFER_EVENT; + } + return TK_DISCARD_EVENT; +} + |