Updating to version 0.20.2
[wmaker-crm.git] / src / session.c
blob280d942efc35ebd8798856c8771740aac85327f1
1 /* session.c - session state handling
3 * Copyright (c) 1998 Dan Pascu
5 * Window Maker window manager
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 * USA.
23 #include "wconfig.h"
25 #include <X11/Xlib.h>
26 #include <X11/Xutil.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <unistd.h>
32 #include "WindowMaker.h"
33 #include "screen.h"
34 #include "window.h"
35 #include "session.h"
36 #include "wcore.h"
37 #include "framewin.h"
38 #include "workspace.h"
39 #include "funcs.h"
40 #include "properties.h"
41 #include "application.h"
42 #include "appicon.h"
44 #include "dock.h"
46 #include "list.h"
48 #include <proplist.h>
51 static proplist_t sApplications = NULL;
52 static proplist_t sCommand;
53 static proplist_t sName;
54 static proplist_t sHost;
55 static proplist_t sWorkspace;
56 static proplist_t sShaded;
57 static proplist_t sMiniaturized;
58 static proplist_t sHidden;
59 static proplist_t sGeometry;
61 static proplist_t sDock;
63 static proplist_t sYes, sNo;
66 static void
67 make_keys()
69 if (sApplications!=NULL)
70 return;
72 sApplications = PLMakeString("Applications");
73 sCommand = PLMakeString("Command");
74 sName = PLMakeString("Name");
75 sHost = PLMakeString("Host");
76 sWorkspace = PLMakeString("Workspace");
77 sShaded = PLMakeString("Shaded");
78 sMiniaturized = PLMakeString("Miniaturized");
79 sHidden = PLMakeString("Hidden");
80 sGeometry = PLMakeString("Geometry");
81 sDock = PLMakeString("Dock");
83 sYes = PLMakeString("Yes");
84 sNo = PLMakeString("No");
89 static int
90 getBool(proplist_t value)
92 char *val;
94 if (!PLIsString(value)) {
95 return 0;
97 if (!(val = PLGetString(value))) {
98 return 0;
101 if ((val[1]=='\0' && (val[0]=='y' || val[0]=='Y'))
102 || strcasecmp(val, "YES")==0) {
104 return 1;
105 } else if ((val[1]=='\0' && (val[0]=='n' || val[0]=='N'))
106 || strcasecmp(val, "NO")==0) {
107 return 0;
108 } else {
109 int i;
110 if (sscanf(val, "%i", &i)==1) {
111 return (i!=0);
112 } else {
113 wwarning(_("can't convert \"%s\" to boolean"), val);
114 return 0;
121 static proplist_t
122 makeWindowState(WWindow *wwin, WApplication *wapp)
124 WScreen *scr = wwin->screen_ptr;
125 Window win;
126 int argc;
127 char **argv;
128 char *class, *instance, *command=NULL, buffer[256];
129 proplist_t win_state, cmd, name, workspace;
130 proplist_t shaded, miniaturized, hidden, geometry;
131 proplist_t dock;
133 if (wwin->main_window!=None && wwin->main_window!=wwin->client_win)
134 win = wwin->main_window;
135 else
136 win = wwin->client_win;
138 if (XGetCommand(dpy, win, &argv, &argc) && argc>0) {
139 command = FlattenStringList(argv, argc);
140 XFreeStringList(argv);
142 if (!command)
143 return NULL;
145 if (PropGetWMClass(win, &class, &instance)) {
146 if (class && instance)
147 sprintf(buffer, "%s.%s", instance, class);
148 else if (instance)
149 sprintf(buffer, "%s", instance);
150 else if (class)
151 sprintf(buffer, ".%s", class);
152 else
153 sprintf(buffer, ".");
155 name = PLMakeString(buffer);
156 cmd = PLMakeString(command);
157 /*sprintf(buffer, "%d", wwin->frame->workspace+1);
158 workspace = PLMakeString(buffer);*/
159 workspace = PLMakeString(scr->workspaces[wwin->frame->workspace]->name);
160 shaded = wwin->flags.shaded ? sYes : sNo;
161 miniaturized = wwin->flags.miniaturized ? sYes : sNo;
162 hidden = wwin->flags.hidden ? sYes : sNo;
163 sprintf(buffer, "%ix%i+%i+%i", wwin->client.width, wwin->client.height,
164 wwin->frame_x, wwin->frame_y);
165 geometry = PLMakeString(buffer);
167 win_state = PLMakeDictionaryFromEntries(sName, name,
168 sCommand, cmd,
169 sWorkspace, workspace,
170 sShaded, shaded,
171 sMiniaturized, miniaturized,
172 sHidden, hidden,
173 sGeometry, geometry,
174 NULL);
176 PLRelease(name);
177 PLRelease(cmd);
178 PLRelease(workspace);
179 PLRelease(geometry);
180 if (wapp && wapp->app_icon && wapp->app_icon->dock) {
181 int i;
182 char *name;
183 if (wapp->app_icon->dock == scr->dock) {
184 name="Dock";
185 } else {
186 for(i=0; i<scr->workspace_count; i++)
187 if(scr->workspaces[i]->clip == wapp->app_icon->dock)
188 break;
189 assert( i < scr->workspace_count);
190 /*n = i+1;*/
191 name = scr->workspaces[i]->name;
193 dock = PLMakeString(name);
194 PLInsertDictionaryEntry(win_state, sDock, dock);
195 PLRelease(dock);
197 } else {
198 win_state = NULL;
201 if (instance) XFree(instance);
202 if (class) XFree(class);
203 if (command) free(command);
205 return win_state;
209 void
210 wSessionSaveState(WScreen *scr)
212 WWindow *wwin = scr->focused_window;
213 proplist_t win_info, wks;
214 proplist_t list=NULL;
215 LinkedList *wapp_list=NULL;
218 make_keys();
220 if (!scr->session_state) {
221 scr->session_state = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
222 if (!scr->session_state)
223 return;
226 list = PLMakeArrayFromElements(NULL);
228 while (wwin) {
229 WApplication *wapp=wApplicationOf(wwin->main_window);
231 if (wwin->transient_for==None && list_find(wapp_list, wapp)==NULL
232 && !wwin->window_flags.dont_save_session) {
233 /* A entry for this application was not yet saved. Save one. */
234 if ((win_info = makeWindowState(wwin, wapp))!=NULL) {
235 list = PLAppendArrayElement(list, win_info);
236 PLRelease(win_info);
237 /* If we were succesful in saving the info for this window
238 * add the application the window belongs to, to the
239 * application list, so no multiple entries for the same
240 * application are saved.
242 wapp_list = list_cons(wapp, wapp_list);
245 wwin = wwin->prev;
247 PLRemoveDictionaryEntry(scr->session_state, sApplications);
248 PLInsertDictionaryEntry(scr->session_state, sApplications, list);
249 PLRelease(list);
251 wks = PLMakeString(scr->workspaces[scr->current_workspace]->name);
252 PLInsertDictionaryEntry(scr->session_state, sWorkspace, wks);
253 PLRelease(wks);
255 list_free(wapp_list);
259 void
260 wSessionClearState(WScreen *scr)
262 make_keys();
264 if (!scr->session_state)
265 return;
267 PLRemoveDictionaryEntry(scr->session_state, sApplications);
268 PLRemoveDictionaryEntry(scr->session_state, sWorkspace);
272 static pid_t
273 execCommand(WScreen *scr, char *command, char *host)
275 pid_t pid;
276 char **argv;
277 int argc;
279 ParseCommand(command, &argv, &argc);
281 if (argv==NULL) {
282 return 0;
285 if ((pid=fork())==0) {
286 char **args;
287 int i;
289 SetupEnvironment(scr);
291 close(ConnectionNumber(dpy));
293 args = malloc(sizeof(char*)*(argc+1));
294 if (!args)
295 exit(111);
296 for (i=0; i<argc; i++) {
297 args[i] = argv[i];
299 args[argc] = NULL;
300 execvp(argv[0], args);
301 exit(111);
303 while (argc > 0)
304 free(argv[--argc]);
305 free(argv);
306 return pid;
310 static WSavedState*
311 getWindowState(WScreen *scr, proplist_t win_state)
313 WSavedState *state = wmalloc(sizeof(WSavedState));
314 proplist_t value;
315 char *tmp;
316 int i;
318 memset(state, 0, sizeof(WSavedState));
319 state->workspace = -1;
320 value = PLGetDictionaryEntry(win_state, sWorkspace);
321 if (value && PLIsString(value)) {
322 tmp = PLGetString(value);
323 if (sscanf(tmp, "%i", &state->workspace)!=1) {
324 state->workspace = -1;
325 for (i=0; i < scr->workspace_count; i++) {
326 if (strcmp(scr->workspaces[i]->name, tmp)==0) {
327 state->workspace = i;
328 break;
331 } else {
332 state->workspace--;
335 if ((value = PLGetDictionaryEntry(win_state, sShaded))!=NULL)
336 state->shaded = getBool(value);
337 if ((value = PLGetDictionaryEntry(win_state, sMiniaturized))!=NULL)
338 state->miniaturized = getBool(value);
339 if ((value = PLGetDictionaryEntry(win_state, sHidden))!=NULL)
340 state->hidden = getBool(value);
342 value = PLGetDictionaryEntry(win_state, sGeometry);
343 if (value && PLIsString(value)) {
344 if (sscanf(PLGetString(value), "%ix%i+%i+%i",
345 &state->w, &state->h, &state->x, &state->y)==4 &&
346 (state->w>0 && state->h>0)) {
347 state->use_geometry = 1;
348 } else if (sscanf(PLGetString(value), "%i,%i,%i,%i",
349 &state->x, &state->y, &state->w, &state->h)==4 &&
350 (state->w>0 && state->h>0)) {
351 /* TODO: remove redundant sscanf() in version 0.20.x */
352 state->use_geometry = 1;
357 return state;
361 #define SAME(x, y) (((x) && (y) && !strcmp((x), (y))) || (!(x) && !(y)))
364 void
365 wSessionRestoreState(WScreen *scr)
367 WSavedState *state;
368 char *instance, *class, *command, *host;
369 proplist_t win_info, apps, cmd, value;
370 pid_t pid;
371 int i, count;
372 WDock *dock;
373 WAppIcon *btn=NULL;
374 int j, n, found;
375 char *tmp;
377 make_keys();
379 if (!scr->session_state)
380 return;
382 PLSetStringCmpHook(NULL);
384 apps = PLGetDictionaryEntry(scr->session_state, sApplications);
385 if (!apps)
386 return;
388 count = PLGetNumberOfElements(apps);
389 if (count==0)
390 return;
392 for (i=0; i<count; i++) {
393 win_info = PLGetArrayElement(apps, i);
395 cmd = PLGetDictionaryEntry(win_info, sCommand);
396 if (!cmd || !PLIsString(cmd) || !(command = PLGetString(cmd))) {
397 continue;
400 value = PLGetDictionaryEntry(win_info, sName);
401 if (!value)
402 continue;
404 ParseWindowName(value, &instance, &class, "session");
405 if (!instance && !class)
406 continue;
408 value = PLGetDictionaryEntry(win_info, sHost);
409 if (value && PLIsString(value))
410 host = PLGetString(value);
411 else
412 host = NULL;
414 state = getWindowState(scr, win_info);
416 dock = NULL;
417 value = PLGetDictionaryEntry(win_info, sDock);
418 if (value && PLIsString(value) && (tmp = PLGetString(value))!=NULL) {
419 if (sscanf(tmp, "%i", &n)!=1) {
420 if (!strcasecmp(tmp, "DOCK")) {
421 dock = scr->dock;
422 } else {
423 for (j=0; j < scr->workspace_count; j++) {
424 if (strcmp(scr->workspaces[j]->name, tmp)==0) {
425 dock = scr->workspaces[j]->clip;
426 break;
430 } else {
431 if (n == 0) {
432 dock = scr->dock;
433 } else if (n>0 && n<=scr->workspace_count) {
434 dock = scr->workspaces[n-1]->clip;
439 found = 0;
440 if (dock!=NULL) {
441 for (j=0; j<dock->max_icons; j++) {
442 btn = dock->icon_array[j];
443 if (btn && SAME(instance, btn->wm_instance) &&
444 SAME(class, btn->wm_class) &&
445 SAME(command, btn->command)) {
446 found = 1;
447 break;
452 if (found) {
453 wDockLaunchWithState(dock, btn, state);
454 } else if ((pid = execCommand(scr, command, host)) > 0) {
455 wWindowAddSavedState(instance, class, command, pid, state);
456 } else {
457 free(state);
460 if (instance) free(instance);
461 if (class) free(class);
463 /* clean up */
464 PLSetStringCmpHook(StringCompareHook);
468 void
469 wSessionRestoreLastWorkspace(WScreen *scr)
471 proplist_t wks;
472 int w, i;
473 char *tmp;
475 make_keys();
477 if (!scr->session_state)
478 return;
480 PLSetStringCmpHook(NULL);
482 wks = PLGetDictionaryEntry(scr->session_state, sWorkspace);
483 if (!wks || !PLIsString(wks))
484 return;
486 tmp = PLGetString(wks);
488 /* clean up */
489 PLSetStringCmpHook(StringCompareHook);
491 if (sscanf(tmp, "%i", &w)!=1) {
492 w = -1;
493 for (i=0; i < scr->workspace_count; i++) {
494 if (strcmp(scr->workspaces[i]->name, tmp)==0) {
495 w = i;
496 break;
499 } else {
500 w--;
503 if (w!=scr->current_workspace && w<scr->workspace_count) {
504 wWorkspaceChange(scr, w);