Change to the linux kernel coding style
[wmaker-crm.git] / src / session.c
Commit [+]AuthorDateLineData
9007a657 dan1998-11-23 11:32:19 +00001/* session.c - session state handling and R6 style session management
9d2e6ef9 scottc1998-09-29 22:36:29 +00002 *
4153e2fd dan2003-01-16 23:30:45 +00003 * Copyright (c) 1998-2003 Dan Pascu
4 * Copyright (c) 1998-2003 Alfredo Kojima
9d2e6ef9 scottc1998-09-29 22:36:29 +00005 *
9af1c6c4 dan1998-10-21 14:43:47 +00006 * Window Maker window manager
9d2e6ef9 scottc1998-09-29 22:36:29 +00007 *
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.
12 *
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.
17 *
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
6830b057 dan2004-10-12 21:28:27 +000020 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
9d2e6ef9 scottc1998-09-29 22:36:29 +000021 * USA.
22 */
23
416e3a82 dan1999-01-25 19:06:50 +000024/*
6830b057 dan2004-10-12 21:28:27 +000025 *
416e3a82 dan1999-01-25 19:06:50 +000026 * 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)
30 *
31 * When doing a checkpoint:
6830b057 dan2004-10-12 21:28:27 +000032 *
416e3a82 dan1999-01-25 19:06:50 +000033 * = 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
6830b057 dan2004-10-12 21:28:27 +000038 *
416e3a82 dan1999-01-25 19:06:50 +000039 * = With XSMP
40 * Send checkpoint request to sm
41 *
42 * When exiting:
43 * -------------
6830b057 dan2004-10-12 21:28:27 +000044 *
416e3a82 dan1999-01-25 19:06:50 +000045 * = Without XSMP
6830b057 dan2004-10-12 21:28:27 +000046 *
416e3a82 dan1999-01-25 19:06:50 +000047 * 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
6830b057 dan2004-10-12 21:28:27 +000053 *
416e3a82 dan1999-01-25 19:06:50 +000054 * = With XSMP
55 *
56 * Send Shutdown request to session manager
6830b057 dan2004-10-12 21:28:27 +000057 * if SaveYourself message received, save state of clients
416e3a82 dan1999-01-25 19:06:50 +000058 * if the Die message is received, exit.
59 */
60
9d2e6ef9 scottc1998-09-29 22:36:29 +000061#include "wconfig.h"
62
63#include <X11/Xlib.h>
64#include <X11/Xutil.h>
9007a657 dan1998-11-23 11:32:19 +000065
416e3a82 dan1999-01-25 19:06:50 +000066#ifdef XSMP_ENABLED
9007a657 dan1998-11-23 11:32:19 +000067#include <X11/SM/SMlib.h>
68#endif
69
9d2e6ef9 scottc1998-09-29 22:36:29 +000070#include <stdlib.h>
71#include <stdio.h>
72#include <string.h>
73#include <unistd.h>
9007a657 dan1998-11-23 11:32:19 +000074#include <time.h>
75
9d2e6ef9 scottc1998-09-29 22:36:29 +000076#include "WindowMaker.h"
77#include "screen.h"
78#include "window.h"
416e3a82 dan1999-01-25 19:06:50 +000079#include "client.h"
9d2e6ef9 scottc1998-09-29 22:36:29 +000080#include "session.h"
81#include "wcore.h"
82#include "framewin.h"
83#include "workspace.h"
84#include "funcs.h"
85#include "properties.h"
86#include "application.h"
87#include "appicon.h"
88
89#include "dock.h"
90
33cc542e dan2001-10-04 03:07:34 +000091#include <WINGs/WUtil.h>
9d2e6ef9 scottc1998-09-29 22:36:29 +000092
416e3a82 dan1999-01-25 19:06:50 +000093/** Global **/
94
95extern Atom _XA_WM_SAVE_YOURSELF;
9d2e6ef9 scottc1998-09-29 22:36:29 +000096
416e3a82 dan1999-01-25 19:06:50 +000097extern Time LastTimestamp;
98
99#ifdef XSMP_ENABLED
345d980b dan1998-11-27 12:26:46 +0000100
101extern int wScreenCount;
102
9007a657 dan1998-11-23 11:32:19 +0000103/* requested for SaveYourselfPhase2 */
104static Bool sWaitingPhase2 = False;
105
106static SmcConn sSMCConn = NULL;
107
108static WMHandlerID sSMInputHandler = NULL;
109
110/* our SM client ID */
111static char *sClientID = NULL;
112#endif
113
33cc542e dan2001-10-04 03:07:34 +0000114static WMPropList *sApplications = NULL;
115static WMPropList *sCommand;
116static WMPropList *sName;
117static WMPropList *sHost;
118static WMPropList *sWorkspace;
119static WMPropList *sShaded;
120static WMPropList *sMiniaturized;
121static WMPropList *sHidden;
122static WMPropList *sGeometry;
123static WMPropList *sShortcutMask;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000124
33cc542e dan2001-10-04 03:07:34 +0000125static WMPropList *sDock;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000126
33cc542e dan2001-10-04 03:07:34 +0000127static WMPropList *sYes, *sNo;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000128
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200129static void make_keys()
9d2e6ef9 scottc1998-09-29 22:36:29 +0000130{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200131 if (sApplications != NULL)
132 return;
133
134 sApplications = WMCreatePLString("Applications");
135 sCommand = WMCreatePLString("Command");
136 sName = WMCreatePLString("Name");
137 sHost = WMCreatePLString("Host");
138 sWorkspace = WMCreatePLString("Workspace");
139 sShaded = WMCreatePLString("Shaded");
140 sMiniaturized = WMCreatePLString("Miniaturized");
141 sHidden = WMCreatePLString("Hidden");
142 sGeometry = WMCreatePLString("Geometry");
143 sDock = WMCreatePLString("Dock");
144 sShortcutMask = WMCreatePLString("ShortcutMask");
145
146 sYes = WMCreatePLString("Yes");
147 sNo = WMCreatePLString("No");
9d2e6ef9 scottc1998-09-29 22:36:29 +0000148}
149
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200150static int getBool(WMPropList * value)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000151{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200152 char *val;
153
154 if (!WMIsPLString(value)) {
155 return 0;
156 }
157 if (!(val = WMGetFromPLString(value))) {
158 return 0;
159 }
160
161 if ((val[1] == '\0' && (val[0] == 'y' || val[0] == 'Y'))
162 || strcasecmp(val, "YES") == 0) {
163
164 return 1;
165 } else if ((val[1] == '\0' && (val[0] == 'n' || val[0] == 'N'))
166 || strcasecmp(val, "NO") == 0) {
167 return 0;
168 } else {
169 int i;
170 if (sscanf(val, "%i", &i) == 1) {
171 return (i != 0);
172 } else {
173 wwarning(_("can't convert \"%s\" to boolean"), val);
174 return 0;
175 }
176 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000177}
178
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200179static unsigned getInt(WMPropList * value)
f5177e67 kojima2000-03-28 02:48:32 +0000180{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200181 char *val;
182 unsigned n;
183
184 if (!WMIsPLString(value))
185 return 0;
186 val = WMGetFromPLString(value);
187 if (!val)
188 return 0;
189 if (sscanf(val, "%u", &n) != 1)
190 return 0;
191
192 return n;
f5177e67 kojima2000-03-28 02:48:32 +0000193}
194
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200195static WMPropList *makeWindowState(WWindow * wwin, WApplication * wapp)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000196{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200197 WScreen *scr = wwin->screen_ptr;
198 Window win;
199 int i;
200 unsigned mask;
201 char *class, *instance, *command = NULL, buffer[512];
202 WMPropList *win_state, *cmd, *name, *workspace;
203 WMPropList *shaded, *miniaturized, *hidden, *geometry;
204 WMPropList *dock, *shortcut;
205
206 if (wwin->orig_main_window != None && wwin->orig_main_window != wwin->client_win)
207 win = wwin->orig_main_window;
208 else
209 win = wwin->client_win;
210
211 command = GetCommandForWindow(win);
212 if (!command)
213 return NULL;
214
215 if (PropGetWMClass(win, &class, &instance)) {
216 if (class && instance)
217 snprintf(buffer, sizeof(buffer), "%s.%s", instance, class);
218 else if (instance)
219 snprintf(buffer, sizeof(buffer), "%s", instance);
220 else if (class)
221 snprintf(buffer, sizeof(buffer), ".%s", class);
222 else
223 snprintf(buffer, sizeof(buffer), ".");
224
225 name = WMCreatePLString(buffer);
226 cmd = WMCreatePLString(command);
227 /*sprintf(buffer, "%d", wwin->frame->workspace+1);
228 workspace = WMCreatePLString(buffer); */
229 workspace = WMCreatePLString(scr->workspaces[wwin->frame->workspace]->name);
230 shaded = wwin->flags.shaded ? sYes : sNo;
231 miniaturized = wwin->flags.miniaturized ? sYes : sNo;
232 hidden = wwin->flags.hidden ? sYes : sNo;
233 snprintf(buffer, sizeof(buffer), "%ix%i+%i+%i",
234 wwin->client.width, wwin->client.height, wwin->frame_x, wwin->frame_y);
235 geometry = WMCreatePLString(buffer);
236
237 for (mask = 0, i = 0; i < MAX_WINDOW_SHORTCUTS; i++) {
238 if (scr->shortcutWindows[i] != NULL &&
239 WMGetFirstInArray(scr->shortcutWindows[i], wwin) != WANotFound) {
240 mask |= 1 << i;
241 }
242 }
243
244 snprintf(buffer, sizeof(buffer), "%u", mask);
245 shortcut = WMCreatePLString(buffer);
246
247 win_state = WMCreatePLDictionary(sName, name,
248 sCommand, cmd,
249 sWorkspace, workspace,
250 sShaded, shaded,
251 sMiniaturized, miniaturized,
252 sHidden, hidden,
253 sShortcutMask, shortcut, sGeometry, geometry, NULL);
254
255 WMReleasePropList(name);
256 WMReleasePropList(cmd);
257 WMReleasePropList(workspace);
258 WMReleasePropList(geometry);
259 WMReleasePropList(shortcut);
260 if (wapp && wapp->app_icon && wapp->app_icon->dock) {
261 int i;
262 char *name;
263 if (wapp->app_icon->dock == scr->dock) {
264 name = "Dock";
265 } else {
266 for (i = 0; i < scr->workspace_count; i++)
267 if (scr->workspaces[i]->clip == wapp->app_icon->dock)
268 break;
269 assert(i < scr->workspace_count);
270 /*n = i+1; */
271 name = scr->workspaces[i]->name;
272 }
273 dock = WMCreatePLString(name);
274 WMPutInPLDictionary(win_state, sDock, dock);
275 WMReleasePropList(dock);
276 }
277 } else {
278 win_state = NULL;
279 }
280
281 if (instance)
282 XFree(instance);
283 if (class)
284 XFree(class);
285 if (command)
286 wfree(command);
287
288 return win_state;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000289}
290
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200291void wSessionSaveState(WScreen * scr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000292{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200293 WWindow *wwin = scr->focused_window;
294 WMPropList *win_info, *wks;
295 WMPropList *list = NULL;
296 WMArray *wapp_list = NULL;
297
298 make_keys();
299
300 if (!scr->session_state) {
301 scr->session_state = WMCreatePLDictionary(NULL, NULL);
302 if (!scr->session_state)
303 return;
304 }
305
306 list = WMCreatePLArray(NULL);
307
308 wapp_list = WMCreateArray(16);
309
310 while (wwin) {
311 WApplication *wapp = wApplicationOf(wwin->main_window);
312 Window appId = wwin->orig_main_window;
313
314 if ((wwin->transient_for == None || wwin->transient_for == wwin->screen_ptr->root_win)
315 && WMGetFirstInArray(wapp_list, (void *)appId) == WANotFound
316 && !WFLAGP(wwin, dont_save_session)) {
317 /* A entry for this application was not yet saved. Save one. */
318 if ((win_info = makeWindowState(wwin, wapp)) != NULL) {
319 WMAddToPLArray(list, win_info);
320 WMReleasePropList(win_info);
321 /* If we were succesful in saving the info for this window
322 * add the application the window belongs to, to the
323 * application list, so no multiple entries for the same
324 * application are saved.
325 */
326 WMAddToArray(wapp_list, (void *)appId);
327 }
328 }
329 wwin = wwin->prev;
330 }
331 WMRemoveFromPLDictionary(scr->session_state, sApplications);
332 WMPutInPLDictionary(scr->session_state, sApplications, list);
333 WMReleasePropList(list);
334
335 wks = WMCreatePLString(scr->workspaces[scr->current_workspace]->name);
336 WMPutInPLDictionary(scr->session_state, sWorkspace, wks);
337 WMReleasePropList(wks);
338
339 WMFreeArray(wapp_list);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000340}
341
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200342void wSessionClearState(WScreen * scr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000343{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200344 make_keys();
9d2e6ef9 scottc1998-09-29 22:36:29 +0000345
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200346 if (!scr->session_state)
347 return;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000348
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200349 WMRemoveFromPLDictionary(scr->session_state, sApplications);
350 WMRemoveFromPLDictionary(scr->session_state, sWorkspace);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000351}
352
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200353static pid_t execCommand(WScreen * scr, char *command, char *host)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000354{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200355 pid_t pid;
356 char **argv;
357 int argc;
358
359 wtokensplit(command, &argv, &argc);
360
361 if (!argc) {
362 return 0;
363 }
364
365 if ((pid = fork()) == 0) {
366 char **args;
367 int i;
368
369 SetupEnvironment(scr);
370
371 args = malloc(sizeof(char *) * (argc + 1));
372 if (!args)
373 exit(111);
374 for (i = 0; i < argc; i++) {
375 args[i] = argv[i];
376 }
377 args[argc] = NULL;
378 execvp(argv[0], args);
379 exit(111);
380 }
381 while (argc > 0)
382 wfree(argv[--argc]);
383 wfree(argv);
384 return pid;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000385}
386
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200387static WSavedState *getWindowState(WScreen * scr, WMPropList * win_state)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000388{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200389 WSavedState *state = wmalloc(sizeof(WSavedState));
390 WMPropList *value;
391 char *tmp;
392 unsigned mask;
393 int i;
394
395 memset(state, 0, sizeof(WSavedState));
396 state->workspace = -1;
397 value = WMGetFromPLDictionary(win_state, sWorkspace);
398 if (value && WMIsPLString(value)) {
399 tmp = WMGetFromPLString(value);
400 if (sscanf(tmp, "%i", &state->workspace) != 1) {
401 state->workspace = -1;
402 for (i = 0; i < scr->workspace_count; i++) {
403 if (strcmp(scr->workspaces[i]->name, tmp) == 0) {
404 state->workspace = i;
405 break;
406 }
407 }
408 } else {
409 state->workspace--;
410 }
411 }
412 if ((value = WMGetFromPLDictionary(win_state, sShaded)) != NULL)
413 state->shaded = getBool(value);
414 if ((value = WMGetFromPLDictionary(win_state, sMiniaturized)) != NULL)
415 state->miniaturized = getBool(value);
416 if ((value = WMGetFromPLDictionary(win_state, sHidden)) != NULL)
417 state->hidden = getBool(value);
418 if ((value = WMGetFromPLDictionary(win_state, sShortcutMask)) != NULL) {
419 mask = getInt(value);
420 state->window_shortcuts = mask;
421 }
422
423 value = WMGetFromPLDictionary(win_state, sGeometry);
424 if (value && WMIsPLString(value)) {
425 if (!(sscanf(WMGetFromPLString(value), "%ix%i+%i+%i",
426 &state->w, &state->h, &state->x, &state->y) == 4 && (state->w > 0 && state->h > 0))) {
427 state->w = 0;
428 state->h = 0;
429 }
430 }
431
432 return state;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000433}
434
9d2e6ef9 scottc1998-09-29 22:36:29 +0000435#define SAME(x, y) (((x) && (y) && !strcmp((x), (y))) || (!(x) && !(y)))
436
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200437void wSessionRestoreState(WScreen * scr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000438{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200439 WSavedState *state;
440 char *instance, *class, *command, *host;
441 WMPropList *win_info, *apps, *cmd, *value;
442 pid_t pid;
443 int i, count;
444 WDock *dock;
445 WAppIcon *btn = NULL;
446 int j, n, found;
447 char *tmp;
448
449 make_keys();
450
451 if (!scr->session_state)
452 return;
453
454 WMPLSetCaseSensitive(True);
455
456 apps = WMGetFromPLDictionary(scr->session_state, sApplications);
457 if (!apps)
458 return;
459
460 count = WMGetPropListItemCount(apps);
461 if (count == 0)
462 return;
463
464 for (i = 0; i < count; i++) {
465 win_info = WMGetFromPLArray(apps, i);
466
467 cmd = WMGetFromPLDictionary(win_info, sCommand);
468 if (!cmd || !WMIsPLString(cmd) || !(command = WMGetFromPLString(cmd))) {
469 continue;
470 }
471
472 value = WMGetFromPLDictionary(win_info, sName);
473 if (!value)
474 continue;
475
476 ParseWindowName(value, &instance, &class, "session");
477 if (!instance && !class)
478 continue;
479
480 value = WMGetFromPLDictionary(win_info, sHost);
481 if (value && WMIsPLString(value))
482 host = WMGetFromPLString(value);
483 else
484 host = NULL;
485
486 state = getWindowState(scr, win_info);
487
488 dock = NULL;
489 value = WMGetFromPLDictionary(win_info, sDock);
490 if (value && WMIsPLString(value) && (tmp = WMGetFromPLString(value)) != NULL) {
491 if (sscanf(tmp, "%i", &n) != 1) {
492 if (!strcasecmp(tmp, "DOCK")) {
493 dock = scr->dock;
494 } else {
495 for (j = 0; j < scr->workspace_count; j++) {
496 if (strcmp(scr->workspaces[j]->name, tmp) == 0) {
497 dock = scr->workspaces[j]->clip;
498 break;
499 }
500 }
501 }
502 } else {
503 if (n == 0) {
504 dock = scr->dock;
505 } else if (n > 0 && n <= scr->workspace_count) {
506 dock = scr->workspaces[n - 1]->clip;
507 }
508 }
509 }
510
511 found = 0;
512 if (dock != NULL) {
513 for (j = 0; j < dock->max_icons; j++) {
514 btn = dock->icon_array[j];
515 if (btn && SAME(instance, btn->wm_instance) &&
516 SAME(class, btn->wm_class) && SAME(command, btn->command) && !btn->launching) {
517 found = 1;
518 break;
519 }
520 }
521 }
522
523 if (found) {
524 wDockLaunchWithState(dock, btn, state);
525 } else if ((pid = execCommand(scr, command, host)) > 0) {
526 wWindowAddSavedState(instance, class, command, pid, state);
527 } else {
528 wfree(state);
529 }
530
531 if (instance)
532 wfree(instance);
533 if (class)
534 wfree(class);
535 }
536 /* clean up */
537 WMPLSetCaseSensitive(False);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000538}
539
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200540void wSessionRestoreLastWorkspace(WScreen * scr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000541{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200542 WMPropList *wks;
543 int w, i;
544 char *tmp;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000545
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200546 make_keys();
9d2e6ef9 scottc1998-09-29 22:36:29 +0000547
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200548 if (!scr->session_state)
549 return;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000550
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200551 WMPLSetCaseSensitive(True);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000552
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200553 wks = WMGetFromPLDictionary(scr->session_state, sWorkspace);
554 if (!wks || !WMIsPLString(wks))
555 return;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000556
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200557 tmp = WMGetFromPLString(wks);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000558
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200559 /* clean up */
560 WMPLSetCaseSensitive(False);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000561
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200562 if (sscanf(tmp, "%i", &w) != 1) {
563 w = -1;
564 for (i = 0; i < scr->workspace_count; i++) {
565 if (strcmp(scr->workspaces[i]->name, tmp) == 0) {
566 w = i;
567 break;
568 }
569 }
570 } else {
571 w--;
572 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000573
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200574 if (w != scr->current_workspace && w < scr->workspace_count) {
575 wWorkspaceChange(scr, w);
576 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000577}
578
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200579static void clearWaitingAckState(WScreen * scr)
416e3a82 dan1999-01-25 19:06:50 +0000580{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200581 WWindow *wwin;
582 WApplication *wapp;
583
584 for (wwin = scr->focused_window; wwin != NULL; wwin = wwin->prev) {
585 wwin->flags.waiting_save_ack = 0;
586 if (wwin->main_window != None) {
587 wapp = wApplicationOf(wwin->main_window);
588 if (wapp)
589 wapp->main_window_desc->flags.waiting_save_ack = 0;
590 }
591 }
416e3a82 dan1999-01-25 19:06:50 +0000592}
593
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200594void wSessionSaveClients(WScreen * scr)
416e3a82 dan1999-01-25 19:06:50 +0000595{
6830b057 dan2004-10-12 21:28:27 +0000596
416e3a82 dan1999-01-25 19:06:50 +0000597}
6830b057 dan2004-10-12 21:28:27 +0000598
416e3a82 dan1999-01-25 19:06:50 +0000599/*
600 * With XSMP, this job is done by smproxy
601 */
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200602void wSessionSendSaveYourself(WScreen * scr)
416e3a82 dan1999-01-25 19:06:50 +0000603{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200604 WWindow *wwin;
605 int count;
416e3a82 dan1999-01-25 19:06:50 +0000606
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200607 /* freeze client interaction with clients */
608 XGrabKeyboard(dpy, scr->root_win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
609 XGrabPointer(dpy, scr->root_win, False, ButtonPressMask | ButtonReleaseMask,
610 GrabModeAsync, GrabModeAsync, scr->root_win, None, CurrentTime);
416e3a82 dan1999-01-25 19:06:50 +0000611
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200612 clearWaitingAckState(scr);
416e3a82 dan1999-01-25 19:06:50 +0000613
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200614 count = 0;
416e3a82 dan1999-01-25 19:06:50 +0000615
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200616 /* first send SAVE_YOURSELF for everybody */
617 for (wwin = scr->focused_window; wwin != NULL; wwin = wwin->prev) {
618 WWindow *mainWin;
416e3a82 dan1999-01-25 19:06:50 +0000619
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200620 mainWin = wWindowFor(wwin->main_window);
416e3a82 dan1999-01-25 19:06:50 +0000621
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200622 if (mainWin) {
623 /* if the client is a multi-window client, only send message
624 * to the main window */
625 wwin = mainWin;
626 }
416e3a82 dan1999-01-25 19:06:50 +0000627
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200628 /* make sure the SAVE_YOURSELF flag is up-to-date */
629 PropGetProtocols(wwin->client_win, &wwin->protocols);
416e3a82 dan1999-01-25 19:06:50 +0000630
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200631 if (wwin->protocols.SAVE_YOURSELF) {
632 if (!wwin->flags.waiting_save_ack) {
633 wClientSendProtocol(wwin, _XA_WM_SAVE_YOURSELF, LastTimestamp);
9007a657 dan1998-11-23 11:32:19 +0000634
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200635 wwin->flags.waiting_save_ack = 1;
636 count++;
637 }
638 } else {
639 wwin->flags.waiting_save_ack = 0;
640 }
641 }
416e3a82 dan1999-01-25 19:06:50 +0000642
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200643 /* then wait for acknowledge */
644 while (count > 0) {
6830b057 dan2004-10-12 21:28:27 +0000645
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200646 }
416e3a82 dan1999-01-25 19:06:50 +0000647
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200648 XUngrabPointer(dpy, CurrentTime);
649 XUngrabKeyboard(dpy, CurrentTime);
650 XFlush(dpy);
416e3a82 dan1999-01-25 19:06:50 +0000651}
652
416e3a82 dan1999-01-25 19:06:50 +0000653#ifdef XSMP_ENABLED
9007a657 dan1998-11-23 11:32:19 +0000654/*
6830b057 dan2004-10-12 21:28:27 +0000655 * With full session management support, the part of WMState
345d980b dan1998-11-27 12:26:46 +0000656 * that store client window state will become obsolete (maybe we can reuse
657 * the old code too),
9007a657 dan1998-11-23 11:32:19 +0000658 * but we still need to store state info like the dock and workspaces.
659 * It is better to keep dock/wspace info in WMState because the user
660 * might want to keep the dock configuration while not wanting to
6830b057 dan2004-10-12 21:28:27 +0000661 * resume a previously saved session.
662 * So, wmaker specific state info can be saved in
25c37b76 kojima2005-03-11 01:58:55 +0000663 * ~/GNUstep/Library/WindowMaker/statename.state
9007a657 dan1998-11-23 11:32:19 +0000664 * Its better to not put it in the defaults directory because:
665 * - its not a defaults file (having domain names like wmaker0089504baa
666 * in the defaults directory wouldn't be very neat)
667 * - this state file is not meant to be edited by users
6830b057 dan2004-10-12 21:28:27 +0000668 *
9007a657 dan1998-11-23 11:32:19 +0000669 * The old session code will become obsolete. When wmaker is
49e59ab3 dan2001-09-10 03:56:00 +0000670 * compiled with R6 sm support compiled in, it'll be better to
9007a657 dan1998-11-23 11:32:19 +0000671 * use a totally rewritten state saving code, but we can keep
6830b057 dan2004-10-12 21:28:27 +0000672 * the current code for when XSMP_ENABLED is not compiled in.
673 *
9007a657 dan1998-11-23 11:32:19 +0000674 * This will be confusing to old users (well get lots of "SAVE_SESSION broke!"
49e59ab3 dan2001-09-10 03:56:00 +0000675 * messages), but it'll be better.
6830b057 dan2004-10-12 21:28:27 +0000676 *
9007a657 dan1998-11-23 11:32:19 +0000677 * -readme
678 */
679
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200680static char *getWindowRole(Window window)
4a473b8a kojima1999-04-10 18:27:21 +0000681{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200682 XTextProperty prop;
683 static Atom atom = 0;
6830b057 dan2004-10-12 21:28:27 +0000684
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200685 if (!atom)
686 atom = XInternAtom(dpy, "WM_WINDOW_ROLE", False);
4a473b8a kojima1999-04-10 18:27:21 +0000687
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200688 if (XGetTextProperty(dpy, window, &prop, atom)) {
689 if (prop.encoding == XA_STRING && prop.format == 8 && prop.nitems > 0)
690 return prop.value;
691 }
6830b057 dan2004-10-12 21:28:27 +0000692
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200693 return NULL;
4a473b8a kojima1999-04-10 18:27:21 +0000694}
695
9007a657 dan1998-11-23 11:32:19 +0000696/*
345d980b dan1998-11-27 12:26:46 +0000697 *
698 * Saved Info:
4a473b8a kojima1999-04-10 18:27:21 +0000699 *
345d980b dan1998-11-27 12:26:46 +0000700 * WM_WINDOW_ROLE
4a473b8a kojima1999-04-10 18:27:21 +0000701 *
702 * WM_CLASS.instance
703 * WM_CLASS.class
704 * WM_NAME
705 * WM_COMMAND
6830b057 dan2004-10-12 21:28:27 +0000706 *
345d980b dan1998-11-27 12:26:46 +0000707 * geometry
0261c326 dan1999-01-06 15:22:33 +0000708 * state = (miniaturized, shaded, etc)
709 * attribute
710 * workspace #
711 * app state = (which dock, hidden)
712 * window shortcut #
9007a657 dan1998-11-23 11:32:19 +0000713 */
0261c326 dan1999-01-06 15:22:33 +0000714
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200715static WMPropList *makeAppState(WWindow * wwin)
0261c326 dan1999-01-06 15:22:33 +0000716{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200717 WApplication *wapp;
718 WMPropList *state;
719 WScreen *scr = wwin->screen_ptr;
6830b057 dan2004-10-12 21:28:27 +0000720
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200721 state = WMCreatePLArray(NULL, NULL);
0261c326 dan1999-01-06 15:22:33 +0000722
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200723 wapp = wApplicationOf(wwin->main_window);
6830b057 dan2004-10-12 21:28:27 +0000724
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200725 if (wapp) {
726 if (wapp->app_icon && wapp->app_icon->dock) {
0261c326 dan1999-01-06 15:22:33 +0000727
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200728 if (wapp->app_icon->dock == scr->dock) {
729 WMAddToPLArray(state, WMCreatePLString("Dock"));
730 } else {
731 int i;
0261c326 dan1999-01-06 15:22:33 +0000732
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200733 for (i = 0; i < scr->workspace_count; i++)
734 if (scr->workspaces[i]->clip == wapp->app_icon->dock)
735 break;
0261c326 dan1999-01-06 15:22:33 +0000736
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200737 assert(i < scr->workspace_count);
0261c326 dan1999-01-06 15:22:33 +0000738
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200739 WMAddToPLArray(state, WMCreatePLString(scr->workspaces[i]->name));
740 }
741 }
6830b057 dan2004-10-12 21:28:27 +0000742
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200743 WMAddToPLArray(state, WMCreatePLString(wapp->hidden ? "1" : "0"));
744 }
6830b057 dan2004-10-12 21:28:27 +0000745
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200746 return state;
0261c326 dan1999-01-06 15:22:33 +0000747}
748
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200749Bool wSessionGetStateFor(WWindow * wwin, WSessionData * state)
4a473b8a kojima1999-04-10 18:27:21 +0000750{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200751 char *str;
752 WMPropList *slist;
753 WMPropList *elem;
754 WMPropList *value;
755 int index = 0;
4a473b8a kojima1999-04-10 18:27:21 +0000756
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200757 index = 3;
4a473b8a kojima1999-04-10 18:27:21 +0000758
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200759 /* geometry */
760 value = WMGetFromPLArray(slist, index++);
761 str = WMGetFromPLString(value);
4a473b8a kojima1999-04-10 18:27:21 +0000762
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200763 sscanf(str, "%i %i %i %i %i %i", &state->x, &state->y,
764 &state->width, &state->height, &state->user_changed_width, &state->user_changed_height);
4a473b8a kojima1999-04-10 18:27:21 +0000765
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200766 /* state */
767 value = WMGetFromPLArray(slist, index++);
768 str = WMGetFromPLString(value);
7f018497 kojima1999-04-24 20:08:20 +0000769
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200770 sscanf(str, "%i %i %i", &state->miniaturized, &state->shaded, &state->maximized);
4a473b8a kojima1999-04-10 18:27:21 +0000771
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200772 /* attributes */
773 value = WMGetFromPLArray(slist, index++);
774 str = WMGetFromPLString(value);
4a473b8a kojima1999-04-10 18:27:21 +0000775
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200776 getAttributeState(str, &state->mflags, &state->flags);
7f018497 kojima1999-04-24 20:08:20 +0000777
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200778 /* workspace */
779 value = WMGetFromPLArray(slist, index++);
780 str = WMGetFromPLString(value);
4a473b8a kojima1999-04-10 18:27:21 +0000781
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200782 sscanf(str, "%i", &state->workspace);
4a473b8a kojima1999-04-10 18:27:21 +0000783
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200784 /* app state (repeated for all windows of the app) */
785 value = WMGetFromPLArray(slist, index++);
786 str = WMGetFromPLString(value);
7f018497 kojima1999-04-24 20:08:20 +0000787
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200788 /* ???? */
7f018497 kojima1999-04-24 20:08:20 +0000789
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200790 /* shortcuts */
791 value = WMGetFromPLArray(slist, index++);
792 str = WMGetFromPLString(value);
4a473b8a kojima1999-04-10 18:27:21 +0000793
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200794 sscanf(str, "%i", &state->shortcuts);
4a473b8a kojima1999-04-10 18:27:21 +0000795}
796
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200797static WMPropList *makeAttributeState(WWindow * wwin)
0261c326 dan1999-01-06 15:22:33 +0000798{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200799 unsigned int data1, data2;
800 char buffer[256];
0261c326 dan1999-01-06 15:22:33 +0000801
802#define W_FLAG(wwin, FLAG) ((wwin)->defined_user_flags.FLAG \
6830b057 dan2004-10-12 21:28:27 +0000803 ? (wwin)->user_flags.FLAG : -1)
0261c326 dan1999-01-06 15:22:33 +0000804
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200805 snprintf(buffer, sizeof(buffer),
806 "%i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i %i",
807 W_FLAG(no_titlebar),
808 W_FLAG(no_resizable),
809 W_FLAG(no_closable),
810 W_FLAG(no_miniaturizable),
811 W_FLAG(no_resizebar), W_FLAG(no_close_button), W_FLAG(no_miniaturize_button),
812 /*
813 W_FLAG(broken_close),
814 W_FLAG(kill_close),
815 */
816 W_FLAG(no_shadeable),
817 W_FLAG(omnipresent),
818 W_FLAG(skip_window_list),
819 W_FLAG(floating),
820 W_FLAG(sunken),
821 W_FLAG(no_bind_keys),
822 W_FLAG(no_bind_mouse),
823 W_FLAG(no_hide_others),
824 W_FLAG(no_appicon),
825 W_FLAG(dont_move_off),
826 W_FLAG(no_focusable),
827 W_FLAG(always_user_icon),
828 W_FLAG(start_miniaturized),
829 W_FLAG(start_hidden),
830 W_FLAG(start_maximized), W_FLAG(dont_save_session), W_FLAG(emulate_appicon));
831
832 return WMCreatePLString(buffer);
0261c326 dan1999-01-06 15:22:33 +0000833}
834
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200835static void appendStringInArray(WMPropList * array, char *str)
4a473b8a kojima1999-04-10 18:27:21 +0000836{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200837 WMPropList *val;
6830b057 dan2004-10-12 21:28:27 +0000838
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200839 val = WMCreatePLString(str);
840 WMAddToPLArray(array, val);
841 WMReleasePropList(val);
4a473b8a kojima1999-04-10 18:27:21 +0000842}
843
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200844static WMPropList *makeClientState(WWindow * wwin)
9007a657 dan1998-11-23 11:32:19 +0000845{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200846 WMPropList *state;
847 WMPropList *tmp;
848 char *str;
849 char buffer[512];
850 int i;
851 unsigned shortcuts;
852
853 state = WMCreatePLArray(NULL, NULL);
854
855 /* WM_WINDOW_ROLE */
856 str = getWindowRole(wwin->client_win);
857 if (!str)
858 appendStringInArray(state, "");
859 else {
860 appendStringInArray(state, str);
861 XFree(str);
862 }
863
864 /* WM_CLASS.instance */
865 appendStringInArray(state, wwin->wm_instance);
866
867 /* WM_CLASS.class */
868 appendStringInArray(state, wwin->wm_class);
869
870 /* WM_NAME */
871 if (wwin->flags.wm_name_changed)
872 appendStringInArray(state, "");
873 else
874 appendStringInArray(state, wwin->frame->name);
875
876 /* geometry */
877 snprintf(buffer, sizeof(buffer), "%i %i %i %i %i %i", wwin->frame_x, wwin->frame_y,
878 wwin->client.width, wwin->client.height,
879 wwin->flags.user_changed_width, wwin->flags.user_changed_height);
880 appendStringInArray(state, buffer);
881
882 /* state */
883 snprintf(buffer, sizeof(buffer), "%i %i %i", wwin->flags.miniaturized,
884 wwin->flags.shaded, wwin->flags.maximized);
885 appendStringInArray(state, buffer);
886
887 /* attributes */
888 tmp = makeAttributeState(wwin);
889 WMAddToPLArray(state, tmp);
890 WMReleasePropList(tmp);
891
892 /* workspace */
893 snprintf(buffer, sizeof(buffer), "%i", wwin->frame->workspace);
894 appendStringInArray(state, buffer);
895
896 /* app state (repeated for all windows of the app) */
897 tmp = makeAppState(wwin);
898 WMAddToPLArray(state, tmp);
899 WMReleasePropList(tmp);
900
901 /* shortcuts */
902 shortcuts = 0;
903 for (i = 0; i < MAX_WINDOW_SHORTCUTS; i++) {
904 if (scr->shortcutWindow[i] == wwin) {
905 shortcuts |= 1 << i;
906 }
907 }
908 snprintf(buffer, sizeof(buffer), "%ui", shortcuts);
909 appendStringInArray(tmp, buffer);
910
911 return state;
9007a657 dan1998-11-23 11:32:19 +0000912}
913
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200914static void smSaveYourselfPhase2Proc(SmcConn smc_conn, SmPointer client_data)
9007a657 dan1998-11-23 11:32:19 +0000915{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200916 SmProp props[4];
917 SmPropValue prop1val, prop2val, prop3val, prop4val;
918 char **argv = (char **)client_data;
919 int argc;
920 int i, j;
921 Bool ok = False;
922 char *statefile = NULL;
923 char *prefix;
924 Bool gsPrefix = False;
925 char *discardCmd = NULL;
926 time_t t;
927 WMPropList *state, *plState;
928 int len;
9007a657 dan1998-11-23 11:32:19 +0000929
930#ifdef DEBUG1
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200931 puts("received SaveYourselfPhase2 SM message");
9007a657 dan1998-11-23 11:32:19 +0000932#endif
933
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200934 /* save session state */
935
936 /* the file that will contain the state */
937 prefix = getenv("SM_SAVE_DIR");
938 if (!prefix) {
939 prefix = wusergnusteppath();
940 if (prefix)
941 gsPrefix = True;
942 }
943 if (!prefix) {
944 prefix = getenv("HOME");
945 }
946 if (!prefix)
947 prefix = ".";
948
949 len = strlen(prefix) + 64;
950 statefile = malloc(len);
951 if (!statefile) {
952 wwarning(_("out of memory while saving session state"));
953 goto fail;
954 }
955
956 t = time();
957 i = 0;
958 do {
959 if (gsPrefix)
960 snprintf(statefile, len, "%s/Library/WindowMaker/wmaker.%l%i.state", prefix, t, i);
961 else
962 snprintf(statefile, len, "%s/wmaker.%l%i.state", prefix, t, i);
963 i++;
964 } while (access(F_OK, statefile) != -1);
965
966 /* save the states of all windows we're managing */
967 state = WMCreatePLArray(NULL, NULL);
968
969 /*
970 * Format:
971 *
972 * state_file ::= dictionary with version_info ; state
973 * version_info ::= 'version' = '1';
974 * state ::= 'state' = array of screen_info
975 * screen_info ::= array of (screen number, window_info, window_info, ...)
976 * window_info ::=
977 */
978 for (i = 0; i < wScreenCount; i++) {
979 WScreen *scr;
980 WWindow *wwin;
981 char buf[32];
982 WMPropList *pscreen;
983
984 scr = wScreenWithNumber(i);
985
986 snprintf(buf, sizeof(buf), "%i", scr->screen);
987 pscreen = WMCreatePLArray(WMCreatePLString(buf), NULL);
988
989 wwin = scr->focused_window;
990 while (wwin) {
991 WMPropList *pwindow;
992
993 pwindow = makeClientState(wwin);
994 WMAddToPLArray(pscreen, pwindow);
995
996 wwin = wwin->prev;
997 }
998
999 WMAddToPLArray(state, pscreen);
1000 }
1001
1002 plState = WMCreatePLDictionary(WMCreatePLString("Version"),
1003 WMCreatePLString("1.0"), WMCreatePLString("Screens"), state, NULL);
1004
1005 WMWritePropListToFile(plState, statefile, False);
1006
1007 WMReleasePropList(plState);
1008
1009 /* set the remaining properties that we didn't set at
1010 * startup time */
1011
1012 for (argc = 0, i = 0; argv[i] != NULL; i++) {
1013 if (strcmp(argv[i], "-clientid") == 0 || strcmp(argv[i], "-restore") == 0) {
1014 i++;
1015 } else {
1016 argc++;
1017 }
1018 }
1019
1020 prop[0].name = SmRestartCommand;
1021 prop[0].type = SmLISTofARRAY8;
1022 prop[0].vals = malloc(sizeof(SmPropValue) * (argc + 4));
1023 prop[0].num_vals = argc + 4;
1024
1025 prop[1].name = SmCloneCommand;
1026 prop[1].type = SmLISTofARRAY8;
1027 prop[1].vals = malloc(sizeof(SmPropValue) * (argc));
1028 prop[1].num_vals = argc;
1029
1030 if (!prop[0].vals || !prop[1].vals) {
1031 wwarning(_("end of memory while saving session state"));
1032 goto fail;
1033 }
1034
1035 for (j = 0, i = 0; i < argc + 4; i++) {
1036 if (strcmp(argv[i], "-clientid") == 0 || strcmp(argv[i], "-restore") == 0) {
1037 i++;
1038 } else {
1039 prop[0].vals[j].value = argv[i];
1040 prop[0].vals[j].length = strlen(argv[i]);
1041 prop[1].vals[j].value = argv[i];
1042 prop[1].vals[j].length = strlen(argv[i]);
1043 j++;
1044 }
1045 }
1046 prop[0].vals[j].value = "-clientid";
1047 prop[0].vals[j].length = 9;
1048 j++;
1049 prop[0].vals[j].value = sClientID;
1050 prop[0].vals[j].length = strlen(sClientID);
1051 j++;
1052 prop[0].vals[j].value = "-restore";
1053 prop[0].vals[j].length = 11;
1054 j++;
1055 prop[0].vals[j].value = statefile;
1056 prop[0].vals[j].length = strlen(statefile);
1057
1058 {
1059 int len = strlen(statefile) + 8;
1060
1061 discardCmd = malloc(len);
1062 if (!discardCmd)
1063 goto fail;
1064 snprintf(discardCmd, len, "rm %s", statefile);
1065 }
1066 prop[2].name = SmDiscardCommand;
1067 prop[2].type = SmARRAY8;
1068 prop[2].vals[0] = discardCmd;
1069 prop[2].num_vals = 1;
1070
1071 SmcSetProperties(sSMCConn, 3, prop);
1072
1073 ok = True;
1074 fail:
1075 SmcSaveYourselfDone(smc_conn, ok);
1076
1077 if (prop[0].vals)
1078 wfree(prop[0].vals);
1079 if (prop[1].vals)
1080 wfree(prop[1].vals);
1081 if (discardCmd)
1082 wfree(discardCmd);
1083
1084 if (!ok) {
1085 remove(statefile);
1086 }
1087 if (statefile)
1088 wfree(statefile);
9007a657 dan1998-11-23 11:32:19 +00001089}
1090
9007a657 dan1998-11-23 11:32:19 +00001091static void
1092smSaveYourselfProc(SmcConn smc_conn, SmPointer client_data, int save_type,
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001093 Bool shutdown, int interact_style, Bool fast)
9007a657 dan1998-11-23 11:32:19 +00001094{
1095#ifdef DEBUG1
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001096 puts("received SaveYourself SM message");
9007a657 dan1998-11-23 11:32:19 +00001097#endif
1098
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001099 if (!SmcRequestSaveYourselfPhase2(smc_conn, smSaveYourselfPhase2Proc, client_data)) {
9007a657 dan1998-11-23 11:32:19 +00001100
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001101 SmcSaveYourselfDone(smc_conn, False);
1102 sWaitingPhase2 = False;
1103 } else {
9007a657 dan1998-11-23 11:32:19 +00001104#ifdef DEBUG1
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001105 puts("successfull request of SYS phase 2");
9007a657 dan1998-11-23 11:32:19 +00001106#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001107 sWaitingPhase2 = True;
1108 }
9007a657 dan1998-11-23 11:32:19 +00001109}
1110
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001111static void smDieProc(SmcConn smc_conn, SmPointer client_data)
9007a657 dan1998-11-23 11:32:19 +00001112{
1113#ifdef DEBUG1
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001114 puts("received Die SM message");
9007a657 dan1998-11-23 11:32:19 +00001115#endif
1116
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001117 wSessionDisconnectManager();
9007a657 dan1998-11-23 11:32:19 +00001118
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001119 Shutdown(WSExitMode, True);
9007a657 dan1998-11-23 11:32:19 +00001120}
1121
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001122static void smSaveCompleteProc(SmcConn smc_conn)
9007a657 dan1998-11-23 11:32:19 +00001123{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001124 /* it means that we can resume doing things that can change our state */
9007a657 dan1998-11-23 11:32:19 +00001125#ifdef DEBUG1
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001126 puts("received SaveComplete SM message");
9007a657 dan1998-11-23 11:32:19 +00001127#endif
1128}
1129
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001130static void smShutdownCancelledProc(SmcConn smc_conn, SmPointer client_data)
9007a657 dan1998-11-23 11:32:19 +00001131{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001132 if (sWaitingPhase2) {
9007a657 dan1998-11-23 11:32:19 +00001133
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001134 sWaitingPhase2 = False;
9007a657 dan1998-11-23 11:32:19 +00001135
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001136 SmcSaveYourselfDone(smc_conn, False);
1137 }
9007a657 dan1998-11-23 11:32:19 +00001138}
1139
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001140static void iceMessageProc(int fd, int mask, void *clientData)
9007a657 dan1998-11-23 11:32:19 +00001141{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001142 IceConn iceConn = (IceConn) clientData;
9007a657 dan1998-11-23 11:32:19 +00001143
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001144 IceProcessMessages(iceConn, NULL, NULL);
9007a657 dan1998-11-23 11:32:19 +00001145}
1146
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001147static void iceIOErrorHandler(IceConnection ice_conn)
9007a657 dan1998-11-23 11:32:19 +00001148{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001149 /* This is not fatal but can mean the session manager exited.
1150 * If the session manager exited normally we would get a
1151 * Die message, so this probably means an abnormal exit.
1152 * If the sm was the last client of session, then we'll die
1153 * anyway, otherwise we can continue doing our stuff.
1154 */
1155 wwarning(_("connection to the session manager was lost"));
1156 wSessionDisconnectManager();
9007a657 dan1998-11-23 11:32:19 +00001157}
1158
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001159void wSessionConnectManager(char **argv, int argc)
9007a657 dan1998-11-23 11:32:19 +00001160{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001161 IceConn iceConn;
1162 char *previous_id = NULL;
1163 char buffer[256];
1164 SmcCallbacks callbacks;
1165 unsigned long mask;
1166 char uid[32];
1167 char pid[32];
1168 SmProp props[4];
1169 SmPropValue prop1val, prop2val, prop3val, prop4val;
1170 char restartStyle;
1171 int i;
1172
1173 mask = SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask;
1174
1175 callbacks.save_yourself.callback = smSaveYourselfProc;
1176 callbacks.save_yourself.client_data = argv;
1177
1178 callbacks.die.callback = smDieProc;
1179 callbacks.die.client_data = NULL;
1180
1181 callbacks.save_complete.callback = smSaveCompleteProc;
1182 callbacks.save_complete.client_data = NULL;
1183
1184 callbacks.shutdown_cancelled.callback = smShutdownCancelledProc;
1185 callbacks.shutdown_cancelled.client_data = NULL;
1186
1187 for (i = 0; i < argc; i++) {
1188 if (strcmp(argv[i], "-clientid") == 0) {
1189 previous_id = argv[i + 1];
1190 break;
1191 }
1192 }
1193
1194 /* connect to the session manager */
1195 sSMCConn = SmcOpenConnection(NULL, NULL, SmProtoMajor, SmProtoMinor,
1196 mask, &callbacks, previous_id, &sClientID, 255, buffer);
1197 if (!sSMCConn) {
1198 return;
1199 }
9007a657 dan1998-11-23 11:32:19 +00001200#ifdef DEBUG1
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001201 puts("connected to the session manager");
9007a657 dan1998-11-23 11:32:19 +00001202#endif
1203
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001204 /* IceSetIOErrorHandler(iceIOErrorHandler); */
1205
1206 /* check for session manager clients */
1207 iceConn = SmcGetIceConnection(smcConn);
1208
1209 if (fcntl(IceConnectionNumber(iceConn), F_SETFD, FD_CLOEXEC) < 0) {
1210 wsyserror("error setting close-on-exec flag for ICE connection");
1211 }
1212
1213 sSMInputHandler = WMAddInputHandler(IceConnectionNumber(iceConn), WIReadMask, iceMessageProc, iceConn);
1214
1215 /* setup information about ourselves */
1216
1217 /* program name */
1218 prop1val.value = argv[0];
1219 prop1val.length = strlen(argv[0]);
1220 prop[0].name = SmProgram;
1221 prop[0].type = SmARRAY8;
1222 prop[0].num_vals = 1;
1223 prop[0].vals = &prop1val;
1224
1225 /* The XSMP doc from X11R6.1 says it contains the user name,
1226 * but every client implementation I saw places the uid # */
1227 snprintf(uid, sizeof(uid), "%i", getuid());
1228 prop2val.value = uid;
1229 prop2val.length = strlen(uid);
1230 prop[1].name = SmUserID;
1231 prop[1].type = SmARRAY8;
1232 prop[1].num_vals = 1;
1233 prop[1].vals = &prop2val;
1234
1235 /* Restart style. We should restart only if we were running when
1236 * the previous session finished. */
1237 restartStyle = SmRestartIfRunning;
1238 prop3val.value = &restartStyle;
1239 prop3val.length = 1;
1240 prop[2].name = SmRestartStyleHint;
1241 prop[2].type = SmCARD8;
1242 prop[2].num_vals = 1;
1243 prop[2].vals = &prop3val;
1244
1245 /* Our PID. Not required but might be usefull */
1246 snprintf(pid, sizeof(pid), "%i", getpid());
1247 prop4val.value = pid;
1248 prop4val.length = strlen(pid);
1249 prop[3].name = SmProcessID;
1250 prop[3].type = SmARRAY8;
1251 prop[3].num_vals = 1;
1252 prop[3].vals = &prop4val;
1253
1254 /* we'll set the rest of the hints later */
1255
1256 SmcSetProperties(sSMCConn, 4, props);
9007a657 dan1998-11-23 11:32:19 +00001257
1258}
1259
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001260void wSessionDisconnectManager(void)
9007a657 dan1998-11-23 11:32:19 +00001261{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001262 if (sSMCConn) {
1263 WMDeleteInputHandler(sSMInputHandler);
1264 sSMInputHandler = NULL;
9007a657 dan1998-11-23 11:32:19 +00001265
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001266 SmcCloseConnection(sSMCConn, 0, NULL);
1267 sSMCConn = NULL;
1268 }
9007a657 dan1998-11-23 11:32:19 +00001269}
1270
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001271void wSessionRequestShutdown(void)
9007a657 dan1998-11-23 11:32:19 +00001272{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001273 /* request a shutdown to the session manager */
1274 if (sSMCConn)
1275 SmcRequestSaveYourself(sSMCConn, SmSaveBoth, True, SmInteractStyleAny, False, True);
9007a657 dan1998-11-23 11:32:19 +00001276}
1277
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001278Bool wSessionIsManaged(void)
9007a657 dan1998-11-23 11:32:19 +00001279{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001280 return sSMCConn != NULL;
9007a657 dan1998-11-23 11:32:19 +00001281}
1282
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001283#endif /* !XSMP_ENABLED */