/* * 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. * * RCS: @(#) $Id: tkUnixDraw.c,v 1.6 2000/07/20 21:38:28 ericm Exp $ */ #include "tkPort.h" #include "tkInt.h" #if !defined(__WIN32__) && !defined(MAC_TCL) #include "tkUnixInt.h" #endif /* * 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); if (XEmptyRegion((Region) damageRgn)) { return 0; } else { return 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; } /* *---------------------------------------------------------------------- * * TkpDrawHighlightBorder -- * * This procedure draws a rectangular ring around the outside of * a widget to indicate that it has received the input focus. * * On Unix, we just draw the simple inset ring. On other sytems, * e.g. the Mac, the focus ring is a little more complicated, so we * need this abstraction. * * Results: * None. * * Side effects: * A rectangle "width" pixels wide is drawn in "drawable", * corresponding to the outer area of "tkwin". * *---------------------------------------------------------------------- */ void TkpDrawHighlightBorder(tkwin, fgGC, bgGC, highlightWidth, drawable) Tk_Window tkwin; GC fgGC; GC bgGC; int highlightWidth; Drawable drawable; { TkDrawInsetFocusHighlight(tkwin, fgGC, highlightWidth, drawable, 0); }