]> Dogcows Code - chaz/openbox/blob - openbox/session.c
fix libwnck by unmapping the plate window as well as the client during iconify animation
[chaz/openbox] / openbox / session.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3 session.c for the Openbox window manager
4 Copyright (c) 2003-2007 Dana Jansens
5
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.
10
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.
15
16 See the COPYING file for a copy of the GNU General Public License.
17 */
18
19 /* This session code is largely inspired by metacity code. */
20
21 #include "session.h"
22
23 struct _ObClient;
24
25 GList *session_saved_state = NULL;
26 gint session_desktop = -1;
27
28 #ifndef USE_SM
29 void session_startup(gint argc, gchar **argv) {}
30 void session_shutdown(gboolean permanent) {}
31 GList* session_state_find(struct _ObClient *c) { return NULL; }
32 #else
33
34 #include "debug.h"
35 #include "openbox.h"
36 #include "client.h"
37 #include "prop.h"
38 #include "focus.h"
39 #include "screen.h"
40 #include "gettext.h"
41 #include "parser/parse.h"
42
43 #include <time.h>
44 #include <errno.h>
45 #include <stdio.h>
46
47 #ifdef HAVE_UNISTD_H
48 # include <sys/types.h>
49 # include <unistd.h>
50 #endif
51
52 #include <X11/SM/SMlib.h>
53
54 #define SM_ERR_LEN 1024
55
56 static SmcConn sm_conn;
57 static gint sm_argc;
58 static gchar **sm_argv;
59
60 /* Data saved from the first level save yourself */
61 typedef struct {
62 ObClient *focus_client;
63 gint desktop;
64 } ObSMSaveData;
65
66 static gboolean session_connect();
67
68 static void session_load_file(const gchar *path);
69 static gboolean session_save_to_file(const ObSMSaveData *savedata);
70
71 static void session_setup_program();
72 static void session_setup_user();
73 static void session_setup_restart_style(gboolean restart);
74 static void session_setup_pid();
75 static void session_setup_priority();
76 static void session_setup_clone_command();
77 static void session_setup_restart_command();
78
79 static void sm_save_yourself(SmcConn conn, SmPointer data, gint save_type,
80 Bool shutdown, gint interact_style, Bool fast);
81 static void sm_die(SmcConn conn, SmPointer data);
82 static void sm_save_complete(SmcConn conn, SmPointer data);
83 static void sm_shutdown_cancelled(SmcConn conn, SmPointer data);
84
85 static gboolean session_state_cmp(ObSessionState *s, ObClient *c);
86 static void session_state_free(ObSessionState *state);
87
88 void session_startup(gint argc, gchar **argv)
89 {
90 gchar *dir;
91
92 if (!ob_sm_use) return;
93
94 sm_argc = argc;
95 sm_argv = argv;
96
97 dir = g_build_filename(parse_xdg_data_home_path(),
98 "openbox", "sessions", NULL);
99 if (!parse_mkdir_path(dir, 0700)) {
100 g_message(_("Unable to make directory '%s': %s"),
101 dir, g_strerror(errno));
102 }
103
104 if (ob_sm_save_file != NULL) {
105 if (ob_sm_restore) {
106 ob_debug_type(OB_DEBUG_SM, "Loading from session file %s\n",
107 ob_sm_save_file);
108 session_load_file(ob_sm_save_file);
109 }
110 } else {
111 gchar *filename;
112
113 /* this algo is from metacity */
114 filename = g_strdup_printf("%u-%u-%u.obs",
115 (guint)time(NULL),
116 (guint)getpid(),
117 g_random_int());
118 ob_sm_save_file = g_build_filename(dir, filename, NULL);
119 g_free(filename);
120 }
121
122 if (session_connect()) {
123 session_setup_program();
124 session_setup_user();
125 session_setup_restart_style(TRUE);
126 session_setup_pid();
127 session_setup_priority();
128 session_setup_clone_command();
129 }
130
131 g_free(dir);
132 }
133
134 void session_shutdown(gboolean permanent)
135 {
136 if (!ob_sm_use) return;
137
138 if (sm_conn) {
139 /* if permanent is true then we will change our session state so that
140 the SM won't run us again */
141 if (permanent)
142 session_setup_restart_style(FALSE);
143
144 SmcCloseConnection(sm_conn, 0, NULL);
145
146 while (session_saved_state) {
147 session_state_free(session_saved_state->data);
148 session_saved_state = g_list_delete_link(session_saved_state,
149 session_saved_state);
150 }
151 }
152 }
153
154 /*! Connect to the session manager and set up our callback functions */
155 static gboolean session_connect()
156 {
157 SmcCallbacks cb;
158 gchar *oldid;
159 gchar sm_err[SM_ERR_LEN];
160
161 /* set up our callback functions */
162 cb.save_yourself.callback = sm_save_yourself;
163 cb.save_yourself.client_data = NULL;
164 cb.die.callback = sm_die;
165 cb.die.client_data = NULL;
166 cb.save_complete.callback = sm_save_complete;
167 cb.save_complete.client_data = NULL;
168 cb.shutdown_cancelled.callback = sm_shutdown_cancelled;
169 cb.shutdown_cancelled.client_data = NULL;
170
171 /* connect to the server */
172 oldid = ob_sm_id;
173 ob_debug_type(OB_DEBUG_SM, "Connecting to SM with id: %s\n",
174 oldid ? oldid : "(null)");
175 sm_conn = SmcOpenConnection(NULL, NULL, 1, 0,
176 SmcSaveYourselfProcMask |
177 SmcDieProcMask |
178 SmcSaveCompleteProcMask |
179 SmcShutdownCancelledProcMask,
180 &cb, oldid, &ob_sm_id,
181 SM_ERR_LEN-1, sm_err);
182 g_free(oldid);
183 ob_debug_type(OB_DEBUG_SM, "Connected to SM with id: %s\n", ob_sm_id);
184 if (sm_conn == NULL)
185 ob_debug("Failed to connect to session manager: %s\n", sm_err);
186 return sm_conn != NULL;
187 }
188
189 static void session_setup_program()
190 {
191 SmPropValue vals = {
192 .value = sm_argv[0],
193 .length = strlen(sm_argv[0]) + 1
194 };
195 SmProp prop = {
196 .name = g_strdup(SmProgram),
197 .type = g_strdup(SmARRAY8),
198 .num_vals = 1,
199 .vals = &vals
200 };
201 SmProp *list = &prop;
202 ob_debug_type(OB_DEBUG_SM, "Setting program: %s\n", sm_argv[0]);
203 SmcSetProperties(sm_conn, 1, &list);
204 g_free(prop.name);
205 g_free(prop.type);
206 }
207
208 static void session_setup_user()
209 {
210 char *user = g_strdup(g_get_user_name());
211
212 SmPropValue vals = {
213 .value = user,
214 .length = strlen(user) + 1
215 };
216 SmProp prop = {
217 .name = g_strdup(SmUserID),
218 .type = g_strdup(SmARRAY8),
219 .num_vals = 1,
220 .vals = &vals
221 };
222 SmProp *list = &prop;
223 ob_debug_type(OB_DEBUG_SM, "Setting user: %s\n", user);
224 SmcSetProperties(sm_conn, 1, &list);
225 g_free(prop.name);
226 g_free(prop.type);
227 g_free(user);
228 }
229
230 static void session_setup_restart_style(gboolean restart)
231 {
232 gchar restart_hint = restart ? SmRestartImmediately : SmRestartIfRunning;
233
234 SmPropValue vals = {
235 .value = &restart_hint,
236 .length = 1
237 };
238 SmProp prop = {
239 .name = g_strdup(SmRestartStyleHint),
240 .type = g_strdup(SmCARD8),
241 .num_vals = 1,
242 .vals = &vals
243 };
244 SmProp *list = &prop;
245 ob_debug_type(OB_DEBUG_SM, "Setting restart: %d\n", restart);
246 SmcSetProperties(sm_conn, 1, &list);
247 g_free(prop.name);
248 g_free(prop.type);
249 }
250
251 static void session_setup_pid()
252 {
253 gchar *pid = g_strdup_printf("%ld", (glong) getpid());
254
255 SmPropValue vals = {
256 .value = pid,
257 .length = strlen(pid) + 1
258 };
259 SmProp prop = {
260 .name = g_strdup(SmProcessID),
261 .type = g_strdup(SmARRAY8),
262 .num_vals = 1,
263 .vals = &vals
264 };
265 SmProp *list = &prop;
266 ob_debug_type(OB_DEBUG_SM, "Setting pid: %s\n", pid);
267 SmcSetProperties(sm_conn, 1, &list);
268 g_free(prop.name);
269 g_free(prop.type);
270 g_free(pid);
271 }
272
273 /*! This is a gnome-session-manager extension */
274 static void session_setup_priority()
275 {
276 gchar priority = 20; /* 20 is a lower prioity to run before other apps */
277
278 SmPropValue vals = {
279 .value = &priority,
280 .length = 1
281 };
282 SmProp prop = {
283 .name = g_strdup("_GSM_Priority"),
284 .type = g_strdup(SmCARD8),
285 .num_vals = 1,
286 .vals = &vals
287 };
288 SmProp *list = &prop;
289 ob_debug_type(OB_DEBUG_SM, "Setting priority: %d\n", priority);
290 SmcSetProperties(sm_conn, 1, &list);
291 g_free(prop.name);
292 g_free(prop.type);
293 }
294
295 static void session_setup_clone_command()
296 {
297 gint i;
298
299 SmPropValue *vals = g_new(SmPropValue, sm_argc);
300 SmProp prop = {
301 .name = g_strdup(SmCloneCommand),
302 .type = g_strdup(SmLISTofARRAY8),
303 .num_vals = sm_argc,
304 .vals = vals
305 };
306 SmProp *list = &prop;
307
308 ob_debug_type(OB_DEBUG_SM, "Setting clone command: (%d)\n", sm_argc);
309 for (i = 0; i < sm_argc; ++i) {
310 vals[i].value = sm_argv[i];
311 vals[i].length = strlen(sm_argv[i]) + 1;
312 ob_debug_type(OB_DEBUG_SM, " %s\n", vals[i].value);
313 }
314
315 SmcSetProperties(sm_conn, 1, &list);
316 g_free(prop.name);
317 g_free(prop.type);
318 g_free(vals);
319 }
320
321 static void session_setup_restart_command()
322 {
323 gint i;
324
325 SmPropValue *vals = g_new(SmPropValue, sm_argc + 4);
326 SmProp prop = {
327 .name = g_strdup(SmRestartCommand),
328 .type = g_strdup(SmLISTofARRAY8),
329 .num_vals = sm_argc + 4,
330 .vals = vals
331 };
332 SmProp *list = &prop;
333
334 ob_debug_type(OB_DEBUG_SM, "Setting restart command: (%d)\n", sm_argc+4);
335 for (i = 0; i < sm_argc; ++i) {
336 vals[i].value = sm_argv[i];
337 vals[i].length = strlen(sm_argv[i]) + 1;
338 ob_debug_type(OB_DEBUG_SM, " %s\n", vals[i].value);
339 }
340
341 vals[i].value = g_strdup("--sm-client-id");
342 vals[i].length = strlen("--sm-client-id") + 1;
343 vals[i+1].value = ob_sm_id;
344 vals[i+1].length = strlen(ob_sm_id) + 1;
345 ob_debug_type(OB_DEBUG_SM, " %s\n", vals[i].value);
346 ob_debug_type(OB_DEBUG_SM, " %s\n", vals[i+1].value);
347
348 vals[i+2].value = g_strdup("--sm-save-file");
349 vals[i+2].length = strlen("--sm-save-file") + 1;
350 vals[i+3].value = ob_sm_save_file;
351 vals[i+3].length = strlen(ob_sm_save_file) + 1;
352 ob_debug_type(OB_DEBUG_SM, " %s\n", vals[i+2].value);
353 ob_debug_type(OB_DEBUG_SM, " %s\n", vals[i+3].value);
354
355 SmcSetProperties(sm_conn, 1, &list);
356 g_free(prop.name);
357 g_free(prop.type);
358 g_free(vals[i].value);
359 g_free(vals[i+2].value);
360 g_free(vals);
361 }
362
363 static ObSMSaveData *sm_save_get_data()
364 {
365 ObSMSaveData *savedata = g_new0(ObSMSaveData, 1);
366 savedata->focus_client = focus_client;
367 savedata->desktop = screen_desktop;
368 return savedata;
369 }
370
371 static void sm_save_yourself_2(SmcConn conn, SmPointer data)
372 {
373 gboolean success;
374 ObSMSaveData *savedata = data;
375
376 /* save the current state */
377 ob_debug_type(OB_DEBUG_SM, "Session save phase 2 requested\n");
378 ob_debug_type(OB_DEBUG_SM,
379 " Saving session to file '%s'\n", ob_sm_save_file);
380 if (savedata == NULL)
381 savedata = sm_save_get_data();
382 success = session_save_to_file(savedata);
383 g_free(savedata);
384
385 /* tell the session manager how to restore this state */
386 if (success) session_setup_restart_command();
387
388 ob_debug_type(OB_DEBUG_SM, "Saving is done (success = %d)\n", success);
389 SmcSaveYourselfDone(conn, success);
390 }
391
392
393 static void sm_save_yourself(SmcConn conn, SmPointer data, gint save_type,
394 Bool shutdown, gint interact_style, Bool fast)
395 {
396 ObSMSaveData *savedata = NULL;
397 gchar *vendor;
398
399 ob_debug_type(OB_DEBUG_SM, "Session save requested\n");
400
401 vendor = SmcVendor(sm_conn);
402 ob_debug_type(OB_DEBUG_SM, "Session manager's vendor: %s\n", vendor);
403
404 if (!strcmp(vendor, "KDE")) {
405 /* ksmserver guarantees that phase 1 will complete before allowing any
406 clients interaction, so we can save this sanely here before they
407 get messed up from interaction */
408 savedata = sm_save_get_data();
409 }
410 free(vendor);
411
412 if (!SmcRequestSaveYourselfPhase2(conn, sm_save_yourself_2, savedata)) {
413 ob_debug_type(OB_DEBUG_SM, "Requst for phase 2 failed\n");
414 g_free(savedata);
415 SmcSaveYourselfDone(conn, FALSE);
416 }
417 }
418
419 static void sm_die(SmcConn conn, SmPointer data)
420 {
421 ob_debug_type(OB_DEBUG_SM, "Die requested\n");
422 ob_exit(0);
423 }
424
425 static void sm_save_complete(SmcConn conn, SmPointer data)
426 {
427 ob_debug_type(OB_DEBUG_SM, "Save complete\n");
428 }
429
430 static void sm_shutdown_cancelled(SmcConn conn, SmPointer data)
431 {
432 ob_debug_type(OB_DEBUG_SM, "Shutdown cancelled\n");
433 }
434
435 static gboolean session_save_to_file(const ObSMSaveData *savedata)
436 {
437 FILE *f;
438 GList *it;
439 gboolean success = TRUE;
440
441 f = fopen(ob_sm_save_file, "w");
442 if (!f) {
443 success = FALSE;
444 g_message(_("Unable to save the session to '%s': %s"),
445 ob_sm_save_file, g_strerror(errno));
446 } else {
447 fprintf(f, "<?xml version=\"1.0\"?>\n\n");
448 fprintf(f, "<openbox_session>\n\n");
449
450 fprintf(f, "<desktop>%d</desktop>\n", savedata->desktop);
451
452 /* they are ordered top to bottom in stacking order */
453 for (it = stacking_list; it; it = g_list_next(it)) {
454 gint prex, prey, prew, preh;
455 ObClient *c;
456 gchar *t;
457
458 if (WINDOW_IS_CLIENT(it->data))
459 c = WINDOW_AS_CLIENT(it->data);
460 else
461 continue;
462
463 if (!client_normal(c))
464 continue;
465
466 if (!c->sm_client_id) {
467 ob_debug_type(OB_DEBUG_SM, "Client %s does not have a "
468 "session id set\n",
469 c->title);
470 if (!c->wm_command) {
471 ob_debug_type(OB_DEBUG_SM, "Client %s does not have an "
472 "oldskool wm_command set either. We won't "
473 "be saving its data\n",
474 c->title);
475 continue;
476 }
477 }
478
479 ob_debug_type(OB_DEBUG_SM, "Saving state for client %s\n",
480 c->title);
481
482 prex = c->area.x;
483 prey = c->area.y;
484 prew = c->area.width;
485 preh = c->area.height;
486 if (c->fullscreen) {
487 prex = c->pre_fullscreen_area.x;
488 prey = c->pre_fullscreen_area.x;
489 prew = c->pre_fullscreen_area.width;
490 preh = c->pre_fullscreen_area.height;
491 }
492 if (c->max_horz) {
493 prex = c->pre_max_area.x;
494 prew = c->pre_max_area.width;
495 }
496 if (c->max_vert) {
497 prey = c->pre_max_area.y;
498 preh = c->pre_max_area.height;
499 }
500
501 if (c->sm_client_id)
502 fprintf(f, "<window id=\"%s\">\n", c->sm_client_id);
503 else
504 fprintf(f, "<window command=\"%s\">\n", c->wm_command);
505
506 t = g_markup_escape_text(c->name, -1);
507 fprintf(f, "\t<name>%s</name>\n", t);
508 g_free(t);
509
510 t = g_markup_escape_text(c->class, -1);
511 fprintf(f, "\t<class>%s</class>\n", t);
512 g_free(t);
513
514 t = g_markup_escape_text(c->role, -1);
515 fprintf(f, "\t<role>%s</role>\n", t);
516 g_free(t);
517
518 fprintf(f, "\t<windowtype>%d</windowtype>\n", c->type);
519
520 fprintf(f, "\t<desktop>%d</desktop>\n", c->desktop);
521 fprintf(f, "\t<x>%d</x>\n", prex);
522 fprintf(f, "\t<y>%d</y>\n", prey);
523 fprintf(f, "\t<width>%d</width>\n", prew);
524 fprintf(f, "\t<height>%d</height>\n", preh);
525 if (c->shaded)
526 fprintf(f, "\t<shaded />\n");
527 if (c->iconic)
528 fprintf(f, "\t<iconic />\n");
529 if (c->skip_pager)
530 fprintf(f, "\t<skip_pager />\n");
531 if (c->skip_taskbar)
532 fprintf(f, "\t<skip_taskbar />\n");
533 if (c->fullscreen)
534 fprintf(f, "\t<fullscreen />\n");
535 if (c->above)
536 fprintf(f, "\t<above />\n");
537 if (c->below)
538 fprintf(f, "\t<below />\n");
539 if (c->max_horz)
540 fprintf(f, "\t<max_horz />\n");
541 if (c->max_vert)
542 fprintf(f, "\t<max_vert />\n");
543 if (c->undecorated)
544 fprintf(f, "\t<undecorated />\n");
545 if (savedata->focus_client == c)
546 fprintf(f, "\t<focused />\n");
547 fprintf(f, "</window>\n\n");
548 }
549
550 fprintf(f, "</openbox_session>\n");
551
552 if (fflush(f)) {
553 success = FALSE;
554 g_message(_("Error while saving the session to '%s': %s"),
555 ob_sm_save_file, g_strerror(errno));
556 }
557 fclose(f);
558 }
559
560 return success;
561 }
562
563 static void session_state_free(ObSessionState *state)
564 {
565 if (state) {
566 g_free(state->id);
567 g_free(state->command);
568 g_free(state->name);
569 g_free(state->class);
570 g_free(state->role);
571
572 g_free(state);
573 }
574 }
575
576 static gboolean session_state_cmp(ObSessionState *s, ObClient *c)
577 {
578 ob_debug_type(OB_DEBUG_SM, "Comparing client against saved state: \n");
579 ob_debug_type(OB_DEBUG_SM, " client id: %s \n", c->sm_client_id);
580 ob_debug_type(OB_DEBUG_SM, " client name: %s \n", c->name);
581 ob_debug_type(OB_DEBUG_SM, " client class: %s \n", c->class);
582 ob_debug_type(OB_DEBUG_SM, " client role: %s \n", c->role);
583 ob_debug_type(OB_DEBUG_SM, " client type: %s \n", c->type);
584 ob_debug_type(OB_DEBUG_SM, " client command: %s \n",
585 c->wm_command ? c->wm_command : "(null)");
586 ob_debug_type(OB_DEBUG_SM, " state id: %s \n", s->id);
587 ob_debug_type(OB_DEBUG_SM, " state name: %s \n", s->name);
588 ob_debug_type(OB_DEBUG_SM, " state class: %s \n", s->class);
589 ob_debug_type(OB_DEBUG_SM, " state role: %s \n", s->role);
590 ob_debug_type(OB_DEBUG_SM, " state type: %s \n", s->type);
591 ob_debug_type(OB_DEBUG_SM, " state command: %s \n",
592 s->command ? s->command : "(null)");
593
594 if ((c->sm_client_id && s->id && !strcmp(c->sm_client_id, s->id)) ||
595 (c->wm_command && s->command && !strcmp(c->wm_command, s->command)))
596 {
597 return (!strcmp(s->name, c->name) &&
598 !strcmp(s->class, c->class) &&
599 !strcmp(s->role, c->role) &&
600 /* the check for type is to catch broken clients, like
601 firefox, which open a different window on startup
602 with the same info as the one we saved. only do this
603 check for old windows that dont use xsmp, others should
604 know better ! */
605 (!s->command || c->type == s->type));
606 }
607 return FALSE;
608 }
609
610 GList* session_state_find(ObClient *c)
611 {
612 GList *it;
613
614 for (it = session_saved_state; it; it = g_list_next(it)) {
615 ObSessionState *s = it->data;
616 if (!s->matched && session_state_cmp(s, c)) {
617 s->matched = TRUE;
618 break;
619 }
620 }
621 return it;
622 }
623
624 static void session_load_file(const gchar *path)
625 {
626 xmlDocPtr doc;
627 xmlNodePtr node, n;
628 GList *it, *inext;
629
630 if (!parse_load(path, "openbox_session", &doc, &node))
631 return;
632
633 if ((n = parse_find_node("desktop", node->children)))
634 session_desktop = parse_int(doc, n);
635
636 for (node = parse_find_node("window", node->children); node != NULL;
637 node = parse_find_node("window", node->next))
638 {
639 ObSessionState *state;
640
641 state = g_new0(ObSessionState, 1);
642
643 if (!parse_attr_string("id", node, &state->id))
644 if (!parse_attr_string("command", node, &state->command))
645 goto session_load_bail;
646 if (!(n = parse_find_node("name", node->children)))
647 goto session_load_bail;
648 state->name = parse_string(doc, n);
649 if (!(n = parse_find_node("class", node->children)))
650 goto session_load_bail;
651 state->class = parse_string(doc, n);
652 if (!(n = parse_find_node("role", node->children)))
653 goto session_load_bail;
654 state->role = parse_string(doc, n);
655 if (!(n = parse_find_node("windowtype", node->children)))
656 goto session_load_bail;
657 state->type = parse_int(doc, n);
658 if (!(n = parse_find_node("desktop", node->children)))
659 goto session_load_bail;
660 state->desktop = parse_int(doc, n);
661 if (!(n = parse_find_node("x", node->children)))
662 goto session_load_bail;
663 state->x = parse_int(doc, n);
664 if (!(n = parse_find_node("y", node->children)))
665 goto session_load_bail;
666 state->y = parse_int(doc, n);
667 if (!(n = parse_find_node("width", node->children)))
668 goto session_load_bail;
669 state->w = parse_int(doc, n);
670 if (!(n = parse_find_node("height", node->children)))
671 goto session_load_bail;
672 state->h = parse_int(doc, n);
673
674 state->shaded =
675 parse_find_node("shaded", node->children) != NULL;
676 state->iconic =
677 parse_find_node("iconic", node->children) != NULL;
678 state->skip_pager =
679 parse_find_node("skip_pager", node->children) != NULL;
680 state->skip_taskbar =
681 parse_find_node("skip_taskbar", node->children) != NULL;
682 state->fullscreen =
683 parse_find_node("fullscreen", node->children) != NULL;
684 state->above =
685 parse_find_node("above", node->children) != NULL;
686 state->below =
687 parse_find_node("below", node->children) != NULL;
688 state->max_horz =
689 parse_find_node("max_horz", node->children) != NULL;
690 state->max_vert =
691 parse_find_node("max_vert", node->children) != NULL;
692 state->undecorated =
693 parse_find_node("undecorated", node->children) != NULL;
694 state->focused =
695 parse_find_node("focused", node->children) != NULL;
696
697 /* save this. they are in the file in stacking order, so preserve
698 that order here */
699 session_saved_state = g_list_append(session_saved_state, state);
700 continue;
701
702 session_load_bail:
703 session_state_free(state);
704 }
705
706 /* Remove any duplicates. This means that if two windows (or more) are
707 saved with the same session state, we won't restore a session for any
708 of them because we don't know what window to put what on. AHEM FIREFOX.
709
710 This is going to be an O(2^n) kind of operation unfortunately.
711 */
712 for (it = session_saved_state; it; it = inext) {
713 GList *jt, *jnext;
714 gboolean founddup = FALSE;
715 ObSessionState *s1 = it->data;
716
717 inext = g_list_next(it);
718
719 for (jt = g_list_next(it); jt; jt = jnext) {
720 ObSessionState *s2 = jt->data;
721 gboolean match;
722
723 jnext = g_list_next(jt);
724
725 if (s1->id && s2->id)
726 match = strcmp(s1->id, s2->id) == 0;
727 else if (s1->command && s2->command)
728 match = strcmp(s1->command, s2->command) == 0;
729 else
730 match = FALSE;
731
732 if (match &&
733 !strcmp(s1->name, s2->name) &&
734 !strcmp(s1->class, s2->class) &&
735 !strcmp(s1->role, s2->role))
736 {
737 session_state_free(s2);
738 session_saved_state =
739 g_list_delete_link(session_saved_state, jt);
740 founddup = TRUE;
741 }
742 }
743
744 if (founddup) {
745 session_state_free(s1);
746 session_saved_state = g_list_delete_link(session_saved_state, it);
747 }
748 }
749
750 xmlFreeDoc(doc);
751 }
752
753 #endif
This page took 0.072827 seconds and 4 git commands to generate.