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