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