]> git.decadent.org.uk Git - ion3.git/blob - ioncore/sizehint.c
ee5560f875270e38cef891f16f224c2c54df06c9
[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, wa;
74     int h=*hp, ha;
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     wa=w-hints->base_width;
89     ha=h-hints->base_height;
90     
91     if(wa>=0 && ha>=0){
92         correct_aspect(wa, ha, hints, &wa, &ha);
93         w=wa+hints->base_width;
94         h=ha+hints->base_height;
95     }
96     
97     if(hints->max_set){
98         w=minof(w, hints->max_width);
99         h=minof(h, hints->max_height);
100     }
101
102     if(hints->inc_set){
103         /* base size should be set to 0 if none given by user program */
104         bs=(hints->base_set ? hints->base_width : 0);
105         if(w>bs)
106             w=((w-bs)/hints->width_inc)*hints->width_inc+bs;
107         bs=(hints->base_set ? hints->base_height : 0);
108         if(h>bs)
109             h=((h-bs)/hints->height_inc)*hints->height_inc+bs;
110     }
111     
112     *wp=w;
113     *hp=h;
114 }
115
116
117 /*}}}*/
118
119
120 /*{{{ X size hints sanity adjustment */
121
122
123 void xsizehints_sanity_adjust(XSizeHints *hints)
124 {
125     if(!(hints->flags&PMinSize)){
126         if(hints->flags&PBaseSize){
127             hints->min_width=hints->base_width;
128             hints->min_height=hints->base_height;
129         }else{
130             hints->min_width=0;
131             hints->min_height=0;
132         }
133     }
134
135     if(hints->min_width<0)
136         hints->min_width=0;
137     if(hints->min_height<0)
138         hints->min_height=0;
139
140     if(!(hints->flags&PBaseSize) || hints->base_width<0)
141         hints->base_width=0;
142     if(!(hints->flags&PBaseSize) || hints->base_height<0)
143         hints->base_height=0;
144
145     
146     if(hints->flags&PMaxSize){
147         if(hints->max_width<hints->min_width)
148             hints->max_width=hints->min_width;
149         if(hints->max_height<hints->min_height)
150             hints->max_height=hints->min_height;
151     }
152     
153     hints->flags|=(PBaseSize|PMinSize);
154
155     if(hints->flags&PResizeInc){
156         if(hints->width_inc<=0 || hints->height_inc<=0){
157             warn(TR("Invalid client-supplied width/height increment."));
158             hints->flags&=~PResizeInc;
159         }
160     }
161     
162     if(hints->flags&PAspect){
163         if(hints->min_aspect.x<=0 || hints->min_aspect.y<=0 ||
164            hints->min_aspect.x<=0 || hints->min_aspect.y<=0){
165             warn(TR("Invalid client-supplied aspect-ratio."));
166             hints->flags&=~PAspect;
167         }
168     }
169     
170     if(!(hints->flags&PWinGravity))
171         hints->win_gravity=ForgetGravity;
172 }
173
174
175 /*}}}*/
176
177
178 /*{{{ xsizehints_adjust_for */
179
180
181 void sizehints_adjust_for(WSizeHints *hints, WRegion *reg)
182 {
183     WSizeHints tmp_hints;
184     
185     region_size_hints(reg, &tmp_hints);
186     
187     if(tmp_hints.min_set){
188         if(!hints->min_set){
189             hints->min_set=TRUE;
190             hints->min_width=tmp_hints.min_width;
191             hints->min_height=tmp_hints.min_height;
192         }else{
193             hints->min_width=maxof(hints->min_width,
194                                    tmp_hints.min_width);
195             hints->min_height=maxof(hints->min_height,
196                                     tmp_hints.min_height);
197         }
198     }
199     
200     if(tmp_hints.max_set && hints->max_set){
201         hints->max_width=maxof(hints->max_width,
202                                tmp_hints.max_width);
203         hints->max_height=maxof(hints->max_height,
204                                 tmp_hints.max_height);
205     }else{
206         hints->max_set=FALSE;
207     }
208 }
209
210
211 /*}}}*/
212
213
214 /*{{{ account_gravity */
215
216
217 int xgravity_deltax(int gravity, int left, int right)
218 {
219     int woff=left+right;
220
221     if(gravity==StaticGravity || gravity==ForgetGravity){
222         return -left;
223     }else if(gravity==NorthWestGravity || gravity==WestGravity ||
224              gravity==SouthWestGravity){
225         /* */
226     }else if(gravity==NorthEastGravity || gravity==EastGravity ||
227              gravity==SouthEastGravity){
228         /* geom->x=geom->w+geom->x-(geom->w+woff) */
229         return -woff;
230     }else if(gravity==CenterGravity || gravity==NorthGravity ||
231              gravity==SouthGravity){
232         /* geom->x=geom->x+geom->w/2-(geom->w+woff)/2 */
233         return -woff/2;
234     }
235     return 0;
236 }
237
238
239 int xgravity_deltay(int gravity, int top, int bottom)
240 {
241     int hoff=top+bottom;
242     
243     if(gravity==StaticGravity || gravity==ForgetGravity){
244         return -top;
245     }else if(gravity==NorthWestGravity || gravity==NorthGravity ||
246              gravity==NorthEastGravity){
247         /* */
248     }else if(gravity==SouthWestGravity || gravity==SouthGravity ||
249              gravity==SouthEastGravity){
250         /* geom->y=geom->y+geom->h-(geom->h+hoff) */
251         return -hoff;
252     }else if(gravity==CenterGravity || gravity==WestGravity ||
253              gravity==EastGravity){
254         /* geom->y=geom->y+geom->h/2-(geom->h+hoff)/2 */
255         return -hoff/2;
256     }
257     return 0;
258 }
259
260
261 void xgravity_translate(int gravity, WRegion *reg, WRectangle *geom)
262 {
263     int top=0, left=0, bottom=0, right=0;
264     WRootWin *root;
265
266     root=region_rootwin_of(reg);
267     region_rootpos(reg, &left, &top);
268     right=REGION_GEOM(root).w-left-REGION_GEOM(reg).w;
269     bottom=REGION_GEOM(root).h-top-REGION_GEOM(reg).h;
270
271     geom->x+=xgravity_deltax(gravity, left, right);
272     geom->y+=xgravity_deltay(gravity, top, bottom);
273 }
274
275
276 /*}}}*/
277
278
279 /*{{{ Init */
280
281
282 void xsizehints_to_sizehints(const XSizeHints *xh, WSizeHints *hints)
283 {
284     hints->max_width=xh->max_width;
285     hints->max_height=xh->max_height;
286     hints->min_width=xh->min_width;
287     hints->min_height=xh->min_height;
288     hints->base_width=xh->base_width;
289     hints->base_height=xh->base_height;
290     hints->width_inc=xh->width_inc;
291     hints->height_inc=xh->height_inc;
292     hints->min_aspect.x=xh->min_aspect.x;
293     hints->min_aspect.y=xh->min_aspect.y;
294     hints->max_aspect.x=xh->max_aspect.x;
295     hints->max_aspect.y=xh->max_aspect.y;
296     
297     hints->max_set=((xh->flags&PMaxSize)!=0);
298     hints->min_set=((xh->flags&PMinSize)!=0);
299     hints->base_set=((xh->flags&PBaseSize)!=0);
300     hints->inc_set=((xh->flags&PResizeInc)!=0);
301     hints->aspect_set=((xh->flags&PAspect)!=0);
302     hints->no_constrain=0;
303 }
304
305
306 void sizehints_clear(WSizeHints *hints)
307 {
308     hints->max_set=0;
309     hints->min_set=0;
310     hints->inc_set=0;
311     hints->base_set=0;
312     hints->aspect_set=0;
313     hints->no_constrain=0;
314 }
315
316
317 /*}}}*/