/*1* tkUnixDraw.c --2*3* This file contains X specific drawing routines.4*5* Copyright (c) 1995 Sun Microsystems, Inc.6*7* See the file "license.terms" for information on usage and redistribution8* of this file, and for a DISCLAIMER OF ALL WARRANTIES.9*10* SCCS: @(#) tkUnixDraw.c 1.7 96/02/15 18:55:2611*/1213#include "tkInt.h"1415/*16* The following structure is used to pass information to17* ScrollRestrictProc from TkScrollWindow.18*/1920typedef struct ScrollInfo {21int done; /* Flag is 0 until filtering is done. */22Display *display; /* Display to filter. */23Window window; /* Window to filter. */24TkRegion region; /* Region into which damage is accumulated. */25int dx, dy; /* Amount by which window was shifted. */26} ScrollInfo;2728/*29* Forward declarations for procedures declared later in this file:30*/3132static Tk_RestrictAction ScrollRestrictProc _ANSI_ARGS_((33ClientData arg, XEvent *eventPtr));3435/*36*----------------------------------------------------------------------37*38* TkScrollWindow --39*40* Scroll a rectangle of the specified window and accumulate41* damage information in the specified Region.42*43* Results:44* Returns 0 if no damage additional damage was generated. Sets45* damageRgn to contain the damaged areas and returns 1 if46* GraphicsExpose events were detected.47*48* Side effects:49* Scrolls the bits in the window and enters the event loop50* looking for damage events.51*52*----------------------------------------------------------------------53*/5455int56TkScrollWindow(tkwin, gc, x, y, width, height, dx, dy, damageRgn)57Tk_Window tkwin; /* The window to be scrolled. */58GC gc; /* GC for window to be scrolled. */59int x, y, width, height; /* Position rectangle to be scrolled. */60int dx, dy; /* Distance rectangle should be moved. */61TkRegion damageRgn; /* Region to accumulate damage in. */62{63Tk_RestrictProc *oldProc;64ClientData oldArg, dummy;65ScrollInfo info;6667XCopyArea(Tk_Display(tkwin), Tk_WindowId(tkwin), Tk_WindowId(tkwin), gc,68x, y, (unsigned int) width, (unsigned int) height, x + dx, y + dy);6970info.done = 0;71info.window = Tk_WindowId(tkwin);72info.display = Tk_Display(tkwin);73info.region = damageRgn;74info.dx = dx;75info.dy = dy;7677/*78* Sync the event stream so all of the expose events will be on the79* X event queue before we start filtering. This avoids busy waiting80* while we filter events.81*/8283XSync(info.display, False);84oldProc = Tk_RestrictEvents(ScrollRestrictProc, (ClientData) &info,85&oldArg);86while (!info.done) {87Tcl_DoOneEvent(TCL_WINDOW_EVENTS|TCL_DONT_WAIT);88}89Tk_RestrictEvents(oldProc, oldArg, &dummy);9091return XEmptyRegion((Region) damageRgn) ? 0 : 1;92}9394/*95*----------------------------------------------------------------------96*97* ScrollRestrictProc --98*99* A Tk_RestrictProc used by TkScrollWindow to gather up Expose100* information into a single damage region. It accumulates damage101* events on the specified window until a NoExpose or the last102* GraphicsExpose event is detected.103*104* Results:105* None.106*107* Side effects:108* Discards Expose events after accumulating damage information109* for a particular window.110*111*----------------------------------------------------------------------112*/113114static Tk_RestrictAction115ScrollRestrictProc(arg, eventPtr)116ClientData arg;117XEvent *eventPtr;118{119ScrollInfo *info = (ScrollInfo *) arg;120XRectangle rect;121122/*123* Defer events which aren't for the specified window.124*/125126if (info->done || (eventPtr->xany.display != info->display)127|| (eventPtr->xany.window != info->window)) {128return TK_DEFER_EVENT;129}130131if (eventPtr->type == NoExpose) {132info->done = 1;133} else if (eventPtr->type == GraphicsExpose) {134rect.x = eventPtr->xgraphicsexpose.x;135rect.y = eventPtr->xgraphicsexpose.y;136rect.width = eventPtr->xgraphicsexpose.width;137rect.height = eventPtr->xgraphicsexpose.height;138XUnionRectWithRegion(&rect, (Region) info->region,139(Region) info->region);140141if (eventPtr->xgraphicsexpose.count == 0) {142info->done = 1;143}144} else if (eventPtr->type == Expose) {145146/*147* This case is tricky. This event was already queued before148* the XCopyArea was issued. If this area overlaps the area149* being copied, then some of the copied area may be invalid.150* The easiest way to handle this case is to mark both the151* original area and the shifted area as damaged.152*/153154rect.x = eventPtr->xexpose.x;155rect.y = eventPtr->xexpose.y;156rect.width = eventPtr->xexpose.width;157rect.height = eventPtr->xexpose.height;158XUnionRectWithRegion(&rect, (Region) info->region,159(Region) info->region);160rect.x += info->dx;161rect.y += info->dy;162XUnionRectWithRegion(&rect, (Region) info->region,163(Region) info->region);164} else {165return TK_DEFER_EVENT;166}167return TK_DISCARD_EVENT;168}169170171172