URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [services/] [gfx/] [mw/] [v2_0/] [src/] [nanox/] [srvfunc.c] - Rev 174
Compare with Previous | Blame | View Log
/* * Copyright (c) 1999, 2000, 2001 Greg Haerr <greg@censoft.com> * Copyright (c) 2000 Alex Holden <alex@linuxhacker.org> * Copyright (c) 1991 David I. Bell * Permission is granted to use, distribute, or modify this source, * provided that this copyright notice remains intact. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #define MWINCLUDECOLORS #include "serv.h" static int nextid = GR_ROOT_WINDOW_ID + 1; static void CheckNextEvent(GR_EVENT *ep, GR_BOOL doSelect); /* * Return information about the screen for clients to use. */ void GrGetScreenInfo(GR_SCREEN_INFO *sip) { GdGetScreenInfo(rootwp->psd, sip); /* virtual/workspace screen sizing*/ #if 0 /* force small screen for emulation purposes*/ sip->vs_width = 240; /* PDA*/ sip->vs_height = 320; sip->ws_width = 240; sip->ws_height = 298; #else /* set workspace equal to screen area minus 22 pixel taskbar*/ sip->vs_width = sip->cols; sip->vs_height = sip->rows; sip->ws_width = sip->cols; sip->ws_height = sip->rows - 22; #endif } /* * Return the size of a text string for the font in a graphics context. * This is the width of the string, the height of the string, * and the height above the bottom of the font of the baseline for the font. */ void GrGetGCTextSize(GR_GC_ID gc, void *str, int count, int flags, GR_SIZE *retwidth, GR_SIZE *retheight, GR_SIZE *retbase) { GR_GC *gcp; GR_FONT *fontp; PMWFONT pf; gcp = GsFindGC(gc); if (gcp == NULL) fontp = NULL; else fontp = GsFindFont(gcp->fontid); pf = fontp? fontp->pfont: stdfont; GdGetTextSize(pf, str, count, retwidth, retheight, retbase, flags); } #if NONETWORK /* * Return the next waiting event for a client, or wait for one if there * is none yet. The event is copied into the specified structure, and * then is moved from the event queue to the free event queue. If there * is an error event waiting, it is delivered before any other events. */ void GrGetNextEvent(GR_EVENT *ep) { GrGetNextEventTimeout(ep, 0L); } /* * Return the next event from the event queue, or * wait for a new one if one is not ready. If timeout * is nonzero, return timeout event if time elapsed. */ void GrGetNextEventTimeout(GR_EVENT *ep, GR_TIMEOUT timeout) { /* If no event ready, wait for one*/ /* Note: won't work for multiple clients*/ /* This is OK, since only static linked apps call this function*/ while(curclient->eventhead == NULL) GsSelect(timeout); CheckNextEvent(ep, GR_FALSE); } /* * Wait until an event is available for a client, and then peek at it. */ void GrPeekWaitEvent(GR_EVENT *ep) { while(curclient->eventhead == NULL) GsSelect(0L); GrPeekEvent(ep); } #endif /* * Return the next event from the event queue if one is ready. * If one is not ready, then the type GR_EVENT_TYPE_NONE is returned. * If it is an error event, then a user-specified routine is called * if it was defined, otherwise we clean up and exit. */ void GrCheckNextEvent(GR_EVENT *ep) { CheckNextEvent(ep, GR_TRUE); } static void CheckNextEvent(GR_EVENT *ep, GR_BOOL doSelect) { GR_EVENT_LIST * elp; #if NONETWORK /* Since we're bound to server, select() is only called * thru here */ if(doSelect) GsSelect(0L); #endif /* Copy first event if any*/ if(!GrPeekEvent(ep)) return; /* Get first event again*/ elp = curclient->eventhead; /* Remove first event from queue*/ curclient->eventhead = elp->next; if (curclient->eventtail == elp) curclient->eventtail = NULL; elp->next = eventfree; eventfree = elp; } /* * Peek at the event queue for the current client to see if there are any * outstanding events. Returns the event at the head of the queue, or * else a null event type. The event is still left in the queue, however. */ int GrPeekEvent(GR_EVENT *ep) { GR_EVENT_LIST * elp; elp = curclient->eventhead; if(elp == NULL) { ep->type = GR_EVENT_TYPE_NONE; return 0; } /* copy event out*/ *ep = elp->event; return 1; } /* * Return information about a window id. */ void GrGetWindowInfo(GR_WINDOW_ID wid, GR_WINDOW_INFO *infoptr) { GR_WINDOW *wp; /* window structure */ GR_PIXMAP *pp; GR_EVENT_CLIENT *evp; /* event-client structure */ /* first check window list*/ wp = GsFindWindow(wid); if (wp) { infoptr->wid = wid; /* report parent-relative x,y coordinates*/ infoptr->x = wp->x - (wp->parent ? wp->parent->x : 0); infoptr->y = wp->y - (wp->parent ? wp->parent->y : 0); infoptr->width = wp->width; infoptr->height = wp->height; infoptr->parent = wp->parent? wp->parent->id: 0; infoptr->child = wp->children? wp->children->id: 0; infoptr->sibling = wp->siblings? wp->siblings->id: 0; infoptr->mapped = wp->mapped; infoptr->unmapcount = wp->unmapcount; infoptr->inputonly = !wp->output; infoptr->bordersize = wp->bordersize; infoptr->bordercolor = wp->bordercolor; infoptr->background = wp->background; infoptr->props = wp->props; infoptr->cursor = wp->cursorid; infoptr->processid = wp->owner? wp->owner->processid: 0; infoptr->eventmask = 0; for (evp = wp->eventclients; evp; evp = evp->next) { if (evp->client == curclient) infoptr->eventmask = evp->eventmask; } return; } /* then pixmap list*/ pp = GsFindPixmap(wid); if (pp) { infoptr->wid = wid; infoptr->x = pp->x; infoptr->y = pp->y; infoptr->width = pp->width; infoptr->height = pp->height; infoptr->parent = 0; infoptr->child = 0; infoptr->sibling = 0; infoptr->mapped = GR_FALSE; infoptr->unmapcount = 0; infoptr->inputonly = GR_FALSE; infoptr->bordersize = 0; infoptr->bordercolor = 0; infoptr->background = 0; infoptr->eventmask = 0; infoptr->cursor = 0; infoptr->processid = pp->owner? pp->owner->processid: 0; return; } /* No error if window id is invalid.*/ memset(infoptr, 0, sizeof(GR_WINDOW_INFO)); } /* * Destroy an existing window and all of its children. * Also used to destroy a pixmap. */ void GrDestroyWindow(GR_WINDOW_ID wid) { GR_WINDOW *wp; /* window structure */ GR_PIXMAP *pp; GR_PIXMAP *prevpp; PSD psd; wp = GsFindWindow(wid); if (wp) { GsWpDestroyWindow(wp); } else { pp = GsFindPixmap(wid); if (pp) { psd = pp->psd; /* deallocate pixmap memory*/ if (psd->flags & PSF_ADDRMALLOC) free(psd->addr); /* deallocate mem gc*/ psd->FreeMemGC(psd); /* * Remove this pixmap from the complete list of pixmaps. */ prevpp = listpp; if (prevpp == pp) listpp = pp->next; else { while (prevpp->next != pp) prevpp = prevpp->next; prevpp->next = pp->next; } /* * Forget various information if they related to this * pixmap. Then finally free the structure. */ if (pp == cachepp) { cachepixmapid = 0; cachepp = NULL; } free(pp); } } } /* * Raise a window to the highest level among its siblings. */ void GrRaiseWindow(GR_WINDOW_ID wid) { GR_WINDOW *wp; /* window structure */ GR_WINDOW *prevwp; /* previous window pointer */ GR_BOOL overlap; /* TRUE if there was overlap */ wp = GsFindWindow(wid); if ((wp == NULL) || (wp == rootwp)) return; /* * If this is already the highest window then we are done. */ prevwp = wp->parent->children; if (prevwp == wp) return; /* * Find the sibling just before this window so we can unlink it. * Also, determine if any sibling ahead of us overlaps the window. * Remember that for exposure events. */ overlap = GR_FALSE; while (prevwp->siblings != wp) { overlap |= GsCheckOverlap(prevwp, wp); prevwp = prevwp->siblings; } overlap |= GsCheckOverlap(prevwp, wp); /* * Now unlink the window and relink it in at the front of the * sibling chain. */ prevwp->siblings = wp->siblings; wp->siblings = wp->parent->children; wp->parent->children = wp; /* * Finally redraw the window if necessary. */ if (overlap) { GsDrawBorder(wp); GsExposeArea(wp, wp->x, wp->y, wp->width, wp->height, NULL); } } /* * Lower a window to the lowest level among its siblings. */ void GrLowerWindow(GR_WINDOW_ID wid) { GR_WINDOW *wp; /* window structure */ GR_WINDOW *prevwp; /* previous window pointer */ GR_WINDOW *sibwp; /* sibling window */ GR_WINDOW *expwp; /* siblings being exposed */ wp = GsFindWindow(wid); if ((wp == NULL) || (wp == rootwp)) return; if (wp->siblings == NULL) return; /* * Find the sibling just before this window so we can unlink us. */ prevwp = wp->parent->children; if (prevwp != wp) { while (prevwp->siblings != wp) prevwp = prevwp->siblings; } /* * Remember the first sibling that is after us, so we can * generate exposure events for the remaining siblings. Then * walk down the sibling chain looking for the last sibling. */ expwp = wp->siblings; sibwp = wp; while (sibwp->siblings) sibwp = sibwp->siblings; /* * Now unlink the window and relink it in at the end of the * sibling chain. */ if (prevwp == wp) wp->parent->children = wp->siblings; else prevwp->siblings = wp->siblings; sibwp->siblings = wp; wp->siblings = NULL; /* * Finally redraw the sibling windows which this window covered * if they overlapped our window. */ while (expwp && (expwp != wp)) { if (GsCheckOverlap(wp, expwp)) { GsExposeArea(expwp, wp->x - wp->bordersize, wp->y - wp->bordersize, wp->width + wp->bordersize * 2, wp->height + wp->bordersize * 2, NULL); } expwp = expwp->siblings; } } /* Offset a window position and all children by offx,offy*/ static void OffsetWindow(GR_WINDOW *wp, GR_COORD offx, GR_COORD offy) { GR_WINDOW *cp; wp->x += offx; wp->y += offy; for(cp=wp->children; cp; cp=cp->siblings) OffsetWindow(cp, offx, offy); } /* deliver an update move event to window and all children*/ static void DeliverUpdateMoveEventAndChildren(GR_WINDOW *wp) { GR_WINDOW * childwp; GsDeliverUpdateEvent(wp, GR_UPDATE_MOVE, wp->x, wp->y, wp->width, wp->height); for (childwp = wp->children; childwp; childwp = childwp->siblings) DeliverUpdateMoveEventAndChildren(childwp); } /* * Move the window to the specified position relative to its parent. */ void GrMoveWindow(GR_WINDOW_ID wid, GR_COORD x, GR_COORD y) { GR_WINDOW *wp; /* window structure */ GR_COORD offx, offy; wp = GsFindWindow(wid); if (wp == NULL) return; if (wp == rootwp) { GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wid); return; } x += wp->parent->x; y += wp->parent->y; offx = x - wp->x; offy = y - wp->y; if (wp->x == x && wp->y == y) return; /*** move algorithms not requiring unmap/map ***/ #if 1 /* perform screen blit if topmost and mapped - no flicker!*/ if (wp->mapped && wp == wp->parent->children && wp->parent->id == GR_ROOT_WINDOW_ID /* temp don't blit in portrait mode, still buggy*/ && !(wp->psd->portrait & (MWPORTRAIT_LEFT|MWPORTRAIT_RIGHT)) ) { int oldx = wp->x; int oldy = wp->y; GR_WINDOW_ID pixid = GrNewPixmap(wp->width, wp->height,NULL); GR_GC_ID gc = GrNewGC(); GR_WINDOW * stopwp = wp; int X, Y, W, H; /* must hide cursor first or GdFixCursor() will show it*/ GdHideCursor(rootwp->psd); /* turn off clipping of root's children*/ GrSetGCMode(gc, GR_MODE_COPY|GR_MODE_EXCLUDECHILDREN); /* copy topmost window contents offscreen*/ GrCopyArea(pixid, gc, 0, 0, wp->width, wp->height, GR_ROOT_WINDOW_ID, oldx, oldy, MWROP_COPY); /* calc new window offsets*/ OffsetWindow(wp, offx, offy); /* force recalc of clip region*/ clipwp = NULL; /* copy window bits to new location*/ GrCopyArea(GR_ROOT_WINDOW_ID, gc, wp->x, wp->y, wp->width, wp->height, pixid, 0, 0, MWROP_COPY); /* * If any portion of the window was offscreen * and is coming onscreen, must send expose events * to this window as well. */ if ((oldx < 0 && wp->x > oldx) || (oldy < 0 && wp->y > oldy) || (oldx+wp->width > rootwp->width && wp->x < oldx) || (oldy+wp->height > rootwp->height && wp->y < oldy)) stopwp = NULL; /* * Calculate bounded exposed area and * redraw anything lower than stopwp window. */ X = MWMIN(oldx, wp->x); Y = MWMIN(oldy, wp->y); W = MWMAX(oldx, wp->x) + wp->width - X; H = MWMAX(oldy, wp->y) + wp->height - Y; GsExposeArea(rootwp, X, Y, W, H, stopwp); GdShowCursor(rootwp->psd); GrDestroyGC(gc); GrDestroyWindow(pixid); DeliverUpdateMoveEventAndChildren(wp); return; } #endif #if 0 /* perform quick move and expose if topmost and mapped - no blit*/ if (wp->mapped && wp == wp->parent->children) { int oldx = wp->x; int oldy = wp->y; int X, Y, W, H; OffsetWindow(wp, offx, offy); /* force recalc of clip region*/ clipwp = NULL; X = MWMIN(oldx, wp->x); Y = MWMIN(oldy, wp->y); W = MWMAX(oldx, wp->x) + wp->width - X; H = MWMAX(oldy, wp->y) + wp->height - Y; GsExposeArea(rootwp, X, Y, W, H, NULL); DeliverUpdateMoveEventAndChildren(wp); return; } #endif /* * This method will redraw the window entirely, * resulting in considerable flicker. */ GsWpUnmapWindow(wp, GR_TRUE); OffsetWindow(wp, offx, offy); GsWpMapWindow(wp, GR_FALSE); DeliverUpdateMoveEventAndChildren(wp); } /* * Resize the window to be the specified size. */ void GrResizeWindow(GR_WINDOW_ID wid, GR_SIZE width, GR_SIZE height) { GR_WINDOW *wp; /* window structure */ wp = GsFindWindow(wid); if (wp == NULL) return; if (wp == rootwp) { GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wid); return; } if ((width <= 0) || (height <= 0)) { GsError(GR_ERROR_BAD_WINDOW_SIZE, wid); return; } if ((wp->width == width) && (wp->height == height)) return; if (wp->unmapcount || !wp->output) { wp->width = width; wp->height = height; return; } /* * This should be optimized to not require redrawing of the window * when possible. */ GsWpUnmapWindow(wp, GR_TRUE); wp->width = width; wp->height = height; GsWpMapWindow(wp, GR_FALSE); GsDeliverUpdateEvent(wp, GR_UPDATE_SIZE, wp->x, wp->y, width, height); } /* set unmapcount for a window and all its children*/ static void SetUnmapCountTree(GR_WINDOW *wp, int value, GR_BOOL increment) { GR_WINDOW * childwp; if (increment) wp->unmapcount += value; else wp->unmapcount = value; for (childwp = wp->children; childwp; childwp = childwp->siblings) SetUnmapCountTree(childwp, value, increment); } /* * Reparent window to new parent, position at passed x, y * * NOTE: currently, the new parent must be mapped before * reparenting, or the children of the newly parented window * will have bad unmapcount values due to the GrMapWindow * being called on the parent afterwards, and chaining down * through the children. */ void GrReparentWindow(GR_WINDOW_ID wid, GR_WINDOW_ID pwid, GR_COORD x, GR_COORD y) { GR_WINDOW *wp; /* window structure */ GR_WINDOW *pwp; /* parent window structure */ GR_WINDOW **mysibptr; /* handle to my sibling ptr */ GR_COORD offx, offy; GR_BOOL wasmapped; wp = GsFindWindow(wid); pwp = GsFindWindow(pwid); if (wp == NULL || pwp == NULL || wp == pwp) return; if (wp == rootwp) { GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wid); return; } x += pwp->x; y += pwp->y; offx = x - wp->x; offy = y - wp->y; /*printf("pid %d wid %d (oldpid %d) %d,%d\n", pwid, wid, wp->parent->id, pwp->unmapcount, wp->unmapcount);*/ /* * Always unmap window, can't hurt if not mapped. */ wasmapped = (wp->unmapcount == 0); GsWpUnmapWindow(wp, GR_TRUE); for(mysibptr = &(wp->parent->children); *mysibptr != wp; mysibptr = &((*mysibptr)->siblings)) continue; *mysibptr = wp->siblings; wp->parent = pwp; wp->siblings = pwp->children; pwp->children = wp; OffsetWindow(wp, offx, offy); #if 1 /* temp fix to bad mapcount reparenting code below*/ GsWpMapWindow(wp, GR_FALSE); #else /* * If parent mapped and window was mapped, set unmapcount * to 0 and remap window. */ if (!pwp->unmapcount && wasmapped) { SetUnmapCountTree(wp, 0, GR_FALSE); GsWpMapWindow(wp, GR_FALSE); } else { if (wasmapped) SetUnmapCountTree(wp, pwp->unmapcount, GR_FALSE); else SetUnmapCountTree(wp, pwp->unmapcount+1, GR_FALSE); } #endif } static int nextgcid = 1000; /* * Allocate a new GC with default parameters. * The GC is owned by the current client. */ GR_GC_ID GrNewGC(void) { GR_GC *gcp; gcp = (GR_GC *) malloc(sizeof(GR_GC)); if (gcp == NULL) { GsError(GR_ERROR_MALLOC_FAILED, 0); return 0; } gcp->id = nextgcid++; gcp->mode = GR_MODE_COPY; gcp->regionid = 0; /* no region*/ gcp->xoff = 0; /* no offset*/ gcp->yoff = 0; gcp->fontid = 0; /* 0 is default font*/ gcp->foreground = WHITE; gcp->background = BLACK; gcp->usebackground = GR_TRUE; gcp->changed = GR_TRUE; gcp->owner = curclient; gcp->next = listgcp; listgcp = gcp; return gcp->id; } /* * Destroy an existing graphics context. */ void GrDestroyGC(GR_GC_ID gc) { GR_GC *gcp; /* graphics context */ GR_GC *prevgcp; /* previous graphics context */ gcp = GsFindGC(gc); if (gcp == NULL) return; if (gc == cachegcid) { cachegcid = 0; cachegcp = NULL; } if (gcp == curgcp) curgcp = NULL; if (listgcp == gcp) listgcp = gcp->next; else { prevgcp = listgcp; while (prevgcp->next != gcp) prevgcp = prevgcp->next; prevgcp->next = gcp->next; } free(gcp); } /* * Allocate a new GC which is a copy of another one. * The GC is owned by the current client. */ GR_GC_ID GrCopyGC(GR_GC_ID gc) { GR_GC *oldgcp; /* old graphics context */ GR_GC *gcp; /* new graphics context */ oldgcp = GsFindGC(gc); if (oldgcp == NULL) return 0; gcp = (GR_GC *) malloc(sizeof(GR_GC)); if (gcp == NULL) { GsError(GR_ERROR_MALLOC_FAILED, 0); return 0; } /* * Copy all the old gcp values into the new one, except allocate * a new id for it and link it into the list of GCs. */ *gcp = *oldgcp; gcp->id = nextgcid++; gcp->changed = GR_TRUE; gcp->owner = curclient; gcp->next = listgcp; listgcp = gcp; return gcp->id; } /* * Return information about the specified graphics context. */ void GrGetGCInfo(GR_GC_ID gcid, GR_GC_INFO *gcip) { GR_GC *gcp; /* * Find the GC manually so that an error is not generated. */ for (gcp = listgcp; gcp && (gcp->id != gcid); gcp = gcp->next) continue; if (gcp == NULL) { memset(gcip, 0, sizeof(GR_GC_INFO)); return; } gcip->gcid = gcid; gcip->mode = gcp->mode; gcip->region = gcp->regionid; gcip->xoff = gcp->xoff; gcip->yoff = gcp->yoff; gcip->font = gcp->fontid; gcip->foreground = gcp->foreground; gcip->background = gcp->background; gcip->usebackground = gcp->usebackground; } static int nextregionid = 1000; /* * Allocate a new REGION with default parameters. * The REGION is owned by the current client. */ GR_REGION_ID GrNewRegion(void) { GR_REGION *regionp; regionp = (GR_REGION *) malloc(sizeof(GR_REGION)); if (regionp == NULL) { GsError(GR_ERROR_MALLOC_FAILED, 0); return 0; } regionp->rgn = GdAllocRegion(); regionp->id = nextregionid++; regionp->owner = curclient; regionp->next = listregionp; listregionp = regionp; return regionp->id; } /* * Allocate a new region from a set of points interpreted as a polygon. * The REGION is owned by the current client. */ GR_REGION_ID GrNewPolygonRegion(int mode, GR_COUNT count, GR_POINT *points) { #if POLYREGIONS GR_REGION *regionp; regionp = (GR_REGION *) malloc(sizeof(GR_REGION)); if (regionp == NULL) { GsError(GR_ERROR_MALLOC_FAILED, 0); return 0; } regionp->rgn = GdAllocPolygonRegion(points, count, mode); regionp->id = nextregionid++; regionp->owner = curclient; regionp->next = listregionp; listregionp = regionp; return regionp->id; #else return 0; #endif } /* * Destroy an existing region. */ void GrDestroyRegion(GR_REGION_ID region) { GR_REGION *regionp; /* region */ GR_REGION *prevregionp; /* previous region */ regionp = GsFindRegion(region); if (regionp == NULL) return; if (listregionp == regionp) listregionp = regionp->next; else { prevregionp = listregionp; while (prevregionp->next != regionp) prevregionp = prevregionp->next; prevregionp->next = regionp->next; } GdDestroyRegion(regionp->rgn); free(regionp); } /* * Updates the region from a union of the specified rectangle * and the original region. */ void GrUnionRectWithRegion(GR_REGION_ID region, GR_RECT *rect) { GR_REGION *regionp; MWRECT rc; regionp = GsFindRegion(region); if (regionp) { /* convert Nano-X rect to MW rect*/ rc.left = rect->x; rc.top = rect->y; rc.right = rect->x + rect->width; rc.bottom = rect->y + rect->height; GdUnionRectWithRegion(&rc, regionp->rgn); } } /* * Updates the region from a union of two regions. */ void GrUnionRegion(GR_REGION_ID dst_rgn, GR_REGION_ID src_rgn1, GR_REGION_ID src_rgn2) { GR_REGION *regionp; GR_REGION *srcregionp1; GR_REGION *srcregionp2; regionp = GsFindRegion(dst_rgn); if (regionp == NULL) return; srcregionp1 = GsFindRegion(src_rgn1); if (srcregionp1 == NULL) return; srcregionp2 = GsFindRegion(src_rgn2); if (srcregionp2 == NULL) return; GdUnionRegion(regionp->rgn, srcregionp1->rgn, srcregionp2->rgn); } /* * Updates the region by subtracting a region from another. */ void GrSubtractRegion(GR_REGION_ID dst_rgn, GR_REGION_ID src_rgn1, GR_REGION_ID src_rgn2) { GR_REGION *regionp; GR_REGION *srcregionp1; GR_REGION *srcregionp2; regionp = GsFindRegion(dst_rgn); if (regionp == NULL) return; srcregionp1 = GsFindRegion(src_rgn1); if (srcregionp1 == NULL) return; srcregionp2 = GsFindRegion(src_rgn2); if (srcregionp2 == NULL) return; GdSubtractRegion(regionp->rgn, srcregionp1->rgn, srcregionp2->rgn); } /* * Updates the region to the difference of two regions. */ void GrXorRegion(GR_REGION_ID dst_rgn, GR_REGION_ID src_rgn1, GR_REGION_ID src_rgn2) { GR_REGION *regionp; GR_REGION *srcregionp1; GR_REGION *srcregionp2; regionp = GsFindRegion(dst_rgn); if (regionp == NULL) return; srcregionp1 = GsFindRegion(src_rgn1); if (srcregionp1 == NULL) return; srcregionp2 = GsFindRegion(src_rgn2); if (srcregionp2 == NULL) return; GdXorRegion(regionp->rgn, srcregionp1->rgn, srcregionp2->rgn); } /* * Updates the region from a intersection of two regions. */ void GrIntersectRegion(GR_REGION_ID dst_rgn, GR_REGION_ID src_rgn1, GR_REGION_ID src_rgn2) { GR_REGION *regionp; GR_REGION *srcregionp1; GR_REGION *srcregionp2; regionp = GsFindRegion(dst_rgn); if (regionp == NULL) return; srcregionp1 = GsFindRegion(src_rgn1); if (srcregionp1 == NULL) return; srcregionp2 = GsFindRegion(src_rgn2); if (srcregionp2 == NULL) return; GdIntersectRegion(regionp->rgn, srcregionp1->rgn, srcregionp2->rgn); } /* * Sets the clip-mask in the GC to the specified region. */ void GrSetGCRegion(GR_GC_ID gc, GR_REGION_ID region) { GR_GC *gcp; gcp = GsFindGC(gc); if(gcp == NULL) return; gcp->regionid = region; gcp->changed = GR_TRUE; } /* * Set the x,y origin of user clip region in GC. */ void GrSetGCClipOrigin(GR_GC_ID gc, int xoff, int yoff) { GR_GC *gcp; gcp = GsFindGC(gc); if(gcp == NULL) return; gcp->xoff = xoff; gcp->yoff = yoff; gcp->changed = GR_TRUE; } /* * Determines whether a specified point resides in a region. */ GR_BOOL GrPointInRegion(GR_REGION_ID region, GR_COORD x, GR_COORD y) { GR_REGION *regionp; regionp = GsFindRegion(region); if (regionp == NULL) return GR_FALSE; return GdPtInRegion(regionp->rgn, x, y); } /* * Determines whether a specified rectangle at least partly resides * in a region. */ int GrRectInRegion(GR_REGION_ID region, GR_COORD x, GR_COORD y, GR_COORD w, GR_COORD h) { GR_REGION *regionp; MWRECT rect; regionp = GsFindRegion(region); if (regionp == NULL) return MWRECT_OUT; rect.left = x; rect.top = y; rect.right = x + w; rect.bottom = y + h; return GdRectInRegion(regionp->rgn, &rect); } /* * Return GR_TRUE if a region is empty. */ GR_BOOL GrEmptyRegion(GR_REGION_ID region) { GR_REGION *regionp; regionp = GsFindRegion(region); if (regionp == NULL) return GR_TRUE; return GdEmptyRegion(regionp->rgn); } /* * Return GR_TRUE if two regions are identical. */ GR_BOOL GrEqualRegion(GR_REGION_ID rgn1, GR_REGION_ID rgn2) { GR_REGION *prgn1; GR_REGION *prgn2; prgn1 = GsFindRegion(rgn1); prgn2 = GsFindRegion(rgn2); if (!prgn1 && !prgn2) return GR_TRUE; if (!prgn1 || !prgn2) return GR_FALSE; return GdEqualRegion(prgn1->rgn, prgn2->rgn); } /* * Offset a region by dx, dy. */ void GrOffsetRegion(GR_REGION_ID region, GR_SIZE dx, GR_SIZE dy) { GR_REGION *regionp; regionp = GsFindRegion(region); if (regionp) GdOffsetRegion(regionp->rgn, dx, dy); } /* * Return the bounding box for the specified region. */ int GrGetRegionBox(GR_REGION_ID region, GR_RECT *rect) { GR_REGION *regionp; MWRECT rc; int ret_val; regionp = GsFindRegion(region); if (regionp == NULL) { memset(rect, 0, sizeof(GR_RECT)); return MWREGION_ERROR; } ret_val = GdGetRegionBox(regionp->rgn, &rc); /* convert MW rect to Nano-X rect*/ rect->x = rc.left; rect->y = rc.top; rect->width = rc.right - rc.left; rect->height = rc.bottom - rc.top; return ret_val; } static int nextfontid = 1000; /* * Allocate a new GC with default parameters. * The GC is owned by the current client. */ GR_FONT_ID GrCreateFont(GR_CHAR *name, GR_COORD height, GR_LOGFONT *plogfont) { GR_FONT *fontp; fontp = (GR_FONT *) malloc(sizeof(GR_FONT)); if (fontp == NULL) { GsError(GR_ERROR_MALLOC_FAILED, 0); return 0; } if (plogfont) fontp->pfont = GdCreateFont(&scrdev, NULL, 0, plogfont); else fontp->pfont = GdCreateFont(&scrdev, name, height, NULL); fontp->id = nextfontid++; fontp->owner = curclient; fontp->next = listfontp; listfontp = fontp; return fontp->id; } /* Set the font size for the passed font*/ void GrSetFontSize(GR_FONT_ID fontid, GR_COORD size) { GR_FONT *fontp; fontp = GsFindFont(fontid); if (fontp) GdSetFontSize(fontp->pfont, size); } /* Set the font rotation in tenths of degrees for the passed font*/ void GrSetFontRotation(GR_FONT_ID fontid, int tenthdegrees) { GR_FONT *fontp; fontp = GsFindFont(fontid); if (fontp) GdSetFontRotation(fontp->pfont, tenthdegrees); } /* Set the font size for the passed font*/ void GrSetFontAttr(GR_FONT_ID fontid, int setflags, int clrflags) { GR_FONT *fontp; fontp = GsFindFont(fontid); if (fontp) GdSetFontAttr(fontp->pfont, setflags, clrflags); } /* * Unload and deallocate an existing font. */ void GrDestroyFont(GR_FONT_ID fontid) { GR_FONT *fontp; GR_FONT *prevfontp; fontp = GsFindFont(fontid); if (fontp == NULL) return; if (listfontp == fontp) listfontp = fontp->next; else { prevfontp = listfontp; while (prevfontp->next != fontp) prevfontp = prevfontp->next; prevfontp->next = fontp->next; } GdDestroyFont(fontp->pfont); free(fontp); } /* * Return useful information about the specified font. * Font #0 returns info about the standard font. */ void GrGetFontInfo(GR_FONT_ID font, GR_FONT_INFO *fip) { GR_FONT *fontp; PMWFONT pf; if (font == 0) pf = stdfont; else { fontp = GsFindFont(font); if (!fontp) { memset(fip, 0, sizeof(GR_FONT_INFO)); return; } pf = fontp->pfont; } GdGetFontInfo(pf, fip); } /* * Select events for a window for this client. * The events are a bitmask for the events desired. */ void GrSelectEvents(GR_WINDOW_ID wid, GR_EVENT_MASK eventmask) { GR_WINDOW *wp; /* window structure */ GR_EVENT_CLIENT *evp; /* event-client structure */ wp = GsFindWindow(wid); if (wp == NULL) return; /* * See if this client is already in the event client list. * If so, then just replace the events he is selecting for. */ for (evp = wp->eventclients; evp; evp = evp->next) { if (evp->client == curclient) { evp->eventmask = eventmask; return; } } /* * A new client for this window, so allocate a new event client * structure and insert it into the front of the list in the window. */ evp = (GR_EVENT_CLIENT *) malloc(sizeof(GR_EVENT_CLIENT)); if (evp == NULL) { GsError(GR_ERROR_MALLOC_FAILED, wid); return; } evp->client = curclient; evp->eventmask = eventmask; evp->next = wp->eventclients; wp->eventclients = evp; /* * If it's a request for child updates to the root window, * then search entire list and send map events for * mapped windows now. This allows a window manager * to get the mapped window list without another API call. */ if (wid==GR_ROOT_WINDOW_ID && (eventmask & GR_EVENT_MASK_CHLD_UPDATE)) { for (wp = listwp; wp; wp = wp->next) { if (wp->unmapcount == 0) GsDeliverUpdateEvent(wp, GR_UPDATE_MAP, wp->x, wp->y, wp->width, wp->height); } } } static GR_WINDOW * NewWindow(GR_WINDOW *pwp, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height, GR_SIZE bordersize, GR_COLOR background, GR_COLOR bordercolor) { GR_WINDOW *wp; /* new window*/ if (width <= 0 || height <= 0 || bordersize < 0) { GsError(GR_ERROR_BAD_WINDOW_SIZE, 0); return NULL; } wp = (GR_WINDOW *) malloc(sizeof(GR_WINDOW)); if (wp == NULL) { GsError(GR_ERROR_MALLOC_FAILED, 0); return NULL; } wp->id = nextid++; wp->psd = rootwp->psd; wp->parent = pwp; wp->children = NULL; wp->siblings = pwp->children; wp->next = listwp; wp->x = pwp->x + x; wp->y = pwp->y + y; wp->width = width; wp->height = height; wp->bordersize = bordersize; wp->background = background; wp->bgpixmap = NULL; wp->bgpixmapflags = GR_BACKGROUND_TILE; wp->bordercolor = bordercolor; wp->nopropmask = 0; wp->eventclients = NULL; wp->owner = curclient; wp->cursorid = pwp->cursorid; wp->mapped = GR_FALSE; wp->unmapcount = pwp->unmapcount + 1; wp->output = GR_TRUE; wp->props = 0; wp->title = NULL; pwp->children = wp; listwp = wp; return wp; } /* * Allocate a new window which is a child of the specified window. * The window inherits the cursor of the parent window. * The window is owned by the current client. */ GR_WINDOW_ID GrNewWindow(GR_WINDOW_ID parent, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height, GR_SIZE bordersize, GR_COLOR background, GR_COLOR bordercolor) { GR_WINDOW *pwp; /* parent window */ GR_WINDOW *wp; /* new window */ pwp = GsFindWindow(parent); if (pwp == NULL) return 0; if (!pwp->output) { GsError(GR_ERROR_INPUT_ONLY_WINDOW, pwp->id); return 0; } wp = NewWindow(pwp, x, y, width, height, bordersize, background, bordercolor); return wp? wp->id: 0; } /* * Allocate a new input-only window which is a child of the specified window. * Such a window is invisible, cannot be drawn into, and is only used to * return events. The window inherits the cursor of the parent window. * The window is owned by the current client. */ GR_WINDOW_ID GrNewInputWindow(GR_WINDOW_ID parent, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height) { GR_WINDOW *pwp; /* parent window */ GR_WINDOW *wp; /* new window */ pwp = GsFindWindow(parent); if (pwp == NULL) return 0; wp = NewWindow(pwp, x, y, width, height, 0, BLACK, BLACK); if (wp) { /* convert to input-only window*/ wp->output = GR_FALSE; return wp->id; } return 0; } /* * Allocate a pixmap, can be used with any drawing functions * for offscreen drawing */ GR_WINDOW_ID GrNewPixmap(GR_SIZE width, GR_SIZE height, void * pixels) { GR_PIXMAP *pp; PSD psd; int size, linelen, bpp, planes; if (width <= 0 || height <= 0) { /* no error for now, server will desynchronize w/app*/ /*GsError(GR_ERROR_BAD_WINDOW_SIZE, 0);*/ return 0; } /* * allocate offscreen psd. If screen driver doesn't * support blitting, this will fail. Use root window screen * device for compatibility for now. */ planes = rootwp->psd->planes; bpp = rootwp->psd->bpp; psd = rootwp->psd->AllocateMemGC(rootwp->psd); if (!psd) return 0; pp = (GR_PIXMAP *) malloc(sizeof(GR_PIXMAP)); if (pp == NULL) { GsError(GR_ERROR_MALLOC_FAILED, 0); psd->FreeMemGC(psd); return 0; } GdCalcMemGCAlloc(psd, width, height, 0, 0, &size, &linelen); /* Allocate space for pixel values */ if (!pixels) { pixels = calloc(size, 1); psd->flags |= PSF_ADDRMALLOC; } if (!pixels) { free(pp); psd->FreeMemGC(psd); GsError(GR_ERROR_MALLOC_FAILED, 0); return 0; } pp->id = nextid++; pp->next = listpp; pp->psd = psd; pp->x = 0; pp->y = 0; pp->width = width; pp->height = height; pp->owner = curclient; psd->MapMemGC(psd, width, height, planes, bpp, linelen, size, pixels); listpp = pp; return pp->id; } /* * Map the window to make it (and possibly its children) visible on the screen. */ void GrMapWindow(GR_WINDOW_ID wid) { GR_WINDOW *wp; /* window structure */ wp = GsFindWindow(wid); if (!wp || wp->mapped) return; wp->mapped = GR_TRUE; GsWpMapWindow(wp, GR_FALSE); } /* * Unmap the window to make it and its children invisible on the screen. */ void GrUnmapWindow(GR_WINDOW_ID wid) { GR_WINDOW *wp; /* window structure */ wp = GsFindWindow(wid); if (!wp || !wp->mapped) return; GsWpUnmapWindow(wp, GR_FALSE); wp->mapped = GR_FALSE; } /* * Clear the associated area of a window to its background color * or pixmap. Generate expose event for window if exposeflag set. */ void GrClearArea(GR_WINDOW_ID wid, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height, GR_BOOL exposeflag) { GR_WINDOW *wp; /* window structure */ wp = GsPrepareWindow(wid); if (wp) { if (width == 0) width = wp->width; if (height == 0) height = wp->height; GsWpClearWindow(wp, x, y, width, height, exposeflag); } } /* Return window with keyboard focus.*/ GR_WINDOW_ID GrGetFocus(void) { return focuswp->id; } /* * Set the focus to a particular window. * This makes keyboard events only visible to that window or children of it, * depending on the pointer location. */ void GrSetFocus(GR_WINDOW_ID wid) { GR_WINDOW *wp; /* window structure */ wp = GsFindWindow(wid); if (wp == NULL) return; if (wp->unmapcount) { GsError(GR_ERROR_UNMAPPED_FOCUS_WINDOW, wid); return; } /* Check if window wants focus, if not, ignore call*/ if (wp->props & GR_WM_PROPS_NOFOCUS) return; focusfixed = (wp != rootwp); GsWpSetFocus(wp); } /* * Create a new server-based cursor resource. */ static int nextcursorid = 1000; GR_CURSOR_ID GrNewCursor(GR_SIZE width, GR_SIZE height, GR_COORD hotx, GR_COORD hoty, GR_COLOR foreground, GR_COLOR background, GR_BITMAP *fgbitmap, GR_BITMAP *bgbitmap) { GR_CURSOR *cp; int bytes; /* * Make sure the size of the bitmap is reasonable. */ if (width <= 0 || width > MWMAX_CURSOR_SIZE || height <= 0 || height > MWMAX_CURSOR_SIZE) { GsError(GR_ERROR_BAD_CURSOR_SIZE, 0); return 0; } cp = (GR_CURSOR *)malloc(sizeof(GR_CURSOR)); if (cp == NULL) { GsError(GR_ERROR_MALLOC_FAILED, 0); return 0; } /* fill in cursor structure*/ cp->cursor.width = width; cp->cursor.height = height; cp->cursor.hotx = hotx; cp->cursor.hoty = hoty; cp->cursor.fgcolor = foreground; cp->cursor.bgcolor = background; bytes = GR_BITMAP_SIZE(width, height) * sizeof(GR_BITMAP); memcpy(&cp->cursor.image, fgbitmap, bytes); memcpy(&cp->cursor.mask, bgbitmap, bytes); cp->id = nextcursorid++; cp->owner = curclient; cp->next = listcursorp; listcursorp = cp; return cp->id; } /* * Destroy a server-based cursor. */ void GrDestroyCursor(GR_CURSOR_ID cid) { GR_CURSOR *cursorp; GR_CURSOR *prevcursorp; cursorp = GsFindCursor(cid); if (cursorp == NULL) return; if (listcursorp == cursorp) listcursorp = cursorp->next; else { prevcursorp = listcursorp; while (prevcursorp->next != cursorp) prevcursorp = prevcursorp->next; prevcursorp->next = cursorp->next; } if (curcursor == cursorp) curcursor = NULL; free(cursorp); GsCheckCursor(); } /* * Specify a cursor for a window. * This cursor will only be used within that window, and by default * for its new children. If the cursor is currently within this * window, it will be changed to the new one immediately. * If the new cursor id is 0, revert to the root window cursor. */ void GrSetWindowCursor(GR_WINDOW_ID wid, GR_CURSOR_ID cid) { GR_WINDOW *wp; GR_CURSOR *cp; /* cursor structure */ wp = GsFindWindow(wid); if (wp == NULL) return; if (cid == 0) cp = stdcursor; else { cp = GsFindCursor(cid); if (!cp) return; /* FIXME add server errmsg*/ } wp->cursorid = cid; /* * If this was the current cursor, then draw the new one. */ if (cp == curcursor || curcursor == NULL) { GdMoveCursor(cursorx - cp->cursor.hotx, cursory - cp->cursor.hoty); GdSetCursor(&cp->cursor); } GsCheckCursor(); } /* * Move the cursor to the specified absolute screen coordinates. * The coordinates are that of the defined hot spot of the cursor. * The cursor's appearance is changed to that defined for the window * in which the cursor is moved to. In addition, mouse enter, mouse * exit, focus in, and focus out events are generated if necessary. * The current mouse location is also changed. */ void GrMoveCursor(GR_COORD x, GR_COORD y) { /* * Move the cursor only if necessary, offsetting it to * place the hot spot at the specified coordinates. */ if ((x != cursorx) || (y != cursory)) { if(curcursor) { GdMoveCursor(x - curcursor->cursor.hotx, y - curcursor->cursor.hoty); GdMoveMouse(x, y); } cursorx = x; cursory = y; } /* * Now check to see which window the mouse is in, whether or * not the cursor shape should be changed, and whether or not * the input focus window should be changed. */ GsCheckMouseWindow(); GsCheckFocusWindow(); GsCheckCursor(); } /* * Set the foreground color in a graphics context. */ void GrSetGCForeground(GR_GC_ID gc, GR_COLOR foreground) { GR_GC *gcp; /* graphics context */ gcp = GsFindGC(gc); if (!gcp || gcp->foreground == foreground) return; gcp->foreground = foreground; gcp->changed = GR_TRUE; } /* * Set the background color in a graphics context. */ void GrSetGCBackground(GR_GC_ID gc, GR_COLOR background) { GR_GC *gcp; /* graphics context */ gcp = GsFindGC(gc); if (!gcp || gcp->background == background) return; gcp->background = background; gcp->changed = GR_TRUE; } /* * Set whether or not the background color is drawn in bitmaps and text. */ void GrSetGCUseBackground(GR_GC_ID gc, GR_BOOL flag) { GR_GC *gcp; /* graphics context */ flag = (flag != 0); gcp = GsFindGC(gc); if (!gcp || gcp->usebackground == flag) return; gcp->usebackground = flag; gcp->changed = GR_TRUE; } /* * Set the drawing mode in a graphics context. */ void GrSetGCMode(GR_GC_ID gc, int mode) { GR_GC *gcp; /* graphics context */ gcp = GsFindGC(gc); if (!gcp || gcp->mode == mode) return; if ((mode & GR_MODE_DRAWMASK) > GR_MAX_MODE) { GsError(GR_ERROR_BAD_DRAWING_MODE, gc); return; } gcp->mode = mode; gcp->changed = GR_TRUE; } /* * Set the text font in a graphics context. */ void GrSetGCFont(GR_GC_ID gc, GR_FONT_ID font) { GR_GC *gcp; /* graphics context */ GR_FONT *fontp; gcp = GsFindGC(gc); if (!gcp || gcp->fontid == font) return; fontp = GsFindFont(font); gcp->fontid = font; gcp->changed = GR_TRUE; } /* * Draw a line in the specified drawable using the specified graphics context. */ void GrLine(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x1, GR_COORD y1, GR_COORD x2, GR_COORD y2) { GR_DRAWABLE *dp; switch (GsPrepareDrawing(id, gc, &dp)) { case GR_DRAW_TYPE_WINDOW: case GR_DRAW_TYPE_PIXMAP: GdLine(dp->psd, dp->x + x1, dp->y + y1, dp->x + x2, dp->y + y2, TRUE); break; } } /* * Draw the boundary of a rectangle in the specified drawable using the * specified graphics context. * NOTE: this function draws a rectangle 1 pixel wider and higher * than Xlib's XDrawRectangle(). */ void GrRect(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height) { GR_DRAWABLE *dp; switch (GsPrepareDrawing(id, gc, &dp)) { case GR_DRAW_TYPE_WINDOW: case GR_DRAW_TYPE_PIXMAP: GdRect(dp->psd, dp->x + x, dp->y + y, width, height); break; } } /* * Fill a rectangle in the specified drawable using the specified * graphics context. */ void GrFillRect(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height) { GR_DRAWABLE *dp; switch (GsPrepareDrawing(id, gc, &dp)) { case GR_DRAW_TYPE_WINDOW: case GR_DRAW_TYPE_PIXMAP: GdFillRect(dp->psd, dp->x + x, dp->y + y, width,height); break; } } /* * Draw the boundary of an ellipse in the specified drawable with * the specified graphics context. Integer only. */ void GrEllipse(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y, GR_SIZE rx, GR_SIZE ry) { GR_DRAWABLE *dp; switch (GsPrepareDrawing(id, gc, &dp)) { case GR_DRAW_TYPE_WINDOW: case GR_DRAW_TYPE_PIXMAP: GdEllipse(dp->psd, dp->x + x, dp->y + y, rx, ry, FALSE); break; } } /* * Fill an ellipse in the specified drawable using the specified * graphics context. Integer only. */ void GrFillEllipse(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y, GR_SIZE rx, GR_SIZE ry) { GR_DRAWABLE *dp; switch (GsPrepareDrawing(id, gc, &dp)) { case GR_DRAW_TYPE_WINDOW: case GR_DRAW_TYPE_PIXMAP: GdEllipse(dp->psd, dp->x + x, dp->y + y, rx, ry, TRUE); break; } } /* * Draw an arc, pie or ellipse in the specified drawable using * the specified graphics context. Integer only. */ void GrArc(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y, GR_SIZE rx, GR_SIZE ry, GR_COORD ax, GR_COORD ay, GR_COORD bx, GR_COORD by, int type) { GR_DRAWABLE *dp; switch (GsPrepareDrawing(id, gc, &dp)) { case GR_DRAW_TYPE_WINDOW: case GR_DRAW_TYPE_PIXMAP: GdArc(dp->psd, dp->x + x, dp->y + y, rx, ry, dp->x+ax, dp->y+ay, dp->x+bx, dp->y+by, type); break; } } /* * Draw an arc or pie in the specified drawable using * the specified graphics context. Requires floating point. */ void GrArcAngle(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y, GR_SIZE rx, GR_SIZE ry, GR_COORD angle1, GR_COORD angle2, int type) { GR_DRAWABLE *dp; switch (GsPrepareDrawing(id, gc, &dp)) { case GR_DRAW_TYPE_WINDOW: case GR_DRAW_TYPE_PIXMAP: GdArcAngle(dp->psd, dp->x + x, dp->y + y, rx, ry, angle1, angle2, type); break; } } /* * Draw a rectangular area in the specified drawable using the specified * graphics, as determined by the specified bit map. This differs from * rectangle drawing in that the rectangle is drawn using the foreground * color and possibly the background color as determined by the bit map. * Each row of bits is aligned to the next bitmap word boundary (so there * is padding at the end of the row). The background bit values are only * written if the usebackground flag is set in the GC. */ void GrBitmap(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height, GR_BITMAP *imagebits) { GR_DRAWABLE *dp; switch (GsPrepareDrawing(id, gc, &dp)) { case GR_DRAW_TYPE_WINDOW: case GR_DRAW_TYPE_PIXMAP: GdBitmap(dp->psd, dp->x + x, dp->y + y, width, height, imagebits); break; } } /* draw a multicolor image at x, y*/ void GrDrawImageBits(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y, GR_IMAGE_HDR *pimage) { GR_DRAWABLE *dp; switch (GsPrepareDrawing(id, gc, &dp)) { case GR_DRAW_TYPE_WINDOW: case GR_DRAW_TYPE_PIXMAP: GdDrawImage(dp->psd, dp->x + x, dp->y + y, pimage); break; } } #if !((DOS_DJGPP) || (__PACIFIC__) || (DOS_TURBOC)) /* Load an image file from disk and display it at the specified coordinates*/ void GrDrawImageFromFile(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height, char* path, int flags) { #if defined(HAVE_FILEIO) GR_DRAWABLE *dp; switch (GsPrepareDrawing(id, gc, &dp)) { case GR_DRAW_TYPE_WINDOW: case GR_DRAW_TYPE_PIXMAP: GdDrawImageFromFile(dp->psd, dp->x + x, dp->y + y, width, height, path, flags); break; } #endif } /* load image from file and cache it*/ GR_IMAGE_ID GrLoadImageFromFile(char *path, int flags) { #if defined(HAVE_FILEIO) GR_IMAGE_ID id; GR_IMAGE * imagep; id = GdLoadImageFromFile(&scrdev, path, flags); if (!id) return 0; imagep = (GR_IMAGE *) malloc(sizeof(GR_IMAGE)); if (imagep == NULL) { GsError(GR_ERROR_MALLOC_FAILED, 0); GdFreeImage(id); return 0; } imagep->id = id; imagep->owner = curclient; imagep->next = listimagep; listimagep = imagep; return id; #else return 0; #endif } /* Draw an image from a buffer */ void GrDrawImageFromBuffer(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height, void *buffer, int size, int flags) { GR_DRAWABLE *dp; switch (GsPrepareDrawing(id, gc, &dp)) { case GR_DRAW_TYPE_WINDOW: case GR_DRAW_TYPE_PIXMAP: GdDrawImageFromBuffer(dp->psd, dp->x + x, dp->y + y, width, height, buffer, size, flags); break; } } /* load image from the given buffer and cache it*/ GR_IMAGE_ID GrLoadImageFromBuffer(void *buffer, int size, int flags) { GR_IMAGE_ID id; GR_IMAGE * imagep; id = GdLoadImageFromBuffer(&scrdev, buffer, size, flags); if (!id) return(0); imagep = (GR_IMAGE *) malloc(sizeof(GR_IMAGE)); if (imagep == NULL) { GsError(GR_ERROR_MALLOC_FAILED, 0); GdFreeImage(id); return 0; } imagep->id = id; imagep->owner = curclient; imagep->next = listimagep; listimagep = imagep; return id; } /* draw cached image*/ void GrDrawImageToFit(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height, GR_IMAGE_ID imageid) { #if defined(HAVE_FILEIO) GR_DRAWABLE *dp; switch (GsPrepareDrawing(id, gc, &dp)) { case GR_DRAW_TYPE_WINDOW: case GR_DRAW_TYPE_PIXMAP: GdDrawImageToFit(dp->psd, dp->x + x, dp->y + y, width, height, imageid); break; } #endif } /* free cached image*/ void GrFreeImage(GR_IMAGE_ID id) { #if defined(HAVE_FILEIO) GR_IMAGE *imagep; GR_IMAGE *previmagep; for (imagep = listimagep; imagep; imagep = imagep->next) { if (imagep->id == id) { if (listimagep == imagep) listimagep = imagep->next; else { previmagep = listimagep; while (previmagep->next != imagep) previmagep = previmagep->next; previmagep->next = imagep->next; } GdFreeImage(imagep->id); free(imagep); return; } } #endif } /* return cached image information*/ void GrGetImageInfo(GR_IMAGE_ID id, GR_IMAGE_INFO *iip) { #if defined(HAVE_FILEIO) GdGetImageInfo(id, iip); #else memset(iip, 0, sizeof(GR_IMAGE_INFO)); #endif } #endif /* !defined (DOS_DJGPP)|| (__PACIFIC__) || (DOS_TURBOC)) */ /* * Draw a rectangular area in the specified drawable using the specified * graphics context. This differs from rectangle drawing in that the * color values for each pixel in the rectangle are specified. * The color table is indexed row by row. */ void GrArea(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height, void *pixels, int pixtype) { GR_DRAWABLE *dp; switch (GsPrepareDrawing(id, gc, &dp)) { case GR_DRAW_TYPE_WINDOW: case GR_DRAW_TYPE_PIXMAP: GdArea(dp->psd, dp->x + x, dp->y + y, width, height, pixels, pixtype); break; } } /* * Copy a rectangle from one drawable to another or the same */ void GrCopyArea(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height, GR_DRAW_ID source, GR_COORD srcx, GR_COORD srcy, int op) { GR_DRAWABLE *dp; GR_WINDOW *swp; GR_PIXMAP *spp = NULL; GR_DRAW_TYPE type; PSD srcpsd; srcpsd = NULL; swp = GsFindWindow(source); type = GsPrepareDrawing(id, gc, &dp); if (type == GR_DRAW_TYPE_NONE) return; if (swp) { srcpsd = swp->psd; srcx += swp->x; srcy += swp->y; } else { spp = GsFindPixmap(source); if (spp) srcpsd = spp->psd; } if (!srcpsd) return; #if DYNAMICREGIONS /* * Skip blit and send expose event if window is partly * obscured and source and destination are onscreen. * Also check that receiving window's first client has * selected for expose events. This keeps brain-dead * programs that don't process exposure events somewhat working. */ if (swp && (srcpsd == dp->psd) && swp->eventclients && (swp->eventclients->eventmask & GR_EVENT_MASK_EXPOSURE)) { MWRECT rc; extern MWCLIPREGION *clipregion; /* clip blit rectangle to source screen/bitmap size*/ if(srcx+width > srcpsd->xvirtres) width = srcpsd->xvirtres - srcx; if(srcy+height > srcpsd->yvirtres) height = srcpsd->yvirtres - srcy; rc.left = srcx; rc.top = srcy; rc.right = srcx + width; rc.bottom = srcy + height; /* * if source isn't entirely within clip region, then * the blit is partly obscured and will copy some garbage. * In this case, skip the blit, punt, and deliver an * exposure event instead for proper display. */ if (GdRectInRegion(clipregion, &rc) != MWRECT_ALLIN) { GsDeliverExposureEvent(swp, dp->x+x, dp->y+y, width, height); return; } } #endif /* perform blit*/ GdCheckCursor(srcpsd, srcx, srcy, srcx+width, srcy+height); /* FIXME*/ GdBlit(dp->psd, dp->x+x, dp->y+y, width, height, srcpsd, srcx, srcy,op); GdFixCursor(srcpsd); /* FIXME*/ } /* * Read the color values from the specified rectangular area of the * specified drawable into a supplied buffer. If the drawable is a * window which is obscured by other windows, then the returned values * will include the values from the covering windows. Regions outside * of the screen boundaries, or unmapped windows will return black. */ void GrReadArea(GR_DRAW_ID id,GR_COORD x,GR_COORD y,GR_SIZE width,GR_SIZE height, GR_PIXELVAL *pixels) { GR_WINDOW *wp; GR_PIXMAP *pp = NULL; if ((wp = GsFindWindow(id)) == NULL && (pp = GsFindPixmap(id)) == NULL){ GsError(GR_ERROR_BAD_WINDOW_ID, id); return; } if (wp != NULL) { if (wp->unmapcount || (x >= wp->width) || (y >= wp->height) || (x + width <= 0) || (y + height <= 0)) { /* long count; * GR_PIXELVAL black; * * black = GdFindColor(BLACK); * count = width * height; * while (count-- > 0) * *pixels++ = black; */ return; } GdReadArea(wp->psd, wp->x+x, wp->y+y, width, height, pixels); } if (pp != NULL) { if ((x >= pp->width) || (y >= pp->height) || (x + width <= 0) || (y + height <= 0)) { return; } GdReadArea(pp->psd, x, y, width, height, pixels); } } /* * Draw a point in the specified drawable using the specified * graphics context. */ void GrPoint(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y) { GR_DRAWABLE *dp; switch (GsPrepareDrawing(id, gc, &dp)) { case GR_DRAW_TYPE_WINDOW: case GR_DRAW_TYPE_PIXMAP: GdPoint(dp->psd, dp->x + x, dp->y + y); break; } } /* * Draw points in the specified drawable using the specified * graphics context. */ void GrPoints(GR_DRAW_ID id, GR_GC_ID gc, GR_COUNT count, GR_POINT *pointtable) { GR_DRAWABLE *dp; GR_POINT *pp; GR_COUNT i; PSD psd; switch (GsPrepareDrawing(id, gc, &dp)) { case GR_DRAW_TYPE_WINDOW: case GR_DRAW_TYPE_PIXMAP: psd = dp->psd; break; default: return; } pp = pointtable; for (i = count; i-- > 0; pp++) { GdPoint(psd, pp->x + dp->x, pp->y + dp->y); } } /* * Draw a polygon in the specified drawable using the specified * graphics context. The polygon is only complete if the first * point is repeated at the end. */ void GrPoly(GR_DRAW_ID id, GR_GC_ID gc, GR_COUNT count, GR_POINT *pointtable) { GR_DRAWABLE *dp; GR_POINT *pp; GR_COUNT i; PSD psd; switch (GsPrepareDrawing(id, gc, &dp)) { case GR_DRAW_TYPE_WINDOW: case GR_DRAW_TYPE_PIXMAP: psd = dp->psd; break; default: return; } /* * Here for drawing to a window. * Relocate all the points relative to the window. */ pp = pointtable; for (i = count; i-- > 0; pp++) { pp->x += dp->x; pp->y += dp->y; } GdPoly(psd, count, pointtable); #ifdef NONETWORK /* * The following is only necessary when the server * isn't a separate process. We don't want to change the * user's arguments! */ pp = pointtable; for (i = count; i-- > 0; pp++) { pp->x -= dp->x; pp->y -= dp->y; } #endif } /* * Draw a filled polygon in the specified drawable using the specified * graphics context. The last point may be a duplicate of the first * point, but this is not required. */ void GrFillPoly(GR_DRAW_ID id, GR_GC_ID gc, GR_COUNT count, GR_POINT *pointtable) { GR_DRAWABLE *dp; GR_POINT *pp; GR_COUNT i; PSD psd; switch (GsPrepareDrawing(id, gc, &dp)) { case GR_DRAW_TYPE_WINDOW: case GR_DRAW_TYPE_PIXMAP: psd = dp->psd; break; default: return; } /* * Here for drawing to a window. * Relocate all the points relative to the window. */ pp = pointtable; for (i = count; i-- > 0; pp++) { pp->x += dp->x; pp->y += dp->y; } GdFillPoly(psd, count, pointtable); #ifdef NONETWORK /* * The following is only necessary when the server * isn't a separate process. We don't want to change the * user's arguments! */ pp = pointtable; for (i = count; i-- > 0; pp++) { pp->x -= dp->x; pp->y -= dp->y; } #endif } /* * Draw a text string in the specified drawable using the * specified graphics context. */ void GrText(GR_DRAW_ID id, GR_GC_ID gc, GR_COORD x, GR_COORD y, void *str, GR_COUNT count, int flags) { GR_DRAWABLE *dp; /* default to baseline alignment if none specified*/ if((flags&(MWTF_TOP|MWTF_BASELINE|MWTF_BOTTOM)) == 0) flags |= MWTF_BASELINE; switch (GsPrepareDrawing(id, gc, &dp)) { case GR_DRAW_TYPE_WINDOW: case GR_DRAW_TYPE_PIXMAP: GdText(dp->psd, dp->x + x, dp->y + y, str, count,flags); break; } } /* Return the system palette entries*/ void GrGetSystemPalette(GR_PALETTE *pal) { /* return 0 count if not in palettized mode*/ memset(pal, 0, sizeof(GR_PALETTE *)); if(rootwp->psd->pixtype == MWPF_PALETTE) { pal->count = (int)rootwp->psd->ncolors; GdGetPalette(rootwp->psd, 0, pal->count, pal->palette); } } /* Set the system palette entries from first for count*/ void GrSetSystemPalette(GR_COUNT first, GR_PALETTE *pal) { GdSetPalette(rootwp->psd, first, pal->count, pal->palette); if (first == 0) GsRedrawScreen(); } /* Convert passed color value to pixel value, depending on system mode*/ void GrFindColor(GR_COLOR c, GR_PIXELVAL *retpixel) { *retpixel = GdFindColor(c); } /* visible =0, no cursor change; =1, show; else hide*/ void GrInjectPointerEvent(GR_COORD x, GR_COORD y, int button, int visible) { if (visible != 0) { if (visible == 1) GdShowCursor(&scrdev); else GdHideCursor(&scrdev); } GdMoveMouse(x, y); GsHandleMouseStatus(x, y, button); } void GrInjectKeyboardEvent(GR_WINDOW_ID wid, GR_KEY keyvalue, GR_KEYMOD modifiers, GR_SCANCODE scancode, GR_BOOL pressed) { /* create a keyboard event */ GsDeliverKeyboardEvent(wid, pressed? GR_EVENT_TYPE_KEY_DOWN: GR_EVENT_TYPE_KEY_UP, keyvalue, modifiers, scancode); } /* * Set certain window properties, according to flags value * passed in props. */ void GrSetWMProperties(GR_WINDOW_ID wid, GR_WM_PROPERTIES *props) { GR_WINDOW *wp; int tl = 0; /* Initialized to avoid warning */ /* Find the window structure (generate an error if it doesn't exist) */ wp = GsFindWindow(wid); if(!wp) { GsError(GR_ERROR_BAD_WINDOW_ID, wid); return; } /* Set window properties*/ if (props->flags & GR_WM_FLAGS_PROPS) wp->props = props->props; /* Set window title*/ if (props->flags & GR_WM_FLAGS_TITLE) { /* Remove the old title if it exists */ if(wp->title) free(wp->title); /* Calculate the space needed to store the new title */ if(props->title) tl = strlen(props->title) + 1; /* Check for empty title*/ if(!props->title || tl == 1) { wp->title = NULL; } else { /* Otherwise, allocate some space for the new title */ if(!(wp->title = malloc(tl))) GsError(GR_ERROR_MALLOC_FAILED, wid); else memcpy(wp->title, props->title, tl); } } /* Set window background*/ if (props->flags & GR_WM_FLAGS_BACKGROUND) { if (wp->background != props->background) { wp->background = props->background; GsExposeArea(wp, wp->x, wp->y, wp->width, wp->height, NULL); } } /* Set window border size*/ if (props->flags & GR_WM_FLAGS_BORDERSIZE) { if (wp->bordersize != props->bordersize) { GsWpUnmapWindow(wp, GR_TRUE); wp->bordersize = props->bordersize; GsWpMapWindow(wp, GR_TRUE); } } /* Set window border color*/ if (props->flags & GR_WM_FLAGS_BORDERCOLOR) { if (wp->bordercolor != props->bordercolor) { wp->bordercolor = props->bordercolor; if (wp->bordersize) GsDrawBorder(wp); } } } /* * Return all window properties */ void GrGetWMProperties(GR_WINDOW_ID wid, GR_WM_PROPERTIES *props) { GR_WINDOW *wp; /* Find the window structure, no error on invalid window id*/ wp = GsFindWindow(wid); if(!wp) { /* set flags to 0 on bad window id*/ memset(props, 0, sizeof(GR_WM_PROPERTIES)); return; } /* Return everything, regardless of props->flags*/ props->flags = GR_WM_FLAGS_PROPS | GR_WM_FLAGS_TITLE | GR_WM_FLAGS_BACKGROUND | GR_WM_FLAGS_BORDERSIZE | GR_WM_FLAGS_BORDERCOLOR; props->props = wp->props; props->title = wp->title; props->background = wp->background; props->bordersize = wp->bordersize; props->bordercolor = wp->bordercolor; } void GrCloseWindow(GR_WINDOW_ID wid) { GR_WINDOW *wp; /* Find the window structure (generate an error if it doesn't exist) */ wp = GsFindWindow(wid); if(!wp) { /* * no error for now, client/server problems * with nxwm when sent */ /*GsError(GR_ERROR_BAD_WINDOW_ID, wid);*/ return; } /* Send a CLOSE_REQ event to the client */ GsDeliverGeneralEvent(wp, GR_EVENT_TYPE_CLOSE_REQ, NULL); } void GrKillWindow(GR_WINDOW_ID wid) { GR_WINDOW *wp; /* Find the window structure (generate an error if it doesn't exist) */ wp = GsFindWindow(wid); if(!wp) { GsError(GR_ERROR_BAD_WINDOW_ID, wid); return; } /* Forcibly kill the connection to the client */ GsClose(wp->owner->id); } /* * GrGetSystemColor color scheme definitions */ /* define color scheme: A (tan), B (winstd) or C (old)*/ #define A #define A_RGB(r,g,b) #define B_RGB(r,g,b) #define C_RGB(r,g,b) #ifdef A #undef A_RGB #define A_RGB(r,g,b) GR_RGB(r,g,b), #endif #ifdef B #undef B_RGB #define B_RGB(r,g,b) GR_RGB(r,g,b), #endif #ifdef C #undef C_RGB #define C_RGB(r,g,b) GR_RGB(r,g,b), #endif #define MAXSYSCOLORS 20 /* # of GR_COLOR_* system colors*/ static GR_COLOR sysColors[MAXSYSCOLORS] = { /* desktop background*/ GR_RGB( 0, 128, 128), /* GR_COLOR_DESKTOP */ /* caption colors*/ A_RGB(128, 0, 0) /* GR_COLOR_ACTIVECAPTION */ B_RGB(128, 0, 128) /* GR_COLOR_ACTIVECAPTION */ C_RGB(128, 0, 128) /* GR_COLOR_ACTIVECAPTION */ GR_RGB(255, 255, 255), /* GR_COLOR_ACTIVECAPTIONTEXT */ A_RGB(162, 141, 104) /* GR_COLOR_INACTIVECAPTION */ B_RGB(128, 128, 128) /* GR_COLOR_INACTIVECAPTION */ C_RGB( 0, 64, 128) /* GR_COLOR_INACTIVECAPTION */ GR_RGB(192, 192, 192), /* GR_COLOR_INACTIVECAPTIONTEXT */ /* 3d border shades*/ GR_RGB( 0, 0, 0), /* GR_COLOR_WINDOWFRAME */ A_RGB(162, 141, 104) /* GR_COLOR_BTNSHADOW */ B_RGB(128, 128, 128) /* GR_COLOR_BTNSHADOW */ C_RGB(128, 128, 128) /* GR_COLOR_BTNSHADOW */ A_RGB(213, 204, 187) /* GR_COLOR_3DLIGHT */ B_RGB(223, 223, 223) /* GR_COLOR_3DLIGHT */ C_RGB(192, 192, 192) /* GR_COLOR_3DLIGHT */ A_RGB(234, 230, 221) /* GR_COLOR_BTNHIGHLIGHT */ B_RGB(255, 255, 255) /* GR_COLOR_BTNHIGHLIGHT */ C_RGB(223, 223, 223) /* GR_COLOR_BTNHIGHLIGHT */ /* top level application window backgrounds/text*/ A_RGB(213, 204, 187) /* GR_COLOR_APPWINDOW */ B_RGB(192, 192, 192) /* GR_COLOR_APPWINDOW */ C_RGB(160, 160, 160) /* GR_COLOR_APPWINDOW */ GR_RGB( 0, 0, 0), /* GR_COLOR_APPTEXT */ /* button control backgrounds/text (usually same as app window colors)*/ A_RGB(213, 204, 187) /* GR_COLOR_BTNFACE */ B_RGB(192, 192, 192) /* GR_COLOR_BTNFACE */ C_RGB(160, 160, 160) /* GR_COLOR_BTNFACE */ GR_RGB( 0, 0, 0), /* GR_COLOR_BTNTEXT */ /* edit/listbox control backgrounds/text, selected highlights*/ GR_RGB(255, 255, 255), /* GR_COLOR_WINDOW */ GR_RGB( 0, 0, 0), /* GR_COLOR_WINDOWTEXT */ GR_RGB(128, 0, 0), /* GR_COLOR_HIGHLIGHT */ GR_RGB(255, 255, 255), /* GR_COLOR_HIGHLIGHTTEXT */ GR_RGB( 64, 64, 64), /* GR_COLOR_GRAYTEXT */ /* menu backgrounds/text*/ A_RGB(213, 204, 187) /* GR_COLOR_MENU */ B_RGB(192, 192, 192) /* GR_COLOR_MENU */ C_RGB(160, 160, 160) /* GR_COLOR_MENU */ GR_RGB( 0, 0, 0), /* GR_COLOR_MENUTEXT */ }; /* Return system-defined color*/ GR_COLOR GrGetSysColor(int index) { if(index >= 0 && index < MAXSYSCOLORS) return sysColors[index]; return 0; } void GrSetScreenSaverTimeout(GR_TIMEOUT timeout) { MWTIMER *timer; screensaver_delay = timeout * 1000; if((timer = GdFindTimer(GsActivateScreenSaver))) GdDestroyTimer(timer); /* 0 timeout cancels timer*/ if (timeout == 0) return; GdAddTimer(screensaver_delay, GsActivateScreenSaver, GsActivateScreenSaver); } void GrSetSelectionOwner(GR_WINDOW_ID wid, GR_CHAR *typelist) { GR_WINDOW_ID oldwid = selection_owner.wid; if(selection_owner.typelist) free(selection_owner.typelist); selection_owner.wid = wid; if(wid) { if(!(selection_owner.typelist = strdup(typelist))) { GsError(GR_ERROR_MALLOC_FAILED, wid); selection_owner.wid = 0; } } else selection_owner.typelist = NULL; GsDeliverSelectionChangedEvent(oldwid, wid); } GR_WINDOW_ID GrGetSelectionOwner(GR_CHAR **typelist) { *typelist = selection_owner.typelist; return selection_owner.wid; } void GrRequestClientData(GR_WINDOW_ID wid, GR_WINDOW_ID rid, GR_SERIALNO serial, GR_MIMETYPE mimetype) { GsDeliverClientDataReqEvent(rid, wid, serial, mimetype); } void GrSendClientData(GR_WINDOW_ID wid, GR_WINDOW_ID did, GR_SERIALNO serial, GR_LENGTH len, GR_LENGTH thislen, void *data) { void *p; if(!(p = malloc(len))) { GsError(GR_ERROR_MALLOC_FAILED, wid); return; /* FIXME note no error to application*/ } memcpy(p, data, thislen); GsDeliverClientDataEvent(did, wid, serial, len, thislen, p); } /* * Set a window's background pixmap. Note that this doesn't * cause a screen refresh, use GrClearWindow if required. */ void GrSetBackgroundPixmap(GR_WINDOW_ID wid, GR_WINDOW_ID pixmap, int flags) { GR_WINDOW *wp; GR_PIXMAP *pp = NULL; if (!(wp = GsFindWindow(wid))) { GsError(GR_ERROR_BAD_WINDOW_ID, wid); return; } if (pixmap && !(pp = GsFindPixmap(pixmap))) { GsError(GR_ERROR_BAD_WINDOW_ID, pixmap); return; } wp->bgpixmap = pp; wp->bgpixmapflags = flags; } void GrGetFontList(GR_FONTLIST ***fonts, int *numfonts) { GdGetFontList(fonts,numfonts); } void GrFreeFontList(GR_FONTLIST ***fonts, int num) { GdFreeFontList(fonts, num); } /* * Return window parent and list of children. * Caller must free() children list after use. */ void GrQueryTree(GR_WINDOW_ID wid, GR_WINDOW_ID *parentid, GR_WINDOW_ID **children, GR_COUNT *nchildren) { GR_WINDOW *wp; GR_WINDOW *cp; GR_WINDOW_ID *retarray; GR_COUNT n = 0; wp = GsFindWindow(wid); if (!wp) { *parentid = 0; nochildren: *children = NULL; *nchildren = 0; return; } *parentid = wp->parent? wp->parent->id: 0; /* count children for alloc*/ for(cp=wp->children; cp; cp=cp->siblings) ++n; if (n == 0) goto nochildren; /* alloc return child array*/ retarray = (GR_WINDOW_ID *)malloc(n * sizeof(GR_WINDOW_ID)); if (!retarray) { GsError(GR_ERROR_MALLOC_FAILED, 0); goto nochildren; } /* fill in return array*/ n = 0; for(cp=wp->children; cp; cp=cp->siblings) { retarray[n++] = cp->id; } *children = retarray; *nchildren = n; } static int next_timer_id = 1000; /** * GrCreateTimer: * @wid: the ID of the window to use as a destination for GR_TIMER_EVENT * events that result from this timer. * @period: the timer period in milliseconds * @Returns: the ID of the newly created timer, or 0 if failure. * * Creates a Nano-X timer with the specified period. * NOTE: There is a potential for more GR_TIMER_EVENTS to be queued * in the connection between the Nano-X server and client. The client * should be able to handle late arriving GR_TIMER_EVENTs. */ GR_TIMER_ID GrCreateTimer (GR_WINDOW_ID wid, GR_TIMEOUT period) { GR_TIMER *timer; /* Create a nano-X layer timr */ timer = (GR_TIMER*) malloc (sizeof (GR_TIMER)); if (timer == NULL) { GsError (GR_ERROR_MALLOC_FAILED, 0); return 0; } /* Create a device independent layer timer */ timer->timer = GdAddPeriodicTimer (period, GsTimerCB, timer); if (timer->timer == NULL) { free (timer); GsError (GR_ERROR_MALLOC_FAILED, 0); return 0; } /* * Fill in the rest of the timer structure, and * link the new timer into the servers list of timers. */ timer->id = next_timer_id++; timer->owner = curclient; timer->wid = wid; timer->next = list_timer; list_timer = timer; return timer->id; } /** * GrDestroyTimer: * @tid: the ID of the timer to destroy * * Destroys a timer previously created with GrCreateTimer(). */ void GrDestroyTimer (GR_TIMER_ID tid) { GR_TIMER *timer; GR_TIMER *prev_timer; /* Find the timer structure that corresponds to "tid" */ timer = GsFindTimer (tid); if (timer == NULL) return; if (tid == cache_timer_id) { cache_timer_id = 0; cache_timer = NULL; } /* Delete the timer from the device independent engine layer */ GdDestroyTimer (timer->timer); /* Pull the timer out of the servers list */ if (list_timer == timer) { list_timer = timer->next; } else { prev_timer = list_timer; while (prev_timer->next != timer) { prev_timer = prev_timer->next; } prev_timer->next = timer->next; } free (timer); } /** * GrSetPortraitMode * @newmode: new portrait mode * * Sets new server portrait mode and redraws all windows. */ void GrSetPortraitMode(int portraitmode) { GsSetPortraitMode(portraitmode); }