resize.c revision 3e747e6d
1/*****************************************************************************/
2/*
3
4Copyright 1989, 1998  The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall not be
23used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from The Open Group.
25
26*/
27/**       Copyright 1988 by Evans & Sutherland Computer Corporation,        **/
28/**                          Salt Lake City, Utah                           **/
29/**                        Cambridge, Massachusetts                         **/
30/**                                                                         **/
31/**                           All Rights Reserved                           **/
32/**                                                                         **/
33/**    Permission to use, copy, modify, and distribute this software and    **/
34/**    its documentation  for  any  purpose  and  without  fee is hereby    **/
35/**    granted, provided that the above copyright notice appear  in  all    **/
36/**    copies and that both  that  copyright  notice  and  this  permis-    **/
37/**    sion  notice appear in supporting  documentation,  and  that  the    **/
38/**    name of Evans & Sutherland not be used in advertising    **/
39/**    in publicity pertaining to distribution of the  software  without    **/
40/**    specific, written prior permission.                                  **/
41/**                                                                         **/
42/**    EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD    **/
43/**    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-    **/
44/**    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND    **/
45/**    BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-    **/
46/**    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA    **/
47/**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
48/**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
49/**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
50/*****************************************************************************/
51
52
53/***********************************************************************
54 *
55 * $Xorg: resize.c,v 1.5 2001/02/09 02:05:37 xorgcvs Exp $
56 *
57 * window resizing borrowed from the "wm" window manager
58 *
59 * 11-Dec-87 Thomas E. LaStrange                File created
60 *
61 ***********************************************************************/
62
63/* $XFree86: xc/programs/twm/resize.c,v 1.7 2001/01/17 23:45:07 dawes Exp $ */
64
65#include <stdio.h>
66#include "twm.h"
67#include "parse.h"
68#include "util.h"
69#include "resize.h"
70#include "iconmgr.h"
71#include "add_window.h"
72#include "screen.h"
73#include "events.h"
74
75#define MINHEIGHT 0     /* had been 32 */
76#define MINWIDTH 0      /* had been 60 */
77
78static int dragx;       /* all these variables are used */
79static int dragy;       /* in resize operations */
80static int dragWidth;
81static int dragHeight;
82
83static int origx;
84static int origy;
85static int origWidth;
86static int origHeight;
87
88static int clampTop;
89static int clampBottom;
90static int clampLeft;
91static int clampRight;
92static int clampDX;
93static int clampDY;
94
95static int last_width;
96static int last_height;
97
98
99static void
100do_auto_clamp (TwmWindow *tmp_win, XEvent *evp)
101{
102    Window junkRoot;
103    int x, y, h, v, junkbw;
104    unsigned int junkMask;
105
106    switch (evp->type) {
107      case ButtonPress:
108	x = evp->xbutton.x_root;
109	y = evp->xbutton.y_root;
110	break;
111      case KeyPress:
112	x = evp->xkey.x_root;
113	y = evp->xkey.y_root;
114	break;
115      default:
116	if (!XQueryPointer (dpy, Scr->Root, &junkRoot, &junkRoot,
117			    &x, &y, &junkbw, &junkbw, &junkMask))
118	  return;
119    }
120
121    h = ((x - dragx) / (dragWidth < 3 ? 1 : (dragWidth / 3)));
122    v = ((y - dragy - tmp_win->title_height) /
123	 (dragHeight < 3 ? 1 : (dragHeight / 3)));
124
125    if (h <= 0) {
126	clampLeft = 1;
127	clampDX = (x - dragx);
128    } else if (h >= 2) {
129	clampRight = 1;
130	clampDX = (x - dragx - dragWidth);
131    }
132
133    if (v <= 0) {
134	clampTop = 1;
135	clampDY = (y - dragy);
136    } else if (v >= 2) {
137	clampBottom = 1;
138	clampDY = (y - dragy - dragHeight);
139    }
140}
141
142
143/**
144 * begin a window resize operation
145 *  \param ev           the event structure (button press)
146 *  \param tmp_win      the TwmWindow pointer
147 *  \param fromtitlebar action invoked from titlebar button
148 */
149void
150StartResize(XEvent *evp, TwmWindow *tmp_win, Bool fromtitlebar)
151{
152    Window      junkRoot;
153    unsigned int junkbw, junkDepth;
154
155    ResizeWindow = tmp_win->frame;
156    XGrabServer(dpy);
157    XGrabPointer(dpy, Scr->Root, True,
158        ButtonPressMask | ButtonReleaseMask |
159	ButtonMotionMask | PointerMotionHintMask,
160        GrabModeAsync, GrabModeAsync,
161        Scr->Root, Scr->ResizeCursor, CurrentTime);
162
163    XGetGeometry(dpy, (Drawable) tmp_win->frame, &junkRoot,
164        &dragx, &dragy, (unsigned int *)&dragWidth, (unsigned int *)&dragHeight, &junkbw,
165                 &junkDepth);
166    dragx += tmp_win->frame_bw;
167    dragy += tmp_win->frame_bw;
168    origx = dragx;
169    origy = dragy;
170    origWidth = dragWidth;
171    origHeight = dragHeight;
172    clampTop = clampBottom = clampLeft = clampRight = clampDX = clampDY = 0;
173
174    if (Scr->AutoRelativeResize && !fromtitlebar)
175      do_auto_clamp (tmp_win, evp);
176
177    Scr->SizeStringOffset = SIZE_HINDENT;
178    XResizeWindow (dpy, Scr->SizeWindow,
179		   Scr->SizeStringWidth + SIZE_HINDENT * 2,
180		   Scr->SizeFont.height + SIZE_VINDENT * 2);
181    XMapRaised(dpy, Scr->SizeWindow);
182    InstallRootColormap();
183    last_width = 0;
184    last_height = 0;
185    DisplaySize(tmp_win, origWidth, origHeight);
186    MoveOutline (Scr->Root, dragx - tmp_win->frame_bw,
187		 dragy - tmp_win->frame_bw, dragWidth + 2 * tmp_win->frame_bw,
188		 dragHeight + 2 * tmp_win->frame_bw,
189		 tmp_win->frame_bw, tmp_win->title_height);
190}
191
192
193
194void
195MenuStartResize(TwmWindow *tmp_win, int x, int y, int w, int h)
196{
197    XGrabServer(dpy);
198    XGrabPointer(dpy, Scr->Root, True,
199        ButtonPressMask | ButtonMotionMask | PointerMotionMask,
200        GrabModeAsync, GrabModeAsync,
201        Scr->Root, Scr->ResizeCursor, CurrentTime);
202    dragx = x + tmp_win->frame_bw;
203    dragy = y + tmp_win->frame_bw;
204    origx = dragx;
205    origy = dragy;
206    dragWidth = origWidth = w; /* - 2 * tmp_win->frame_bw; */
207    dragHeight = origHeight = h; /* - 2 * tmp_win->frame_bw; */
208    clampTop = clampBottom = clampLeft = clampRight = clampDX = clampDY = 0;
209    last_width = 0;
210    last_height = 0;
211    Scr->SizeStringOffset = SIZE_HINDENT;
212    XResizeWindow (dpy, Scr->SizeWindow,
213		   Scr->SizeStringWidth + SIZE_HINDENT * 2,
214		   Scr->SizeFont.height + SIZE_VINDENT * 2);
215    XMapRaised(dpy, Scr->SizeWindow);
216    DisplaySize(tmp_win, origWidth, origHeight);
217    MoveOutline (Scr->Root, dragx - tmp_win->frame_bw,
218		 dragy - tmp_win->frame_bw,
219		 dragWidth + 2 * tmp_win->frame_bw,
220		 dragHeight + 2 * tmp_win->frame_bw,
221		 tmp_win->frame_bw, tmp_win->title_height);
222}
223
224/**
225 * begin a windorew resize operation from AddWindow
226 *  \param tmp_win the TwmWindow pointer
227 */
228void
229AddStartResize(TwmWindow *tmp_win, int x, int y, int w, int h)
230{
231    XGrabServer(dpy);
232    XGrabPointer(dpy, Scr->Root, True,
233        ButtonReleaseMask | ButtonMotionMask | PointerMotionHintMask,
234        GrabModeAsync, GrabModeAsync,
235        Scr->Root, Scr->ResizeCursor, CurrentTime);
236
237    dragx = x + tmp_win->frame_bw;
238    dragy = y + tmp_win->frame_bw;
239    origx = dragx;
240    origy = dragy;
241    dragWidth = origWidth = w - 2 * tmp_win->frame_bw;
242    dragHeight = origHeight = h - 2 * tmp_win->frame_bw;
243    clampTop = clampBottom = clampLeft = clampRight = clampDX = clampDY = 0;
244/*****
245    if (Scr->AutoRelativeResize) {
246	clampRight = clampBottom = 1;
247    }
248*****/
249    last_width = 0;
250    last_height = 0;
251    DisplaySize(tmp_win, origWidth, origHeight);
252}
253
254
255
256void
257MenuDoResize(int x_root, int y_root, TwmWindow *tmp_win)
258{
259    int action;
260
261    action = 0;
262
263    x_root -= clampDX;
264    y_root -= clampDY;
265
266    if (clampTop) {
267        int         delta = y_root - dragy;
268        if (dragHeight - delta < MINHEIGHT) {
269            delta = dragHeight - MINHEIGHT;
270            clampTop = 0;
271        }
272        dragy += delta;
273        dragHeight -= delta;
274        action = 1;
275    }
276    else if (y_root <= dragy/* ||
277             y_root == findRootInfo(root)->rooty*/) {
278        dragy = y_root;
279        dragHeight = origy + origHeight -
280            y_root;
281        clampBottom = 0;
282        clampTop = 1;
283	clampDY = 0;
284        action = 1;
285    }
286    if (clampLeft) {
287        int         delta = x_root - dragx;
288        if (dragWidth - delta < MINWIDTH) {
289            delta = dragWidth - MINWIDTH;
290            clampLeft = 0;
291        }
292        dragx += delta;
293        dragWidth -= delta;
294        action = 1;
295    }
296    else if (x_root <= dragx/* ||
297             x_root == findRootInfo(root)->rootx*/) {
298        dragx = x_root;
299        dragWidth = origx + origWidth -
300            x_root;
301        clampRight = 0;
302        clampLeft = 1;
303	clampDX = 0;
304        action = 1;
305    }
306    if (clampBottom) {
307        int         delta = y_root - dragy - dragHeight;
308        if (dragHeight + delta < MINHEIGHT) {
309            delta = MINHEIGHT - dragHeight;
310            clampBottom = 0;
311        }
312        dragHeight += delta;
313        action = 1;
314    }
315    else if (y_root >= dragy + dragHeight) {
316        dragy = origy;
317        dragHeight = 1 + y_root - dragy;
318        clampTop = 0;
319        clampBottom = 1;
320	clampDY = 0;
321        action = 1;
322    }
323    if (clampRight) {
324        int         delta = x_root - dragx - dragWidth;
325        if (dragWidth + delta < MINWIDTH) {
326            delta = MINWIDTH - dragWidth;
327            clampRight = 0;
328        }
329        dragWidth += delta;
330        action = 1;
331    }
332    else if (x_root >= dragx + dragWidth) {
333        dragx = origx;
334        dragWidth = 1 + x_root - origx;
335        clampLeft = 0;
336        clampRight = 1;
337	clampDX = 0;
338        action = 1;
339    }
340
341    if (action) {
342        ConstrainSize (tmp_win, &dragWidth, &dragHeight);
343        if (clampLeft)
344            dragx = origx + origWidth - dragWidth;
345        if (clampTop)
346            dragy = origy + origHeight - dragHeight;
347        MoveOutline(Scr->Root,
348            dragx - tmp_win->frame_bw,
349            dragy - tmp_win->frame_bw,
350            dragWidth + 2 * tmp_win->frame_bw,
351            dragHeight + 2 * tmp_win->frame_bw,
352	    tmp_win->frame_bw, tmp_win->title_height);
353    }
354
355    DisplaySize(tmp_win, dragWidth, dragHeight);
356}
357
358
359/**
360 * move the rubberband around.  This is called for each motion event when
361 * we are resizing
362 *
363 *  \param x_root  the X corrdinate in the root window
364 *  \param y_root  the Y corrdinate in the root window
365 *  \param tmp_win the current twm window
366 */
367void
368DoResize(int x_root, int y_root, TwmWindow *tmp_win)
369{
370    int action;
371
372    action = 0;
373
374    x_root -= clampDX;
375    y_root -= clampDY;
376
377    if (clampTop) {
378        int         delta = y_root - dragy;
379        if (dragHeight - delta < MINHEIGHT) {
380            delta = dragHeight - MINHEIGHT;
381            clampTop = 0;
382        }
383        dragy += delta;
384        dragHeight -= delta;
385        action = 1;
386    }
387    else if (y_root <= dragy/* ||
388             y_root == findRootInfo(root)->rooty*/) {
389        dragy = y_root;
390        dragHeight = origy + origHeight -
391            y_root;
392        clampBottom = 0;
393        clampTop = 1;
394	clampDY = 0;
395        action = 1;
396    }
397    if (clampLeft) {
398        int         delta = x_root - dragx;
399        if (dragWidth - delta < MINWIDTH) {
400            delta = dragWidth - MINWIDTH;
401            clampLeft = 0;
402        }
403        dragx += delta;
404        dragWidth -= delta;
405        action = 1;
406    }
407    else if (x_root <= dragx/* ||
408             x_root == findRootInfo(root)->rootx*/) {
409        dragx = x_root;
410        dragWidth = origx + origWidth -
411            x_root;
412        clampRight = 0;
413        clampLeft = 1;
414	clampDX = 0;
415        action = 1;
416    }
417    if (clampBottom) {
418        int         delta = y_root - dragy - dragHeight;
419        if (dragHeight + delta < MINHEIGHT) {
420            delta = MINHEIGHT - dragHeight;
421            clampBottom = 0;
422        }
423        dragHeight += delta;
424        action = 1;
425    }
426    else if (y_root >= dragy + dragHeight - 1/* ||
427           y_root == findRootInfo(root)->rooty
428           + findRootInfo(root)->rootheight - 1*/) {
429        dragy = origy;
430        dragHeight = 1 + y_root - dragy;
431        clampTop = 0;
432        clampBottom = 1;
433	clampDY = 0;
434        action = 1;
435    }
436    if (clampRight) {
437        int         delta = x_root - dragx - dragWidth;
438        if (dragWidth + delta < MINWIDTH) {
439            delta = MINWIDTH - dragWidth;
440            clampRight = 0;
441        }
442        dragWidth += delta;
443        action = 1;
444    }
445    else if (x_root >= dragx + dragWidth - 1/* ||
446             x_root == findRootInfo(root)->rootx +
447             findRootInfo(root)->rootwidth - 1*/) {
448        dragx = origx;
449        dragWidth = 1 + x_root - origx;
450        clampLeft = 0;
451        clampRight = 1;
452	clampDX = 0;
453        action = 1;
454    }
455
456    if (action) {
457        ConstrainSize (tmp_win, &dragWidth, &dragHeight);
458        if (clampLeft)
459            dragx = origx + origWidth - dragWidth;
460        if (clampTop)
461            dragy = origy + origHeight - dragHeight;
462        MoveOutline(Scr->Root,
463            dragx - tmp_win->frame_bw,
464            dragy - tmp_win->frame_bw,
465            dragWidth + 2 * tmp_win->frame_bw,
466            dragHeight + 2 * tmp_win->frame_bw,
467	    tmp_win->frame_bw, tmp_win->title_height);
468    }
469
470    DisplaySize(tmp_win, dragWidth, dragHeight);
471}
472
473/**
474 * display the size in the dimensions window.
475 *
476 *  \param tmp_win the current twm window
477 *  \param width   the width of the rubber band
478 *  \param height  the height of the rubber band
479 */
480void
481DisplaySize(TwmWindow *tmp_win, int width, int height)
482{
483    char str[100];
484    int dwidth;
485    int dheight;
486
487    if (last_width == width && last_height == height)
488        return;
489
490    last_width = width;
491    last_height = height;
492
493    dheight = height - tmp_win->title_height;
494    dwidth = width;
495
496    /*
497     * ICCCM says that PMinSize is the default is no PBaseSize is given,
498     * and vice-versa.
499     */
500    if (tmp_win->hints.flags&(PMinSize|PBaseSize) && tmp_win->hints.flags & PResizeInc)
501    {
502	if (tmp_win->hints.flags & PBaseSize) {
503	    dwidth -= tmp_win->hints.base_width;
504	    dheight -= tmp_win->hints.base_height;
505	} else {
506	    dwidth -= tmp_win->hints.min_width;
507	    dheight -= tmp_win->hints.min_height;
508	}
509    }
510
511    if (tmp_win->hints.flags & PResizeInc)
512    {
513        dwidth /= tmp_win->hints.width_inc;
514        dheight /= tmp_win->hints.height_inc;
515    }
516
517    (void) sprintf (str, " %4d x %-4d ", dwidth, dheight);
518    XRaiseWindow(dpy, Scr->SizeWindow);
519    MyFont_ChangeGC(Scr->DefaultC.fore, Scr->DefaultC.back, &Scr->SizeFont);
520    MyFont_DrawImageString (dpy, Scr->SizeWindow, &Scr->SizeFont,
521			    Scr->NormalGC, Scr->SizeStringOffset,
522			    Scr->SizeFont.ascent + SIZE_VINDENT,
523			    str, 13);
524}
525
526/**
527 * finish the resize operation
528 */
529void
530EndResize()
531{
532    TwmWindow *tmp_win;
533
534#ifdef DEBUG
535    fprintf(stderr, "EndResize\n");
536#endif
537
538    MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
539    XUnmapWindow(dpy, Scr->SizeWindow);
540
541    XFindContext(dpy, ResizeWindow, TwmContext, (caddr_t *)&tmp_win);
542
543    ConstrainSize (tmp_win, &dragWidth, &dragHeight);
544
545    if (dragWidth != tmp_win->frame_width ||
546        dragHeight != tmp_win->frame_height)
547            tmp_win->zoomed = ZOOM_NONE;
548
549    SetupWindow (tmp_win, dragx - tmp_win->frame_bw, dragy - tmp_win->frame_bw,
550		 dragWidth, dragHeight, -1);
551
552    if (tmp_win->iconmgr)
553    {
554	int ncols = tmp_win->iconmgrp->cur_columns;
555	if (ncols == 0) ncols = 1;
556
557	tmp_win->iconmgrp->width = (int) ((dragWidth *
558					   (long) tmp_win->iconmgrp->columns)
559					  / ncols);
560        PackIconManager(tmp_win->iconmgrp);
561    }
562
563    if (!Scr->NoRaiseResize)
564        XRaiseWindow(dpy, tmp_win->frame);
565
566    UninstallRootColormap();
567
568    ResizeWindow = None;
569}
570
571void
572MenuEndResize(TwmWindow *tmp_win)
573{
574    MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0);
575    XUnmapWindow(dpy, Scr->SizeWindow);
576    ConstrainSize (tmp_win, &dragWidth, &dragHeight);
577    AddingX = dragx - tmp_win->frame_bw;
578    AddingY = dragy - tmp_win->frame_bw;
579    AddingW = dragWidth;/* + (2 * tmp_win->frame_bw);*/
580    AddingH = dragHeight;/* + (2 * tmp_win->frame_bw);*/
581    SetupWindow (tmp_win, AddingX, AddingY, AddingW, AddingH, -1);
582}
583
584
585
586/**
587 * finish the resize operation for AddWindo<w
588 */
589void
590AddEndResize(TwmWindow *tmp_win)
591{
592
593#ifdef DEBUG
594    fprintf(stderr, "AddEndResize\n");
595#endif
596
597    ConstrainSize (tmp_win, &dragWidth, &dragHeight);
598    AddingX = dragx - tmp_win->frame_bw;
599    AddingY = dragy - tmp_win->frame_bw;
600    AddingW = dragWidth + (2 * tmp_win->frame_bw);
601    AddingH = dragHeight + (2 * tmp_win->frame_bw);
602}
603
604/**
605 * adjust the given width and height to account for the constraints imposed
606 * by size hints.
607 *
608 *      The general algorithm, especially the aspect ratio stuff, is
609 *      borrowed from uwm's CheckConsistency routine.
610 */
611void
612ConstrainSize (TwmWindow *tmp_win, int *widthp, int *heightp)
613{
614#define makemult(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) )
615#define _min(a,b) (((a) < (b)) ? (a) : (b))
616
617    int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc, delta;
618    int baseWidth, baseHeight;
619    int dwidth = *widthp, dheight = *heightp;
620
621
622    dheight -= tmp_win->title_height;
623
624    if (tmp_win->hints.flags & PMinSize) {
625        minWidth = tmp_win->hints.min_width;
626        minHeight = tmp_win->hints.min_height;
627    } else if (tmp_win->hints.flags & PBaseSize) {
628        minWidth = tmp_win->hints.base_width;
629        minHeight = tmp_win->hints.base_height;
630    } else
631        minWidth = minHeight = 1;
632
633    if (tmp_win->hints.flags & PBaseSize) {
634	baseWidth = tmp_win->hints.base_width;
635	baseHeight = tmp_win->hints.base_height;
636    } else if (tmp_win->hints.flags & PMinSize) {
637	baseWidth = tmp_win->hints.min_width;
638	baseHeight = tmp_win->hints.min_height;
639    } else
640	baseWidth = baseHeight = 0;
641
642
643    if (tmp_win->hints.flags & PMaxSize) {
644        maxWidth = _min (Scr->MaxWindowWidth, tmp_win->hints.max_width);
645        maxHeight = _min (Scr->MaxWindowHeight, tmp_win->hints.max_height);
646    } else {
647        maxWidth = Scr->MaxWindowWidth;
648	maxHeight = Scr->MaxWindowHeight;
649    }
650
651    if (tmp_win->hints.flags & PResizeInc) {
652        xinc = tmp_win->hints.width_inc;
653        yinc = tmp_win->hints.height_inc;
654    } else
655        xinc = yinc = 1;
656
657    /*
658     * First, clamp to min and max values
659     */
660    if (dwidth < minWidth) dwidth = minWidth;
661    if (dheight < minHeight) dheight = minHeight;
662
663    if (dwidth > maxWidth) dwidth = maxWidth;
664    if (dheight > maxHeight) dheight = maxHeight;
665
666
667    /*
668     * Second, fit to base + N * inc
669     */
670    dwidth = ((dwidth - baseWidth) / xinc * xinc) + baseWidth;
671    dheight = ((dheight - baseHeight) / yinc * yinc) + baseHeight;
672
673
674    /*
675     * Third, adjust for aspect ratio
676     */
677#define maxAspectX tmp_win->hints.max_aspect.x
678#define maxAspectY tmp_win->hints.max_aspect.y
679#define minAspectX tmp_win->hints.min_aspect.x
680#define minAspectY tmp_win->hints.min_aspect.y
681    /*
682     * The math looks like this:
683     *
684     * minAspectX    dwidth     maxAspectX
685     * ---------- <= ------- <= ----------
686     * minAspectY    dheight    maxAspectY
687     *
688     * If that is multiplied out, then the width and height are
689     * invalid in the following situations:
690     *
691     * minAspectX * dheight > minAspectY * dwidth
692     * maxAspectX * dheight < maxAspectY * dwidth
693     *
694     */
695
696    if (tmp_win->hints.flags & PAspect)
697    {
698        if (minAspectX * dheight > minAspectY * dwidth)
699        {
700            delta = makemult(minAspectX * dheight / minAspectY - dwidth,
701                             xinc);
702            if (dwidth + delta <= maxWidth) dwidth += delta;
703            else
704            {
705                delta = makemult(dheight - dwidth*minAspectY/minAspectX,
706                                 yinc);
707                if (dheight - delta >= minHeight) dheight -= delta;
708            }
709        }
710
711        if (maxAspectX * dheight < maxAspectY * dwidth)
712        {
713            delta = makemult(dwidth * maxAspectY / maxAspectX - dheight,
714                             yinc);
715            if (dheight + delta <= maxHeight) dheight += delta;
716            else
717            {
718                delta = makemult(dwidth - maxAspectX*dheight/maxAspectY,
719                                 xinc);
720                if (dwidth - delta >= minWidth) dwidth -= delta;
721            }
722        }
723    }
724
725
726    /*
727     * Fourth, account for border width and title height
728     */
729    *widthp = dwidth;
730    *heightp = dheight + tmp_win->title_height;
731}
732
733
734/**
735 * set window sizes, this was called from either AddWindow, EndResize, or
736 * HandleConfigureNotify.
737 *
738 *  Special Considerations:
739 * This routine will check to make sure the window is not completely off the
740 * display, if it is, it'll bring some of it back on.
741 *
742 * The tmp_win->frame_XXX variables should NOT be updated with the values of
743 * x,y,w,h prior to calling this routine, since the new values are compared
744 * against the old to see whether a synthetic ConfigureNotify event should be
745 * sent.  (It should be sent if the window was moved but not resized.)
746 *
747 *  \param tmp_win the TwmWindow pointer
748 *  \param x       the x coordinate of the upper-left outer corner of the frame
749 *  \param y       the y coordinate of the upper-left outer corner of the frame
750 *  \param w       the width of the frame window w/o border
751 *  \param h       the height of the frame window w/o border
752 *  \param bw      the border width of the frame window or -1 not to change
753 */
754void SetupWindow (TwmWindow *tmp_win, int x, int y, int w, int h, int bw)
755{
756    SetupFrame (tmp_win, x, y, w, h, bw, False);
757}
758
759/**
760 *  \param sendEvent whether or not to force a send
761 */
762void SetupFrame (TwmWindow *tmp_win, int x, int y, int w, int h, int bw, Bool sendEvent)
763{
764    XEvent client_event;
765    XWindowChanges frame_wc, xwc;
766    unsigned long frame_mask, xwcm;
767    int title_width, title_height;
768    int reShape;
769
770#ifdef DEBUG
771    fprintf (stderr, "SetupWindow: x=%d, y=%d, w=%d, h=%d, bw=%d\n",
772	     x, y, w, h, bw);
773#endif
774
775    if (x >= Scr->MyDisplayWidth)
776      x = Scr->MyDisplayWidth - 16;	/* one "average" cursor width */
777    if (y >= Scr->MyDisplayHeight)
778      y = Scr->MyDisplayHeight - 16;	/* one "average" cursor width */
779    if (bw < 0)
780      bw = tmp_win->frame_bw;		/* -1 means current frame width */
781
782    if (tmp_win->iconmgr) {
783	tmp_win->iconmgrp->width = w;
784        h = tmp_win->iconmgrp->height + tmp_win->title_height;
785    }
786
787    /*
788     * According to the July 27, 1988 ICCCM draft, we should send a
789     * "synthetic" ConfigureNotify event to the client if the window
790     * was moved but not resized.
791     */
792    if (((x != tmp_win->frame_x || y != tmp_win->frame_y) &&
793	 (w == tmp_win->frame_width && h == tmp_win->frame_height)) ||
794	(bw != tmp_win->frame_bw))
795      sendEvent = TRUE;
796
797    xwcm = CWWidth;
798    title_width = xwc.width = w;
799    title_height = Scr->TitleHeight + bw;
800
801    ComputeWindowTitleOffsets (tmp_win, xwc.width, True);
802
803    reShape = (tmp_win->wShaped ? TRUE : FALSE);
804    if (tmp_win->squeeze_info)		/* check for title shaping */
805    {
806	title_width = tmp_win->rightx + Scr->TBInfo.rightoff;
807	if (title_width < xwc.width)
808	{
809	    xwc.width = title_width;
810	    if (tmp_win->frame_height != h ||
811	    	tmp_win->frame_width != w ||
812		tmp_win->frame_bw != bw ||
813	    	title_width != tmp_win->title_width)
814	    	reShape = TRUE;
815	}
816	else
817	{
818	    if (!tmp_win->wShaped) reShape = TRUE;
819	    title_width = xwc.width;
820	}
821    }
822
823    tmp_win->title_width = title_width;
824    if (tmp_win->title_height) tmp_win->title_height = title_height;
825
826    if (tmp_win->title_w) {
827	if (bw != tmp_win->frame_bw) {
828	    xwc.border_width = bw;
829	    tmp_win->title_x = xwc.x = -bw;
830	    tmp_win->title_y = xwc.y = -bw;
831	    xwcm |= (CWX | CWY | CWBorderWidth);
832	}
833
834	XConfigureWindow(dpy, tmp_win->title_w, xwcm, &xwc);
835    }
836
837    if (tmp_win->attr.width != w)
838	tmp_win->widthEverChangedByUser = True;
839
840    if (tmp_win->attr.height != (h - tmp_win->title_height))
841	tmp_win->heightEverChangedByUser = True;
842
843    tmp_win->attr.width = w;
844    tmp_win->attr.height = h - tmp_win->title_height;
845
846    XMoveResizeWindow (dpy, tmp_win->w, 0, tmp_win->title_height,
847		       w, h - tmp_win->title_height);
848
849    /*
850     * fix up frame and assign size/location values in tmp_win
851     */
852    frame_mask = 0;
853    if (bw != tmp_win->frame_bw) {
854	frame_wc.border_width = tmp_win->frame_bw = bw;
855	frame_mask |= CWBorderWidth;
856    }
857    frame_wc.x = tmp_win->frame_x = x;
858    frame_wc.y = tmp_win->frame_y = y;
859    frame_wc.width = tmp_win->frame_width = w;
860    frame_wc.height = tmp_win->frame_height = h;
861    frame_mask |= (CWX | CWY | CWWidth | CWHeight);
862    XConfigureWindow (dpy, tmp_win->frame, frame_mask, &frame_wc);
863
864    /*
865     * fix up highlight window
866     */
867    if (tmp_win->title_height && tmp_win->hilite_w)
868    {
869	xwc.width = (tmp_win->rightx - tmp_win->highlightx);
870	if (Scr->TBInfo.nright > 0) xwc.width -= Scr->TitlePadding;
871        if (xwc.width <= 0) {
872            xwc.x = Scr->MyDisplayWidth;	/* move offscreen */
873            xwc.width = 1;
874        } else {
875            xwc.x = tmp_win->highlightx;
876        }
877
878        xwcm = CWX | CWWidth;
879        XConfigureWindow(dpy, tmp_win->hilite_w, xwcm, &xwc);
880    }
881
882    if (HasShape && reShape) {
883	SetFrameShape (tmp_win);
884    }
885
886    if (sendEvent)
887    {
888        client_event.type = ConfigureNotify;
889        client_event.xconfigure.display = dpy;
890        client_event.xconfigure.event = tmp_win->w;
891        client_event.xconfigure.window = tmp_win->w;
892        client_event.xconfigure.x = (x + tmp_win->frame_bw - tmp_win->old_bw);
893        client_event.xconfigure.y = (y + tmp_win->frame_bw +
894				     tmp_win->title_height - tmp_win->old_bw);
895        client_event.xconfigure.width = tmp_win->frame_width;
896        client_event.xconfigure.height = tmp_win->frame_height -
897                tmp_win->title_height;
898        client_event.xconfigure.border_width = tmp_win->old_bw;
899        /* Real ConfigureNotify events say we're above title window, so ... */
900	/* what if we don't have a title ????? */
901        client_event.xconfigure.above = tmp_win->frame;
902        client_event.xconfigure.override_redirect = False;
903        XSendEvent(dpy, tmp_win->w, False, StructureNotifyMask, &client_event);
904    }
905}
906
907
908/**
909 * zooms window to full height of screen or to full height and width of screen.
910 * (Toggles so that it can undo the zoom - even when switching between fullzoom
911 * and vertical zoom.)
912 *
913 *  \param tmp_win  the TwmWindow pointer
914 */
915void
916fullzoom(TwmWindow *tmp_win, int flag)
917{
918    Window      junkRoot;
919    unsigned int junkbw, junkDepth;
920    int basex, basey;
921    int frame_bw_times_2;
922
923	XGetGeometry(dpy, (Drawable) tmp_win->frame, &junkRoot,
924	        &dragx, &dragy, (unsigned int *)&dragWidth, (unsigned int *)&dragHeight, &junkbw,
925	        &junkDepth);
926
927	basex = 0;
928	basey = 0;
929
930        if (tmp_win->zoomed == flag)
931        {
932            dragHeight = tmp_win->save_frame_height;
933            dragWidth = tmp_win->save_frame_width;
934            dragx = tmp_win->save_frame_x;
935            dragy = tmp_win->save_frame_y;
936            tmp_win->zoomed = ZOOM_NONE;
937        }
938        else
939        {
940                if (tmp_win->zoomed == ZOOM_NONE)
941                {
942                        tmp_win->save_frame_x = dragx;
943                        tmp_win->save_frame_y = dragy;
944                        tmp_win->save_frame_width = dragWidth;
945                        tmp_win->save_frame_height = dragHeight;
946                        tmp_win->zoomed = flag;
947                 }
948                  else
949                            tmp_win->zoomed = flag;
950
951
952	frame_bw_times_2 = 2*tmp_win->frame_bw;
953
954        switch (flag)
955        {
956        case ZOOM_NONE:
957            break;
958        case F_ZOOM:
959            dragHeight = Scr->MyDisplayHeight - frame_bw_times_2;
960            dragy=basey;
961            break;
962        case F_HORIZOOM:
963            dragx = basex;
964            dragWidth = Scr->MyDisplayWidth - frame_bw_times_2;
965            break;
966        case F_FULLZOOM:
967            dragx = basex;
968            dragy = basey;
969            dragHeight = Scr->MyDisplayHeight - frame_bw_times_2;
970            dragWidth = Scr->MyDisplayWidth - frame_bw_times_2;
971            break;
972        case F_LEFTZOOM:
973            dragx = basex;
974            dragy = basey;
975            dragHeight = Scr->MyDisplayHeight - frame_bw_times_2;
976            dragWidth = Scr->MyDisplayWidth/2 - frame_bw_times_2;
977            break;
978        case F_RIGHTZOOM:
979            dragx = basex + Scr->MyDisplayWidth/2;
980            dragy = basey;
981            dragHeight = Scr->MyDisplayHeight - frame_bw_times_2;
982            dragWidth = Scr->MyDisplayWidth/2 - frame_bw_times_2;
983            break;
984        case F_TOPZOOM:
985            dragx = basex;
986            dragy = basey;
987            dragHeight = Scr->MyDisplayHeight/2 - frame_bw_times_2;
988            dragWidth = Scr->MyDisplayWidth - frame_bw_times_2;
989            break;
990        case F_BOTTOMZOOM:
991            dragx = basex;
992            dragy = basey + Scr->MyDisplayHeight/2;
993            dragHeight = Scr->MyDisplayHeight/2 - frame_bw_times_2;
994            dragWidth = Scr->MyDisplayWidth - frame_bw_times_2;
995            break;
996         }
997      }
998
999    if (!Scr->NoRaiseResize)
1000        XRaiseWindow(dpy, tmp_win->frame);
1001
1002    ConstrainSize(tmp_win, &dragWidth, &dragHeight);
1003
1004    SetupWindow (tmp_win, dragx , dragy , dragWidth, dragHeight, -1);
1005    XUngrabPointer (dpy, CurrentTime);
1006    XUngrabServer (dpy);
1007}
1008
1009void
1010SetFrameShape (TwmWindow *tmp)
1011{
1012    /*
1013     * see if the titlebar needs to move
1014     */
1015    if (tmp->title_w) {
1016	int oldx = tmp->title_x, oldy = tmp->title_y;
1017	ComputeTitleLocation (tmp);
1018	if (oldx != tmp->title_x || oldy != tmp->title_y)
1019	  XMoveWindow (dpy, tmp->title_w, tmp->title_x, tmp->title_y);
1020    }
1021
1022    /*
1023     * The frame consists of the shape of the contents window offset by
1024     * title_height or'ed with the shape of title_w (which is always
1025     * rectangular).
1026     */
1027    if (tmp->wShaped) {
1028	/*
1029	 * need to do general case
1030	 */
1031	XShapeCombineShape (dpy, tmp->frame, ShapeBounding,
1032			    0, tmp->title_height, tmp->w,
1033			    ShapeBounding, ShapeSet);
1034	if (tmp->title_w) {
1035	    XShapeCombineShape (dpy, tmp->frame, ShapeBounding,
1036				tmp->title_x + tmp->frame_bw,
1037				tmp->title_y + tmp->frame_bw,
1038				tmp->title_w, ShapeBounding,
1039				ShapeUnion);
1040	}
1041    } else {
1042	/*
1043	 * can optimize rectangular contents window
1044	 */
1045	if (tmp->squeeze_info) {
1046	    XRectangle  newBounding[2];
1047	    XRectangle  newClip[2];
1048	    int fbw2 = 2 * tmp->frame_bw;
1049
1050	    /*
1051	     * Build the border clipping rectangles; one around title, one
1052	     * around window.  The title_[xy] field already have had frame_bw
1053	     * subtracted off them so that they line up properly in the frame.
1054	     *
1055	     * The frame_width and frame_height do *not* include borders.
1056	     */
1057	    /* border */
1058	    newBounding[0].x = tmp->title_x;
1059	    newBounding[0].y = tmp->title_y;
1060	    newBounding[0].width = tmp->title_width + fbw2;
1061	    newBounding[0].height = tmp->title_height;
1062	    newBounding[1].x = -tmp->frame_bw;
1063	    newBounding[1].y = Scr->TitleHeight;
1064	    newBounding[1].width = tmp->attr.width + fbw2;
1065	    newBounding[1].height = tmp->attr.height + fbw2;
1066	    XShapeCombineRectangles (dpy, tmp->frame, ShapeBounding, 0, 0,
1067				     newBounding, 2, ShapeSet, YXBanded);
1068	    /* insides */
1069	    newClip[0].x = tmp->title_x + tmp->frame_bw;
1070	    newClip[0].y = 0;
1071	    newClip[0].width = tmp->title_width;
1072	    newClip[0].height = Scr->TitleHeight;
1073	    newClip[1].x = 0;
1074	    newClip[1].y = tmp->title_height;
1075	    newClip[1].width = tmp->attr.width;
1076	    newClip[1].height = tmp->attr.height;
1077	    XShapeCombineRectangles (dpy, tmp->frame, ShapeClip, 0, 0,
1078				     newClip, 2, ShapeSet, YXBanded);
1079	} else {
1080	    (void) XShapeCombineMask (dpy, tmp->frame, ShapeBounding, 0, 0,
1081 				      None, ShapeSet);
1082	    (void) XShapeCombineMask (dpy, tmp->frame, ShapeClip, 0, 0,
1083				      None, ShapeSet);
1084	}
1085    }
1086}
1087
1088/*
1089 * Squeezed Title:
1090 *
1091 *                         tmp->title_x
1092 *                   0     |
1093 *  tmp->title_y   ........+--------------+.........  -+,- tmp->frame_bw
1094 *             0   : ......| +----------+ |....... :  -++
1095 *                 : :     | |          | |      : :   ||-Scr->TitleHeight
1096 *                 : :     | |          | |      : :   ||
1097 *                 +-------+ +----------+ +--------+  -+|-tmp->title_height
1098 *                 | +---------------------------+ |  --+
1099 *                 | |                           | |
1100 *                 | |                           | |
1101 *                 | |                           | |
1102 *                 | |                           | |
1103 *                 | |                           | |
1104 *                 | +---------------------------+ |
1105 *                 +-------------------------------+
1106 *
1107 *
1108 * Unsqueezed Title:
1109 *
1110 *                 tmp->title_x
1111 *                 | 0
1112 *  tmp->title_y   +-------------------------------+  -+,tmp->frame_bw
1113 *             0   | +---------------------------+ |  -+'
1114 *                 | |                           | |   |-Scr->TitleHeight
1115 *                 | |                           | |   |
1116 *                 + +---------------------------+ +  -+
1117 *                 |-+---------------------------+-|
1118 *                 | |                           | |
1119 *                 | |                           | |
1120 *                 | |                           | |
1121 *                 | |                           | |
1122 *                 | |                           | |
1123 *                 | +---------------------------+ |
1124 *                 +-------------------------------+
1125 *
1126 *
1127 *
1128 * Dimensions and Positions:
1129 *
1130 *     frame orgin                 (0, 0)
1131 *     frame upper left border     (-tmp->frame_bw, -tmp->frame_bw)
1132 *     frame size w/o border       tmp->frame_width , tmp->frame_height
1133 *     frame/title border width    tmp->frame_bw
1134 *     extra title height w/o bdr  tmp->title_height = TitleHeight + frame_bw
1135 *     title window height         Scr->TitleHeight
1136 *     title origin w/o border     (tmp->title_x, tmp->title_y)
1137 *     client origin               (0, Scr->TitleHeight + tmp->frame_bw)
1138 *     client size                 tmp->attr.width , tmp->attr.height
1139 *
1140 * When shaping, need to remember that the width and height of rectangles
1141 * are really deltax and deltay to lower right handle corner, so they need
1142 * to have -1 subtracted from would normally be the actual extents.
1143 */
1144