2 * ion/ioncore/sizepolicy.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
6 * See the included file LICENSE for details.
9 #include <libtu/minmax.h>
16 #include "sizepolicy.h"
20 static int fit_x(int x
, int w
, const WRectangle
*max_geom
)
22 int mw
=maxof(max_geom
->w
, 1);
24 return minof(maxof(x
, max_geom
->x
), max_geom
->x
+mw
-w
);
28 static int fit_y(int y
, int h
, const WRectangle
*max_geom
)
30 int mh
=maxof(max_geom
->h
, 1);
32 return minof(maxof(y
, max_geom
->y
), max_geom
->y
+mh
-h
);
36 static void do_gravity(const WRectangle
*max_geom
, int szplcy
,
39 /* Assumed: width and height already adjusted within limits */
45 switch(szplcy
&SIZEPOLICY_HORIZ_MASK
){
46 case SIZEPOLICY_HORIZ_LEFT
:
50 case SIZEPOLICY_HORIZ_RIGHT
:
51 geom
->x
=max_geom
->x
+max_geom
->w
-geom
->w
;
54 case SIZEPOLICY_HORIZ_CENTER
:
55 geom
->x
=max_geom
->x
+max_geom
->w
/2-geom
->w
/2;
59 geom
->x
=fit_x(geom
->x
, geom
->w
, max_geom
);
62 switch(szplcy
&SIZEPOLICY_VERT_MASK
){
63 case SIZEPOLICY_VERT_TOP
:
67 case SIZEPOLICY_VERT_BOTTOM
:
68 geom
->y
=max_geom
->y
+max_geom
->h
-geom
->h
;
71 case SIZEPOLICY_VERT_CENTER
:
72 geom
->y
=max_geom
->y
+max_geom
->h
/2-geom
->h
/2;
76 geom
->y
=fit_x(geom
->y
, geom
->h
, max_geom
);
81 static void gravity_stretch_policy(int szplcy
, WRegion
*reg
,
82 const WRectangle
*rq_geom
, WFitParams
*fp
,
85 WRectangle max_geom
=fp
->g
;
90 w
=(ws
? max_geom
.w
: minof(rq_geom
->w
, max_geom
.w
));
91 h
=(hs
? max_geom
.h
: minof(rq_geom
->h
, max_geom
.h
));
94 region_size_hints_correct(reg
, &w
, &h
, FALSE
);
99 do_gravity(&max_geom
, szplcy
, &(fp
->g
));
103 static void sizepolicy_free_snap(WSizePolicy
*szplcy
, WRegion
*reg
,
104 WRectangle
*rq_geom
, int rq_flags
,
107 WRectangle max_geom
=fp
->g
;
108 bool fullw
=((rq_flags
®ION_RQGEOM_WEAK_W
) &&
109 (*szplcy
&SIZEPOLICY_HORIZ_MASK
)==SIZEPOLICY_HORIZ_CENTER
);
110 bool fullh
=((rq_flags
®ION_RQGEOM_WEAK_H
) &&
111 (*szplcy
&SIZEPOLICY_VERT_MASK
)==SIZEPOLICY_VERT_CENTER
);
113 int w
=(fullw
? max_geom
.w
: minof(rq_geom
->w
, max_geom
.w
));
114 int h
=(fullh
? max_geom
.h
: minof(rq_geom
->h
, max_geom
.h
));
117 /* ignore out-of-bound values for 'x' entirely */
118 if(!(rq_flags
®ION_RQGEOM_WEAK_X
) && rq_geom
->x
> max_geom
.w
){
119 rq_flags
|=REGION_RQGEOM_WEAK_X
;
120 rq_geom
->x
= reg
->geom
.x
;
123 /* ignore out-of-bound values for 'y' entirely */
124 if(!(rq_flags
®ION_RQGEOM_WEAK_Y
) && rq_geom
->y
> max_geom
.h
){
125 rq_flags
|=REGION_RQGEOM_WEAK_Y
;
126 rq_geom
->y
= reg
->geom
.y
;
129 if(!(rq_flags
®ION_RQGEOM_WEAK_X
)
130 && rq_flags
®ION_RQGEOM_WEAK_W
){
131 x_
=fit_x(rq_geom
->x
, 1, &max_geom
);
132 if(((*szplcy
)&SIZEPOLICY_HORIZ_MASK
)==SIZEPOLICY_HORIZ_RIGHT
)
133 w
=max_geom
.x
+max_geom
.w
-x_
;
135 w
=minof(w
, max_geom
.x
+max_geom
.w
-x_
);
138 if(!(rq_flags
®ION_RQGEOM_WEAK_Y
)
139 && rq_flags
®ION_RQGEOM_WEAK_H
){
140 y_
=fit_x(rq_geom
->y
, 1, &max_geom
);
141 if(((*szplcy
)&SIZEPOLICY_VERT_MASK
)==SIZEPOLICY_VERT_BOTTOM
)
142 h
=max_geom
.y
+max_geom
.h
-y_
;
144 h
=minof(h
, max_geom
.y
+max_geom
.h
-y_
);
148 region_size_hints_correct(reg
, &w
, &h
, FALSE
);
153 if(!(rq_flags
®ION_RQGEOM_WEAK_X
)
154 && rq_flags
®ION_RQGEOM_WEAK_W
){
156 }else if(rq_flags
®ION_RQGEOM_WEAK_X
){
157 switch((*szplcy
)&SIZEPOLICY_HORIZ_MASK
){
158 case SIZEPOLICY_HORIZ_CENTER
:
159 fp
->g
.x
=max_geom
.x
+(max_geom
.w
-w
)/2;
162 case SIZEPOLICY_HORIZ_LEFT
:
166 case SIZEPOLICY_HORIZ_RIGHT
:
167 fp
->g
.x
=max_geom
.x
+max_geom
.w
-w
;
171 fp
->g
.x
=fit_x(rq_geom
->x
, w
, &max_geom
);
175 fp
->g
.x
=fit_x(rq_geom
->x
, w
, &max_geom
);
178 if(!(rq_flags
®ION_RQGEOM_WEAK_Y
)
179 && rq_flags
®ION_RQGEOM_WEAK_H
){
181 }else if(rq_flags
®ION_RQGEOM_WEAK_Y
){
182 switch((*szplcy
)&SIZEPOLICY_VERT_MASK
){
183 case SIZEPOLICY_VERT_CENTER
:
184 fp
->g
.y
=max_geom
.y
+(max_geom
.h
-h
)/2;
187 case SIZEPOLICY_VERT_TOP
:
191 case SIZEPOLICY_VERT_BOTTOM
:
192 fp
->g
.y
=max_geom
.y
+max_geom
.h
-h
;
196 fp
->g
.y
=fit_y(rq_geom
->y
, h
, &max_geom
);
200 fp
->g
.y
=fit_y(rq_geom
->y
, h
, &max_geom
);
203 (*szplcy
)&=~(SIZEPOLICY_VERT_MASK
|SIZEPOLICY_HORIZ_MASK
);
205 *szplcy
|=( (fullw
|| fp
->g
.x
<=max_geom
.x
? SIZEPOLICY_HORIZ_LEFT
: 0)
206 |(fullw
|| fp
->g
.x
+fp
->g
.w
>=max_geom
.x
+max_geom
.w
? SIZEPOLICY_HORIZ_RIGHT
: 0)
207 |(fullh
|| fp
->g
.y
<=max_geom
.y
? SIZEPOLICY_VERT_TOP
: 0)
208 |(fullh
|| fp
->g
.y
+fp
->g
.h
>=max_geom
.y
+max_geom
.h
? SIZEPOLICY_VERT_BOTTOM
: 0));
212 static WSizePolicy
org(WSizePolicy base
, WSizePolicy g
)
214 if((base
&SIZEPOLICY_VERT_MASK
)==0)
215 base
|=g
&SIZEPOLICY_VERT_MASK
;
217 if((base
&SIZEPOLICY_HORIZ_MASK
)==0)
218 base
|=g
&SIZEPOLICY_HORIZ_MASK
;
224 void sizepolicy(WSizePolicy
*szplcy
, WRegion
*reg
,
225 const WRectangle
*rq_geom
, int rq_flags
,
228 uint extra
=fp
->mode
®ION_FIT_ROTATE
;
234 tmp
=REGION_GEOM(reg
);
238 if((*szplcy
)&SIZEPOLICY_SHRUNK
){
240 tmp
.w
=region_min_w(reg
);
241 tmp
.h
=region_min_h(reg
);
246 rq_flags
&=~(REGION_RQGEOM_WEAK_W
|REGION_RQGEOM_WEAK_H
);
249 fp
->mode
=REGION_FIT_EXACT
|extra
;
251 switch((*szplcy
)&SIZEPOLICY_MASK
){
252 case SIZEPOLICY_GRAVITY
:
253 gravity_stretch_policy(*szplcy
, reg
, &tmp
, fp
, FALSE
, FALSE
);
256 case SIZEPOLICY_STRETCH_LEFT
:
257 gravity_stretch_policy(org(*szplcy
, SIZEPOLICY_HORIZ_LEFT
|SIZEPOLICY_VERT_CENTER
),
258 reg
, &tmp
, fp
, FALSE
, TRUE
);
261 case SIZEPOLICY_STRETCH_RIGHT
:
262 gravity_stretch_policy(org(*szplcy
, SIZEPOLICY_HORIZ_RIGHT
|SIZEPOLICY_VERT_CENTER
),
263 reg
, &tmp
, fp
, FALSE
, TRUE
);
266 case SIZEPOLICY_STRETCH_TOP
:
267 gravity_stretch_policy(org(*szplcy
, SIZEPOLICY_VERT_TOP
|SIZEPOLICY_HORIZ_CENTER
),
268 reg
, &tmp
, fp
, TRUE
, FALSE
);
271 case SIZEPOLICY_STRETCH_BOTTOM
:
272 gravity_stretch_policy(org(*szplcy
, SIZEPOLICY_VERT_BOTTOM
|SIZEPOLICY_HORIZ_CENTER
),
273 reg
, &tmp
, fp
, TRUE
, FALSE
);
276 case SIZEPOLICY_FULL_EXACT
:
277 gravity_stretch_policy(org(*szplcy
, SIZEPOLICY_VERT_CENTER
|SIZEPOLICY_HORIZ_CENTER
),
278 reg
, &tmp
, fp
, TRUE
, TRUE
);
281 case SIZEPOLICY_FREE
:
283 region_size_hints_correct(reg
, &tmp
.w
, &tmp
.h
, FALSE
);
284 rectangle_constrain(&tmp
, &(fp
->g
));
288 case SIZEPOLICY_VISIBILITY_CONSTRAINED
:
290 region_size_hints_correct(reg
, &tmp
.w
, &tmp
.h
, FALSE
);
292 /* Constraint such that at least min(size, CF_VISIBILITY_CONSTRAINT)
293 * much is visible at each border.
295 int dx
=maxof(0, tmp
.w
-CF_VISIBILITY_CONSTRAINT
);
296 int dy
=maxof(0, tmp
.h
-CF_VISIBILITY_CONSTRAINT
);
297 tmp
.x
=maxof(fp
->g
.x
-dx
, minof(tmp
.x
, fp
->g
.x
+fp
->g
.w
+dx
-tmp
.w
));
298 tmp
.y
=maxof(fp
->g
.y
-dy
, minof(tmp
.y
, fp
->g
.y
+fp
->g
.h
+dy
-tmp
.h
));
303 case SIZEPOLICY_UNCONSTRAINED
:
305 region_size_hints_correct(reg
, &tmp
.w
, &tmp
.h
, TRUE
);
309 case SIZEPOLICY_FREE_GLUE
:
310 sizepolicy_free_snap(szplcy
, reg
, &tmp
, rq_flags
, fp
);
313 case SIZEPOLICY_FULL_BOUNDS
:
315 fp
->mode
=REGION_FIT_BOUNDS
|extra
;
321 /* translation table for sizepolicy specifications */
322 static StringIntMap szplcy_specs
[] = {
323 {"default", SIZEPOLICY_DEFAULT
},
324 {"full", SIZEPOLICY_FULL_EXACT
},
325 {"full_bounds", SIZEPOLICY_FULL_BOUNDS
},
326 {"free", SIZEPOLICY_FREE
},
327 {"free_glue", SIZEPOLICY_FREE_GLUE
},
328 {"northwest", SIZEPOLICY_GRAVITY_NORTHWEST
},
329 {"north", SIZEPOLICY_GRAVITY_NORTH
},
330 {"northeast", SIZEPOLICY_GRAVITY_NORTHEAST
},
331 {"west", SIZEPOLICY_GRAVITY_WEST
},
332 {"center", SIZEPOLICY_GRAVITY_CENTER
},
333 {"east", SIZEPOLICY_GRAVITY_EAST
},
334 {"southwest", SIZEPOLICY_GRAVITY_SOUTHWEST
},
335 {"south", SIZEPOLICY_GRAVITY_SOUTH
},
336 {"southeast", SIZEPOLICY_GRAVITY_SOUTHEAST
},
337 {"stretch_top", SIZEPOLICY_STRETCH_TOP
},
338 {"stretch_bottom", SIZEPOLICY_STRETCH_BOTTOM
},
339 {"stretch_left", SIZEPOLICY_STRETCH_LEFT
},
340 {"stretch_right", SIZEPOLICY_STRETCH_RIGHT
},
341 {"free_glue_northwest", SIZEPOLICY_FREE_GLUE__NORTHWEST
},
342 {"free_glue_north", SIZEPOLICY_FREE_GLUE__NORTH
},
343 {"free_glue_northeast", SIZEPOLICY_FREE_GLUE__NORTHEAST
},
344 {"free_glue_west", SIZEPOLICY_FREE_GLUE__WEST
},
345 {"free_glue_center", SIZEPOLICY_FREE_GLUE__CENTER
},
346 {"free_glue_east", SIZEPOLICY_FREE_GLUE__EAST
},
347 {"free_glue_southwest", SIZEPOLICY_FREE_GLUE__SOUTHWEST
},
348 {"free_glue_south", SIZEPOLICY_FREE_GLUE__SOUTH
},
349 {"free_glue_southeast", SIZEPOLICY_FREE_GLUE__SOUTHEAST
},
350 {"visibility_constrained", SIZEPOLICY_VISIBILITY_CONSTRAINED
},
351 {"unconstrained", SIZEPOLICY_UNCONSTRAINED
},
352 { NULL
, SIZEPOLICY_DEFAULT
} /* end marker */
356 bool string2sizepolicy(const char *szplcy
, WSizePolicy
*value
)
360 tmp
=stringintmap_value(szplcy_specs
, szplcy
, -1);
363 *value
=SIZEPOLICY_DEFAULT
;
372 const char *sizepolicy2string(WSizePolicy szplcy
)
374 const char* str
=stringintmap_key(szplcy_specs
, szplcy
, NULL
);
376 /* fall back on policy without modifiers if full name not found
378 * Without this, the scratchpad sometimes became impossible to resize
380 * http://lists.berlios.de/pipermail/ion-general/2009-December/001775.html
381 * http://article.gmane.org/gmane.comp.window-managers.ion.general/8897/match=scratchpad
383 str
=stringintmap_key(szplcy_specs
, szplcy
&0xff, NULL
);