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 8/9) Message-ID: <999@pdact.pd.necisa.oz.au> Date: 22 Apr 91 00:58:19 GMT Organization: NEC Information Systems Australia, Canberra Lines: 1568 #! /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_func.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 top level routines to execute client functions. X * These functions are the server side of the client GrXXXX functions. X * Clients should not call these GsXXXX functions, but should only call X * the GrXXXX functions. In this way, when the server becomes a separate X * process, the client code will not need changes. X * X * When the server is its own process, these functions will be called by X * a dispatcher routine which can read messages from multiple clients. X * The dispatcher should set the curclient variable to the client which X * is being executed, and the curfunc variable to the current function name. X * Then the setting of curfunc throughout this file can be removed. X */ X#include X#include "graph_serv.h" X X X/* X * Open a connection from a new client to the server. X * This returns the first resource id to be allocated by the client. X * On an error, zero is returned. X */ XGR_ID XGsOpen() X{ X curfunc = "GrOpen"; /* temporary */ X X if (GsInitialize()) X return 0; X X curclient = &clients[0]; X curclient->num = 1; X curclient->infd = -1; /* not used yet */ X curclient->outfd = -1; X curclient->allocid = GR_ID_BASE(curclient->num); X curclient->errorevent.type = GR_EVENT_TYPE_NONE; X curclient->eventhead = NULL; X curclient->eventhead = NULL; X X return curclient->allocid; X} X X X/* X * Close the connection to the server. X */ Xvoid XGsClose() X{ X curfunc = "GrClose"; /* temporary */ X X /* MUST RELEASE ALL RESOURCES ALLOCATED BY THIS CLIENT */ X X curclient->num = 0; X curclient->infd = -1; /* not used yet */ X curclient->outfd = -1; X X GsTerminate(); X} X X X/* X * Flush graphics to the device. X */ Xvoid XGsFlush() X{ X curfunc = "GrFlush"; /* temporary */ X X GdFlush(); X} X X X/* X * Return information about the screen for clients to use. X */ Xvoid XGsGetScreenInfo(sip) X GR_SCREEN_INFO *sip; /* pointer to screen info */ X{ X curfunc = "GrGetScreenInfo"; /* temporary */ X X *sip = sinfo; X} X X X/* X * Return the size of a text string for the font in a graphics context. X * This is the width of the string, the height of the string, X * and the height above the bottom of the font of the baseline for the font. X */ Xvoid XGsGetGCTextSize(gc, cp, len, retwidth, retheight, retbase) X GR_GC_ID gc; /* graphics context containing font */ X GR_CHAR *cp; /* address of text string */ X GR_SIZE len; /* length of text string */ X GR_SIZE *retwidth; /* returned width of string */ X GR_SIZE *retheight; /* returned height of string */ X GR_SIZE *retbase; /* returned height of baseline */ X{ X GR_GC *gcp; /* graphics context */ X GR_FONT_INFO *fip; /* current font info */ X X curfunc = "GrGCTextSize"; /* temporary */ X X gcp = GsFindGC(gc); X if (gcp == NULL) { X *retwidth = 0; X *retheight = 1; X *retbase = 0; X return; X } X X fip = &curfont; X if (fip->font != gcp->font) X GdGetFontInfo(gcp->font, fip); X X *retheight = fip->height; X *retbase = fip->baseline; X if (fip->fixed) { X *retwidth = fip->maxwidth * len; X return; X } X X *retwidth = 0; X while (len-- > 0) X *retwidth += fip->widths[*cp++]; X} X X X/* X * Return the next waiting event for a client, or wait for one if there X * is none yet. The event is copied into the specified structure, and X * then is moved from the event queue to the free event queue. If there X * is an error event waiting, it is delivered before any other events. X */ Xvoid XGsGetNextEvent(ep) X GR_EVENT *ep; /* pointer to element to return */ X{ X GR_EVENT_LIST *elp; /* current element list */ X X curfunc = "GrGetNextEvent"; /* temporary */ X X if (curclient->errorevent.type == GR_EVENT_TYPE_ERROR) { X *((GR_EVENT_ERROR *) ep) = curclient->errorevent; X curclient->errorevent.type = GR_EVENT_TYPE_NONE; X return; X } X X if (curclient->eventhead == NULL) X GsCheckEvent(GR_TRUE); X if (curclient->eventhead == NULL) { X ep->type = GR_EVENT_TYPE_NONE; X return; X } X elp = curclient->eventhead; X *ep = elp->event; X curclient->eventhead = elp->next; X if (curclient->eventhead == NULL) X curclient->eventtail = NULL; X elp->next = eventfree; X eventfree = elp; X} X X X/* X * Peek at the event queue for the current client to see if there are any X * outstanding events. Returns the event at the head of the queue, or X * else a null event type. The event is still left in the queue, however. X */ Xvoid XGsPeekEvent(ep) X GR_EVENT *ep; /* pointer to element to return */ X{ X curfunc = "GrPeekEvent"; /* temporary */ X X if (curclient->errorevent.type == GR_EVENT_TYPE_ERROR) { X *((GR_EVENT_ERROR *) ep) = curclient->errorevent; X return; X } X X if (curclient->eventhead == NULL) X GsCheckEvent(GR_FALSE); X X if (curclient->eventhead) { X *ep = curclient->eventhead->event; X return; X } X ep->type = GR_EVENT_TYPE_NONE; X} X X X/* X * Return information about a window id. X */ Xvoid XGsGetWindowInfo(wid, infoptr) X GR_WINDOW_ID wid; /* window to find out about */ X GR_WINDOW_INFO *infoptr; /* pointer to returned data */ X{ X GR_WINDOW *wp; /* window structure */ X GR_EVENT_CLIENT *evp; /* event-client structure */ X X curfunc = "GrGetWindowInfo"; /* temporary */ X X /* X * Find the window manually so that an error is not generated. X */ X for (wp = listwp; wp && (wp->id != wid); wp = wp->next) X continue; X X if (wp == NULL) { X infoptr->wid = 0; X return; X } X X infoptr->wid = wid; X infoptr->parent = wp->parent->id; X infoptr->child = wp->children->id; X infoptr->sibling = wp->siblings->id; X infoptr->mapped = wp->mapped; X infoptr->unmapcount = wp->unmapcount; X infoptr->inputonly = !wp->output; X infoptr->x = wp->x; X infoptr->y = wp->y; X infoptr->width = wp->width; X infoptr->height = wp->height; X infoptr->bordersize = wp->bordersize; X infoptr->bordercolor = wp->bordercolor; X infoptr->background = wp->background; X infoptr->eventmask = 0; X X for (evp = wp->eventclients; evp; evp = evp->next) { X if (evp->client == curclient) X infoptr->eventmask = evp->eventmask; X } X} X X X/* X * Destroy an existing window and all of its children. X */ Xvoid XGsDestroyWindow(wid) X GR_WINDOW_ID wid; /* window to destroy */ X{ X GR_WINDOW *wp; /* window structure */ X X curfunc = "GrDestroyWindow"; /* temporary */ X X wp = GsFindWindow(wid); X if (wp) X GsWpDestroyWindow(wp); X} X X X/* X * Raise a window to the highest level among its siblings. X */ Xvoid XGsRaiseWindow(wid) X GR_WINDOW_ID wid; /* window to be raised */ X{ X GR_WINDOW *wp; /* window structure */ X GR_WINDOW *prevwp; /* previous window pointer */ X GR_BOOL overlap; /* TRUE if there was overlap */ X X curfunc = "GrRaiseWindow"; /* temporary */ X X wp = GsFindWindow(wid); X if ((wp == NULL) || (wp == rootwp)) X return; X X /* X * If this is already the highest window then we are done. X */ X prevwp = wp->parent->children; X if (prevwp == wp) X return; X X /* X * Find the sibling just before this window so we can unlink it. X * Also, determine if any sibling ahead of us overlaps the window. X * Remember that for exposure events. X */ X overlap = GR_FALSE; X while (prevwp->siblings != wp) { X overlap |= GsCheckOverlap(prevwp, wp); X prevwp = prevwp->siblings; X } X overlap |= GsCheckOverlap(prevwp, wp); X X /* X * Now unlink the window and relink it in at the front of the X * sibling chain. X */ X prevwp->siblings = wp->siblings; X wp->siblings = wp->parent->children; X wp->parent->children = wp; X X /* X * Finally redraw the window if necessary. X */ X if (overlap) { X GsDrawBorder(wp); X GsExposeArea(wp, wp->x, wp->y, wp->width, wp->height); X } X} X X X/* X * Lower a window to the lowest level among its siblings. X */ Xvoid XGsLowerWindow(wid) X GR_WINDOW_ID wid; /* window to be lowered */ X{ X GR_WINDOW *wp; /* window structure */ X GR_WINDOW *prevwp; /* previous window pointer */ X GR_WINDOW *sibwp; /* sibling window */ X GR_WINDOW *expwp; /* siblings being exposed */ X X curfunc = "GrLowerWindow"; /* temporary */ X X wp = GsFindWindow(wid); X if ((wp == NULL) || (wp == rootwp) || (wp->siblings == NULL)) X return; X X /* X * Find the sibling just before this window so we can unlink us. X */ X prevwp = wp->parent->children; X if (prevwp != wp) { X while (prevwp->siblings != wp) X prevwp = prevwp->siblings; X } X X /* X * Remember the first sibling that is after us, so we can X * generate exposure events for the remaining siblings. Then X * walk down the sibling chain looking for the last sibling. X */ X expwp = wp->siblings; X sibwp = wp; X while (sibwp->siblings) X sibwp = sibwp->siblings; X X /* X * Now unlink the window and relink it in at the end of the X * sibling chain. X */ X if (prevwp == wp) X wp->parent->children = wp->siblings; X else X prevwp->siblings = wp->siblings; X sibwp->siblings = wp; X X wp->siblings = NULL; X X /* X * Finally redraw the sibling windows which this window covered X * if they overlapped our window. X */ X while (expwp && (expwp != wp)) { X if (GsCheckOverlap(wp, expwp)) { X GsExposeArea(expwp, wp->x - wp->bordersize, X wp->y - wp->bordersize, X wp->width + wp->bordersize * 2, X wp->height + wp->bordersize * 2); X } X expwp = expwp->siblings; X } X} X X X/* X * Move the window to the specified position relative to its parent. X */ Xvoid XGsMoveWindow(wid, x, y) X GR_WINDOW_ID wid; /* window to be lowered */ X GR_COORD x; /* new relative x position */ X GR_COORD y; /* new relative y position */ X{ X GR_WINDOW *wp; /* window structure */ X X curfunc = "GrMoveWindow"; /* temporary */ X X wp = GsFindWindow(wid); X if (wp == NULL) X return; X if (wp == rootwp) { X GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wid); X return; X } X X x += wp->parent->x; X y += wp->parent->y; X X if ((wp->x == x) && (wp->y == y)) X return; X X if (wp->unmapcount || !wp->output) { X wp->x = x; X wp->y = y; X return; X } X X /* X * This should be optimized to not require redrawing of the window X * when possible. X */ X GsWpUnmapWindow(wp); X wp->x = x; X wp->y = y; X GsWpMapWindow(wp); X} X X X/* X * Resize the window to be the specified size. X */ Xvoid XGsResizeWindow(wid, width, height) X GR_WINDOW_ID wid; /* window to be lowered */ X GR_SIZE width; /* new width of window */ X GR_SIZE height; /* new height of window */ X{ X GR_WINDOW *wp; /* window structure */ X X curfunc = "GrResizeWindow"; /* temporary */ X X wp = GsFindWindow(wid); X if (wp == NULL) X return; X if (wp == rootwp) { X GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wid); X return; X } X if ((width <= 0) || (height <= 0)) { X GsError(GR_ERROR_BAD_WINDOW_SIZE, wid); X return; X } X X if ((wp->width == width) && (wp->height == height)) X return; X X if (wp->unmapcount || !wp->output) { X wp->width = width; X wp->height = height; X return; X } X X /* X * This should be optimized to not require redrawing of the window X * when possible. X */ X GsWpUnmapWindow(wp); X wp->width = width; X wp->height = height; X GsWpMapWindow(wp); X} X X X/* X * Allocate a new GC with default parameters. X * The GC is owned by the current client. X */ XGR_GC_ID XGsNewGC() X{ X GR_GC *gcp; X X curfunc = "GrNewGC"; /* temporary */ X X /* X * Increment this before checking for errors since the client X * always increments his. X */ X curclient->allocid++; X X gcp = (GR_GC *) malloc(sizeof(GR_GC)); X if (gcp == NULL) { X GsError(GR_ERROR_MALLOC_FAILED, 0); X return 0; X } X X gcp->id = curclient->allocid; X gcp->mode = GR_MODE_SET; X gcp->font = 0; X gcp->foreground = sinfo.white; X gcp->background = sinfo.black; X gcp->usebackground = GR_TRUE; X gcp->changed = GR_TRUE; X gcp->next = listgcp; X X listgcp = gcp; X X return gcp->id; X} X X X/* X * Destroy an existing graphics context. X */ Xvoid XGsDestroyGC(gc) X GR_GC_ID gc; /* graphics context to destroy */ X{ X GR_GC *gcp; /* graphics context */ X GR_GC *prevgcp; /* previous graphics context */ X X curfunc = "GrDestroyGC"; /* temporary */ X X gcp = GsFindGC(gc); X if (gcp == NULL) X return; X X if (gc == cachegcid) { X cachegcid = 0; X cachegcp = NULL; X } X X if (listgcp == gcp) { X listgcp = gcp->next; X free(gcp); X return; X } X X prevgcp = listgcp; X while (prevgcp->next != gcp) X prevgcp = prevgcp->next; X X prevgcp->next = gcp->next; X free(gcp); X} X X X/* X * Allocate a new GC which is a copy of another one. X * The GC is owned by the current client. X */ XGR_GC_ID XGsCopyGC(gc) X GR_GC_ID gc; /* GC to be copied */ X{ X GR_GC *oldgcp; /* old graphics context */ X GR_GC *gcp; /* new graphics context */ X X curfunc = "GrCopyGC"; /* temporary */ X X /* X * Increment this before checking for errors since the client X * always increments his. X */ X curclient->allocid++; X X oldgcp = GsFindGC(gc); X if (oldgcp == NULL) X return 0; X X gcp = (GR_GC *) malloc(sizeof(GR_GC)); X if (gcp == NULL) { X GsError(GR_ERROR_MALLOC_FAILED, 0); X return 0; X } X X /* X * Copy all the old gcp values into the new one, except allocate X * a new id for it and link it into the list of GCs. X */ X *gcp = *oldgcp; X gcp->id = curclient->allocid; X gcp->changed = GR_TRUE; X gcp->next = listgcp; X listgcp = gcp; X X return gcp->id; X} X X X/* X * Return information about the specified graphics context. X */ Xvoid XGsGetGCInfo(gcid, gcip) X GR_GC_ID gcid; /* graphics context */ X GR_GC_INFO *gcip; /* address of graphics context info */ X{ X GR_GC *gcp; X X /* X * Find the GC manually so that an error is not generated. X */ X for (gcp = listgcp; gcp && (gcp->id != gcid); gcp = gcp->next) X continue; X X if (gcp == NULL) { X gcip->gcid = 0; X return; X } X X gcip->gcid = gcid; X gcip->mode = gcp->mode; X gcip->font = gcp->font; X gcip->foreground = gcp->foreground; X gcip->background = gcp->background; X gcip->usebackground = gcp->usebackground; X} X X X/* X * Return useful information about the specified font. X */ Xvoid XGsGetFontInfo(font, fip) X GR_FONT font; /* font number */ X GR_FONT_INFO *fip; /* address of font info */ X{ X /* X * See if the font is built-in or not. Someday for non-builtin X * fonts, we can return something for them. X */ X if (font >= sinfo.fonts) { X fip->font = 0; X return; X } X GdGetFontInfo(font, fip); X} X X X/* X * Select events for a window for this client. X * The events are a bitmask for the events desired. X */ Xvoid XGsSelectEvents(wid, eventmask) X GR_WINDOW_ID wid; /* window id */ X GR_EVENT_MASK eventmask; /* mask of events wanted */ X{ X GR_WINDOW *wp; /* window structure */ X GR_EVENT_CLIENT *evp; /* event-client structure */ X X curfunc = "GrSelectEvents"; /* temporary */ X X wp = GsFindWindow(wid); X if (wp == NULL) X return; X X /* X * See if this client is already in the event client list. X * If so, then just replace the events he is selecting for. X */ X for (evp = wp->eventclients; evp; evp = evp->next) { X if (evp->client == curclient) { X evp->eventmask = eventmask; X return; X } X } X X /* X * A new client for this window, so allocate a new event client X * structure and insert it into the front of the list in the window. X */ X evp = (GR_EVENT_CLIENT *) malloc(sizeof(GR_EVENT_CLIENT)); X if (evp == NULL) { X GsError(GR_ERROR_MALLOC_FAILED, wid); X return; X } X X evp->client = curclient; X evp->eventmask = eventmask; X evp->next = wp->eventclients; X wp->eventclients = evp; X} X X X/* X * Allocate a new window which is a child of the specified window. X * The window inherits the cursor of the parent window. X * The window is owned by the current client. X */ XGR_WINDOW_ID XGsNewWindow(parent, x, y, width, height, bordersize, background, bordercolor) X GR_WINDOW_ID parent; /* parent id */ X GR_COORD x; /* x position relative to parent */ X GR_COORD y; /* y position relative to parent */ X GR_SIZE width; /* width */ X GR_SIZE height; /* height */ X GR_SIZE bordersize; /* size of border */ X GR_COLOR background; /* background color */ X GR_COLOR bordercolor; /* border color */ X{ X GR_WINDOW *pwp; /* parent window */ X GR_WINDOW *wp; /* new window */ X X curfunc = "GrNewWindow"; /* temporary */ X X /* X * Increment this before checking for errors since the client X * always increments his. X */ X curclient->allocid++; X X if ((width <= 0) || (height <= 0) || (bordersize < 0)) { X GsError(GR_ERROR_BAD_WINDOW_SIZE, 0); X return 0; X } X X pwp = GsFindWindow(parent); X if (pwp == NULL) X return 0; X X if (!pwp->output) { X GsError(GR_ERROR_INPUT_ONLY_WINDOW, pwp->id); X return 0; X } X X wp = (GR_WINDOW *) malloc(sizeof(GR_WINDOW)); X if (wp == NULL) { X GsError(GR_ERROR_MALLOC_FAILED, 0); X return 0; X } X X wp->id = curclient->allocid; X wp->parent = pwp; X wp->children = NULL; X wp->siblings = pwp->children; X wp->next = listwp; X wp->x = pwp->x + x; X wp->y = pwp->y + y; X wp->width = width; X wp->height = height; X wp->bordersize = bordersize; X wp->background = background; X wp->bordercolor = bordercolor; X wp->nopropmask = 0; X wp->eventclients = NULL; X wp->cursor = pwp->cursor; X wp->mapped = GR_FALSE; X wp->unmapcount = pwp->unmapcount + 1; X wp->output = GR_TRUE; X X wp->cursor->usecount++; X pwp->children = wp; X listwp = wp; X X return wp->id; X} X X X/* X * Allocate a new input-only window which is a child of the specified window. X * Such a window is invisible, cannot be drawn into, and is only used to X * return events. The window inherits the cursor of the parent window. X * The window is owned by the current client. X */ XGR_WINDOW_ID XGsNewInputWindow(parent, x, y, width, height) X GR_WINDOW_ID parent; /* parent id */ X GR_COORD x; /* x position relative to parent */ X GR_COORD y; /* y position relative to parent */ X GR_SIZE width; /* width */ X GR_SIZE height; /* height */ X{ X GR_WINDOW *pwp; /* parent window */ X GR_WINDOW *wp; /* new window */ X X curfunc = "GrNewInputWindow"; /* temporary */ X X /* X * Increment this before checking for errors since the client X * always increments his. X */ X curclient->allocid++; X X if ((width <= 0) || (height <= 0)) { X GsError(GR_ERROR_BAD_WINDOW_SIZE, 0); X return 0; X } X X pwp = GsFindWindow(parent); X if (pwp == NULL) X return 0; X X wp = (GR_WINDOW *) malloc(sizeof(GR_WINDOW)); X if (wp == NULL) { X GsError(GR_ERROR_MALLOC_FAILED, 0); X return 0; X } X X wp->id = curclient->allocid; X wp->parent = pwp; X wp->children = NULL; X wp->siblings = pwp->children; X wp->next = listwp; X wp->x = pwp->x + x; X wp->y = pwp->y + y; X wp->width = width; X wp->height = height; X wp->bordersize = 0; X wp->background = sinfo.black; X wp->bordercolor = sinfo.black; X wp->nopropmask = 0; X wp->eventclients = NULL; X wp->cursor = pwp->cursor; X wp->mapped = GR_FALSE; X wp->unmapcount = pwp->unmapcount + 1; X wp->output = GR_FALSE; X X wp->cursor->usecount++; X pwp->children = wp; X listwp = wp; X X return wp->id; X} X X X/* X * Map the window to make it (and possibly its children) visible on the screen. X */ Xvoid XGsMapWindow(wid) X GR_WINDOW_ID wid; /* window to be mapped */ X{ X GR_WINDOW *wp; /* window structure */ X X curfunc = "GrMapWindow"; /* temporary */ X X wp = GsFindWindow(wid); X if ((wp == NULL) || wp->mapped) X return; X X wp->mapped = GR_TRUE; X X GsWpMapWindow(wp); X} X X X/* X * Unmap the window to make it and its children invisible on the screen. X */ Xvoid XGsUnmapWindow(wid) X GR_WINDOW_ID wid; /* window to be unmapped */ X{ X GR_WINDOW *wp; /* window structure */ X X curfunc = "GrUnmapWindow"; /* temporary */ X X wp = GsFindWindow(wid); X if ((wp == NULL) || !wp->mapped) X return; X X GsWpUnmapWindow(wp); X X wp->mapped = GR_FALSE; X} X X X/* X * Clear the specified window. X * This sets the window to its background color. X * If the exposeflag is nonzero, then this also creates an exposure X * event for the window. X */ Xvoid XGsClearWindow(wid, exposeflag) X GR_WINDOW_ID wid; /* window id */ X GR_BOOL exposeflag; /* nonzero to cause an exposure */ X{ X GR_WINDOW *wp; /* window structure */ X X curfunc = "GrClearWindow"; /* temporary */ X X wp = GsPrepareWindow(wid); X if (wp) X GsWpClearWindow(wp, 0, 0, wp->width, wp->height, exposeflag); X} X X X/* X * Set the focus to a particular window. X * This makes keyboard events only visible to that window or children of it, X * depending on the pointer location. X */ Xvoid XGsSetFocus(wid) X GR_WINDOW_ID wid; /* window id */ X{ X GR_WINDOW *wp; /* window structure */ X X curfunc = "GrSetFocus"; /* temporary */ X X wp = GsFindWindow(wid); X if (wp == NULL) X return; X X if (wp->unmapcount) { X GsError(GR_ERROR_UNMAPPED_FOCUS_WINDOW, wid); X return; X } X X focusfixed = (wp != rootwp); X GsWpSetFocus(wp); X} X X X/* X * Set the border of a window to the specified color. X */ Xvoid XGsSetBorderColor(wid, color) X GR_WINDOW_ID wid; /* window id */ X GR_COLOR color; /* color for border */ X{ X GR_WINDOW *wp; /* window structure */ X X curfunc = "GrSetBorderColor"; /* temporary */ X X wp = GsFindWindow(wid); X if ((wp == NULL) || (wp->bordercolor == color) || X (wp->bordersize == 0)) X return; X X wp->bordercolor = color; X if (wp->unmapcount == 0) X GsDrawBorder(wp); X} X X X/* X * Specify a cursor for a window. X * This cursor will only be used within that window, and by default X * for its new children. If the cursor is currently within this X * window, it will be changed to the new one immediately. X */ Xvoid XGsSetCursor(wid, width, height, hotx, hoty, foreground, background, X fgbitmap, bgbitmap) X X GR_WINDOW_ID wid; /* window id to set cursor for */ X GR_SIZE width; /* width of cursor */ X GR_SIZE height; /* height of cursor */ X GR_COORD hotx; /* relative x position of hot spot */ X GR_COORD hoty; /* relative y position of hot spot */ X GR_COLOR foreground; /* foreground color of cursor */ X GR_COLOR background; /* background color of cursor */ X GR_BITMAP *fgbitmap; /* foreground bitmap */ X GR_BITMAP *bgbitmap; /* background bitmap */ X{ X GR_WINDOW *wp; /* window structure */ X GR_CURSOR *cp; /* cursor structure */ X int bytes; /* number of bytes of bitmap */ X X curfunc = "GrSetCursor"; /* temporary */ X X wp = GsFindWindow(wid); X if (wp == NULL) X return; X X /* X * Make sure the size of the bitmap is reasonable. X */ X if ((width <= 0) || (width > GR_MAX_CURSOR_SIZE) || X (height <= 0) || (height > GR_MAX_CURSOR_SIZE)) X { X GsError(GR_ERROR_BAD_CURSOR_SIZE, 0); X return; X } X bytes = GR_BITMAP_SIZE(width, height) * sizeof(GR_BITMAP); X X /* X * See if the window is using a shared cursor definition. X * If so, then allocate a new private one, otherwise reuse it. X */ X cp = wp->cursor; X if (cp->usecount-- > 1) { X cp = (GR_CURSOR *) malloc(sizeof(GR_CURSOR)); X if (cp == NULL) { X GsError(GR_ERROR_MALLOC_FAILED, 0); X return; X } X } X X cp->usecount = 1; X cp->width = width; X cp->height = height; X cp->hotx = hotx; X cp->hoty = hoty; X cp->foreground = foreground; X cp->background = background; X memcpy((char *) cp->fgbitmap, (char *) fgbitmap, bytes); X memcpy((char *) cp->bgbitmap, (char *) bgbitmap, bytes); X wp->cursor = cp; X X /* X * If this was the current cursor, then draw the new one. X */ X if (cp == curcursor) { X GdSetCursor(cp->width, cp->height, cp->foreground, X cp->background, cp->fgbitmap, cp->bgbitmap); X GdMoveCursor(cursorx - cp->hotx, cursory - cp->hoty); X } X} X X X/* X * Move the cursor to the specified absolute screen coordinates. X * The coordinates are that of the defined hot spot of the cursor. X * The cursor's appearance is changed to that defined for the window X * in which the cursor is moved to. In addition, mouse enter, mouse X * exit, focus in, and focus out events are generated if necessary. X */ Xvoid XGsMoveCursor(x, y) X GR_COORD x; /* new x position of cursor */ X GR_COORD y; /* new y position of cursor */ X{ X curfunc = "GrMoveCursor"; /* temporary */ X X /* X * Move the cursor only if necessary, offsetting it to X * place the hot spot at the specified coordinates. X */ X if ((x != cursorx) || (y != cursory)) { X GdMoveCursor(x - curcursor->hotx, y - curcursor->hoty); X cursorx = x; X cursory = y; X } X X /* X * Now check to see which window the mouse is in, whether or X * not the cursor shape should be changed, and whether or not X * the input focus window should be changed. X */ X GsCheckMouseWindow(); X GsCheckFocusWindow(); X GsCheckCursor(); X} X X X/* X * Set the foreground color in a graphics context. X */ Xvoid XGsSetGCForeground(gc, foreground) X GR_GC_ID gc; /* graphics context id */ X GR_COLOR foreground; /* foreground color */ X{ X GR_GC *gcp; /* graphics context */ X X curfunc = "GrSetGCForeground"; /* temporary */ X X gcp = GsFindGC(gc); X if ((gcp == NULL) || (gcp->foreground == foreground)) X return; X gcp->foreground = foreground; X gcp->changed = GR_TRUE; X} X X X/* X * Set the background color in a graphics context. X */ Xvoid XGsSetGCBackground(gc, background) X GR_GC_ID gc; /* graphics context id */ X GR_COLOR background; /* background color */ X{ X GR_GC *gcp; /* graphics context */ X X curfunc = "GrSetGCBackground"; /* temporary */ X X gcp = GsFindGC(gc); X if ((gcp == NULL) || (gcp->background == background)) X return; X gcp->background = background; X gcp->changed = GR_TRUE; X} X X X/* X * Set whether or not the background color is drawn in bitmaps and text. X */ Xvoid XGsSetGCUseBackground(gc, flag) X GR_GC_ID gc; /* graphics context id */ X GR_BOOL flag; /* TRUE if background is drawn */ X{ X GR_GC *gcp; /* graphics context */ X X curfunc = "GrSetGCUseBackground"; /* temporary */ X X flag = (flag != 0); X gcp = GsFindGC(gc); X if ((gcp == NULL) || (gcp->usebackground == flag)) X return; X gcp->usebackground = flag; X gcp->changed = GR_TRUE; X} X X X/* X * Set the drawing mode in a graphics context. X */ Xvoid XGsSetGCMode(gc, mode) X GR_GC_ID gc; /* graphics context id */ X GR_MODE mode; /* drawing mode */ X{ X GR_GC *gcp; /* graphics context */ X X curfunc = "GrSetGCMode"; /* temporary */ X X gcp = GsFindGC(gc); X if ((gcp == NULL) || (gcp->mode == mode)) X return; X if (mode > GR_MAX_MODE) { X GsError(GR_ERROR_BAD_DRAWING_MODE, gc); X return; X } X gcp->mode = mode; X gcp->changed = GR_TRUE; X} X X X/* X * Set the text font in a graphics context. X */ Xvoid XGsSetGCFont(gc, font) X GR_GC_ID gc; /* graphics context id */ X GR_FONT font; /* text font */ X{ X GR_GC *gcp; /* graphics context */ X X curfunc = "GrSetGCFont"; /* temporary */ X X gcp = GsFindGC(gc); X if ((gcp == NULL) || (gcp->font == font)) X return; X gcp->font = font; X gcp->changed = GR_TRUE; X} X X X/* X * Draw a line in the specified drawable using the specified graphics context. X */ Xvoid XGsLine(id, gc, x1, y1, x2, y2) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COORD x1; X GR_COORD y1; X GR_COORD x2; X GR_COORD y2; X{ X GR_WINDOW *wp; X GR_PIXMAP *pmp; X X curfunc = "GrLine"; /* temporary */ X X switch (GsPrepareDrawing(id, gc, &wp, &pmp)) { X case GR_DRAW_TYPE_WINDOW: X GdLine(wp->x + x1, wp->y + y1, wp->x + x2, wp->y + y2); X break; X } X} X X X/* X * Draw the boundary of a rectangle in the specified drawable using the X * specified graphics context. X */ Xvoid XGsRect(id, gc, x, y, width, height) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COORD x; X GR_COORD y; X GR_SIZE width; X GR_SIZE height; X{ X GR_WINDOW *wp; X GR_PIXMAP *pmp; X X curfunc = "GrRect"; /* temporary */ X X switch (GsPrepareDrawing(id, gc, &wp, &pmp)) { X case GR_DRAW_TYPE_WINDOW: X GdRect(wp->x + x, wp->y + y, width, height); X break; X } X} X X X/* X * Fill a rectangle in the specified drawable using the specified X * graphics context. X */ Xvoid XGsFillRect(id, gc, x, y, width, height) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COORD x; X GR_COORD y; X GR_SIZE width; X GR_SIZE height; X{ X GR_WINDOW *wp; X GR_PIXMAP *pmp; X X curfunc = "GrFillRect"; /* temporary */ X X switch (GsPrepareDrawing(id, gc, &wp, &pmp)) { X case GR_DRAW_TYPE_WINDOW: X GdFillRect(wp->x + x, wp->y + y, width, height); X break; X } X} X X X/* X * Draw the boundary of an ellipse in the specified drawable with X * the specified graphics context. X */ Xvoid XGsEllipse(id, gc, x, y, rx, ry) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COORD x; X GR_COORD y; X GR_SIZE rx; X GR_SIZE ry; X{ X GR_WINDOW *wp; X GR_PIXMAP *pmp; X X curfunc = "GrEllipse"; /* temporary */ X X switch (GsPrepareDrawing(id, gc, &wp, &pmp)) { X case GR_DRAW_TYPE_WINDOW: X GdEllipse(wp->x + x, wp->y + y, rx, ry); X break; X } X} X X X/* X * Fill an ellipse in the specified drawable using the specified X * graphics context. X */ Xvoid XGsFillEllipse(id, gc, x, y, rx, ry) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COORD x; X GR_COORD y; X GR_SIZE rx; X GR_SIZE ry; X{ X GR_WINDOW *wp; X GR_PIXMAP *pmp; X X curfunc = "GrFillEllipse"; /* temporary */ X X switch (GsPrepareDrawing(id, gc, &wp, &pmp)) { X case GR_DRAW_TYPE_WINDOW: X GdFillEllipse(wp->x + x, wp->y + y, rx, ry); X break; X } X} X X X/* X * Draw a rectangular area in the specified drawable using the specified X * graphics, as determined by the specified bit map. This differs from X * rectangle drawing in that the rectangle is drawn using the foreground X * color and possibly the background color as determined by the bit map. X * Each row of bits is aligned to the next bitmap word boundary (so there X * is padding at the end of the row). The background bit values are only X * written if the usebackground flag is set in the GC. X */ Xvoid XGsBitmap(id, gc, x, y, width, height, bitmaptable) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COORD x; X GR_COORD y; X GR_SIZE width; X GR_SIZE height; X GR_BITMAP *bitmaptable; X{ X GR_WINDOW *wp; X GR_PIXMAP *pmp; X X curfunc = "GrBitmap"; /* temporary */ X X switch (GsPrepareDrawing(id, gc, &wp, &pmp)) { X case GR_DRAW_TYPE_WINDOW: X GdBitmap(wp->x + x, wp->y + y, width, height, X bitmaptable); X break; X } X} X X X/* X * Draw a rectangular area in the specified drawable using the specified X * graphics context. This differs from rectangle drawing in that the X * color values for each pixel in the rectangle are specified. The color X * values are restricted to 8 bit values. The color table is indexed X * row by row. X */ Xvoid XGsArea8(id, gc, x, y, width, height, colortable) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COORD x; X GR_COORD y; X GR_SIZE width; X GR_SIZE height; X GR_COLOR8 *colortable; X{ X GR_WINDOW *wp; X GR_PIXMAP *pmp; X X curfunc = "GrArea8"; /* temporary */ X X switch (GsPrepareDrawing(id, gc, &wp, &pmp)) { X case GR_DRAW_TYPE_WINDOW: X GdArea8(wp->x + x, wp->y + y, width, height, X colortable); X break; X } X} X X X/* X * Read the color values from the specified rectangular area of the X * specified drawable into a supplied buffer. If the drawable is a X * window which is obscured by other windows, then the returned values X * will include the values from the covering windows. Regions outside X * of the screen boundaries, or unmapped windows will return black. X */ Xvoid XGsReadArea8(id, x, y, width, height, colortable) X GR_DRAW_ID id; X GR_COORD x; X GR_COORD y; X GR_SIZE width; X GR_SIZE height; X GR_COLOR8 *colortable; X{ X GR_WINDOW *wp; X long count; X X wp = GsFindWindow(id); /* wrong, should check pixmap */ X if ((wp == NULL) || wp->unmapcount || (x >= wp->width) || X (y >= wp->height) || (x + width <= 0) || (y + height <= 0)) X { X count = width * height; X while (count-- > 0) X *colortable++ = sinfo.black; X return; X } X GdReadArea8(wp->x, wp->y, width, height, colortable); X} X X X/* X * Draw a point in the specified drawable using the specified X * graphics context. X */ Xvoid XGsPoint(id, gc, x, y) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COORD x; X GR_COORD y; X{ X GR_WINDOW *wp; X GR_PIXMAP *pmp; X X curfunc = "GrPoint"; /* temporary */ X X switch (GsPrepareDrawing(id, gc, &wp, &pmp)) { X case GR_DRAW_TYPE_WINDOW: X GdPoint(wp->x + x, wp->y + y); X break; X } X} X X X/* X * Draw a polygon in the specified drawable using the specified X * graphics context. The polygon is only complete if the first X * point is repeated at the end. X */ Xvoid XGsPoly(id, gc, count, pointtable) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COUNT count; X GR_POINT *pointtable; X{ X GR_WINDOW *wp; X GR_PIXMAP *pmp; X GR_POINT *pp; X GR_COUNT i; X X curfunc = "GrPoly"; /* temporary */ X X switch (GsPrepareDrawing(id, gc, &wp, &pmp)) { X case GR_DRAW_TYPE_WINDOW: X break; X default: X return; X } X X /* X * Here for drawing to a window. X * Relocate all the points relative to the window. X */ X pp = pointtable; X for (i = count; i-- > 0; pp++) { X pp->x += wp->x; X pp->y += wp->y; X } X X GdPoly(count, pointtable); X X /* X * The following is temporarily necessary until the server X * becomes a separate process. We don't want to change the X * user's arguments! X */ X pp = pointtable; X for (i = count; i-- > 0; pp++) { X pp->x -= wp->x; X pp->y -= wp->y; X } X} X X X/* X * Draw a filled polygon in the specified drawable using the specified X * graphics context. The last point may be a duplicate of the first X * point, but this is not required. X */ Xvoid XGsFillPoly(id, gc, count, pointtable) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COUNT count; X GR_POINT *pointtable; X{ X GR_WINDOW *wp; X GR_PIXMAP *pmp; X GR_POINT *pp; X GR_COUNT i; X X curfunc = "GrFillPoly"; /* temporary */ X X switch (GsPrepareDrawing(id, gc, &wp, &pmp)) { X case GR_DRAW_TYPE_WINDOW: X break; X default: X return; X } X X /* X * Here for drawing to a window. X * Relocate all the points relative to the window. X */ X pp = pointtable; X for (i = count; i-- > 0; pp++) { X pp->x += wp->x; X pp->y += wp->y; X } X X GdFillPoly(count, pointtable); X X /* X * The following is temporarily necessary until the server X * becomes a separate process. We don't want to change the X * user's arguments! X */ X pp = pointtable; X for (i = count; i-- > 0; pp++) { X pp->x -= wp->x; X pp->y -= wp->y; X } X} X X X/* X * Draw a text string in the specified drawable using the X * specified graphics context. X */ Xvoid XGsText(id, gc, x, y, str, count) X GR_DRAW_ID id; X GR_GC_ID gc; X GR_COORD x; X GR_COORD y; X GR_CHAR *str; X GR_COUNT count; X{ X GR_WINDOW *wp; X GR_PIXMAP *pmp; X X curfunc = "GrText"; /* temporary */ X X switch (GsPrepareDrawing(id, gc, &wp, &pmp)) { X case GR_DRAW_TYPE_WINDOW: X GdText(wp->x + x, wp->y + y, str, count); X break; X } X} X X/* END CODE */ END_OF_FILE if test 33072 -ne `wc -c <'mini-x/server/serv_func.c'`; then echo shar: \"'mini-x/server/serv_func.c'\" unpacked with wrong size! fi # end of 'mini-x/server/serv_func.c' fi echo shar: End of archive 8 \(of 9\). cp /dev/null ark8isdone 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