1 /* windMove.c -
2  *
3  *	This file contains the functions which move windows around on
4  *	the screen.  It does not contain the functions that change the
5  *	contents of the windows.
6  *
7  *     *********************************************************************
8  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
9  *     * Permission to use, copy, modify, and distribute this              *
10  *     * software and its documentation for any purpose and without        *
11  *     * fee is hereby granted, provided that the above copyright          *
12  *     * notice appear in all copies.  The University of California        *
13  *     * makes no representations about the suitability of this            *
14  *     * software for any purpose.  It is provided "as is" without         *
15  *     * express or implied warranty.  Export of this software outside     *
16  *     * of the United States of America may require an export license.    *
17  *     *********************************************************************
18  */
19 
20 #ifndef lint
21 static char rcsid[] __attribute__ ((unused)) = "$Header$";
22 #endif  /* not lint */
23 
24 #include <stdio.h>
25 #include <string.h>
26 
27 #include "utils/magic.h"
28 #include "textio/textio.h"
29 #include "utils/geometry.h"
30 #include "windows/windows.h"
31 #include "graphics/graphics.h"
32 #include "graphics/glyphs.h"
33 #include "windows/windInt.h"
34 #include "tiles/tile.h"
35 #include "utils/hash.h"
36 #include "database/database.h"
37 #include "utils/malloc.h"
38 
39 /* The following own variable is used to pass information between
40  * WindReframe and windFindUnobscured.
41  */
42 
43 static MagWindow *sharedW;
44 
45 /*
46  * By default, new windows have scroll bars, border, a title caption,
47  * and allow standard window commands.
48  */
49 int WindDefaultFlags = WIND_SCROLLBARS | WIND_CAPTION |
50 			WIND_BORDER | WIND_COMMANDS |
51 			WIND_SCROLLABLE;
52 
53 /*
54  * A mask of the current window IDs, as well as a limit on the number of
55  * windows we can create.
56  */
57 
58 int windWindowMask = 0;  /* One bit per window ID */
59 int windMaxWindows = 32; /* May be decreased via the WIND_MAX_WINDOWS() macro */
60 int windCurNumWindows = 0;
61 
62 
63 /*
64  * ----------------------------------------------------------------------------
65  * windUnlink --
66  *
67  *	Unlink a window from the doubly linked list of windows.
68  *
69  * Results:
70  *	None.
71  *
72  * Side effects:
73  *	The window is unlinked.
74  * ----------------------------------------------------------------------------
75  */
76 
77 void
windUnlink(w)78 windUnlink(w)
79     MagWindow *w;
80 {
81     ASSERT(w != (MagWindow *) NULL, "windUnlink");
82     ASSERT(windTopWindow != (MagWindow *) NULL, "windUnlink");
83     ASSERT(windBottomWindow != (MagWindow *) NULL, "windUnlink");
84     ASSERT(windTopWindow->w_prevWindow == (MagWindow *) NULL, "windUnlink");
85     ASSERT(windBottomWindow->w_nextWindow == (MagWindow *) NULL, "windUnlink");
86 
87     if ( (windTopWindow == w) || (windBottomWindow == w) )
88     {
89 	if (windTopWindow == w)
90 	{
91 	    windTopWindow = w->w_nextWindow;
92 	    if (windTopWindow != (MagWindow *) NULL)
93 		windTopWindow->w_prevWindow = (MagWindow *) NULL;
94 	}
95 	if (windBottomWindow == w)
96 	{
97 	    windBottomWindow = w->w_prevWindow;
98 	    if (windBottomWindow != (MagWindow *) NULL)
99 		windBottomWindow->w_nextWindow = (MagWindow *) NULL;
100 	}
101     }
102     else
103     {
104        w->w_nextWindow->w_prevWindow = w->w_prevWindow;
105        w->w_prevWindow->w_nextWindow = w->w_nextWindow;
106     }
107 
108     w->w_nextWindow = (MagWindow *) NULL;
109     w->w_prevWindow = (MagWindow *) NULL;
110 }
111 
112 /*
113  * ----------------------------------------------------------------------------
114  *
115  * windFree --
116  *
117  * 	This local procedure does the dirty work of freeing up
118  *	memory in a window.
119  *
120  * Results:
121  *	None.
122  *
123  * Side effects:
124  *	All storage associated with w is returned to the free pool.
125  *
126  * ----------------------------------------------------------------------------
127  */
128 
129 void
windFree(w)130 windFree(w)
131     MagWindow *w;
132 {
133     windWindowMask &= ~(1 << w->w_wid);
134     windCurNumWindows--;
135     if (w->w_caption != (char *) NULL) freeMagic(w->w_caption);
136     if (w->w_iconname != (char *) NULL) freeMagic(w->w_iconname);
137     if (GrFreeBackingStorePtr != NULL) (*GrFreeBackingStorePtr)(w);
138     if (w->w_redrawAreas != (ClientData) NULL) {
139 	DBFreePaintPlane( (Plane *) w->w_redrawAreas);
140 	TiFreePlane( (Plane *) w->w_redrawAreas);
141     }
142     freeMagic( (char *) w);
143 }
144 
145 /*
146  * ----------------------------------------------------------------------------
147  * WindSetWindowAreas --
148  *
149  *	Given the location of the window on the screen, compute w->w_allArea
150  *	and w->w_screenArea in the window's own coordinate system.
151  *
152  * Results:
153  *	None.
154  *
155  * Side effects:
156  *	Modifies w->w_allArea and w->w_screenArea.
157  * ----------------------------------------------------------------------------
158  */
159 
160 void
WindSetWindowAreas(w)161 WindSetWindowAreas(w)
162     MagWindow *w;
163 {
164     switch ( WindPackageType )
165     {
166 	case WIND_X_WINDOWS:
167 	    /* Windows have origin at lower-left corner */
168 	    w->w_allArea.r_xbot = w->w_allArea.r_ybot = 0;
169 	    w->w_allArea.r_xtop = w->w_frameArea.r_xtop - w->w_frameArea.r_xbot;
170 	    w->w_allArea.r_ytop = w->w_frameArea.r_ytop - w->w_frameArea.r_ybot;
171 	    break;
172 
173 	default:
174 	    /* Windows are all in the same coordinate system */
175 	    w->w_allArea = w->w_frameArea;
176     }
177     WindOutToIn(w, &w->w_allArea, &w->w_screenArea);
178 }
179 
180 
181 /*
182  * ----------------------------------------------------------------------------
183  * windSetWindowPosition --
184  *
185  *	(deprecated function)
186  *
187  * Results:
188  *	None.
189  *
190  * Side effects:
191  *	None.
192  * ----------------------------------------------------------------------------
193  */
194 
195 void
windSetWindowPosition(w)196 windSetWindowPosition(w)
197     MagWindow *w;
198 {
199 }
200 
201 /*
202  * ----------------------------------------------------------------------------
203  * WindDelete --
204  *
205  *	Delete a window.
206  *
207  * Results:
208  *	TRUE if the window was deleted, FALSE otherwise.
209  *
210  * Side effects:
211  *	The window disappears from the sreen.  The window's client is notified
212  *	that this is about to happen, and it may refuse to let it happen.
213  * ----------------------------------------------------------------------------
214  */
215 
216 bool
WindDelete(w)217 WindDelete(w)
218     MagWindow *w;
219 {
220     clientRec *cr;
221 
222     ASSERT(w != (MagWindow *) NULL, "WindDelete");
223 
224     cr = (clientRec *) w->w_client;
225     if ( (cr->w_delete == NULL) || (*(cr->w_delete))(w) )
226     {
227 	WindAreaChanged(w, &(w->w_allArea) );
228 	if (GrDeleteWindowPtr != NULL) (*GrDeleteWindowPtr)(w);
229 	windUnlink(w);
230 	windReClip();
231 	windFree(w);
232 	return TRUE;
233     }
234     else
235 	return FALSE;
236 }
237 
238 
239 /*
240  * ----------------------------------------------------------------------------
241  * WindCreate --
242  *
243  *	Create a new window for the specified client.
244  *
245  * Results:
246  *	A pointer to the new window, or NULL if one couldn't be created.
247  *
248  * Side effects:
249  *	An empty window is created, and it is displayed.
250  *	The new window is place on top of all the other
251  *	windows.
252  * ----------------------------------------------------------------------------
253  */
254 
255 MagWindow *
WindCreate(client,frameArea,isHint,argc,argv)256 WindCreate(client, frameArea, isHint, argc, argv)
257     WindClient client;		/* The client that will control this window */
258     Rect *frameArea;		/* The area that the window is to occupy */
259     bool isHint;		/* TRUE if the above rectangle is only a
260 				 * hint and it is OK for a window package to
261 				 * override it to maintain a consistent
262 				 * user interface.
263 				 */
264     int argc;			/* Passed to the client */
265     char *argv[];
266 {
267     MagWindow *w;
268     clientRec *cr;
269     bool OK;
270     int id;
271 
272     if (windCurNumWindows + 1 > windMaxWindows) {
273 	TxError("Can't have more than %d windows.\n", windMaxWindows);
274 	return NULL;
275     }
276     windCurNumWindows++;
277 
278     cr = (clientRec *) client;
279 
280     /* initialize the window */
281     w = (MagWindow *) mallocMagic( sizeof(MagWindow) );
282     w->w_client = client;
283     w->w_flags = WindDefaultFlags;
284     w->w_clipAgainst = (LinkedRect *) NULL;
285     w->w_caption = (char *) NULL;
286     w->w_stippleOrigin.p_x = 0;
287     w->w_stippleOrigin.p_y = 0;
288     w->w_bbox = NULL;
289     w->w_grdata = (ClientData) NULL;
290     w->w_grdata2 = (ClientData) NULL;
291     w->w_backingStore = (ClientData)NULL;
292     w->w_redrawAreas = (ClientData) NULL;
293     w->w_surfaceID = (ClientData) NULL;
294     w->w_iconname = NULL;
295     for (id = 0; ((1 << id) & windWindowMask) != 0; id++) /* advance id */ ;
296     windWindowMask |= (1 << id);
297     w->w_wid = id;
298 
299     /* locate window on the screen */
300     if (frameArea == (Rect *) NULL)
301     {
302 	switch ( WindPackageType )
303 	{
304 	    case WIND_X_WINDOWS:
305 		/*
306 		 * Create default size window in upper left corner
307 		 * of screen.
308 		 */
309 		w->w_frameArea.r_xbot = GrScreenRect.r_xbot;
310 		w->w_frameArea.r_ytop = GrScreenRect.r_ytop;
311 		w->w_frameArea.r_xtop =
312 		    (GrScreenRect.r_xtop - GrScreenRect.r_xbot) / 2;
313 		w->w_frameArea.r_ybot =
314 		    (GrScreenRect.r_ytop - GrScreenRect.r_ybot) / 2;
315 		break;
316 
317 	    default:
318 		w->w_frameArea = GrScreenRect;
319 	}
320     }
321     else
322 	w->w_frameArea = *frameArea;
323 
324     WindSetWindowAreas(w);
325 
326     /* now link the window in on top */
327     w->w_nextWindow = windTopWindow;
328     w->w_prevWindow = (MagWindow *) NULL;
329     if (windTopWindow == (MagWindow *) NULL)
330 	windBottomWindow = w;
331     else
332 	windTopWindow->w_prevWindow = w;
333     windTopWindow = w;
334 
335     /* notify the client */
336     OK = ((cr->w_create == NULL) || (*(cr->w_create))(w, argc, argv));
337 
338 #ifdef THREE_D
339     if (strcmp(cr->w_clientName, "wind3d"))
340 #endif
341 
342     if (OK && (GrCreateWindowPtr != NULL))
343 	OK = (*GrCreateWindowPtr)(w, (argc > 1) ? argv[1] : NULL);
344 
345     if (OK)
346     {
347 	WindSetWindowAreas(w);
348 	windSetWindowPosition(w);
349 	WindAreaChanged(w, &(w->w_allArea));
350     }
351     else
352     {
353 	/* the client refused the new window */
354 	windUnlink(w);
355 	windFree(w);
356 	w = (MagWindow *) NULL;
357     }
358     windReClip();
359     if ((GrCreateBackingStorePtr != NULL) && (w != NULL) &&
360 		(!(w->w_flags & WIND_OBSCURED)))
361 	(*GrCreateBackingStorePtr)(w);
362 
363     return w;
364 }
365 
366 /*
367  * ----------------------------------------------------------------------------
368  *
369  * WindOutToIn and WindInToOut --
370  *
371  * 	The two procedures on this page translate from window inside
372  *	area (the area used to display the surface) to window
373  *	outside area (the total area of the window including caption),
374  *	and vice versa.
375  *
376  * Results:
377  *	None.
378  *
379  * Side effects:
380  *	Each procedure modifies its third parameter.  WindOutToIn
381  *	fills in the third parameter with the inside area of the
382  *	window whose outside area is out, and WindInToOut does the
383  *	opposite.
384  *
385  * ----------------------------------------------------------------------------
386  */
387 
388 void
WindOutToIn(w,out,in)389 WindOutToIn(w, out, in)
390     MagWindow *w;			/* Window under consideration */
391     Rect *out;			/* Pointer to rectangle of outside area of
392 				 * a window.
393 				 */
394     Rect *in;			/* Pointer to rectangle to be filled in with
395 				 * inside area corresponding to out.
396 				 */
397 {
398     *in = *out;
399     in->r_xbot += LEFT_BORDER(w);
400     in->r_xtop -= RIGHT_BORDER(w);
401     in->r_ybot += BOT_BORDER(w);
402     in->r_ytop -= TOP_BORDER(w);
403 }
404 
WindInToOut(w,in,out)405 void WindInToOut(w, in, out)
406     MagWindow *w;			/* Window under consideration */
407     Rect *in;			/* Pointer to rectangle of outside area of
408 				 * a window.
409 				 */
410     Rect *out;			/* Pointer to rectangle to be filled in with
411 				 * inside area corresponding to out.
412 				 */
413 {
414     *out = *in;
415     out->r_xbot -= LEFT_BORDER(w);
416     out->r_xtop += RIGHT_BORDER(w);
417     out->r_ybot -= BOT_BORDER(w);
418     out->r_ytop += TOP_BORDER(w);
419 }
420 
421 
422 /*
423  * ----------------------------------------------------------------------------
424  * WindUnder --
425  *
426  *	Move a window underneath the rest.
427  *
428  * Results:
429  *	None.
430  *
431  * Side effects:
432  *	The window is moved so that it is underneath the rest.  This will
433  *	cause portions of uncovered windows to be redisplayed.
434  * ----------------------------------------------------------------------------
435  */
436 
437 void
WindUnder(w)438 WindUnder(w)
439     MagWindow *w;		/* the window to be moved */
440 {
441     Rect area;
442     MagWindow *w2;
443 
444     switch ( WindPackageType )
445     {
446 	case WIND_X_WINDOWS:
447 	    if ( GrUnderWindowPtr )
448 		(*GrUnderWindowPtr)(w);
449 	    break;
450 	default:
451 	    /* Mark for redisplay all the areas that this window
452 	     * currently obscures.
453 	     */
454 
455 	    for (w2 = w->w_nextWindow; w2 != NULL; w2 = w2->w_nextWindow)
456 	    {
457 		area = w2->w_allArea;
458 		GeoClip(&area, &w->w_allArea);
459 		if ((area.r_xbot <= area.r_xtop) && (area.r_ybot <= area.r_ytop))
460 		    WindAreaChanged(w, &area);
461 	    }
462 
463 	    /* take the window out of the linked list */
464 	    windUnlink(w);
465 
466 	    /* now link it back in at the bottom */
467 	    w->w_prevWindow = windBottomWindow;
468 	    if (windBottomWindow != (MagWindow *) NULL)
469 		windBottomWindow->w_nextWindow = w;
470 	    else
471 		windTopWindow = w;
472 	    windBottomWindow = w;
473 
474 	    windReClip();
475     }
476 }
477 
478 
479 /*
480  * ----------------------------------------------------------------------------
481  * WindOver --
482  *
483  *	Move a window so that it is over (on top of) the other windows.
484  *
485  * Results:
486  *	None.
487  *
488  * Side effects:
489  *	The window is moved to the top.  This may obscure some other windows.
490  *	The window that is moved will be redisplayed.
491  * ----------------------------------------------------------------------------
492  */
493 
494 void
WindOver(w)495 WindOver(w)
496     MagWindow *w;		/* the window to be moved */
497 {
498     LinkedRect *r;
499     Rect area;
500 
501     switch ( WindPackageType )
502     {
503 	case WIND_X_WINDOWS:
504 	    if ( GrOverWindowPtr )
505 		(*GrOverWindowPtr)(w);
506 	    break;
507 
508 	default:
509 	    /* Mark for redisplay all of the areas of the screen that
510 	     * currently obscure this window.
511 	     */
512 
513 	    for (r = w->w_clipAgainst; r != NULL; r = r->r_next)
514 	    {
515 		area = r->r_r;
516 		GeoClip(&area, &w->w_frameArea);
517 		if ((area.r_xbot <= area.r_xtop) && (area.r_ybot <= area.r_ytop))
518 		    WindAreaChanged((MagWindow *) NULL, &area);
519 	    }
520 
521 	    /* take the window out of the linked list */
522 	    windUnlink(w);
523 
524 	    /* now link it back in at the top */
525 	    w->w_nextWindow = windTopWindow;
526 	    if (windTopWindow != (MagWindow *) NULL)
527 		windTopWindow->w_prevWindow = w;
528 	    else
529 		windBottomWindow = w;
530 	    windTopWindow = w;
531 
532 	    windReClip();
533     }
534 }
535 
536 /*
537  * ----------------------------------------------------------------------------
538  *
539  * windFindUnobscured --
540  *
541  * 	Locates one portion of a rectangle that is unobscured, if
542  *	any part of the rectangle is unobscured.  Used only by
543  *	WindReframe.
544  *
545  * Results:
546  *	Always returns TRUE.
547  *
548  * Side effects:
549  *	The caller must place in the shared variable sharedW the
550  *	name of a window, or NULL.  That window, and all windows
551  *	above it, are checked to see if any obscure area.  If
552  *	there is any unobscured part of area, it is placed in
553  *	okArea.  If several distinct parts of area are unobscured,
554  *	one, but only one, of them will be placed in okArea.
555  *
556  * ----------------------------------------------------------------------------
557  */
558 
559 int
windFindUnobscured(area,okArea)560 windFindUnobscured(area, okArea)
561     Rect *area;				/* Area that may be obscured. */
562     Rect *okArea;			/* Modified to contain one of the
563 					 * unobscured areas.
564 					 */
565 {
566     MagWindow *w;
567     w = sharedW;
568     if (w == NULL)
569     {
570 	*okArea = *area;
571 	return FALSE;
572     }
573     sharedW = w->w_prevWindow;
574     (void) GeoDisjoint(area, &w->w_frameArea,
575 	windFindUnobscured, (ClientData) okArea);
576     return FALSE;
577 }
578 
579 /*
580  * ----------------------------------------------------------------------------
581  * WindReframe --
582  *
583  *	Change the size or location of a window.
584  *
585  * Results:
586  *	None.
587  *
588  * Side effects:
589  *	The window is moved, and areas of the screen are marked for
590  *	redisplay.  This routine tries to be tricky in order to avoid
591  *	massive redisplay for small changes.
592  * ----------------------------------------------------------------------------
593  */
594 
595 void
WindReframe(w,r,inside,move)596 WindReframe(w, r, inside, move)
597     MagWindow *w;		/* the window to be reframed */
598     Rect *r;		/* the new location in screen coordinates */
599     bool inside;	/* TRUE if the rectangle is the screen location of
600 			 * the inside of the window, FALSE if the above
601 			 * rectangle includes border areas.
602 			 */
603     bool move;		/* Move the coordinate system of the window the same
604 			 * amount as the lower left corner of the window?
605 			 */
606 {
607     Rect newFrameArea;			/* New w_frameArea. */
608     Rect dontRedisplay;			/* Used to record an area that does
609 					 * not have to be redisplayed.
610 					 */
611     int xmove, ymove;			/* Distance window is moving. */
612     extern int windReframeFunc();	/* Forward declaration. */
613     clientRec *cr;
614 
615     cr = (clientRec *) w->w_client;
616 
617     /* Ensure that the new window size is not inside out and has some size to
618      * it.  Compute the new w_frameArea (in newFrameArea).
619      */
620 
621     GeoCanonicalRect(r, &newFrameArea);
622     if (inside) WindInToOut(w, &newFrameArea, &newFrameArea);
623 
624     if ((w->w_flags & WIND_ISICONIC) == 0) {
625 	/* Not iconic -- enforce a minimum size */
626 	newFrameArea.r_xtop = MAX(newFrameArea.r_xtop,
627 	    newFrameArea.r_xbot + WIND_MIN_WIDTH);
628 	newFrameArea.r_ytop = MAX(newFrameArea.r_ytop,
629 	newFrameArea.r_ybot + WIND_MIN_HEIGHT);
630     }
631 
632     /* Give the client a chance to modify the change. */
633     if (cr->w_reposition != NULL)
634 	(*(cr->w_reposition))(w, &newFrameArea, FALSE);
635 
636 
637     /* If the window coordinates are moving, update the transform
638      * so that the lower-left corner of the window remains at the
639      * same location in surface coordinates.
640      */
641 
642     if (move)
643     {
644 	xmove = newFrameArea.r_xbot - w->w_frameArea.r_xbot;
645 	w->w_origin.p_x += xmove << SUBPIXELBITS;
646 	ymove = newFrameArea.r_ybot - w->w_frameArea.r_ybot;
647 	w->w_origin.p_y += ymove << SUBPIXELBITS;
648 	w->w_stippleOrigin.p_x += xmove;
649 	w->w_stippleOrigin.p_y += ymove;
650     }
651 
652     switch ( WindPackageType )
653     {
654 	case WIND_X_WINDOWS:
655 	    break;
656 
657 	default:
658 	    /* Now comes the tricky part:  figuring out what to redisplay.
659 	     * The simple way out is to force redisplay at both the old and
660 	     * new window positions.  Naturally this code is going to be more
661 	     * ambitious.  There are two steps.  First, figure out what piece
662 	     * of the old window must be redisplayed, then move the window,
663 	     * then figure out what pieces of the new window must be redisplayed.
664 	     * If the window coordinates aren't moving, then any screen area
665 	     * common to the old and new positions needn't be redisplayed,
666 	     * since its contents won't change.
667 	     */
668 
669 	     if (!move)
670 	     {
671 		/* Compute the intersection of the old and new areas in
672 		 * dontRedisplay.  Mark old areas outside of this common area as
673 		 * needing to be redisplayed.
674 		 */
675 		WindOutToIn(w, &newFrameArea, &dontRedisplay);
676 		GeoClip(&dontRedisplay, &w->w_screenArea);
677 		(void) GeoDisjoint(&w->w_frameArea, &dontRedisplay, windReframeFunc,
678 		    (ClientData) w);
679 	    }
680 	    else
681 	    {
682 		/* Record the entire old area as needing to be redisplayed. */
683 
684 		WindAreaChanged(w, &w->w_allArea);
685 		dontRedisplay = w->w_allArea;
686 	    }
687     }
688 
689     /* At this point, we've recorded any old area that needs to be
690      * redisplayed.
691      */
692 
693     w->w_frameArea = newFrameArea;
694     WindSetWindowAreas(w);
695     windSetWindowPosition(w);
696     windFixSurfaceArea(w);
697     windReClip();
698 
699     switch (WindPackageType)
700     {
701 	case WIND_X_WINDOWS:
702 	    /* Regenerate backing store, if enabled */
703 	    if ((GrCreateBackingStorePtr != NULL) &&
704 			(!(w->w_flags & WIND_OBSCURED)))
705 		(*GrCreateBackingStorePtr)(w);
706 	    break;
707 
708 	default:
709 	    /* Now that the window has been moved, record any of the new area that
710 	     * has to be redisplayed.
711 	     */
712 
713 	    (void) GeoDisjoint(&w->w_allArea, &dontRedisplay, windReframeFunc,
714 		(ClientData) w);
715     }
716 
717     /* Give the client a chance to do things like windMove().
718      */
719     if (cr->w_reposition != NULL)
720 	(*(cr->w_reposition))(w, &newFrameArea, TRUE);
721 }
722 
723 int
windReframeFunc(area,w)724 windReframeFunc(area, w)
725     Rect *area;			/* Area to redisplay. */
726     MagWindow *w;			/* Window in which to redisplay. */
727 
728 {
729     WindAreaChanged(w, area);
730     return 0;
731 }
732 
733 /*
734  * ----------------------------------------------------------------------------
735  *
736  * WindFullScreen --
737  *
738  * 	This procedure blows a window up so it's on top of all the others
739  *	and is full-screen.  Or, if the window was already full-screen,
740  *	it is put back where it came from before it was made full-screen.
741  *
742  * Results:
743  *	None.
744  *
745  * Side effects:
746  *	The window's size and location are changed.
747  *
748  * ----------------------------------------------------------------------------
749  */
750 
751 void
WindFullScreen(w)752 WindFullScreen(w)
753     MagWindow *w;			/* Window to be blown up or shrunk back. */
754 {
755     int i;
756     MagWindow *w2;
757     Rect newFrameArea;
758     clientRec *cr;
759     int newDepth;
760 
761     cr = (clientRec *) w->w_client;
762 
763     /* Compute default new location. */
764 
765     if (w->w_flags & WIND_FULLSCREEN)
766 	newFrameArea = w->w_oldArea;
767     else
768 	newFrameArea = GrScreenRect;
769 
770     /* Give the client a chance to modify newFrameArea. */
771 
772     if (cr->w_reposition != NULL)
773 	(*(cr->w_reposition))(w, &newFrameArea, FALSE);
774 
775     /*
776      * Now, actually modify the window and its position.
777      */
778 
779     /* Compute new stuff. */
780 
781     if (w->w_flags & WIND_FULLSCREEN)
782     {
783 	newDepth = w->w_oldDepth;
784 	w->w_flags &= ~WIND_FULLSCREEN;
785     }
786     else
787     {
788 	newDepth = 0;
789 	w->w_flags |= WIND_FULLSCREEN;
790 
791 	/* Record old depth and area. */
792 
793 	w->w_oldArea = w->w_frameArea;
794 	w->w_oldDepth = 0;
795 	for (w2 = windTopWindow; w2 != w; w2 = w2->w_nextWindow)
796 	{
797 	    ASSERT(w2 != (MagWindow *) NULL, "WindFullScreen");
798 	    w->w_oldDepth += 1;
799 	}
800     }
801 
802 
803     /* Change the view and screen location. */
804     w->w_frameArea = newFrameArea;
805     WindSetWindowAreas(w);
806     windSetWindowPosition(w);
807     WindMove(w, &w->w_surfaceArea);
808 
809     /* Move the window to the proper depth.  */
810     if (windTopWindow != (MagWindow *) NULL)
811     {
812 	if (newDepth == 0)
813 	{
814 	    switch ( WindPackageType )
815 	    {
816 		case WIND_X_WINDOWS:
817 		    break;
818 
819 		default:
820 		    WindOver(w);
821 	    }
822 	}
823 	else
824 	{
825 	    windUnlink(w);
826 	    w2 = windTopWindow;
827 	    for (i=1; i<newDepth; i++)
828 		if (w2->w_nextWindow != NULL) w2 = w2->w_nextWindow;
829 	    w->w_nextWindow = w2->w_nextWindow;
830 	    w->w_prevWindow = w2;
831 	    w2->w_nextWindow = w;
832 	    if (w->w_nextWindow == NULL)
833 		windBottomWindow = w;
834 	    else
835 		w->w_nextWindow->w_prevWindow = w;
836 	    windReClip();
837 	}
838     }
839 
840     /* Notify the client. */
841     if (cr->w_reposition != NULL)
842 	(*(cr->w_reposition))(w, &newFrameArea, TRUE);
843 
844     /* Record new display areas. */
845     switch (WindPackageType)
846     {
847 	case WIND_X_WINDOWS:
848 	    if (GrConfigureWindowPtr != NULL)
849 		(*GrConfigureWindowPtr)(w);
850 	    if (GrCreateBackingStorePtr != NULL &&
851 			(!(w->w_flags & WIND_OBSCURED)))
852 		(*GrCreateBackingStorePtr)(w);
853 	    break;
854 	default:
855 	    WindAreaChanged((MagWindow *) NULL, (Rect *) NULL);
856     }
857 }
858