Remove XSMP_ENABLED constructs
[wmaker-crm.git] / src / session.c
blobcbb4e1e5e56c350a21693c63602d5de953734e80
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
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21 * USA.
26 * If defined(XSMP_ENABLED) and session manager is running then
27 * do normal stuff
28 * else
29 * do pre-R6 session management stuff (save window state and relaunch)
31 * When doing a checkpoint:
33 * = Without XSMP
34 * Open "Stop"/status Dialog
35 * Send SAVE_YOURSELF to clients and wait for reply
36 * Save restart info
37 * Save state of clients
39 * = With XSMP
40 * Send checkpoint request to sm
42 * When exiting:
43 * -------------
45 * = Without XSMP
47 * Open "Exit Now"/status Dialog
48 * Send SAVE_YOURSELF to clients and wait for reply
49 * Save restart info
50 * Save state of clients
51 * Send DELETE to all clients
52 * When no more clients are left or user hit "Exit Now", exit
54 * = With XSMP
56 * Send Shutdown request to session manager
57 * if SaveYourself message received, save state of clients
58 * if the Die message is received, exit.
61 #include "wconfig.h"
63 #include <X11/Xlib.h>
64 #include <X11/Xutil.h>
66 #include <stdlib.h>
67 #include <stdio.h>
68 #include <string.h>
69 #include <unistd.h>
70 #include <time.h>
72 #include "WindowMaker.h"
73 #include "screen.h"
74 #include "window.h"
75 #include "client.h"
76 #include "session.h"
77 #include "wcore.h"
78 #include "framewin.h"
79 #include "workspace.h"
80 #include "funcs.h"
81 #include "properties.h"
82 #include "application.h"
83 #include "appicon.h"
84 #include "dock.h"
86 #include <WINGs/WUtil.h>
88 /** Global **/
90 extern Atom _XA_WM_SAVE_YOURSELF;
92 extern Time LastTimestamp;
94 static WMPropList *sApplications = NULL;
95 static WMPropList *sCommand;
96 static WMPropList *sName;
97 static WMPropList *sHost;
98 static WMPropList *sWorkspace;
99 static WMPropList *sShaded;
100 static WMPropList *sMiniaturized;
101 static WMPropList *sHidden;
102 static WMPropList *sGeometry;
103 static WMPropList *sShortcutMask;
105 static WMPropList *sDock;
106 static WMPropList *sYes, *sNo;
108 static void make_keys()
110 if (sApplications != NULL)
111 return;
113 sApplications = WMCreatePLString("Applications");
114 sCommand = WMCreatePLString("Command");
115 sName = WMCreatePLString("Name");
116 sHost = WMCreatePLString("Host");
117 sWorkspace = WMCreatePLString("Workspace");
118 sShaded = WMCreatePLString("Shaded");
119 sMiniaturized = WMCreatePLString("Miniaturized");
120 sHidden = WMCreatePLString("Hidden");
121 sGeometry = WMCreatePLString("Geometry");
122 sDock = WMCreatePLString("Dock");
123 sShortcutMask = WMCreatePLString("ShortcutMask");
125 sYes = WMCreatePLString("Yes");
126 sNo = WMCreatePLString("No");
129 static int getBool(WMPropList * value)
131 char *val;
133 if (!WMIsPLString(value)) {
134 return 0;
136 if (!(val = WMGetFromPLString(value))) {
137 return 0;
140 if ((val[1] == '\0' && (val[0] == 'y' || val[0] == 'Y'))
141 || strcasecmp(val, "YES") == 0) {
143 return 1;
144 } else if ((val[1] == '\0' && (val[0] == 'n' || val[0] == 'N'))
145 || strcasecmp(val, "NO") == 0) {
146 return 0;
147 } else {
148 int i;
149 if (sscanf(val, "%i", &i) == 1) {
150 return (i != 0);
151 } else {
152 wwarning(_("can't convert \"%s\" to boolean"), val);
153 return 0;
158 static unsigned getInt(WMPropList * value)
160 char *val;
161 unsigned n;
163 if (!WMIsPLString(value))
164 return 0;
165 val = WMGetFromPLString(value);
166 if (!val)
167 return 0;
168 if (sscanf(val, "%u", &n) != 1)
169 return 0;
171 return n;
174 static WMPropList *makeWindowState(WWindow * wwin, WApplication * wapp)
176 WScreen *scr = wwin->screen_ptr;
177 Window win;
178 int i;
179 unsigned mask;
180 char *class, *instance, *command = NULL, buffer[512];
181 WMPropList *win_state, *cmd, *name, *workspace;
182 WMPropList *shaded, *miniaturized, *hidden, *geometry;
183 WMPropList *dock, *shortcut;
185 if (wwin->orig_main_window != None && wwin->orig_main_window != wwin->client_win)
186 win = wwin->orig_main_window;
187 else
188 win = wwin->client_win;
190 command = GetCommandForWindow(win);
191 if (!command)
192 return NULL;
194 if (PropGetWMClass(win, &class, &instance)) {
195 if (class && instance)
196 snprintf(buffer, sizeof(buffer), "%s.%s", instance, class);
197 else if (instance)
198 snprintf(buffer, sizeof(buffer), "%s", instance);
199 else if (class)
200 snprintf(buffer, sizeof(buffer), ".%s", class);
201 else
202 snprintf(buffer, sizeof(buffer), ".");
204 name = WMCreatePLString(buffer);
205 cmd = WMCreatePLString(command);
206 /*sprintf(buffer, "%d", wwin->frame->workspace+1);
207 workspace = WMCreatePLString(buffer); */
208 workspace = WMCreatePLString(scr->workspaces[wwin->frame->workspace]->name);
209 shaded = wwin->flags.shaded ? sYes : sNo;
210 miniaturized = wwin->flags.miniaturized ? sYes : sNo;
211 hidden = wwin->flags.hidden ? sYes : sNo;
212 snprintf(buffer, sizeof(buffer), "%ix%i+%i+%i",
213 wwin->client.width, wwin->client.height, wwin->frame_x, wwin->frame_y);
214 geometry = WMCreatePLString(buffer);
216 for (mask = 0, i = 0; i < MAX_WINDOW_SHORTCUTS; i++) {
217 if (scr->shortcutWindows[i] != NULL &&
218 WMGetFirstInArray(scr->shortcutWindows[i], wwin) != WANotFound) {
219 mask |= 1 << i;
223 snprintf(buffer, sizeof(buffer), "%u", mask);
224 shortcut = WMCreatePLString(buffer);
226 win_state = WMCreatePLDictionary(sName, name,
227 sCommand, cmd,
228 sWorkspace, workspace,
229 sShaded, shaded,
230 sMiniaturized, miniaturized,
231 sHidden, hidden,
232 sShortcutMask, shortcut, sGeometry, geometry, NULL);
234 WMReleasePropList(name);
235 WMReleasePropList(cmd);
236 WMReleasePropList(workspace);
237 WMReleasePropList(geometry);
238 WMReleasePropList(shortcut);
239 if (wapp && wapp->app_icon && wapp->app_icon->dock) {
240 int i;
241 char *name;
242 if (wapp->app_icon->dock == scr->dock) {
243 name = "Dock";
244 } else {
245 for (i = 0; i < scr->workspace_count; i++)
246 if (scr->workspaces[i]->clip == wapp->app_icon->dock)
247 break;
248 assert(i < scr->workspace_count);
249 /*n = i+1; */
250 name = scr->workspaces[i]->name;
252 dock = WMCreatePLString(name);
253 WMPutInPLDictionary(win_state, sDock, dock);
254 WMReleasePropList(dock);
256 } else {
257 win_state = NULL;
260 if (instance)
261 XFree(instance);
262 if (class)
263 XFree(class);
264 if (command)
265 wfree(command);
267 return win_state;
270 void wSessionSaveState(WScreen * scr)
272 WWindow *wwin = scr->focused_window;
273 WMPropList *win_info, *wks;
274 WMPropList *list = NULL;
275 WMArray *wapp_list = NULL;
277 make_keys();
279 if (!scr->session_state) {
280 scr->session_state = WMCreatePLDictionary(NULL, NULL);
281 if (!scr->session_state)
282 return;
285 list = WMCreatePLArray(NULL);
287 wapp_list = WMCreateArray(16);
289 while (wwin) {
290 WApplication *wapp = wApplicationOf(wwin->main_window);
291 Window appId = wwin->orig_main_window;
293 if ((wwin->transient_for == None || wwin->transient_for == wwin->screen_ptr->root_win)
294 && (WMGetFirstInArray(wapp_list, (void *)appId) == WANotFound
295 || WFLAGP(wwin, shared_appicon))
296 && !WFLAGP(wwin, dont_save_session)) {
297 /* A entry for this application was not yet saved. Save one. */
298 if ((win_info = makeWindowState(wwin, wapp)) != NULL) {
299 WMAddToPLArray(list, win_info);
300 WMReleasePropList(win_info);
301 /* If we were succesful in saving the info for this window
302 * add the application the window belongs to, to the
303 * application list, so no multiple entries for the same
304 * application are saved.
306 WMAddToArray(wapp_list, (void *)appId);
309 wwin = wwin->prev;
311 WMRemoveFromPLDictionary(scr->session_state, sApplications);
312 WMPutInPLDictionary(scr->session_state, sApplications, list);
313 WMReleasePropList(list);
315 wks = WMCreatePLString(scr->workspaces[scr->current_workspace]->name);
316 WMPutInPLDictionary(scr->session_state, sWorkspace, wks);
317 WMReleasePropList(wks);
319 WMFreeArray(wapp_list);
322 void wSessionClearState(WScreen * scr)
324 make_keys();
326 if (!scr->session_state)
327 return;
329 WMRemoveFromPLDictionary(scr->session_state, sApplications);
330 WMRemoveFromPLDictionary(scr->session_state, sWorkspace);
333 static pid_t execCommand(WScreen * scr, char *command, char *host)
335 pid_t pid;
336 char **argv;
337 int argc;
339 wtokensplit(command, &argv, &argc);
341 if (!argc) {
342 return 0;
345 if ((pid = fork()) == 0) {
346 char **args;
347 int i;
349 SetupEnvironment(scr);
351 args = malloc(sizeof(char *) * (argc + 1));
352 if (!args)
353 exit(111);
354 for (i = 0; i < argc; i++) {
355 args[i] = argv[i];
357 args[argc] = NULL;
358 execvp(argv[0], args);
359 exit(111);
361 while (argc > 0)
362 wfree(argv[--argc]);
363 wfree(argv);
364 return pid;
367 static WSavedState *getWindowState(WScreen * scr, WMPropList * win_state)
369 WSavedState *state = wmalloc(sizeof(WSavedState));
370 WMPropList *value;
371 char *tmp;
372 unsigned mask;
373 int i;
375 memset(state, 0, sizeof(WSavedState));
376 state->workspace = -1;
377 value = WMGetFromPLDictionary(win_state, sWorkspace);
378 if (value && WMIsPLString(value)) {
379 tmp = WMGetFromPLString(value);
380 if (sscanf(tmp, "%i", &state->workspace) != 1) {
381 state->workspace = -1;
382 for (i = 0; i < scr->workspace_count; i++) {
383 if (strcmp(scr->workspaces[i]->name, tmp) == 0) {
384 state->workspace = i;
385 break;
388 } else {
389 state->workspace--;
392 if ((value = WMGetFromPLDictionary(win_state, sShaded)) != NULL)
393 state->shaded = getBool(value);
394 if ((value = WMGetFromPLDictionary(win_state, sMiniaturized)) != NULL)
395 state->miniaturized = getBool(value);
396 if ((value = WMGetFromPLDictionary(win_state, sHidden)) != NULL)
397 state->hidden = getBool(value);
398 if ((value = WMGetFromPLDictionary(win_state, sShortcutMask)) != NULL) {
399 mask = getInt(value);
400 state->window_shortcuts = mask;
403 value = WMGetFromPLDictionary(win_state, sGeometry);
404 if (value && WMIsPLString(value)) {
405 if (!(sscanf(WMGetFromPLString(value), "%ix%i+%i+%i",
406 &state->w, &state->h, &state->x, &state->y) == 4 && (state->w > 0 && state->h > 0))) {
407 state->w = 0;
408 state->h = 0;
412 return state;
415 #define SAME(x, y) (((x) && (y) && !strcmp((x), (y))) || (!(x) && !(y)))
417 void wSessionRestoreState(WScreen * scr)
419 WSavedState *state;
420 char *instance, *class, *command, *host;
421 WMPropList *win_info, *apps, *cmd, *value;
422 pid_t pid;
423 int i, count;
424 WDock *dock;
425 WAppIcon *btn = NULL;
426 int j, n, found;
427 char *tmp;
429 make_keys();
431 if (!scr->session_state)
432 return;
434 WMPLSetCaseSensitive(True);
436 apps = WMGetFromPLDictionary(scr->session_state, sApplications);
437 if (!apps)
438 return;
440 count = WMGetPropListItemCount(apps);
441 if (count == 0)
442 return;
444 for (i = 0; i < count; i++) {
445 win_info = WMGetFromPLArray(apps, i);
447 cmd = WMGetFromPLDictionary(win_info, sCommand);
448 if (!cmd || !WMIsPLString(cmd) || !(command = WMGetFromPLString(cmd))) {
449 continue;
452 value = WMGetFromPLDictionary(win_info, sName);
453 if (!value)
454 continue;
456 ParseWindowName(value, &instance, &class, "session");
457 if (!instance && !class)
458 continue;
460 value = WMGetFromPLDictionary(win_info, sHost);
461 if (value && WMIsPLString(value))
462 host = WMGetFromPLString(value);
463 else
464 host = NULL;
466 state = getWindowState(scr, win_info);
468 dock = NULL;
469 value = WMGetFromPLDictionary(win_info, sDock);
470 if (value && WMIsPLString(value) && (tmp = WMGetFromPLString(value)) != NULL) {
471 if (sscanf(tmp, "%i", &n) != 1) {
472 if (!strcasecmp(tmp, "DOCK")) {
473 dock = scr->dock;
474 } else {
475 for (j = 0; j < scr->workspace_count; j++) {
476 if (strcmp(scr->workspaces[j]->name, tmp) == 0) {
477 dock = scr->workspaces[j]->clip;
478 break;
482 } else {
483 if (n == 0) {
484 dock = scr->dock;
485 } else if (n > 0 && n <= scr->workspace_count) {
486 dock = scr->workspaces[n - 1]->clip;
491 found = 0;
492 if (dock != NULL) {
493 for (j = 0; j < dock->max_icons; j++) {
494 btn = dock->icon_array[j];
495 if (btn && SAME(instance, btn->wm_instance) &&
496 SAME(class, btn->wm_class) && SAME(command, btn->command) && !btn->launching) {
497 found = 1;
498 break;
503 if (found) {
504 wDockLaunchWithState(dock, btn, state);
505 } else if ((pid = execCommand(scr, command, host)) > 0) {
506 wWindowAddSavedState(instance, class, command, pid, state);
507 } else {
508 wfree(state);
511 if (instance)
512 wfree(instance);
513 if (class)
514 wfree(class);
516 /* clean up */
517 WMPLSetCaseSensitive(False);
520 void wSessionRestoreLastWorkspace(WScreen * scr)
522 WMPropList *wks;
523 int w, i;
524 char *tmp;
526 make_keys();
528 if (!scr->session_state)
529 return;
531 WMPLSetCaseSensitive(True);
533 wks = WMGetFromPLDictionary(scr->session_state, sWorkspace);
534 if (!wks || !WMIsPLString(wks))
535 return;
537 tmp = WMGetFromPLString(wks);
539 /* clean up */
540 WMPLSetCaseSensitive(False);
542 if (sscanf(tmp, "%i", &w) != 1) {
543 w = -1;
544 for (i = 0; i < scr->workspace_count; i++) {
545 if (strcmp(scr->workspaces[i]->name, tmp) == 0) {
546 w = i;
547 break;
550 } else {
551 w--;
554 if (w != scr->current_workspace && w < scr->workspace_count) {
555 wWorkspaceChange(scr, w);
559 static void clearWaitingAckState(WScreen * scr)
561 WWindow *wwin;
562 WApplication *wapp;
564 for (wwin = scr->focused_window; wwin != NULL; wwin = wwin->prev) {
565 wwin->flags.waiting_save_ack = 0;
566 if (wwin->main_window != None) {
567 wapp = wApplicationOf(wwin->main_window);
568 if (wapp)
569 wapp->main_window_desc->flags.waiting_save_ack = 0;
574 void wSessionSaveClients(WScreen * scr)
580 * With XSMP, this job is done by smproxy
582 void wSessionSendSaveYourself(WScreen * scr)
584 WWindow *wwin;
585 int count;
587 /* freeze client interaction with clients */
588 XGrabKeyboard(dpy, scr->root_win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
589 XGrabPointer(dpy, scr->root_win, False, ButtonPressMask | ButtonReleaseMask,
590 GrabModeAsync, GrabModeAsync, scr->root_win, None, CurrentTime);
592 clearWaitingAckState(scr);
594 count = 0;
596 /* first send SAVE_YOURSELF for everybody */
597 for (wwin = scr->focused_window; wwin != NULL; wwin = wwin->prev) {
598 WWindow *mainWin;
600 mainWin = wWindowFor(wwin->main_window);
602 if (mainWin) {
603 /* if the client is a multi-window client, only send message
604 * to the main window */
605 wwin = mainWin;
608 /* make sure the SAVE_YOURSELF flag is up-to-date */
609 PropGetProtocols(wwin->client_win, &wwin->protocols);
611 if (wwin->protocols.SAVE_YOURSELF) {
612 if (!wwin->flags.waiting_save_ack) {
613 wClientSendProtocol(wwin, _XA_WM_SAVE_YOURSELF, LastTimestamp);
615 wwin->flags.waiting_save_ack = 1;
616 count++;
618 } else {
619 wwin->flags.waiting_save_ack = 0;
623 /* then wait for acknowledge */
624 while (count > 0) {
628 XUngrabPointer(dpy, CurrentTime);
629 XUngrabKeyboard(dpy, CurrentTime);
630 XFlush(dpy);