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
) {}
44 #include "obt/parse.h"
45 #include "obt/paths.h"
52 # include <sys/types.h>
56 #include <X11/SM/SMlib.h>
58 #define SM_ERR_LEN 1024
60 static SmcConn sm_conn
;
62 static gchar
**sm_argv
;
64 /* Data saved from the first level save yourself */
66 ObClient
*focus_client
;
70 static gboolean
session_connect();
72 static void session_load_file(const gchar
*path
);
73 static gboolean
session_save_to_file(const ObSMSaveData
*savedata
);
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();
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
);
89 static gboolean
session_state_cmp(ObSessionState
*s
, ObClient
*c
);
90 static void session_state_free(ObSessionState
*state
);
92 void session_startup(gint argc
, gchar
**argv
)
97 if (!ob_sm_use
) return;
103 dir
= g_build_filename(obt_paths_cache_home(p
),
104 "openbox", "sessions", NULL
);
105 obt_paths_unref(p
), p
= NULL
;
107 if (!obt_paths_mkdir_path(dir
, 0700)) {
108 g_message(_("Unable to make directory \"%s\": %s"),
109 dir
, g_strerror(errno
));
112 if (ob_sm_save_file
!= NULL
) {
114 ob_debug_type(OB_DEBUG_SM
, "Loading from session file %s",
116 session_load_file(ob_sm_save_file
);
121 /* this algo is from metacity */
122 filename
= g_strdup_printf("%u-%u-%u.obs",
126 ob_sm_save_file
= g_build_filename(dir
, filename
, NULL
);
130 if (session_connect()) {
131 session_setup_program();
132 session_setup_user();
133 session_setup_restart_style(TRUE
);
135 session_setup_priority();
136 session_setup_clone_command();
142 void session_shutdown(gboolean permanent
)
144 if (!ob_sm_use
) return;
147 /* if permanent is true then we will change our session state so that
148 the SM won't run us again */
150 session_setup_restart_style(FALSE
);
152 SmcCloseConnection(sm_conn
, 0, NULL
);
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
);
162 /*! Connect to the session manager and set up our callback functions */
163 static gboolean
session_connect(void)
167 gchar sm_err
[SM_ERR_LEN
];
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
;
179 /* connect to the server */
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
|
186 SmcSaveCompleteProcMask
|
187 SmcShutdownCancelledProcMask
,
188 &cb
, oldid
, &ob_sm_id
,
189 SM_ERR_LEN
-1, sm_err
);
191 ob_debug_type(OB_DEBUG_SM
, "Connected to SM with id: %s", ob_sm_id
);
193 ob_debug("Failed to connect to session manager: %s", sm_err
);
194 return sm_conn
!= NULL
;
197 static void session_setup_program(void)
201 .length
= strlen(sm_argv
[0]) + 1
204 .name
= g_strdup(SmProgram
),
205 .type
= g_strdup(SmARRAY8
),
209 SmProp
*list
= &prop
;
210 ob_debug_type(OB_DEBUG_SM
, "Setting program: %s", sm_argv
[0]);
211 SmcSetProperties(sm_conn
, 1, &list
);
216 static void session_setup_user(void)
218 char *user
= g_strdup(g_get_user_name());
222 .length
= strlen(user
) + 1
225 .name
= g_strdup(SmUserID
),
226 .type
= g_strdup(SmARRAY8
),
230 SmProp
*list
= &prop
;
231 ob_debug_type(OB_DEBUG_SM
, "Setting user: %s", user
);
232 SmcSetProperties(sm_conn
, 1, &list
);
238 static void session_setup_restart_style(gboolean restart
)
240 gchar restart_hint
= restart
? SmRestartImmediately
: SmRestartIfRunning
;
243 .value
= &restart_hint
,
247 .name
= g_strdup(SmRestartStyleHint
),
248 .type
= g_strdup(SmCARD8
),
252 SmProp
*list
= &prop
;
253 ob_debug_type(OB_DEBUG_SM
, "Setting restart: %d", restart
);
254 SmcSetProperties(sm_conn
, 1, &list
);
259 static void session_setup_pid(void)
261 gchar
*pid
= g_strdup_printf("%ld", (glong
) getpid());
265 .length
= strlen(pid
) + 1
268 .name
= g_strdup(SmProcessID
),
269 .type
= g_strdup(SmARRAY8
),
273 SmProp
*list
= &prop
;
274 ob_debug_type(OB_DEBUG_SM
, "Setting pid: %s", pid
);
275 SmcSetProperties(sm_conn
, 1, &list
);
281 /*! This is a gnome-session-manager extension */
282 static void session_setup_priority(void)
284 gchar priority
= 20; /* 20 is a lower prioity to run before other apps */
291 .name
= g_strdup("_GSM_Priority"),
292 .type
= g_strdup(SmCARD8
),
296 SmProp
*list
= &prop
;
297 ob_debug_type(OB_DEBUG_SM
, "Setting priority: %d", priority
);
298 SmcSetProperties(sm_conn
, 1, &list
);
303 static void session_setup_clone_command(void)
307 SmPropValue
*vals
= g_new(SmPropValue
, sm_argc
);
309 .name
= g_strdup(SmCloneCommand
),
310 .type
= g_strdup(SmLISTofARRAY8
),
314 SmProp
*list
= &prop
;
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
);
323 SmcSetProperties(sm_conn
, 1, &list
);
329 static void session_setup_restart_command(void)
333 SmPropValue
*vals
= g_new(SmPropValue
, sm_argc
+ 4);
335 .name
= g_strdup(SmRestartCommand
),
336 .type
= g_strdup(SmLISTofARRAY8
),
337 .num_vals
= sm_argc
+ 4,
340 SmProp
*list
= &prop
;
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
);
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
);
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
);
363 SmcSetProperties(sm_conn
, 1, &list
);
366 g_free(vals
[i
].value
);
367 g_free(vals
[i
+2].value
);
371 static ObSMSaveData
*sm_save_get_data(void)
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
378 savedata
->focus_client
= focus_client
;
379 savedata
->desktop
= screen_desktop
;
383 static void sm_save_yourself_2(SmcConn conn
, SmPointer data
)
386 ObSMSaveData
*savedata
= data
;
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
);
397 /* tell the session manager how to restore this state */
398 if (success
) session_setup_restart_command();
400 ob_debug_type(OB_DEBUG_SM
, "Saving is done (success = %d)", success
);
401 SmcSaveYourselfDone(conn
, success
);
405 static void sm_save_yourself(SmcConn conn
, SmPointer data
, gint save_type
,
406 Bool shutdown
, gint interact_style
, Bool fast
)
408 ObSMSaveData
*savedata
= NULL
;
414 (save_type
== SmSaveLocal
? "SmSaveLocal" :
415 (save_type
== SmSaveGlobal
? "SmSaveGlobal" :
416 (save_type
== SmSaveBoth
? "SmSaveBoth" : "INVALID!!")));
417 ob_debug_type(OB_DEBUG_SM
, "Session save requested, type %s\n", sname
);
421 if (save_type
== SmSaveGlobal
) {
422 /* we have no data to save. we only store state to get back to where
423 we were, we don't keep open writable files or anything */
424 SmcSaveYourselfDone(conn
, TRUE
);
428 vendor
= SmcVendor(sm_conn
);
429 ob_debug_type(OB_DEBUG_SM
, "Session manager's vendor: %s", vendor
);
431 if (!strcmp(vendor
, "KDE")) {
432 /* ksmserver guarantees that phase 1 will complete before allowing any
433 clients interaction, so we can save this sanely here before they
434 get messed up from interaction */
435 savedata
= sm_save_get_data();
439 if (!SmcRequestSaveYourselfPhase2(conn
, sm_save_yourself_2
, savedata
)) {
440 ob_debug_type(OB_DEBUG_SM
, "Requst for phase 2 failed");
442 SmcSaveYourselfDone(conn
, FALSE
);
446 static void sm_die(SmcConn conn
, SmPointer data
)
448 ob_debug_type(OB_DEBUG_SM
, "Die requested");
452 static void sm_save_complete(SmcConn conn
, SmPointer data
)
454 ob_debug_type(OB_DEBUG_SM
, "Save complete");
457 static void sm_shutdown_cancelled(SmcConn conn
, SmPointer data
)
459 ob_debug_type(OB_DEBUG_SM
, "Shutdown cancelled");
462 static gboolean
session_save_to_file(const ObSMSaveData
*savedata
)
466 gboolean success
= TRUE
;
468 f
= fopen(ob_sm_save_file
, "w");
471 g_message(_("Unable to save the session to \"%s\": %s"),
472 ob_sm_save_file
, g_strerror(errno
));
474 fprintf(f
, "<?xml version=\"1.0\"?>\n\n");
475 fprintf(f
, "<openbox_session>\n\n");
477 fprintf(f
, "<desktop>%d</desktop>\n", savedata
->desktop
);
479 fprintf(f
, "<numdesktops>%d</numdesktops>\n", screen_num_desktops
);
481 fprintf(f
, "<desktoplayout>\n");
482 fprintf(f
, " <orientation>%d</orientation>\n",
483 screen_desktop_layout
.orientation
);
484 fprintf(f
, " <startcorner>%d</startcorner>\n",
485 screen_desktop_layout
.start_corner
);
486 fprintf(f
, " <columns>%d</columns>\n",
487 screen_desktop_layout
.columns
);
488 fprintf(f
, " <rows>%d</rows>\n",
489 screen_desktop_layout
.rows
);
490 fprintf(f
, "</desktoplayout>\n");
492 if (screen_desktop_names
) {
495 fprintf(f
, "<desktopnames>\n");
496 for (i
= 0; screen_desktop_names
[i
]; ++i
)
497 fprintf(f
, " <name>%s</name>\n", screen_desktop_names
[i
]);
498 fprintf(f
, "</desktopnames>\n");
501 /* they are ordered top to bottom in stacking order */
502 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
503 gint prex
, prey
, prew
, preh
;
507 if (WINDOW_IS_CLIENT(it
->data
))
508 c
= WINDOW_AS_CLIENT(it
->data
);
512 if (!client_normal(c
))
515 if (!c
->sm_client_id
) {
516 ob_debug_type(OB_DEBUG_SM
, "Client %s does not have a "
519 if (!c
->wm_command
) {
520 ob_debug_type(OB_DEBUG_SM
, "Client %s does not have an "
521 "oldskool wm_command set either. We won't "
522 "be saving its data",
528 ob_debug_type(OB_DEBUG_SM
, "Saving state for client %s",
533 prew
= c
->area
.width
;
534 preh
= c
->area
.height
;
536 prex
= c
->pre_fullscreen_area
.x
;
537 prey
= c
->pre_fullscreen_area
.x
;
538 prew
= c
->pre_fullscreen_area
.width
;
539 preh
= c
->pre_fullscreen_area
.height
;
542 prex
= c
->pre_max_area
.x
;
543 prew
= c
->pre_max_area
.width
;
546 prey
= c
->pre_max_area
.y
;
547 preh
= c
->pre_max_area
.height
;
551 fprintf(f
, "<window id=\"%s\">\n", c
->sm_client_id
);
553 fprintf(f
, "<window command=\"%s\">\n", c
->wm_command
);
555 t
= g_markup_escape_text(c
->name
, -1);
556 fprintf(f
, "\t<name>%s</name>\n", t
);
559 t
= g_markup_escape_text(c
->class, -1);
560 fprintf(f
, "\t<class>%s</class>\n", t
);
563 t
= g_markup_escape_text(c
->role
, -1);
564 fprintf(f
, "\t<role>%s</role>\n", t
);
567 fprintf(f
, "\t<windowtype>%d</windowtype>\n", c
->type
);
569 fprintf(f
, "\t<desktop>%d</desktop>\n", c
->desktop
);
570 fprintf(f
, "\t<x>%d</x>\n", prex
);
571 fprintf(f
, "\t<y>%d</y>\n", prey
);
572 fprintf(f
, "\t<width>%d</width>\n", prew
);
573 fprintf(f
, "\t<height>%d</height>\n", preh
);
575 fprintf(f
, "\t<shaded />\n");
577 fprintf(f
, "\t<iconic />\n");
579 fprintf(f
, "\t<skip_pager />\n");
581 fprintf(f
, "\t<skip_taskbar />\n");
583 fprintf(f
, "\t<fullscreen />\n");
585 fprintf(f
, "\t<above />\n");
587 fprintf(f
, "\t<below />\n");
589 fprintf(f
, "\t<max_horz />\n");
591 fprintf(f
, "\t<max_vert />\n");
593 fprintf(f
, "\t<undecorated />\n");
594 if (savedata
->focus_client
== c
)
595 fprintf(f
, "\t<focused />\n");
596 fprintf(f
, "</window>\n\n");
599 fprintf(f
, "</openbox_session>\n");
603 g_message(_("Error while saving the session to \"%s\": %s"),
604 ob_sm_save_file
, g_strerror(errno
));
612 static void session_state_free(ObSessionState
*state
)
616 g_free(state
->command
);
618 g_free(state
->class);
625 static gboolean
session_state_cmp(ObSessionState
*s
, ObClient
*c
)
627 ob_debug_type(OB_DEBUG_SM
, "Comparing client against saved state: ");
628 ob_debug_type(OB_DEBUG_SM
, " client id: %s ", c
->sm_client_id
);
629 ob_debug_type(OB_DEBUG_SM
, " client name: %s ", c
->name
);
630 ob_debug_type(OB_DEBUG_SM
, " client class: %s ", c
->class);
631 ob_debug_type(OB_DEBUG_SM
, " client role: %s ", c
->role
);
632 ob_debug_type(OB_DEBUG_SM
, " client type: %d ", c
->type
);
633 ob_debug_type(OB_DEBUG_SM
, " client command: %s ",
634 c
->wm_command
? c
->wm_command
: "(null)");
635 ob_debug_type(OB_DEBUG_SM
, " state id: %s ", s
->id
);
636 ob_debug_type(OB_DEBUG_SM
, " state name: %s ", s
->name
);
637 ob_debug_type(OB_DEBUG_SM
, " state class: %s ", s
->class);
638 ob_debug_type(OB_DEBUG_SM
, " state role: %s ", s
->role
);
639 ob_debug_type(OB_DEBUG_SM
, " state type: %d ", s
->type
);
640 ob_debug_type(OB_DEBUG_SM
, " state command: %s ",
641 s
->command
? s
->command
: "(null)");
643 if ((c
->sm_client_id
&& s
->id
&& !strcmp(c
->sm_client_id
, s
->id
)) ||
644 (c
->wm_command
&& s
->command
&& !strcmp(c
->wm_command
, s
->command
)))
646 return (!strcmp(s
->name
, c
->name
) &&
647 !strcmp(s
->class, c
->class) &&
648 !strcmp(s
->role
, c
->role
) &&
649 /* the check for type is to catch broken clients, like
650 firefox, which open a different window on startup
651 with the same info as the one we saved. only do this
652 check for old windows that dont use xsmp, others should
654 (!s
->command
|| c
->type
== s
->type
));
659 GList
* session_state_find(ObClient
*c
)
663 for (it
= session_saved_state
; it
; it
= g_list_next(it
)) {
664 ObSessionState
*s
= it
->data
;
665 if (!s
->matched
&& session_state_cmp(s
, c
)) {
673 static void session_load_file(const gchar
*path
)
676 xmlNodePtr node
, n
, m
;
679 i
= obt_parse_instance_new();
681 if (!obt_parse_load_file(i
, path
, "openbox_session")) {
682 ob_debug_type(OB_DEBUG_SM
, "ERROR: session file is missing root node");
683 obt_parse_instance_unref(i
);
686 node
= obt_parse_root(i
);
688 if ((n
= obt_parse_find_node(node
->children
, "desktop")))
689 session_desktop
= obt_parse_node_int(n
);
691 if ((n
= obt_parse_find_node(node
->children
, "numdesktops")))
692 session_num_desktops
= obt_parse_node_int(n
);
694 if ((n
= obt_parse_find_node(node
->children
, "desktoplayout"))) {
695 /* make sure they are all there for it to be valid */
696 if ((m
= obt_parse_find_node(n
->children
, "orientation")))
697 session_desktop_layout
.orientation
= obt_parse_node_int(m
);
698 if (m
&& (m
= obt_parse_find_node(n
->children
, "startcorner")))
699 session_desktop_layout
.start_corner
= obt_parse_node_int(m
);
700 if (m
&& (m
= obt_parse_find_node(n
->children
, "columns")))
701 session_desktop_layout
.columns
= obt_parse_node_int(m
);
702 if (m
&& (m
= obt_parse_find_node(n
->children
, "rows")))
703 session_desktop_layout
.rows
= obt_parse_node_int(m
);
704 session_desktop_layout_present
= m
!= NULL
;
707 if ((n
= obt_parse_find_node(node
->children
, "desktopnames"))) {
708 for (m
= obt_parse_find_node(n
->children
, "name"); m
;
709 m
= obt_parse_find_node(m
->next
, "name"))
711 session_desktop_names
= g_slist_append(session_desktop_names
,
712 obt_parse_node_string(m
));
716 ob_debug_type(OB_DEBUG_SM
, "loading windows");
717 for (node
= obt_parse_find_node(node
->children
, "window"); node
!= NULL
;
718 node
= obt_parse_find_node(node
->next
, "window"))
720 ObSessionState
*state
;
722 state
= g_new0(ObSessionState
, 1);
724 if (!obt_parse_attr_string(node
, "id", &state
->id
))
725 if (!obt_parse_attr_string(node
, "command", &state
->command
))
726 goto session_load_bail
;
727 if (!(n
= obt_parse_find_node(node
->children
, "name")))
728 goto session_load_bail
;
729 state
->name
= obt_parse_node_string(n
);
730 if (!(n
= obt_parse_find_node(node
->children
, "class")))
731 goto session_load_bail
;
732 state
->class = obt_parse_node_string(n
);
733 if (!(n
= obt_parse_find_node(node
->children
, "role")))
734 goto session_load_bail
;
735 state
->role
= obt_parse_node_string(n
);
736 if (!(n
= obt_parse_find_node(node
->children
, "windowtype")))
737 goto session_load_bail
;
738 state
->type
= obt_parse_node_int(n
);
739 if (!(n
= obt_parse_find_node(node
->children
, "desktop")))
740 goto session_load_bail
;
741 state
->desktop
= obt_parse_node_int(n
);
742 if (!(n
= obt_parse_find_node(node
->children
, "x")))
743 goto session_load_bail
;
744 state
->x
= obt_parse_node_int(n
);
745 if (!(n
= obt_parse_find_node(node
->children
, "y")))
746 goto session_load_bail
;
747 state
->y
= obt_parse_node_int(n
);
748 if (!(n
= obt_parse_find_node(node
->children
, "width")))
749 goto session_load_bail
;
750 state
->w
= obt_parse_node_int(n
);
751 if (!(n
= obt_parse_find_node(node
->children
, "height")))
752 goto session_load_bail
;
753 state
->h
= obt_parse_node_int(n
);
756 obt_parse_find_node(node
->children
, "shaded") != NULL
;
758 obt_parse_find_node(node
->children
, "iconic") != NULL
;
760 obt_parse_find_node(node
->children
, "skip_pager") != NULL
;
761 state
->skip_taskbar
=
762 obt_parse_find_node(node
->children
, "skip_taskbar") != NULL
;
764 obt_parse_find_node(node
->children
, "fullscreen") != NULL
;
766 obt_parse_find_node(node
->children
, "above") != NULL
;
768 obt_parse_find_node(node
->children
, "below") != NULL
;
770 obt_parse_find_node(node
->children
, "max_horz") != NULL
;
772 obt_parse_find_node(node
->children
, "max_vert") != NULL
;
774 obt_parse_find_node(node
->children
, "undecorated") != NULL
;
776 obt_parse_find_node(node
->children
, "focused") != NULL
;
778 /* save this. they are in the file in stacking order, so preserve
780 session_saved_state
= g_list_append(session_saved_state
, state
);
781 ob_debug_type(OB_DEBUG_SM
, "loaded %s", state
->name
);
785 ob_debug_type(OB_DEBUG_SM
, "loading FAILED");
786 session_state_free(state
);
789 /* Remove any duplicates. This means that if two windows (or more) are
790 saved with the same session state, we won't restore a session for any
791 of them because we don't know what window to put what on. AHEM FIREFOX.
793 This is going to be an O(2^n) kind of operation unfortunately.
795 for (it
= session_saved_state
; it
; it
= inext
) {
797 gboolean founddup
= FALSE
;
798 ObSessionState
*s1
= it
->data
;
800 inext
= g_list_next(it
);
802 for (jt
= g_list_next(it
); jt
; jt
= jnext
) {
803 ObSessionState
*s2
= jt
->data
;
806 jnext
= g_list_next(jt
);
808 if (s1
->id
&& s2
->id
)
809 match
= strcmp(s1
->id
, s2
->id
) == 0;
810 else if (s1
->command
&& s2
->command
)
811 match
= strcmp(s1
->command
, s2
->command
) == 0;
816 !strcmp(s1
->name
, s2
->name
) &&
817 !strcmp(s1
->class, s2
->class) &&
818 !strcmp(s1
->role
, s2
->role
))
820 ob_debug_type(OB_DEBUG_SM
, "removing duplicate %s", s2
->name
);
821 session_state_free(s2
);
822 session_saved_state
=
823 g_list_delete_link(session_saved_state
, jt
);
829 ob_debug_type(OB_DEBUG_SM
, "removing duplicate %s", s1
->name
);
830 session_state_free(s1
);
831 session_saved_state
= g_list_delete_link(session_saved_state
, it
);
835 obt_parse_instance_unref(i
);
838 void session_request_logout(gboolean silent
)
841 SmcRequestSaveYourself(sm_conn
,
845 SmInteractStyleNone
: SmInteractStyleAny
),
846 TRUE
, /* if false, with GSM, it shows the old
851 g_message(_("Not connected to a session manager"));