2 * Copyright (c) 2000 Greg Haerr <greg@censoft.com>
3 * Copyright (c) 1991 David I. Bell
4 * Permission is granted to use, distribute, or modify this source,
5 * provided that this copyright notice remains intact.
7 * Graphics server utility routines for windows.
19 * Help prevent future bugs by defining this variable to an illegal value.
20 * These routines should not be referencing this, but should be using
23 #define mapped cannotusemapped
26 * Redraw the screen completely.
31 /* Redraw all windows*/
32 GsExposeArea(rootwp, 0, 0, rootwp->width, rootwp->height, NULL);
36 * Activate Screen Saver.
39 GsActivateScreenSaver(void *arg)
41 screensaver_active = GR_TRUE;
42 GsDeliverScreenSaverEvent(GR_TRUE);
46 * Deactivate screen saver and reset timer if active.
49 GsResetScreenSaver(void)
53 if(screensaver_active == GR_TRUE) {
54 screensaver_active = GR_FALSE;
55 GsDeliverScreenSaverEvent(GR_FALSE);
57 if(screensaver_delay) {
58 if((timer = GdFindTimer(GsActivateScreenSaver)))
59 GdDestroyTimer(timer);
60 GdAddTimer(screensaver_delay, GsActivateScreenSaver,
61 GsActivateScreenSaver);
68 GR_TIMER *timer = (GR_TIMER*) arg;
70 GsDeliverTimerEvent (timer->owner, timer->wid, timer->id);
75 * Unmap the window to make it and its children invisible on the screen.
76 * This is a recursive routine which increments the unmapcount values for
77 * this window and all of its children, and causes exposure events for
78 * windows which are newly uncovered.
79 * If temp_unmap set, don't reset focus or generate mouse/focus events,
80 * as window will be mapped again momentarily (window move, resize, etc)
82 void GsWpUnmapWindow(GR_WINDOW *wp, GR_BOOL temp_unmap)
84 GR_WINDOW *pwp; /* parent window */
85 GR_WINDOW *sibwp; /* sibling window */
86 GR_WINDOW *childwp; /* child window */
87 GR_SIZE bs; /* border size of this window */
90 GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wp->id);
99 for (childwp = wp->children; childwp; childwp = childwp->siblings)
100 GsWpUnmapWindow(childwp, temp_unmap);
102 if (!temp_unmap && wp == mousewp) {
103 GsCheckMouseWindow();
107 if (!temp_unmap && wp == focuswp) {
109 /* don't revert to mouse enter/leave focus if fixed*/
112 focusfixed = GR_FALSE;
113 GsCheckFocusWindow();
117 /* Send update event if just unmapped*/
118 if (wp->unmapcount == 1) {
119 GsDeliverUpdateEvent(wp,
120 (temp_unmap? GR_UPDATE_UNMAPTEMP: GR_UPDATE_UNMAP),
125 * If this is an input-only window or the parent window is
126 * still unmapped, then we are all done.
128 if (!wp->output || wp->parent->unmapcount)
132 * Clear the area in the parent for this window, causing an
133 * exposure event for it. Take into account the border size.
137 GsWpClearWindow(pwp, wp->x - pwp->x - bs, wp->y - pwp->y - bs,
138 wp->width + bs * 2, wp->height + bs * 2, GR_TRUE);
141 * Finally clear and redraw all parts of our lower sibling
142 * windows that were covered by this window.
145 while (sibwp->siblings) {
146 sibwp = sibwp->siblings;
147 GsExposeArea(sibwp, wp->x - bs, wp->y - bs,
148 wp->width + bs * 2, wp->height + bs * 2, NULL);
153 * Map the window to possibly make it and its children visible on the screen.
154 * This is a recursive routine which decrements the unmapcount values for
155 * this window and all of its children, and causes exposure events for
156 * those windows which become visible.
157 * If temp is set, then window is being mapped again after a temporary
158 * unmap, so don't reset focus or generate mouse/focus events.
160 void GsWpMapWindow(GR_WINDOW *wp, GR_BOOL temp)
163 GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wp->id);
170 if (!temp && wp->unmapcount == 0) {
171 GsCheckMouseWindow();
172 GsCheckFocusWindow();
176 /* send update event if just mapped*/
177 if (wp->unmapcount == 0) {
178 GsDeliverUpdateEvent(wp, GR_UPDATE_MAP, wp->x, wp->y,
179 wp->width, wp->height);
183 * If the window is an output window and just became visible,
184 * then draw its border, clear it to the background color, and
185 * generate an exposure event.
187 if (wp->output && (wp->unmapcount == 0)) {
189 GsWpClearWindow(wp, 0, 0, wp->width, wp->height, GR_TRUE);
193 * Do the same thing for the children.
195 for (wp = wp->children; wp; wp = wp->siblings)
196 GsWpMapWindow(wp, temp);
200 * Destroy the specified window, and all of its children.
201 * This is a recursive routine.
203 void GsWpDestroyWindow(GR_WINDOW *wp)
205 GR_WINDOW *prevwp; /* previous window pointer */
206 GR_EVENT_CLIENT *ecp; /* selections for window */
207 GR_WINDOW_ID oldwid; /* old selection owner */
210 GsError(GR_ERROR_ILLEGAL_ON_ROOT_WINDOW, wp->id);
214 /* Disable selection if this window is the owner */
215 if(selection_owner.wid == wp->id) {
216 oldwid = selection_owner.wid;
217 selection_owner.wid = 0;
218 if(selection_owner.typelist) free(selection_owner.typelist);
219 GsDeliverSelectionChangedEvent(oldwid, 0);
223 * Unmap the window first.
225 if (wp->unmapcount == 0)
226 GsWpUnmapWindow(wp, GR_FALSE);
228 /* send update event*/
229 GsDeliverUpdateEvent(wp, GR_UPDATE_DESTROY, wp->x, wp->y,
230 wp->width, wp->height);
233 * Destroy all children.
236 GsWpDestroyWindow(wp->children);
239 * Free all client selection structures.
241 while (wp->eventclients) {
242 ecp = wp->eventclients;
243 wp->eventclients = ecp->next;
248 * Remove this window from the child list of its parent.
250 prevwp = wp->parent->children;
252 wp->parent->children = wp->siblings;
254 while (prevwp->siblings != wp)
255 prevwp = prevwp->siblings;
256 prevwp->siblings = wp->siblings;
261 * Remove this window from the complete list of windows.
267 while (prevwp->next != wp)
268 prevwp = prevwp->next;
269 prevwp->next = wp->next;
274 * Forget various information if they related to this window.
275 * Then finally free the structure.
279 if (wp == grabbuttonwp)
286 /* don't revert to mouse enter/leave focus if fixed*/
287 /*focusfixed = GR_FALSE;*/
291 GsCheckMouseWindow();
300 * Draw a window's background pixmap.
303 * GR_BACKGROUND_TILE- tile the pixmap across the window (default).
304 * GR_BACKGROUND_TOPLEFT- draw the pixmap at (0,0) relative to the window.
305 * GR_BACKGROUND_CENTER- draw the pixmap in the middle of the window.
306 * GR_BACKGROUND_STRETCH- stretch the pixmap within the window.
307 * GR_BACKGROUND_TRANS- if the pixmap is smaller than the window and not
308 * using tile mode, there will be gaps around the pixmap. This flag causes
309 * to not fill in the spaces with the background colour.
311 void GsWpDrawBackgroundPixmap(GR_WINDOW *wp, GR_PIXMAP *pm, GR_COORD x,
312 GR_COORD y, GR_SIZE width, GR_SIZE height)
314 GR_SIZE destwidth, destheight, fillwidth, fillheight, pmwidth, pmheight;
315 GR_COORD fromx, fromy, destx, desty, pixmapx = 0, pixmapy = 0;
317 if(wp->bgpixmapflags & (GR_BACKGROUND_TOPLEFT|GR_BACKGROUND_STRETCH)) {
320 } else if(wp->bgpixmapflags & GR_BACKGROUND_CENTER) {
321 if(pm->width >= wp->width) pixmapx = 0;
322 else pixmapx = (wp->width - pm->width) / 2;
323 if(pm->height >= wp->height) pixmapy = 0;
324 else pixmapy = (wp->height - pm->height) / 2;
326 /* GR_BACKGROUND_TILE (default)*/
327 GsWpTileBackgroundPixmap(wp, pm, x, y, width, height);
331 if(pm->width > wp->width) pmwidth = wp->width;
332 else pmwidth = pm->width;
333 if(pm->height > wp->height) pmheight = wp->height;
334 else pmheight = pm->height;
339 destwidth = pixmapx + pmwidth - x;
343 destwidth = x + width - pixmapx;
349 destheight = pixmapy + pmheight - desty;
353 destheight = y + height - pixmapy;
356 if(destwidth > 0 && destheight > 0) {
357 if (wp->bgpixmapflags & GR_BACKGROUND_STRETCH) {
358 GdStretchBlit(wp->psd, destx + wp->x, desty + wp->y,
359 destwidth, destheight, pm->psd, fromx, fromy,
360 pm->width, pm->height, MWROP_COPY);
361 } else GdBlit(wp->psd, destx + wp->x, desty + wp->y, destwidth,
362 destheight, pm->psd, fromx, fromy, MWROP_COPY);
365 if(wp->bgpixmapflags & (GR_BACKGROUND_TRANS|GR_BACKGROUND_STRETCH))
368 /* Fill in the gaps around the pixmap */
370 fillwidth = pixmapx - x;
371 if(fillwidth > width) fillwidth = width;
373 GdFillRect(wp->psd, wp->x + x, wp->y + y, fillwidth,fillheight);
375 if((x + width) > (pixmapx + pmwidth)) {
376 fillwidth = (x + width) - (pixmapx + pmwidth);
377 if(fillwidth > width) fillwidth = width;
379 if(x < (pixmapx + pmwidth)) destx = pixmapx + pmwidth + wp->x;
380 else destx = x + wp->x;
381 GdFillRect(wp->psd, destx, wp->y + y, fillwidth, fillheight);
384 fillheight = pixmapy - y;
385 if(fillheight > height) fillheight = height;
386 if(x < pixmapx) destx = pixmapx + wp->x;
387 else destx = x + wp->x;
388 if((x + width) > (pixmapx + pmwidth))
389 fillwidth = pixmapx + pmwidth - destx;
390 else fillwidth = x + width - destx;
391 if((fillwidth > 0) && (fillheight > 0)) {
392 GdFillRect(wp->psd, destx, wp->y + y, fillwidth,
396 if((y + height) > (pixmapy + pmheight)) {
397 fillheight = (y + height) - (pixmapy + pmheight);
398 if(fillheight > height) fillheight = height;
399 if(x < pixmapx) destx = pixmapx + wp->x;
400 else destx = x + wp->x;
401 if(y < (pixmapy + pmheight)) desty = pixmapy + pmheight + wp->y;
402 else desty = y + wp->y;
404 if((x + width) > (pixmapx + pmwidth))
405 fillwidth = pixmapx + pmwidth - destx;
406 else fillwidth = x + width - destx;
407 if((fillwidth > 0) && (fillheight > 0)) {
408 GdFillRect(wp->psd, destx, desty, fillwidth,fillheight);
414 * Draw a tiled pixmap window background.
417 GsWpTileBackgroundPixmap(GR_WINDOW *wp, GR_PIXMAP *pm, GR_COORD x, GR_COORD y,
418 GR_SIZE width, GR_SIZE height)
420 GR_COORD tilex = 0, tiley = 0, fromx, fromy, cx, cy;
421 GR_SIZE destwidth, destheight, pmwidth, pmheight, cwidth, cheight;
423 if(pm->width > wp->width) pmwidth = wp->width;
424 else pmwidth = pm->width;
425 if(pm->height > wp->height) pmheight = wp->height;
426 else pmheight = pm->height;
428 for(;tiley < wp->height; tiley += pmheight, tilex = 0) {
429 if(tiley > (y + height)) continue;
430 if(y > (tiley + pmheight)) continue;
431 if((tiley + pmheight) > wp->height)
432 destheight = wp->height - tiley;
433 else destheight = pmheight;
434 for(;tilex < wp->width; tilex += pmwidth) {
435 if(tilex > (x + width)) continue;
436 if(x > (tilex + pmwidth)) continue;
437 if((tilex + pmwidth) > wp->width)
438 destwidth = wp->width - tilex;
439 else destwidth = pmwidth;
441 if((tilex >= x) && ((tilex + destwidth)<=(x + width))) {
448 cwidth = destwidth - fromx;
451 cwidth = x + width - tilex;
453 if(cwidth > width) cwidth = width;
454 if(cwidth > destwidth) cwidth = destwidth;
455 cx = wp->x + tilex + fromx;
458 if((tiley >= y)&&((tiley + destheight)<=(y + height))) {
461 cheight = destheight;
465 cheight = destheight - fromy;
468 cheight = y + height - tiley;
470 if(cwidth > width) cwidth = width;
471 if(cheight > destheight) cheight = destheight;
472 cy = wp->y + tiley + fromy;
475 if((cwidth > 0) && (cheight > 0)) {
476 GdBlit(wp->psd, cx, cy, cwidth, cheight,
477 pm->psd, fromx, fromy, MWROP_COPY);
484 * Clear the specified area of a window and possibly make an exposure event.
485 * This sets the area window to its background color or pixmap. If the
486 * exposeflag is nonzero, then this also creates an exposure event for the
490 GsWpClearWindow(GR_WINDOW *wp, GR_COORD x, GR_COORD y, GR_SIZE width,
491 GR_SIZE height, GR_BOOL exposeflag)
493 if (wp->unmapcount || !wp->output)
496 * Reduce the arguments so that they actually lie within the window.
506 if (x + width > wp->width)
507 width = wp->width - x;
508 if (y + height > wp->height)
509 height = wp->height - y;
512 * Now see if the region is really in the window. If not, then
515 if ((x >= wp->width) || (y >= wp->height) || (width <= 0) ||
520 * Draw the background of the window.
521 * Invalidate the current graphics context since
522 * we are changing the foreground color and mode.
524 GsSetClipWindow(wp, NULL, 0);
526 if (!(wp->props & GR_WM_PROPS_NOBACKGROUND)) {
527 GdSetMode(GR_MODE_COPY);
528 GdSetForeground(GdFindColor(wp->background));
530 GsWpDrawBackgroundPixmap(wp, wp->bgpixmap, x, y,
533 GdFillRect(wp->psd, wp->x + x, wp->y + y, width,height);
538 * Now do the exposure if required.
541 GsDeliverExposureEvent(wp, x, y, width, height);
545 * Handle the exposing of the specified absolute region of the screen,
546 * starting with the specified window. That window and all of its
547 * children will be redrawn and/or exposure events generated if they
548 * overlap the specified area. This is a recursive routine.
551 GsExposeArea(GR_WINDOW *wp, GR_COORD rootx, GR_COORD rooty, GR_SIZE width,
552 GR_SIZE height, GR_WINDOW *stopwp)
554 if (!wp->output || wp->unmapcount || wp == stopwp)
558 * First see if the area overlaps the window including the border.
559 * If not, then there is nothing more to do.
561 if ((rootx >= wp->x + wp->width + wp->bordersize) ||
562 (rooty >= wp->y + wp->height + wp->bordersize) ||
563 (rootx + width <= wp->x - wp->bordersize) ||
564 (rooty + height <= wp->y - wp->bordersize))
568 * The area does overlap the window. See if the area overlaps
569 * the border, and if so, then redraw it.
571 if ((rootx < wp->x) || (rooty < wp->y) ||
572 (rootx + width > wp->x + wp->width) ||
573 (rooty + height > wp->y + wp->height))
577 * Now clear the window itself in the specified area,
578 * which might cause an exposure event.
580 GsWpClearWindow(wp, rootx - wp->x, rooty - wp->y,
581 width, height, GR_TRUE);
584 * Now do the same for all the children.
586 for (wp = wp->children; wp; wp = wp->siblings)
587 GsExposeArea(wp, rootx, rooty, width, height, stopwp);
591 * Draw the border of a window if there is one.
592 * Note: To allow the border to be drawn with the correct clipping,
593 * we temporarily grow the size of the window to include the border.
595 void GsDrawBorder(GR_WINDOW *wp)
597 GR_COORD lminx; /* left edge minimum x */
598 GR_COORD rminx; /* right edge minimum x */
599 GR_COORD tminy; /* top edge minimum y */
600 GR_COORD bminy; /* bottom edge minimum y */
601 GR_COORD topy; /* top y value of window */
602 GR_COORD boty; /* bottom y value of window */
603 GR_SIZE width; /* original width of window */
604 GR_SIZE height; /* original height of window */
605 GR_SIZE bs; /* border size */
614 rminx = wp->x + width;
616 bminy = wp->y + height;
622 wp->width += (bs * 2);
623 wp->height += (bs * 2);
627 GsSetClipWindow(wp, NULL, 0);
629 GdSetMode(GR_MODE_COPY);
630 GdSetForeground(GdFindColor(wp->bordercolor));
633 GdLine(wp->psd, lminx, tminy, rminx, tminy, TRUE);
634 GdLine(wp->psd, lminx, bminy, rminx, bminy, TRUE);
635 GdLine(wp->psd, lminx, topy, lminx, boty, TRUE);
636 GdLine(wp->psd, rminx, topy, rminx, boty, TRUE);
638 GdFillRect(wp->psd, lminx, tminy, width + bs * 2, bs);
639 GdFillRect(wp->psd, lminx, bminy, width + bs * 2, bs);
640 GdFillRect(wp->psd, lminx, topy, bs, height);
641 GdFillRect(wp->psd, rminx, topy, bs, height);
645 * Restore the true window size.
646 * Forget the currently clipped window since we messed it up.
650 wp->width -= (bs * 2);
651 wp->height -= (bs * 2);
657 * Check to see if the first window overlaps the second window.
659 GR_BOOL GsCheckOverlap(GR_WINDOW *topwp, GR_WINDOW *botwp)
671 if (!topwp->output || topwp->unmapcount || botwp->unmapcount)
674 bs = topwp->bordersize;
675 minx1 = topwp->x - bs;
676 miny1 = topwp->y - bs;
677 maxx1 = topwp->x + topwp->width + bs - 1;
678 maxy1 = topwp->y + topwp->height + bs - 1;
680 bs = botwp->bordersize;
681 minx2 = botwp->x - bs;
682 miny2 = botwp->y - bs;
683 maxx2 = botwp->x + botwp->width + bs - 1;
684 maxy2 = botwp->y + botwp->height + bs - 1;
686 if ((minx1 > maxx2) || (minx2 > maxx1) || (miny1 > maxy2)
694 * Return a pointer to the window structure with the specified window id.
695 * Returns NULL if the window does not exist.
698 GsFindWindow(GR_WINDOW_ID id)
700 GR_WINDOW *wp; /* current window pointer */
703 * See if this is the root window or the same window as last time.
705 if (id == GR_ROOT_WINDOW_ID)
708 if ((id == cachewindowid) && id)
712 * No, search for it and cache it for future calls.
714 for (wp = listwp; wp; wp = wp->next) {
728 * Return a pointer to the pixmap structure with the specified window id.
729 * Returns NULL if the pixmap does not exist.
732 GsFindPixmap(GR_WINDOW_ID id)
734 GR_PIXMAP *pp; /* current pixmap pointer */
736 if ((id == cachepixmapid) && id)
740 * No, search for it and cache it for future calls.
742 for (pp = listpp; pp; pp = pp->next) {
755 * Return a pointer to the graphics context with the specified id.
756 * Returns NULL if the graphics context does not exist, with an
760 GsFindGC(GR_GC_ID gcid)
762 GR_GC *gcp; /* current graphics context pointer */
765 * See if this is the same graphics context as last time.
767 if ((gcid == cachegcid) && gcid)
771 * No, search for it and cache it for future calls.
773 for (gcp = listgcp; gcp; gcp = gcp->next) {
774 if (gcp->id == gcid) {
781 GsError(GR_ERROR_BAD_GC_ID, gcid);
786 /* Return a pointer to the region with the specified id.*/
788 GsFindRegion(GR_REGION_ID regionid)
790 GR_REGION *regionp; /* current region pointer */
792 for (regionp = listregionp; regionp; regionp = regionp->next) {
793 if (regionp->id == regionid) {
801 /* find a font with specified id*/
803 GsFindFont(GR_FONT_ID fontid)
807 for (fontp = listfontp; fontp; fontp = fontp->next) {
808 if (fontp->id == fontid)
814 /* find a cursor with specified id*/
816 GsFindCursor(GR_CURSOR_ID cursorid)
820 for (cursorp = listcursorp; cursorp; cursorp = cursorp->next) {
821 if (cursorp->id == cursorid)
828 GsFindTimer (GR_TIMER_ID timer_id)
833 * See if this is the same graphics context as last time.
835 if ((timer_id == cache_timer_id) && timer_id)
839 * No, search for it and cache it for future calls.
841 for (timer = list_timer; timer != NULL; timer = timer->next)
843 if (timer->id == timer_id)
845 cache_timer_id = timer_id;
855 * Prepare to do drawing in a window or pixmap using the specified
856 * graphics context. Returns the drawable pointer if successful,
857 * and the type of drawing id that was supplied. Returns the special value
858 * GR_DRAW_TYPE_NONE if an error is generated, or if drawing is useless.
860 GR_DRAW_TYPE GsPrepareDrawing(GR_DRAW_ID id, GR_GC_ID gcid, GR_DRAWABLE **retdp)
862 GR_WINDOW *wp; /* found window */
863 GR_PIXMAP *pp; /* found pixmap */
864 GR_GC *gcp; /* found graphics context */
866 GR_REGION *regionp; /* user clipping region */
872 gcp = GsFindGC(gcid);
874 return GR_DRAW_TYPE_NONE;
877 * If the graphics context is not the current one, then
878 * make it the current one and remember to update it.
882 gcp->changed = GR_TRUE;
886 * Look for window or pixmap id
889 wp = GsFindWindow(id);
891 pp = GsFindPixmap(id);
893 return GR_DRAW_TYPE_NONE;
896 reg = GdAllocRectRegion(0, 0, pp->psd->xvirtres,
898 /* intersect with user region if any*/
900 regionp = GsFindRegion(gcp->regionid);
902 GdIntersectRegion(reg, reg, regionp->rgn);
904 GdSetClipRegion(pp->psd, reg);
908 /* FIXME: setup pixmap clipping, different from windows*/
911 cliprect.width = pp->psd->xvirtres;
912 cliprect.height = pp->psd->yvirtres;
913 GdSetClipRects(pp->psd, 1, &cliprect);
916 /* reset clip cache for next window draw*/
921 GsError(GR_ERROR_INPUT_ONLY_WINDOW, id);
922 return GR_DRAW_TYPE_NONE;
926 return GR_DRAW_TYPE_NONE;
929 * If the window is not the currently clipped one,
930 * then make it the current one and define its clip rectangles.
932 if (wp != clipwp || gcp->changed) {
933 /* find user region for intersect*/
935 regionp = GsFindRegion(gcp->regionid);
939 * Special handling if user region is not at offset 0,0
941 if (regionp && (gcp->xoff || gcp->yoff)) {
942 MWCLIPREGION *local = GdAllocRegion();
944 GdCopyRegion(local, regionp->rgn);
945 GdOffsetRegion(local, gcp->xoff, gcp->yoff);
947 GsSetClipWindow(wp, local,
948 gcp->mode & ~GR_MODE_DRAWMASK);
950 GdDestroyRegion(local);
952 GsSetClipWindow(wp, regionp? regionp->rgn: NULL,
953 gcp->mode & ~GR_MODE_DRAWMASK);
959 * If the graphics context has been changed, then tell the
960 * device driver about it.
963 GdSetForeground(GdFindColor(gcp->foreground));
964 GdSetBackground(GdFindColor(gcp->background));
965 GdSetMode(gcp->mode & GR_MODE_DRAWMASK);
966 GdSetUseBackground(gcp->usebackground);
967 fontp = GsFindFont(gcp->fontid);
968 pf = fontp? fontp->pfont: stdfont;
970 gcp->changed = GR_FALSE;
973 *retdp = wp? (GR_DRAWABLE *)wp: (GR_DRAWABLE *)pp;
974 return wp? GR_DRAW_TYPE_WINDOW: GR_DRAW_TYPE_PIXMAP;
978 * Prepare the specified window for drawing into it.
979 * This sets up the clipping regions to just allow drawing into it.
980 * Returns NULL if the drawing is illegal (with an error generated),
981 * or if the window is not mapped.
983 GR_WINDOW *GsPrepareWindow(GR_WINDOW_ID wid)
985 GR_WINDOW *wp; /* found window */
987 wp = GsFindWindow(wid);
992 GsError(GR_ERROR_INPUT_ONLY_WINDOW, wid);
1000 /* FIXME: no user region clipping here*/
1001 GsSetClipWindow(wp, NULL, 0);
1008 * Find the window which is currently visible for the specified coordinates.
1009 * This just walks down the window tree looking for the deepest mapped
1010 * window which contains the specified point. If the coordinates are
1011 * off the screen, the root window is returned.
1013 GR_WINDOW *GsFindVisibleWindow(GR_COORD x, GR_COORD y)
1015 GR_WINDOW *wp; /* current window */
1016 GR_WINDOW *retwp; /* returned window */
1021 if ((wp->unmapcount == 0) && (wp->x <= x) && (wp->y <= y) &&
1022 (wp->x + wp->width > x) && (wp->y + wp->height > y))
1034 * Check to see if the cursor shape is the correct shape for its current
1035 * location. If not, its shape is changed.
1037 void GsCheckCursor(void)
1039 GR_WINDOW *wp; /* window cursor is in */
1040 GR_CURSOR *cp; /* cursor definition */
1043 * Get the cursor at its current position, and if it is not the
1044 * currently defined one, then set the new cursor. However,
1045 * if the pointer is currently grabbed, then leave it alone.
1051 cp = GsFindCursor(wp->cursorid);
1054 if (cp == curcursor)
1058 * It needs redefining, so do it.
1061 GdMoveCursor(cursorx - cp->cursor.hotx, cursory - cp->cursor.hoty);
1062 GdSetCursor(&cp->cursor);
1066 * Check to see if the window the mouse is currently in has changed.
1067 * If so, generate enter and leave events as required. The newest
1068 * mouse window is remembered in mousewp. However, do not change the
1069 * window while it is grabbed.
1071 void GsCheckMouseWindow(void)
1073 GR_WINDOW *wp; /* newest window for mouse */
1077 wp = GsFindVisibleWindow(cursorx, cursory);
1081 GsDeliverGeneralEvent(mousewp, GR_EVENT_TYPE_MOUSE_EXIT, NULL);
1085 GsDeliverGeneralEvent(wp, GR_EVENT_TYPE_MOUSE_ENTER, NULL);
1089 * Determine the current focus window for the current mouse coordinates.
1090 * The mouse coordinates only matter if the focus is not fixed. Otherwise,
1091 * the selected window is dependant on the window which wants keyboard
1092 * events. This also sets the current focus for that found window.
1093 * The window with focus is remembered in focuswp.
1095 void GsCheckFocusWindow(void)
1097 GR_WINDOW *wp; /* current window */
1098 GR_EVENT_CLIENT *ecp; /* current event client */
1099 GR_EVENT_MASK eventmask; /* event mask */
1104 eventmask = GR_EVENT_MASK_KEY_DOWN;
1107 * Walk upwards from the current window containing the mouse
1108 * looking for the first window which would accept a keyboard event.
1110 for (wp = mousewp; ;wp = wp->parent) {
1111 if (wp->props & GR_WM_PROPS_NOFOCUS)
1113 for (ecp = wp->eventclients; ecp; ecp = ecp->next) {
1114 if (ecp->eventmask & eventmask) {
1119 if ((wp == rootwp) || (wp->nopropmask & eventmask)) {
1120 GsWpSetFocus(rootwp);
1126 /* Send an update activate event to top level window of passed window*/
1128 GsWpNotifyActivate(GR_WINDOW *wp)
1132 for (pwp=wp; pwp->parent; pwp=pwp->parent)
1133 if (pwp->parent->id == GR_ROOT_WINDOW_ID)
1135 if (pwp->id != GR_ROOT_WINDOW_ID)
1136 GsDeliverUpdateEvent(pwp, GR_UPDATE_ACTIVATE, 0, 0, 0, 0);
1140 * Set the input focus to the specified window.
1141 * This generates focus out and focus in events as necessary.
1143 void GsWpSetFocus(GR_WINDOW *wp)
1145 GR_WINDOW *oldfocus;
1150 GsDeliverGeneralEvent(focuswp, GR_EVENT_TYPE_FOCUS_OUT, wp);
1151 GsWpNotifyActivate(focuswp);
1156 GsDeliverGeneralEvent(wp, GR_EVENT_TYPE_FOCUS_IN, oldfocus);
1157 GsWpNotifyActivate(focuswp);
1161 * Set dynamic portrait mode and redraw screen.
1164 GsSetPortraitMode(int mode)
1166 GdSetPortraitMode(&scrdev, mode);
1167 GdRestrictMouse(0, 0, scrdev.xvirtres - 1, scrdev.yvirtres - 1);
1169 /* reset clip and root window size*/
1171 rootwp->width = scrdev.xvirtres;
1172 rootwp->height = scrdev.yvirtres;
1174 /* deliver portrait changed event to all windows selecting it*/
1175 GsDeliverPortraitChangedEvent();
1177 /* redraw screen - apps may redraw/resize again causing flicker*/
1182 * Check mouse coordinates and possibly set indicated portrait
1183 * mode from mouse position.
1186 GsSetPortraitModeFromXY(GR_COORD rootx, GR_COORD rooty)
1192 switch (scrdev.portrait) {
1193 case MWPORTRAIT_NONE:
1195 newmode = MWPORTRAIT_LEFT;
1197 case MWPORTRAIT_LEFT:
1198 newmode = MWPORTRAIT_DOWN;
1200 case MWPORTRAIT_DOWN:
1201 newmode = MWPORTRAIT_RIGHT;
1203 case MWPORTRAIT_RIGHT:
1204 newmode = MWPORTRAIT_NONE;
1207 GsSetPortraitMode(newmode);
1208 GrMoveCursor(5, rooty);
1209 GdMoveMouse(5, rooty);
1210 } else if (rootx == scrdev.xvirtres-1) {
1212 switch (scrdev.portrait) {
1213 case MWPORTRAIT_NONE:
1215 newmode = MWPORTRAIT_RIGHT;
1217 case MWPORTRAIT_LEFT:
1218 newmode = MWPORTRAIT_NONE;
1220 case MWPORTRAIT_DOWN:
1221 newmode = MWPORTRAIT_LEFT;
1223 case MWPORTRAIT_RIGHT:
1224 newmode = MWPORTRAIT_DOWN;
1227 GsSetPortraitMode(newmode);
1228 GrMoveCursor(scrdev.xvirtres-5, rooty);
1229 GdMoveMouse(scrdev.xvirtres-5, rooty);