2 * ion/ioncore/group-ws.c
4 * Copyright (c) Tuomo Valkonen 1999-2006.
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.
14 #include <libtu/minmax.h>
15 #include <libtu/objp.h>
27 #include "grouppholder.h"
28 #include "groupedpholder.h"
29 #include "framedpholder.h"
30 #include "float-placement.h"
37 static bool default_ws_params_set=FALSE;
38 static ExtlTab default_ws_params;
42 * Set module basic settings. Currently only the \code{placement_method}
43 * parameter is supported.
45 * The method can be one of ''udlr'', ''lrud'' (default) and ''random''.
46 * The ''udlr'' method looks for free space starting from top the top left
47 * corner of the workspace moving first down keeping the x coordinate fixed.
48 * If it find no free space, it start looking similarly at next x coordinate
49 * unoccupied by other objects and so on. ''lrud' is the same but with the
50 * role of coordinates changed and both fall back to ''random'' placement
51 * if no free area was found.
54 void ioncore_groupws_set(ExtlTab tab)
59 if(extl_table_gets_s(tab, "float_placement_method", &method)){
60 if(strcmp(method, "udlr")==0)
61 ioncore_placement_method=PLACEMENT_UDLR;
62 else if(strcmp(method, "lrud")==0)
63 ioncore_placement_method=PLACEMENT_LRUD;
64 else if(strcmp(method, "random")==0)
65 ioncore_placement_method=PLACEMENT_RANDOM;
67 warn(TR("Unknown placement method \"%s\"."), method);
71 if(extl_table_gets_t(tab, "default_ws_params", &t)){
72 if(default_ws_params_set)
73 extl_unref_table(default_ws_params);
75 default_ws_params_set=TRUE;
80 void ioncore_groupws_get(ExtlTab t)
82 extl_table_sets_s(t, "float_placement_method",
83 (ioncore_placement_method==PLACEMENT_UDLR
85 : (ioncore_placement_method==PLACEMENT_LRUD
89 if(default_ws_params_set)
90 extl_table_sets_t(t, "default_ws_params", default_ws_params);
100 static bool groupws_attach_framed(WGroupWS *ws,
101 WGroupAttachParams *ap,
105 WRegionAttachData data;
107 data.type=REGION_ATTACH_REPARENT;
110 return (region_attach_framed((WRegion*)ws, fp,
111 (WRegionAttachFn*)group_do_attach,
116 bool groupws_handle_drop(WGroupWS *ws, int x, int y,
119 WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
120 WFramedParam fp=FRAMEDPARAM_INIT;
122 ap.switchto_set=TRUE;
125 fp.inner_geom_gravity_set=TRUE;
128 fp.inner_geom.w=REGION_GEOM(dropped).w;
129 fp.inner_geom.h=REGION_GEOM(dropped).h;
130 fp.gravity=NorthWestGravity;
132 return groupws_attach_framed(ws, &ap, &fp, dropped);
137 * Attach region \var{reg} on \var{ws}.
138 * At least the following fields in \var{t} are supported:
140 * \begin{tabularx}{\linewidth}{lX}
141 * \tabhead{Field & Description}
142 * \var{switchto} & Should the region be switched to (boolean)? Optional. \\
143 * \var{geom} & Geometry; \var{x} and \var{y}, if set, indicates top-left of
144 * the frame to be created while \var{width} and \var{height}, if set, indicate
145 * the size of the client window within that frame. Optional.
148 EXTL_EXPORT_AS(WGroupWS, attach_framed)
149 bool groupws_attach_framed_extl(WGroupWS *ws, WRegion *reg, ExtlTab t)
151 WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
152 WFramedParam fp=FRAMEDPARAM_INIT;
158 fp.gravity=ForgetGravity;
160 if(extl_table_is_bool_set(t, "switchto")){
161 ap.switchto_set=TRUE;
165 if(extl_table_gets_t(t, "geom", >)){
171 if(extl_table_gets_i(gt, "x", &(ap.geom.x)))
173 if(extl_table_gets_i(gt, "y", &(ap.geom.y)))
176 if(extl_table_gets_i(gt, "w", &(ap.geom.w)))
178 if(extl_table_gets_i(gt, "h", &(ap.geom.h)))
181 fp.inner_geom.w=maxof(fp.inner_geom.w, 1);
182 fp.inner_geom.h=maxof(fp.inner_geom.h, 1);
184 fp.inner_geom_gravity_set=(size==2 && pos==2);
186 extl_unref_table(gt);
189 return groupws_attach_framed(ws, &ap, &fp, reg);
196 /*{{{ groupws_prepare_manage */
199 #define REG_OK(R) OBJ_IS(R, WMPlex)
202 static WMPlex *find_existing(WGroupWS *ws)
205 WRegion *r=(ws->grp.current_managed!=NULL
206 ? ws->grp.current_managed->reg
209 if(r!=NULL && REG_OK(r))
212 FOR_ALL_MANAGED_BY_GROUP(&ws->grp, r, tmp){
221 static WPHolder *groupws_do_prepare_manage(WGroupWS *ws,
222 const WClientWin *cwin,
223 const WManageParams *param,
224 int redir, int geom_weak)
226 WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
227 WFramedParam fp=FRAMEDPARAM_INIT;
230 if(redir==MANAGE_REDIR_PREFER_YES){
231 WMPlex *m=find_existing(ws);
234 ph=region_prepare_manage((WRegion*)m, cwin, param,
235 MANAGE_REDIR_STRICT_YES);
241 if(redir==MANAGE_REDIR_STRICT_YES)
244 fp.inner_geom_gravity_set=TRUE;
245 fp.inner_geom=param->geom;
246 fp.gravity=param->gravity;
249 ap.geom_weak=geom_weak;
251 ph=(WPHolder*)create_grouppholder(&ws->grp, NULL, &ap);
254 ph=pholder_either((WPHolder*)create_framedpholder(ph, &fp), ph);
257 ph=pholder_either((WPHolder*)create_groupedpholder((WPHolder*)ph), ph);
263 WPHolder *groupws_prepare_manage(WGroupWS *ws, const WClientWin *cwin,
264 const WManageParams *param,
267 WRegion *b=(ws->grp.bottom!=NULL ? ws->grp.bottom->reg : NULL);
269 bool act_b=(ws->grp.bottom==ws->grp.current_managed);
270 bool always_float, use_bottom;
273 if(param->maprq && ioncore_g.opmode!=IONCORE_OPMODE_INIT
275 /* When the window is mapped by application request, position
276 * request is only honoured if the position was given by the user
277 * and in case of a transient (the app may know better where to
278 * place them) or if we're initialising.
280 weak=REGION_RQGEOM_WEAK_X|REGION_RQGEOM_WEAK_Y;
283 if(b!=NULL && !HAS_DYN(b, region_prepare_manage))
287 ? !extl_table_is_bool_set(cwin->proptab, "float")
290 if(b!=NULL && use_bottom)
291 ph=region_prepare_manage(b, cwin, param, redir);
294 ph=groupws_do_prepare_manage(ws, cwin, param, redir, weak);
296 if(ph==NULL && b!=NULL && !use_bottom)
297 ph=region_prepare_manage(b, cwin, param, redir);
303 WPHolder *groupws_prepare_manage_transient(WGroupWS *ws, const WClientWin *cwin,
304 const WManageParams *param,
307 WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
308 WFramedParam fp=FRAMEDPARAM_INIT;
311 ap.stack_above=OBJ_CAST(REGION_PARENT(param->tfor), WRegion);
312 if(ap.stack_above==NULL)
315 fp.inner_geom_gravity_set=TRUE;
316 fp.inner_geom=param->geom;
317 fp.gravity=param->gravity;
318 fp.mkframe=create_transient_frame;
323 ph=(WPHolder*)create_grouppholder(&ws->grp, NULL, &ap);
325 return pholder_either((WPHolder*)create_framedpholder(ph, &fp), ph);
329 WPHolder *groupws_get_rescue_pholder_for(WGroupWS *ws,
332 WGroupAttachParams ap=GROUPATTACHPARAMS_INIT;
333 WFramedParam fp=FRAMEDPARAM_INIT;
337 ap.geom=REGION_GEOM(forwhat);
340 ap.geom_weak=(REGION_PARENT(forwhat)!=REGION_PARENT(ws)
341 ? REGION_RQGEOM_WEAK_X|REGION_RQGEOM_WEAK_Y
344 ph=(WPHolder*)create_grouppholder(&ws->grp, NULL, &ap);
346 return pholder_either((WPHolder*)create_framedpholder(ph, &fp), ph);
353 /*{{{ WGroupWS class */
356 bool groupws_init(WGroupWS *ws, WWindow *parent, const WFitParams *fp)
358 if(!group_init(&(ws->grp), parent, fp))
361 ((WRegion*)ws)->flags|=REGION_GRAB_ON_PARENT;
363 region_add_bindmap((WRegion*)ws, ioncore_groupws_bindmap);
369 WGroupWS *create_groupws(WWindow *parent, const WFitParams *fp)
371 CREATEOBJ_IMPL(WGroupWS, groupws, (p, parent, fp));
375 void groupws_deinit(WGroupWS *ws)
377 group_deinit(&(ws->grp));
381 WRegion *groupws_load(WWindow *par, const WFitParams *fp,
386 ws=create_groupws(par, fp);
391 group_do_load(&ws->grp, tab);
397 WRegion *groupws_load_default(WWindow *par, const WFitParams *fp)
399 return groupws_load(par, fp, (default_ws_params_set
401 : extl_table_none()));
405 static DynFunTab groupws_dynfuntab[]={
406 {(DynFun*)region_prepare_manage,
407 (DynFun*)groupws_prepare_manage},
409 {(DynFun*)region_prepare_manage_transient,
410 (DynFun*)groupws_prepare_manage_transient},
412 {(DynFun*)region_handle_drop,
413 (DynFun*)groupws_handle_drop},
415 {(DynFun*)region_get_rescue_pholder_for,
416 (DynFun*)groupws_get_rescue_pholder_for},
418 {region_manage_stdisp,
419 group_manage_stdisp},
426 IMPLCLASS(WGroupWS, WGroup, groupws_deinit, groupws_dynfuntab);