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