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