1 /* DBWhighlights.c -
2 *
3 * This file contains routines that allow the highlight plane
4 * to be used to display additional things besides the box.
5 * The routines coordinate all the clients that have highlights
6 * to display so that when one of them updates its highlights
7 * it doesn't trash the others' highlights.
8 *
9 * *********************************************************************
10 * * Copyright (C) 1985, 1990 Regents of the University of California. *
11 * * Permission to use, copy, modify, and distribute this *
12 * * software and its documentation for any purpose and without *
13 * * fee is hereby granted, provided that the above copyright *
14 * * notice appear in all copies. The University of California *
15 * * makes no representations about the suitability of this *
16 * * software for any purpose. It is provided "as is" without *
17 * * express or implied warranty. Export of this software outside *
18 * * of the United States of America may require an export license. *
19 * *********************************************************************
20 */
21
22 #ifndef lint
23 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/dbwind/DBWhlights.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
24 #endif /* not lint */
25
26 #include <stdio.h>
27
28 #include "utils/magic.h"
29 #include "utils/geometry.h"
30 #include "utils/styles.h"
31 #include "tiles/tile.h"
32 #include "utils/hash.h"
33 #include "database/database.h"
34 #include "windows/windows.h"
35 #include "graphics/graphics.h"
36 #include "dbwind/dbwind.h"
37 #include "textio/textio.h"
38 #include "graphics/graphicsInt.h"
39
40 #define WINDOW_DEF(w) (((CellUse *)(w->w_surfaceID))->cu_def)
41
42 /* The array below is used to hold the addresses of redisplay
43 * procedures for each of the highlight clients. Whenever
44 * highlights must be redisplayed, each highlight client
45 * is invoked for each database window.
46 */
47
48 #define MAXCLIENTS 10
49 static int (*(dbwhlClients[MAXCLIENTS]))();
50
51 /*
52 * ----------------------------------------------------------------------------
53 *
54 * DBWHLAddClient --
55 *
56 * This procedure is used to add another client to those
57 * that are displaying highlights. The redisplay procedure
58 * passed in by the client will be invoked in the following
59 * way:
60 * int
61 * redisplayProc(window, plane)
62 * MagWindow *window;
63 * Plane *plane;
64 * {
65 * }
66 * The procedure is invoked once for each window that contains
67 * database information (and potentially has highlights). The
68 * window has been locked via GrLock() before the proc is called,
69 * and the clipping area has already been set up. The procedure
70 * is given a pointer to the window, and a pointer to a plane.
71 * The plane contains non-space tiles over all areas where highlight
72 * information needs to be redrawn (all of these areas have had
73 * their highlight information erased). The client should redraw
74 * any of its highlights that touch any non-space areas.
75 *
76 * Results:
77 * None.
78 *
79 * Side effects:
80 * The client is added to our list of clients.
81 *
82 * ----------------------------------------------------------------------------
83 */
84
85 void
86 DBWHLAddClient(redisplayProc)
87 int (*redisplayProc)(); /* Procedure to call during redisplays. */
88 {
89 int i;
90 for (i = 0; i < MAXCLIENTS; i++)
91 {
92 if (dbwhlClients[i] == NULL)
93 {
94 dbwhlClients[i] = redisplayProc;
95 return;
96 }
97 }
98 TxError("Magic error: ran out of space in highlight client table.\n");
99 TxError("Tell your system maintainer to enlarge the table.\n");
100 }
101
102 /*
103 * ----------------------------------------------------------------------------
104 *
105 * DBWHLRemoveClient --
106 *
107 * This just removes a client from the list of those that we
108 * know about.
109 *
110 * Results:
111 * None.
112 *
113 * Side effects:
114 * The given redisplay procedure will no longer be invoked
115 * during redisplays.
116 *
117 * ----------------------------------------------------------------------------
118 */
119
120 void
121 DBWHLRemoveClient(redisplayProc)
122 int (*redisplayProc)(); /* A redisplay procedure. This
123 * procedure must previously have been
124 * passed in to DBWHLAddClient.
125 */
126 {
127 int i;
128 for (i = 0; i < MAXCLIENTS; i += 1)
129 {
130 if (dbwhlClients[i] == redisplayProc)
131 {
132 dbwhlClients[i] = NULL;
133 return;
134 }
135 }
136 ASSERT(FALSE, "DBWHLRemoveClient");
137 }
138
139 /*
140 * ----------------------------------------------------------------------------
141 *
142 * DBWHLRedraw --
143 *
144 * This procedure is invoked to redisplay highlights. The
145 * clients that manage highlights are free to draw on the screen
146 * at will. But if a client ever erases highlight information, it
147 * must call this procedure so that the other clients can redraw
148 * any of their highlights that might have been erased. This
149 * procedure records what has changed. The information isn't actually
150 * redrawn until the next time WindUpdate is called. This is done
151 * to avoid repeated redraws when several pieces of highlights change
152 * in the same area at the same time.
153 *
154 * Results:
155 * None.
156 *
157 * Side effects:
158 * Information is recorded so that specified area will have its
159 * highlight information erased and redrawn the next time that
160 * WindUpdate is called.
161 *
162 * ----------------------------------------------------------------------------
163 */
164
165 void
DBWHLRedraw(rootDef,area,erase)166 DBWHLRedraw(rootDef, area, erase)
167 CellDef *rootDef; /* Highlight information will be redrawn in
168 * all windows for which this is the root
169 * cell definition.
170 */
171 Rect *area; /* The area over which to redraw. Highlights
172 * will be redrawn in this area plus enough
173 * surrounding area to catch degenerate boxes
174 * (drawn as crosses) and labels that may
175 * stick out from their attachment points.
176 */
177 bool erase; /* TRUE means we should erase are before
178 * redrawing it. FALSE means that either the
179 * client has erased the area, or there's no
180 * need to erase it because all that's
181 * happening is to add new information to the
182 * display.
183 */
184 {
185 extern CellDef *dbwhlDef;
186 extern bool dbwhlErase;
187 extern int dbwhlRedrawFunc();
188 Rect ourArea;
189
190 dbwhlDef = rootDef; /* Must pass to search function. */
191 dbwhlErase = erase;
192
193 /* If we're passed a NULL area, expand it by one unit in both
194 * directions so that we're certain to have non-zero area.
195 * Otherwise the various search procedures have big troubles.
196 */
197
198 ourArea = *area;
199 if (ourArea.r_xbot >= ourArea.r_xtop)
200 {
201 ourArea.r_xtop = ourArea.r_xbot + 1;
202 ourArea.r_xbot--;
203 }
204 if (ourArea.r_ybot >= ourArea.r_ytop)
205 {
206 ourArea.r_ytop = ourArea.r_ybot + 1;
207 ourArea.r_ybot--;
208 }
209 (void) WindSearch(DBWclientID, (ClientData) NULL, &ourArea,
210 dbwhlRedrawFunc, (ClientData) &ourArea);
211 }
212
213 CellDef *dbwhlDef;
214 bool dbwhlErase;
215
216 /* This procedure records the area to be erased (if any) and the
217 * area to be redisplayed (which is larger than the area to be
218 * erased).
219 */
220
221 int
dbwhlRedrawFunc(window,area)222 dbwhlRedrawFunc(window, area)
223 MagWindow *window; /* Window to redraw. */
224 Rect *area; /* Passed as client data. */
225 {
226 Rect erase, expand, redraw;
227 DBWclientRec *crec = (DBWclientRec *) window->w_clientData;
228
229 if (WINDOW_DEF(window) != dbwhlDef) return 0;
230
231 /* The area that we erase must be large enough to include material
232 * that sticks out from the area of the highlights. There are two
233 * ways that material sticks out: (a) zero-size boxes are drawn as
234 * crosses, and the crosses stick outside of the box's area; (b)
235 * labels are attached to points or rectangles, but the text usually
236 * extends far beyond the attachment point.
237 */
238
239 WindSurfaceToScreen(window, area, &erase);
240 expand = GrCrossRect;
241 (void) GeoInclude(&crec->dbw_expandAmounts, &expand);
242
243 if (dbwhlErase)
244 {
245 bool needErase = TRUE;
246
247 erase.r_xbot += expand.r_xbot;
248 erase.r_ybot += expand.r_ybot;
249 erase.r_xtop += expand.r_xtop;
250 erase.r_ytop += expand.r_ytop;
251
252 /* On some displays (e.g. black-and-white ones), highlights use
253 * the same color planes as other information. If this is the
254 * case, redisplay everything (this will redisplay highlights too,
255 * so there's nothing additional to do here).
256 *
257 * This is also the case if we use backing store but the backing
258 * store has been removed due to becoming invalid, such as when
259 * an attempt is made to redraw into an obscured or unmapped
260 * window.
261 */
262
263 if (((GrGetBackingStorePtr == NULL) &&
264 ((GrStyleTable[STYLE_ERASEHIGHLIGHTS].mask &
265 GrStyleTable[STYLE_ERASEALLBUTTOOLS].mask) != 0)) ||
266 ((GrGetBackingStorePtr != NULL) &&
267 window->w_backingStore == (ClientData)NULL))
268
269 {
270 DBWAreaChanged(dbwhlDef, area, crec->dbw_bitmask,
271 (TileTypeBitMask *) NULL);
272 WindAnotherUpdatePlease = TRUE;
273 return 0;
274 }
275
276 DBPaintPlane(crec->dbw_hlErase, &erase,
277 DBStdPaintTbl(TT_ERROR_P, PL_DRC_ERROR),
278 (PaintUndoInfo *) NULL);
279 }
280
281 /* The area whose highlights must be redrawn is the area erased, but
282 * it must be expanded again to include the fact that we may have
283 * just erased a piece of a label that stuck out from some other point.
284 * This area gets translated back into database coordinates and saved
285 * in dbwhlRedrawPlane, but first it gets expanded by one more unit just to
286 * eliminate edge effects: all impacted highlights are now guaranteed
287 * to OVERLAP an area in dbwhlRedrawPlane, not just touch.
288 */
289
290 erase.r_xbot -= expand.r_xtop;
291 erase.r_ybot -= expand.r_ytop;
292 erase.r_xtop -= expand.r_xbot;
293 erase.r_ytop -= expand.r_ybot;
294 (void) WindScreenToSurface(window, &erase, &redraw);
295 GEO_EXPAND(&redraw, 1, &redraw);
296 DBPaintPlane(crec->dbw_hlRedraw, &redraw,
297 DBStdPaintTbl(TT_ERROR_P, PL_DRC_ERROR),
298 (PaintUndoInfo *) NULL);
299 return 0;
300 }
301
302 /*
303 * ----------------------------------------------------------------------------
304 *
305 * DBWHLRedrawPrepWindow --
306 *
307 * This procedure is similar to DBWHLRedraw. However, it is
308 * intended to indicate areas to redraw highlights for a
309 * single window only. This is required by the backing store
310 * mechanism when a window is scrolled, and the part of the
311 * window area that remains visible is refreshed from backing
312 * store. This area does not need to have layout redrawn, but
313 * does need to have all hightlights redrawn, since the
314 * highlights aren't saved in backing store.
315 *
316 * Results:
317 * None.
318 *
319 * Side effects:
320 * Information is recorded so that specified area will have its
321 * highlight information erased and redrawn the next time that
322 * WindUpdate is called.
323 *
324 * ----------------------------------------------------------------------------
325 */
326
327 void
DBWHLRedrawPrepWindow(MagWindow * window,Rect * area)328 DBWHLRedrawPrepWindow(MagWindow *window, Rect *area)
329 {
330 extern CellDef *dbwhlDef;
331 extern bool dbwhlErase;
332 extern int dbwhlRedrawFunc();
333
334 dbwhlDef = WINDOW_DEF(window);
335 dbwhlErase = FALSE;
336 dbwhlRedrawFunc(window, area);
337 }
338
339 /*
340 * ----------------------------------------------------------------------------
341 *
342 * DBWHLRedrawWind --
343 *
344 * This procedure is called to redraw highlight information in a
345 * particular window. It is normally called as part of WindUpdate
346 * by DBWHLUpdate. The areas to be erased and redrawn must already
347 * be present in the clientData record.
348 *
349 * Results:
350 * Always returns 0 to keep searches from aborting.
351 *
352 * Side effects:
353 * The plane dbw_hlPlane indicates which highlight areas must be
354 * redrawn for this window. Any highlights that touch any of these
355 * areas are redrawn. The plane is then cleared.
356 *
357 * ----------------------------------------------------------------------------
358 */
359
360 int
DBWHLRedrawWind(window)361 DBWHLRedrawWind(window)
362 MagWindow *window; /* Window in which to redraw highlights. */
363 {
364 int i;
365 DBWclientRec *crec;
366 extern int dbwhlEraseFunc(); /* Forward reference. */
367
368 GrLock(window, TRUE);
369 crec = (DBWclientRec *) window->w_clientData;
370
371 /* First erase, then redraw: */
372
373 (void) DBSrPaintArea((Tile *) NULL, crec->dbw_hlErase, &TiPlaneRect,
374 &DBAllButSpaceBits, dbwhlEraseFunc, (ClientData)window);
375
376 /* Now call each client to redraw its own stuff. */
377
378 for (i = 0; i < MAXCLIENTS; i += 1)
379 {
380 if (dbwhlClients[i] == NULL) continue;
381 (void) (*(dbwhlClients[i]))(window, crec->dbw_hlRedraw);
382 }
383
384 DBClearPaintPlane(crec->dbw_hlErase);
385 DBClearPaintPlane(crec->dbw_hlRedraw);
386 GrUnlock(window);
387 return 0;
388 }
389
390 /* The procedure below erases highlight information for each tile that
391 * it's called with. Returns 0 to keep the search from aborting.
392 */
393
394 int
dbwhlEraseFunc(tile,window)395 dbwhlEraseFunc(tile, window)
396 Tile *tile; /* Tile describing area to be erased. */
397 MagWindow *window; /* Window that is being altered. */
398 {
399 Rect area;
400 bool needErase = TRUE;
401
402 TiToRect(tile, &area);
403
404 /* If the graphics package allows highlight areas to be */
405 /* cached in backing store, then we do a quick check to */
406 /* see if we can just copy the background back in and */
407 /* avoid repainting. */
408
409 if (GrGetBackingStorePtr != NULL)
410 if ((*GrGetBackingStorePtr)(window, &area))
411 needErase = FALSE;
412
413 if (needErase) GrClipBox(&area, STYLE_ERASEHIGHLIGHTS);
414 return 0;
415 }
416
417 /*
418 * ----------------------------------------------------------------------------
419 * DBWHLUpdate --
420 *
421 * This procedure is called once as part of each WindUpdate call.
422 * It checks for any windows that have highlight information that
423 * needs to be redrawn
424 *
425 * Results:
426 * None.
427 *
428 * Side effects:
429 * Highlights get redrawn on the screen.
430 * ----------------------------------------------------------------------------
431 */
432
433 void
DBWHLUpdate()434 DBWHLUpdate()
435 {
436 extern int dbwhlUpdateWindowFunc();
437
438 /* Scan through all of the layout windows and redraw their
439 * highlight information, if necessary.
440 */
441
442 (void) WindSearch(DBWclientID, (ClientData) NULL, (Rect *) NULL,
443 DBWHLRedrawWind, (ClientData) NULL);
444 }
445