]> Dogcows Code - chaz/openbox/blob - openbox/session.c
Merge branch 'backport' into work
[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 gint session_num_desktops = 0;
28 gboolean session_desktop_layout_present = FALSE;
29 ObDesktopLayout session_desktop_layout;
30 GSList *session_desktop_names = NULL;
31
32 #ifndef USE_SM
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 #else
37
38 #include "debug.h"
39 #include "openbox.h"
40 #include "client.h"
41 #include "focus.h"
42 #include "gettext.h"
43 #include "obt/parse.h"
44 #include "obt/paths.h"
45
46 #include <time.h>
47 #include <errno.h>
48 #include <stdio.h>
49
50 #ifdef HAVE_UNISTD_H
51 # include <sys/types.h>
52 # include <unistd.h>
53 #endif
54
55 #include <X11/SM/SMlib.h>
56
57 #define SM_ERR_LEN 1024
58
59 static SmcConn sm_conn;
60 static gint sm_argc;
61 static gchar **sm_argv;
62
63 /* Data saved from the first level save yourself */
64 typedef struct {
65 ObClient *focus_client;
66 gint desktop;
67 } ObSMSaveData;
68
69 static gboolean session_connect();
70
71 static void session_load_file(const gchar *path);
72 static gboolean session_save_to_file(const ObSMSaveData *savedata);
73
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();
81
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);
87
88 static gboolean session_state_cmp(ObSessionState *s, ObClient *c);
89 static void session_state_free(ObSessionState *state);
90
91 void session_startup(gint argc, gchar **argv)
92 {
93 gchar *dir;
94 ObtPaths *p;
95
96 if (!ob_sm_use) return;
97
98 sm_argc = argc;
99 sm_argv = argv;
100
101 p = obt_paths_new();
102 dir = g_build_filename(obt_paths_cache_home(p),
103 "openbox", "sessions", NULL);
104 obt_paths_unref(p), p = NULL;
105
106 if (!obt_paths_mkdir_path(dir, 0700)) {
107 g_message(_("Unable to make directory '%s': %s"),
108 dir, g_strerror(errno));
109 }
110
111 if (ob_sm_save_file != NULL) {
112 if (ob_sm_restore) {
113 ob_debug_type(OB_DEBUG_SM, "Loading from session file %s",
114 ob_sm_save_file);
115 session_load_file(ob_sm_save_file);
116 }
117 } else {
118 gchar *filename;
119
120 /* this algo is from metacity */
121 filename = g_strdup_printf("%u-%u-%u.obs",
122 (guint)time(NULL),
123 (guint)getpid(),
124 g_random_int());
125 ob_sm_save_file = g_build_filename(dir, filename, NULL);
126 g_free(filename);
127 }
128
129 if (session_connect()) {
130 session_setup_program();
131 session_setup_user();
132 session_setup_restart_style(TRUE);
133 session_setup_pid();
134 session_setup_priority();
135 session_setup_clone_command();
136 }
137
138 g_free(dir);
139 }
140
141 void session_shutdown(gboolean permanent)
142 {
143 if (!ob_sm_use) return;
144
145 if (sm_conn) {
146 /* if permanent is true then we will change our session state so that
147 the SM won't run us again */
148 if (permanent)
149 session_setup_restart_style(FALSE);
150
151 SmcCloseConnection(sm_conn, 0, NULL);
152
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);
157 }
158 }
159 }
160
161 /*! Connect to the session manager and set up our callback functions */
162 static gboolean session_connect()
163 {
164 SmcCallbacks cb;
165 gchar *oldid;
166 gchar sm_err[SM_ERR_LEN];
167
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;
177
178 /* connect to the server */
179 oldid = ob_sm_id;
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 |
184 SmcDieProcMask |
185 SmcSaveCompleteProcMask |
186 SmcShutdownCancelledProcMask,
187 &cb, oldid, &ob_sm_id,
188 SM_ERR_LEN-1, sm_err);
189 g_free(oldid);
190 ob_debug_type(OB_DEBUG_SM, "Connected to SM with id: %s", ob_sm_id);
191 if (sm_conn == NULL)
192 ob_debug("Failed to connect to session manager: %s", sm_err);
193 return sm_conn != NULL;
194 }
195
196 static void session_setup_program()
197 {
198 SmPropValue vals = {
199 .value = sm_argv[0],
200 .length = strlen(sm_argv[0]) + 1
201 };
202 SmProp prop = {
203 .name = g_strdup(SmProgram),
204 .type = g_strdup(SmARRAY8),
205 .num_vals = 1,
206 .vals = &vals
207 };
208 SmProp *list = &prop;
209 ob_debug_type(OB_DEBUG_SM, "Setting program: %s", sm_argv[0]);
210 SmcSetProperties(sm_conn, 1, &list);
211 g_free(prop.name);
212 g_free(prop.type);
213 }
214
215 static void session_setup_user()
216 {
217 char *user = g_strdup(g_get_user_name());
218
219 SmPropValue vals = {
220 .value = user,
221 .length = strlen(user) + 1
222 };
223 SmProp prop = {
224 .name = g_strdup(SmUserID),
225 .type = g_strdup(SmARRAY8),
226 .num_vals = 1,
227 .vals = &vals
228 };
229 SmProp *list = &prop;
230 ob_debug_type(OB_DEBUG_SM, "Setting user: %s", user);
231 SmcSetProperties(sm_conn, 1, &list);
232 g_free(prop.name);
233 g_free(prop.type);
234 g_free(user);
235 }
236
237 static void session_setup_restart_style(gboolean restart)
238 {
239 gchar restart_hint = restart ? SmRestartImmediately : SmRestartIfRunning;
240
241 SmPropValue vals = {
242 .value = &restart_hint,
243 .length = 1
244 };
245 SmProp prop = {
246 .name = g_strdup(SmRestartStyleHint),
247 .type = g_strdup(SmCARD8),
248 .num_vals = 1,
249 .vals = &vals
250 };
251 SmProp *list = &prop;
252 ob_debug_type(OB_DEBUG_SM, "Setting restart: %d", restart);
253 SmcSetProperties(sm_conn, 1, &list);
254 g_free(prop.name);
255 g_free(prop.type);
256 }
257
258 static void session_setup_pid()
259 {
260 gchar *pid = g_strdup_printf("%ld", (glong) getpid());
261
262 SmPropValue vals = {
263 .value = pid,
264 .length = strlen(pid) + 1
265 };
266 SmProp prop = {
267 .name = g_strdup(SmProcessID),
268 .type = g_strdup(SmARRAY8),
269 .num_vals = 1,
270 .vals = &vals
271 };
272 SmProp *list = &prop;
273 ob_debug_type(OB_DEBUG_SM, "Setting pid: %s", pid);
274 SmcSetProperties(sm_conn, 1, &list);
275 g_free(prop.name);
276 g_free(prop.type);
277 g_free(pid);
278 }
279
280 /*! This is a gnome-session-manager extension */
281 static void session_setup_priority()
282 {
283 gchar priority = 20; /* 20 is a lower prioity to run before other apps */
284
285 SmPropValue vals = {
286 .value = &priority,
287 .length = 1
288 };
289 SmProp prop = {
290 .name = g_strdup("_GSM_Priority"),
291 .type = g_strdup(SmCARD8),
292 .num_vals = 1,
293 .vals = &vals
294 };
295 SmProp *list = &prop;
296 ob_debug_type(OB_DEBUG_SM, "Setting priority: %d", priority);
297 SmcSetProperties(sm_conn, 1, &list);
298 g_free(prop.name);
299 g_free(prop.type);
300 }
301
302 static void session_setup_clone_command()
303 {
304 gint i;
305
306 SmPropValue *vals = g_new(SmPropValue, sm_argc);
307 SmProp prop = {
308 .name = g_strdup(SmCloneCommand),
309 .type = g_strdup(SmLISTofARRAY8),
310 .num_vals = sm_argc,
311 .vals = vals
312 };
313 SmProp *list = &prop;
314
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);
320 }
321
322 SmcSetProperties(sm_conn, 1, &list);
323 g_free(prop.name);
324 g_free(prop.type);
325 g_free(vals);
326 }
327
328 static void session_setup_restart_command()
329 {
330 gint i;
331
332 SmPropValue *vals = g_new(SmPropValue, sm_argc + 4);
333 SmProp prop = {
334 .name = g_strdup(SmRestartCommand),
335 .type = g_strdup(SmLISTofARRAY8),
336 .num_vals = sm_argc + 4,
337 .vals = vals
338 };
339 SmProp *list = &prop;
340
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);
346 }
347
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);
354
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);
361
362 SmcSetProperties(sm_conn, 1, &list);
363 g_free(prop.name);
364 g_free(prop.type);
365 g_free(vals[i].value);
366 g_free(vals[i+2].value);
367 g_free(vals);
368 }
369
370 static ObSMSaveData *sm_save_get_data()
371 {
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
376 the save.. */
377 savedata->focus_client = focus_client;
378 savedata->desktop = screen_desktop;
379 return savedata;
380 }
381
382 static void sm_save_yourself_2(SmcConn conn, SmPointer data)
383 {
384 gboolean success;
385 ObSMSaveData *savedata = data;
386
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);
394 g_free(savedata);
395
396 /* tell the session manager how to restore this state */
397 if (success) session_setup_restart_command();
398
399 ob_debug_type(OB_DEBUG_SM, "Saving is done (success = %d)", success);
400 SmcSaveYourselfDone(conn, success);
401 }
402
403
404 static void sm_save_yourself(SmcConn conn, SmPointer data, gint save_type,
405 Bool shutdown, gint interact_style, Bool fast)
406 {
407 ObSMSaveData *savedata = NULL;
408 gchar *vendor;
409
410 ob_debug_type(OB_DEBUG_SM, "Session save requested");
411
412 vendor = SmcVendor(sm_conn);
413 ob_debug_type(OB_DEBUG_SM, "Session manager's vendor: %s", vendor);
414
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();
420 }
421 free(vendor);
422
423 if (!SmcRequestSaveYourselfPhase2(conn, sm_save_yourself_2, savedata)) {
424 ob_debug_type(OB_DEBUG_SM, "Requst for phase 2 failed");
425 g_free(savedata);
426 SmcSaveYourselfDone(conn, FALSE);
427 }
428 }
429
430 static void sm_die(SmcConn conn, SmPointer data)
431 {
432 ob_debug_type(OB_DEBUG_SM, "Die requested");
433 ob_exit(0);
434 }
435
436 static void sm_save_complete(SmcConn conn, SmPointer data)
437 {
438 ob_debug_type(OB_DEBUG_SM, "Save complete");
439 }
440
441 static void sm_shutdown_cancelled(SmcConn conn, SmPointer data)
442 {
443 ob_debug_type(OB_DEBUG_SM, "Shutdown cancelled");
444 }
445
446 static gboolean session_save_to_file(const ObSMSaveData *savedata)
447 {
448 FILE *f;
449 GList *it;
450 gboolean success = TRUE;
451
452 f = fopen(ob_sm_save_file, "w");
453 if (!f) {
454 success = FALSE;
455 g_message(_("Unable to save the session to '%s': %s"),
456 ob_sm_save_file, g_strerror(errno));
457 } else {
458 fprintf(f, "<?xml version=\"1.0\"?>\n\n");
459 fprintf(f, "<openbox_session>\n\n");
460
461 fprintf(f, "<desktop>%d</desktop>\n", savedata->desktop);
462
463 fprintf(f, "<numdesktops>%d</numdesktops>\n", screen_num_desktops);
464
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");
475
476 if (screen_desktop_names) {
477 gint i;
478
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");
483 }
484
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;
488 ObClient *c;
489 gchar *t;
490
491 if (WINDOW_IS_CLIENT(it->data))
492 c = WINDOW_AS_CLIENT(it->data);
493 else
494 continue;
495
496 if (!client_normal(c))
497 continue;
498
499 if (!c->sm_client_id) {
500 ob_debug_type(OB_DEBUG_SM, "Client %s does not have a "
501 "session id set",
502 c->title);
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",
507 c->title);
508 continue;
509 }
510 }
511
512 ob_debug_type(OB_DEBUG_SM, "Saving state for client %s",
513 c->title);
514
515 prex = c->area.x;
516 prey = c->area.y;
517 prew = c->area.width;
518 preh = c->area.height;
519 if (c->fullscreen) {
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;
524 }
525 if (c->max_horz) {
526 prex = c->pre_max_area.x;
527 prew = c->pre_max_area.width;
528 }
529 if (c->max_vert) {
530 prey = c->pre_max_area.y;
531 preh = c->pre_max_area.height;
532 }
533
534 if (c->sm_client_id)
535 fprintf(f, "<window id=\"%s\">\n", c->sm_client_id);
536 else
537 fprintf(f, "<window command=\"%s\">\n", c->wm_command);
538
539 t = g_markup_escape_text(c->name, -1);
540 fprintf(f, "\t<name>%s</name>\n", t);
541 g_free(t);
542
543 t = g_markup_escape_text(c->class, -1);
544 fprintf(f, "\t<class>%s</class>\n", t);
545 g_free(t);
546
547 t = g_markup_escape_text(c->role, -1);
548 fprintf(f, "\t<role>%s</role>\n", t);
549 g_free(t);
550
551 fprintf(f, "\t<windowtype>%d</windowtype>\n", c->type);
552
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);
558 if (c->shaded)
559 fprintf(f, "\t<shaded />\n");
560 if (c->iconic)
561 fprintf(f, "\t<iconic />\n");
562 if (c->skip_pager)
563 fprintf(f, "\t<skip_pager />\n");
564 if (c->skip_taskbar)
565 fprintf(f, "\t<skip_taskbar />\n");
566 if (c->fullscreen)
567 fprintf(f, "\t<fullscreen />\n");
568 if (c->above)
569 fprintf(f, "\t<above />\n");
570 if (c->below)
571 fprintf(f, "\t<below />\n");
572 if (c->max_horz)
573 fprintf(f, "\t<max_horz />\n");
574 if (c->max_vert)
575 fprintf(f, "\t<max_vert />\n");
576 if (c->undecorated)
577 fprintf(f, "\t<undecorated />\n");
578 if (savedata->focus_client == c)
579 fprintf(f, "\t<focused />\n");
580 fprintf(f, "</window>\n\n");
581 }
582
583 fprintf(f, "</openbox_session>\n");
584
585 if (fflush(f)) {
586 success = FALSE;
587 g_message(_("Error while saving the session to '%s': %s"),
588 ob_sm_save_file, g_strerror(errno));
589 }
590 fclose(f);
591 }
592
593 return success;
594 }
595
596 static void session_state_free(ObSessionState *state)
597 {
598 if (state) {
599 g_free(state->id);
600 g_free(state->command);
601 g_free(state->name);
602 g_free(state->class);
603 g_free(state->role);
604
605 g_free(state);
606 }
607 }
608
609 static gboolean session_state_cmp(ObSessionState *s, ObClient *c)
610 {
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)");
626
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)))
629 {
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
637 know better ! */
638 (!s->command || c->type == s->type));
639 }
640 return FALSE;
641 }
642
643 GList* session_state_find(ObClient *c)
644 {
645 GList *it;
646
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)) {
650 s->matched = TRUE;
651 break;
652 }
653 }
654 return it;
655 }
656
657 static void session_load_file(const gchar *path)
658 {
659 ObtParseInst *i;
660 xmlNodePtr node, n, m;
661 GList *it, *inext;
662
663 i = obt_parse_instance_new();
664
665 if (!obt_parse_load_file(i, path, "openbox_session")) {
666 obt_parse_instance_unref(i);
667 return;
668 }
669 node = obt_parse_root(i);
670
671 if ((n = obt_parse_find_node(node->children, "desktop")))
672 session_desktop = obt_parse_node_int(n);
673
674 if ((n = obt_parse_find_node(node->children, "numdesktops")))
675 session_num_desktops = obt_parse_node_int(n);
676
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;
688 }
689
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"))
693 {
694 session_desktop_names = g_slist_append(session_desktop_names,
695 obt_parse_node_string(m));
696 }
697 }
698
699 for (node = obt_parse_find_node(node->children, "window"); node != NULL;
700 node = obt_parse_find_node(node->next, "window"))
701 {
702 ObSessionState *state;
703
704 state = g_new0(ObSessionState, 1);
705
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);
736
737 state->shaded =
738 obt_parse_find_node(node->children, "shaded") != NULL;
739 state->iconic =
740 obt_parse_find_node(node->children, "iconic") != NULL;
741 state->skip_pager =
742 obt_parse_find_node(node->children, "skip_pager") != NULL;
743 state->skip_taskbar =
744 obt_parse_find_node(node->children, "skip_taskbar") != NULL;
745 state->fullscreen =
746 obt_parse_find_node(node->children, "fullscreen") != NULL;
747 state->above =
748 obt_parse_find_node(node->children, "above") != NULL;
749 state->below =
750 obt_parse_find_node(node->children, "below") != NULL;
751 state->max_horz =
752 obt_parse_find_node(node->children, "max_horz") != NULL;
753 state->max_vert =
754 obt_parse_find_node(node->children, "max_vert") != NULL;
755 state->undecorated =
756 obt_parse_find_node(node->children, "undecorated") != NULL;
757 state->focused =
758 obt_parse_find_node(node->children, "focused") != NULL;
759
760 /* save this. they are in the file in stacking order, so preserve
761 that order here */
762 session_saved_state = g_list_append(session_saved_state, state);
763 continue;
764
765 session_load_bail:
766 session_state_free(state);
767 }
768
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.
772
773 This is going to be an O(2^n) kind of operation unfortunately.
774 */
775 for (it = session_saved_state; it; it = inext) {
776 GList *jt, *jnext;
777 gboolean founddup = FALSE;
778 ObSessionState *s1 = it->data;
779
780 inext = g_list_next(it);
781
782 for (jt = g_list_next(it); jt; jt = jnext) {
783 ObSessionState *s2 = jt->data;
784 gboolean match;
785
786 jnext = g_list_next(jt);
787
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;
792 else
793 match = FALSE;
794
795 if (match &&
796 !strcmp(s1->name, s2->name) &&
797 !strcmp(s1->class, s2->class) &&
798 !strcmp(s1->role, s2->role))
799 {
800 session_state_free(s2);
801 session_saved_state =
802 g_list_delete_link(session_saved_state, jt);
803 founddup = TRUE;
804 }
805 }
806
807 if (founddup) {
808 session_state_free(s1);
809 session_saved_state = g_list_delete_link(session_saved_state, it);
810 }
811 }
812
813 obt_parse_instance_unref(i);
814 }
815
816 #endif
This page took 0.082866 seconds and 5 git commands to generate.