Fix some warnings
[wmaker-crm.git] / src / session.c
blob5d72ef1d5dc8984682cbbdf14beba776c415f9fb
1 /* session.c - session state handling and R6 style session management
3 * Copyright (c) 1998-2003 Dan Pascu
4 * Copyright (c) 1998-2003 Alfredo Kojima
6 * Window Maker window manager
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * If defined(XSMP_ENABLED) and session manager is running then
26 * do normal stuff
27 * else
28 * do pre-R6 session management stuff (save window state and relaunch)
30 * When doing a checkpoint:
32 * = Without XSMP
33 * Open "Stop"/status Dialog
34 * Send SAVE_YOURSELF to clients and wait for reply
35 * Save restart info
36 * Save state of clients
38 * = With XSMP
39 * Send checkpoint request to sm
41 * When exiting:
42 * -------------
44 * = Without XSMP
46 * Open "Exit Now"/status Dialog
47 * Send SAVE_YOURSELF to clients and wait for reply
48 * Save restart info
49 * Save state of clients
50 * Send DELETE to all clients
51 * When no more clients are left or user hit "Exit Now", exit
53 * = With XSMP
55 * Send Shutdown request to session manager
56 * if SaveYourself message received, save state of clients
57 * if the Die message is received, exit.
60 #include "wconfig.h"
62 #include <X11/Xlib.h>
63 #include <X11/Xutil.h>
65 #include <stdlib.h>
66 #include <stdio.h>
67 #include <string.h>
68 #include <unistd.h>
69 #include <time.h>
71 #include "WindowMaker.h"
72 #include "screen.h"
73 #include "window.h"
74 #include "client.h"
75 #include "session.h"
76 #include "framewin.h"
77 #include "workspace.h"
78 #include "funcs.h"
79 #include "properties.h"
80 #include "application.h"
81 #include "appicon.h"
82 #include "dock.h"
84 #include <WINGs/WUtil.h>
86 /** Global **/
88 extern Atom _XA_WM_SAVE_YOURSELF;
90 extern Time LastTimestamp;
92 static WMPropList *sApplications = NULL;
93 static WMPropList *sCommand;
94 static WMPropList *sName;
95 static WMPropList *sHost;
96 static WMPropList *sWorkspace;
97 static WMPropList *sShaded;
98 static WMPropList *sMiniaturized;
99 static WMPropList *sHidden;
100 static WMPropList *sGeometry;
101 static WMPropList *sShortcutMask;
103 static WMPropList *sDock;
104 static WMPropList *sYes, *sNo;
106 static void make_keys(void)
108 if (sApplications != NULL)
109 return;
111 sApplications = WMCreatePLString("Applications");
112 sCommand = WMCreatePLString("Command");
113 sName = WMCreatePLString("Name");
114 sHost = WMCreatePLString("Host");
115 sWorkspace = WMCreatePLString("Workspace");
116 sShaded = WMCreatePLString("Shaded");
117 sMiniaturized = WMCreatePLString("Miniaturized");
118 sHidden = WMCreatePLString("Hidden");
119 sGeometry = WMCreatePLString("Geometry");
120 sDock = WMCreatePLString("Dock");
121 sShortcutMask = WMCreatePLString("ShortcutMask");
123 sYes = WMCreatePLString("Yes");
124 sNo = WMCreatePLString("No");
127 static int getBool(WMPropList * value)
129 char *val;
131 if (!WMIsPLString(value)) {
132 return 0;
134 if (!(val = WMGetFromPLString(value))) {
135 return 0;
138 if ((val[1] == '\0' && (val[0] == 'y' || val[0] == 'Y'))
139 || strcasecmp(val, "YES") == 0) {
141 return 1;
142 } else if ((val[1] == '\0' && (val[0] == 'n' || val[0] == 'N'))
143 || strcasecmp(val, "NO") == 0) {
144 return 0;
145 } else {
146 int i;
147 if (sscanf(val, "%i", &i) == 1) {
148 return (i != 0);
149 } else {
150 wwarning(_("can't convert \"%s\" to boolean"), val);
151 return 0;
156 static unsigned getInt(WMPropList * value)
158 char *val;
159 unsigned n;
161 if (!WMIsPLString(value))
162 return 0;
163 val = WMGetFromPLString(value);
164 if (!val)
165 return 0;
166 if (sscanf(val, "%u", &n) != 1)
167 return 0;
169 return n;
172 static WMPropList *makeWindowState(WWindow * wwin, WApplication * wapp)
174 WScreen *scr = wwin->screen_ptr;
175 Window win;
176 int i;
177 unsigned mask;
178 char *class, *instance, *command = NULL, buffer[512];
179 WMPropList *win_state, *cmd, *name, *workspace;
180 WMPropList *shaded, *miniaturized, *hidden, *geometry;
181 WMPropList *dock, *shortcut;
183 if (wwin->orig_main_window != None && wwin->orig_main_window != wwin->client_win)
184 win = wwin->orig_main_window;
185 else
186 win = wwin->client_win;
188 command = GetCommandForWindow(win);
189 if (!command)
190 return NULL;
192 if (PropGetWMClass(win, &class, &instance)) {
193 if (class && instance)
194 snprintf(buffer, sizeof(buffer), "%s.%s", instance, class);
195 else if (instance)
196 snprintf(buffer, sizeof(buffer), "%s", instance);
197 else if (class)
198 snprintf(buffer, sizeof(buffer), ".%s", class);
199 else
200 snprintf(buffer, sizeof(buffer), ".");
202 name = WMCreatePLString(buffer);
203 cmd = WMCreatePLString(command);
204 /*sprintf(buffer, "%d", wwin->frame->workspace+1);
205 workspace = WMCreatePLString(buffer); */
206 workspace = WMCreatePLString(scr->workspaces[wwin->frame->workspace]->name);
207 shaded = wwin->flags.shaded ? sYes : sNo;
208 miniaturized = wwin->flags.miniaturized ? sYes : sNo;
209 hidden = wwin->flags.hidden ? sYes : sNo;
210 snprintf(buffer, sizeof(buffer), "%ix%i+%i+%i",
211 wwin->client.width, wwin->client.height, wwin->frame_x, wwin->frame_y);
212 geometry = WMCreatePLString(buffer);
214 for (mask = 0, i = 0; i < MAX_WINDOW_SHORTCUTS; i++) {
215 if (scr->shortcutWindows[i] != NULL &&
216 WMGetFirstInArray(scr->shortcutWindows[i], wwin) != WANotFound) {
217 mask |= 1 << i;
221 snprintf(buffer, sizeof(buffer), "%u", mask);
222 shortcut = WMCreatePLString(buffer);
224 win_state = WMCreatePLDictionary(sName, name,
225 sCommand, cmd,
226 sWorkspace, workspace,
227 sShaded, shaded,
228 sMiniaturized, miniaturized,
229 sHidden, hidden,
230 sShortcutMask, shortcut, sGeometry, geometry, NULL);
232 WMReleasePropList(name);
233 WMReleasePropList(cmd);
234 WMReleasePropList(workspace);
235 WMReleasePropList(geometry);
236 WMReleasePropList(shortcut);
237 if (wapp && wapp->app_icon && wapp->app_icon->dock) {
238 int i;
239 char *name;
240 if (wapp->app_icon->dock == scr->dock) {
241 name = "Dock";
242 } else {
243 for (i = 0; i < scr->workspace_count; i++)
244 if (scr->workspaces[i]->clip == wapp->app_icon->dock)
245 break;
246 assert(i < scr->workspace_count);
247 /*n = i+1; */
248 name = scr->workspaces[i]->name;
250 dock = WMCreatePLString(name);
251 WMPutInPLDictionary(win_state, sDock, dock);
252 WMReleasePropList(dock);
254 } else {
255 win_state = NULL;
258 if (instance)
259 XFree(instance);
260 if (class)
261 XFree(class);
262 if (command)
263 wfree(command);
265 return win_state;
268 void wSessionSaveState(WScreen * scr)
270 WWindow *wwin = scr->focused_window;
271 WMPropList *win_info, *wks;
272 WMPropList *list = NULL;
273 WMArray *wapp_list = NULL;
275 make_keys();
277 if (!scr->session_state) {
278 scr->session_state = WMCreatePLDictionary(NULL, NULL);
279 if (!scr->session_state)
280 return;
283 list = WMCreatePLArray(NULL);
285 wapp_list = WMCreateArray(16);
287 while (wwin) {
288 WApplication *wapp = wApplicationOf(wwin->main_window);
289 Window appId = wwin->orig_main_window;
291 if ((wwin->transient_for == None || wwin->transient_for == wwin->screen_ptr->root_win)
292 && (WMGetFirstInArray(wapp_list, (void *)appId) == WANotFound
293 || WFLAGP(wwin, shared_appicon))
294 && !WFLAGP(wwin, dont_save_session)) {
295 /* A entry for this application was not yet saved. Save one. */
296 if ((win_info = makeWindowState(wwin, wapp)) != NULL) {
297 WMAddToPLArray(list, win_info);
298 WMReleasePropList(win_info);
299 /* If we were succesful in saving the info for this window
300 * add the application the window belongs to, to the
301 * application list, so no multiple entries for the same
302 * application are saved.
304 WMAddToArray(wapp_list, (void *)appId);
307 wwin = wwin->prev;
309 WMRemoveFromPLDictionary(scr->session_state, sApplications);
310 WMPutInPLDictionary(scr->session_state, sApplications, list);
311 WMReleasePropList(list);
313 wks = WMCreatePLString(scr->workspaces[scr->current_workspace]->name);
314 WMPutInPLDictionary(scr->session_state, sWorkspace, wks);
315 WMReleasePropList(wks);
317 WMFreeArray(wapp_list);
320 void wSessionClearState(WScreen * scr)
322 make_keys();
324 if (!scr->session_state)
325 return;
327 WMRemoveFromPLDictionary(scr->session_state, sApplications);
328 WMRemoveFromPLDictionary(scr->session_state, sWorkspace);
331 static pid_t execCommand(WScreen * scr, char *command, char *host)
333 pid_t pid;
334 char **argv;
335 int argc;
337 wtokensplit(command, &argv, &argc);
339 if (!argc) {
340 return 0;
343 if ((pid = fork()) == 0) {
344 char **args;
345 int i;
347 SetupEnvironment(scr);
349 args = malloc(sizeof(char *) * (argc + 1));
350 if (!args)
351 exit(111);
352 for (i = 0; i < argc; i++) {
353 args[i] = argv[i];
355 args[argc] = NULL;
356 execvp(argv[0], args);
357 exit(111);
359 while (argc > 0)
360 wfree(argv[--argc]);
361 wfree(argv);
362 return pid;
365 static WSavedState *getWindowState(WScreen * scr, WMPropList * win_state)
367 WSavedState *state = wmalloc(sizeof(WSavedState));
368 WMPropList *value;
369 char *tmp;
370 unsigned mask;
371 int i;
373 memset(state, 0, sizeof(WSavedState));
374 state->workspace = -1;
375 value = WMGetFromPLDictionary(win_state, sWorkspace);
376 if (value && WMIsPLString(value)) {
377 tmp = WMGetFromPLString(value);
378 if (sscanf(tmp, "%i", &state->workspace) != 1) {
379 state->workspace = -1;
380 for (i = 0; i < scr->workspace_count; i++) {
381 if (strcmp(scr->workspaces[i]->name, tmp) == 0) {
382 state->workspace = i;
383 break;
386 } else {
387 state->workspace--;
390 if ((value = WMGetFromPLDictionary(win_state, sShaded)) != NULL)
391 state->shaded = getBool(value);
392 if ((value = WMGetFromPLDictionary(win_state, sMiniaturized)) != NULL)
393 state->miniaturized = getBool(value);
394 if ((value = WMGetFromPLDictionary(win_state, sHidden)) != NULL)
395 state->hidden = getBool(value);
396 if ((value = WMGetFromPLDictionary(win_state, sShortcutMask)) != NULL) {
397 mask = getInt(value);
398 state->window_shortcuts = mask;
401 value = WMGetFromPLDictionary(win_state, sGeometry);
402 if (value && WMIsPLString(value)) {
403 if (!(sscanf(WMGetFromPLString(value), "%ix%i+%i+%i",
404 &state->w, &state->h, &state->x, &state->y) == 4 && (state->w > 0 && state->h > 0))) {
405 state->w = 0;
406 state->h = 0;
410 return state;
413 #define SAME(x, y) (((x) && (y) && !strcmp((x), (y))) || (!(x) && !(y)))
415 void wSessionRestoreState(WScreen * scr)
417 WSavedState *state;
418 char *instance, *class, *command, *host;
419 WMPropList *win_info, *apps, *cmd, *value;
420 pid_t pid;
421 int i, count;
422 WDock *dock;
423 WAppIcon *btn = NULL;
424 int j, n, found;
425 char *tmp;
427 make_keys();
429 if (!scr->session_state)
430 return;
432 WMPLSetCaseSensitive(True);
434 apps = WMGetFromPLDictionary(scr->session_state, sApplications);
435 if (!apps)
436 return;
438 count = WMGetPropListItemCount(apps);
439 if (count == 0)
440 return;
442 for (i = 0; i < count; i++) {
443 win_info = WMGetFromPLArray(apps, i);
445 cmd = WMGetFromPLDictionary(win_info, sCommand);
446 if (!cmd || !WMIsPLString(cmd) || !(command = WMGetFromPLString(cmd))) {
447 continue;
450 value = WMGetFromPLDictionary(win_info, sName);
451 if (!value)
452 continue;
454 ParseWindowName(value, &instance, &class, "session");
455 if (!instance && !class)
456 continue;
458 value = WMGetFromPLDictionary(win_info, sHost);
459 if (value && WMIsPLString(value))
460 host = WMGetFromPLString(value);
461 else
462 host = NULL;
464 state = getWindowState(scr, win_info);
466 dock = NULL;
467 value = WMGetFromPLDictionary(win_info, sDock);
468 if (value && WMIsPLString(value) && (tmp = WMGetFromPLString(value)) != NULL) {
469 if (sscanf(tmp, "%i", &n) != 1) {
470 if (!strcasecmp(tmp, "DOCK")) {
471 dock = scr->dock;
472 } else {
473 for (j = 0; j < scr->workspace_count; j++) {
474 if (strcmp(scr->workspaces[j]->name, tmp) == 0) {
475 dock = scr->workspaces[j]->clip;
476 break;
480 } else {
481 if (n == 0) {
482 dock = scr->dock;
483 } else if (n > 0 && n <= scr->workspace_count) {
484 dock = scr->workspaces[n - 1]->clip;
489 found = 0;
490 if (dock != NULL) {
491 for (j = 0; j < dock->max_icons; j++) {
492 btn = dock->icon_array[j];
493 if (btn && SAME(instance, btn->wm_instance) &&
494 SAME(class, btn->wm_class) && SAME(command, btn->command) && !btn->launching) {
495 found = 1;
496 break;
501 if (found) {
502 wDockLaunchWithState(dock, btn, state);
503 } else if ((pid = execCommand(scr, command, host)) > 0) {
504 wWindowAddSavedState(instance, class, command, pid, state);
505 } else {
506 wfree(state);
509 if (instance)
510 wfree(instance);
511 if (class)
512 wfree(class);
514 /* clean up */
515 WMPLSetCaseSensitive(False);
518 void wSessionRestoreLastWorkspace(WScreen * scr)
520 WMPropList *wks;
521 int w, i;
522 char *tmp;
524 make_keys();
526 if (!scr->session_state)
527 return;
529 WMPLSetCaseSensitive(True);
531 wks = WMGetFromPLDictionary(scr->session_state, sWorkspace);
532 if (!wks || !WMIsPLString(wks))
533 return;
535 tmp = WMGetFromPLString(wks);
537 /* clean up */
538 WMPLSetCaseSensitive(False);
540 if (sscanf(tmp, "%i", &w) != 1) {
541 w = -1;
542 for (i = 0; i < scr->workspace_count; i++) {
543 if (strcmp(scr->workspaces[i]->name, tmp) == 0) {
544 w = i;
545 break;
548 } else {
549 w--;
552 if (w != scr->current_workspace && w < scr->workspace_count) {
553 wWorkspaceChange(scr, w);
557 static void clearWaitingAckState(WScreen * scr)
559 WWindow *wwin;
560 WApplication *wapp;
562 for (wwin = scr->focused_window; wwin != NULL; wwin = wwin->prev) {
563 wwin->flags.waiting_save_ack = 0;
564 if (wwin->main_window != None) {
565 wapp = wApplicationOf(wwin->main_window);
566 if (wapp)
567 wapp->main_window_desc->flags.waiting_save_ack = 0;
572 void wSessionSaveClients(WScreen * scr)
578 * With XSMP, this job is done by smproxy
580 void wSessionSendSaveYourself(WScreen * scr)
582 WWindow *wwin;
583 int count;
585 /* freeze client interaction with clients */
586 XGrabKeyboard(dpy, scr->root_win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
587 XGrabPointer(dpy, scr->root_win, False, ButtonPressMask | ButtonReleaseMask,
588 GrabModeAsync, GrabModeAsync, scr->root_win, None, CurrentTime);
590 clearWaitingAckState(scr);
592 count = 0;
594 /* first send SAVE_YOURSELF for everybody */
595 for (wwin = scr->focused_window; wwin != NULL; wwin = wwin->prev) {
596 WWindow *mainWin;
598 mainWin = wWindowFor(wwin->main_window);
600 if (mainWin) {
601 /* if the client is a multi-window client, only send message
602 * to the main window */
603 wwin = mainWin;
606 /* make sure the SAVE_YOURSELF flag is up-to-date */
607 PropGetProtocols(wwin->client_win, &wwin->protocols);
609 if (wwin->protocols.SAVE_YOURSELF) {
610 if (!wwin->flags.waiting_save_ack) {
611 wClientSendProtocol(wwin, _XA_WM_SAVE_YOURSELF, LastTimestamp);
613 wwin->flags.waiting_save_ack = 1;
614 count++;
616 } else {
617 wwin->flags.waiting_save_ack = 0;
621 /* then wait for acknowledge */
622 while (count > 0) {
626 XUngrabPointer(dpy, CurrentTime);
627 XUngrabKeyboard(dpy, CurrentTime);
628 XFlush(dpy);