]> git.decadent.org.uk Git - ion3.git/blob - ioncore/saveload.c
b179ccf9ca3926e5334f5090e990f368408d53b1
[ion3.git] / ioncore / saveload.c
1 /*
2  * ion/ioncore/saveload.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 <time.h>
14 #include <unistd.h>
15
16 #include <libtu/objp.h>
17 #include <libextl/readconfig.h>
18 #include <libextl/extl.h>
19
20 #include "common.h"
21 #include "global.h"
22 #include "region.h"
23 #include "screen.h"
24 #include "saveload.h"
25 #include "names.h"
26 #include "attach.h"
27 #include "reginfo.h"
28 #include "extlconv.h"
29 #include "group-ws.h"
30
31
32 static bool loading_layout=FALSE;
33 static bool layout_load_error=FALSE;
34
35
36 /*{{{ Session management module support */
37
38
39 static SMAddCallback *add_cb;
40 static SMCfgCallback *cfg_cb;
41 static SMPHolderCallback *ph_cb;
42 static bool clientwin_was_missing=FALSE;
43
44
45 void ioncore_set_sm_callbacks(SMAddCallback *add, SMCfgCallback *cfg)
46 {
47     add_cb=add;
48     cfg_cb=cfg;
49 }
50
51
52 void ioncore_get_sm_callbacks(SMAddCallback **add, SMCfgCallback **cfg)
53 {
54     *add=add_cb;
55     *cfg=cfg_cb;
56 }
57
58
59 void ioncore_set_sm_pholder_callback(SMPHolderCallback *phcb)
60 {
61     ph_cb=phcb;
62 }
63
64
65 void ioncore_clientwin_load_missing()
66 {
67     clientwin_was_missing=TRUE;
68 }
69
70
71 /*}}}*/
72
73
74 /*{{{ Load support functions */
75
76
77 WRegion *create_region_load(WWindow *par, const WFitParams *fp, 
78                             ExtlTab tab)
79 {
80     char *objclass=NULL, *name=NULL;
81     WRegionLoadCreateFn* fn=NULL;
82     WRegClassInfo *info=NULL;
83     WRegion *reg=NULL;
84     bool grouped=FALSE;
85     char *grouped_name=NULL;
86     
87     if(!extl_table_gets_s(tab, "type", &objclass))
88         return NULL;
89     
90     if(objclass==NULL)
91         return NULL;
92     
93     info=ioncore_lookup_regclass(objclass, FALSE);
94     if(info!=NULL)
95         fn=info->lc_fn;
96     
97     if(fn==NULL){
98         warn(TR("Unknown class \"%s\", cannot create region."),
99              objclass);
100         layout_load_error=loading_layout;
101         return NULL;
102     }
103
104     free(objclass);
105     
106     clientwin_was_missing=FALSE;
107     
108     reg=fn(par, fp, tab);
109     
110     if(reg==NULL){
111         if(clientwin_was_missing && add_cb!=NULL && ph_cb!=NULL){
112             WPHolder *ph=ph_cb();
113             if(ph!=NULL){
114                 if(!add_cb(ph, tab))
115                     destroy_obj((Obj*)ph);
116             }
117         }
118     }else{
119         if(!OBJ_IS(reg, WClientWin)){
120             if(extl_table_gets_s(tab, "name", &name)){
121                 region_set_name(reg, name);
122                 free(name);
123             }
124         }
125     }
126     
127     ph_cb=NULL;
128     
129     return reg;
130 }
131
132     
133 /*}}}*/
134
135
136 /*{{{ Save support functions */
137
138
139 bool region_supports_save(WRegion *reg)
140 {
141     return HAS_DYN(reg, region_get_configuration);
142 }
143
144
145 ExtlTab region_get_base_configuration(WRegion *reg)
146 {
147     const char *name;
148     ExtlTab tab;
149     
150     tab=extl_create_table();
151     
152     extl_table_sets_s(tab, "type", OBJ_TYPESTR(reg));
153     
154     name=region_name(reg);
155     
156     if(name!=NULL && !OBJ_IS(reg, WClientWin))
157         extl_table_sets_s(tab, "name", name);
158     
159     return tab;
160 }
161
162
163 static bool get_config_clientwins=TRUE;
164
165
166 ExtlTab region_get_configuration(WRegion *reg)
167 {
168     ExtlTab tab=extl_table_none();
169     if(get_config_clientwins || !OBJ_IS(reg, WClientWin)){
170         CALL_DYN_RET(tab, ExtlTab, region_get_configuration, reg, (reg));
171     }
172     return tab;
173 }
174
175
176 /*EXTL_DOC
177  * Get configuration tree. If \var{clientwins} is unset, client windows
178  * are filtered out.
179  */
180 EXTL_EXPORT_AS(WRegion, get_configuration)
181 ExtlTab region_get_configuration_extl(WRegion *reg, bool clientwins)
182 {
183     ExtlTab tab;
184     
185     get_config_clientwins=clientwins;
186     
187     tab=region_get_configuration(reg);
188     
189     get_config_clientwins=TRUE;
190     
191     return tab;
192 }
193
194
195 /*}}}*/
196
197
198 /*{{{ save_workspaces, load_workspaces */
199
200
201 static const char backup_msg[]=DUMMY_TR(
202 "There were errors loading layout. Backing up current layout savefile as\n"
203 "%s.\n"
204 "If you are _not_ running under a session manager and wish to restore your\n"
205 "old layout, copy this backup file over the layout savefile found in the\n"
206 "same directory while Ion is not running and after having fixed your other\n"
207 "configuration files that are causing this problem. (Maybe a missing\n"
208 "module?)");
209
210
211 bool ioncore_init_layout()
212 {
213     ExtlTab tab;
214     WScreen *scr;
215     bool ok;
216     int n=0;
217     
218     ok=extl_read_savefile("saved_layout", &tab);
219     
220     loading_layout=TRUE;
221     layout_load_error=FALSE;
222     
223     FOR_ALL_SCREENS(scr){
224         ExtlTab scrtab=extl_table_none();
225         bool scrok=FALSE;
226         
227         /* Potential Xinerama or such support should set the screen ID
228          * of the root window to less than zero, and number its own
229          * fake screens up from 0.
230          */
231         if(screen_id(scr)<0)
232             continue;
233
234         if(ok)
235             scrok=extl_table_geti_t(tab, screen_id(scr), &scrtab);
236         
237         n+=(TRUE==screen_init_layout(scr, scrtab));
238         
239         if(scrok)
240             extl_unref_table(scrtab);
241     }
242
243     loading_layout=FALSE;
244
245     if(layout_load_error){
246         time_t t=time(NULL);
247         char tm[]="saved_layout.backup-YYYYMMDDHHMMSS\0\0\0\0";
248         char *backup;
249         
250         strftime(tm+20, 15, "%Y%m%d%H%M%S", localtime(&t));
251         backup=extl_get_savefile(tm);
252         if(backup==NULL){
253             warn(TR("Unable to get file for layout backup."));
254             return FALSE;
255         }
256         if(access(backup, F_OK)==0){
257             warn(TR("Backup file %s already exists."), backup);
258             free(backup);
259             return FALSE;
260         }
261         warn(TR(backup_msg), backup);
262         if(!extl_serialise(backup, tab))
263             warn(TR("Failed backup."));
264         free(backup);
265     }
266         
267     if(n==0){
268         warn(TR("Unable to initialise layout on any screen."));
269         return FALSE;
270     }else{
271         return TRUE;
272     }
273 }
274
275
276 bool ioncore_save_layout()
277 {
278     WScreen *scr=NULL;
279     ExtlTab tab=extl_create_table();
280     bool ret;
281     
282     if(tab==extl_table_none())
283         return FALSE;
284     
285     FOR_ALL_SCREENS(scr){
286         ExtlTab scrtab;
287         
288         /* See note above */
289         if(screen_id(scr)<0)
290             continue;
291             
292         scrtab=region_get_configuration((WRegion*)scr);
293         
294         if(scrtab==extl_table_none()){
295             warn(TR("Unable to get configuration for screen %d."),
296                  screen_id(scr));
297         }else{
298             extl_table_seti_t(tab, screen_id(scr), scrtab);
299             extl_unref_table(scrtab);
300         }
301     }
302     
303     ret=extl_write_savefile("saved_layout", tab);
304     
305     extl_unref_table(tab);
306     
307     if(!ret)
308         warn(TR("Unable to save layout."));
309         
310     return ret;
311 }
312
313
314 /*}}}*/
315
316