1/* 2 * tkUnixDraw.c -- 3 * 4 * This file contains X specific drawing routines. 5 * 6 * Copyright (c) 1995 Sun Microsystems, Inc. 7 * 8 * See the file "license.terms" for information on usage and redistribution 9 * of this file, and for a DISCLAIMER OF ALL WARRANTIES. 10 * 11 * RCS: @(#) $Id: tkUnixDraw.c,v 1.6.8.1 2005/07/28 04:57:38 hobbs Exp $ 12 */ 13 14#include "tkPort.h" 15#include "tkInt.h" 16 17#if !defined(__WIN32__) && !defined(MAC_TCL) 18#include "tkUnixInt.h" 19#endif 20 21/* 22 * The following structure is used to pass information to 23 * ScrollRestrictProc from TkScrollWindow. 24 */ 25 26typedef struct ScrollInfo { 27 int done; /* Flag is 0 until filtering is done. */ 28 Display *display; /* Display to filter. */ 29 Window window; /* Window to filter. */ 30 TkRegion region; /* Region into which damage is accumulated. */ 31 int dx, dy; /* Amount by which window was shifted. */ 32} ScrollInfo; 33 34/* 35 * Forward declarations for procedures declared later in this file: 36 */ 37 38static Tk_RestrictAction ScrollRestrictProc _ANSI_ARGS_(( 39 ClientData arg, XEvent *eventPtr)); 40 41/* 42 *---------------------------------------------------------------------- 43 * 44 * TkScrollWindow -- 45 * 46 * Scroll a rectangle of the specified window and accumulate 47 * damage information in the specified Region. 48 * 49 * Results: 50 * Returns 0 if no damage additional damage was generated. Sets 51 * damageRgn to contain the damaged areas and returns 1 if 52 * GraphicsExpose events were detected. 53 * 54 * Side effects: 55 * Scrolls the bits in the window and enters the event loop 56 * looking for damage events. 57 * 58 *---------------------------------------------------------------------- 59 */ 60 61int 62TkScrollWindow(tkwin, gc, x, y, width, height, dx, dy, damageRgn) 63 Tk_Window tkwin; /* The window to be scrolled. */ 64 GC gc; /* GC for window to be scrolled. */ 65 int x, y, width, height; /* Position rectangle to be scrolled. */ 66 int dx, dy; /* Distance rectangle should be moved. */ 67 TkRegion damageRgn; /* Region to accumulate damage in. */ 68{ 69 Tk_RestrictProc *oldProc; 70 ClientData oldArg, dummy; 71 ScrollInfo info; 72 73 XCopyArea(Tk_Display(tkwin), Tk_WindowId(tkwin), Tk_WindowId(tkwin), gc, 74 x, y, (unsigned int) width, (unsigned int) height, x + dx, y + dy); 75 76 info.done = 0; 77 info.window = Tk_WindowId(tkwin); 78 info.display = Tk_Display(tkwin); 79 info.region = damageRgn; 80 info.dx = dx; 81 info.dy = dy; 82 83 /* 84 * Sync the event stream so all of the expose events will be on the 85 * Tk event queue before we start filtering. This avoids busy waiting 86 * while we filter events. 87 */ 88 89 TkpSync(info.display); 90 oldProc = Tk_RestrictEvents(ScrollRestrictProc, (ClientData) &info, 91 &oldArg); 92 while (!info.done) { 93 Tcl_ServiceEvent(TCL_WINDOW_EVENTS); 94 } 95 Tk_RestrictEvents(oldProc, oldArg, &dummy); 96 97 if (XEmptyRegion((Region) damageRgn)) { 98 return 0; 99 } else { 100 return 1; 101 } 102} 103 104/* 105 *---------------------------------------------------------------------- 106 * 107 * ScrollRestrictProc -- 108 * 109 * A Tk_RestrictProc used by TkScrollWindow to gather up Expose 110 * information into a single damage region. It accumulates damage 111 * events on the specified window until a NoExpose or the last 112 * GraphicsExpose event is detected. 113 * 114 * Results: 115 * None. 116 * 117 * Side effects: 118 * Discards Expose events after accumulating damage information 119 * for a particular window. 120 * 121 *---------------------------------------------------------------------- 122 */ 123 124static Tk_RestrictAction 125ScrollRestrictProc(arg, eventPtr) 126 ClientData arg; 127 XEvent *eventPtr; 128{ 129 ScrollInfo *info = (ScrollInfo *) arg; 130 XRectangle rect; 131 132 /* 133 * Defer events which aren't for the specified window. 134 */ 135 136 if (info->done || (eventPtr->xany.display != info->display) 137 || (eventPtr->xany.window != info->window)) { 138 return TK_DEFER_EVENT; 139 } 140 141 if (eventPtr->type == NoExpose) { 142 info->done = 1; 143 } else if (eventPtr->type == GraphicsExpose) { 144 rect.x = eventPtr->xgraphicsexpose.x; 145 rect.y = eventPtr->xgraphicsexpose.y; 146 rect.width = eventPtr->xgraphicsexpose.width; 147 rect.height = eventPtr->xgraphicsexpose.height; 148 XUnionRectWithRegion(&rect, (Region) info->region, 149 (Region) info->region); 150 151 if (eventPtr->xgraphicsexpose.count == 0) { 152 info->done = 1; 153 } 154 } else if (eventPtr->type == Expose) { 155 156 /* 157 * This case is tricky. This event was already queued before 158 * the XCopyArea was issued. If this area overlaps the area 159 * being copied, then some of the copied area may be invalid. 160 * The easiest way to handle this case is to mark both the 161 * original area and the shifted area as damaged. 162 */ 163 164 rect.x = eventPtr->xexpose.x; 165 rect.y = eventPtr->xexpose.y; 166 rect.width = eventPtr->xexpose.width; 167 rect.height = eventPtr->xexpose.height; 168 XUnionRectWithRegion(&rect, (Region) info->region, 169 (Region) info->region); 170 rect.x += info->dx; 171 rect.y += info->dy; 172 XUnionRectWithRegion(&rect, (Region) info->region, 173 (Region) info->region); 174 } else { 175 return TK_DEFER_EVENT; 176 } 177 return TK_DISCARD_EVENT; 178} 179 180/* 181 *---------------------------------------------------------------------- 182 * 183 * TkpDrawHighlightBorder -- 184 * 185 * This procedure draws a rectangular ring around the outside of 186 * a widget to indicate that it has received the input focus. 187 * 188 * On Unix, we just draw the simple inset ring. On other sytems, 189 * e.g. the Mac, the focus ring is a little more complicated, so we 190 * need this abstraction. 191 * 192 * Results: 193 * None. 194 * 195 * Side effects: 196 * A rectangle "width" pixels wide is drawn in "drawable", 197 * corresponding to the outer area of "tkwin". 198 * 199 *---------------------------------------------------------------------- 200 */ 201 202void 203TkpDrawHighlightBorder(tkwin, fgGC, bgGC, highlightWidth, drawable) 204 Tk_Window tkwin; 205 GC fgGC; 206 GC bgGC; 207 int highlightWidth; 208 Drawable drawable; 209{ 210 TkDrawInsetFocusHighlight(tkwin, fgGC, highlightWidth, drawable, 0); 211} 212 213/* 214 *---------------------------------------------------------------------- 215 * 216 * TkpDrawFrame -- 217 * 218 * This procedure draws the rectangular frame area. 219 * 220 * Results: 221 * None. 222 * 223 * Side effects: 224 * Draws inside the tkwin area. 225 * 226 *---------------------------------------------------------------------- 227 */ 228 229void 230TkpDrawFrame (Tk_Window tkwin, Tk_3DBorder border, 231 int highlightWidth, int borderWidth, int relief) 232{ 233 Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), 234 border, highlightWidth, highlightWidth, 235 Tk_Width(tkwin) - 2 * highlightWidth, 236 Tk_Height(tkwin) - 2 * highlightWidth, 237 borderWidth, relief); 238} 239