1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 session.c for the Openbox window manager
4 Copyright (c) 2003-2007 Dana Jansens
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.
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.
16 See the COPYING file for a copy of the GNU General Public License.
19 /* This session code is largely inspired by metacity code. */
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
;
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
; }
46 #include "obt/paths.h"
53 # include <sys/types.h>
57 #include <X11/SM/SMlib.h>
59 #define SM_ERR_LEN 1024
61 static SmcConn sm_conn
;
63 static gchar
**sm_argv
;
65 /* Data saved from the first level save yourself */
67 ObClient
*focus_client
;
71 static gboolean
session_connect();
73 static void session_load_file(const gchar
*path
);
74 static gboolean
session_save_to_file(const ObSMSaveData
*savedata
);
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();
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
);
90 static gboolean
session_state_cmp(ObSessionState
*s
, ObClient
*c
);
91 static void session_state_free(ObSessionState
*state
);
93 void session_startup(gint argc
, gchar
**argv
)
98 if (!ob_sm_use
) return;
104 dir
= g_build_filename(obt_paths_cache_home(p
),
105 "openbox", "sessions", NULL
);
106 obt_paths_unref(p
), p
= NULL
;
108 if (!obt_paths_mkdir_path(dir
, 0700)) {
109 g_message(_("Unable to make directory \"%s\": %s"),
110 dir
, g_strerror(errno
));
113 if (ob_sm_save_file
!= NULL
) {
115 ob_debug_type(OB_DEBUG_SM
, "Loading from session file %s",
117 session_load_file(ob_sm_save_file
);
122 /* this algo is from metacity */
123 filename
= g_strdup_printf("%u-%u-%u.obs",
127 ob_sm_save_file
= g_build_filename(dir
, filename
, NULL
);
131 if (session_connect()) {
132 session_setup_program();
133 session_setup_user();
134 session_setup_restart_style(TRUE
);
136 session_setup_priority();
137 session_setup_clone_command();
143 void session_shutdown(gboolean permanent
)
145 if (!ob_sm_use
) return;
148 /* if permanent is true then we will change our session state so that
149 the SM won't run us again */
151 session_setup_restart_style(FALSE
);
153 SmcCloseConnection(sm_conn
, 0, NULL
);
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
);
163 gboolean
session_connected(void)
168 /*! Connect to the session manager and set up our callback functions */
169 static gboolean
session_connect(void)
173 gchar sm_err
[SM_ERR_LEN
];
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
;
185 /* connect to the server */
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
|
192 SmcSaveCompleteProcMask
|
193 SmcShutdownCancelledProcMask
,
194 &cb
, oldid
, &ob_sm_id
,
195 SM_ERR_LEN
-1, sm_err
);
197 ob_debug_type(OB_DEBUG_SM
, "Connected to SM with id: %s", ob_sm_id
);
199 ob_debug("Failed to connect to session manager: %s", sm_err
);
200 return sm_conn
!= NULL
;
203 static void session_setup_program(void)
207 .length
= strlen(sm_argv
[0]) + 1
210 .name
= g_strdup(SmProgram
),
211 .type
= g_strdup(SmARRAY8
),
215 SmProp
*list
= &prop
;
216 ob_debug_type(OB_DEBUG_SM
, "Setting program: %s", sm_argv
[0]);
217 SmcSetProperties(sm_conn
, 1, &list
);
222 static void session_setup_user(void)
224 char *user
= g_strdup(g_get_user_name());
228 .length
= strlen(user
) + 1
231 .name
= g_strdup(SmUserID
),
232 .type
= g_strdup(SmARRAY8
),
236 SmProp
*list
= &prop
;
237 ob_debug_type(OB_DEBUG_SM
, "Setting user: %s", user
);
238 SmcSetProperties(sm_conn
, 1, &list
);
244 static void session_setup_restart_style(gboolean restart
)
246 gchar restart_hint
= restart
? SmRestartImmediately
: SmRestartIfRunning
;
249 .value
= &restart_hint
,
253 .name
= g_strdup(SmRestartStyleHint
),
254 .type
= g_strdup(SmCARD8
),
258 SmProp
*list
= &prop
;
259 ob_debug_type(OB_DEBUG_SM
, "Setting restart: %d", restart
);
260 SmcSetProperties(sm_conn
, 1, &list
);
265 static void session_setup_pid(void)
267 gchar
*pid
= g_strdup_printf("%ld", (glong
) getpid());
271 .length
= strlen(pid
) + 1
274 .name
= g_strdup(SmProcessID
),
275 .type
= g_strdup(SmARRAY8
),
279 SmProp
*list
= &prop
;
280 ob_debug_type(OB_DEBUG_SM
, "Setting pid: %s", pid
);
281 SmcSetProperties(sm_conn
, 1, &list
);
287 /*! This is a gnome-session-manager extension */
288 static void session_setup_priority(void)
290 gchar priority
= 20; /* 20 is a lower prioity to run before other apps */
297 .name
= g_strdup("_GSM_Priority"),
298 .type
= g_strdup(SmCARD8
),
302 SmProp
*list
= &prop
;
303 ob_debug_type(OB_DEBUG_SM
, "Setting priority: %d", priority
);
304 SmcSetProperties(sm_conn
, 1, &list
);
309 static void session_setup_clone_command(void)
313 SmPropValue
*vals
= g_new(SmPropValue
, sm_argc
);
315 .name
= g_strdup(SmCloneCommand
),
316 .type
= g_strdup(SmLISTofARRAY8
),
320 SmProp
*list
= &prop
;
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
);
329 SmcSetProperties(sm_conn
, 1, &list
);
335 static void session_setup_restart_command(void)
339 SmPropValue
*vals
= g_new(SmPropValue
, sm_argc
+ 4);
341 .name
= g_strdup(SmRestartCommand
),
342 .type
= g_strdup(SmLISTofARRAY8
),
343 .num_vals
= sm_argc
+ 4,
346 SmProp
*list
= &prop
;
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
);
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
);
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
);
369 SmcSetProperties(sm_conn
, 1, &list
);
372 g_free(vals
[i
].value
);
373 g_free(vals
[i
+2].value
);
377 static ObSMSaveData
*sm_save_get_data(void)
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
384 savedata
->focus_client
= focus_client
;
385 savedata
->desktop
= screen_desktop
;
389 static void sm_save_yourself_2(SmcConn conn
, SmPointer data
)
392 ObSMSaveData
*savedata
= data
;
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
);
403 /* tell the session manager how to restore this state */
404 if (success
) session_setup_restart_command();
406 ob_debug_type(OB_DEBUG_SM
, "Saving is done (success = %d)", success
);
407 SmcSaveYourselfDone(conn
, success
);
410 static void sm_save_yourself(SmcConn conn
, SmPointer data
, gint save_type
,
411 Bool shutdown
, gint interact_style
, Bool fast
)
413 ObSMSaveData
*savedata
= NULL
;
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
);
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
);
433 vendor
= SmcVendor(sm_conn
);
434 ob_debug_type(OB_DEBUG_SM
, "Session manager's vendor: %s", vendor
);
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();
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
);
451 static void sm_die(SmcConn conn
, SmPointer data
)
453 ob_debug_type(OB_DEBUG_SM
, "Die requested");
457 static void sm_save_complete(SmcConn conn
, SmPointer data
)
459 ob_debug_type(OB_DEBUG_SM
, "Save complete");
462 static void sm_shutdown_cancelled(SmcConn conn
, SmPointer data
)
464 ob_debug_type(OB_DEBUG_SM
, "Shutdown cancelled");
467 static gboolean
session_save_to_file(const ObSMSaveData
*savedata
)
471 gboolean success
= TRUE
;
473 f
= fopen(ob_sm_save_file
, "w");
476 g_message(_("Unable to save the session to \"%s\": %s"),
477 ob_sm_save_file
, g_strerror(errno
));
479 fprintf(f
, "<?xml version=\"1.0\"?>\n\n");
480 fprintf(f
, "<openbox_session>\n\n");
482 fprintf(f
, "<desktop>%d</desktop>\n", savedata
->desktop
);
484 fprintf(f
, "<numdesktops>%d</numdesktops>\n", screen_num_desktops
);
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");
497 if (screen_desktop_names
) {
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
);
507 fprintf(f
, "</desktopnames>\n");
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
;
516 if (WINDOW_IS_CLIENT(it
->data
))
517 c
= WINDOW_AS_CLIENT(it
->data
);
521 if (!client_normal(c
))
524 if (!c
->sm_client_id
) {
525 ob_debug_type(OB_DEBUG_SM
, "Client %s does not have a "
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",
537 ob_debug_type(OB_DEBUG_SM
, "Saving state for client %s",
542 prew
= c
->area
.width
;
543 preh
= c
->area
.height
;
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
;
551 prex
= c
->pre_max_area
.x
;
552 prew
= c
->pre_max_area
.width
;
555 prey
= c
->pre_max_area
.y
;
556 preh
= c
->pre_max_area
.height
;
560 fprintf(f
, "<window id=\"%s\">\n", c
->sm_client_id
);
562 t
= g_markup_escape_text(c
->wm_command
, -1);
563 fprintf(f
, "<window command=\"%s\">\n", t
);
567 t
= g_markup_escape_text(c
->name
, -1);
568 fprintf(f
, "\t<name>%s</name>\n", t
);
571 t
= g_markup_escape_text(c
->class, -1);
572 fprintf(f
, "\t<class>%s</class>\n", t
);
575 t
= g_markup_escape_text(c
->role
, -1);
576 fprintf(f
, "\t<role>%s</role>\n", t
);
579 fprintf(f
, "\t<windowtype>%d</windowtype>\n", c
->type
);
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
);
587 fprintf(f
, "\t<shaded />\n");
589 fprintf(f
, "\t<iconic />\n");
591 fprintf(f
, "\t<skip_pager />\n");
593 fprintf(f
, "\t<skip_taskbar />\n");
595 fprintf(f
, "\t<fullscreen />\n");
597 fprintf(f
, "\t<above />\n");
599 fprintf(f
, "\t<below />\n");
601 fprintf(f
, "\t<max_horz />\n");
603 fprintf(f
, "\t<max_vert />\n");
605 fprintf(f
, "\t<undecorated />\n");
606 if (savedata
->focus_client
== c
)
607 fprintf(f
, "\t<focused />\n");
608 fprintf(f
, "</window>\n\n");
611 fprintf(f
, "</openbox_session>\n");
615 g_message(_("Error while saving the session to \"%s\": %s"),
616 ob_sm_save_file
, g_strerror(errno
));
624 static void session_state_free(ObSessionState
*state
)
628 g_free(state
->command
);
630 g_free(state
->class);
633 g_slice_free(ObSessionState
, state
);
637 static gboolean
session_state_cmp(ObSessionState
*s
, ObClient
*c
)
639 ob_debug_type(OB_DEBUG_SM
, "Comparing client against saved state: ");
640 ob_debug_type(OB_DEBUG_SM
, " client id: %s ", c
->sm_client_id
);
641 ob_debug_type(OB_DEBUG_SM
, " client name: %s ", c
->name
);
642 ob_debug_type(OB_DEBUG_SM
, " client class: %s ", c
->class);
643 ob_debug_type(OB_DEBUG_SM
, " client role: %s ", c
->role
);
644 ob_debug_type(OB_DEBUG_SM
, " client type: %d ", c
->type
);
645 ob_debug_type(OB_DEBUG_SM
, " client command: %s ",
646 c
->wm_command
? c
->wm_command
: "(null)");
647 ob_debug_type(OB_DEBUG_SM
, " state id: %s ", s
->id
);
648 ob_debug_type(OB_DEBUG_SM
, " state name: %s ", s
->name
);
649 ob_debug_type(OB_DEBUG_SM
, " state class: %s ", s
->class);
650 ob_debug_type(OB_DEBUG_SM
, " state role: %s ", s
->role
);
651 ob_debug_type(OB_DEBUG_SM
, " state type: %d ", s
->type
);
652 ob_debug_type(OB_DEBUG_SM
, " state command: %s ",
653 s
->command
? s
->command
: "(null)");
655 if ((c
->sm_client_id
&& s
->id
&& !strcmp(c
->sm_client_id
, s
->id
)) ||
656 (c
->wm_command
&& s
->command
&& !strcmp(c
->wm_command
, s
->command
)))
658 return (!strcmp(s
->name
, c
->name
) &&
659 !strcmp(s
->class, c
->class) &&
660 !strcmp(s
->role
, c
->role
) &&
661 /* the check for type is to catch broken clients, like
662 firefox, which open a different window on startup
663 with the same info as the one we saved. only do this
664 check for old windows that dont use xsmp, others should
666 (!s
->command
|| c
->type
== s
->type
));
671 GList
* session_state_find(ObClient
*c
)
675 for (it
= session_saved_state
; it
; it
= g_list_next(it
)) {
676 ObSessionState
*s
= it
->data
;
677 if (!s
->matched
&& session_state_cmp(s
, c
)) {
685 static void session_load_file(const gchar
*path
)
688 xmlNodePtr node
, n
, m
;
691 i
= obt_xml_instance_new();
693 if (!obt_xml_load_file(i
, path
, "openbox_session")) {
694 ob_debug_type(OB_DEBUG_SM
, "ERROR: session file is missing root node");
695 obt_xml_instance_unref(i
);
698 node
= obt_xml_root(i
);
700 if ((n
= obt_xml_find_node(node
->children
, "desktop")))
701 session_desktop
= obt_xml_node_int(n
);
703 if ((n
= obt_xml_find_node(node
->children
, "numdesktops")))
704 session_num_desktops
= obt_xml_node_int(n
);
706 if ((n
= obt_xml_find_node(node
->children
, "desktoplayout"))) {
707 /* make sure they are all there for it to be valid */
708 if ((m
= obt_xml_find_node(n
->children
, "orientation")))
709 session_desktop_layout
.orientation
= obt_xml_node_int(m
);
710 if (m
&& (m
= obt_xml_find_node(n
->children
, "startcorner")))
711 session_desktop_layout
.start_corner
= obt_xml_node_int(m
);
712 if (m
&& (m
= obt_xml_find_node(n
->children
, "columns")))
713 session_desktop_layout
.columns
= obt_xml_node_int(m
);
714 if (m
&& (m
= obt_xml_find_node(n
->children
, "rows")))
715 session_desktop_layout
.rows
= obt_xml_node_int(m
);
716 session_desktop_layout_present
= m
!= NULL
;
719 if ((n
= obt_xml_find_node(node
->children
, "desktopnames"))) {
720 for (m
= obt_xml_find_node(n
->children
, "name"); m
;
721 m
= obt_xml_find_node(m
->next
, "name"))
723 session_desktop_names
= g_slist_append(session_desktop_names
,
724 obt_xml_node_string(m
));
728 ob_debug_type(OB_DEBUG_SM
, "loading windows");
729 for (node
= obt_xml_find_node(node
->children
, "window"); node
!= NULL
;
730 node
= obt_xml_find_node(node
->next
, "window"))
732 ObSessionState
*state
;
734 state
= g_slice_new0(ObSessionState
);
736 if (!obt_xml_attr_string(node
, "id", &state
->id
))
737 if (!obt_xml_attr_string(node
, "command", &state
->command
))
738 goto session_load_bail
;
739 if (!(n
= obt_xml_find_node(node
->children
, "name")))
740 goto session_load_bail
;
741 state
->name
= obt_xml_node_string(n
);
742 if (!(n
= obt_xml_find_node(node
->children
, "class")))
743 goto session_load_bail
;
744 state
->class = obt_xml_node_string(n
);
745 if (!(n
= obt_xml_find_node(node
->children
, "role")))
746 goto session_load_bail
;
747 state
->role
= obt_xml_node_string(n
);
748 if (!(n
= obt_xml_find_node(node
->children
, "windowtype")))
749 goto session_load_bail
;
750 state
->type
= obt_xml_node_int(n
);
751 if (!(n
= obt_xml_find_node(node
->children
, "desktop")))
752 goto session_load_bail
;
753 state
->desktop
= obt_xml_node_int(n
);
754 if (!(n
= obt_xml_find_node(node
->children
, "x")))
755 goto session_load_bail
;
756 state
->x
= obt_xml_node_int(n
);
757 if (!(n
= obt_xml_find_node(node
->children
, "y")))
758 goto session_load_bail
;
759 state
->y
= obt_xml_node_int(n
);
760 if (!(n
= obt_xml_find_node(node
->children
, "width")))
761 goto session_load_bail
;
762 state
->w
= obt_xml_node_int(n
);
763 if (!(n
= obt_xml_find_node(node
->children
, "height")))
764 goto session_load_bail
;
765 state
->h
= obt_xml_node_int(n
);
768 obt_xml_find_node(node
->children
, "shaded") != NULL
;
770 obt_xml_find_node(node
->children
, "iconic") != NULL
;
772 obt_xml_find_node(node
->children
, "skip_pager") != NULL
;
773 state
->skip_taskbar
=
774 obt_xml_find_node(node
->children
, "skip_taskbar") != NULL
;
776 obt_xml_find_node(node
->children
, "fullscreen") != NULL
;
778 obt_xml_find_node(node
->children
, "above") != NULL
;
780 obt_xml_find_node(node
->children
, "below") != NULL
;
782 obt_xml_find_node(node
->children
, "max_horz") != NULL
;
784 obt_xml_find_node(node
->children
, "max_vert") != NULL
;
786 obt_xml_find_node(node
->children
, "undecorated") != NULL
;
788 obt_xml_find_node(node
->children
, "focused") != NULL
;
790 /* save this. they are in the file in stacking order, so preserve
792 session_saved_state
= g_list_append(session_saved_state
, state
);
793 ob_debug_type(OB_DEBUG_SM
, "loaded %s", state
->name
);
797 ob_debug_type(OB_DEBUG_SM
, "loading FAILED");
798 session_state_free(state
);
801 /* Remove any duplicates. This means that if two windows (or more) are
802 saved with the same session state, we won't restore a session for any
803 of them because we don't know what window to put what on. AHEM FIREFOX.
805 This is going to be an O(2^n) kind of operation unfortunately.
807 for (it
= session_saved_state
; it
; it
= inext
) {
809 gboolean founddup
= FALSE
;
810 ObSessionState
*s1
= it
->data
;
812 inext
= g_list_next(it
);
814 for (jt
= g_list_next(it
); jt
; jt
= jnext
) {
815 ObSessionState
*s2
= jt
->data
;
818 jnext
= g_list_next(jt
);
820 if (s1
->id
&& s2
->id
)
821 match
= strcmp(s1
->id
, s2
->id
) == 0;
822 else if (s1
->command
&& s2
->command
)
823 match
= strcmp(s1
->command
, s2
->command
) == 0;
828 !strcmp(s1
->name
, s2
->name
) &&
829 !strcmp(s1
->class, s2
->class) &&
830 !strcmp(s1
->role
, s2
->role
))
832 ob_debug_type(OB_DEBUG_SM
, "removing duplicate %s", s2
->name
);
833 session_state_free(s2
);
834 session_saved_state
=
835 g_list_delete_link(session_saved_state
, jt
);
841 ob_debug_type(OB_DEBUG_SM
, "removing duplicate %s", s1
->name
);
842 session_state_free(s1
);
843 session_saved_state
= g_list_delete_link(session_saved_state
, it
);
847 obt_xml_instance_unref(i
);
850 void session_request_logout(gboolean silent
)
853 SmcRequestSaveYourself(sm_conn
,
857 SmInteractStyleNone
: SmInteractStyleAny
),
858 TRUE
, /* if false, with GSM, it shows the old
863 g_message(_("Not connected to a session manager"));