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 "parser/parse.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
)
97 if (!ob_sm_use
) return;
102 dir
= g_build_filename(parse_xdg_data_home_path(),
103 "openbox", "sessions", NULL
);
104 if (!parse_mkdir_path(dir
, 0700)) {
105 g_message(_("Unable to make directory \"%s\": %s"),
106 dir
, g_strerror(errno
));
109 if (ob_sm_save_file
!= NULL
) {
111 ob_debug_type(OB_DEBUG_SM
, "Loading from session file %s\n",
113 session_load_file(ob_sm_save_file
);
118 /* this algo is from metacity */
119 filename
= g_strdup_printf("%u-%u-%u.obs",
123 ob_sm_save_file
= g_build_filename(dir
, filename
, NULL
);
127 if (session_connect()) {
128 session_setup_program();
129 session_setup_user();
130 session_setup_restart_style(TRUE
);
132 session_setup_priority();
133 session_setup_clone_command();
139 void session_shutdown(gboolean permanent
)
141 if (!ob_sm_use
) return;
144 /* if permanent is true then we will change our session state so that
145 the SM won't run us again */
147 session_setup_restart_style(FALSE
);
149 SmcCloseConnection(sm_conn
, 0, NULL
);
151 while (session_saved_state
) {
152 session_state_free(session_saved_state
->data
);
153 session_saved_state
= g_list_delete_link(session_saved_state
,
154 session_saved_state
);
159 gboolean
session_connected(void)
164 /*! Connect to the session manager and set up our callback functions */
165 static gboolean
session_connect()
169 gchar sm_err
[SM_ERR_LEN
];
171 /* set up our callback functions */
172 cb
.save_yourself
.callback
= sm_save_yourself
;
173 cb
.save_yourself
.client_data
= NULL
;
174 cb
.die
.callback
= sm_die
;
175 cb
.die
.client_data
= NULL
;
176 cb
.save_complete
.callback
= sm_save_complete
;
177 cb
.save_complete
.client_data
= NULL
;
178 cb
.shutdown_cancelled
.callback
= sm_shutdown_cancelled
;
179 cb
.shutdown_cancelled
.client_data
= NULL
;
181 /* connect to the server */
183 ob_debug_type(OB_DEBUG_SM
, "Connecting to SM with id: %s\n",
184 oldid
? oldid
: "(null)");
185 sm_conn
= SmcOpenConnection(NULL
, NULL
, 1, 0,
186 SmcSaveYourselfProcMask
|
188 SmcSaveCompleteProcMask
|
189 SmcShutdownCancelledProcMask
,
190 &cb
, oldid
, &ob_sm_id
,
191 SM_ERR_LEN
-1, sm_err
);
193 ob_debug_type(OB_DEBUG_SM
, "Connected to SM with id: %s\n", ob_sm_id
);
195 ob_debug("Failed to connect to session manager: %s\n", sm_err
);
196 return sm_conn
!= NULL
;
199 static void session_setup_program()
203 .length
= strlen(sm_argv
[0]) + 1
206 .name
= g_strdup(SmProgram
),
207 .type
= g_strdup(SmARRAY8
),
211 SmProp
*list
= &prop
;
212 ob_debug_type(OB_DEBUG_SM
, "Setting program: %s\n", sm_argv
[0]);
213 SmcSetProperties(sm_conn
, 1, &list
);
218 static void session_setup_user()
220 char *user
= g_strdup(g_get_user_name());
224 .length
= strlen(user
) + 1
227 .name
= g_strdup(SmUserID
),
228 .type
= g_strdup(SmARRAY8
),
232 SmProp
*list
= &prop
;
233 ob_debug_type(OB_DEBUG_SM
, "Setting user: %s\n", user
);
234 SmcSetProperties(sm_conn
, 1, &list
);
240 static void session_setup_restart_style(gboolean restart
)
242 gchar restart_hint
= restart
? SmRestartImmediately
: SmRestartIfRunning
;
245 .value
= &restart_hint
,
249 .name
= g_strdup(SmRestartStyleHint
),
250 .type
= g_strdup(SmCARD8
),
254 SmProp
*list
= &prop
;
255 ob_debug_type(OB_DEBUG_SM
, "Setting restart: %d\n", restart
);
256 SmcSetProperties(sm_conn
, 1, &list
);
261 static void session_setup_pid()
263 gchar
*pid
= g_strdup_printf("%ld", (glong
) getpid());
267 .length
= strlen(pid
) + 1
270 .name
= g_strdup(SmProcessID
),
271 .type
= g_strdup(SmARRAY8
),
275 SmProp
*list
= &prop
;
276 ob_debug_type(OB_DEBUG_SM
, "Setting pid: %s\n", pid
);
277 SmcSetProperties(sm_conn
, 1, &list
);
283 /*! This is a gnome-session-manager extension */
284 static void session_setup_priority()
286 gchar priority
= 20; /* 20 is a lower prioity to run before other apps */
293 .name
= g_strdup("_GSM_Priority"),
294 .type
= g_strdup(SmCARD8
),
298 SmProp
*list
= &prop
;
299 ob_debug_type(OB_DEBUG_SM
, "Setting priority: %d\n", priority
);
300 SmcSetProperties(sm_conn
, 1, &list
);
305 static void session_setup_clone_command()
309 SmPropValue
*vals
= g_new(SmPropValue
, sm_argc
);
311 .name
= g_strdup(SmCloneCommand
),
312 .type
= g_strdup(SmLISTofARRAY8
),
316 SmProp
*list
= &prop
;
318 ob_debug_type(OB_DEBUG_SM
, "Setting clone command: (%d)\n", sm_argc
);
319 for (i
= 0; i
< sm_argc
; ++i
) {
320 vals
[i
].value
= sm_argv
[i
];
321 vals
[i
].length
= strlen(sm_argv
[i
]) + 1;
322 ob_debug_type(OB_DEBUG_SM
, " %s\n", vals
[i
].value
);
325 SmcSetProperties(sm_conn
, 1, &list
);
331 static void session_setup_restart_command()
335 SmPropValue
*vals
= g_new(SmPropValue
, sm_argc
+ 4);
337 .name
= g_strdup(SmRestartCommand
),
338 .type
= g_strdup(SmLISTofARRAY8
),
339 .num_vals
= sm_argc
+ 4,
342 SmProp
*list
= &prop
;
344 ob_debug_type(OB_DEBUG_SM
, "Setting restart command: (%d)\n", sm_argc
+4);
345 for (i
= 0; i
< sm_argc
; ++i
) {
346 vals
[i
].value
= sm_argv
[i
];
347 vals
[i
].length
= strlen(sm_argv
[i
]) + 1;
348 ob_debug_type(OB_DEBUG_SM
, " %s\n", vals
[i
].value
);
351 vals
[i
].value
= g_strdup("--sm-client-id");
352 vals
[i
].length
= strlen("--sm-client-id") + 1;
353 vals
[i
+1].value
= ob_sm_id
;
354 vals
[i
+1].length
= strlen(ob_sm_id
) + 1;
355 ob_debug_type(OB_DEBUG_SM
, " %s\n", vals
[i
].value
);
356 ob_debug_type(OB_DEBUG_SM
, " %s\n", vals
[i
+1].value
);
358 vals
[i
+2].value
= g_strdup("--sm-save-file");
359 vals
[i
+2].length
= strlen("--sm-save-file") + 1;
360 vals
[i
+3].value
= ob_sm_save_file
;
361 vals
[i
+3].length
= strlen(ob_sm_save_file
) + 1;
362 ob_debug_type(OB_DEBUG_SM
, " %s\n", vals
[i
+2].value
);
363 ob_debug_type(OB_DEBUG_SM
, " %s\n", vals
[i
+3].value
);
365 SmcSetProperties(sm_conn
, 1, &list
);
368 g_free(vals
[i
].value
);
369 g_free(vals
[i
+2].value
);
373 static ObSMSaveData
*sm_save_get_data()
375 ObSMSaveData
*savedata
= g_new0(ObSMSaveData
, 1);
376 /* save the active desktop and client.
377 we don't bother to preemptively save the other desktop state like
378 number and names of desktops, cuz those shouldn't be changing during
380 savedata
->focus_client
= focus_client
;
381 savedata
->desktop
= screen_desktop
;
385 static void sm_save_yourself_2(SmcConn conn
, SmPointer data
)
388 ObSMSaveData
*savedata
= data
;
390 /* save the current state */
391 ob_debug_type(OB_DEBUG_SM
, "Session save phase 2 requested\n");
392 ob_debug_type(OB_DEBUG_SM
,
393 " Saving session to file '%s'\n", ob_sm_save_file
);
394 if (savedata
== NULL
)
395 savedata
= sm_save_get_data();
396 success
= session_save_to_file(savedata
);
399 /* tell the session manager how to restore this state */
400 if (success
) session_setup_restart_command();
402 ob_debug_type(OB_DEBUG_SM
, "Saving is done (success = %d)\n", success
);
403 SmcSaveYourselfDone(conn
, success
);
406 static void sm_save_yourself(SmcConn conn
, SmPointer data
, gint save_type
,
407 Bool shutdown
, gint interact_style
, Bool fast
)
409 ObSMSaveData
*savedata
= NULL
;
415 (save_type
== SmSaveLocal
? "SmSaveLocal" :
416 (save_type
== SmSaveGlobal
? "SmSaveGlobal" :
417 (save_type
== SmSaveBoth
? "SmSaveBoth" : "INVALID!!")));
418 ob_debug_type(OB_DEBUG_SM
, "Session save requested, type %s\n", sname
);
422 if (save_type
== SmSaveGlobal
) {
423 /* we have no data to save. we only store state to get back to where
424 we were, we don't keep open writable files or anything */
425 SmcSaveYourselfDone(conn
, TRUE
);
429 vendor
= SmcVendor(sm_conn
);
430 ob_debug_type(OB_DEBUG_SM
, "Session manager's vendor: %s\n", vendor
);
432 if (!strcmp(vendor
, "KDE")) {
433 /* ksmserver guarantees that phase 1 will complete before allowing any
434 clients interaction, so we can save this sanely here before they
435 get messed up from interaction */
436 savedata
= sm_save_get_data();
440 if (!SmcRequestSaveYourselfPhase2(conn
, sm_save_yourself_2
, savedata
)) {
441 ob_debug_type(OB_DEBUG_SM
, "Requst for phase 2 failed\n");
443 SmcSaveYourselfDone(conn
, FALSE
);
447 static void sm_die(SmcConn conn
, SmPointer data
)
449 ob_debug_type(OB_DEBUG_SM
, "Die requested\n");
453 static void sm_save_complete(SmcConn conn
, SmPointer data
)
455 ob_debug_type(OB_DEBUG_SM
, "Save complete\n");
458 static void sm_shutdown_cancelled(SmcConn conn
, SmPointer data
)
460 ob_debug_type(OB_DEBUG_SM
, "Shutdown cancelled\n");
463 static gboolean
session_save_to_file(const ObSMSaveData
*savedata
)
467 gboolean success
= TRUE
;
469 f
= fopen(ob_sm_save_file
, "w");
472 g_message(_("Unable to save the session to \"%s\": %s"),
473 ob_sm_save_file
, g_strerror(errno
));
475 fprintf(f
, "<?xml version=\"1.0\"?>\n\n");
476 fprintf(f
, "<openbox_session>\n\n");
478 fprintf(f
, "<desktop>%d</desktop>\n", savedata
->desktop
);
480 fprintf(f
, "<numdesktops>%d</numdesktops>\n", screen_num_desktops
);
482 fprintf(f
, "<desktoplayout>\n");
483 fprintf(f
, " <orientation>%d</orientation>\n",
484 screen_desktop_layout
.orientation
);
485 fprintf(f
, " <startcorner>%d</startcorner>\n",
486 screen_desktop_layout
.start_corner
);
487 fprintf(f
, " <columns>%d</columns>\n",
488 screen_desktop_layout
.columns
);
489 fprintf(f
, " <rows>%d</rows>\n",
490 screen_desktop_layout
.rows
);
491 fprintf(f
, "</desktoplayout>\n");
493 if (screen_desktop_names
) {
497 fprintf(f
, "<desktopnames>\n");
498 for (i
= 0; screen_desktop_names
[i
]; ++i
){
499 t
= g_markup_escape_text(screen_desktop_names
[i
], -1);
500 fprintf(f
, " <name>%s</name>\n", t
);
503 fprintf(f
, "</desktopnames>\n");
506 /* they are ordered top to bottom in stacking order */
507 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
508 gint prex
, prey
, prew
, preh
;
512 if (WINDOW_IS_CLIENT(it
->data
))
513 c
= WINDOW_AS_CLIENT(it
->data
);
517 if (!client_normal(c
))
520 if (!c
->sm_client_id
) {
521 ob_debug_type(OB_DEBUG_SM
, "Client %s does not have a "
524 if (!c
->wm_command
) {
525 ob_debug_type(OB_DEBUG_SM
, "Client %s does not have an "
526 "oldskool wm_command set either. We won't "
527 "be saving its data\n",
533 ob_debug_type(OB_DEBUG_SM
, "Saving state for client %s\n",
538 prew
= c
->area
.width
;
539 preh
= c
->area
.height
;
541 prex
= c
->pre_fullscreen_area
.x
;
542 prey
= c
->pre_fullscreen_area
.x
;
543 prew
= c
->pre_fullscreen_area
.width
;
544 preh
= c
->pre_fullscreen_area
.height
;
547 prex
= c
->pre_max_area
.x
;
548 prew
= c
->pre_max_area
.width
;
551 prey
= c
->pre_max_area
.y
;
552 preh
= c
->pre_max_area
.height
;
556 fprintf(f
, "<window id=\"%s\">\n", c
->sm_client_id
);
558 t
= g_markup_escape_text(c
->wm_command
, -1);
559 fprintf(f
, "<window command=\"%s\">\n", t
);
563 t
= g_markup_escape_text(c
->name
, -1);
564 fprintf(f
, "\t<name>%s</name>\n", t
);
567 t
= g_markup_escape_text(c
->class, -1);
568 fprintf(f
, "\t<class>%s</class>\n", t
);
571 t
= g_markup_escape_text(c
->role
, -1);
572 fprintf(f
, "\t<role>%s</role>\n", t
);
575 fprintf(f
, "\t<windowtype>%d</windowtype>\n", c
->type
);
577 fprintf(f
, "\t<desktop>%d</desktop>\n", c
->desktop
);
578 fprintf(f
, "\t<x>%d</x>\n", prex
);
579 fprintf(f
, "\t<y>%d</y>\n", prey
);
580 fprintf(f
, "\t<width>%d</width>\n", prew
);
581 fprintf(f
, "\t<height>%d</height>\n", preh
);
583 fprintf(f
, "\t<shaded />\n");
585 fprintf(f
, "\t<iconic />\n");
587 fprintf(f
, "\t<skip_pager />\n");
589 fprintf(f
, "\t<skip_taskbar />\n");
591 fprintf(f
, "\t<fullscreen />\n");
593 fprintf(f
, "\t<above />\n");
595 fprintf(f
, "\t<below />\n");
597 fprintf(f
, "\t<max_horz />\n");
599 fprintf(f
, "\t<max_vert />\n");
601 fprintf(f
, "\t<undecorated />\n");
602 if (savedata
->focus_client
== c
)
603 fprintf(f
, "\t<focused />\n");
604 fprintf(f
, "</window>\n\n");
607 fprintf(f
, "</openbox_session>\n");
611 g_message(_("Error while saving the session to \"%s\": %s"),
612 ob_sm_save_file
, g_strerror(errno
));
620 static void session_state_free(ObSessionState
*state
)
624 g_free(state
->command
);
626 g_free(state
->class);
633 static gboolean
session_state_cmp(ObSessionState
*s
, ObClient
*c
)
635 ob_debug_type(OB_DEBUG_SM
, "Comparing client against saved state: \n");
636 ob_debug_type(OB_DEBUG_SM
, " client id: %s \n", c
->sm_client_id
);
637 ob_debug_type(OB_DEBUG_SM
, " client name: %s \n", c
->name
);
638 ob_debug_type(OB_DEBUG_SM
, " client class: %s \n", c
->class);
639 ob_debug_type(OB_DEBUG_SM
, " client role: %s \n", c
->role
);
640 ob_debug_type(OB_DEBUG_SM
, " client type: %d \n", c
->type
);
641 ob_debug_type(OB_DEBUG_SM
, " client command: %s \n",
642 c
->wm_command
? c
->wm_command
: "(null)");
643 ob_debug_type(OB_DEBUG_SM
, " state id: %s \n", s
->id
);
644 ob_debug_type(OB_DEBUG_SM
, " state name: %s \n", s
->name
);
645 ob_debug_type(OB_DEBUG_SM
, " state class: %s \n", s
->class);
646 ob_debug_type(OB_DEBUG_SM
, " state role: %s \n", s
->role
);
647 ob_debug_type(OB_DEBUG_SM
, " state type: %d \n", s
->type
);
648 ob_debug_type(OB_DEBUG_SM
, " state command: %s \n",
649 s
->command
? s
->command
: "(null)");
651 if ((c
->sm_client_id
&& s
->id
&& !strcmp(c
->sm_client_id
, s
->id
)) ||
652 (c
->wm_command
&& s
->command
&& !strcmp(c
->wm_command
, s
->command
)))
654 return (!strcmp(s
->name
, c
->name
) &&
655 !strcmp(s
->class, c
->class) &&
656 !strcmp(s
->role
, c
->role
) &&
657 /* the check for type is to catch broken clients, like
658 firefox, which open a different window on startup
659 with the same info as the one we saved. only do this
660 check for old windows that dont use xsmp, others should
662 (!s
->command
|| c
->type
== s
->type
));
667 GList
* session_state_find(ObClient
*c
)
671 for (it
= session_saved_state
; it
; it
= g_list_next(it
)) {
672 ObSessionState
*s
= it
->data
;
673 if (!s
->matched
&& session_state_cmp(s
, c
)) {
681 static void session_load_file(const gchar
*path
)
684 xmlNodePtr node
, n
, m
;
687 if (!parse_load(path
, "openbox_session", &doc
, &node
))
690 if ((n
= parse_find_node("desktop", node
->children
)))
691 session_desktop
= parse_int(doc
, n
);
693 if ((n
= parse_find_node("numdesktops", node
->children
)))
694 session_num_desktops
= parse_int(doc
, n
);
696 if ((n
= parse_find_node("desktoplayout", node
->children
))) {
697 /* make sure they are all there for it to be valid */
698 if ((m
= parse_find_node("orientation", n
->children
)))
699 session_desktop_layout
.orientation
= parse_int(doc
, m
);
700 if (m
&& (m
= parse_find_node("startcorner", n
->children
)))
701 session_desktop_layout
.start_corner
= parse_int(doc
, m
);
702 if (m
&& (m
= parse_find_node("columns", n
->children
)))
703 session_desktop_layout
.columns
= parse_int(doc
, m
);
704 if (m
&& (m
= parse_find_node("rows", n
->children
)))
705 session_desktop_layout
.rows
= parse_int(doc
, m
);
706 session_desktop_layout_present
= m
!= NULL
;
709 if ((n
= parse_find_node("desktopnames", node
->children
))) {
710 for (m
= parse_find_node("name", n
->children
); m
;
711 m
= parse_find_node("name", m
->next
))
713 session_desktop_names
= g_slist_append(session_desktop_names
,
714 parse_string(doc
, m
));
718 for (node
= parse_find_node("window", node
->children
); node
!= NULL
;
719 node
= parse_find_node("window", node
->next
))
721 ObSessionState
*state
;
723 state
= g_new0(ObSessionState
, 1);
725 if (!parse_attr_string("id", node
, &state
->id
))
726 if (!parse_attr_string("command", node
, &state
->command
))
727 goto session_load_bail
;
728 if (!(n
= parse_find_node("name", node
->children
)))
729 goto session_load_bail
;
730 state
->name
= parse_string(doc
, n
);
731 if (!(n
= parse_find_node("class", node
->children
)))
732 goto session_load_bail
;
733 state
->class = parse_string(doc
, n
);
734 if (!(n
= parse_find_node("role", node
->children
)))
735 goto session_load_bail
;
736 state
->role
= parse_string(doc
, n
);
737 if (!(n
= parse_find_node("windowtype", node
->children
)))
738 goto session_load_bail
;
739 state
->type
= parse_int(doc
, n
);
740 if (!(n
= parse_find_node("desktop", node
->children
)))
741 goto session_load_bail
;
742 state
->desktop
= parse_int(doc
, n
);
743 if (!(n
= parse_find_node("x", node
->children
)))
744 goto session_load_bail
;
745 state
->x
= parse_int(doc
, n
);
746 if (!(n
= parse_find_node("y", node
->children
)))
747 goto session_load_bail
;
748 state
->y
= parse_int(doc
, n
);
749 if (!(n
= parse_find_node("width", node
->children
)))
750 goto session_load_bail
;
751 state
->w
= parse_int(doc
, n
);
752 if (!(n
= parse_find_node("height", node
->children
)))
753 goto session_load_bail
;
754 state
->h
= parse_int(doc
, n
);
757 parse_find_node("shaded", node
->children
) != NULL
;
759 parse_find_node("iconic", node
->children
) != NULL
;
761 parse_find_node("skip_pager", node
->children
) != NULL
;
762 state
->skip_taskbar
=
763 parse_find_node("skip_taskbar", node
->children
) != NULL
;
765 parse_find_node("fullscreen", node
->children
) != NULL
;
767 parse_find_node("above", node
->children
) != NULL
;
769 parse_find_node("below", node
->children
) != NULL
;
771 parse_find_node("max_horz", node
->children
) != NULL
;
773 parse_find_node("max_vert", node
->children
) != NULL
;
775 parse_find_node("undecorated", node
->children
) != NULL
;
777 parse_find_node("focused", node
->children
) != NULL
;
779 /* save this. they are in the file in stacking order, so preserve
781 session_saved_state
= g_list_append(session_saved_state
, state
);
785 session_state_free(state
);
788 /* Remove any duplicates. This means that if two windows (or more) are
789 saved with the same session state, we won't restore a session for any
790 of them because we don't know what window to put what on. AHEM FIREFOX.
792 This is going to be an O(2^n) kind of operation unfortunately.
794 for (it
= session_saved_state
; it
; it
= inext
) {
796 gboolean founddup
= FALSE
;
797 ObSessionState
*s1
= it
->data
;
799 inext
= g_list_next(it
);
801 for (jt
= g_list_next(it
); jt
; jt
= jnext
) {
802 ObSessionState
*s2
= jt
->data
;
805 jnext
= g_list_next(jt
);
807 if (s1
->id
&& s2
->id
)
808 match
= strcmp(s1
->id
, s2
->id
) == 0;
809 else if (s1
->command
&& s2
->command
)
810 match
= strcmp(s1
->command
, s2
->command
) == 0;
815 !strcmp(s1
->name
, s2
->name
) &&
816 !strcmp(s1
->class, s2
->class) &&
817 !strcmp(s1
->role
, s2
->role
))
819 session_state_free(s2
);
820 session_saved_state
=
821 g_list_delete_link(session_saved_state
, jt
);
827 session_state_free(s1
);
828 session_saved_state
= g_list_delete_link(session_saved_state
, it
);
835 void session_request_logout(gboolean silent
)
838 SmcRequestSaveYourself(sm_conn
,
842 SmInteractStyleNone
: SmInteractStyleAny
),
843 TRUE
, /* if false, with GSM, it shows the old
848 g_message(_("Not connected to a session manager"));