summaryrefslogtreecommitdiff
path: root/src/WindowState.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/WindowState.cc')
-rw-r--r--src/WindowState.cc266
1 files changed, 266 insertions, 0 deletions
diff --git a/src/WindowState.cc b/src/WindowState.cc
new file mode 100644
index 0000000..2f8fd4e
--- /dev/null
+++ b/src/WindowState.cc
@@ -0,0 +1,266 @@
1// WindowState.cc
2// Copyright (c) 2008 Fluxbox Team (fluxgen at fluxbox dot org)
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22#include "WindowState.hh"
23
24#include "FbTk/StringUtil.hh"
25
26#include <stdlib.h>
27
28bool WindowState::useBorder() const {
29 return !fullscreen && maximized != MAX_FULL && deco_mask & DECORM_BORDER;
30}
31
32bool WindowState::useHandle() const {
33 return !fullscreen && !shaded && deco_mask & DECORM_HANDLE;
34}
35
36bool WindowState::useTabs() const {
37 return !fullscreen && deco_mask & DECORM_TAB;
38}
39
40bool WindowState::useTitlebar() const {
41 return !fullscreen && deco_mask & DECORM_TITLEBAR;
42}
43
44void WindowState::saveGeometry(int new_x, int new_y,
45 unsigned int new_w, unsigned int new_h) {
46 if (fullscreen || maximized == MAX_FULL)
47 return;
48
49 if (!(maximized & MAX_HORZ)) {
50 x = new_x;
51 width = new_w;
52 }
53 if (!(maximized & MAX_VERT)) {
54 y = new_y;
55 if (!shaded)
56 height = new_h;
57 }
58}
59
60int WindowState::getDecoMaskFromString(const std::string &str_label) {
61 std::string label = FbTk::StringUtil::toLower(str_label);
62 if (label == "none")
63 return DECOR_NONE;
64 if (label == "normal")
65 return DECOR_NORMAL;
66 if (label == "tiny")
67 return DECOR_TINY;
68 if (label == "tool")
69 return DECOR_TOOL;
70 if (label == "border")
71 return DECOR_BORDER;
72 if (label == "tab")
73 return DECOR_TAB;
74 int mask = -1;
75 if ((str_label.size() > 1 && str_label[0] == '0' && str_label[1] == 'x') ||
76 (str_label.size() > 0 && isdigit(str_label[0])))
77 mask = strtol(str_label.c_str(), NULL, 0);
78 return mask;
79}
80
81void SizeHints::reset(const XSizeHints &sizehint) {
82 if (sizehint.flags & PMinSize) {
83 min_width = sizehint.min_width;
84 min_height = sizehint.min_height;
85 } else
86 min_width = min_height = 1;
87
88 if (sizehint.flags & PBaseSize) {
89 base_width = sizehint.base_width;
90 base_height = sizehint.base_height;
91 if (!(sizehint.flags & PMinSize)) {
92 min_width = base_width;
93 min_height = base_height;
94 }
95 } else
96 base_width = base_height = 0;
97
98 if (sizehint.flags & PMaxSize) {
99 max_width = sizehint.max_width;
100 max_height = sizehint.max_height;
101 } else
102 max_width = max_height = 0; // unbounded
103
104 if (sizehint.flags & PResizeInc) {
105 width_inc = sizehint.width_inc;
106 height_inc = sizehint.height_inc;
107 } else
108 width_inc = height_inc = 1;
109
110 if (sizehint.flags & PAspect) {
111 min_aspect_x = sizehint.min_aspect.x;
112 min_aspect_y = sizehint.min_aspect.y;
113 max_aspect_x = sizehint.max_aspect.x;
114 max_aspect_y = sizehint.max_aspect.y;
115 } else {
116 min_aspect_x = max_aspect_y = 0;
117 min_aspect_y = max_aspect_x = 1;
118 }
119
120 if (sizehint.flags & PWinGravity)
121 win_gravity = sizehint.win_gravity;
122 else
123 win_gravity = NorthWestGravity;
124
125 // some sanity checks
126 if (width_inc == 0)
127 width_inc = 1;
128 if (height_inc == 0)
129 height_inc = 1;
130
131 if (base_width > min_width)
132 min_width = base_width;
133 if (base_height > min_height)
134 min_height = base_height;
135}
136
137void closestPointToAspect(unsigned int &ret_x, unsigned int &ret_y,
138 unsigned int point_x, unsigned int point_y,
139 unsigned int aspect_x, unsigned int aspect_y) {
140 double u = static_cast<double>(point_x * aspect_x + point_y * aspect_y) /
141 static_cast<double>(aspect_x * aspect_x + aspect_y * aspect_y);
142
143 ret_x = static_cast<unsigned int>(u * aspect_x);
144 ret_y = static_cast<unsigned int>(u * aspect_y);
145}
146
147unsigned int increaseToMultiple(unsigned int val, unsigned int inc) {
148 return val % inc ? val + inc - (val % inc) : val;
149}
150
151unsigned int decreaseToMultiple(unsigned int val, unsigned int inc) {
152 return val % inc ? val - (val % inc) : val;
153}
154
155/**
156 * Changes width and height to the nearest (lower) value
157 * that conforms to it's size hints.
158 *
159 * display_* give the values that would be displayed
160 * to the user when resizing.
161 * We use pointers for display_* since they are optional.
162 *
163 * See ICCCM section 4.1.2.3
164 */
165void SizeHints::apply(unsigned int &width, unsigned int &height,
166 bool make_fit) const {
167
168 /* aspect ratios are applied exclusive to the base size
169 *
170 * min_aspect_x width max_aspect_x
171 * ------------ < ------- < ------------
172 * min_aspect_y height max_aspect_y
173 *
174 * The trick is how to get back to the aspect ratio with minimal
175 * change - do we modify x, y or both?
176 * A: we minimise the distance between the current point, and
177 * the target aspect ratio (consider them as x,y coordinates)
178 * Consider that the aspect ratio is a line, and the current
179 * w/h is a point, so we're just using the formula for
180 * shortest distance from a point to a line!
181 */
182
183 // make respective to base_size
184 unsigned int w = width - base_width, h = height - base_height;
185
186 if (min_aspect_y > 0 && w * min_aspect_y < min_aspect_x * h) {
187 closestPointToAspect(w, h, w, h, min_aspect_x, min_aspect_y);
188 // new w must be > old w, new h must be < old h
189 w = increaseToMultiple(w, width_inc);
190 h = decreaseToMultiple(h, height_inc);
191 } else if (max_aspect_x > 0 && w * max_aspect_y > max_aspect_x * h) {
192 closestPointToAspect(w, h, w, h, max_aspect_x, max_aspect_y);
193 // new w must be < old w, new h must be > old h
194 w = decreaseToMultiple(w, width_inc);
195 h = increaseToMultiple(h, height_inc);
196 }
197
198 // Check minimum size
199 if (w + base_width < min_width) {
200 w = increaseToMultiple(min_width - base_width, width_inc);
201 // need to check maximum aspect again
202 if (max_aspect_x > 0 && w * max_aspect_y > max_aspect_x * h)
203 h = increaseToMultiple(w * max_aspect_y / max_aspect_x, height_inc);
204 }
205
206 if (h + base_height < min_height) {
207 h = increaseToMultiple(min_height - base_height, height_inc);
208 // need to check minimum aspect again
209 if (min_aspect_y > 0 && w * min_aspect_y < min_aspect_x * h)
210 w = increaseToMultiple(h * min_aspect_x / min_aspect_y, width_inc);
211 }
212
213 unsigned int max_w = make_fit && (width < max_width || max_width == 0) ?
214 width : max_width;
215 unsigned int max_h = make_fit && (height < max_height || max_height == 0) ?
216 height : max_height;
217
218 // Check maximum size
219 if (max_w > 0 && w + base_width > max_w)
220 w = max_w - base_width;
221
222 if (max_h > 0 && h + base_height > max_h)
223 h = max_h - base_height;
224
225 w = decreaseToMultiple(w, width_inc);
226 h = decreaseToMultiple(h, height_inc);
227
228 // need to check aspects one more time
229 if (min_aspect_y > 0 && w * min_aspect_y < min_aspect_x * h)
230 h = decreaseToMultiple(w * min_aspect_y / min_aspect_x, height_inc);
231
232 if (max_aspect_x > 0 && w * max_aspect_y > max_aspect_x * h)
233 w = decreaseToMultiple(h * max_aspect_x / max_aspect_y, width_inc);
234
235 width = w + base_width;
236 height = h + base_height;
237}
238
239// check if the given width and height satisfy the size hints
240bool SizeHints::valid(unsigned int w, unsigned int h) const {
241 if (w < min_width || h < min_height)
242 return false;
243
244 if (w > max_width || h > max_height)
245 return false;
246
247 if ((w - base_width) % width_inc != 0)
248 return false;
249
250 if ((h - base_height) % height_inc != 0)
251 return false;
252
253 if (min_aspect_x * (h - base_height) > (w - base_width) * min_aspect_y)
254 return false;
255
256 if (max_aspect_x * (h - base_height) < (w - base_width) * max_aspect_y)
257 return false;
258
259 return true;
260}
261
262void SizeHints::displaySize(unsigned int &i, unsigned int &j,
263 unsigned int width, unsigned int height) const {
264 i = (width - base_width) / width_inc;
265 j = (height - base_height) / height_inc;
266}