]> git.decadent.org.uk Git - ion3.git/blob - ioncore/sizehint.c
[svn-upgrade] Integrating new upstream version, ion3 (20070203)
[ion3.git] / ioncore / sizehint.c
1 /*
2  * ion/ioncore/sizehint.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2007. 
5  *
6  * Ion is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  */
11
12 #include <string.h>
13 #include <libtu/minmax.h>
14
15 #include "common.h"
16 #include "global.h"
17 #include "region.h"
18 #include "resize.h"
19 #include "sizehint.h"
20 #include "rootwin.h"
21
22
23 /*{{{ xsizehints_correct */
24
25
26 static void do_correct_aspect(int max_w, int max_h, int ax, int ay,
27                               int *wret, int *hret)
28 {
29     int w=*wret, h=*hret;
30
31     if(ax>ay){
32         h=(w*ay)/ax;
33         if(max_h>0 && h>max_h){
34             h=max_h;
35             w=(h*ax)/ay;
36         }
37     }else{
38         w=(h*ax)/ay;
39         if(max_w>0 && w>max_w){
40             w=max_w;
41             h=(w*ay)/ax;
42         }
43     }
44     
45     *wret=w;
46     *hret=h;
47 }
48
49
50 static void correct_aspect(int max_w, int max_h, const WSizeHints *hints,
51                            int *wret, int *hret)
52 {
53     if(!hints->aspect_set)
54         return;
55     
56     if(*wret*hints->max_aspect.y>*hret*hints->max_aspect.x){
57         do_correct_aspect(max_w, max_h,
58                           hints->min_aspect.x, hints->min_aspect.y,
59                           wret, hret);
60     }
61
62     if(*wret*hints->min_aspect.y<*hret*hints->min_aspect.x){
63         do_correct_aspect(max_w, max_h,
64                           hints->max_aspect.x, hints->max_aspect.y,
65                           wret, hret);
66     }
67 }
68
69
70 void sizehints_correct(const WSizeHints *hints, int *wp, int *hp, 
71                        bool min, bool override_no_constrain)
72 {
73     int w=*wp;
74     int h=*hp;
75     int bs=0;
76     
77     if(min){
78         w=maxof(w, hints->min_width);
79         h=maxof(h, hints->min_height);
80     }
81     
82     if(hints->no_constrain && !override_no_constrain){
83         *wp=w;
84         *hp=h;
85         return;
86     }
87
88     if(w>=hints->min_width && h>=hints->min_height)
89         correct_aspect(w, h, hints, &w, &h);
90     
91     if(hints->max_set){
92         w=minof(w, hints->max_width);
93         h=minof(h, hints->max_height);
94     }
95
96     if(hints->inc_set){
97         /* base size should be set to 0 if none given by user program */
98         bs=(hints->base_set ? hints->base_width : 0);
99         if(w>bs)
100             w=((w-bs)/hints->width_inc)*hints->width_inc+bs;
101         bs=(hints->base_set ? hints->base_height : 0);
102         if(h>bs)
103             h=((h-bs)/hints->height_inc)*hints->height_inc+bs;
104     }
105     
106     *wp=w;
107     *hp=h;
108 }
109
110
111 /*}}}*/
112
113
114 /*{{{ X size hints sanity adjustment */
115
116
117 void xsizehints_sanity_adjust(XSizeHints *hints)
118 {
119     if(!(hints->flags&PMinSize)){
120         if(hints->flags&PBaseSize){
121             hints->min_width=hints->base_width;
122             hints->min_height=hints->base_height;
123         }else{
124             hints->min_width=0;
125             hints->min_height=0;
126         }
127     }
128
129     if(hints->min_width<0)
130         hints->min_width=0;
131     if(hints->min_height<0)
132         hints->min_height=0;
133
134     if(!(hints->flags&PBaseSize) || hints->base_width<0)
135         hints->base_width=hints->min_width;
136     if(!(hints->flags&PBaseSize) || hints->base_height<0)
137         hints->base_height=hints->min_height;
138
139     
140     if(hints->flags&PMaxSize){
141         if(hints->max_width<hints->min_width)
142             hints->max_width=hints->min_width;
143         if(hints->max_height<hints->min_height)
144             hints->max_height=hints->min_height;
145     }
146     
147     hints->flags|=(PBaseSize|PMinSize);
148
149     if(hints->flags&PResizeInc){
150         if(hints->width_inc<=0 || hints->height_inc<=0){
151             warn(TR("Invalid client-supplied width/height increment."));
152             hints->flags&=~PResizeInc;
153         }
154     }
155     
156     if(hints->flags&PAspect){
157         if(hints->min_aspect.x<=0 || hints->min_aspect.y<=0 ||
158            hints->min_aspect.x<=0 || hints->min_aspect.y<=0){
159             warn(TR("Invalid client-supplied aspect-ratio."));
160             hints->flags&=~PAspect;
161         }
162     }
163     
164     if(!(hints->flags&PWinGravity))
165         hints->win_gravity=ForgetGravity;
166 }
167
168
169 /*}}}*/
170
171
172 /*{{{ xsizehints_adjust_for */
173
174
175 void sizehints_adjust_for(WSizeHints *hints, WRegion *reg)
176 {
177     WSizeHints tmp_hints;
178     
179     region_size_hints(reg, &tmp_hints);
180     
181     if(tmp_hints.min_set){
182         if(!hints->min_set){
183             hints->min_set=TRUE;
184             hints->min_width=tmp_hints.min_width;
185             hints->min_height=tmp_hints.min_height;
186         }else{
187             hints->min_width=maxof(hints->min_width,
188                                    tmp_hints.min_width);
189             hints->min_height=maxof(hints->min_height,
190                                     tmp_hints.min_height);
191         }
192     }
193     
194     if(tmp_hints.max_set && hints->max_set){
195         hints->max_width=maxof(hints->max_width,
196                                tmp_hints.max_width);
197         hints->max_height=maxof(hints->max_height,
198                                 tmp_hints.max_height);
199     }else{
200         hints->max_set=FALSE;
201     }
202 }
203
204
205 /*}}}*/
206
207
208 /*{{{ account_gravity */
209
210
211 int xgravity_deltax(int gravity, int left, int right)
212 {
213     int woff=left+right;
214
215     if(gravity==StaticGravity || gravity==ForgetGravity){
216         return -left;
217     }else if(gravity==NorthWestGravity || gravity==WestGravity ||
218              gravity==SouthWestGravity){
219         /* */
220     }else if(gravity==NorthEastGravity || gravity==EastGravity ||
221              gravity==SouthEastGravity){
222         /* geom->x=geom->w+geom->x-(geom->w+woff) */
223         return -woff;
224     }else if(gravity==CenterGravity || gravity==NorthGravity ||
225              gravity==SouthGravity){
226         /* geom->x=geom->x+geom->w/2-(geom->w+woff)/2 */
227         return -woff/2;
228     }
229     return 0;
230 }
231
232
233 int xgravity_deltay(int gravity, int top, int bottom)
234 {
235     int hoff=top+bottom;
236     
237     if(gravity==StaticGravity || gravity==ForgetGravity){
238         return -top;
239     }else if(gravity==NorthWestGravity || gravity==NorthGravity ||
240              gravity==NorthEastGravity){
241         /* */
242     }else if(gravity==SouthWestGravity || gravity==SouthGravity ||
243              gravity==SouthEastGravity){
244         /* geom->y=geom->y+geom->h-(geom->h+hoff) */
245         return -hoff;
246     }else if(gravity==CenterGravity || gravity==WestGravity ||
247              gravity==EastGravity){
248         /* geom->y=geom->y+geom->h/2-(geom->h+hoff)/2 */
249         return -hoff/2;
250     }
251     return 0;
252 }
253
254
255 void xgravity_translate(int gravity, WRegion *reg, WRectangle *geom)
256 {
257     int top=0, left=0, bottom=0, right=0;
258     WRootWin *root;
259
260     root=region_rootwin_of(reg);
261     region_rootpos(reg, &left, &top);
262     right=REGION_GEOM(root).w-left-REGION_GEOM(reg).w;
263     bottom=REGION_GEOM(root).h-top-REGION_GEOM(reg).h;
264
265     geom->x+=xgravity_deltax(gravity, left, right);
266     geom->y+=xgravity_deltay(gravity, top, bottom);
267 }
268
269
270 /*}}}*/
271
272
273 /*{{{ Init */
274
275
276 void xsizehints_to_sizehints(const XSizeHints *xh, WSizeHints *hints)
277 {
278     hints->max_width=xh->max_width;
279     hints->max_height=xh->max_height;
280     hints->min_width=xh->min_width;
281     hints->min_height=xh->min_height;
282     hints->base_width=xh->base_width;
283     hints->base_height=xh->base_height;
284     hints->width_inc=xh->width_inc;
285     hints->height_inc=xh->height_inc;
286     hints->min_aspect.x=xh->min_aspect.x;
287     hints->min_aspect.y=xh->min_aspect.y;
288     hints->max_aspect.x=xh->max_aspect.x;
289     hints->max_aspect.y=xh->max_aspect.y;
290     
291     hints->max_set=((xh->flags&PMaxSize)!=0);
292     hints->min_set=((xh->flags&PMinSize)!=0);
293     hints->base_set=((xh->flags&PBaseSize)!=0);
294     hints->inc_set=((xh->flags&PResizeInc)!=0);
295     hints->aspect_set=((xh->flags&PAspect)!=0);
296     hints->no_constrain=0;
297 }
298
299
300 void sizehints_clear(WSizeHints *hints)
301 {
302     hints->max_set=0;
303     hints->min_set=0;
304     hints->inc_set=0;
305     hints->base_set=0;
306     hints->aspect_set=0;
307     hints->no_constrain=0;
308 }
309
310
311 /*}}}*/