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"
50 # include <sys/types.h>
54 #include <X11/SM/SMlib.h>
56 #define SM_ERR_LEN 1024
58 static SmcConn sm_conn
;
60 static gchar
**sm_argv
;
62 /* Data saved from the first level save yourself */
64 ObClient
*focus_client
;
68 static gboolean
session_connect();
70 static void session_load_file(const gchar
*path
);
71 static gboolean
session_save_to_file(const ObSMSaveData
*savedata
);
73 static void session_setup_program();
74 static void session_setup_user();
75 static void session_setup_restart_style(gboolean restart
);
76 static void session_setup_pid();
77 static void session_setup_priority();
78 static void session_setup_clone_command();
79 static void session_setup_restart_command();
81 static void sm_save_yourself(SmcConn conn
, SmPointer data
, gint save_type
,
82 Bool shutdown
, gint interact_style
, Bool fast
);
83 static void sm_die(SmcConn conn
, SmPointer data
);
84 static void sm_save_complete(SmcConn conn
, SmPointer data
);
85 static void sm_shutdown_cancelled(SmcConn conn
, SmPointer data
);
87 static gboolean
session_state_cmp(ObSessionState
*s
, ObClient
*c
);
88 static void session_state_free(ObSessionState
*state
);
90 void session_startup(gint argc
, gchar
**argv
)
94 if (!ob_sm_use
) return;
99 dir
= g_build_filename(parse_xdg_data_home_path(),
100 "openbox", "sessions", NULL
);
101 if (!parse_mkdir_path(dir
, 0700)) {
102 g_message(_("Unable to make directory '%s': %s"),
103 dir
, g_strerror(errno
));
106 if (ob_sm_save_file
!= NULL
) {
108 ob_debug_type(OB_DEBUG_SM
, "Loading from session file %s\n",
110 session_load_file(ob_sm_save_file
);
115 /* this algo is from metacity */
116 filename
= g_strdup_printf("%u-%u-%u.obs",
120 ob_sm_save_file
= g_build_filename(dir
, filename
, NULL
);
124 if (session_connect()) {
125 session_setup_program();
126 session_setup_user();
127 session_setup_restart_style(TRUE
);
129 session_setup_priority();
130 session_setup_clone_command();
136 void session_shutdown(gboolean permanent
)
138 if (!ob_sm_use
) return;
141 /* if permanent is true then we will change our session state so that
142 the SM won't run us again */
144 session_setup_restart_style(FALSE
);
146 SmcCloseConnection(sm_conn
, 0, NULL
);
148 while (session_saved_state
) {
149 session_state_free(session_saved_state
->data
);
150 session_saved_state
= g_list_delete_link(session_saved_state
,
151 session_saved_state
);
156 /*! Connect to the session manager and set up our callback functions */
157 static gboolean
session_connect()
161 gchar sm_err
[SM_ERR_LEN
];
163 /* set up our callback functions */
164 cb
.save_yourself
.callback
= sm_save_yourself
;
165 cb
.save_yourself
.client_data
= NULL
;
166 cb
.die
.callback
= sm_die
;
167 cb
.die
.client_data
= NULL
;
168 cb
.save_complete
.callback
= sm_save_complete
;
169 cb
.save_complete
.client_data
= NULL
;
170 cb
.shutdown_cancelled
.callback
= sm_shutdown_cancelled
;
171 cb
.shutdown_cancelled
.client_data
= NULL
;
173 /* connect to the server */
175 ob_debug_type(OB_DEBUG_SM
, "Connecting to SM with id: %s\n",
176 oldid
? oldid
: "(null)");
177 sm_conn
= SmcOpenConnection(NULL
, NULL
, 1, 0,
178 SmcSaveYourselfProcMask
|
180 SmcSaveCompleteProcMask
|
181 SmcShutdownCancelledProcMask
,
182 &cb
, oldid
, &ob_sm_id
,
183 SM_ERR_LEN
-1, sm_err
);
185 ob_debug_type(OB_DEBUG_SM
, "Connected to SM with id: %s\n", ob_sm_id
);
187 ob_debug("Failed to connect to session manager: %s\n", sm_err
);
188 return sm_conn
!= NULL
;
191 static void session_setup_program()
195 .length
= strlen(sm_argv
[0]) + 1
198 .name
= g_strdup(SmProgram
),
199 .type
= g_strdup(SmARRAY8
),
203 SmProp
*list
= &prop
;
204 ob_debug_type(OB_DEBUG_SM
, "Setting program: %s\n", sm_argv
[0]);
205 SmcSetProperties(sm_conn
, 1, &list
);
210 static void session_setup_user()
212 char *user
= g_strdup(g_get_user_name());
216 .length
= strlen(user
) + 1
219 .name
= g_strdup(SmUserID
),
220 .type
= g_strdup(SmARRAY8
),
224 SmProp
*list
= &prop
;
225 ob_debug_type(OB_DEBUG_SM
, "Setting user: %s\n", user
);
226 SmcSetProperties(sm_conn
, 1, &list
);
232 static void session_setup_restart_style(gboolean restart
)
234 gchar restart_hint
= restart
? SmRestartImmediately
: SmRestartIfRunning
;
237 .value
= &restart_hint
,
241 .name
= g_strdup(SmRestartStyleHint
),
242 .type
= g_strdup(SmCARD8
),
246 SmProp
*list
= &prop
;
247 ob_debug_type(OB_DEBUG_SM
, "Setting restart: %d\n", restart
);
248 SmcSetProperties(sm_conn
, 1, &list
);
253 static void session_setup_pid()
255 gchar
*pid
= g_strdup_printf("%ld", (glong
) getpid());
259 .length
= strlen(pid
) + 1
262 .name
= g_strdup(SmProcessID
),
263 .type
= g_strdup(SmARRAY8
),
267 SmProp
*list
= &prop
;
268 ob_debug_type(OB_DEBUG_SM
, "Setting pid: %s\n", pid
);
269 SmcSetProperties(sm_conn
, 1, &list
);
275 /*! This is a gnome-session-manager extension */
276 static void session_setup_priority()
278 gchar priority
= 20; /* 20 is a lower prioity to run before other apps */
285 .name
= g_strdup("_GSM_Priority"),
286 .type
= g_strdup(SmCARD8
),
290 SmProp
*list
= &prop
;
291 ob_debug_type(OB_DEBUG_SM
, "Setting priority: %d\n", priority
);
292 SmcSetProperties(sm_conn
, 1, &list
);
297 static void session_setup_clone_command()
301 SmPropValue
*vals
= g_new(SmPropValue
, sm_argc
);
303 .name
= g_strdup(SmCloneCommand
),
304 .type
= g_strdup(SmLISTofARRAY8
),
308 SmProp
*list
= &prop
;
310 ob_debug_type(OB_DEBUG_SM
, "Setting clone command: (%d)\n", sm_argc
);
311 for (i
= 0; i
< sm_argc
; ++i
) {
312 vals
[i
].value
= sm_argv
[i
];
313 vals
[i
].length
= strlen(sm_argv
[i
]) + 1;
314 ob_debug_type(OB_DEBUG_SM
, " %s\n", vals
[i
].value
);
317 SmcSetProperties(sm_conn
, 1, &list
);
323 static void session_setup_restart_command()
327 SmPropValue
*vals
= g_new(SmPropValue
, sm_argc
+ 4);
329 .name
= g_strdup(SmRestartCommand
),
330 .type
= g_strdup(SmLISTofARRAY8
),
331 .num_vals
= sm_argc
+ 4,
334 SmProp
*list
= &prop
;
336 ob_debug_type(OB_DEBUG_SM
, "Setting restart command: (%d)\n", sm_argc
+4);
337 for (i
= 0; i
< sm_argc
; ++i
) {
338 vals
[i
].value
= sm_argv
[i
];
339 vals
[i
].length
= strlen(sm_argv
[i
]) + 1;
340 ob_debug_type(OB_DEBUG_SM
, " %s\n", vals
[i
].value
);
343 vals
[i
].value
= g_strdup("--sm-client-id");
344 vals
[i
].length
= strlen("--sm-client-id") + 1;
345 vals
[i
+1].value
= ob_sm_id
;
346 vals
[i
+1].length
= strlen(ob_sm_id
) + 1;
347 ob_debug_type(OB_DEBUG_SM
, " %s\n", vals
[i
].value
);
348 ob_debug_type(OB_DEBUG_SM
, " %s\n", vals
[i
+1].value
);
350 vals
[i
+2].value
= g_strdup("--sm-save-file");
351 vals
[i
+2].length
= strlen("--sm-save-file") + 1;
352 vals
[i
+3].value
= ob_sm_save_file
;
353 vals
[i
+3].length
= strlen(ob_sm_save_file
) + 1;
354 ob_debug_type(OB_DEBUG_SM
, " %s\n", vals
[i
+2].value
);
355 ob_debug_type(OB_DEBUG_SM
, " %s\n", vals
[i
+3].value
);
357 SmcSetProperties(sm_conn
, 1, &list
);
360 g_free(vals
[i
].value
);
361 g_free(vals
[i
+2].value
);
365 static ObSMSaveData
*sm_save_get_data()
367 ObSMSaveData
*savedata
= g_new0(ObSMSaveData
, 1);
368 /* save the active desktop and client.
369 we don't bother to preemptively save the other desktop state like
370 number and names of desktops, cuz those shouldn't be changing during
372 savedata
->focus_client
= focus_client
;
373 savedata
->desktop
= screen_desktop
;
377 static void sm_save_yourself_2(SmcConn conn
, SmPointer data
)
380 ObSMSaveData
*savedata
= data
;
382 /* save the current state */
383 ob_debug_type(OB_DEBUG_SM
, "Session save phase 2 requested\n");
384 ob_debug_type(OB_DEBUG_SM
,
385 " Saving session to file '%s'\n", ob_sm_save_file
);
386 if (savedata
== NULL
)
387 savedata
= sm_save_get_data();
388 success
= session_save_to_file(savedata
);
391 /* tell the session manager how to restore this state */
392 if (success
) session_setup_restart_command();
394 ob_debug_type(OB_DEBUG_SM
, "Saving is done (success = %d)\n", success
);
395 SmcSaveYourselfDone(conn
, success
);
399 static void sm_save_yourself(SmcConn conn
, SmPointer data
, gint save_type
,
400 Bool shutdown
, gint interact_style
, Bool fast
)
402 ObSMSaveData
*savedata
= NULL
;
405 ob_debug_type(OB_DEBUG_SM
, "Session save requested\n");
407 vendor
= SmcVendor(sm_conn
);
408 ob_debug_type(OB_DEBUG_SM
, "Session manager's vendor: %s\n", vendor
);
410 if (!strcmp(vendor
, "KDE")) {
411 /* ksmserver guarantees that phase 1 will complete before allowing any
412 clients interaction, so we can save this sanely here before they
413 get messed up from interaction */
414 savedata
= sm_save_get_data();
418 if (!SmcRequestSaveYourselfPhase2(conn
, sm_save_yourself_2
, savedata
)) {
419 ob_debug_type(OB_DEBUG_SM
, "Requst for phase 2 failed\n");
421 SmcSaveYourselfDone(conn
, FALSE
);
425 static void sm_die(SmcConn conn
, SmPointer data
)
427 ob_debug_type(OB_DEBUG_SM
, "Die requested\n");
431 static void sm_save_complete(SmcConn conn
, SmPointer data
)
433 ob_debug_type(OB_DEBUG_SM
, "Save complete\n");
436 static void sm_shutdown_cancelled(SmcConn conn
, SmPointer data
)
438 ob_debug_type(OB_DEBUG_SM
, "Shutdown cancelled\n");
441 static gboolean
session_save_to_file(const ObSMSaveData
*savedata
)
445 gboolean success
= TRUE
;
447 f
= fopen(ob_sm_save_file
, "w");
450 g_message(_("Unable to save the session to '%s': %s"),
451 ob_sm_save_file
, g_strerror(errno
));
453 fprintf(f
, "<?xml version=\"1.0\"?>\n\n");
454 fprintf(f
, "<openbox_session>\n\n");
456 fprintf(f
, "<desktop>%d</desktop>\n", savedata
->desktop
);
458 fprintf(f
, "<numdesktops>%d</numdesktops>\n", screen_num_desktops
);
460 fprintf(f
, "<desktoplayout>\n");
461 fprintf(f
, " <orientation>%d</orientation>\n",
462 screen_desktop_layout
.orientation
);
463 fprintf(f
, " <startcorner>%d</startcorner>\n",
464 screen_desktop_layout
.start_corner
);
465 fprintf(f
, " <columns>%d</columns>\n",
466 screen_desktop_layout
.columns
);
467 fprintf(f
, " <rows>%d</rows>\n",
468 screen_desktop_layout
.rows
);
469 fprintf(f
, "</desktoplayout>\n");
471 if (screen_desktop_names
) {
474 fprintf(f
, "<desktopnames>\n");
475 for (i
= 0; screen_desktop_names
[i
]; ++i
)
476 fprintf(f
, " <name>%s</name>\n", screen_desktop_names
[i
]);
477 fprintf(f
, "</desktopnames>\n");
480 /* they are ordered top to bottom in stacking order */
481 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
482 gint prex
, prey
, prew
, preh
;
486 if (WINDOW_IS_CLIENT(it
->data
))
487 c
= WINDOW_AS_CLIENT(it
->data
);
491 if (!client_normal(c
))
494 if (!c
->sm_client_id
) {
495 ob_debug_type(OB_DEBUG_SM
, "Client %s does not have a "
498 if (!c
->wm_command
) {
499 ob_debug_type(OB_DEBUG_SM
, "Client %s does not have an "
500 "oldskool wm_command set either. We won't "
501 "be saving its data\n",
507 ob_debug_type(OB_DEBUG_SM
, "Saving state for client %s\n",
512 prew
= c
->area
.width
;
513 preh
= c
->area
.height
;
515 prex
= c
->pre_fullscreen_area
.x
;
516 prey
= c
->pre_fullscreen_area
.x
;
517 prew
= c
->pre_fullscreen_area
.width
;
518 preh
= c
->pre_fullscreen_area
.height
;
521 prex
= c
->pre_max_area
.x
;
522 prew
= c
->pre_max_area
.width
;
525 prey
= c
->pre_max_area
.y
;
526 preh
= c
->pre_max_area
.height
;
530 fprintf(f
, "<window id=\"%s\">\n", c
->sm_client_id
);
532 fprintf(f
, "<window command=\"%s\">\n", c
->wm_command
);
534 t
= g_markup_escape_text(c
->name
, -1);
535 fprintf(f
, "\t<name>%s</name>\n", t
);
538 t
= g_markup_escape_text(c
->class, -1);
539 fprintf(f
, "\t<class>%s</class>\n", t
);
542 t
= g_markup_escape_text(c
->role
, -1);
543 fprintf(f
, "\t<role>%s</role>\n", t
);
546 fprintf(f
, "\t<windowtype>%d</windowtype>\n", c
->type
);
548 fprintf(f
, "\t<desktop>%d</desktop>\n", c
->desktop
);
549 fprintf(f
, "\t<x>%d</x>\n", prex
);
550 fprintf(f
, "\t<y>%d</y>\n", prey
);
551 fprintf(f
, "\t<width>%d</width>\n", prew
);
552 fprintf(f
, "\t<height>%d</height>\n", preh
);
554 fprintf(f
, "\t<shaded />\n");
556 fprintf(f
, "\t<iconic />\n");
558 fprintf(f
, "\t<skip_pager />\n");
560 fprintf(f
, "\t<skip_taskbar />\n");
562 fprintf(f
, "\t<fullscreen />\n");
564 fprintf(f
, "\t<above />\n");
566 fprintf(f
, "\t<below />\n");
568 fprintf(f
, "\t<max_horz />\n");
570 fprintf(f
, "\t<max_vert />\n");
572 fprintf(f
, "\t<undecorated />\n");
573 if (savedata
->focus_client
== c
)
574 fprintf(f
, "\t<focused />\n");
575 fprintf(f
, "</window>\n\n");
578 fprintf(f
, "</openbox_session>\n");
582 g_message(_("Error while saving the session to '%s': %s"),
583 ob_sm_save_file
, g_strerror(errno
));
591 static void session_state_free(ObSessionState
*state
)
595 g_free(state
->command
);
597 g_free(state
->class);
604 static gboolean
session_state_cmp(ObSessionState
*s
, ObClient
*c
)
606 ob_debug_type(OB_DEBUG_SM
, "Comparing client against saved state: \n");
607 ob_debug_type(OB_DEBUG_SM
, " client id: %s \n", c
->sm_client_id
);
608 ob_debug_type(OB_DEBUG_SM
, " client name: %s \n", c
->name
);
609 ob_debug_type(OB_DEBUG_SM
, " client class: %s \n", c
->class);
610 ob_debug_type(OB_DEBUG_SM
, " client role: %s \n", c
->role
);
611 ob_debug_type(OB_DEBUG_SM
, " client type: %d \n", c
->type
);
612 ob_debug_type(OB_DEBUG_SM
, " client command: %s \n",
613 c
->wm_command
? c
->wm_command
: "(null)");
614 ob_debug_type(OB_DEBUG_SM
, " state id: %s \n", s
->id
);
615 ob_debug_type(OB_DEBUG_SM
, " state name: %s \n", s
->name
);
616 ob_debug_type(OB_DEBUG_SM
, " state class: %s \n", s
->class);
617 ob_debug_type(OB_DEBUG_SM
, " state role: %s \n", s
->role
);
618 ob_debug_type(OB_DEBUG_SM
, " state type: %d \n", s
->type
);
619 ob_debug_type(OB_DEBUG_SM
, " state command: %s \n",
620 s
->command
? s
->command
: "(null)");
622 if ((c
->sm_client_id
&& s
->id
&& !strcmp(c
->sm_client_id
, s
->id
)) ||
623 (c
->wm_command
&& s
->command
&& !strcmp(c
->wm_command
, s
->command
)))
625 return (!strcmp(s
->name
, c
->name
) &&
626 !strcmp(s
->class, c
->class) &&
627 !strcmp(s
->role
, c
->role
) &&
628 /* the check for type is to catch broken clients, like
629 firefox, which open a different window on startup
630 with the same info as the one we saved. only do this
631 check for old windows that dont use xsmp, others should
633 (!s
->command
|| c
->type
== s
->type
));
638 GList
* session_state_find(ObClient
*c
)
642 for (it
= session_saved_state
; it
; it
= g_list_next(it
)) {
643 ObSessionState
*s
= it
->data
;
644 if (!s
->matched
&& session_state_cmp(s
, c
)) {
652 static void session_load_file(const gchar
*path
)
655 xmlNodePtr node
, n
, m
;
658 i
= obt_parse_instance_new();
660 if (!obt_parse_load_file(i
, path
, "openbox_session")) {
661 obt_parse_instance_unref(i
);
664 node
= obt_parse_instance_root(i
);
666 if ((n
= obt_parse_find_node(node
->children
, "desktop")))
667 session_desktop
= obt_parse_node_int(n
);
669 if ((n
= obt_parse_find_node(node
->children
, "numdesktops")))
670 session_num_desktops
= obt_parse_node_int(n
);
672 if ((n
= obt_parse_find_node(node
->children
, "desktoplayout"))) {
673 /* make sure they are all there for it to be valid */
674 if ((m
= obt_parse_find_node(n
->children
, "orientation")))
675 session_desktop_layout
.orientation
= obt_parse_node_int(m
);
676 if (m
&& (m
= obt_parse_find_node(n
->children
, "startcorner")))
677 session_desktop_layout
.start_corner
= obt_parse_node_int(m
);
678 if (m
&& (m
= obt_parse_find_node(n
->children
, "columns")))
679 session_desktop_layout
.columns
= obt_parse_node_int(m
);
680 if (m
&& (m
= obt_parse_find_node(n
->children
, "rows")))
681 session_desktop_layout
.rows
= obt_parse_node_int(m
);
682 session_desktop_layout_present
= m
!= NULL
;
685 if ((n
= obt_parse_find_node(node
->children
, "desktopnames"))) {
686 for (m
= obt_parse_find_node(n
->children
, "name"); m
;
687 m
= obt_parse_find_node(m
->next
, "name"))
689 session_desktop_names
= g_slist_append(session_desktop_names
,
690 obt_parse_node_string(m
));
694 for (node
= obt_parse_find_node(node
->children
, "window"); node
!= NULL
;
695 node
= obt_parse_find_node(node
->next
, "window"))
697 ObSessionState
*state
;
699 state
= g_new0(ObSessionState
, 1);
701 if (!obt_parse_attr_string(node
, "id", &state
->id
))
702 if (!obt_parse_attr_string(node
, "command", &state
->command
))
703 goto session_load_bail
;
704 if (!(n
= obt_parse_find_node(node
->children
, "name")))
705 goto session_load_bail
;
706 state
->name
= obt_parse_node_string(n
);
707 if (!(n
= obt_parse_find_node(node
->children
, "class")))
708 goto session_load_bail
;
709 state
->class = obt_parse_node_string(n
);
710 if (!(n
= obt_parse_find_node(node
->children
, "role")))
711 goto session_load_bail
;
712 state
->role
= obt_parse_node_string(n
);
713 if (!(n
= obt_parse_find_node(node
->children
, "windowtype")))
714 goto session_load_bail
;
715 state
->type
= obt_parse_node_int(n
);
716 if (!(n
= obt_parse_find_node(node
->children
, "desktop")))
717 goto session_load_bail
;
718 state
->desktop
= obt_parse_node_int(n
);
719 if (!(n
= obt_parse_find_node(node
->children
, "x")))
720 goto session_load_bail
;
721 state
->x
= obt_parse_node_int(n
);
722 if (!(n
= obt_parse_find_node(node
->children
, "y")))
723 goto session_load_bail
;
724 state
->y
= obt_parse_node_int(n
);
725 if (!(n
= obt_parse_find_node(node
->children
, "width")))
726 goto session_load_bail
;
727 state
->w
= obt_parse_node_int(n
);
728 if (!(n
= obt_parse_find_node(node
->children
, "height")))
729 goto session_load_bail
;
730 state
->h
= obt_parse_node_int(n
);
733 obt_parse_find_node(node
->children
, "shaded") != NULL
;
735 obt_parse_find_node(node
->children
, "iconic") != NULL
;
737 obt_parse_find_node(node
->children
, "skip_pager") != NULL
;
738 state
->skip_taskbar
=
739 obt_parse_find_node(node
->children
, "skip_taskbar") != NULL
;
741 obt_parse_find_node(node
->children
, "fullscreen") != NULL
;
743 obt_parse_find_node(node
->children
, "above") != NULL
;
745 obt_parse_find_node(node
->children
, "below") != NULL
;
747 obt_parse_find_node(node
->children
, "max_horz") != NULL
;
749 obt_parse_find_node(node
->children
, "max_vert") != NULL
;
751 obt_parse_find_node(node
->children
, "undecorated") != NULL
;
753 obt_parse_find_node(node
->children
, "focused") != NULL
;
755 /* save this. they are in the file in stacking order, so preserve
757 session_saved_state
= g_list_append(session_saved_state
, state
);
761 session_state_free(state
);
764 /* Remove any duplicates. This means that if two windows (or more) are
765 saved with the same session state, we won't restore a session for any
766 of them because we don't know what window to put what on. AHEM FIREFOX.
768 This is going to be an O(2^n) kind of operation unfortunately.
770 for (it
= session_saved_state
; it
; it
= inext
) {
772 gboolean founddup
= FALSE
;
773 ObSessionState
*s1
= it
->data
;
775 inext
= g_list_next(it
);
777 for (jt
= g_list_next(it
); jt
; jt
= jnext
) {
778 ObSessionState
*s2
= jt
->data
;
781 jnext
= g_list_next(jt
);
783 if (s1
->id
&& s2
->id
)
784 match
= strcmp(s1
->id
, s2
->id
) == 0;
785 else if (s1
->command
&& s2
->command
)
786 match
= strcmp(s1
->command
, s2
->command
) == 0;
791 !strcmp(s1
->name
, s2
->name
) &&
792 !strcmp(s1
->class, s2
->class) &&
793 !strcmp(s1
->role
, s2
->role
))
795 session_state_free(s2
);
796 session_saved_state
=
797 g_list_delete_link(session_saved_state
, jt
);
803 session_state_free(s1
);
804 session_saved_state
= g_list_delete_link(session_saved_state
, it
);
808 obt_parse_instance_unref(i
);