]> Dogcows Code - chaz/openbox/blob - openbox/session.c
don't save our state for SmSaveGlobal session saves, just Local ones
[chaz/openbox] / openbox / session.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3 session.c for the Openbox window manager
4 Copyright (c) 2003-2007 Dana Jansens
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 See the COPYING file for a copy of the GNU General Public License.
17 */
18
19 /* This session code is largely inspired by metacity code. */
20
21 #include "session.h"
22
23 struct _ObClient;
24
25 GList *session_saved_state = NULL;
26 gint session_desktop = -1;
27 gint session_num_desktops = 0;
28 gboolean session_desktop_layout_present = FALSE;
29 ObDesktopLayout session_desktop_layout;
30 GSList *session_desktop_names = NULL;
31
32 #ifndef USE_SM
33 void session_startup(gint argc, gchar **argv) {}
34 void session_shutdown(gboolean permanent) {}
35 GList* session_state_find(struct _ObClient *c) { return NULL; }
36 void session_request_logout(gboolean silent) {}
37 #else
38
39 #include "debug.h"
40 #include "openbox.h"
41 #include "client.h"
42 #include "prop.h"
43 #include "focus.h"
44 #include "gettext.h"
45 #include "parser/parse.h"
46
47 #include <time.h>
48 #include <errno.h>
49 #include <stdio.h>
50
51 #ifdef HAVE_UNISTD_H
52 # include <sys/types.h>
53 # include <unistd.h>
54 #endif
55
56 #include <X11/SM/SMlib.h>
57
58 #define SM_ERR_LEN 1024
59
60 static SmcConn sm_conn;
61 static gint sm_argc;
62 static gchar **sm_argv;
63
64 /* Data saved from the first level save yourself */
65 typedef struct {
66 ObClient *focus_client;
67 gint desktop;
68 } ObSMSaveData;
69
70 static gboolean session_connect();
71
72 static void session_load_file(const gchar *path);
73 static gboolean session_save_to_file(const ObSMSaveData *savedata);
74
75 static void session_setup_program();
76 static void session_setup_user();
77 static void session_setup_restart_style(gboolean restart);
78 static void session_setup_pid();
79 static void session_setup_priority();
80 static void session_setup_clone_command();
81 static void session_setup_restart_command();
82
83 static void sm_save_yourself(SmcConn conn, SmPointer data, gint save_type,
84 Bool shutdown, gint interact_style, Bool fast);
85 static void sm_die(SmcConn conn, SmPointer data);
86 static void sm_save_complete(SmcConn conn, SmPointer data);
87 static void sm_shutdown_cancelled(SmcConn conn, SmPointer data);
88
89 static gboolean session_state_cmp(ObSessionState *s, ObClient *c);
90 static void session_state_free(ObSessionState *state);
91
92 void session_startup(gint argc, gchar **argv)
93 {
94 gchar *dir;
95
96 if (!ob_sm_use) return;
97
98 sm_argc = argc;
99 sm_argv = argv;
100
101 dir = g_build_filename(parse_xdg_data_home_path(),
102 "openbox", "sessions", NULL);
103 if (!parse_mkdir_path(dir, 0700)) {
104 g_message(_("Unable to make directory \"%s\": %s"),
105 dir, g_strerror(errno));
106 }
107
108 if (ob_sm_save_file != NULL) {
109 if (ob_sm_restore) {
110 ob_debug_type(OB_DEBUG_SM, "Loading from session file %s\n",
111 ob_sm_save_file);
112 session_load_file(ob_sm_save_file);
113 }
114 } else {
115 gchar *filename;
116
117 /* this algo is from metacity */
118 filename = g_strdup_printf("%u-%u-%u.obs",
119 (guint)time(NULL),
120 (guint)getpid(),
121 g_random_int());
122 ob_sm_save_file = g_build_filename(dir, filename, NULL);
123 g_free(filename);
124 }
125
126 if (session_connect()) {
127 session_setup_program();
128 session_setup_user();
129 session_setup_restart_style(TRUE);
130 session_setup_pid();
131 session_setup_priority();
132 session_setup_clone_command();
133 }
134
135 g_free(dir);
136 }
137
138 void session_shutdown(gboolean permanent)
139 {
140 if (!ob_sm_use) return;
141
142 if (sm_conn) {
143 /* if permanent is true then we will change our session state so that
144 the SM won't run us again */
145 if (permanent)
146 session_setup_restart_style(FALSE);
147
148 SmcCloseConnection(sm_conn, 0, NULL);
149
150 while (session_saved_state) {
151 session_state_free(session_saved_state->data);
152 session_saved_state = g_list_delete_link(session_saved_state,
153 session_saved_state);
154 }
155 }
156 }
157
158 /*! Connect to the session manager and set up our callback functions */
159 static gboolean session_connect()
160 {
161 SmcCallbacks cb;
162 gchar *oldid;
163 gchar sm_err[SM_ERR_LEN];
164
165 /* set up our callback functions */
166 cb.save_yourself.callback = sm_save_yourself;
167 cb.save_yourself.client_data = NULL;
168 cb.die.callback = sm_die;
169 cb.die.client_data = NULL;
170 cb.save_complete.callback = sm_save_complete;
171 cb.save_complete.client_data = NULL;
172 cb.shutdown_cancelled.callback = sm_shutdown_cancelled;
173 cb.shutdown_cancelled.client_data = NULL;
174
175 /* connect to the server */
176 oldid = ob_sm_id;
177 ob_debug_type(OB_DEBUG_SM, "Connecting to SM with id: %s\n",
178 oldid ? oldid : "(null)");
179 sm_conn = SmcOpenConnection(NULL, NULL, 1, 0,
180 SmcSaveYourselfProcMask |
181 SmcDieProcMask |
182 SmcSaveCompleteProcMask |
183 SmcShutdownCancelledProcMask,
184 &cb, oldid, &ob_sm_id,
185 SM_ERR_LEN-1, sm_err);
186 g_free(oldid);
187 ob_debug_type(OB_DEBUG_SM, "Connected to SM with id: %s\n", ob_sm_id);
188 if (sm_conn == NULL)
189 ob_debug("Failed to connect to session manager: %s\n", sm_err);
190 return sm_conn != NULL;
191 }
192
193 static void session_setup_program()
194 {
195 SmPropValue vals = {
196 .value = sm_argv[0],
197 .length = strlen(sm_argv[0]) + 1
198 };
199 SmProp prop = {
200 .name = g_strdup(SmProgram),
201 .type = g_strdup(SmARRAY8),
202 .num_vals = 1,
203 .vals = &vals
204 };
205 SmProp *list = &prop;
206 ob_debug_type(OB_DEBUG_SM, "Setting program: %s\n", sm_argv[0]);
207 SmcSetProperties(sm_conn, 1, &list);
208 g_free(prop.name);
209 g_free(prop.type);
210 }
211
212 static void session_setup_user()
213 {
214 char *user = g_strdup(g_get_user_name());
215
216 SmPropValue vals = {
217 .value = user,
218 .length = strlen(user) + 1
219 };
220 SmProp prop = {
221 .name = g_strdup(SmUserID),
222 .type = g_strdup(SmARRAY8),
223 .num_vals = 1,
224 .vals = &vals
225 };
226 SmProp *list = &prop;
227 ob_debug_type(OB_DEBUG_SM, "Setting user: %s\n", user);
228 SmcSetProperties(sm_conn, 1, &list);
229 g_free(prop.name);
230 g_free(prop.type);
231 g_free(user);
232 }
233
234 static void session_setup_restart_style(gboolean restart)
235 {
236 gchar restart_hint = restart ? SmRestartImmediately : SmRestartIfRunning;
237
238 SmPropValue vals = {
239 .value = &restart_hint,
240 .length = 1
241 };
242 SmProp prop = {
243 .name = g_strdup(SmRestartStyleHint),
244 .type = g_strdup(SmCARD8),
245 .num_vals = 1,
246 .vals = &vals
247 };
248 SmProp *list = &prop;
249 ob_debug_type(OB_DEBUG_SM, "Setting restart: %d\n", restart);
250 SmcSetProperties(sm_conn, 1, &list);
251 g_free(prop.name);
252 g_free(prop.type);
253 }
254
255 static void session_setup_pid()
256 {
257 gchar *pid = g_strdup_printf("%ld", (glong) getpid());
258
259 SmPropValue vals = {
260 .value = pid,
261 .length = strlen(pid) + 1
262 };
263 SmProp prop = {
264 .name = g_strdup(SmProcessID),
265 .type = g_strdup(SmARRAY8),
266 .num_vals = 1,
267 .vals = &vals
268 };
269 SmProp *list = &prop;
270 ob_debug_type(OB_DEBUG_SM, "Setting pid: %s\n", pid);
271 SmcSetProperties(sm_conn, 1, &list);
272 g_free(prop.name);
273 g_free(prop.type);
274 g_free(pid);
275 }
276
277 /*! This is a gnome-session-manager extension */
278 static void session_setup_priority()
279 {
280 gchar priority = 20; /* 20 is a lower prioity to run before other apps */
281
282 SmPropValue vals = {
283 .value = &priority,
284 .length = 1
285 };
286 SmProp prop = {
287 .name = g_strdup("_GSM_Priority"),
288 .type = g_strdup(SmCARD8),
289 .num_vals = 1,
290 .vals = &vals
291 };
292 SmProp *list = &prop;
293 ob_debug_type(OB_DEBUG_SM, "Setting priority: %d\n", priority);
294 SmcSetProperties(sm_conn, 1, &list);
295 g_free(prop.name);
296 g_free(prop.type);
297 }
298
299 static void session_setup_clone_command()
300 {
301 gint i;
302
303 SmPropValue *vals = g_new(SmPropValue, sm_argc);
304 SmProp prop = {
305 .name = g_strdup(SmCloneCommand),
306 .type = g_strdup(SmLISTofARRAY8),
307 .num_vals = sm_argc,
308 .vals = vals
309 };
310 SmProp *list = &prop;
311
312 ob_debug_type(OB_DEBUG_SM, "Setting clone command: (%d)\n", sm_argc);
313 for (i = 0; i < sm_argc; ++i) {
314 vals[i].value = sm_argv[i];
315 vals[i].length = strlen(sm_argv[i]) + 1;
316 ob_debug_type(OB_DEBUG_SM, " %s\n", vals[i].value);
317 }
318
319 SmcSetProperties(sm_conn, 1, &list);
320 g_free(prop.name);
321 g_free(prop.type);
322 g_free(vals);
323 }
324
325 static void session_setup_restart_command()
326 {
327 gint i;
328
329 SmPropValue *vals = g_new(SmPropValue, sm_argc + 4);
330 SmProp prop = {
331 .name = g_strdup(SmRestartCommand),
332 .type = g_strdup(SmLISTofARRAY8),
333 .num_vals = sm_argc + 4,
334 .vals = vals
335 };
336 SmProp *list = &prop;
337
338 ob_debug_type(OB_DEBUG_SM, "Setting restart command: (%d)\n", sm_argc+4);
339 for (i = 0; i < sm_argc; ++i) {
340 vals[i].value = sm_argv[i];
341 vals[i].length = strlen(sm_argv[i]) + 1;
342 ob_debug_type(OB_DEBUG_SM, " %s\n", vals[i].value);
343 }
344
345 vals[i].value = g_strdup("--sm-client-id");
346 vals[i].length = strlen("--sm-client-id") + 1;
347 vals[i+1].value = ob_sm_id;
348 vals[i+1].length = strlen(ob_sm_id) + 1;
349 ob_debug_type(OB_DEBUG_SM, " %s\n", vals[i].value);
350 ob_debug_type(OB_DEBUG_SM, " %s\n", vals[i+1].value);
351
352 vals[i+2].value = g_strdup("--sm-save-file");
353 vals[i+2].length = strlen("--sm-save-file") + 1;
354 vals[i+3].value = ob_sm_save_file;
355 vals[i+3].length = strlen(ob_sm_save_file) + 1;
356 ob_debug_type(OB_DEBUG_SM, " %s\n", vals[i+2].value);
357 ob_debug_type(OB_DEBUG_SM, " %s\n", vals[i+3].value);
358
359 SmcSetProperties(sm_conn, 1, &list);
360 g_free(prop.name);
361 g_free(prop.type);
362 g_free(vals[i].value);
363 g_free(vals[i+2].value);
364 g_free(vals);
365 }
366
367 static ObSMSaveData *sm_save_get_data()
368 {
369 ObSMSaveData *savedata = g_new0(ObSMSaveData, 1);
370 /* save the active desktop and client.
371 we don't bother to preemptively save the other desktop state like
372 number and names of desktops, cuz those shouldn't be changing during
373 the save.. */
374 savedata->focus_client = focus_client;
375 savedata->desktop = screen_desktop;
376 return savedata;
377 }
378
379 static void sm_save_yourself_2(SmcConn conn, SmPointer data)
380 {
381 gboolean success;
382 ObSMSaveData *savedata = data;
383
384 /* save the current state */
385 ob_debug_type(OB_DEBUG_SM, "Session save phase 2 requested\n");
386 ob_debug_type(OB_DEBUG_SM,
387 " Saving session to file '%s'\n", ob_sm_save_file);
388 if (savedata == NULL)
389 savedata = sm_save_get_data();
390 success = session_save_to_file(savedata);
391 g_free(savedata);
392
393 /* tell the session manager how to restore this state */
394 if (success) session_setup_restart_command();
395
396 ob_debug_type(OB_DEBUG_SM, "Saving is done (success = %d)\n", success);
397 SmcSaveYourselfDone(conn, success);
398 }
399
400
401 static void sm_save_yourself(SmcConn conn, SmPointer data, gint save_type,
402 Bool shutdown, gint interact_style, Bool fast)
403 {
404 ObSMSaveData *savedata = NULL;
405 gchar *vendor;
406
407 #ifdef DEBUG
408 {
409 const gchar *sname =
410 (save_type == SmSaveLocal ? "SmSaveLocal" :
411 (save_type == SmSaveGlobal ? "SmSaveGlobal" :
412 (save_type == SmSaveBoth ? "SmSaveBoth" : "INVALID!!")));
413 ob_debug_type(OB_DEBUG_SM, "Session save requested, type %s\n", sname);
414 }
415 #endif
416
417 if (save_type == SmSaveGlobal) {
418 /* we have no data to save. we only store state to get back to where
419 we were, we don't keep open writable files or anything */
420 SmcSaveYourselfDone(conn, TRUE);
421 return;
422 }
423
424 vendor = SmcVendor(sm_conn);
425 ob_debug_type(OB_DEBUG_SM, "Session manager's vendor: %s\n", vendor);
426
427 if (!strcmp(vendor, "KDE")) {
428 /* ksmserver guarantees that phase 1 will complete before allowing any
429 clients interaction, so we can save this sanely here before they
430 get messed up from interaction */
431 savedata = sm_save_get_data();
432 }
433 free(vendor);
434
435 if (!SmcRequestSaveYourselfPhase2(conn, sm_save_yourself_2, savedata)) {
436 ob_debug_type(OB_DEBUG_SM, "Requst for phase 2 failed\n");
437 g_free(savedata);
438 SmcSaveYourselfDone(conn, FALSE);
439 }
440 }
441
442 static void sm_die(SmcConn conn, SmPointer data)
443 {
444 ob_debug_type(OB_DEBUG_SM, "Die requested\n");
445 ob_exit(0);
446 }
447
448 static void sm_save_complete(SmcConn conn, SmPointer data)
449 {
450 ob_debug_type(OB_DEBUG_SM, "Save complete\n");
451 }
452
453 static void sm_shutdown_cancelled(SmcConn conn, SmPointer data)
454 {
455 ob_debug_type(OB_DEBUG_SM, "Shutdown cancelled\n");
456 }
457
458 static gboolean session_save_to_file(const ObSMSaveData *savedata)
459 {
460 FILE *f;
461 GList *it;
462 gboolean success = TRUE;
463
464 f = fopen(ob_sm_save_file, "w");
465 if (!f) {
466 success = FALSE;
467 g_message(_("Unable to save the session to \"%s\": %s"),
468 ob_sm_save_file, g_strerror(errno));
469 } else {
470 fprintf(f, "<?xml version=\"1.0\"?>\n\n");
471 fprintf(f, "<openbox_session>\n\n");
472
473 fprintf(f, "<desktop>%d</desktop>\n", savedata->desktop);
474
475 fprintf(f, "<numdesktops>%d</numdesktops>\n", screen_num_desktops);
476
477 fprintf(f, "<desktoplayout>\n");
478 fprintf(f, " <orientation>%d</orientation>\n",
479 screen_desktop_layout.orientation);
480 fprintf(f, " <startcorner>%d</startcorner>\n",
481 screen_desktop_layout.start_corner);
482 fprintf(f, " <columns>%d</columns>\n",
483 screen_desktop_layout.columns);
484 fprintf(f, " <rows>%d</rows>\n",
485 screen_desktop_layout.rows);
486 fprintf(f, "</desktoplayout>\n");
487
488 if (screen_desktop_names) {
489 gint i;
490
491 fprintf(f, "<desktopnames>\n");
492 for (i = 0; screen_desktop_names[i]; ++i)
493 fprintf(f, " <name>%s</name>\n", screen_desktop_names[i]);
494 fprintf(f, "</desktopnames>\n");
495 }
496
497 /* they are ordered top to bottom in stacking order */
498 for (it = stacking_list; it; it = g_list_next(it)) {
499 gint prex, prey, prew, preh;
500 ObClient *c;
501 gchar *t;
502
503 if (WINDOW_IS_CLIENT(it->data))
504 c = WINDOW_AS_CLIENT(it->data);
505 else
506 continue;
507
508 if (!client_normal(c))
509 continue;
510
511 if (!c->sm_client_id) {
512 ob_debug_type(OB_DEBUG_SM, "Client %s does not have a "
513 "session id set\n",
514 c->title);
515 if (!c->wm_command) {
516 ob_debug_type(OB_DEBUG_SM, "Client %s does not have an "
517 "oldskool wm_command set either. We won't "
518 "be saving its data\n",
519 c->title);
520 continue;
521 }
522 }
523
524 ob_debug_type(OB_DEBUG_SM, "Saving state for client %s\n",
525 c->title);
526
527 prex = c->area.x;
528 prey = c->area.y;
529 prew = c->area.width;
530 preh = c->area.height;
531 if (c->fullscreen) {
532 prex = c->pre_fullscreen_area.x;
533 prey = c->pre_fullscreen_area.x;
534 prew = c->pre_fullscreen_area.width;
535 preh = c->pre_fullscreen_area.height;
536 }
537 if (c->max_horz) {
538 prex = c->pre_max_area.x;
539 prew = c->pre_max_area.width;
540 }
541 if (c->max_vert) {
542 prey = c->pre_max_area.y;
543 preh = c->pre_max_area.height;
544 }
545
546 if (c->sm_client_id)
547 fprintf(f, "<window id=\"%s\">\n", c->sm_client_id);
548 else
549 fprintf(f, "<window command=\"%s\">\n", c->wm_command);
550
551 t = g_markup_escape_text(c->name, -1);
552 fprintf(f, "\t<name>%s</name>\n", t);
553 g_free(t);
554
555 t = g_markup_escape_text(c->class, -1);
556 fprintf(f, "\t<class>%s</class>\n", t);
557 g_free(t);
558
559 t = g_markup_escape_text(c->role, -1);
560 fprintf(f, "\t<role>%s</role>\n", t);
561 g_free(t);
562
563 fprintf(f, "\t<windowtype>%d</windowtype>\n", c->type);
564
565 fprintf(f, "\t<desktop>%d</desktop>\n", c->desktop);
566 fprintf(f, "\t<x>%d</x>\n", prex);
567 fprintf(f, "\t<y>%d</y>\n", prey);
568 fprintf(f, "\t<width>%d</width>\n", prew);
569 fprintf(f, "\t<height>%d</height>\n", preh);
570 if (c->shaded)
571 fprintf(f, "\t<shaded />\n");
572 if (c->iconic)
573 fprintf(f, "\t<iconic />\n");
574 if (c->skip_pager)
575 fprintf(f, "\t<skip_pager />\n");
576 if (c->skip_taskbar)
577 fprintf(f, "\t<skip_taskbar />\n");
578 if (c->fullscreen)
579 fprintf(f, "\t<fullscreen />\n");
580 if (c->above)
581 fprintf(f, "\t<above />\n");
582 if (c->below)
583 fprintf(f, "\t<below />\n");
584 if (c->max_horz)
585 fprintf(f, "\t<max_horz />\n");
586 if (c->max_vert)
587 fprintf(f, "\t<max_vert />\n");
588 if (c->undecorated)
589 fprintf(f, "\t<undecorated />\n");
590 if (savedata->focus_client == c)
591 fprintf(f, "\t<focused />\n");
592 fprintf(f, "</window>\n\n");
593 }
594
595 fprintf(f, "</openbox_session>\n");
596
597 if (fflush(f)) {
598 success = FALSE;
599 g_message(_("Error while saving the session to \"%s\": %s"),
600 ob_sm_save_file, g_strerror(errno));
601 }
602 fclose(f);
603 }
604
605 return success;
606 }
607
608 static void session_state_free(ObSessionState *state)
609 {
610 if (state) {
611 g_free(state->id);
612 g_free(state->command);
613 g_free(state->name);
614 g_free(state->class);
615 g_free(state->role);
616
617 g_free(state);
618 }
619 }
620
621 static gboolean session_state_cmp(ObSessionState *s, ObClient *c)
622 {
623 ob_debug_type(OB_DEBUG_SM, "Comparing client against saved state: \n");
624 ob_debug_type(OB_DEBUG_SM, " client id: %s \n", c->sm_client_id);
625 ob_debug_type(OB_DEBUG_SM, " client name: %s \n", c->name);
626 ob_debug_type(OB_DEBUG_SM, " client class: %s \n", c->class);
627 ob_debug_type(OB_DEBUG_SM, " client role: %s \n", c->role);
628 ob_debug_type(OB_DEBUG_SM, " client type: %d \n", c->type);
629 ob_debug_type(OB_DEBUG_SM, " client command: %s \n",
630 c->wm_command ? c->wm_command : "(null)");
631 ob_debug_type(OB_DEBUG_SM, " state id: %s \n", s->id);
632 ob_debug_type(OB_DEBUG_SM, " state name: %s \n", s->name);
633 ob_debug_type(OB_DEBUG_SM, " state class: %s \n", s->class);
634 ob_debug_type(OB_DEBUG_SM, " state role: %s \n", s->role);
635 ob_debug_type(OB_DEBUG_SM, " state type: %d \n", s->type);
636 ob_debug_type(OB_DEBUG_SM, " state command: %s \n",
637 s->command ? s->command : "(null)");
638
639 if ((c->sm_client_id && s->id && !strcmp(c->sm_client_id, s->id)) ||
640 (c->wm_command && s->command && !strcmp(c->wm_command, s->command)))
641 {
642 return (!strcmp(s->name, c->name) &&
643 !strcmp(s->class, c->class) &&
644 !strcmp(s->role, c->role) &&
645 /* the check for type is to catch broken clients, like
646 firefox, which open a different window on startup
647 with the same info as the one we saved. only do this
648 check for old windows that dont use xsmp, others should
649 know better ! */
650 (!s->command || c->type == s->type));
651 }
652 return FALSE;
653 }
654
655 GList* session_state_find(ObClient *c)
656 {
657 GList *it;
658
659 for (it = session_saved_state; it; it = g_list_next(it)) {
660 ObSessionState *s = it->data;
661 if (!s->matched && session_state_cmp(s, c)) {
662 s->matched = TRUE;
663 break;
664 }
665 }
666 return it;
667 }
668
669 static void session_load_file(const gchar *path)
670 {
671 xmlDocPtr doc;
672 xmlNodePtr node, n, m;
673 GList *it, *inext;
674
675 if (!parse_load(path, "openbox_session", &doc, &node))
676 return;
677
678 if ((n = parse_find_node("desktop", node->children)))
679 session_desktop = parse_int(doc, n);
680
681 if ((n = parse_find_node("numdesktops", node->children)))
682 session_num_desktops = parse_int(doc, n);
683
684 if ((n = parse_find_node("desktoplayout", node->children))) {
685 /* make sure they are all there for it to be valid */
686 if ((m = parse_find_node("orientation", n->children)))
687 session_desktop_layout.orientation = parse_int(doc, m);
688 if (m && (m = parse_find_node("startcorner", n->children)))
689 session_desktop_layout.start_corner = parse_int(doc, m);
690 if (m && (m = parse_find_node("columns", n->children)))
691 session_desktop_layout.columns = parse_int(doc, m);
692 if (m && (m = parse_find_node("rows", n->children)))
693 session_desktop_layout.rows = parse_int(doc, m);
694 session_desktop_layout_present = m != NULL;
695 }
696
697 if ((n = parse_find_node("desktopnames", node->children))) {
698 for (m = parse_find_node("name", n->children); m;
699 m = parse_find_node("name", m->next))
700 {
701 session_desktop_names = g_slist_append(session_desktop_names,
702 parse_string(doc, m));
703 }
704 }
705
706 for (node = parse_find_node("window", node->children); node != NULL;
707 node = parse_find_node("window", node->next))
708 {
709 ObSessionState *state;
710
711 state = g_new0(ObSessionState, 1);
712
713 if (!parse_attr_string("id", node, &state->id))
714 if (!parse_attr_string("command", node, &state->command))
715 goto session_load_bail;
716 if (!(n = parse_find_node("name", node->children)))
717 goto session_load_bail;
718 state->name = parse_string(doc, n);
719 if (!(n = parse_find_node("class", node->children)))
720 goto session_load_bail;
721 state->class = parse_string(doc, n);
722 if (!(n = parse_find_node("role", node->children)))
723 goto session_load_bail;
724 state->role = parse_string(doc, n);
725 if (!(n = parse_find_node("windowtype", node->children)))
726 goto session_load_bail;
727 state->type = parse_int(doc, n);
728 if (!(n = parse_find_node("desktop", node->children)))
729 goto session_load_bail;
730 state->desktop = parse_int(doc, n);
731 if (!(n = parse_find_node("x", node->children)))
732 goto session_load_bail;
733 state->x = parse_int(doc, n);
734 if (!(n = parse_find_node("y", node->children)))
735 goto session_load_bail;
736 state->y = parse_int(doc, n);
737 if (!(n = parse_find_node("width", node->children)))
738 goto session_load_bail;
739 state->w = parse_int(doc, n);
740 if (!(n = parse_find_node("height", node->children)))
741 goto session_load_bail;
742 state->h = parse_int(doc, n);
743
744 state->shaded =
745 parse_find_node("shaded", node->children) != NULL;
746 state->iconic =
747 parse_find_node("iconic", node->children) != NULL;
748 state->skip_pager =
749 parse_find_node("skip_pager", node->children) != NULL;
750 state->skip_taskbar =
751 parse_find_node("skip_taskbar", node->children) != NULL;
752 state->fullscreen =
753 parse_find_node("fullscreen", node->children) != NULL;
754 state->above =
755 parse_find_node("above", node->children) != NULL;
756 state->below =
757 parse_find_node("below", node->children) != NULL;
758 state->max_horz =
759 parse_find_node("max_horz", node->children) != NULL;
760 state->max_vert =
761 parse_find_node("max_vert", node->children) != NULL;
762 state->undecorated =
763 parse_find_node("undecorated", node->children) != NULL;
764 state->focused =
765 parse_find_node("focused", node->children) != NULL;
766
767 /* save this. they are in the file in stacking order, so preserve
768 that order here */
769 session_saved_state = g_list_append(session_saved_state, state);
770 continue;
771
772 session_load_bail:
773 session_state_free(state);
774 }
775
776 /* Remove any duplicates. This means that if two windows (or more) are
777 saved with the same session state, we won't restore a session for any
778 of them because we don't know what window to put what on. AHEM FIREFOX.
779
780 This is going to be an O(2^n) kind of operation unfortunately.
781 */
782 for (it = session_saved_state; it; it = inext) {
783 GList *jt, *jnext;
784 gboolean founddup = FALSE;
785 ObSessionState *s1 = it->data;
786
787 inext = g_list_next(it);
788
789 for (jt = g_list_next(it); jt; jt = jnext) {
790 ObSessionState *s2 = jt->data;
791 gboolean match;
792
793 jnext = g_list_next(jt);
794
795 if (s1->id && s2->id)
796 match = strcmp(s1->id, s2->id) == 0;
797 else if (s1->command && s2->command)
798 match = strcmp(s1->command, s2->command) == 0;
799 else
800 match = FALSE;
801
802 if (match &&
803 !strcmp(s1->name, s2->name) &&
804 !strcmp(s1->class, s2->class) &&
805 !strcmp(s1->role, s2->role))
806 {
807 session_state_free(s2);
808 session_saved_state =
809 g_list_delete_link(session_saved_state, jt);
810 founddup = TRUE;
811 }
812 }
813
814 if (founddup) {
815 session_state_free(s1);
816 session_saved_state = g_list_delete_link(session_saved_state, it);
817 }
818 }
819
820 xmlFreeDoc(doc);
821 }
822
823 void session_request_logout(gboolean silent)
824 {
825 if (sm_conn) {
826 SmcRequestSaveYourself(sm_conn,
827 SmSaveGlobal,
828 TRUE, /* logout */
829 (silent ?
830 SmInteractStyleNone : SmInteractStyleAny),
831 TRUE, /* if false, with GSM, it shows the old
832 logout prompt */
833 TRUE); /* global */
834 }
835 else
836 g_message(_("Not connected to a session manager"));
837 }
838
839 #endif
This page took 0.073601 seconds and 5 git commands to generate.