magic/windows/windDisp.c

985 lines
28 KiB
C

/* windDisplay.c -
*
* Display the borders of the window, including the caption area.
*
* *********************************************************************
* * Copyright (C) 1985, 1990 Regents of the University of California. *
* * Permission to use, copy, modify, and distribute this *
* * software and its documentation for any purpose and without *
* * fee is hereby granted, provided that the above copyright *
* * notice appear in all copies. The University of California *
* * makes no representations about the suitability of this *
* * software for any purpose. It is provided "as is" without *
* * express or implied warranty. Export of this software outside *
* * of the United States of America may require an export license. *
* *********************************************************************
*/
#ifndef lint
static char rcsid[] __attribute__ ((unused)) = "$Header$";
#endif /* not lint */
#include <stdio.h>
#include "tcltk/tclmagic.h"
#include "utils/magic.h"
#include "utils/utils.h"
#include "textio/textio.h"
#include "utils/geometry.h"
#include "graphics/glyphs.h"
#include "windows/windows.h"
#include "windows/windInt.h"
#include "graphics/graphics.h"
#include "utils/styles.h"
#include "tiles/tile.h"
#include "utils/hash.h"
#include "database/database.h"
#include "utils/undo.h"
#include "utils/signals.h"
#include "utils/malloc.h"
/* The following Plane is used to keep track of areas of the
* screen that have changed. ERROR_P tiles are used to record
* areas of the screen (in pixels) that must be redisplayed.
*
* If windows have speparate coordinate spaces (as on a SUN), this plane
* is ignored and the one in w->w_redrawAreas is used instead.
*/
global Plane *windRedisplayArea = NULL;
static Plane *windCurRedrawPlane = NULL; /* used for sharing between procs */
static LinkedRect *windCoveredAreas = NULL;
global GrGlyphs *windGlyphs = NULL;
/* windCaptionPixels is the height of the caption strip. It is internal to
* this module.
*/
int windCaptionPixels = 0;
/* Are the windows in their own coordinate system?
*/
bool windSomeSeparateRedisplay = FALSE;
/*
* ----------------------------------------------------------------------------
*
* windCheckOnlyWindow --
*
* Check if the TopWindow is the only window---if so, we shouldn't
* generate bothersome messages about the cursor not being in a window,
* because there is no confusion.
*
* We want to make sure that we don't count windows which are not of
* the same client type.
*
* ----------------------------------------------------------------------------
*/
int
windCheckOnlyWindow(MagWindow **w, WindClient client)
{
MagWindow *sw, *tw;
int wct = 0;
if (*w != NULL) return 0;
if (windTopWindow != NULL)
{
for (sw = windTopWindow; sw != NULL; sw = sw->w_nextWindow)
{
if (sw->w_client == client)
{
wct++;
tw = sw;
}
}
if (wct == 1) *w = tw;
}
return 0;
}
/*
* ----------------------------------------------------------------------------
* windFreeList --
*
* Free up a list of linked rectangles.
*
* Results:
* None.
*
* Side effects:
* Storage is reclaimed. The original pointer is NULLed out.
* ----------------------------------------------------------------------------
*/
void
windFreeList(llr)
LinkedRect **llr; /* A pointer to a list of linked rectangles */
{
LinkedRect *lr, *freelr;
lr = *llr;
while (lr != (LinkedRect *) NULL)
{
freelr = lr;
lr = lr->r_next;
freeMagic( (char *) freelr);
}
*llr = (LinkedRect *) NULL;
}
/*
* ----------------------------------------------------------------------------
* windReClip --
*
* Traverse the linked list of windows, updating w_clipAgainst
* for each window.
*
* Results:
* None.
*
* Side effects:
* Changes w_clipAgainst for some windows.
* ----------------------------------------------------------------------------
*/
void
windReClip()
{
MagWindow *w1, *w2;
/* an O(n**2) operation!! */
windFreeList(&windCoveredAreas);
for (w1 = windBottomWindow; w1 != (MagWindow *) NULL; w1 = w1->w_prevWindow)
{
LinkedRect *tmp;
/* add window onto windCoveredAreas */
tmp = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect)));
tmp->r_next = windCoveredAreas;
tmp->r_r = w1->w_frameArea;
windCoveredAreas = tmp;
/* free up the old clipping areas and make new ones */
windFreeList( &(w1->w_clipAgainst) );
w1->w_clipAgainst = (LinkedRect *) NULL;
/* Leave w_clipAgainst to be NULL if we are using some other
* window package, because that package will handle overlapping
* windows.
*/
if (WindPackageType == WIND_MAGIC_WINDOWS) {
for (w2 = w1->w_prevWindow; w2 != (MagWindow *) NULL;
w2 = w2->w_prevWindow)
{
if ( GEO_TOUCH( &(w1->w_frameArea), &(w2->w_frameArea) ))
{
tmp = (LinkedRect *) mallocMagic((unsigned) (sizeof (LinkedRect)));
tmp->r_next = w1->w_clipAgainst;
tmp->r_r = w2->w_frameArea;
w1->w_clipAgainst = tmp;
}
}
}
}
}
/*
* ----------------------------------------------------------------------------
*
* WindSeparateRedisplay --
*
* Tells the window manager to record redisplay areas for this window
* separately -- probably because the window has its own separate
* coordinate system. (Used on the Sun with Suntools or X.)
*
* Results:
* None.
*
* Side Effects:
* None.
*
* ----------------------------------------------------------------------------
*/
void
WindSeparateRedisplay(w)
MagWindow *w;
{
windSomeSeparateRedisplay = TRUE;
if (w->w_redrawAreas != (ClientData)NULL) return;
w->w_redrawAreas = (ClientData) DBNewPlane((ClientData) TT_SPACE);
}
/*
* ----------------------------------------------------------------------------
* WindIconChanged --
*
* Mark the icon for this window as needing to be redisplayed.
*
* Results:
* None.
*
* Side effects:
* None.
* ----------------------------------------------------------------------------
*/
void
WindIconChanged(w)
MagWindow *w;
{
ASSERT(w != NULL, "WindIconChanged");
w->w_flags |= WIND_REDRAWICON;
}
/*
* ----------------------------------------------------------------------------
* WindAreaChanged --
*
* Notify the window package that a certain area of the screen has
* changed, and now needs to be redrawn.
*
* Results:
* None.
*
* Side effects:
* The area is noted as having changed in window w. When
* WindUpdate is called, this area will be redisplayed, but
* only in w. If w is NULL, then this area will be redisplayed
* in all windows. If area is NULL, then the whole area of
* the window will be redisplayed. If both are NULL, then
* the whole screen will be redisplayed.
* ----------------------------------------------------------------------------
*/
void
WindAreaChanged(w, area)
MagWindow *w; /* The window that changed. */
Rect *area; /* The area in screen coordinates.
* NULL means the whole screen. Caller
* should clip this rectangle to the area
* of the window.
*/
{
Rect biggerArea;
int windChangedFunc(); /* Forward declaration. */
if (w == NULL) {
if (windSomeSeparateRedisplay) {
MagWindow *nw;
for (nw = windTopWindow; nw != NULL; nw = nw->w_nextWindow)
WindAreaChanged(nw, area);
return;
} else
windCurRedrawPlane = windRedisplayArea;
} else {
if (w->w_redrawAreas != (ClientData)NULL)
windCurRedrawPlane = (Plane *) w->w_redrawAreas;
else
windCurRedrawPlane = windRedisplayArea;
}
if (area == (Rect *) NULL)
{
/* Everything changed -- all the window's area as well as the icon. */
if (w != (MagWindow *) NULL) {
area = &w->w_allArea;
WindIconChanged(w);
} else {
MagWindow *nw;
area = &GrScreenRect;
for (nw = windTopWindow; nw != NULL; nw = nw->w_nextWindow)
WindIconChanged(nw);
}
}
/* We have to increase the upper x- and y-coordinates of
* the redisplay area by one. This is because a pixel is
* considered to include its entire area (up to the beginning
* of the next pixel). Without this code and corresponding
* hacks in WindUpdate and windBackgroundFunc, little slivers
* get left lying around.
*/
biggerArea = *area;
biggerArea.r_xtop += 1;
biggerArea.r_ytop += 1;
/* If no window is given, or if the window is unobscured,
* then just paint an error tile over the area to be redisplayed.
* Otherwise, clip the area against all the obscuring areas
* for the window. Be careful to keep undo away from this.
*/
UndoDisable();
if ((w == NULL) || (w->w_clipAgainst == NULL))
DBPaintPlane(windCurRedrawPlane, &biggerArea,
DBStdPaintTbl(TT_ERROR_P, PL_DRC_ERROR), (PaintUndoInfo *) NULL);
else
{
(void) GeoDisjoint(&biggerArea, &w->w_clipAgainst->r_r, windChangedFunc,
(ClientData) w->w_clipAgainst->r_next);
}
UndoEnable();
/* If the area is NULL or encompasses the whole screen area, and */
/* there is no backing store, then we should create it so that it */
/* will be copied into on the next display redraw. */
if ((w != NULL) && (w->w_backingStore == (ClientData)NULL) &&
(!(w->w_flags & WIND_OBSCURED)) && (GrCreateBackingStorePtr != NULL))
if ((area == (Rect *)NULL) || GEO_SURROUND(&biggerArea, &w->w_screenArea))
(*GrCreateBackingStorePtr)(w);
}
int
windChangedFunc(area, next)
Rect *area; /* Area that is still unobscured. */
LinkedRect *next; /* Next obscuring area. */
{
/* If we're at the end of obscuring areas, paint an error
* tile to mark what's to be redisplayed. Otherwise,
* clip against the next obscuring area.
*/
if (next == NULL)
DBPaintPlane(windCurRedrawPlane, area,
DBStdPaintTbl(TT_ERROR_P, PL_DRC_ERROR), (PaintUndoInfo *) NULL);
else (void) GeoDisjoint(area, &next->r_r, windChangedFunc,
(ClientData) next->r_next);
return 0;
}
/*
* ----------------------------------------------------------------------------
* windBarLocations --
*
* Find the scroll bars and icons in the window.
* Each argument must point to a different piece of memory.
*
* Results:
* None.
*
* Side effects:
* Returns a bunch of rectangles describing the locations of things.
* See comments next to the argument list for details.
* ----------------------------------------------------------------------------
*/
void
windBarLocations(w, leftBar, botBar, up, down, right, left, zoom)
MagWindow *w; /* The window under consideration. */
/* The following are rectangles that will be filled
* in by this procedure. The values will be in the
* same coordinate sytem as w->w_allArea.
*/
Rect *leftBar; /* The location of the left scrollbar area (not the
* bar itself).
*/
Rect *botBar; /* The location of the bottom scrollbar area. */
Rect *up; /* The location of the 'up arrow' icon above the
* left scroll bar.
*/
Rect *down; /* The location of the 'down arrow' icon below the
* left scroll bar.
*/
Rect *right; /* The location of the 'right arrow' icon to the right
* of the bottom scroll bar.
*/
Rect *left; /* The location of the 'left arrow' icon to the left of
* the bottom scroll bar.
*/
Rect *zoom; /* The location of the 'zoom' icon in the lower-left
* corner of the window.
*/
{
/* left scroll bar area */
leftBar->r_xbot = w->w_allArea.r_xbot + THIN_LINE;
leftBar->r_ybot = w->w_allArea.r_ybot + THIN_LINE + WindScrollBarWidth +
BOT_BORDER(w);
leftBar->r_xtop = leftBar->r_xbot + WindScrollBarWidth - GrPixelCorrect;
leftBar->r_ytop = w->w_allArea.r_ytop - THIN_LINE - WindScrollBarWidth -
TOP_BORDER(w);
/* bottom scroll bar area */
botBar->r_ybot = w->w_allArea.r_ybot + THIN_LINE;
botBar->r_xbot = w->w_allArea.r_xbot + THIN_LINE + WindScrollBarWidth +
LEFT_BORDER(w);
botBar->r_ytop = botBar->r_ybot + WindScrollBarWidth - GrPixelCorrect;
botBar->r_xtop = w->w_allArea.r_xtop - THIN_LINE - WindScrollBarWidth -
RIGHT_BORDER(w);
/* border icons */
down->r_xbot = up->r_xbot = leftBar->r_xbot;
down->r_xtop = up->r_xtop = leftBar->r_xtop;
up->r_ybot = leftBar->r_ytop + THIN_LINE + 1;
up->r_ytop = up->r_ybot + WindScrollBarWidth - 1;
down->r_ytop = leftBar->r_ybot - THIN_LINE - 1;
down->r_ybot = down->r_ytop - WindScrollBarWidth + 1;
left->r_ybot = right->r_ybot = botBar->r_ybot;
left->r_ytop = right->r_ytop = botBar->r_ytop;
right->r_xbot = botBar->r_xtop + THIN_LINE + 1;
right->r_xtop = right->r_xbot + WindScrollBarWidth - 1;
left->r_xtop = botBar->r_xbot - THIN_LINE - 1;
left->r_xbot = left->r_xtop - WindScrollBarWidth + 1;
zoom->r_xbot = w->w_allArea.r_xbot + THIN_LINE;
zoom->r_ybot = w->w_allArea.r_ybot + THIN_LINE;
zoom->r_xtop = zoom->r_xbot + WindScrollBarWidth - 1;
zoom->r_ytop = zoom->r_ybot + WindScrollBarWidth - 1;
}
/*
* ----------------------------------------------------------------------------
* WindDrawBorder --
*
* Draw the border of windows. A window lock is created & then destroyed.
*
* Results:
* None.
*
* Side effects:
* Redisplays the scroll bar & caption areas of a window's border.
* ----------------------------------------------------------------------------
*/
void
WindDrawBorder(w, clip)
MagWindow *w;
Rect *clip;
{
Rect r;
Rect leftBar, botBar, up, down, left, right, zoom;
Rect leftElev, botElev;
int bar, bbox, viewl, viewu;
Point capp;
Rect capr;
GrLock(w, FALSE);
GrClipTo(clip);
/* Redisplay the caption if it overlaps the area. */
capr = w->w_allArea;
capr.r_ybot = capr.r_ytop - TOP_BORDER(w) + GrPixelCorrect;
capp.p_x = (capr.r_xbot + capr.r_xtop) / 2;
capp.p_y = (capr.r_ybot + capr.r_ytop + 1) / 2;
if (GEO_TOUCH(&capr, clip)) {
if (w->w_flags & WIND_BORDER)
GrClipBox(&capr, STYLE_BORDER);
if ((w->w_flags & WIND_CAPTION) && (w->w_caption != NULL)) {
(void) GrPutText(w->w_caption, STYLE_CAPTION, &capp,
GEO_CENTER, GR_TEXT_DEFAULT, FALSE, &capr,
(Rect *) NULL);
}
}
if ((w->w_flags & WIND_BORDER) != 0)
{
/* right border */
r = w->w_allArea;
r.r_xbot = w->w_allArea.r_xtop - RIGHT_BORDER(w) + GrPixelCorrect;
r.r_ytop = w->w_allArea.r_ytop - TOP_BORDER(w);
if (GEO_TOUCH(&r, clip)) GrClipBox(&r, STYLE_BORDER);
if ((w->w_flags & WIND_SCROLLBARS) == 0)
{
/* windows without scroll bars */
/* left border */
r = w->w_allArea;
r.r_xtop = w->w_allArea.r_xbot + LEFT_BORDER(w) - GrPixelCorrect;
r.r_ytop = w->w_allArea.r_ytop - TOP_BORDER(w);
if (GEO_TOUCH(&r, clip)) GrClipBox(&r, STYLE_BORDER);
/* bottom border */
r = w->w_allArea;
r.r_ytop = w->w_allArea.r_ybot + BOT_BORDER(w) - GrPixelCorrect;
if (GEO_TOUCH(&r, clip)) GrClipBox(&r, STYLE_BORDER);
}
}
if ((w->w_flags & WIND_SCROLLBARS) != 0)
{
/* windows with scroll bars */
/* left vertical lines */
r = w->w_allArea;
r.r_ytop = w->w_allArea.r_ytop - TOP_BORDER(w);
r.r_xtop = r.r_xbot + THIN_LINE - GrPixelCorrect;
if (GEO_TOUCH(&r, clip)) GrClipBox(&r, STYLE_BORDER);
r.r_xbot += WindScrollBarWidth + THIN_LINE;
r.r_xtop = r.r_xbot + THIN_LINE - GrPixelCorrect;
if (GEO_TOUCH(&r, clip)) GrClipBox(&r, STYLE_BORDER);
/* bottom horizontal lines */
r = w->w_allArea;
r.r_ytop = r.r_ybot + THIN_LINE - GrPixelCorrect;
if (GEO_TOUCH(&r, clip)) GrClipBox(&r, STYLE_BORDER);
r.r_ybot += WindScrollBarWidth + THIN_LINE;
r.r_ytop = r.r_ybot + THIN_LINE - GrPixelCorrect;
if (GEO_TOUCH(&r, clip)) GrClipBox(&r, STYLE_BORDER);
/* scroll bars */
windBarLocations(w, &leftBar, &botBar, &up, &down, &right, &left, &zoom);
GrClipBox(&leftBar, STYLE_CAPTION);
GrClipBox(&botBar, STYLE_CAPTION);
if (w->w_bbox == NULL) {
TxError("Warning: scroll bars but no w->w_bbox!\n");
TxError("Report this to a magic implementer.\n");
goto leave;
};
/* left scroll bar */
bar = MAX(1, leftBar.r_ytop - leftBar.r_ybot + 1);
bbox = MAX(1, w->w_bbox->r_ytop - w->w_bbox->r_ybot + 1);
viewl = w->w_surfaceArea.r_ybot - w->w_bbox->r_ybot + 1;
viewu = w->w_surfaceArea.r_ytop - w->w_bbox->r_ybot + 1;
leftElev.r_xbot = leftBar.r_xbot + 2;
leftElev.r_xtop = leftBar.r_xtop - 3 + GrPixelCorrect;
leftElev.r_ybot = (bar * viewl) / bbox + leftBar.r_ybot;
leftElev.r_ytop = (bar * viewu) / bbox + leftBar.r_ybot;
leftElev.r_ytop = MIN(leftElev.r_ytop, leftBar.r_ytop - 2);
leftElev.r_ybot = MIN(leftElev.r_ybot, leftElev.r_ytop - 3);
leftElev.r_ybot = MAX(leftElev.r_ybot, leftBar.r_ybot + 2);
leftElev.r_ytop = MAX(leftElev.r_ytop, leftElev.r_ybot + 1
+ GrPixelCorrect + GrPixelCorrect);
GrClipBox(&leftElev, STYLE_ELEVATOR);
r.r_xbot = leftBar.r_xbot;
r.r_xtop = leftBar.r_xtop;
r.r_ybot = leftBar.r_ybot - THIN_LINE;
r.r_ytop = leftBar.r_ybot - GrPixelCorrect;
if (GEO_TOUCH(&r, clip)) GrClipBox(&r, STYLE_BORDER);
r.r_ybot = leftBar.r_ytop + GrPixelCorrect;
r.r_ytop = leftBar.r_ytop + THIN_LINE;
if (GEO_TOUCH(&r, clip)) GrClipBox(&r, STYLE_BORDER);
/* bottom scroll bar */
bar = MAX(1, botBar.r_xtop - botBar.r_xbot + 1);
bbox = MAX(1, w->w_bbox->r_xtop - w->w_bbox->r_xbot + 1);
viewl = w->w_surfaceArea.r_xbot - w->w_bbox->r_xbot + 1;
viewu = w->w_surfaceArea.r_xtop - w->w_bbox->r_xbot + 1;
botElev.r_ybot = botBar.r_ybot + 2;
botElev.r_ytop = botBar.r_ytop - 3 + GrPixelCorrect;
botElev.r_xbot = (bar * viewl) / bbox + botBar.r_xbot;
botElev.r_xtop = (bar * viewu) / bbox + botBar.r_xbot;
botElev.r_xtop = MIN(botElev.r_xtop, botBar.r_xtop - 2);
botElev.r_xbot = MIN(botElev.r_xbot, botElev.r_xtop - 3);
botElev.r_xbot = MAX(botElev.r_xbot, botBar.r_xbot + 2);
botElev.r_xtop = MAX(botElev.r_xtop, botElev.r_xbot + 1
+ GrPixelCorrect + GrPixelCorrect);
GrClipBox(&botElev, STYLE_ELEVATOR);
r.r_ybot = botBar.r_ybot;
r.r_ytop = botBar.r_ytop;
r.r_xbot = botBar.r_xbot - THIN_LINE;
r.r_xtop = botBar.r_xbot - GrPixelCorrect;
if (GEO_TOUCH(&r, clip)) GrClipBox(&r, STYLE_BORDER);
r.r_xbot = botBar.r_xtop + GrPixelCorrect;
r.r_xtop = botBar.r_xtop + THIN_LINE;
if (GEO_TOUCH(&r, clip)) GrClipBox(&r, STYLE_BORDER);
/* icons */
GrDrawGlyph(windGlyphs->gr_glyph[0], &(up.r_ll));
GrDrawGlyph(windGlyphs->gr_glyph[1], &(down.r_ll));
GrDrawGlyph(windGlyphs->gr_glyph[2], &(left.r_ll));
GrDrawGlyph(windGlyphs->gr_glyph[3], &(right.r_ll));
GrDrawGlyph(windGlyphs->gr_glyph[4], &(zoom.r_ll));
}
leave:
GrUnlock(w);
}
/*
* ----------------------------------------------------------------------------
* WindCaption --
*
* Set the caption on the window.
*
* Results:
* None.
*
* Side effects:
* The caption is changed in the data structure and is redisplayed on the
* screen (if any of it is visible). If anything overlaps the caption and
* the caption was redisplayed then the overlap material will be
* redisplayed.
*
* If the new caption is identical to the old then only redisplay is done.
* ----------------------------------------------------------------------------
*/
void
WindCaption(w, caption)
MagWindow *w;
char *caption; /* The string that is to be copied into the caption.
* (The string is copied, not just pointed at.)
*/
{
Rect r;
if (w->w_caption != caption)
(void) StrDup( &(w->w_caption), caption);
r = w->w_allArea;
r.r_ybot = r.r_ytop - TOP_BORDER(w) + 1;
WindAreaChanged(w, &r);
if (GrUpdateIconPtr)(*GrUpdateIconPtr)(w,w->w_caption);
}
/*
* ----------------------------------------------------------------------------
* windNewView --
*
* The window's view has moved -- update the scroll bars.
*
* Results:
* None.
*
* Side effects:
* Records areas for redisplay.
* ----------------------------------------------------------------------------
*/
void
windNewView(w)
MagWindow *w;
{
Rect leftBar, botBar, up, down, right, left, zoom;
if ((w->w_flags & WIND_SCROLLBARS) != 0)
{
windBarLocations(w, &leftBar, &botBar, &up, &down, &right, &left, &zoom);
WindAreaChanged(w, &leftBar);
WindAreaChanged(w, &botBar);
}
}
/*
* ----------------------------------------------------------------------------
* WindRedisplay --
*
* Redisplay the entire window, including the border areas.
* Called without any window locks.
*
* Results:
* None.
*
* Side effects:
* Areas of the screen will be redrawn.
* ----------------------------------------------------------------------------
*/
void
WindRedisplay(w)
MagWindow *w;
{
WindAreaChanged(w, &(w->w_allArea));
}
/*
* ----------------------------------------------------------------------------
* windRedrawIcon --
*
* Redraw a windows icon.
*
* Results:
* None.
*
* Side effects:
* None.
* ----------------------------------------------------------------------------
*/
void
windRedrawIcon(w)
MagWindow *w;
{
Point p;
clientRec *cl;
char *name;
/* Prepare for graphics. */
cl = (clientRec *) w->w_client;
GrLock(w, FALSE);
GrClipBox(&w->w_allArea, STYLE_ERASEALL);
if (cl->w_icon != NULL) {
/* Draw the glyph */
GrDrawGlyph(cl->w_icon, &(w->w_allArea.r_ll));
}
/* Now label the icon */
if (w->w_iconname != NULL)
name = w->w_iconname;
else
name = cl->w_clientName;
p.p_y = w->w_allArea.r_ybot;
p.p_x = (w->w_allArea.r_xbot + w->w_allArea.r_xtop) / 2;
GrPutText(name, STYLE_BORDER, &p, GEO_NORTH, GR_TEXT_SMALL, TRUE,
&w->w_allArea, (Rect *) NULL);
/* We are done */
w->w_flags &= ~WIND_REDRAWICON;
GrUnlock(w);
}
/*
* ----------------------------------------------------------------------------
* WindUpdate --
*
* Update the screen areas that were previously passed to WindAreaChanged.
* Calls clients without any window locks.
*
* Results:
* None.
*
* Side effects:
* Clients will be called to update portions of the screen.
* ----------------------------------------------------------------------------
*/
bool WindAnotherUpdatePlease;
void
WindUpdate()
{
clientRec *cr;
MagWindow *w;
TileTypeBitMask windTileMask;
extern int windUpdateFunc(); /* Forward declaration. */
extern int windBackgroundFunc(); /* Forward declaration. */
Rect r;
WindAnotherUpdatePlease = FALSE;
/* First, if there was a SigWinch (as on a Sun160), then call the
* graphics module so that it can record additional areas to be
* redisplayed.
*/
if (SigGotSigWinch) {
SigGotSigWinch = FALSE;
if (GrDamagedPtr != NULL) (*GrDamagedPtr)();
}
#ifdef MAGIC_WRAPPER
/* Honor the display redraw suspension state */
if (GrDisplayStatus == DISPLAY_SUSPEND) return;
GrDisplayStatus = DISPLAY_IN_PROGRESS;
SigSetTimer(0);
#endif
TTMaskSetOnlyType(&windTileMask, TT_ERROR_P);
/* Make a scan through each of the windows, in order from top
* down. For each window, redisplay the areas of that window
* that have changed, then erase the area of that window from
* the redisplay plane. Since our window areas INCLUDE their
* border pixels on both sides, expand the area on the top and
* right sides before erasing. Without this expansion, and
* corresponding hacks in WindAreaChanged and windBackgroundFunc,
* slivers will accidentally be left undisplayed.
*/
UndoDisable();
for (w = windTopWindow; w != NULL; w = w->w_nextWindow)
{
if (w->w_flags & WIND_ISICONIC) {
if (w->w_flags & WIND_REDRAWICON) windRedrawIcon(w);
} else {
if (w->w_redrawAreas == (ClientData)NULL)
windCurRedrawPlane = windRedisplayArea;
else
windCurRedrawPlane = (Plane *) w->w_redrawAreas;
(void) DBSrPaintArea((Tile *) NULL,
windCurRedrawPlane, &w->w_allArea, &windTileMask,
windUpdateFunc, (ClientData) w);
if (windCurRedrawPlane == windRedisplayArea) {
/* Erase this window from our list, since we have redrawn it.
*/
r = w->w_allArea;
r.r_xtop += 1;
r.r_ytop += 1;
DBPaintPlane(windRedisplayArea, &r,
DBStdEraseTbl(TT_ERROR_P, PL_DRC_ERROR),
(PaintUndoInfo *) NULL);
} else {
/* We are finished with this window's redisplay plane. Clear
* any remaining redisplay tiles, as we may have interrupted
* the redislay and don't want this stuff any more.
*/
DBClearPaintPlane(windCurRedrawPlane);
}
}
}
if (WindPackageType == WIND_MAGIC_WINDOWS)
{
/* For any tiles left that intersect the screen, draw the background
* color (there are no windows over these tiles).
*/
(void) DBSrPaintArea((Tile *) NULL,
windRedisplayArea, &GrScreenRect, &windTileMask,
windBackgroundFunc, (ClientData) NULL);
/* Clear any remaining redisplay tiles, as we may have interrupted
* the redislay and don't want this stuff any more.
*/
DBClearPaintPlane(windRedisplayArea);
};
UndoEnable();
/* Now give the clients a chance to update anything that they wish */
for (cr = windFirstClientRec; cr != (clientRec *) NULL;
cr = cr->w_nextClient)
{
if (cr->w_update != NULL)
(*(cr->w_update)) ();
}
GrFlush();
#ifdef MAGIC_WRAPPER
SigRemoveTimer();
GrDisplayStatus = DISPLAY_IDLE;
#endif
/* See comment in windows.h */
if (WindAnotherUpdatePlease) WindUpdate();
}
/*
* ----------------------------------------------------------------------------
*
* windUpdateFunc --
*
* This procedure is invoked during WindUpdate for each tile that
* intersects a particular window. If the tile type is TT_ERROR_P
* then the intersection between the tile and the window is
* redisplayed.
*
* Results:
* Always returns 0 to keep the search from aborting.
*
* Side effects:
* Information is redisplayed on the screen.
*
* ----------------------------------------------------------------------------
*/
int
windUpdateFunc(tile, w)
Tile *tile; /* Tile in the redisplay plane. */
MagWindow *w; /* Window we're currently interested in. */
{
Rect area;
/* If this is a space tile, there's nothing to do. */
if (TiGetType(tile) == TT_SPACE) return 0;
TiToRect(tile, &area);
GeoClip(&area, &w->w_allArea);
GeoClip(&area, &GrScreenRect);
if ((area.r_xbot > area.r_xtop) || (area.r_ybot > area.r_ytop))
/* nothing to display */
return 0;
/* Skip the border stuff if it isn't going to change. This
* test has to be especially tricky because of the decision
* that pixel at (0,0) extends from (0,0) up to but not including
* (1,1).
*/
if (!((w->w_screenArea.r_xbot <= area.r_xbot)
&& (w->w_screenArea.r_xtop+1 >= area.r_xtop)
&& (w->w_screenArea.r_ybot <= area.r_ybot)
&& (w->w_screenArea.r_ytop+1 >= area.r_ytop))) {
/* Redisplay the border areas. */
WindDrawBorder(w, &area);
};
/* Now call the client to redisplay the interior of the window. */
if (GEO_TOUCH(&(w->w_screenArea), &area))
{
Rect clientArea;
WindScreenToSurface(w, &area, &clientArea);
GeoClip(&area, &w->w_screenArea);
if ( ((clientRec *) (w->w_client))->w_redisplay != NULL)
{
(*(( (clientRec *) (w->w_client))->w_redisplay))
(w, &clientArea, &area);
}
}
return 0;
}
/*
* ----------------------------------------------------------------------------
*
* windBackgroundFunc --
*
* Called for each tile left after redisplaying all of the windows.
* This procedure just draws the background colors in any remaining
* areas that have changed.
*
* Results:
* Always returns 0 to keep the search from aborting.
*
* Side effects:
* The background color gets drawn on the screen.
*
* ----------------------------------------------------------------------------
*/
/* ARGSUSED */
int
windBackgroundFunc(tile, notUsed)
Tile *tile;
ClientData notUsed;
{
Rect area;
if (TiGetType(tile) == (TileType) TT_SPACE) return 0;
TiToRect(tile, &area);
/* Since windows include their border pixels, we have to be
* a bit careful. If the upper or right edge of the area isn't
* the edge of the screen, it is a window. In that case, decrement
* the coordinate so we don't overwrite the edge of the window.
*/
if (area.r_xtop < GrScreenRect.r_xtop) area.r_xtop -= 1;
if (area.r_ytop < GrScreenRect.r_ytop) area.r_ytop -= 1;
GrLock(GR_LOCK_SCREEN, FALSE);
GrClipBox(&area, STYLE_BACKGROUND);
GrUnlock(GR_LOCK_SCREEN);
return 0;
}