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