/* * Deliver a client data event. Delivered to the clients who have selected for * this event on the specified window only. */ void GsDeliverClientDataEvent(GR_WINDOW_ID wid, GR_WINDOW_ID rid, GR_SERIALNO serial, GR_LENGTH len, GR_LENGTH thislen, void *data) { GR_EVENT_CLIENT_DATA *gp; /* client data request event */ GR_EVENT_CLIENT *ecp; /* current event client */ GR_WINDOW *wp; if(!(wp = GsFindWindow(wid))) return; for (ecp = wp->eventclients; ecp; ecp = ecp->next) { if ((ecp->eventmask & GR_EVENT_MASK_CLIENT_DATA) == 0) continue; gp = (GR_EVENT_CLIENT_DATA *) GsAllocEvent(ecp->client); if (gp == NULL) continue; gp->type = GR_EVENT_TYPE_CLIENT_DATA; gp->wid = wid; gp->rid = rid; gp->serial = serial; gp->len = len; gp->datalen = thislen; if(!(gp->data = malloc(thislen))) { GsError(GR_ERROR_MALLOC_FAILED, wid); return; } memcpy(gp->data, data, thislen); continue; } }
/* * Return a pointer to the graphics context with the specified id. * Returns NULL if the graphics context does not exist, with an * error saved. */ GR_GC * GsFindGC(GR_GC_ID gcid) { GR_GC *gcp; /* current graphics context pointer */ /* * See if this is the same graphics context as last time. */ if ((gcid == cachegcid) && gcid) return cachegcp; /* * No, search for it and cache it for future calls. */ for (gcp = listgcp; gcp; gcp = gcp->next) { if (gcp->id == gcid) { cachegcid = gcid; cachegcp = gcp; return gcp; } } GsError(GR_ERROR_BAD_GC_ID, gcid); return NULL; }
/* * Update mouse status and issue events on it if necessary. * This function doesn't block, but is normally only called when * there is known to be some data waiting to be read from the mouse. */ void GsCheckMouseEvent(void) { COORD rootx; /* latest mouse x position */ COORD rooty; /* latest mouse y position */ BUTTON newbuttons; /* latest buttons */ int mousestatus; /* latest mouse status */ /* Read the latest mouse status: */ mousestatus = GdReadMouse(&rootx, &rooty, &newbuttons); if(mousestatus < 0) { GsError(GR_ERROR_MOUSE_ERROR, 0); return; } else if(mousestatus) /* Deliver events as appropriate: */ GsHandleMouseStatus(rootx, rooty, newbuttons); }
/* * Update keyboard status and issue events on it if necessary. * This function doesn't block, but is normally only called when * there is known to be some data waiting to be read from the keyboard. */ void GsCheckKeyboardEvent(void) { unsigned char ch; /* latest character */ MODIFIER modifiers; /* latest modifiers */ int keystatus; /* latest keyboard status */ /* Read the latest keyboard status: */ keystatus = GdReadKeyboard(&ch, &modifiers); if(keystatus < 0) { if(keystatus == -2) /* special case for ESC pressed*/ GsTerminate(); GsError(GR_ERROR_KEYBOARD_ERROR, 0); return; } else if(keystatus) /* Deliver events as appropriate: */ GsDeliverKeyboardEvent(GR_EVENT_TYPE_KEY_DOWN, ch, modifiers); }
/* * Allocate an event to be passed back to the specified client. * The event is already chained onto the event queue, and only * needs filling out. Returns NULL with an error generated if * the event cannot be allocated. */ GR_EVENT *GsAllocEvent(GR_CLIENT *client) { GR_EVENT_LIST *elp; /* current element list */ GR_CLIENT *oldcurclient; /* old current client */ /* * Get a new event structure from the free list, or else * allocate it using malloc. */ elp = eventfree; if (elp) eventfree = elp->next; else { elp = (GR_EVENT_LIST *) malloc(sizeof(GR_EVENT_LIST)); if (elp == NULL) { oldcurclient = curclient; curclient = client; GsError(GR_ERROR_MALLOC_FAILED, 0); curclient = oldcurclient; return NULL; } } /* * Add the event to the end of the event list. */ if (client->eventhead) if (!client->eventtail) client->eventtail = elp; else client->eventtail->next = elp; else client->eventhead = elp; client->eventtail = elp; elp->next = NULL; elp->event.type = GR_EVENT_TYPE_NONE; return &elp->event; }
/* * Update mouse status and issue events on it if necessary. * This function doesn't block, but is normally only called when * there is known to be some data waiting to be read from the mouse. */ GR_BOOL GsCheckMouseEvent(void) { GR_COORD rootx; /* latest mouse x position */ GR_COORD rooty; /* latest mouse y position */ int newbuttons; /* latest buttons */ int mousestatus; /* latest mouse status */ /* Read the latest mouse status: */ mousestatus = GdReadMouse(&rootx, &rooty, &newbuttons); if(mousestatus < 0) { GsError(GR_ERROR_MOUSE_ERROR, 0); return FALSE; } else if(mousestatus) { /* Deliver events as appropriate: */ GsHandleMouseStatus(rootx, rooty, newbuttons); /* possibly reset portrait mode based on mouse position*/ if (autoportrait) GsSetPortraitModeFromXY(rootx, rooty); return TRUE; } return FALSE; }
/* * Map the window to possibly make it and its children visible on the screen. * This is a recursive routine which decrements the unmapcount values for * this window and all of its children, and causes exposure events for * those windows which become visible. * If temp is set, then window is being mapped again after a temporary * unmap, so don't reset focus or generate mouse/focus events. */ void GsWpMapWindow(GR_WINDOW *wp, GR_BOOL temp) { if (wp == rootwp) { GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wp->id); return; } if (wp->unmapcount) --wp->unmapcount; if (!temp && wp->unmapcount == 0) { GsCheckMouseWindow(); GsCheckFocusWindow(); GsCheckCursor(); } /* send update event if just mapped*/ if (wp->unmapcount == 0) { GsDeliverUpdateEvent(wp, GR_UPDATE_MAP, wp->x, wp->y, wp->width, wp->height); } /* * If the window is an output window and just became visible, * then draw its border, clear it to the background color, and * generate an exposure event. */ if (wp->output && (wp->unmapcount == 0)) { GsDrawBorder(wp); GsWpClearWindow(wp, 0, 0, wp->width, wp->height, GR_TRUE); } /* * Do the same thing for the children. */ for (wp = wp->children; wp; wp = wp->siblings) GsWpMapWindow(wp, temp); }
/* * Prepare the specified window for drawing into it. * This sets up the clipping regions to just allow drawing into it. * Returns NULL if the drawing is illegal (with an error generated), * or if the window is not mapped. */ GR_WINDOW *GsPrepareWindow(GR_WINDOW_ID wid) { GR_WINDOW *wp; /* found window */ wp = GsFindWindow(wid); if (wp == NULL) return NULL; if (!wp->output) { GsError(GR_ERROR_INPUT_ONLY_WINDOW, wid); return NULL; } if (wp->unmapcount) return NULL; if (wp != clipwp) { /* FIXME: no user region clipping here*/ GsSetClipWindow(wp, NULL, 0); } return wp; }
/* * Update keyboard status and issue events on it if necessary. * This function doesn't block, but is normally only called when * there is known to be some data waiting to be read from the keyboard. */ GR_BOOL GsCheckKeyboardEvent(void) { MWKEY mwkey; /* latest character */ MWKEYMOD modifiers; /* latest modifiers */ MWSCANCODE scancode; int keystatus; /* latest keyboard status */ /* Read the latest keyboard status: */ keystatus = GdReadKeyboard(&mwkey, &modifiers, &scancode); if(keystatus < 0) { if(keystatus == -2) /* special case return code*/ GsTerminate(); GsError(GR_ERROR_KEYBOARD_ERROR, 0); return FALSE; } else if(keystatus) { /* Deliver events as appropriate: */ switch (mwkey) { case MWKEY_QUIT: GsTerminate(); /* no return*/ case MWKEY_REDRAW: GsRedrawScreen(); break; case MWKEY_PRINT: if (keystatus == 1) GdCaptureScreen("screen.bmp"); break; } GsDeliverKeyboardEvent(0, (keystatus==1? GR_EVENT_TYPE_KEY_DOWN: GR_EVENT_TYPE_KEY_UP), mwkey, modifiers, scancode); return TRUE; } return FALSE; }
/* * Prepare to do drawing in a window or pixmap using the specified * graphics context. Returns the drawable pointer if successful, * and the type of drawing id that was supplied. Returns the special value * GR_DRAW_TYPE_NONE if an error is generated, or if drawing is useless. */ GR_DRAW_TYPE GsPrepareDrawing(GR_DRAW_ID id, GR_GC_ID gcid, GR_DRAWABLE **retdp) { GR_WINDOW *wp; /* found window */ GR_PIXMAP *pp; /* found pixmap */ GR_GC *gcp; /* found graphics context */ GR_FONT *fontp; GR_REGION *regionp; /* user clipping region */ MWCLIPREGION *reg; PMWFONT pf; *retdp = NULL; gcp = GsFindGC(gcid); if (gcp == NULL) return GR_DRAW_TYPE_NONE; /* * If the graphics context is not the current one, then * make it the current one and remember to update it. */ if (gcp != curgcp) { curgcp = gcp; gcp->changed = GR_TRUE; } /* * Look for window or pixmap id */ pp = NULL; wp = GsFindWindow(id); if (wp == NULL) { pp = GsFindPixmap(id); if (pp == NULL) return GR_DRAW_TYPE_NONE; #if DYNAMICREGIONS reg = GdAllocRectRegion(0, 0, pp->psd->xvirtres, pp->psd->yvirtres); /* intersect with user region if any*/ if (gcp->regionid) { regionp = GsFindRegion(gcp->regionid); if (regionp) GdIntersectRegion(reg, reg, regionp->rgn); } GdSetClipRegion(pp->psd, reg); #else { MWCLIPRECT cliprect; /* FIXME: setup pixmap clipping, different from windows*/ cliprect.x = 0; cliprect.y = 0; cliprect.width = pp->psd->xvirtres; cliprect.height = pp->psd->yvirtres; GdSetClipRects(pp->psd, 1, &cliprect); } #endif /* reset clip cache for next window draw*/ clipwp = NULL; } else { if (!wp->output) { GsError(GR_ERROR_INPUT_ONLY_WINDOW, id); return GR_DRAW_TYPE_NONE; } if (wp->unmapcount) return GR_DRAW_TYPE_NONE; /* * If the window is not the currently clipped one, * then make it the current one and define its clip rectangles. */ if (wp != clipwp || gcp->changed) { /* find user region for intersect*/ if (gcp->regionid) regionp = GsFindRegion(gcp->regionid); else regionp = NULL; /* * Special handling if user region is not at offset 0,0 */ if (regionp && (gcp->xoff || gcp->yoff)) { MWCLIPREGION *local = GdAllocRegion(); GdCopyRegion(local, regionp->rgn); GdOffsetRegion(local, gcp->xoff, gcp->yoff); GsSetClipWindow(wp, local, gcp->mode & ~GR_MODE_DRAWMASK); GdDestroyRegion(local); } else { GsSetClipWindow(wp, regionp? regionp->rgn: NULL, gcp->mode & ~GR_MODE_DRAWMASK); } } } /* * If the graphics context has been changed, then tell the * device driver about it. */ if (gcp->changed) { GdSetForeground(GdFindColor(gcp->foreground)); GdSetBackground(GdFindColor(gcp->background)); GdSetMode(gcp->mode & GR_MODE_DRAWMASK); GdSetUseBackground(gcp->usebackground); fontp = GsFindFont(gcp->fontid); pf = fontp? fontp->pfont: stdfont; GdSetFont(pf); gcp->changed = GR_FALSE; } *retdp = wp? (GR_DRAWABLE *)wp: (GR_DRAWABLE *)pp; return wp? GR_DRAW_TYPE_WINDOW: GR_DRAW_TYPE_PIXMAP; }
/* * Unmap the window to make it and its children invisible on the screen. * This is a recursive routine which increments the unmapcount values for * this window and all of its children, and causes exposure events for * windows which are newly uncovered. * If temp_unmap set, don't reset focus or generate mouse/focus events, * as window will be mapped again momentarily (window move, resize, etc) */ void GsWpUnmapWindow(GR_WINDOW *wp, GR_BOOL temp_unmap) { GR_WINDOW *pwp; /* parent window */ GR_WINDOW *sibwp; /* sibling window */ GR_WINDOW *childwp; /* child window */ GR_SIZE bs; /* border size of this window */ if (wp == rootwp) { GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wp->id); return; } if (wp == clipwp) clipwp = NULL; ++wp->unmapcount; for (childwp = wp->children; childwp; childwp = childwp->siblings) GsWpUnmapWindow(childwp, temp_unmap); if (!temp_unmap && wp == mousewp) { GsCheckMouseWindow(); GsCheckCursor(); } if (!temp_unmap && wp == focuswp) { if (focusfixed) /* don't revert to mouse enter/leave focus if fixed*/ focuswp = rootwp; else { focusfixed = GR_FALSE; GsCheckFocusWindow(); } } /* Send update event if just unmapped*/ if (wp->unmapcount == 1) { GsDeliverUpdateEvent(wp, (temp_unmap? GR_UPDATE_UNMAPTEMP: GR_UPDATE_UNMAP), 0, 0, 0, 0); } /* * If this is an input-only window or the parent window is * still unmapped, then we are all done. */ if (!wp->output || wp->parent->unmapcount) return; /* * Clear the area in the parent for this window, causing an * exposure event for it. Take into account the border size. */ bs = wp->bordersize; pwp = wp->parent; GsWpClearWindow(pwp, wp->x - pwp->x - bs, wp->y - pwp->y - bs, wp->width + bs * 2, wp->height + bs * 2, GR_TRUE); /* * Finally clear and redraw all parts of our lower sibling * windows that were covered by this window. */ sibwp = wp; while (sibwp->siblings) { sibwp = sibwp->siblings; GsExposeArea(sibwp, wp->x - bs, wp->y - bs, wp->width + bs * 2, wp->height + bs * 2, NULL); } }
/* * Destroy the specified window, and all of its children. * This is a recursive routine. */ void GsWpDestroyWindow(GR_WINDOW *wp) { GR_WINDOW *prevwp; /* previous window pointer */ GR_EVENT_CLIENT *ecp; /* selections for window */ GR_WINDOW_ID oldwid; /* old selection owner */ if (wp == rootwp) { GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wp->id); return; } /* Disable selection if this window is the owner */ if(selection_owner.wid == wp->id) { oldwid = selection_owner.wid; selection_owner.wid = 0; if(selection_owner.typelist) free(selection_owner.typelist); GsDeliverSelectionChangedEvent(oldwid, 0); } /* * Unmap the window first. */ if (wp->unmapcount == 0) GsWpUnmapWindow(wp, GR_FALSE); /* send update event*/ GsDeliverUpdateEvent(wp, GR_UPDATE_DESTROY, wp->x, wp->y, wp->width, wp->height); /* * Destroy all children. */ while (wp->children) GsWpDestroyWindow(wp->children); /* * Free all client selection structures. */ while (wp->eventclients) { ecp = wp->eventclients; wp->eventclients = ecp->next; free(ecp); } /* * Remove this window from the child list of its parent. */ prevwp = wp->parent->children; if (prevwp == wp) wp->parent->children = wp->siblings; else { while (prevwp->siblings != wp) prevwp = prevwp->siblings; prevwp->siblings = wp->siblings; } wp->siblings = NULL; /* * Remove this window from the complete list of windows. */ prevwp = listwp; if (prevwp == wp) listwp = wp->next; else { while (prevwp->next != wp) prevwp = prevwp->next; prevwp->next = wp->next; } wp->next = NULL; /* * Forget various information if they related to this window. * Then finally free the structure. */ if (wp == clipwp) clipwp = NULL; if (wp == grabbuttonwp) grabbuttonwp = NULL; if (wp == cachewp) { cachewindowid = 0; cachewp = NULL; } if (wp == focuswp) { /* don't revert to mouse enter/leave focus if fixed*/ /*focusfixed = GR_FALSE;*/ focuswp = rootwp; } GsCheckMouseWindow(); if(wp->title) free(wp->title); free(wp); }
/* * Set the clip rectangles for a window taking into account other * windows that may be obscuring it. The windows that may be obscuring * this one are the siblings of each direct ancestor which are higher * in priority than those ancestors. Also, each parent limits the visible * area of the window. The clipping is not done if it is already up to * date of if the window is not outputtable. */ void GsSetClipWindow(GR_WINDOW *wp, MWCLIPREGION *userregion, int flags) { GR_WINDOW *pwp; /* parent window */ GR_WINDOW *sibwp; /* sibling windows */ MWCLIPRECT *clip; /* first clip rectangle */ GR_COUNT count; /* number of clip rectangles */ GR_COUNT newcount; /* number of new rectangles */ GR_COUNT i; /* current index */ GR_COORD minx; /* minimum clip x coordinate */ GR_COORD miny; /* minimum clip y coordinate */ GR_COORD maxx; /* maximum clip x coordinate */ GR_COORD maxy; /* maximum clip y coordinate */ GR_COORD diff; /* difference in coordinates */ GR_SIZE bs; /* border size */ GR_BOOL toomany; /* TRUE if too many clip rects */ MWCLIPRECT cliprects[MAX_CLIPRECTS]; /* clip rectangles */ if (!wp->realized || !wp->output || (wp == clipwp)) return; clipwp = wp; /* * Start with the rectangle for the complete window. * We will then cut pieces out of it as needed. */ count = 1; clip = cliprects; clip->x = wp->x; clip->y = wp->y; clip->width = wp->width; clip->height = wp->height; /* * First walk upwards through all parent windows, * and restrict the visible part of this window to the part * that shows through all of those parent windows. */ pwp = wp; while (pwp != rootwp) { pwp = pwp->parent; diff = pwp->x - clip->x; if (diff > 0) { clip->width -= diff; clip->x = pwp->x; } diff = (pwp->x + pwp->width) - (clip->x + clip->width); if (diff < 0) clip->width += diff; diff = pwp->y - clip->y; if (diff > 0) { clip->height -= diff; clip->y = pwp->y; } diff = (pwp->y + pwp->height) - (clip->y + clip->height); if (diff < 0) clip->height += diff; } /* * If the window is completely clipped out of view, then * set the clipping region to indicate that. */ if ((clip->width <= 0) || (clip->height <= 0)) { GdSetClipRects(clipwp->psd, 1, cliprects); return; } /* * Now examine all windows that obscure this window, and * for each obscuration, break up the clip rectangles into * the smaller pieces that are still visible. The windows * that can obscure us are the earlier siblings of all of * our parents. */ toomany = GR_FALSE; pwp = wp; /*while (pwp != rootwp) {*/ while (pwp != NULL) { wp = pwp; pwp = wp->parent; if(!pwp) { /* We're clipping the root window*/ sibwp = rootwp->children; wp = NULL; } else sibwp = pwp->children; for (; sibwp != wp; sibwp = sibwp->siblings) { if (!sibwp->realized || !sibwp->output) continue; bs = sibwp->bordersize; minx = sibwp->x - bs; miny = sibwp->y - bs; maxx = sibwp->x + sibwp->width + bs - 1; maxy = sibwp->y + sibwp->height + bs - 1; newcount = count; for (i = 0; i < count; i++) { if (newcount > MAX_CLIPRECTS - 3) { toomany = GR_TRUE; break; } newcount += GsSplitClipRect(&cliprects[i], &cliprects[newcount], minx, miny, maxx, maxy); } count = newcount; } if(pwp == rootwp) break; } if (toomany) { GsError(GR_ERROR_TOO_MUCH_CLIPPING, wp->id); clip->x = 0; clip->y = 0; clip->width = -1; clip->height = -1; count = 1; } /* * Set the clip rectangles. */ GdSetClipRects(clipwp->psd, count, cliprects); }
/* * Destroy the specified window, and all of its children. * This is a recursive routine. */ void GsDestroyWindow(GR_WINDOW *wp) { GR_WINDOW *prevwp; /* previous window pointer */ GR_EVENT_CLIENT *ecp; /* selections for window */ GR_WINDOW_ID oldwid; /* old selection owner */ GR_GRABBED_KEY *keygrab; GR_GRABBED_KEY **keygrab_prev_next; if (wp == rootwp) { GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wp->id); return; } /* Disable selection if this window is the owner */ if(selection_owner.wid == wp->id) { oldwid = selection_owner.wid; selection_owner.wid = 0; if(selection_owner.typelist) free(selection_owner.typelist); selection_owner.typelist = NULL; GsDeliverSelectionChangedEvent(oldwid, 0); } /* * Unmap the window first. */ if (wp->realized) GsUnrealizeWindow(wp, GR_FALSE); /* send destroy update event*/ GsDeliverUpdateEvent(wp, GR_UPDATE_DESTROY, wp->x, wp->y, wp->width, wp->height); /* * Destroy all children. */ while (wp->children) GsDestroyWindow(wp->children); /* * Free all client selection structures. */ while (wp->eventclients) { ecp = wp->eventclients; wp->eventclients = ecp->next; DPRINTF("FREE 1 %lx\n", (long)ecp); // FIXME free(ecp); } /* * Remove this window from the child list of its parent. */ prevwp = wp->parent->children; if (prevwp == wp) wp->parent->children = wp->siblings; else { while (prevwp->siblings != wp) prevwp = prevwp->siblings; prevwp->siblings = wp->siblings; } wp->siblings = NULL; /* * Remove this window from the complete list of windows. */ prevwp = listwp; if (prevwp == wp) listwp = wp->next; else { while (prevwp->next != wp) prevwp = prevwp->next; prevwp->next = wp->next; } wp->next = NULL; /* * Forget various information if they related to this window. * Then finally free the structure. */ if (wp == clipwp) clipwp = NULL; if (wp == grabbuttonwp) grabbuttonwp = NULL; if (wp == cachewp) { cachewindowid = 0; cachewp = NULL; } if (wp == focuswp) { /* don't revert to mouse enter/leave focus if fixed*/ /*focusfixed = GR_FALSE;*/ focuswp = rootwp; } GsCheckMouseWindow(); /* * Free title, pixmaps and clipregions associated with window. */ if (wp->title) free(wp->title); if (wp->bgpixmap) GsDestroyPixmap(wp->bgpixmap); if (wp->buffer) GsDestroyPixmap(wp->buffer); #if DYNAMICREGIONS if (wp->clipregion) GdDestroyRegion(wp->clipregion); #endif /* Remove any grabbed keys for this window. */ keygrab_prev_next = &list_grabbed_keys; keygrab = list_grabbed_keys; while (keygrab != NULL) { if (keygrab->wid == wp->id){ /* Delete keygrab. */ *keygrab_prev_next = keygrab->next; free(keygrab); keygrab = *keygrab_prev_next; } else { keygrab_prev_next = &keygrab->next; keygrab = keygrab->next; } } free(wp); }
/* * Map the window to possibly make it and its children visible on the screen. * This is a recursive routine which realizes this window and all of its * children, and causes exposure events for those windows which become visible. * If temp is set, then window is being mapped again after a temporary * unmap, so don't reset focus or generate mouse/focus events. */ void GsRealizeWindow(GR_WINDOW *wp, GR_BOOL temp) { if (wp == rootwp) { GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wp->id); return; } /*printf("RealizeWindow %d, map %d realized %d, parent_realized %d\n", wp->id, wp->mapped, wp->realized, wp->parent->realized);*/ #define OLDWAY 0 #if OLDWAY /* old way, doesn't quite work with unmap/map yourself*/ /* * If window is already realized, or if window * isn't set to be mapped, or parent isn't * realized, then we're done */ if (wp->realized || !wp->mapped || !wp->parent->realized) return; #else /* new way, still small bug with xfreecell and popup windows*/ /* if window is already realized, we're done*/ if (wp->realized) return; /* * Send map update event for window manager or others */ /* send map update event if not temp unmap/map*/ if (!temp) { GsDeliverUpdateEvent(wp, GR_UPDATE_MAP, wp->x, wp->y, wp->width, wp->height); } /* * If window isn't set to be mapped, or parent isn't * realized, then we're done */ if (!wp->mapped || !wp->parent->realized) return; #endif /* set window visible flag*/ wp->realized = GR_TRUE; if (!temp) { GsCheckMouseWindow(); GsCheckFocusWindow(); GsCheckCursor(); } #if OLDWAY /* send map update event if not temp unmap/map*/ if (!temp) { GsDeliverUpdateEvent(wp, GR_UPDATE_MAP, wp->x, wp->y, wp->width, wp->height); } #endif /* * If the window is an output window, then draw its border, * clear it to the background color, and generate an exposure event. */ if (wp->output) { GsDrawBorder(wp); GsClearWindow(wp, 0, 0, wp->width, wp->height, 1); } /* * Do the same thing for the children. */ for (wp = wp->children; wp; wp = wp->siblings) GsRealizeWindow(wp, temp); }
/* * Prepare to do drawing in a window or pixmap using the specified * graphics context. Returns the drawable pointer if successful, * and the type of drawing id that was supplied. Returns the special value * GR_DRAW_TYPE_NONE if an error is generated, or if drawing is useless. */ GR_DRAW_TYPE GsPrepareDrawing(GR_DRAW_ID id, GR_GC_ID gcid, GR_DRAWABLE **retdp) { GR_WINDOW *wp; /* found window */ GR_PIXMAP *pp; /* found pixmap */ GR_GC *gcp; /* found graphics context */ GR_REGION *regionp; /* user clipping region */ MWCLIPREGION*reg; *retdp = NULL; gcp = GsFindGC(gcid); if (gcp == NULL) return GR_DRAW_TYPE_NONE; /* * If the graphics context is not the current one, then * make it the current one and remember to update it. */ if (gcp != curgcp) { curgcp = gcp; gcp->changed = GR_TRUE; } /* * Look for window or pixmap id */ pp = NULL; wp = GsFindWindow(id); if (wp == NULL) { pp = GsFindPixmap(id); if (pp == NULL) return GR_DRAW_TYPE_NONE; havepixmap: #if DYNAMICREGIONS reg = GdAllocRectRegion(0, 0, pp->psd->xvirtres, pp->psd->yvirtres); /* intersect with user region if any*/ if (gcp->regionid) { regionp = GsFindRegion(gcp->regionid); if (regionp) { /* handle pixmap offsets*/ if (gcp->xoff || gcp->yoff) { MWCLIPREGION *local = GdAllocRegion(); GdCopyRegion(local, regionp->rgn); GdOffsetRegion(local, gcp->xoff, gcp->yoff); GdIntersectRegion(reg, reg, local); GdDestroyRegion(local); } else GdIntersectRegion(reg, reg, regionp->rgn); } } GdSetClipRegion(pp->psd, reg); #else { MWCLIPRECT cliprect; /* FIXME: setup pixmap clipping, different from windows*/ cliprect.x = 0; cliprect.y = 0; cliprect.width = pp->psd->xvirtres; cliprect.height = pp->psd->yvirtres; GdSetClipRects(pp->psd, 1, &cliprect); } #endif /* reset clip cache for next window draw*/ clipwp = NULL; } else { if (!wp->output) { GsError(GR_ERROR_INPUT_ONLY_WINDOW, id); return GR_DRAW_TYPE_NONE; } /* check if buffered window*/ if (wp->props & GR_WM_PROPS_BUFFERED) { pp = wp->buffer; wp = NULL; goto havepixmap; /* draw into pixmap buffer*/ } if (!wp->realized) return GR_DRAW_TYPE_NONE; /* * If the window is not the currently clipped one, * then make it the current one and define its clip rectangles. */ if (wp != clipwp || gcp->changed) { #if DYNAMICREGIONS /* find user region for intersect*/ regionp = gcp->regionid? GsFindRegion(gcp->regionid): NULL; /* Special handling if user region is not at offset 0,0*/ if (regionp && (gcp->xoff || gcp->yoff)) { MWCLIPREGION *local = GdAllocRegion(); GdCopyRegion(local, regionp->rgn); GdOffsetRegion(local, gcp->xoff, gcp->yoff); GsSetClipWindow(wp, local, gcp->mode & ~GR_MODE_DRAWMASK); GdDestroyRegion(local); } else GsSetClipWindow(wp, regionp? regionp->rgn: NULL, gcp->mode & ~GR_MODE_DRAWMASK); #else GsSetClipWindow(wp, NULL, gcp->mode & ~GR_MODE_DRAWMASK); #endif /* DYNAMICREGIONS*/ } } /* * If the graphics context has been changed, then tell the * device driver about it. */ if (gcp->changed) { PSD psd = (wp ? wp->psd : pp->psd); uint32_t mask; int count; if (gcp->linestyle == GR_LINE_SOLID) { mask = 0; count = 0; } else { mask = gcp->dashmask; count = gcp->dashcount; } if (gcp->fgispixelval) GdSetForegroundPixelVal(psd, gcp->foreground); else GdSetForegroundColor(psd, gcp->foreground); if (gcp->bgispixelval) GdSetBackgroundPixelVal(psd, gcp->background); else GdSetBackgroundColor(psd, gcp->background); GdSetMode(gcp->mode & GR_MODE_DRAWMASK); GdSetUseBackground(gcp->usebackground); #if MW_FEATURE_SHAPES GdSetDash(&mask, &count); GdSetFillMode(gcp->fillmode); GdSetTSOffset(gcp->ts_offset.x, gcp->ts_offset.y); switch(gcp->fillmode) { case GR_FILL_STIPPLE: case GR_FILL_OPAQUE_STIPPLE: GdSetStippleBitmap(gcp->stipple.bitmap, gcp->stipple.width, gcp->stipple.height); break; case GR_FILL_TILE: GdSetTilePixmap(gcp->tile.psd, gcp->tile.width, gcp->tile.height); break; } #endif gcp->changed = GR_FALSE; } *retdp = wp? (GR_DRAWABLE *)wp: (GR_DRAWABLE *)pp; return wp? GR_DRAW_TYPE_WINDOW: GR_DRAW_TYPE_PIXMAP; }