📄 srvutil.c
字号:
/* * Copyright (c) 2000 Greg Haerr <greg@censoft.com> * Copyright (c) 1991 David I. Bell * Permission is granted to use, distribute, or modify this source, * provided that this copyright notice remains intact. * * Graphics server utility routines for windows. */#include <stdio.h>#include <stdlib.h>#ifndef __PACIFIC__#include <fcntl.h>#endif#include "serv.h"/* * Help prevent future bugs by defining this variable to an illegal value. * These routines should not be referencing this, but should be using * unmapcount instead. */#define mapped cannotusemapped/* * Redraw the screen completely. */voidGsRedrawScreen(void){ /* Redraw all windows*/ GsExposeArea(rootwp, 0, 0, rootwp->width, rootwp->height, NULL);}/* * Activate Screen Saver. */voidGsActivateScreenSaver(void *arg){ screensaver_active = GR_TRUE; GsDeliverScreenSaverEvent(GR_TRUE);}/* * Deactivate screen saver and reset timer if active. */voidGsResetScreenSaver(void){ MWTIMER *timer; if(screensaver_active == GR_TRUE) { screensaver_active = GR_FALSE; GsDeliverScreenSaverEvent(GR_FALSE); } if(screensaver_delay) { if((timer = GdFindTimer(GsActivateScreenSaver))) GdDestroyTimer(timer); GdAddTimer(screensaver_delay, GsActivateScreenSaver, GsActivateScreenSaver); }}voidGsTimerCB (void *arg) { GR_TIMER *timer = (GR_TIMER*) arg; GsDeliverTimerEvent (timer->owner, timer->wid, timer->id);}/* * Unmap the window to make it and its children invisible on the screen. * This is a recursive routine which increments the unmapcount values for * this window and all of its children, and causes exposure events for * windows which are newly uncovered. * If temp_unmap set, don't reset focus or generate mouse/focus events, * as window will be mapped again momentarily (window move, resize, etc) */void GsWpUnmapWindow(GR_WINDOW *wp, GR_BOOL temp_unmap){ GR_WINDOW *pwp; /* parent window */ GR_WINDOW *sibwp; /* sibling window */ GR_WINDOW *childwp; /* child window */ GR_SIZE bs; /* border size of this window */ if (wp == rootwp) { GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wp->id); return; } if (wp == clipwp) clipwp = NULL; ++wp->unmapcount; for (childwp = wp->children; childwp; childwp = childwp->siblings) GsWpUnmapWindow(childwp, temp_unmap); if (!temp_unmap && wp == mousewp) { GsCheckMouseWindow(); GsCheckCursor(); } if (!temp_unmap && wp == focuswp) { if (focusfixed) /* don't revert to mouse enter/leave focus if fixed*/ focuswp = rootwp; else { focusfixed = GR_FALSE; GsCheckFocusWindow(); } } /* Send update event if just unmapped*/ if (wp->unmapcount == 1) { GsDeliverUpdateEvent(wp, (temp_unmap? GR_UPDATE_UNMAPTEMP: GR_UPDATE_UNMAP), 0, 0, 0, 0); } /* * If this is an input-only window or the parent window is * still unmapped, then we are all done. */ if (!wp->output || wp->parent->unmapcount) return; /* * Clear the area in the parent for this window, causing an * exposure event for it. Take into account the border size. */ bs = wp->bordersize; pwp = wp->parent; GsWpClearWindow(pwp, wp->x - pwp->x - bs, wp->y - pwp->y - bs, wp->width + bs * 2, wp->height + bs * 2, GR_TRUE); /* * Finally clear and redraw all parts of our lower sibling * windows that were covered by this window. */ sibwp = wp; while (sibwp->siblings) { sibwp = sibwp->siblings; GsExposeArea(sibwp, wp->x - bs, wp->y - bs, wp->width + bs * 2, wp->height + bs * 2, NULL); }}/* * Map the window to possibly make it and its children visible on the screen. * This is a recursive routine which decrements the unmapcount values for * this window and all of its children, and causes exposure events for * those windows which become visible. * If temp is set, then window is being mapped again after a temporary * unmap, so don't reset focus or generate mouse/focus events. */void GsWpMapWindow(GR_WINDOW *wp, GR_BOOL temp){ if (wp == rootwp) { GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wp->id); return; } if (wp->unmapcount) --wp->unmapcount; if (!temp && wp->unmapcount == 0) { GsCheckMouseWindow(); GsCheckFocusWindow(); GsCheckCursor(); } /* send update event if just mapped*/ if (wp->unmapcount == 0) { GsDeliverUpdateEvent(wp, GR_UPDATE_MAP, wp->x, wp->y, wp->width, wp->height); } /* * If the window is an output window and just became visible, * then draw its border, clear it to the background color, and * generate an exposure event. */ if (wp->output && (wp->unmapcount == 0)) { GsDrawBorder(wp); GsWpClearWindow(wp, 0, 0, wp->width, wp->height, GR_TRUE); } /* * Do the same thing for the children. */ for (wp = wp->children; wp; wp = wp->siblings) GsWpMapWindow(wp, temp);}/* * Destroy the specified window, and all of its children. * This is a recursive routine. */void GsWpDestroyWindow(GR_WINDOW *wp){ GR_WINDOW *prevwp; /* previous window pointer */ GR_EVENT_CLIENT *ecp; /* selections for window */ GR_WINDOW_ID oldwid; /* old selection owner */ if (wp == rootwp) { GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wp->id); return; } /* Disable selection if this window is the owner */ if(selection_owner.wid == wp->id) { oldwid = selection_owner.wid; selection_owner.wid = 0; if(selection_owner.typelist) free(selection_owner.typelist); GsDeliverSelectionChangedEvent(oldwid, 0); } /* * Unmap the window first. */ if (wp->unmapcount == 0) GsWpUnmapWindow(wp, GR_FALSE); /* send update event*/ GsDeliverUpdateEvent(wp, GR_UPDATE_DESTROY, wp->x, wp->y, wp->width, wp->height); /* * Destroy all children. */ while (wp->children) GsWpDestroyWindow(wp->children); /* * Free all client selection structures. */ while (wp->eventclients) { ecp = wp->eventclients; wp->eventclients = ecp->next; free(ecp); } /* * Remove this window from the child list of its parent. */ prevwp = wp->parent->children; if (prevwp == wp) wp->parent->children = wp->siblings; else { while (prevwp->siblings != wp) prevwp = prevwp->siblings; prevwp->siblings = wp->siblings; } wp->siblings = NULL; /* * Remove this window from the complete list of windows. */ prevwp = listwp; if (prevwp == wp) listwp = wp->next; else { while (prevwp->next != wp) prevwp = prevwp->next; prevwp->next = wp->next; } wp->next = NULL; /* * Forget various information if they related to this window. * Then finally free the structure. */ if (wp == clipwp) clipwp = NULL; if (wp == grabbuttonwp) grabbuttonwp = NULL; if (wp == cachewp) { cachewindowid = 0; cachewp = NULL; } if (wp == focuswp) { /* don't revert to mouse enter/leave focus if fixed*/ /*focusfixed = GR_FALSE;*/ focuswp = rootwp; } GsCheckMouseWindow(); if(wp->title) free(wp->title); free(wp);}/* * Draw a window's background pixmap. * * The flags mean: * GR_BACKGROUND_TILE- tile the pixmap across the window (default). * GR_BACKGROUND_TOPLEFT- draw the pixmap at (0,0) relative to the window. * GR_BACKGROUND_CENTER- draw the pixmap in the middle of the window. * GR_BACKGROUND_STRETCH- stretch the pixmap within the window. * GR_BACKGROUND_TRANS- if the pixmap is smaller than the window and not * using tile mode, there will be gaps around the pixmap. This flag causes * to not fill in the spaces with the background colour. */void GsWpDrawBackgroundPixmap(GR_WINDOW *wp, GR_PIXMAP *pm, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height){ GR_SIZE destwidth, destheight, fillwidth, fillheight, pmwidth, pmheight; GR_COORD fromx, fromy, destx, desty, pixmapx = 0, pixmapy = 0; if(wp->bgpixmapflags & (GR_BACKGROUND_TOPLEFT|GR_BACKGROUND_STRETCH)) { pixmapx = 0; pixmapy = 0; } else if(wp->bgpixmapflags & GR_BACKGROUND_CENTER) { if(pm->width >= wp->width) pixmapx = 0; else pixmapx = (wp->width - pm->width) / 2; if(pm->height >= wp->height) pixmapy = 0; else pixmapy = (wp->height - pm->height) / 2; } else { /* GR_BACKGROUND_TILE (default)*/ GsWpTileBackgroundPixmap(wp, pm, x, y, width, height); return; } if(pm->width > wp->width) pmwidth = wp->width; else pmwidth = pm->width; if(pm->height > wp->height) pmheight = wp->height; else pmheight = pm->height; if(x > pixmapx) { destx = x; fromx = x - pixmapx; destwidth = pixmapx + pmwidth - x; } else { destx = pixmapx; fromx = 0; destwidth = x + width - pixmapx; } if(y > pixmapy) { desty = y; fromy = y - pixmapy; destheight = pixmapy + pmheight - desty; } else { desty = pixmapy; fromy = 0; destheight = y + height - pixmapy; } if(destwidth > 0 && destheight > 0) { if (wp->bgpixmapflags & GR_BACKGROUND_STRETCH) { GdStretchBlit(wp->psd, destx + wp->x, desty + wp->y, destwidth, destheight, pm->psd, fromx, fromy, pm->width, pm->height, MWROP_COPY); } else GdBlit(wp->psd, destx + wp->x, desty + wp->y, destwidth, destheight, pm->psd, fromx, fromy, MWROP_COPY); } if(wp->bgpixmapflags & (GR_BACKGROUND_TRANS|GR_BACKGROUND_STRETCH)) return; /* Fill in the gaps around the pixmap */ if(x < pixmapx) { fillwidth = pixmapx - x; if(fillwidth > width) fillwidth = width; fillheight = height; GdFillRect(wp->psd, wp->x + x, wp->y + y, fillwidth,fillheight); } if((x + width) > (pixmapx + pmwidth)) { fillwidth = (x + width) - (pixmapx + pmwidth); if(fillwidth > width) fillwidth = width; fillheight = height; if(x < (pixmapx + pmwidth)) destx = pixmapx + pmwidth + wp->x; else destx = x + wp->x; GdFillRect(wp->psd, destx, wp->y + y, fillwidth, fillheight); } if(y < pixmapy) { fillheight = pixmapy - y; if(fillheight > height) fillheight = height; if(x < pixmapx) destx = pixmapx + wp->x; else destx = x + wp->x; if((x + width) > (pixmapx + pmwidth)) fillwidth = pixmapx + pmwidth - destx; else fillwidth = x + width - destx; if((fillwidth > 0) && (fillheight > 0)) { GdFillRect(wp->psd, destx, wp->y + y, fillwidth, fillheight); } } if((y + height) > (pixmapy + pmheight)) { fillheight = (y + height) - (pixmapy + pmheight); if(fillheight > height) fillheight = height; if(x < pixmapx) destx = pixmapx + wp->x; else destx = x + wp->x; if(y < (pixmapy + pmheight)) desty = pixmapy + pmheight + wp->y; else desty = y + wp->y; if((x + width) > (pixmapx + pmwidth)) fillwidth = pixmapx + pmwidth - destx; else fillwidth = x + width - destx; if((fillwidth > 0) && (fillheight > 0)) { GdFillRect(wp->psd, destx, desty, fillwidth,fillheight); } }}/* * Draw a tiled pixmap window background. */void GsWpTileBackgroundPixmap(GR_WINDOW *wp, GR_PIXMAP *pm, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height){ GR_COORD tilex = 0, tiley = 0, fromx, fromy, cx, cy; GR_SIZE destwidth, destheight, pmwidth, pmheight, cwidth, cheight; if(pm->width > wp->width) pmwidth = wp->width; else pmwidth = pm->width; if(pm->height > wp->height) pmheight = wp->height; else pmheight = pm->height; for(;tiley < wp->height; tiley += pmheight, tilex = 0) { if(tiley > (y + height)) continue; if(y > (tiley + pmheight)) continue; if((tiley + pmheight) > wp->height) destheight = wp->height - tiley; else destheight = pmheight; for(;tilex < wp->width; tilex += pmwidth) { if(tilex > (x + width)) continue; if(x > (tilex + pmwidth)) continue; if((tilex + pmwidth) > wp->width) destwidth = wp->width - tilex; else destwidth = pmwidth; if((tilex >= x) && ((tilex + destwidth)<=(x + width))) { fromx = 0; cx = tilex + wp->x; cwidth = destwidth; } else { if(x > tilex) { fromx = x - tilex; cwidth = destwidth - fromx; } else { fromx = 0; cwidth = x + width - tilex; } if(cwidth > width) cwidth = width; if(cwidth > destwidth) cwidth = destwidth; cx = wp->x + tilex + fromx; } if((tiley >= y)&&((tiley + destheight)<=(y + height))) { fromy = 0; cy = tiley + wp->y; cheight = destheight; } else { if(y > tiley) { fromy = y - tiley; cheight = destheight - fromy; } else { fromy = 0; cheight = y + height - tiley; } if(cwidth > width) cwidth = width; if(cheight > destheight) cheight = destheight; cy = wp->y + tiley + fromy; } if((cwidth > 0) && (cheight > 0)) { GdBlit(wp->psd, cx, cy, cwidth, cheight, pm->psd, fromx, fromy, MWROP_COPY); } } }}/* * Clear the specified area of a window and possibly make an exposure event. * This sets the area window to its background color or pixmap. If the * exposeflag is nonzero, then this also creates an exposure event for the * window. */voidGsWpClearWindow(GR_WINDOW *wp, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height, GR_BOOL exposeflag){ if (wp->unmapcount || !wp->output) return; /* * Reduce the arguments so that they actually lie within the window. */ if (x < 0) { width += x; x = 0; } if (y < 0) { height += y; y = 0; } if (x + width > wp->width) width = wp->width - x; if (y + height > wp->height) height = wp->height - y; /* * Now see if the region is really in the window. If not, then * do nothing. */ if ((x >= wp->width) || (y >= wp->height) || (width <= 0) || (height <= 0)) return; /* * Draw the background of the window. * Invalidate the current graphics context since * we are changing the foreground color and mode. */ GsSetClipWindow(wp, NULL, 0); curgcp = NULL; if (!(wp->props & GR_WM_PROPS_NOBACKGROUND)) { GdSetMode(GR_MODE_COPY); GdSetForeground(GdFindColor(wp->background)); if (wp->bgpixmap) { GsWpDrawBackgroundPixmap(wp, wp->bgpixmap, x, y, width, height); } else { GdFillRect(wp->psd, wp->x + x, wp->y + y, width,height); } } /* * Now do the exposure if required. */ if (exposeflag) GsDeliverExposureEvent(wp, x, y, width, height);}/* * Handle the exposing of the specified absolute region of the screen, * starting with the specified window. That window and all of its * children will be redrawn and/or exposure events generated if they * overlap the specified area. This is a recursive routine. */voidGsExposeArea(GR_WINDOW *wp, GR_COORD rootx, GR_COORD rooty, GR_SIZE width, GR_SIZE height, GR_WINDOW *stopwp){ if (!wp->output || wp->unmapcount || wp == stopwp) return; /* * First see if the area overlaps the window including the border. * If not, then there is nothing more to do. */ if ((rootx >= wp->x + wp->width + wp->bordersize) || (rooty >= wp->y + wp->height + wp->bordersize) || (rootx + width <= wp->x - wp->bordersize) || (rooty + height <= wp->y - wp->bordersize)) return; /* * The area does overlap the window. See if the area overlaps * the border, and if so, then redraw it. */ if ((rootx < wp->x) || (rooty < wp->y) || (rootx + width > wp->x + wp->width) || (rooty + height > wp->y + wp->height)) GsDrawBorder(wp); /* * Now clear the window itself in the specified area, * which might cause an exposure event. */ GsWpClearWindow(wp, rootx - wp->x, rooty - wp->y, width, height, GR_TRUE); /* * Now do the same for all the children. */ for (wp = wp->children; wp; wp = wp->siblings) GsExposeArea(wp, rootx, rooty, width, height, stopwp);}/* * Draw the border of a window if there is one. * Note: To allow the border to be drawn with the correct clipping, * we temporarily grow the size of the window to include the border. */void GsDrawBorder(GR_WINDOW *wp){ GR_COORD lminx; /* left edge minimum x */ GR_COORD rminx; /* right edge minimum x */ GR_COORD tminy; /* top edge minimum y */ GR_COORD bminy; /* bottom edge minimum y */ GR_COORD topy; /* top y value of window */ GR_COORD boty; /* bottom y value of window */ GR_SIZE width; /* original width of window */ GR_SIZE height; /* original height of window */ GR_SIZE bs; /* border size */ bs = wp->bordersize; if (bs <= 0) return; width = wp->width; height = wp->height; lminx = wp->x - bs; rminx = wp->x + width; tminy = wp->y - bs; bminy = wp->y + height;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -