]> git.decadent.org.uk Git - ion3.git/blob - mod_panews/panews.c
[svn-inject] Installing original source of ion3
[ion3.git] / mod_panews / panews.c
1 /*
2  * ion/mod_panews/panews.c
3  *
4  * Copyright (c) Tuomo Valkonen 1999-2006. 
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
14 #include <libtu/objp.h>
15 #include <libtu/minmax.h>
16 #include <libextl/extl.h>
17 #include <libmainloop/defer.h>
18
19 #include <ioncore/common.h>
20 #include <ioncore/global.h>
21 #include <ioncore/region.h>
22 #include <ioncore/focus.h>
23 #include <ioncore/manage.h>
24 #include <ioncore/saveload.h>
25 #include <ioncore/attach.h>
26 #include <ioncore/regbind.h>
27 #include <ioncore/extlconv.h>
28 #include <ioncore/frame.h>
29 #include <mod_tiling/tiling.h>
30 #include <mod_tiling/split.h>
31 #include "panews.h"
32 #include "placement.h"
33 #include "main.h"
34 #include "splitext.h"
35
36
37 /*{{{ Create/destroy */
38
39
40 bool panews_managed_add(WPaneWS *ws, WRegion *reg)
41 {
42     if(OBJ_IS(reg, WFrame))
43         region_add_bindmap(reg, mod_panews_frame_bindmap);
44     
45     return tiling_managed_add_default(&(ws->tiling), reg);
46 }
47
48
49 static WRegion *create_frame_panews(WWindow *parent, const WFitParams *fp)
50 {
51     return (WRegion*)create_frame(parent, fp, "frame-tiled-panews");
52 }
53
54
55 static bool mrsh_init_layout_extl(ExtlFn fn, WPaneWSInitParams *p)
56 {
57     ExtlTab t=extl_create_table();
58     bool ret=FALSE;
59     
60     extl_table_sets_o(t, "ws", (Obj*)p->ws);
61
62     extl_protect(NULL);
63     ret=extl_call(fn, "t", "b", t, &ret);
64     extl_unprotect(NULL);
65     
66     if(ret)
67         ret=extl_table_gets_t(t, "layout", &(p->layout));
68         
69     extl_unref_table(t);
70     return ret;
71 }
72
73
74 static bool panews_init_layout(WPaneWS *ws)
75 {
76     WPaneWSInitParams p;
77     
78     p.ws=ws;
79     p.layout=extl_table_none();
80         
81     hook_call_p(panews_init_layout_alt, &p,
82                 (WHookMarshallExtl*)mrsh_init_layout_extl);
83
84     if(p.layout!=extl_table_none()){            
85         ws->tiling.split_tree=tiling_load_node(&(ws->tiling),
86                                              &REGION_GEOM(ws), 
87                                              p.layout);
88         extl_unref_table(p.layout);
89     }
90          
91     if(ws->tiling.split_tree==NULL)
92         ws->tiling.split_tree=(WSplit*)create_splitunused(&REGION_GEOM(ws), ws);
93         
94     if(ws->tiling.split_tree!=NULL)
95         ws->tiling.split_tree->ws_if_root=&(ws->tiling);
96     
97     return (ws->tiling.split_tree!=NULL);
98 }
99
100
101 bool panews_init(WPaneWS *ws, WWindow *parent, const WFitParams *fp, 
102                  bool ilo)
103 {
104     if(!tiling_init(&(ws->tiling), parent, fp, 
105                    create_frame_panews, FALSE))
106         return FALSE;
107     
108     region_add_bindmap((WRegion*)ws, mod_panews_panews_bindmap);
109
110     assert(ws->tiling.split_tree==NULL);
111     
112     if(ilo){
113         if(!panews_init_layout(ws)){
114             panews_deinit(ws);
115             return FALSE;
116         }
117     }
118     
119     return TRUE;
120 }
121
122
123 WPaneWS *create_panews(WWindow *parent, const WFitParams *fp, bool cu)
124 {
125     CREATEOBJ_IMPL(WPaneWS, panews, (p, parent, fp, cu));
126 }
127
128
129 WPaneWS *create_panews_simple(WWindow *parent, const WFitParams *fp)
130 {
131     return create_panews(parent, fp, TRUE);
132 }
133
134
135 void panews_deinit(WPaneWS *ws)
136 {
137     tiling_deinit(&(ws->tiling));
138 }
139
140
141 static WSplitRegion *get_node_check(WPaneWS *ws, WRegion *reg)
142 {
143     WSplitRegion *node;
144
145     if(reg==NULL)
146         return NULL;
147     
148     node=splittree_node_of(reg);
149     
150     if(node==NULL || REGION_MANAGER(reg)!=(WRegion*)ws)
151         return NULL;
152     
153     return node;
154 }
155
156
157 static void panews_do_managed_remove(WPaneWS *ws, WRegion *reg)
158 {
159     tiling_do_managed_remove(&(ws->tiling), reg);
160     if(OBJ_IS(reg, WFrame))
161         region_remove_bindmap(reg, mod_panews_frame_bindmap);
162 }
163
164
165 static bool plainregionfilter(WSplit *node)
166 {
167     return (strcmp(OBJ_TYPESTR(node), "WSplitRegion")==0);
168 }
169
170
171
172 void panews_managed_remove(WPaneWS *ws, WRegion *reg)
173 {
174     bool ds=OBJ_IS_BEING_DESTROYED(ws);
175     bool act=REGION_IS_ACTIVE(reg);
176     bool mcf=region_may_control_focus((WRegion*)ws);
177     WSplitRegion *node=get_node_check(ws, reg);
178     WRegion *other=NULL;
179
180     other=tiling_do_get_nextto(&(ws->tiling), reg, SPLIT_ANY, PRIMN_ANY, FALSE);
181     
182     panews_do_managed_remove(ws, reg);
183
184     if(node==(WSplitRegion*)(ws->tiling.stdispnode))
185         ws->tiling.stdispnode=NULL;
186     
187     if(node==NULL)
188         return;
189     
190     splittree_remove((WSplit*)node, !ds);
191     
192     if(!ds){
193         if(other==NULL){
194             if(ws->tiling.split_tree==NULL){
195                 warn(TR("Unable to re-initialise workspace. Destroying."));
196                 mainloop_defer_destroy((Obj*)ws);
197             }else if(act && mcf){
198                 /* We don't want to give the stdisp focus, even if one exists. 
199                  * Or do we?
200                  */
201                 tiling_fallback_focus(&ws->tiling, FALSE);
202             }
203         }else if(act && mcf){
204             region_warp(other);
205         }
206     }
207 }
208
209
210 /*}}}*/
211
212
213 /*{{{ Misc. */
214
215
216 bool panews_managed_prepare_focus(WPaneWS *ws, WRegion *reg,
217                                   int flags, WPrepareFocusResult *res)
218 {
219     if(flags&REGION_GOTO_ENTERWINDOW){
220         WSplitRegion *other, *node=get_node_check(ws, reg);
221         if(node!=NULL && OBJ_IS(node, WSplitUnused)){
222             /* An unused region - do not focus unless there are no
223              * normal regions in its pane. 
224              */
225             other=split_tree_find_region_in_pane_of((WSplit*)node);
226             if(other!=NULL){
227                 tiling_managed_prepare_focus(&(ws->tiling), other->reg, 
228                                             flags&~REGION_GOTO_ENTERWINDOW, 
229                                             res);
230                 return FALSE;
231             }
232         }
233     }
234         
235     return tiling_managed_prepare_focus(&(ws->tiling), reg, flags, res);
236 }
237
238
239 static bool filter_no_stdisp_unused(WSplit *split)
240 {
241     return (OBJ_IS(split, WSplitRegion)
242             && !OBJ_IS(split, WSplitST)
243             && !OBJ_IS(split, WSplitUnused));
244 }
245
246
247 bool panews_managed_may_destroy(WPaneWS *ws, WRegion *reg)
248 {
249     if(region_manager_allows_destroying((WRegion*)ws))
250         return TRUE;
251     
252     if(tiling_do_get_nextto(&(ws->tiling), reg, 
253                            SPLIT_ANY, PRIMN_ANY, FALSE)==NULL){
254         return FALSE;
255     }
256     
257     return TRUE;
258 }
259
260
261 bool panews_may_destroy(WPaneWS *ws)
262 {
263     if(split_current_todir(ws->tiling.split_tree, SPLIT_ANY, PRIMN_ANY, 
264                            filter_no_stdisp_unused)!=NULL){
265         warn(TR("Refusing to close non-empty workspace."));
266         return FALSE;
267     }
268     
269     return TRUE;
270 }
271
272
273 /*
274 static WRegion *panews_rqclose_propagate(WPaneWS *ws, WRegion *sub)
275 {
276     WSplitRegion *node=NULL;
277     WRegion *reg=NULL;
278     
279     if(sub==NULL){
280         if(ws->tiling.split_tree!=NULL){
281             node=(WSplitRegion*)split_current_todir(ws->tiling.split_tree, 
282                                                     SPLIT_ANY, PRIMN_ANY, 
283                                                     filter_no_stdisp_unused);
284         }
285         if(node==NULL){
286             mainloop_defer_destroy((Obj*)ws);
287             return (WRegion*)ws;
288         }
289         if(node->reg==NULL)
290             return NULL;
291         sub=node->reg;
292     }else{
293         node=get_node_check(ws, sub);
294         if(node==NULL)
295             return NULL;
296     }
297     
298     
299     return (region_rqclose(sub) ? sub : NULL);
300 }
301 */
302
303
304 /*}}}*/
305
306
307 /*{{{ Save */
308
309
310 ExtlTab panews_get_configuration(WPaneWS *ws)
311 {
312     return tiling_get_configuration(&(ws->tiling));
313 }
314
315
316 /*}}}*/
317
318
319 /*{{{ Load */
320
321
322 static WSplit *load_splitunused(WPaneWS *ws, const WRectangle *geom, 
323                                 ExtlTab tab)
324 {
325     return (WSplit*)create_splitunused(geom, (WPaneWS*)ws);
326 }
327
328
329 static WSplit *load_splitpane(WPaneWS *ws, const WRectangle *geom, ExtlTab tab)
330 {
331     ExtlTab t;
332     WSplitPane *pane;
333     WSplit *cnt;
334
335     pane=create_splitpane(geom, NULL);
336     if(pane==NULL)
337         return NULL;
338     
339     if(extl_table_gets_t(tab, "contents", &t)){
340         cnt=tiling_load_node(&(ws->tiling), geom, t);
341         extl_unref_table(t);
342     }else{
343         cnt=load_splitunused(ws, geom, extl_table_none());
344     }
345     
346     if(cnt==NULL){
347         destroy_obj((Obj*)pane);
348         return NULL;
349     }
350     
351     pane->contents=cnt;
352     cnt->parent=&(pane->isplit);
353     
354     assert(pane->marker==NULL);
355     extl_table_gets_s(tab, "marker", &(pane->marker));
356
357     return (WSplit*)pane;
358 }
359
360
361 static WSplit *panews_load_node(WPaneWS *ws, const WRectangle *geom, 
362                                 ExtlTab tab)
363 {
364     char *s=NULL;
365     
366     if(!extl_table_gets_s(tab, "type", &s)){
367         WRegion *reg=NULL;
368         /* Shortcuts for templates.lua */
369         if(extl_table_gets_o(tab, "reg", (Obj**)&reg)){
370             if(OBJ_IS(reg, WRegion))
371                 return load_splitregion_doit(&(ws->tiling), geom, tab);
372         }else{
373             return load_splitunused(ws, geom, tab);
374         }
375     }else{
376         if(strcmp(s, "WSplitPane")==0)
377             return load_splitpane(ws, geom, tab);
378         else if(strcmp(s, "WSplitUnused")==0)
379             return load_splitunused(ws, geom, tab);
380     }
381
382     return tiling_load_node_default(&(ws->tiling), geom, tab);
383 }
384
385
386 WRegion *panews_load(WWindow *par, const WFitParams *fp, ExtlTab tab)
387 {
388     WPaneWS *ws;
389     ExtlTab treetab;
390
391     ws=create_panews(par, fp, FALSE);
392     
393     if(ws==NULL)
394         return NULL;
395  
396     if(extl_table_gets_t(tab, "split_tree", &treetab)){
397         ws->tiling.split_tree=tiling_load_node(&(ws->tiling), &REGION_GEOM(ws), 
398                                              treetab);
399         extl_unref_table(treetab);
400     }
401     
402     if(ws->tiling.split_tree==NULL){
403         if(!panews_init_layout(ws)){
404             destroy_obj((Obj*)ws);
405             return NULL;
406         }
407     }
408     
409     ws->tiling.split_tree->ws_if_root=ws;
410     split_restack(ws->tiling.split_tree, ws->tiling.dummywin, Above);
411     
412     return (WRegion*)ws;
413 }
414
415
416 /*}}}*/
417
418
419 /*{{{ Dynamic function table and class implementation */
420
421
422 static DynFunTab panews_dynfuntab[]={
423     {region_managed_remove, 
424      panews_managed_remove},
425
426     {(DynFun*)region_prepare_manage, 
427      (DynFun*)panews_prepare_manage},
428     
429     {(DynFun*)region_get_configuration,
430      (DynFun*)panews_get_configuration},
431
432     {(DynFun*)region_may_destroy,
433      (DynFun*)panews_may_destroy},
434
435     {(DynFun*)region_managed_may_destroy,
436      (DynFun*)panews_managed_may_destroy},
437
438     {(DynFun*)tiling_managed_add,
439      (DynFun*)panews_managed_add},
440     
441     {(DynFun*)tiling_load_node,
442      (DynFun*)panews_load_node},
443
444     {(DynFun*)tiling_do_get_nextto,
445      (DynFun*)panews_do_get_nextto},
446
447     {(DynFun*)tiling_do_get_farthest,
448      (DynFun*)panews_do_get_farthest},
449
450     {(DynFun*)region_managed_prepare_focus,
451      (DynFun*)panews_managed_prepare_focus},
452
453     /*
454     {(DynFun*)region_rqclose_propagate,
455      (DynFun*)panews_rqclose_propagate},*/
456     
457     END_DYNFUNTAB
458 };
459
460
461 EXTL_EXPORT
462 IMPLCLASS(WPaneWS, WTiling, panews_deinit, panews_dynfuntab);
463
464     
465 /*}}}*/
466