Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!uwm.edu!spool.mu.edu!munnari.oz.au!manuel!csis!anucsd!pdact!dbell From: dbell@pdact.pd.necisa.oz.au (David I. Bell) Newsgroups: comp.os.minix Subject: MINI-X graphics package (part 7/9) Message-ID: <998@pdact.pd.necisa.oz.au> Date: 22 Apr 91 00:56:52 GMT Organization: NEC Information Systems Australia, Canberra Lines: 1149 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'mini-x/server/serv_util.c' <<'END_OF_FILE' X/* X * Copyright (c) 1991 David I. Bell X * Permission is granted to use, distribute, or modify this source, X * provided that this copyright notice remains intact. X * X * Graphics server utility routines for windows. X */ X#include X#include "graph_serv.h" X X X/* X * Help prevent future bugs by defining this variable to an illegal value. X * These routines should not be referencing this, but should be using X * unmapcount instead. X */ X#define mapped cannotusemapped X X X/* X * Macro to distinguish cases of clipping. X */ X#define GAPVAL(leftgap, rightgap, topgap, bottomgap) \ X (((leftgap) << 3) + ((rightgap) << 2) + ((topgap) << 1) + (bottomgap)) X X X/* X * Unmap the window to make it and its children invisible on the screen. X * This is a recursive routine which increments the unmapcount values for X * this window and all of its children, and causes exposure events for X * windows which are newly uncovered. X */ Xvoid XGsWpUnmapWindow(wp) X GR_WINDOW *wp; /* window to be unmapped */ X{ X GR_WINDOW *pwp; /* parent window */ X GR_WINDOW *sibwp; /* sibling window */ X GR_SIZE bs; /* border size of this window */ X X if (wp == rootwp) { X GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wp->id); X return; X } X X if (wp == clipwp) X clipwp = NULL; X X wp->unmapcount++; X X for (wp = wp->children; wp; wp = wp->siblings) X GsWpUnmapWindow(wp); X X if (wp == mousewp) { X GsCheckMouseWindow(); X GsCheckCursor(); X } X X if (wp == focuswp) { X focusfixed = GR_FALSE; X GsCheckFocusWindow(); X } X X /* X * If this is an input-only window or the parent window is X * still unmapped, then we are all done. X */ X if (!wp->output || wp->parent->unmapcount) X return; X X /* X * Clear the area in the parent for this window, causing an X * exposure event for it. Take into account the border size. X */ X bs = wp->bordersize; X pwp = wp->parent; X GsWpClearWindow(pwp, wp->x - pwp->x - bs, wp->y - pwp->y - bs, X wp->width + bs * 2, wp->height + bs * 2, GR_TRUE); X X /* X * Finally clear and redraw all parts of our lower sibling X * windows that were covered by this window. X */ X sibwp = wp; X while (sibwp->siblings) { X sibwp = sibwp->siblings; X GsExposeArea(sibwp, wp->x - bs, wp->y - bs, X wp->width + bs * 2, wp->height + bs * 2); X } X} X X X/* X * Map the window to possibly make it and its children visible on the screen. X * This is a recursive routine which decrements the unmapcount values for X * this window and all of its children, and causes exposure events for X * those windows which become visible. X */ Xvoid XGsWpMapWindow(wp) X GR_WINDOW *wp; /* window to be unmapped */ X{ X if (wp == rootwp) { X GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wp->id); X return; X } X X if (wp->unmapcount) X wp->unmapcount--; X X if (wp->unmapcount == 0) { X GsCheckMouseWindow(); X GsCheckFocusWindow(); X GsCheckCursor(); X } X X /* X * If the window is an output window and just became visible, X * then draw its border, clear it to the background color, and X * generate an exposure event. X */ X if (wp->output && (wp->unmapcount == 0)) { X GsDrawBorder(wp); X GsWpClearWindow(wp, 0, 0, wp->width, wp->height, GR_TRUE); X } X X /* X * Do the same thing for the children. X */ X for (wp = wp->children; wp; wp = wp->siblings) X GsWpMapWindow(wp); X} X X X/* X * Destroy the specified window, and all of its children. X * This is a recursive routine. X */ Xvoid XGsWpDestroyWindow(wp) X GR_WINDOW *wp; /* window to be destroyed */ X{ X GR_WINDOW *prevwp; /* previous window pointer */ X GR_EVENT_CLIENT *ecp; /* selections for window */ X X if (wp == rootwp) { X GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wp->id); X return; X } X X /* X * Unmap the window first. X */ X if (wp->unmapcount == 0) X GsWpUnmapWindow(wp); X X /* X * Destroy all children. X */ X while (wp->children) X GsWpDestroyWindow(wp->children); X X /* X * Free all client selection structures. X */ X while (wp->eventclients) { X ecp = wp->eventclients; X wp->eventclients = ecp->next; X free(ecp); X } X X /* X * Free any cursor associated with the window. X */ X if (wp->cursor->usecount-- == 1) { X free(wp->cursor); X wp->cursor = NULL; X } X X /* X * Remove this window from the child list of its parent. X */ X prevwp = wp->parent->children; X if (prevwp == wp) X wp->parent->children = wp->siblings; X else { X while (prevwp->siblings != wp) X prevwp = prevwp->siblings; X prevwp->siblings = wp->siblings; X } X wp->siblings = NULL; X X /* X * Remove this window from the complete list of windows. X */ X prevwp = listwp; X if (prevwp == wp) X listwp = wp->next; X else { X while (prevwp->next != wp) X prevwp = prevwp->next; X prevwp->next = wp->next; X } X wp->next = NULL; X X /* X * Forget various information if they related to this window. X * Then finally free the structure. X */ X if (wp == clipwp) X clipwp = NULL; X if (wp == grabbuttonwp) X grabbuttonwp = NULL; X if (wp == cachewp) { X cachewindowid = 0; X cachewp = NULL; X } X if (wp == focuswp) { X focusfixed = GR_FALSE; X focuswp = rootwp; X } X X free(wp); X} X X X/* X * Clear the specified area of a window and possibly make an exposure event. X * This sets the area window to its background color. If the exposeflag is X * nonzero, then this also creates an exposure event for the window. X */ Xvoid XGsWpClearWindow(wp, x, y, width, height, exposeflag) X GR_WINDOW *wp; /* window structure */ X GR_BOOL exposeflag; /* nonzero to cause an exposure */ X{ X if (wp->unmapcount || !wp->output) X return; X X /* X * Reduce the arguments so that they actually lie within the window. X */ X if (x < 0) { X width += x; X x = 0; X } X if (y < 0) { X height += y; X y = 0; X } X if (x + width > wp->width) X width = wp->width - x; X if (y + height > wp->height) X height = wp->height - y; X X /* X * Now see if the region is really in the window. If not, then X * do nothing. X */ X if ((x >= wp->width) || (y >= wp->height) || (width <= 0) || X (height <= 0)) X return; X X /* X * Draw the background of the window. X * Invalidate the current graphics context since X * we are changing the foreground color and mode. X */ X GsSetClipWindow(wp); X curgcp = NULL; X GdSetMode(GR_MODE_SET); X GdSetForeground(wp->background); X GdFillRect(wp->x + x, wp->y + y, width, height); X X /* X * Now do the exposure if required. X */ X if (exposeflag) X GsDeliverExposureEvent(wp, x, y, width, height); X} X X X/* X * Handle the exposing of the specified absolute region of the screen, X * starting with the specified window. That window and all of its X * children will be redrawn and/or exposure events generated if they X * overlap the specified area. This is a recursive routine. X */ Xvoid XGsExposeArea(wp, rootx, rooty, width, height) X GR_WINDOW *wp; /* window which was exposed */ X GR_COORD rootx; /* absolute x coordinate */ X GR_COORD rooty; /* absolute y coordinate */ X GR_SIZE width; /* width of area */ X GR_SIZE height; /* height of area */ X{ X if (!wp->output || wp->unmapcount) X return; X X /* X * First see if the area overlaps the window including the border. X * If not, then there is nothing more to do. X */ X if ((rootx >= wp->x + wp->width + wp->bordersize) || X (rooty >= wp->y + wp->height + wp->bordersize) || X (rootx + width <= wp->x - wp->bordersize) || X (rooty + height <= wp->y - wp->bordersize)) X return; X X /* X * The area does overlap the window. See if the area overlaps X * the border, and if so, then redraw it. X */ X if ((rootx < wp->x) || (rooty < wp->y) || X (rootx + width > wp->x + wp->width) || X (rooty + height > wp->y + wp->height)) X GsDrawBorder(wp); X X /* X * Now clear the window itself in the specified area, X * which might cause an exposure event. X */ X GsWpClearWindow(wp, rootx - wp->x, rooty - wp->y, X width, height, GR_TRUE); X X /* X * Now do the same for all the children. X */ X for (wp = wp->children; wp; wp = wp->siblings) X GsExposeArea(wp, rootx, rooty, width, height); X} X X X/* X * Draw the border of a window if there is one. X * Note: To allow the border to be drawn with the correct clipping, X * we temporarily grow the size of the window to include the border. X */ Xvoid XGsDrawBorder(wp) X GR_WINDOW *wp; /* window needing border drawn */ X{ X GR_COORD lminx; /* left edge minimum x */ X GR_COORD rminx; /* right edge minimum x */ X GR_COORD tminy; /* top edge minimum y */ X GR_COORD bminy; /* bottom edge minimum y */ X GR_COORD topy; /* top y value of window */ X GR_COORD boty; /* bottom y value of window */ X GR_SIZE width; /* original width of window */ X GR_SIZE height; /* original height of window */ X GR_SIZE bs; /* border size */ X X bs = wp->bordersize; X if (bs <= 0) X return; X X width = wp->width; X height = wp->height; X lminx = wp->x - bs; X rminx = wp->x + width; X tminy = wp->y - bs; X bminy = wp->y + height; X topy = wp->y; X boty = bminy - 1; X X wp->x -= bs; X wp->y -= bs; X wp->width += (bs * 2); X wp->height += (bs * 2); X wp->bordersize = 0; X X clipwp = NULL; X GsSetClipWindow(wp); X curgcp = NULL; X GdSetMode(GR_MODE_SET); X GdSetForeground(wp->bordercolor); X X if (bs == 1) { X GdLine(lminx, tminy, rminx, tminy); X GdLine(lminx, bminy, rminx, bminy); X GdLine(lminx, topy, lminx, boty); X GdLine(rminx, topy, rminx, boty); X } else { X GdFillRect(lminx, tminy, width + bs * 2, bs); X GdFillRect(lminx, bminy, width + bs * 2, bs); X GdFillRect(lminx, topy, bs, height); X GdFillRect(rminx, topy, bs, height); X } X X /* X * Restore the true window size. X * Forget the currently clipped window since we messed it up. X */ X wp->x += bs; X wp->y += bs; X wp->width -= (bs * 2); X wp->height -= (bs * 2); X wp->bordersize = bs; X clipwp = NULL; X} X X X/* X * Check to see if the first window overlaps the second window. X */ XGR_BOOL XGsCheckOverlap(topwp, botwp) X GR_WINDOW *topwp; /* window on top */ X GR_WINDOW *botwp; /* window on bottom */ X{ X GR_COORD minx1; X GR_COORD miny1; X GR_COORD maxx1; X GR_COORD maxy1; X GR_COORD minx2; X GR_COORD miny2; X GR_COORD maxx2; X GR_COORD maxy2; X GR_SIZE bs; X X if (!topwp->output || topwp->unmapcount || botwp->unmapcount) X return GR_FALSE; X X bs = topwp->bordersize; X minx1 = topwp->x - bs; X miny1 = topwp->y - bs; X maxx1 = topwp->x + topwp->width + bs - 1; X maxy1 = topwp->y + topwp->height + bs - 1; X X bs = botwp->bordersize; X minx2 = botwp->x - bs; X miny2 = botwp->y - bs; X maxx2 = botwp->x + botwp->width + bs - 1; X maxy2 = botwp->y + botwp->height + bs - 1; X X if ((minx1 > maxx2) || (minx2 > maxx1) || (miny1 > maxy2) X || (miny2 > maxy1)) X return GR_FALSE; X X return GR_TRUE; X} X X X/* X * Return a pointer to the window structure with the specified window id. X * Returns NULL if the window does not exist, with an error set. X */ XGR_WINDOW * XGsFindWindow(id) X GR_WINDOW_ID id; /* id of window to find */ X{ X GR_WINDOW *wp; /* current window pointer */ X X /* X * See if this is the root window or the same window as last time. X */ X if (id == GR_ROOT_WINDOW_ID) X return rootwp; X X if ((id == cachewindowid) && id) X return cachewp; X X /* X * No, search for it and cache it for future calls. X */ X for (wp = listwp; wp; wp = wp->next) { X if (wp->id == id) { X cachewindowid = id; X cachewp = wp; X return wp; X } X } X X GsError(GR_ERROR_BAD_WINDOW_ID, id); X X return NULL; X} X X X/* X * Return a pointer to the graphics context with the specified id. X * Returns NULL if the graphics context does not exist, with an X * error saved. X */ XGR_GC * XGsFindGC(gcid) X GR_GC_ID gcid; /* id of graphics context to find */ X{ X GR_GC *gcp; /* current graphics context pointer */ X X /* X * See if this is the same graphics context as last time. X */ X if ((gcid == cachegcid) && gcid) X return cachegcp; X X /* X * No, search for it and cache it for future calls. X */ X for (gcp = listgcp; gcp; gcp = gcp->next) { X if (gcp->id == gcid) { X cachegcid = gcid; X cachegcp = gcp; X return gcp; X } X } X X GsError(GR_ERROR_BAD_GC_ID, gcid); X X return NULL; X} X X X/* X * Prepare to do drawing in a window or pixmap using the specified X * graphics context. Returns the window or pixmap pointer if successful, X * and the type of drawing id that was supplied. Returns the special value X * GR_DRAW_TYPE_NONE if an error is generated, or if drawing is useless. X */ XGR_DRAW_TYPE XGsPrepareDrawing(id, gcid, retwp, retpixptr) X GR_DRAW_ID id; /* drawing id to be used */ X GR_GC_ID gcid; /* graphics id to be used */ X GR_WINDOW **retwp; /* returned window pointer (or NULL) */ X GR_PIXMAP **retpixptr; /* returned pixmap pointer (or NULL) */ X{ X GR_WINDOW *wp; /* found window */ X GR_GC *gcp; /* found graphics context */ X X *retwp = NULL; X *retpixptr = NULL; X X gcp = GsFindGC(gcid); X if (gcp == NULL) X return GR_DRAW_TYPE_NONE; X X /* X * Future: look for pixmap id too. X * For now, can only have window ids. X */ X wp = GsFindWindow(id); X if (wp == NULL) X return GR_DRAW_TYPE_NONE; X X if (!wp->output) { X GsError(GR_ERROR_INPUT_ONLY_WINDOW, id); X return GR_DRAW_TYPE_NONE; X } X X if (wp->unmapcount) X return GR_DRAW_TYPE_NONE; X X /* X * If the window is not the currently clipped one, then make it the X * current one and define its clip rectangles. X */ X if (wp != clipwp) X GsSetClipWindow(wp); X X /* X * If the graphics context is not the current one, then X * make it the current one and remember to update it. X */ X if (gcp != curgcp) { X curgcp = gcp; X gcp->changed = GR_TRUE; X } X X /* X * If the graphics context has been changed, then tell the X * device driver about it. X */ X if (gcp->changed) { X GdSetForeground(gcp->foreground); X GdSetBackground(gcp->background); X GdSetMode(gcp->mode); X GdSetUseBackground(gcp->usebackground); X gcp->changed = GR_FALSE; X } X X *retwp = wp; X return GR_DRAW_TYPE_WINDOW; X} X X X/* X * Prepare the specified window for drawing into it. X * This sets up the clipping regions to just allow drawing into it. X * Returns NULL if the drawing is illegal (with an error generated), X * or if the window is not mapped. X */ XGR_WINDOW * XGsPrepareWindow(wid) X GR_WINDOW_ID wid; /* window id to be used */ X{ X GR_WINDOW *wp; /* found window */ X X wp = GsFindWindow(wid); X if (wp == NULL) X return NULL; X X if (!wp->output) { X GsError(GR_ERROR_INPUT_ONLY_WINDOW, wid); X return NULL; X } X X if (wp->unmapcount) X return NULL; X X if (wp != clipwp) X GsSetClipWindow(wp); X X return wp; X} X X X/* X * Set the clip rectangles for a window taking into account other X * windows that may be obscuring it. The windows that may be obscuring X * this one are the siblings of each direct ancestor which are higher X * in priority than those ancestors. Also, each parent limits the visible X * area of the window. The clipping is not done if it is already up to X * date of if the window is not outputtable. X */ Xvoid XGsSetClipWindow(wp) X GR_WINDOW *wp; /* window to set clipping for */ X{ X GR_WINDOW *pwp; /* parent window */ X GR_WINDOW *sibwp; /* sibling windows */ X GR_RECT *clip; /* first clip rectangle */ X GR_COUNT count; /* number of clip rectangles */ X GR_COUNT newcount; /* number of new rectangles */ X GR_COUNT i; /* current index */ X GR_COORD minx; /* minimum clip x coordinate */ X GR_COORD miny; /* minimum clip y coordinate */ X GR_COORD maxx; /* maximum clip x coordinate */ X GR_COORD maxy; /* maximum clip y coordinate */ X GR_COORD diff; /* difference in coordinates */ X GR_SIZE bs; /* border size */ X GR_BOOL toomany; /* TRUE if too many clip rects */ X GR_RECT cliprects[GR_MAX_CLIPRECTS]; /* clip rectangles */ X X if (wp->unmapcount || !wp->output || (wp == clipwp)) X return; X X clipwp = wp; X X /* X * Start with the rectangle for the complete window. X * We will then cut pieces out of it as needed. X */ X count = 1; X clip = cliprects; X clip->x = wp->x; X clip->y = wp->y; X clip->width = wp->width; X clip->height = wp->height; X X /* X * First walk upwards through all parent windows, X * and restrict the visible part of this window to the part X * that shows through all of those parent windows. X */ X pwp = wp; X while (pwp != rootwp) { X pwp = pwp->parent; X X diff = pwp->x - clip->x; X if (diff > 0) { X clip->width -= diff; X clip->x = pwp->x; X } X X diff = (pwp->x + pwp->width) - (clip->x + clip->width); X if (diff < 0) X clip->width += diff; X X diff = pwp->y - clip->y; X if (diff > 0) { X clip->height -= diff; X clip->y = pwp->y; X } X X diff = (pwp->y + pwp->height) - (clip->y + clip->height); X if (diff < 0) X clip->height += diff; X } X X /* X * If the window is completely clipped out of view, then X * set the clipping region to indicate that. X */ X if ((clip->width <= 0) || (clip->height <= 0)) { X GdSetClipRects(1, cliprects); X return; X } X X /* X * Now examine all windows that obscure this window, and X * for each obscuration, break up the clip rectangles into X * the smaller pieces that are still visible. The windows X * that can obscure us are the earlier siblings of all of X * our parents. X */ X toomany = GR_FALSE; X pwp = wp; X while (pwp != rootwp) { X wp = pwp; X pwp = wp->parent; X sibwp = pwp->children; X for (; sibwp != wp; sibwp = sibwp->siblings) { X if (sibwp->unmapcount || !sibwp->output) X continue; X X bs = sibwp->bordersize; X minx = sibwp->x - bs; X miny = sibwp->y - bs; X maxx = sibwp->x + sibwp->width + bs - 1; X maxy = sibwp->y + sibwp->height + bs - 1; X X newcount = count; X for (i = 0; i < count; i++) { X if (newcount > GR_MAX_CLIPRECTS - 3) { X toomany = GR_TRUE; X break; X } X newcount += GsSplitClipRect(&cliprects[i], X &cliprects[newcount], X minx, miny, maxx, maxy); X } X count = newcount; X } X } X X if (toomany) { X GsError(GR_ERROR_TOO_MUCH_CLIPPING, wp->id); X clip->x = 0; X clip->y = 0; X clip->width = -1; X clip->height = -1; X count = 1; X } X X /* X * Set the clip rectangles. X */ X GdSetClipRects(count, cliprects); X} X X X/* X * Check the specified clip rectangle against the specified rectangular X * region, and reduce it or split it up into multiple clip rectangles X * such that the specified region is not contained in any of the clip X * rectangles. The source clip rectangle can be modified in place, and X * in addition more clip rectangles can be generated, which are placed in X * the indicated destination location. The maximum number of new clip X * rectangles needed is 3. Returns the number of clip rectangles added. X * If the source clip rectangle is totally obliterated, it is set to an X * impossible region and 0 is returned. When splits are done, we prefer X * to create wide regions instead of high regions. X */ XGR_COUNT XGsSplitClipRect(srcrect, destrect, minx, miny, maxx, maxy) X GR_RECT *srcrect; /* source clip rectangle */ X GR_RECT *destrect; /* source dest rectangle */ X GR_COORD minx; /* minimum x coordinate of region */ X GR_COORD miny; /* minimum y coordinate of region */ X GR_COORD maxx; /* maximum x coordinate of region */ X GR_COORD maxy; /* maximum y coordinate of region */ X{ X GR_COORD x; X GR_COORD y; X GR_SIZE width; X GR_SIZE height; X GR_COORD dx; X GR_COORD dy; X int gaps; X X /* X * First see if there is any overlap at all. X * If not, then nothing to do. X */ X x = srcrect->x; X y = srcrect->y; X width = srcrect->width; X height = srcrect->height; X X if ((minx > maxx) || (miny > maxy) || (maxx < x) || (maxy < y) || X (x + width <= minx) || (y + height <= miny)) X return 0; X X /* X * There is an overlap. Calculate a value to differentiate X * various cases, and then handle each case separately. The X * cases are classified on whether there are gaps on the left, X * right, top, and bottom sides of the clip rectangle. X */ X gaps = 0; X if (x < minx) X gaps |= GAPVAL(1, 0, 0, 0); X if (x + width - 1 > maxx) X gaps |= GAPVAL(0, 1, 0, 0); X if (y < miny) X gaps |= GAPVAL(0, 0, 1, 0); X if (y + height - 1 > maxy) X gaps |= GAPVAL(0, 0, 0, 1); X X switch (gaps) { X case GAPVAL(0, 0, 0, 0): /* no gaps at all */ X srcrect->x = 0; X srcrect->y = 0; X srcrect->width = 0; X srcrect->height = 0; X return 0; X X case GAPVAL(0, 0, 0, 1): /* gap on bottom */ X dy = maxy - y + 1; X srcrect->y += dy; X srcrect->height -= dy; X return 0; X X case GAPVAL(0, 0, 1, 0): /* gap on top */ X srcrect->height = miny - y; X return 0; X X case GAPVAL(0, 0, 1, 1): /* gap on top, bottom */ X srcrect->height = miny - y; X destrect->x = x; X destrect->width = width; X destrect->y = maxy + 1; X destrect->height = y + height - maxy - 1; X return 1; X X case GAPVAL(0, 1, 0, 0): /* gap on right */ X dx = maxx - x + 1; X srcrect->x += dx; X srcrect->width -= dx; X return 0; X X case GAPVAL(0, 1, 0, 1): /* gap on right, bottom */ X dx = maxx - x + 1; X srcrect->x += dx; X srcrect->width -= dx; X srcrect->height = maxy - y + 1; X destrect->x = x; X destrect->width = width; X destrect->y = maxy + 1; X destrect->height = y + height - maxy - 1; X return 1; X X case GAPVAL(0, 1, 1, 0): /* gap on right, top */ X dx = maxx - x + 1; X srcrect->height = miny - y; X destrect->x = x + dx; X destrect->width = width - dx; X destrect->y = miny; X destrect->height = y + height - miny; X return 1; X X case GAPVAL(0, 1, 1, 1): /* gap on right, top, bottom */ X dx = maxx - x + 1; X srcrect->height = miny - y; X destrect->x = x; X destrect->width = width; X destrect->y = maxy + 1; X destrect->height = y + height - maxy - 1; X destrect++; X destrect->x = x + dx; X destrect->width = width - dx; X destrect->y = miny; X destrect->height = maxy - miny + 1; X return 2; X X case GAPVAL(1, 0, 0, 0): /* gap on left */ X srcrect->width = minx - x; X return 0; X X case GAPVAL(1, 0, 0, 1): /* gap on left, bottom */ X srcrect->width = minx - x; X srcrect->height = maxy - y + 1; X destrect->x = x; X destrect->width = width; X destrect->y = maxy + 1; X destrect->height = y + height - maxy - 1; X return 1; X X case GAPVAL(1, 0, 1, 0): /* gap on left, top */ X srcrect->height = miny - y; X destrect->x = x; X destrect->width = minx - x; X destrect->y = miny; X destrect->height = y + height - miny; X return 1; X X case GAPVAL(1, 0, 1, 1): /* gap on left, top, bottom */ X srcrect->height = miny - y; X destrect->x = x; X destrect->width = minx - x; X destrect->y = miny; X destrect->height = maxy - miny + 1; X destrect++; X destrect->x = x; X destrect->width = width; X destrect->y = maxy + 1; X destrect->height = y + height - maxy - 1; X return 2; X X case GAPVAL(1, 1, 0, 0): /* gap on left, right */ X destrect->x = maxx + 1; X destrect->width = x + width - maxx - 1; X destrect->y = y; X destrect->height = height; X srcrect->width = minx - x; X return 1; X X case GAPVAL(1, 1, 0, 1): /* gap on left, right, bottom */ X dy = maxy - y + 1; X srcrect->y += dy; X srcrect->height -= dy; X destrect->x = x; X destrect->width = minx - x; X destrect->y = y; X destrect->height = dy; X destrect++; X destrect->x = maxx + 1; X destrect->width = x + width - maxx - 1; X destrect->y = y; X destrect->height = dy; X return 2; X X case GAPVAL(1, 1, 1, 0): /* gap on left, right, top */ X srcrect->height = miny - y; X destrect->x = x; X destrect->width = minx - x; X destrect->y = miny; X destrect->height = y + height - miny; X destrect++; X destrect->x = maxx + 1; X destrect->width = x + width - maxx - 1; X destrect->y = miny; X destrect->height = y + height - miny; X return 2; X X case GAPVAL(1, 1, 1, 1): /* gap on all sides */ X srcrect->height = miny - y; X destrect->x = x; X destrect->width = minx - x; X destrect->y = miny; X destrect->height = maxy - miny + 1; X destrect++; X destrect->x = maxx + 1; X destrect->width = x + width - maxx - 1; X destrect->y = miny; X destrect->height = maxy - miny + 1; X destrect++; X destrect->x = x; X destrect->width = width; X destrect->y = maxy + 1; X destrect->height = y + height - maxy - 1; X return 3; X } X} X X X/* X * Find the window which is currently visible for the specified coordinates. X * This just walks down the window tree looking for the deepest mapped X * window which contains the specified point. If the coordinates are X * off the screen, the root window is returned. X */ XGR_WINDOW * XGsFindVisibleWindow(x, y) X GR_COORD x; /* x position of cursor */ X GR_COORD y; /* y position of cursor */ X{ X GR_WINDOW *wp; /* current window */ X GR_WINDOW *retwp; /* returned window */ X X wp = rootwp; X retwp = wp; X while (wp) { X if ((wp->unmapcount == 0) && (wp->x <= x) && (wp->y <= y) && X (wp->x + wp->width > x) && (wp->y + wp->height > y)) X { X retwp = wp; X wp = wp->children; X continue; X } X wp = wp->siblings; X } X return retwp; X} X X X/* X * Check to see if the cursor shape is the correct shape for its current X * location. If not, its shape is changed. X */ Xvoid XGsCheckCursor() X{ X GR_WINDOW *wp; /* window cursor is in */ X GR_CURSOR *cp; /* cursor definition */ X X /* X * Get the cursor at its current position, and if it is not the X * currently defined one, then set the new cursor. However, X * if the pointer is currently grabbed, then leave it alone. X */ X wp = grabbuttonwp; X if (wp == NULL) X wp = mousewp; X X cp = wp->cursor; X if (cp == curcursor) X return; X X /* X * It needs redefining, so do it. X */ X curcursor = cp; X GdSetCursor(cp->width, cp->height, cp->foreground, X cp->background, cp->fgbitmap, cp->bgbitmap); X} X X X/* X * Check to see if the window the mouse is currently in has changed. X * If so, generate enter and leave events as required. The newest X * mouse window is remembered in mousewp. However, do not change the X * window while it is grabbed. X */ Xvoid XGsCheckMouseWindow() X{ X GR_WINDOW *wp; /* newest window for mouse */ X X wp = grabbuttonwp; X if (wp == NULL) X wp = GsFindVisibleWindow(cursorx, cursory); X if (wp == mousewp) X return; X X GsDeliverGeneralEvent(mousewp, GR_EVENT_TYPE_MOUSE_EXIT); X X mousewp = wp; X X GsDeliverGeneralEvent(wp, GR_EVENT_TYPE_MOUSE_ENTER); X} X X X/* X * Determine the current focus window for the current mouse coordinates. X * The mouse coordinates only matter if the focus is not fixed. Otherwise, X * the selected window is dependant on the window which wants keyboard X * events. This also sets the current focus for that found window. X * The window with focus is remembered in focuswp. X */ Xvoid XGsCheckFocusWindow() X{ X GR_WINDOW *wp; /* current window */ X GR_EVENT_CLIENT *ecp; /* current event client */ X GR_EVENT_MASK eventmask; /* event mask */ X X if (focusfixed) X return; X X eventmask = GR_EVENT_MASK_KEY_DOWN; X X /* X * Walk upwards from the current window containing the mouse X * looking for the first window which would accept a keyboard event. X */ X for (wp = mousewp; ;wp = wp->parent) { X for (ecp = wp->eventclients; ecp; ecp = ecp->next) { X if (ecp->eventmask & eventmask) { X GsWpSetFocus(wp); X return; X } X } X if ((wp == rootwp) || (wp->nopropmask & eventmask)) { X GsWpSetFocus(rootwp); X return; X } X } X} X X X/* X * Set the input focus to the specified window. X * This generates focus out and focus in events as necessary. X */ Xvoid XGsWpSetFocus(wp) X GR_WINDOW *wp; /* window to get the focus */ X{ X if (wp == focuswp) X return; X X GsDeliverGeneralEvent(focuswp, GR_EVENT_TYPE_FOCUS_OUT); X X focuswp = wp; X X GsDeliverGeneralEvent(wp, GR_EVENT_TYPE_FOCUS_IN); X} X X/* END CODE */ END_OF_FILE if test 26728 -ne `wc -c <'mini-x/server/serv_util.c'`; then echo shar: \"'mini-x/server/serv_util.c'\" unpacked with wrong size! fi # end of 'mini-x/server/serv_util.c' fi echo shar: End of archive 7 \(of 9\). cp /dev/null ark7isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 9 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0