miwindow.c revision 05b261ec
1/***********************************************************
2
3Copyright 1987, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25
26Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
27
28                        All Rights Reserved
29
30Permission to use, copy, modify, and distribute this software and its
31documentation for any purpose and without fee is hereby granted,
32provided that the above copyright notice appear in all copies and that
33both that copyright notice and this permission notice appear in
34supporting documentation, and that the name of Digital not be
35used in advertising or publicity pertaining to distribution of the
36software without specific, written prior permission.
37
38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44SOFTWARE.
45
46******************************************************************/
47#ifdef HAVE_DIX_CONFIG_H
48#include <dix-config.h>
49#endif
50
51#include <X11/X.h>
52#include "regionstr.h"
53#include "region.h"
54#include "mi.h"
55#include "windowstr.h"
56#include "scrnintstr.h"
57#include "pixmapstr.h"
58#include "mivalidate.h"
59
60_X_EXPORT void
61miClearToBackground(pWin, x, y, w, h, generateExposures)
62    WindowPtr pWin;
63    int x,y;
64    int w,h;
65    Bool generateExposures;
66{
67    BoxRec box;
68    RegionRec	reg;
69    RegionPtr pBSReg = NullRegion;
70    ScreenPtr	pScreen;
71    BoxPtr  extents;
72    int	    x1, y1, x2, y2;
73
74    /* compute everything using ints to avoid overflow */
75
76    x1 = pWin->drawable.x + x;
77    y1 = pWin->drawable.y + y;
78    if (w)
79        x2 = x1 + (int) w;
80    else
81        x2 = x1 + (int) pWin->drawable.width - (int) x;
82    if (h)
83        y2 = y1 + h;
84    else
85        y2 = y1 + (int) pWin->drawable.height - (int) y;
86
87    extents = &pWin->clipList.extents;
88
89    /* clip the resulting rectangle to the window clipList extents.  This
90     * makes sure that the result will fit in a box, given that the
91     * screen is < 32768 on a side.
92     */
93
94    if (x1 < extents->x1)
95	x1 = extents->x1;
96    if (x2 > extents->x2)
97	x2 = extents->x2;
98    if (y1 < extents->y1)
99	y1 = extents->y1;
100    if (y2 > extents->y2)
101	y2 = extents->y2;
102
103    if (x2 <= x1 || y2 <= y1)
104    {
105	x2 = x1 = 0;
106	y2 = y1 = 0;
107    }
108
109    box.x1 = x1;
110    box.x2 = x2;
111    box.y1 = y1;
112    box.y2 = y2;
113
114    pScreen = pWin->drawable.pScreen;
115    REGION_INIT(pScreen, &reg, &box, 1);
116    if (pWin->backStorage)
117    {
118	/*
119	 * If the window has backing-store on, call through the
120	 * ClearToBackground vector to handle the special semantics
121	 * (i.e. things backing store is to be cleared out and
122	 * an Expose event is to be generated for those areas in backing
123	 * store if generateExposures is TRUE).
124	 */
125	pBSReg = (* pScreen->ClearBackingStore)(pWin, x, y, w, h,
126						 generateExposures);
127    }
128
129    REGION_INTERSECT(pScreen, &reg, &reg, &pWin->clipList);
130    if (generateExposures)
131	(*pScreen->WindowExposures)(pWin, &reg, pBSReg);
132    else if (pWin->backgroundState != None)
133        (*pScreen->PaintWindowBackground)(pWin, &reg, PW_BACKGROUND);
134    REGION_UNINIT(pScreen, &reg);
135    if (pBSReg)
136	REGION_DESTROY(pScreen, pBSReg);
137}
138
139/*
140 * For SaveUnders using backing-store. The idea is that when a window is mapped
141 * with saveUnder set TRUE, any windows it obscures will have its backing
142 * store turned on setting the DIXsaveUnder bit,
143 * The backing-store code must be written to allow for this
144 */
145
146/*-
147 *-----------------------------------------------------------------------
148 * miCheckSubSaveUnder --
149 *	Check all the inferiors of a window for coverage by saveUnder
150 *	windows. Called from ChangeSaveUnder and CheckSaveUnder.
151 *	This code is very inefficient.
152 *
153 * Results:
154 *	TRUE if any windows need to have backing-store removed.
155 *
156 * Side Effects:
157 *	Windows may have backing-store turned on or off.
158 *
159 *-----------------------------------------------------------------------
160 */
161static Bool
162miCheckSubSaveUnder(
163    WindowPtr		pParent,	/* Parent to check */
164    WindowPtr		pFirst,		/* first reconfigured window */
165    RegionPtr		pRegion)	/* Initial area obscured by saveUnder */
166{
167    WindowPtr		pChild;		/* Current child */
168    ScreenPtr		pScreen;	/* Screen to use */
169    RegionRec		SubRegion;	/* Area of children obscured */
170    Bool		res = FALSE;	/* result */
171    Bool		subInited=FALSE;/* SubRegion initialized */
172
173    pScreen = pParent->drawable.pScreen;
174    if ( (pChild = pParent->firstChild) )
175    {
176	/*
177	 * build region above first changed window
178	 */
179
180	for (; pChild != pFirst; pChild = pChild->nextSib)
181	    if (pChild->viewable && pChild->saveUnder)
182		REGION_UNION(pScreen, pRegion, pRegion, &pChild->borderSize);
183
184	/*
185	 * check region below and including first changed window
186	 */
187
188	for (; pChild; pChild = pChild->nextSib)
189	{
190	    if (pChild->viewable)
191	    {
192		/*
193		 * don't save under nephew/niece windows;
194		 * use a separate region
195		 */
196
197		if (pChild->firstChild)
198		{
199		    if (!subInited)
200		    {
201			REGION_NULL(pScreen, &SubRegion);
202			subInited = TRUE;
203		    }
204		    REGION_COPY(pScreen, &SubRegion, pRegion);
205		    res |= miCheckSubSaveUnder(pChild, pChild->firstChild,
206					     &SubRegion);
207		}
208		else
209		{
210		    res |= miCheckSubSaveUnder(pChild, pChild->firstChild,
211					     pRegion);
212		}
213
214		if (pChild->saveUnder)
215		    REGION_UNION(pScreen, pRegion, pRegion, &pChild->borderSize);
216	    }
217	}
218
219	if (subInited)
220	    REGION_UNINIT(pScreen, &SubRegion);
221    }
222
223    /*
224     * Check the state of this window.	DIX save unders are
225     * enabled for viewable windows with some client expressing
226     * exposure interest and which intersect the save under region
227     */
228
229    if (pParent->viewable &&
230	((pParent->eventMask | wOtherEventMasks(pParent)) & ExposureMask) &&
231	REGION_NOTEMPTY(pScreen, &pParent->borderSize) &&
232	RECT_IN_REGION(pScreen, pRegion, REGION_EXTENTS(pScreen,
233					&pParent->borderSize)) != rgnOUT)
234    {
235	if (!pParent->DIXsaveUnder)
236	{
237	    pParent->DIXsaveUnder = TRUE;
238	    (*pScreen->ChangeWindowAttributes) (pParent, CWBackingStore);
239	}
240    }
241    else
242    {
243	if (pParent->DIXsaveUnder)
244	{
245	    res = TRUE;
246	    pParent->DIXsaveUnder = FALSE;
247	}
248    }
249    return res;
250}
251
252
253/*-
254 *-----------------------------------------------------------------------
255 * miChangeSaveUnder --
256 *	Change the save-under state of a tree of windows. Called when
257 *	a window with saveUnder TRUE is mapped/unmapped/reconfigured.
258 *
259 * Results:
260 *	TRUE if any windows need to have backing-store removed (which
261 *	means that PostChangeSaveUnder needs to be called later to
262 *	finish the job).
263 *
264 * Side Effects:
265 *	Windows may have backing-store turned on or off.
266 *
267 *-----------------------------------------------------------------------
268 */
269Bool
270miChangeSaveUnder(pWin, first)
271    WindowPtr		pWin;
272    WindowPtr		first;		/* First window to check.
273					 * Used when pWin was restacked */
274{
275    RegionRec	rgn;	/* Area obscured by saveUnder windows */
276    ScreenPtr 	pScreen;
277    Bool	res;
278
279    if (!deltaSaveUndersViewable && !numSaveUndersViewable)
280	return FALSE;
281    numSaveUndersViewable += deltaSaveUndersViewable;
282    deltaSaveUndersViewable = 0;
283    pScreen = pWin->drawable.pScreen;
284    REGION_NULL(pScreen, &rgn);
285    res = miCheckSubSaveUnder (pWin->parent,
286			       pWin->saveUnder ? first : pWin->nextSib,
287			       &rgn);
288    REGION_UNINIT(pScreen, &rgn);
289    return res;
290}
291
292/*-
293 *-----------------------------------------------------------------------
294 * miPostChangeSaveUnder --
295 *	Actually turn backing-store off for those windows that no longer
296 *	need to have it on.
297 *
298 * Results:
299 *	None.
300 *
301 * Side Effects:
302 *	Backing-store and SAVE_UNDER_CHANGE_BIT are turned off for those
303 *	windows affected.
304 *
305 *-----------------------------------------------------------------------
306 */
307void
308miPostChangeSaveUnder(pWin, pFirst)
309    WindowPtr		pWin;
310    WindowPtr		pFirst;
311{
312    WindowPtr pParent, pChild;
313    ChangeWindowAttributesProcPtr ChangeWindowAttributes;
314
315    if (!(pParent = pWin->parent))
316	return;
317    ChangeWindowAttributes = pParent->drawable.pScreen->ChangeWindowAttributes;
318    if (!pParent->DIXsaveUnder &&
319	(pParent->backingStore == NotUseful) && pParent->backStorage)
320	(*ChangeWindowAttributes)(pParent, CWBackingStore);
321    if (!(pChild = pFirst))
322	return;
323    while (1)
324    {
325	if (!pChild->DIXsaveUnder &&
326	    (pChild->backingStore == NotUseful) && pChild->backStorage)
327	    (*ChangeWindowAttributes)(pChild, CWBackingStore);
328	if (pChild->firstChild)
329	{
330	    pChild = pChild->firstChild;
331	    continue;
332	}
333	while (!pChild->nextSib)
334	{
335	    pChild = pChild->parent;
336	    if (pChild == pParent)
337		return;
338	}
339	pChild = pChild->nextSib;
340    }
341}
342
343void
344miMarkWindow(pWin)
345    WindowPtr pWin;
346{
347    ValidatePtr val;
348
349    if (pWin->valdata)
350	return;
351    val = (ValidatePtr)xnfalloc(sizeof(ValidateRec));
352    val->before.oldAbsCorner.x = pWin->drawable.x;
353    val->before.oldAbsCorner.y = pWin->drawable.y;
354    val->before.borderVisible = NullRegion;
355    val->before.resized = FALSE;
356    pWin->valdata = val;
357}
358
359Bool
360miMarkOverlappedWindows(pWin, pFirst, ppLayerWin)
361    WindowPtr pWin;
362    WindowPtr pFirst;
363    WindowPtr *ppLayerWin;
364{
365    BoxPtr box;
366    WindowPtr pChild, pLast;
367    Bool anyMarked = FALSE;
368    MarkWindowProcPtr MarkWindow = pWin->drawable.pScreen->MarkWindow;
369    ScreenPtr pScreen;
370
371    pScreen = pWin->drawable.pScreen;
372
373    /* single layered systems are easy */
374    if (ppLayerWin) *ppLayerWin = pWin;
375
376    if (pWin == pFirst)
377    {
378	/* Blindly mark pWin and all of its inferiors.	 This is a slight
379	 * overkill if there are mapped windows that outside pWin's border,
380	 * but it's better than wasting time on RectIn checks.
381	 */
382	pChild = pWin;
383	while (1)
384	{
385	    if (pChild->viewable)
386	    {
387		if (REGION_BROKEN (pScreen, &pChild->winSize))
388		    SetWinSize (pChild);
389		if (REGION_BROKEN (pScreen, &pChild->borderSize))
390		    SetBorderSize (pChild);
391		(* MarkWindow)(pChild);
392		if (pChild->firstChild)
393		{
394		    pChild = pChild->firstChild;
395		    continue;
396		}
397	    }
398	    while (!pChild->nextSib && (pChild != pWin))
399		pChild = pChild->parent;
400	    if (pChild == pWin)
401		break;
402	    pChild = pChild->nextSib;
403	}
404	anyMarked = TRUE;
405	pFirst = pFirst->nextSib;
406    }
407    if ( (pChild = pFirst) )
408    {
409	box = REGION_EXTENTS(pChild->drawable.pScreen, &pWin->borderSize);
410	pLast = pChild->parent->lastChild;
411	while (1)
412	{
413	    if (pChild->viewable)
414	    {
415		if (REGION_BROKEN (pScreen, &pChild->winSize))
416		    SetWinSize (pChild);
417		if (REGION_BROKEN (pScreen, &pChild->borderSize))
418		    SetBorderSize (pChild);
419		if (RECT_IN_REGION(pScreen, &pChild->borderSize, box))
420		{
421		    (* MarkWindow)(pChild);
422		    anyMarked = TRUE;
423		    if (pChild->firstChild)
424		    {
425			pChild = pChild->firstChild;
426			continue;
427		    }
428		}
429	    }
430	    while (!pChild->nextSib && (pChild != pLast))
431		pChild = pChild->parent;
432	    if (pChild == pLast)
433		break;
434	    pChild = pChild->nextSib;
435	}
436    }
437    if (anyMarked)
438	(* MarkWindow)(pWin->parent);
439    return anyMarked;
440}
441
442/*****
443 *  miHandleValidateExposures(pWin)
444 *    starting at pWin, draw background in any windows that have exposure
445 *    regions, translate the regions, restore any backing store,
446 *    and then send any regions still exposed to the client
447 *****/
448_X_EXPORT void
449miHandleValidateExposures(pWin)
450    WindowPtr pWin;
451{
452    WindowPtr pChild;
453    ValidatePtr val;
454    ScreenPtr pScreen;
455    WindowExposuresProcPtr WindowExposures;
456
457    pScreen = pWin->drawable.pScreen;
458
459    pChild = pWin;
460    WindowExposures = pChild->drawable.pScreen->WindowExposures;
461    while (1)
462    {
463	if ( (val = pChild->valdata) )
464	{
465	    if (REGION_NOTEMPTY(pScreen, &val->after.borderExposed))
466		(*pChild->drawable.pScreen->PaintWindowBorder)(pChild,
467						    &val->after.borderExposed,
468						    PW_BORDER);
469	    REGION_UNINIT(pScreen, &val->after.borderExposed);
470	    (*WindowExposures)(pChild, &val->after.exposed, NullRegion);
471	    REGION_UNINIT(pScreen, &val->after.exposed);
472	    xfree(val);
473	    pChild->valdata = (ValidatePtr)NULL;
474	    if (pChild->firstChild)
475	    {
476		pChild = pChild->firstChild;
477		continue;
478	    }
479	}
480	while (!pChild->nextSib && (pChild != pWin))
481	    pChild = pChild->parent;
482	if (pChild == pWin)
483	    break;
484	pChild = pChild->nextSib;
485    }
486}
487
488void
489miMoveWindow(pWin, x, y, pNextSib, kind)
490    WindowPtr pWin;
491    int x,y;
492    WindowPtr pNextSib;
493    VTKind kind;
494{
495    WindowPtr pParent;
496    Bool WasViewable = (Bool)(pWin->viewable);
497    short bw;
498    RegionPtr oldRegion = NULL;
499    DDXPointRec oldpt;
500    Bool anyMarked = FALSE;
501    ScreenPtr pScreen;
502    WindowPtr windowToValidate;
503#ifdef DO_SAVE_UNDERS
504    Bool dosave = FALSE;
505#endif
506    WindowPtr pLayerWin;
507
508    /* if this is a root window, can't be moved */
509    if (!(pParent = pWin->parent))
510       return ;
511    pScreen = pWin->drawable.pScreen;
512    bw = wBorderWidth (pWin);
513
514    oldpt.x = pWin->drawable.x;
515    oldpt.y = pWin->drawable.y;
516    if (WasViewable)
517    {
518	oldRegion = REGION_CREATE(pScreen, NullBox, 1);
519	REGION_COPY(pScreen, oldRegion, &pWin->borderClip);
520	anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, &pLayerWin);
521    }
522    pWin->origin.x = x + (int)bw;
523    pWin->origin.y = y + (int)bw;
524    x = pWin->drawable.x = pParent->drawable.x + x + (int)bw;
525    y = pWin->drawable.y = pParent->drawable.y + y + (int)bw;
526
527    SetWinSize (pWin);
528    SetBorderSize (pWin);
529
530    (*pScreen->PositionWindow)(pWin, x, y);
531
532    windowToValidate = MoveWindowInStack(pWin, pNextSib);
533
534    ResizeChildrenWinSize(pWin, x - oldpt.x, y - oldpt.y, 0, 0);
535
536    if (WasViewable)
537    {
538	if (pLayerWin == pWin)
539	    anyMarked |= (*pScreen->MarkOverlappedWindows)
540				(pWin, windowToValidate, (WindowPtr *)NULL);
541	else
542	    anyMarked |= (*pScreen->MarkOverlappedWindows)
543				(pWin, pLayerWin, (WindowPtr *)NULL);
544
545#ifdef DO_SAVE_UNDERS
546	if (DO_SAVE_UNDERS(pWin))
547	{
548	    dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, windowToValidate);
549	}
550#endif /* DO_SAVE_UNDERS */
551
552	if (anyMarked)
553	{
554	    (*pScreen->ValidateTree)(pLayerWin->parent, NullWindow, kind);
555	    (* pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, oldRegion);
556	    REGION_DESTROY(pScreen, oldRegion);
557	    /* XXX need to retile border if ParentRelative origin */
558	    (*pScreen->HandleExposures)(pLayerWin->parent);
559	}
560#ifdef DO_SAVE_UNDERS
561	if (dosave)
562	    (*pScreen->PostChangeSaveUnder)(pLayerWin, windowToValidate);
563#endif /* DO_SAVE_UNDERS */
564	if (anyMarked && pScreen->PostValidateTree)
565	    (*pScreen->PostValidateTree)(pLayerWin->parent, NullWindow, kind);
566    }
567    if (pWin->realized)
568	WindowsRestructured ();
569}
570
571
572/*
573 * pValid is a region of the screen which has been
574 * successfully copied -- recomputed exposed regions for affected windows
575 */
576
577static int
578miRecomputeExposures (
579    WindowPtr	pWin,
580    pointer		value) /* must conform to VisitWindowProcPtr */
581{
582    ScreenPtr	pScreen;
583    RegionPtr	pValid = (RegionPtr)value;
584
585    if (pWin->valdata)
586    {
587	pScreen = pWin->drawable.pScreen;
588	/*
589	 * compute exposed regions of this window
590	 */
591	REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed,
592			&pWin->clipList, pValid);
593	/*
594	 * compute exposed regions of the border
595	 */
596	REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed,
597			     &pWin->borderClip, &pWin->winSize);
598	REGION_SUBTRACT(pScreen, &pWin->valdata->after.borderExposed,
599			     &pWin->valdata->after.borderExposed, pValid);
600	return WT_WALKCHILDREN;
601    }
602    return WT_NOMATCH;
603}
604
605void
606miSlideAndSizeWindow(pWin, x, y, w, h, pSib)
607    WindowPtr pWin;
608    int x,y;
609    unsigned int w, h;
610    WindowPtr pSib;
611{
612    WindowPtr pParent;
613    Bool WasViewable = (Bool)(pWin->viewable);
614    unsigned short width = pWin->drawable.width,
615		   height = pWin->drawable.height;
616    short oldx = pWin->drawable.x,
617	  oldy = pWin->drawable.y;
618    int bw = wBorderWidth (pWin);
619    short dw, dh;
620    DDXPointRec oldpt;
621    RegionPtr oldRegion = NULL;
622    Bool anyMarked = FALSE;
623    ScreenPtr pScreen;
624    WindowPtr pFirstChange;
625    WindowPtr pChild;
626    RegionPtr	gravitate[StaticGravity + 1];
627    unsigned g;
628    int		nx, ny;		/* destination x,y */
629    int		newx, newy;	/* new inner window position */
630    RegionPtr	pRegion = NULL;
631    RegionPtr	destClip;	/* portions of destination already written */
632    RegionPtr	oldWinClip = NULL;	/* old clip list for window */
633    RegionPtr	borderVisible = NullRegion; /* visible area of the border */
634    RegionPtr	bsExposed = NullRegion;	    /* backing store exposures */
635    Bool	shrunk = FALSE; /* shrunk in an inner dimension */
636    Bool	moved = FALSE;	/* window position changed */
637#ifdef DO_SAVE_UNDERS
638    Bool	dosave = FALSE;
639#endif
640    WindowPtr  pLayerWin;
641
642    /* if this is a root window, can't be resized */
643    if (!(pParent = pWin->parent))
644	return ;
645
646    pScreen = pWin->drawable.pScreen;
647    newx = pParent->drawable.x + x + bw;
648    newy = pParent->drawable.y + y + bw;
649    if (WasViewable)
650    {
651	anyMarked = FALSE;
652	/*
653	 * save the visible region of the window
654	 */
655	oldRegion = REGION_CREATE(pScreen, NullBox, 1);
656	REGION_COPY(pScreen, oldRegion, &pWin->winSize);
657
658	/*
659	 * categorize child windows into regions to be moved
660	 */
661	for (g = 0; g <= StaticGravity; g++)
662	    gravitate[g] = (RegionPtr) NULL;
663	for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib)
664	{
665	    g = pChild->winGravity;
666	    if (g != UnmapGravity)
667	    {
668		if (!gravitate[g])
669		    gravitate[g] = REGION_CREATE(pScreen, NullBox, 1);
670		REGION_UNION(pScreen, gravitate[g],
671				   gravitate[g], &pChild->borderClip);
672	    }
673	    else
674	    {
675		UnmapWindow(pChild, TRUE);
676		anyMarked = TRUE;
677	    }
678	}
679	anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pWin,
680						       &pLayerWin);
681
682	oldWinClip = NULL;
683	if (pWin->bitGravity != ForgetGravity)
684	{
685	    oldWinClip = REGION_CREATE(pScreen, NullBox, 1);
686	    REGION_COPY(pScreen, oldWinClip, &pWin->clipList);
687	}
688	/*
689	 * if the window is changing size, borderExposed
690	 * can't be computed correctly without some help.
691	 */
692	if (pWin->drawable.height > h || pWin->drawable.width > w)
693	    shrunk = TRUE;
694
695	if (newx != oldx || newy != oldy)
696	    moved = TRUE;
697
698	if ((pWin->drawable.height != h || pWin->drawable.width != w) &&
699	    HasBorder (pWin))
700	{
701	    borderVisible = REGION_CREATE(pScreen, NullBox, 1);
702	    /* for tiled borders, we punt and draw the whole thing */
703	    if (pWin->borderIsPixel || !moved)
704	    {
705		if (shrunk || moved)
706		    REGION_SUBTRACT(pScreen, borderVisible,
707					  &pWin->borderClip,
708					  &pWin->winSize);
709		else
710		    REGION_COPY(pScreen, borderVisible,
711					    &pWin->borderClip);
712	    }
713	}
714    }
715    pWin->origin.x = x + bw;
716    pWin->origin.y = y + bw;
717    pWin->drawable.height = h;
718    pWin->drawable.width = w;
719
720    x = pWin->drawable.x = newx;
721    y = pWin->drawable.y = newy;
722
723    SetWinSize (pWin);
724    SetBorderSize (pWin);
725
726    dw = (int)w - (int)width;
727    dh = (int)h - (int)height;
728    ResizeChildrenWinSize(pWin, x - oldx, y - oldy, dw, dh);
729
730    /* let the hardware adjust background and border pixmaps, if any */
731    (*pScreen->PositionWindow)(pWin, x, y);
732
733    pFirstChange = MoveWindowInStack(pWin, pSib);
734
735    if (WasViewable)
736    {
737	pRegion = REGION_CREATE(pScreen, NullBox, 1);
738	if (pWin->backStorage)
739	    REGION_COPY(pScreen, pRegion, &pWin->clipList);
740
741	if (pLayerWin == pWin)
742	    anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pFirstChange,
743						(WindowPtr *)NULL);
744	else
745	    anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pLayerWin,
746						(WindowPtr *)NULL);
747
748	if (pWin->valdata)
749	{
750	    pWin->valdata->before.resized = TRUE;
751	    pWin->valdata->before.borderVisible = borderVisible;
752	}
753
754#ifdef DO_SAVE_UNDERS
755	if (DO_SAVE_UNDERS(pWin))
756	{
757	    dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pFirstChange);
758	}
759#endif /* DO_SAVE_UNDERS */
760
761	if (anyMarked)
762	    (*pScreen->ValidateTree)(pLayerWin->parent, pFirstChange, VTOther);
763	/*
764	 * the entire window is trashed unless bitGravity
765	 * recovers portions of it
766	 */
767	REGION_COPY(pScreen, &pWin->valdata->after.exposed, &pWin->clipList);
768    }
769
770    GravityTranslate (x, y, oldx, oldy, dw, dh, pWin->bitGravity, &nx, &ny);
771
772    if (pWin->backStorage &&
773	((pWin->backingStore == Always) || WasViewable))
774    {
775	if (!WasViewable)
776	    pRegion = &pWin->clipList; /* a convenient empty region */
777	if (pWin->bitGravity == ForgetGravity)
778	    bsExposed = (*pScreen->TranslateBackingStore)
779				(pWin, 0, 0, NullRegion, oldx, oldy);
780	else
781	{
782	    bsExposed = (*pScreen->TranslateBackingStore)
783			     (pWin, nx - x, ny - y, pRegion, oldx, oldy);
784	}
785    }
786
787    if (WasViewable)
788    {
789	/* avoid the border */
790	if (HasBorder (pWin))
791	{
792	    int	offx, offy, dx, dy;
793
794	    /* kruft to avoid double translates for each gravity */
795	    offx = 0;
796	    offy = 0;
797	    for (g = 0; g <= StaticGravity; g++)
798	    {
799		if (!gravitate[g])
800		    continue;
801
802		/* align winSize to gravitate[g].
803		 * winSize is in new coordinates,
804		 * gravitate[g] is still in old coordinates */
805		GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny);
806
807		dx = (oldx - nx) - offx;
808		dy = (oldy - ny) - offy;
809		if (dx || dy)
810		{
811		    REGION_TRANSLATE(pScreen, &pWin->winSize, dx, dy);
812		    offx += dx;
813		    offy += dy;
814		}
815		REGION_INTERSECT(pScreen, gravitate[g], gravitate[g],
816				 &pWin->winSize);
817	    }
818	    /* get winSize back where it belongs */
819	    if (offx || offy)
820		REGION_TRANSLATE(pScreen, &pWin->winSize, -offx, -offy);
821	}
822	/*
823	 * add screen bits to the appropriate bucket
824	 */
825
826	if (oldWinClip)
827	{
828	    /*
829	     * clip to new clipList
830	     */
831	    REGION_COPY(pScreen, pRegion, oldWinClip);
832	    REGION_TRANSLATE(pScreen, pRegion, nx - oldx, ny - oldy);
833	    REGION_INTERSECT(pScreen, oldWinClip, pRegion, &pWin->clipList);
834	    /*
835	     * don't step on any gravity bits which will be copied after this
836	     * region.	Note -- this assumes that the regions will be copied
837	     * in gravity order.
838	     */
839	    for (g = pWin->bitGravity + 1; g <= StaticGravity; g++)
840	    {
841		if (gravitate[g])
842		    REGION_SUBTRACT(pScreen, oldWinClip, oldWinClip,
843					gravitate[g]);
844	    }
845	    REGION_TRANSLATE(pScreen, oldWinClip, oldx - nx, oldy - ny);
846	    g = pWin->bitGravity;
847	    if (!gravitate[g])
848		gravitate[g] = oldWinClip;
849	    else
850	    {
851		REGION_UNION(pScreen, gravitate[g], gravitate[g], oldWinClip);
852		REGION_DESTROY(pScreen, oldWinClip);
853	    }
854	}
855
856	/*
857	 * move the bits on the screen
858	 */
859
860	destClip = NULL;
861
862	for (g = 0; g <= StaticGravity; g++)
863	{
864	    if (!gravitate[g])
865		continue;
866
867	    GravityTranslate (x, y, oldx, oldy, dw, dh, g, &nx, &ny);
868
869	    oldpt.x = oldx + (x - nx);
870	    oldpt.y = oldy + (y - ny);
871
872	    /* Note that gravitate[g] is *translated* by CopyWindow */
873
874	    /* only copy the remaining useful bits */
875
876	    REGION_INTERSECT(pScreen, gravitate[g], gravitate[g], oldRegion);
877
878	    /* clip to not overwrite already copied areas */
879
880	    if (destClip) {
881		REGION_TRANSLATE(pScreen, destClip, oldpt.x - x, oldpt.y - y);
882		REGION_SUBTRACT(pScreen, gravitate[g], gravitate[g], destClip);
883		REGION_TRANSLATE(pScreen, destClip, x - oldpt.x, y - oldpt.y);
884	    }
885
886	    /* and move those bits */
887
888	    if (oldpt.x != x || oldpt.y != y
889#ifdef COMPOSITE
890		|| pWin->redirectDraw
891#endif
892		)
893	    {
894		(*pWin->drawable.pScreen->CopyWindow)(pWin, oldpt, gravitate[g]);
895	    }
896
897	    /* remove any overwritten bits from the remaining useful bits */
898
899	    REGION_SUBTRACT(pScreen, oldRegion, oldRegion, gravitate[g]);
900
901	    /*
902	     * recompute exposed regions of child windows
903	     */
904
905	    for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib)
906	    {
907		if (pChild->winGravity != g)
908		    continue;
909		REGION_INTERSECT(pScreen, pRegion,
910				       &pChild->borderClip, gravitate[g]);
911		TraverseTree (pChild, miRecomputeExposures, (pointer)pRegion);
912	    }
913
914	    /*
915	     * remove the successfully copied regions of the
916	     * window from its exposed region
917	     */
918
919	    if (g == pWin->bitGravity)
920		REGION_SUBTRACT(pScreen, &pWin->valdata->after.exposed,
921				     &pWin->valdata->after.exposed, gravitate[g]);
922	    if (!destClip)
923		destClip = gravitate[g];
924	    else
925	    {
926		REGION_UNION(pScreen, destClip, destClip, gravitate[g]);
927		REGION_DESTROY(pScreen, gravitate[g]);
928	    }
929	}
930
931	REGION_DESTROY(pScreen, oldRegion);
932	REGION_DESTROY(pScreen, pRegion);
933	if (destClip)
934	    REGION_DESTROY(pScreen, destClip);
935	if (bsExposed)
936	{
937	    RegionPtr	valExposed = NullRegion;
938
939	    if (pWin->valdata)
940		valExposed = &pWin->valdata->after.exposed;
941	    (*pScreen->WindowExposures) (pWin, valExposed, bsExposed);
942	    if (valExposed)
943		REGION_EMPTY(pScreen, valExposed);
944	    REGION_DESTROY(pScreen, bsExposed);
945	}
946	if (anyMarked)
947	    (*pScreen->HandleExposures)(pLayerWin->parent);
948#ifdef DO_SAVE_UNDERS
949	if (dosave)
950	{
951	    (*pScreen->PostChangeSaveUnder)(pLayerWin, pFirstChange);
952	}
953#endif /* DO_SAVE_UNDERS */
954	if (anyMarked && pScreen->PostValidateTree)
955	    (*pScreen->PostValidateTree)(pLayerWin->parent, pFirstChange,
956					  VTOther);
957    }
958    else if (bsExposed)
959    {
960	(*pScreen->WindowExposures) (pWin, NullRegion, bsExposed);
961	REGION_DESTROY(pScreen, bsExposed);
962    }
963    if (pWin->realized)
964	WindowsRestructured ();
965}
966
967WindowPtr
968miGetLayerWindow(pWin)
969    WindowPtr pWin;
970{
971    return pWin->firstChild;
972}
973
974#ifdef SHAPE
975/******
976 *
977 * miSetShape
978 *    The border/window shape has changed.  Recompute winSize/borderSize
979 *    and send appropriate exposure events
980 */
981
982_X_EXPORT void
983miSetShape(pWin)
984    WindowPtr	pWin;
985{
986    Bool	WasViewable = (Bool)(pWin->viewable);
987    ScreenPtr 	pScreen = pWin->drawable.pScreen;
988    Bool	anyMarked = FALSE;
989    RegionPtr	pOldClip = NULL, bsExposed;
990#ifdef DO_SAVE_UNDERS
991    Bool	dosave = FALSE;
992#endif
993    WindowPtr   pLayerWin;
994
995    if (WasViewable)
996    {
997	anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin,
998						      &pLayerWin);
999	if (pWin->valdata)
1000	{
1001	    if (HasBorder (pWin))
1002	    {
1003		RegionPtr	borderVisible;
1004
1005		borderVisible = REGION_CREATE(pScreen, NullBox, 1);
1006		REGION_SUBTRACT(pScreen, borderVisible,
1007				      &pWin->borderClip, &pWin->winSize);
1008		pWin->valdata->before.borderVisible = borderVisible;
1009	    }
1010	    pWin->valdata->before.resized = TRUE;
1011	}
1012    }
1013
1014    SetWinSize (pWin);
1015    SetBorderSize (pWin);
1016
1017    ResizeChildrenWinSize(pWin, 0, 0, 0, 0);
1018
1019    if (WasViewable)
1020    {
1021	if (pWin->backStorage)
1022	{
1023	    pOldClip = REGION_CREATE(pScreen, NullBox, 1);
1024	    REGION_COPY(pScreen, pOldClip, &pWin->clipList);
1025	}
1026
1027	anyMarked |= (*pScreen->MarkOverlappedWindows)(pWin, pWin,
1028						(WindowPtr *)NULL);
1029
1030#ifdef DO_SAVE_UNDERS
1031	if (DO_SAVE_UNDERS(pWin))
1032	{
1033	    dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pLayerWin);
1034	}
1035#endif /* DO_SAVE_UNDERS */
1036
1037	if (anyMarked)
1038	    (*pScreen->ValidateTree)(pLayerWin->parent, NullWindow, VTOther);
1039    }
1040
1041    if (pWin->backStorage &&
1042	((pWin->backingStore == Always) || WasViewable))
1043    {
1044	if (!WasViewable)
1045	    pOldClip = &pWin->clipList; /* a convenient empty region */
1046	bsExposed = (*pScreen->TranslateBackingStore)
1047			     (pWin, 0, 0, pOldClip,
1048			      pWin->drawable.x, pWin->drawable.y);
1049	if (WasViewable)
1050	    REGION_DESTROY(pScreen, pOldClip);
1051	if (bsExposed)
1052	{
1053	    RegionPtr	valExposed = NullRegion;
1054
1055	    if (pWin->valdata)
1056		valExposed = &pWin->valdata->after.exposed;
1057	    (*pScreen->WindowExposures) (pWin, valExposed, bsExposed);
1058	    if (valExposed)
1059		REGION_EMPTY(pScreen, valExposed);
1060	    REGION_DESTROY(pScreen, bsExposed);
1061	}
1062    }
1063    if (WasViewable)
1064    {
1065	if (anyMarked)
1066	    (*pScreen->HandleExposures)(pLayerWin->parent);
1067#ifdef DO_SAVE_UNDERS
1068	if (dosave)
1069	    (*pScreen->PostChangeSaveUnder)(pLayerWin, pLayerWin);
1070#endif /* DO_SAVE_UNDERS */
1071	if (anyMarked && pScreen->PostValidateTree)
1072	    (*pScreen->PostValidateTree)(pLayerWin->parent, NullWindow, VTOther);
1073    }
1074    if (pWin->realized)
1075	WindowsRestructured ();
1076    CheckCursorConfinement(pWin);
1077}
1078#endif
1079
1080/* Keeps the same inside(!) origin */
1081
1082_X_EXPORT void
1083miChangeBorderWidth(pWin, width)
1084    WindowPtr pWin;
1085    unsigned int width;
1086{
1087    int oldwidth;
1088    Bool anyMarked = FALSE;
1089    ScreenPtr pScreen;
1090    Bool WasViewable = (Bool)(pWin->viewable);
1091    Bool HadBorder;
1092#ifdef DO_SAVE_UNDERS
1093    Bool	dosave = FALSE;
1094#endif
1095    WindowPtr  pLayerWin;
1096
1097    oldwidth = wBorderWidth (pWin);
1098    if (oldwidth == width)
1099	return;
1100    HadBorder = HasBorder(pWin);
1101    pScreen = pWin->drawable.pScreen;
1102    if (WasViewable && width < oldwidth)
1103	anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin, &pLayerWin);
1104
1105    pWin->borderWidth = width;
1106    SetBorderSize (pWin);
1107
1108    if (WasViewable)
1109    {
1110	if (width > oldwidth)
1111	{
1112	    anyMarked = (*pScreen->MarkOverlappedWindows)(pWin, pWin,
1113							  &pLayerWin);
1114	    /*
1115	     * save the old border visible region to correctly compute
1116	     * borderExposed.
1117	     */
1118	    if (pWin->valdata && HadBorder)
1119	    {
1120		RegionPtr   borderVisible;
1121		borderVisible = REGION_CREATE(pScreen, NULL, 1);
1122		REGION_SUBTRACT(pScreen, borderVisible,
1123				      &pWin->borderClip, &pWin->winSize);
1124		pWin->valdata->before.borderVisible = borderVisible;
1125	    }
1126	}
1127#ifdef DO_SAVE_UNDERS
1128	if (DO_SAVE_UNDERS(pWin))
1129	{
1130	    dosave = (*pScreen->ChangeSaveUnder)(pLayerWin, pWin->nextSib);
1131	}
1132#endif /* DO_SAVE_UNDERS */
1133
1134	if (anyMarked)
1135	{
1136	    (*pScreen->ValidateTree)(pLayerWin->parent, pLayerWin, VTOther);
1137	    (*pScreen->HandleExposures)(pLayerWin->parent);
1138	}
1139#ifdef DO_SAVE_UNDERS
1140	if (dosave)
1141	    (*pScreen->PostChangeSaveUnder)(pLayerWin, pWin->nextSib);
1142#endif /* DO_SAVE_UNDERS */
1143	if (anyMarked && pScreen->PostValidateTree)
1144	    (*pScreen->PostValidateTree)(pLayerWin->parent, pLayerWin,
1145					  VTOther);
1146    }
1147    if (pWin->realized)
1148	WindowsRestructured ();
1149}
1150
1151void
1152miMarkUnrealizedWindow(pChild, pWin, fromConfigure)
1153    WindowPtr pChild;
1154    WindowPtr pWin;
1155    Bool fromConfigure;
1156{
1157    if ((pChild != pWin) || fromConfigure)
1158    {
1159	REGION_EMPTY(pChild->drawable.pScreen, &pChild->clipList);
1160	if (pChild->drawable.pScreen->ClipNotify)
1161	    (* pChild->drawable.pScreen->ClipNotify)(pChild, 0, 0);
1162	REGION_EMPTY(pChild->drawable.pScreen, &pChild->borderClip);
1163    }
1164}
1165
1166_X_EXPORT void
1167miSegregateChildren(WindowPtr pWin, RegionPtr pReg, int depth)
1168{
1169    ScreenPtr pScreen;
1170    WindowPtr pChild;
1171
1172    pScreen = pWin->drawable.pScreen;
1173
1174    for (pChild = pWin->firstChild; pChild; pChild = pChild->nextSib)
1175    {
1176	if (pChild->drawable.depth == depth)
1177	    REGION_UNION(pScreen, pReg, pReg, &pChild->borderClip);
1178
1179	if (pChild->firstChild)
1180	    miSegregateChildren(pChild, pReg, depth);
1181    }
1182}
1183