1 /* -*-c-*- */
2 /*
3 * FvwmButtons, copyright 1996, Jarl Totland
4 *
5 * This module, and the entire GoodStuff program, and the concept for
6 * interfacing this module to the Window Manager, are all original work
7 * by Robert Nation
8 */
9
10 /* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see: <http://www.gnu.org/licenses/>
22 */
23
24 #include "config.h"
25
26 #include "misc.h"
27 #include <stdio.h>
28
29 /**
30 *** ConstrainSize()
31 *** Adjust a given width and height to account for the constraints imposed by
32 *** size hints.
33 *** The general algorithm, especially the aspect ratio stuff, is borrowed from
34 *** uwm's CheckConsistency routine.
35 **/
ConstrainSize(XSizeHints * hints,int * widthp,int * heightp)36 void ConstrainSize (XSizeHints *hints, int *widthp, int *heightp)
37 {
38 #define makemult(a,b) ((b == 1) ? (a) : (((int)((a) / (b))) * (b)))
39
40 int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc, delta;
41 int baseWidth, baseHeight;
42 int dwidth = *widthp, dheight = *heightp;
43
44 if (hints->flags & PMinSize)
45 {
46 minWidth = hints->min_width;
47 minHeight = hints->min_height;
48 if (hints->flags & PBaseSize)
49 {
50 baseWidth = hints->base_width;
51 baseHeight = hints->base_height;
52 }
53 else
54 {
55 baseWidth = hints->min_width;
56 baseHeight = hints->min_height;
57 }
58 }
59 else if (hints->flags & PBaseSize)
60 {
61 minWidth = hints->base_width;
62 minHeight = hints->base_height;
63 baseWidth = hints->base_width;
64 baseHeight = hints->base_height;
65 }
66 else
67 {
68 minWidth = 1;
69 minHeight = 1;
70 baseWidth = 1;
71 baseHeight = 1;
72 }
73
74 if (hints->flags & PMaxSize)
75 {
76 maxWidth = hints->max_width;
77 maxHeight = hints->max_height;
78 }
79 else
80 {
81 maxWidth = 32767;
82 maxHeight = 32767;
83 }
84 if (hints->flags & PResizeInc)
85 {
86 xinc = hints->width_inc;
87 yinc = hints->height_inc;
88 }
89 else
90 {
91 xinc = 1;
92 yinc = 1;
93 }
94
95 /*
96 * First, clamp to min and max values
97 */
98 if (dwidth < minWidth)
99 {
100 dwidth = minWidth;
101 }
102 if (dheight < minHeight)
103 {
104 dheight = minHeight;
105 }
106
107 if (dwidth > maxWidth)
108 {
109 dwidth = maxWidth;
110 }
111 if (dheight > maxHeight)
112 {
113 dheight = maxHeight;
114 }
115
116
117 /*
118 * Second, fit to base + N * inc
119 */
120 dwidth = ((dwidth - baseWidth) / xinc * xinc) + baseWidth;
121 dheight = ((dheight - baseHeight) / yinc * yinc) + baseHeight;
122
123
124 /*
125 * Third, adjust for aspect ratio
126 */
127 #define maxAspectX hints->max_aspect.x
128 #define maxAspectY hints->max_aspect.y
129 #define minAspectX hints->min_aspect.x
130 #define minAspectY hints->min_aspect.y
131 /*
132 * The math looks like this:
133 *
134 * minAspectX dwidth maxAspectX
135 * ---------- <= ------- <= ----------
136 * minAspectY dheight maxAspectY
137 *
138 * If that is multiplied out, then the width and height are
139 * invalid in the following situations:
140 *
141 * minAspectX * dheight > minAspectY * dwidth
142 * maxAspectX * dheight < maxAspectY * dwidth
143 *
144 */
145
146 if (hints->flags & PAspect)
147 {
148 if (minAspectX * dheight > minAspectY * dwidth)
149 {
150 delta = makemult(
151 dheight - minAspectY * dwidth / minAspectX,
152 yinc);
153 if (dheight - delta >= minHeight)
154 {
155 dheight -= delta;
156 }
157 else
158 {
159 delta = makemult(
160 minAspectX * dheight / minAspectY -
161 dwidth, xinc);
162 if (dwidth + delta <= maxWidth)
163 {
164 dwidth += delta;
165 }
166 }
167 }
168
169 if (maxAspectX * dheight < maxAspectY * dwidth)
170 {
171 delta = makemult(
172 dwidth - maxAspectX * dheight / maxAspectY,
173 xinc);
174 if (dwidth - delta >= minWidth)
175 {
176 dwidth -= delta;
177 }
178 else
179 {
180 delta = makemult(
181 dwidth * maxAspectY / maxAspectX -
182 dheight, yinc);
183 if (dheight + delta <= maxHeight)
184 {
185 dheight += delta;
186 }
187 }
188 }
189 }
190
191 *widthp = dwidth;
192 *heightp = dheight;
193 return;
194 #undef makemult
195 #undef maxAspectX
196 #undef maxAspectY
197 #undef minAspectX
198 #undef minAspectY
199 }
200