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
; }
43 #include "obt/parse.h"
44 #include "obt/paths.h"
51 # include <sys/types.h>
55 #include <X11/SM/SMlib.h>
57 #define SM_ERR_LEN 1024
59 static SmcConn sm_conn
;
61 static gchar
**sm_argv
;
63 /* Data saved from the first level save yourself */
65 ObClient
*focus_client
;
69 static gboolean
session_connect();
71 static void session_load_file(const gchar
*path
);
72 static gboolean
session_save_to_file(const ObSMSaveData
*savedata
);
74 static void session_setup_program();
75 static void session_setup_user();
76 static void session_setup_restart_style(gboolean restart
);
77 static void session_setup_pid();
78 static void session_setup_priority();
79 static void session_setup_clone_command();
80 static void session_setup_restart_command();
82 static void sm_save_yourself(SmcConn conn
, SmPointer data
, gint save_type
,
83 Bool shutdown
, gint interact_style
, Bool fast
);
84 static void sm_die(SmcConn conn
, SmPointer data
);
85 static void sm_save_complete(SmcConn conn
, SmPointer data
);
86 static void sm_shutdown_cancelled(SmcConn conn
, SmPointer data
);
88 static gboolean
session_state_cmp(ObSessionState
*s
, ObClient
*c
);
89 static void session_state_free(ObSessionState
*state
);
91 void session_startup(gint argc
, gchar
**argv
)
96 if (!ob_sm_use
) return;
102 dir
= g_build_filename(obt_paths_cache_home(p
),
103 "openbox", "sessions", NULL
);
104 obt_paths_unref(p
), p
= NULL
;
106 if (!obt_paths_mkdir_path(dir
, 0700)) {
107 g_message(_("Unable to make directory '%s': %s"),
108 dir
, g_strerror(errno
));
111 if (ob_sm_save_file
!= NULL
) {
113 ob_debug_type(OB_DEBUG_SM
, "Loading from session file %s",
115 session_load_file(ob_sm_save_file
);
120 /* this algo is from metacity */
121 filename
= g_strdup_printf("%u-%u-%u.obs",
125 ob_sm_save_file
= g_build_filename(dir
, filename
, NULL
);
129 if (session_connect()) {
130 session_setup_program();
131 session_setup_user();
132 session_setup_restart_style(TRUE
);
134 session_setup_priority();
135 session_setup_clone_command();
141 void session_shutdown(gboolean permanent
)
143 if (!ob_sm_use
) return;
146 /* if permanent is true then we will change our session state so that
147 the SM won't run us again */
149 session_setup_restart_style(FALSE
);
151 SmcCloseConnection(sm_conn
, 0, NULL
);
153 while (session_saved_state
) {
154 session_state_free(session_saved_state
->data
);
155 session_saved_state
= g_list_delete_link(session_saved_state
,
156 session_saved_state
);
161 /*! Connect to the session manager and set up our callback functions */
162 static gboolean
session_connect()
166 gchar sm_err
[SM_ERR_LEN
];
168 /* set up our callback functions */
169 cb
.save_yourself
.callback
= sm_save_yourself
;
170 cb
.save_yourself
.client_data
= NULL
;
171 cb
.die
.callback
= sm_die
;
172 cb
.die
.client_data
= NULL
;
173 cb
.save_complete
.callback
= sm_save_complete
;
174 cb
.save_complete
.client_data
= NULL
;
175 cb
.shutdown_cancelled
.callback
= sm_shutdown_cancelled
;
176 cb
.shutdown_cancelled
.client_data
= NULL
;
178 /* connect to the server */
180 ob_debug_type(OB_DEBUG_SM
, "Connecting to SM with id: %s",
181 oldid
? oldid
: "(null)");
182 sm_conn
= SmcOpenConnection(NULL
, NULL
, 1, 0,
183 SmcSaveYourselfProcMask
|
185 SmcSaveCompleteProcMask
|
186 SmcShutdownCancelledProcMask
,
187 &cb
, oldid
, &ob_sm_id
,
188 SM_ERR_LEN
-1, sm_err
);
190 ob_debug_type(OB_DEBUG_SM
, "Connected to SM with id: %s", ob_sm_id
);
192 ob_debug("Failed to connect to session manager: %s", sm_err
);
193 return sm_conn
!= NULL
;
196 static void session_setup_program()
200 .length
= strlen(sm_argv
[0]) + 1
203 .name
= g_strdup(SmProgram
),
204 .type
= g_strdup(SmARRAY8
),
208 SmProp
*list
= &prop
;
209 ob_debug_type(OB_DEBUG_SM
, "Setting program: %s", sm_argv
[0]);
210 SmcSetProperties(sm_conn
, 1, &list
);
215 static void session_setup_user()
217 char *user
= g_strdup(g_get_user_name());
221 .length
= strlen(user
) + 1
224 .name
= g_strdup(SmUserID
),
225 .type
= g_strdup(SmARRAY8
),
229 SmProp
*list
= &prop
;
230 ob_debug_type(OB_DEBUG_SM
, "Setting user: %s", user
);
231 SmcSetProperties(sm_conn
, 1, &list
);
237 static void session_setup_restart_style(gboolean restart
)
239 gchar restart_hint
= restart
? SmRestartImmediately
: SmRestartIfRunning
;
242 .value
= &restart_hint
,
246 .name
= g_strdup(SmRestartStyleHint
),
247 .type
= g_strdup(SmCARD8
),
251 SmProp
*list
= &prop
;
252 ob_debug_type(OB_DEBUG_SM
, "Setting restart: %d", restart
);
253 SmcSetProperties(sm_conn
, 1, &list
);
258 static void session_setup_pid()
260 gchar
*pid
= g_strdup_printf("%ld", (glong
) getpid());
264 .length
= strlen(pid
) + 1
267 .name
= g_strdup(SmProcessID
),
268 .type
= g_strdup(SmARRAY8
),
272 SmProp
*list
= &prop
;
273 ob_debug_type(OB_DEBUG_SM
, "Setting pid: %s", pid
);
274 SmcSetProperties(sm_conn
, 1, &list
);
280 /*! This is a gnome-session-manager extension */
281 static void session_setup_priority()
283 gchar priority
= 20; /* 20 is a lower prioity to run before other apps */
290 .name
= g_strdup("_GSM_Priority"),
291 .type
= g_strdup(SmCARD8
),
295 SmProp
*list
= &prop
;
296 ob_debug_type(OB_DEBUG_SM
, "Setting priority: %d", priority
);
297 SmcSetProperties(sm_conn
, 1, &list
);
302 static void session_setup_clone_command()
306 SmPropValue
*vals
= g_new(SmPropValue
, sm_argc
);
308 .name
= g_strdup(SmCloneCommand
),
309 .type
= g_strdup(SmLISTofARRAY8
),
313 SmProp
*list
= &prop
;
315 ob_debug_type(OB_DEBUG_SM
, "Setting clone command: (%d)", sm_argc
);
316 for (i
= 0; i
< sm_argc
; ++i
) {
317 vals
[i
].value
= sm_argv
[i
];
318 vals
[i
].length
= strlen(sm_argv
[i
]) + 1;
319 ob_debug_type(OB_DEBUG_SM
, " %s", vals
[i
].value
);
322 SmcSetProperties(sm_conn
, 1, &list
);
328 static void session_setup_restart_command()
332 SmPropValue
*vals
= g_new(SmPropValue
, sm_argc
+ 4);
334 .name
= g_strdup(SmRestartCommand
),
335 .type
= g_strdup(SmLISTofARRAY8
),
336 .num_vals
= sm_argc
+ 4,
339 SmProp
*list
= &prop
;
341 ob_debug_type(OB_DEBUG_SM
, "Setting restart command: (%d)", sm_argc
+4);
342 for (i
= 0; i
< sm_argc
; ++i
) {
343 vals
[i
].value
= sm_argv
[i
];
344 vals
[i
].length
= strlen(sm_argv
[i
]) + 1;
345 ob_debug_type(OB_DEBUG_SM
, " %s", vals
[i
].value
);
348 vals
[i
].value
= g_strdup("--sm-client-id");
349 vals
[i
].length
= strlen("--sm-client-id") + 1;
350 vals
[i
+1].value
= ob_sm_id
;
351 vals
[i
+1].length
= strlen(ob_sm_id
) + 1;
352 ob_debug_type(OB_DEBUG_SM
, " %s", vals
[i
].value
);
353 ob_debug_type(OB_DEBUG_SM
, " %s", vals
[i
+1].value
);
355 vals
[i
+2].value
= g_strdup("--sm-save-file");
356 vals
[i
+2].length
= strlen("--sm-save-file") + 1;
357 vals
[i
+3].value
= ob_sm_save_file
;
358 vals
[i
+3].length
= strlen(ob_sm_save_file
) + 1;
359 ob_debug_type(OB_DEBUG_SM
, " %s", vals
[i
+2].value
);
360 ob_debug_type(OB_DEBUG_SM
, " %s", vals
[i
+3].value
);
362 SmcSetProperties(sm_conn
, 1, &list
);
365 g_free(vals
[i
].value
);
366 g_free(vals
[i
+2].value
);
370 static ObSMSaveData
*sm_save_get_data()
372 ObSMSaveData
*savedata
= g_new0(ObSMSaveData
, 1);
373 /* save the active desktop and client.
374 we don't bother to preemptively save the other desktop state like
375 number and names of desktops, cuz those shouldn't be changing during
377 savedata
->focus_client
= focus_client
;
378 savedata
->desktop
= screen_desktop
;
382 static void sm_save_yourself_2(SmcConn conn
, SmPointer data
)
385 ObSMSaveData
*savedata
= data
;
387 /* save the current state */
388 ob_debug_type(OB_DEBUG_SM
, "Session save phase 2 requested");
389 ob_debug_type(OB_DEBUG_SM
,
390 " Saving session to file '%s'", ob_sm_save_file
);
391 if (savedata
== NULL
)
392 savedata
= sm_save_get_data();
393 success
= session_save_to_file(savedata
);
396 /* tell the session manager how to restore this state */
397 if (success
) session_setup_restart_command();
399 ob_debug_type(OB_DEBUG_SM
, "Saving is done (success = %d)", success
);
400 SmcSaveYourselfDone(conn
, success
);
404 static void sm_save_yourself(SmcConn conn
, SmPointer data
, gint save_type
,
405 Bool shutdown
, gint interact_style
, Bool fast
)
407 ObSMSaveData
*savedata
= NULL
;
410 ob_debug_type(OB_DEBUG_SM
, "Session save requested");
412 vendor
= SmcVendor(sm_conn
);
413 ob_debug_type(OB_DEBUG_SM
, "Session manager's vendor: %s", vendor
);
415 if (!strcmp(vendor
, "KDE")) {
416 /* ksmserver guarantees that phase 1 will complete before allowing any
417 clients interaction, so we can save this sanely here before they
418 get messed up from interaction */
419 savedata
= sm_save_get_data();
423 if (!SmcRequestSaveYourselfPhase2(conn
, sm_save_yourself_2
, savedata
)) {
424 ob_debug_type(OB_DEBUG_SM
, "Requst for phase 2 failed");
426 SmcSaveYourselfDone(conn
, FALSE
);
430 static void sm_die(SmcConn conn
, SmPointer data
)
432 ob_debug_type(OB_DEBUG_SM
, "Die requested");
436 static void sm_save_complete(SmcConn conn
, SmPointer data
)
438 ob_debug_type(OB_DEBUG_SM
, "Save complete");
441 static void sm_shutdown_cancelled(SmcConn conn
, SmPointer data
)
443 ob_debug_type(OB_DEBUG_SM
, "Shutdown cancelled");
446 static gboolean
session_save_to_file(const ObSMSaveData
*savedata
)
450 gboolean success
= TRUE
;
452 f
= fopen(ob_sm_save_file
, "w");
455 g_message(_("Unable to save the session to '%s': %s"),
456 ob_sm_save_file
, g_strerror(errno
));
458 fprintf(f
, "<?xml version=\"1.0\"?>\n\n");
459 fprintf(f
, "<openbox_session>\n\n");
461 fprintf(f
, "<desktop>%d</desktop>\n", savedata
->desktop
);
463 fprintf(f
, "<numdesktops>%d</numdesktops>\n", screen_num_desktops
);
465 fprintf(f
, "<desktoplayout>\n");
466 fprintf(f
, " <orientation>%d</orientation>\n",
467 screen_desktop_layout
.orientation
);
468 fprintf(f
, " <startcorner>%d</startcorner>\n",
469 screen_desktop_layout
.start_corner
);
470 fprintf(f
, " <columns>%d</columns>\n",
471 screen_desktop_layout
.columns
);
472 fprintf(f
, " <rows>%d</rows>\n",
473 screen_desktop_layout
.rows
);
474 fprintf(f
, "</desktoplayout>\n");
476 if (screen_desktop_names
) {
479 fprintf(f
, "<desktopnames>\n");
480 for (i
= 0; screen_desktop_names
[i
]; ++i
)
481 fprintf(f
, " <name>%s</name>\n", screen_desktop_names
[i
]);
482 fprintf(f
, "</desktopnames>\n");
485 /* they are ordered top to bottom in stacking order */
486 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
487 gint prex
, prey
, prew
, preh
;
491 if (WINDOW_IS_CLIENT(it
->data
))
492 c
= WINDOW_AS_CLIENT(it
->data
);
496 if (!client_normal(c
))
499 if (!c
->sm_client_id
) {
500 ob_debug_type(OB_DEBUG_SM
, "Client %s does not have a "
503 if (!c
->wm_command
) {
504 ob_debug_type(OB_DEBUG_SM
, "Client %s does not have an "
505 "oldskool wm_command set either. We won't "
506 "be saving its data",
512 ob_debug_type(OB_DEBUG_SM
, "Saving state for client %s",
517 prew
= c
->area
.width
;
518 preh
= c
->area
.height
;
520 prex
= c
->pre_fullscreen_area
.x
;
521 prey
= c
->pre_fullscreen_area
.x
;
522 prew
= c
->pre_fullscreen_area
.width
;
523 preh
= c
->pre_fullscreen_area
.height
;
526 prex
= c
->pre_max_area
.x
;
527 prew
= c
->pre_max_area
.width
;
530 prey
= c
->pre_max_area
.y
;
531 preh
= c
->pre_max_area
.height
;
535 fprintf(f
, "<window id=\"%s\">\n", c
->sm_client_id
);
537 fprintf(f
, "<window command=\"%s\">\n", c
->wm_command
);
539 t
= g_markup_escape_text(c
->name
, -1);
540 fprintf(f
, "\t<name>%s</name>\n", t
);
543 t
= g_markup_escape_text(c
->class, -1);
544 fprintf(f
, "\t<class>%s</class>\n", t
);
547 t
= g_markup_escape_text(c
->role
, -1);
548 fprintf(f
, "\t<role>%s</role>\n", t
);
551 fprintf(f
, "\t<windowtype>%d</windowtype>\n", c
->type
);
553 fprintf(f
, "\t<desktop>%d</desktop>\n", c
->desktop
);
554 fprintf(f
, "\t<x>%d</x>\n", prex
);
555 fprintf(f
, "\t<y>%d</y>\n", prey
);
556 fprintf(f
, "\t<width>%d</width>\n", prew
);
557 fprintf(f
, "\t<height>%d</height>\n", preh
);
559 fprintf(f
, "\t<shaded />\n");
561 fprintf(f
, "\t<iconic />\n");
563 fprintf(f
, "\t<skip_pager />\n");
565 fprintf(f
, "\t<skip_taskbar />\n");
567 fprintf(f
, "\t<fullscreen />\n");
569 fprintf(f
, "\t<above />\n");
571 fprintf(f
, "\t<below />\n");
573 fprintf(f
, "\t<max_horz />\n");
575 fprintf(f
, "\t<max_vert />\n");
577 fprintf(f
, "\t<undecorated />\n");
578 if (savedata
->focus_client
== c
)
579 fprintf(f
, "\t<focused />\n");
580 fprintf(f
, "</window>\n\n");
583 fprintf(f
, "</openbox_session>\n");
587 g_message(_("Error while saving the session to '%s': %s"),
588 ob_sm_save_file
, g_strerror(errno
));
596 static void session_state_free(ObSessionState
*state
)
600 g_free(state
->command
);
602 g_free(state
->class);
609 static gboolean
session_state_cmp(ObSessionState
*s
, ObClient
*c
)
611 ob_debug_type(OB_DEBUG_SM
, "Comparing client against saved state: ");
612 ob_debug_type(OB_DEBUG_SM
, " client id: %s ", c
->sm_client_id
);
613 ob_debug_type(OB_DEBUG_SM
, " client name: %s ", c
->name
);
614 ob_debug_type(OB_DEBUG_SM
, " client class: %s ", c
->class);
615 ob_debug_type(OB_DEBUG_SM
, " client role: %s ", c
->role
);
616 ob_debug_type(OB_DEBUG_SM
, " client type: %d ", c
->type
);
617 ob_debug_type(OB_DEBUG_SM
, " client command: %s ",
618 c
->wm_command
? c
->wm_command
: "(null)");
619 ob_debug_type(OB_DEBUG_SM
, " state id: %s ", s
->id
);
620 ob_debug_type(OB_DEBUG_SM
, " state name: %s ", s
->name
);
621 ob_debug_type(OB_DEBUG_SM
, " state class: %s ", s
->class);
622 ob_debug_type(OB_DEBUG_SM
, " state role: %s ", s
->role
);
623 ob_debug_type(OB_DEBUG_SM
, " state type: %d ", s
->type
);
624 ob_debug_type(OB_DEBUG_SM
, " state command: %s ",
625 s
->command
? s
->command
: "(null)");
627 if ((c
->sm_client_id
&& s
->id
&& !strcmp(c
->sm_client_id
, s
->id
)) ||
628 (c
->wm_command
&& s
->command
&& !strcmp(c
->wm_command
, s
->command
)))
630 return (!strcmp(s
->name
, c
->name
) &&
631 !strcmp(s
->class, c
->class) &&
632 !strcmp(s
->role
, c
->role
) &&
633 /* the check for type is to catch broken clients, like
634 firefox, which open a different window on startup
635 with the same info as the one we saved. only do this
636 check for old windows that dont use xsmp, others should
638 (!s
->command
|| c
->type
== s
->type
));
643 GList
* session_state_find(ObClient
*c
)
647 for (it
= session_saved_state
; it
; it
= g_list_next(it
)) {
648 ObSessionState
*s
= it
->data
;
649 if (!s
->matched
&& session_state_cmp(s
, c
)) {
657 static void session_load_file(const gchar
*path
)
660 xmlNodePtr node
, n
, m
;
663 i
= obt_parse_instance_new();
665 if (!obt_parse_load_file(i
, path
, "openbox_session")) {
666 obt_parse_instance_unref(i
);
669 node
= obt_parse_root(i
);
671 if ((n
= obt_parse_find_node(node
->children
, "desktop")))
672 session_desktop
= obt_parse_node_int(n
);
674 if ((n
= obt_parse_find_node(node
->children
, "numdesktops")))
675 session_num_desktops
= obt_parse_node_int(n
);
677 if ((n
= obt_parse_find_node(node
->children
, "desktoplayout"))) {
678 /* make sure they are all there for it to be valid */
679 if ((m
= obt_parse_find_node(n
->children
, "orientation")))
680 session_desktop_layout
.orientation
= obt_parse_node_int(m
);
681 if (m
&& (m
= obt_parse_find_node(n
->children
, "startcorner")))
682 session_desktop_layout
.start_corner
= obt_parse_node_int(m
);
683 if (m
&& (m
= obt_parse_find_node(n
->children
, "columns")))
684 session_desktop_layout
.columns
= obt_parse_node_int(m
);
685 if (m
&& (m
= obt_parse_find_node(n
->children
, "rows")))
686 session_desktop_layout
.rows
= obt_parse_node_int(m
);
687 session_desktop_layout_present
= m
!= NULL
;
690 if ((n
= obt_parse_find_node(node
->children
, "desktopnames"))) {
691 for (m
= obt_parse_find_node(n
->children
, "name"); m
;
692 m
= obt_parse_find_node(m
->next
, "name"))
694 session_desktop_names
= g_slist_append(session_desktop_names
,
695 obt_parse_node_string(m
));
699 for (node
= obt_parse_find_node(node
->children
, "window"); node
!= NULL
;
700 node
= obt_parse_find_node(node
->next
, "window"))
702 ObSessionState
*state
;
704 state
= g_new0(ObSessionState
, 1);
706 if (!obt_parse_attr_string(node
, "id", &state
->id
))
707 if (!obt_parse_attr_string(node
, "command", &state
->command
))
708 goto session_load_bail
;
709 if (!(n
= obt_parse_find_node(node
->children
, "name")))
710 goto session_load_bail
;
711 state
->name
= obt_parse_node_string(n
);
712 if (!(n
= obt_parse_find_node(node
->children
, "class")))
713 goto session_load_bail
;
714 state
->class = obt_parse_node_string(n
);
715 if (!(n
= obt_parse_find_node(node
->children
, "role")))
716 goto session_load_bail
;
717 state
->role
= obt_parse_node_string(n
);
718 if (!(n
= obt_parse_find_node(node
->children
, "windowtype")))
719 goto session_load_bail
;
720 state
->type
= obt_parse_node_int(n
);
721 if (!(n
= obt_parse_find_node(node
->children
, "desktop")))
722 goto session_load_bail
;
723 state
->desktop
= obt_parse_node_int(n
);
724 if (!(n
= obt_parse_find_node(node
->children
, "x")))
725 goto session_load_bail
;
726 state
->x
= obt_parse_node_int(n
);
727 if (!(n
= obt_parse_find_node(node
->children
, "y")))
728 goto session_load_bail
;
729 state
->y
= obt_parse_node_int(n
);
730 if (!(n
= obt_parse_find_node(node
->children
, "width")))
731 goto session_load_bail
;
732 state
->w
= obt_parse_node_int(n
);
733 if (!(n
= obt_parse_find_node(node
->children
, "height")))
734 goto session_load_bail
;
735 state
->h
= obt_parse_node_int(n
);
738 obt_parse_find_node(node
->children
, "shaded") != NULL
;
740 obt_parse_find_node(node
->children
, "iconic") != NULL
;
742 obt_parse_find_node(node
->children
, "skip_pager") != NULL
;
743 state
->skip_taskbar
=
744 obt_parse_find_node(node
->children
, "skip_taskbar") != NULL
;
746 obt_parse_find_node(node
->children
, "fullscreen") != NULL
;
748 obt_parse_find_node(node
->children
, "above") != NULL
;
750 obt_parse_find_node(node
->children
, "below") != NULL
;
752 obt_parse_find_node(node
->children
, "max_horz") != NULL
;
754 obt_parse_find_node(node
->children
, "max_vert") != NULL
;
756 obt_parse_find_node(node
->children
, "undecorated") != NULL
;
758 obt_parse_find_node(node
->children
, "focused") != NULL
;
760 /* save this. they are in the file in stacking order, so preserve
762 session_saved_state
= g_list_append(session_saved_state
, state
);
766 session_state_free(state
);
769 /* Remove any duplicates. This means that if two windows (or more) are
770 saved with the same session state, we won't restore a session for any
771 of them because we don't know what window to put what on. AHEM FIREFOX.
773 This is going to be an O(2^n) kind of operation unfortunately.
775 for (it
= session_saved_state
; it
; it
= inext
) {
777 gboolean founddup
= FALSE
;
778 ObSessionState
*s1
= it
->data
;
780 inext
= g_list_next(it
);
782 for (jt
= g_list_next(it
); jt
; jt
= jnext
) {
783 ObSessionState
*s2
= jt
->data
;
786 jnext
= g_list_next(jt
);
788 if (s1
->id
&& s2
->id
)
789 match
= strcmp(s1
->id
, s2
->id
) == 0;
790 else if (s1
->command
&& s2
->command
)
791 match
= strcmp(s1
->command
, s2
->command
) == 0;
796 !strcmp(s1
->name
, s2
->name
) &&
797 !strcmp(s1
->class, s2
->class) &&
798 !strcmp(s1
->role
, s2
->role
))
800 session_state_free(s2
);
801 session_saved_state
=
802 g_list_delete_link(session_saved_state
, jt
);
808 session_state_free(s1
);
809 session_saved_state
= g_list_delete_link(session_saved_state
, it
);
813 obt_parse_instance_unref(i
);