]> Dogcows Code - chaz/openbox/blob - openbox/session.c
small api change for parsing
[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
45 #include <time.h>
46 #include <errno.h>
47 #include <stdio.h>
48
49 #ifdef HAVE_UNISTD_H
50 # include <sys/types.h>
51 # include <unistd.h>
52 #endif
53
54 #include <X11/SM/SMlib.h>
55
56 #define SM_ERR_LEN 1024
57
58 static SmcConn sm_conn;
59 static gint sm_argc;
60 static gchar **sm_argv;
61
62 /* Data saved from the first level save yourself */
63 typedef struct {
64 ObClient *focus_client;
65 gint desktop;
66 } ObSMSaveData;
67
68 static gboolean session_connect();
69
70 static void session_load_file(const gchar *path);
71 static gboolean session_save_to_file(const ObSMSaveData *savedata);
72
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();
80
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);
86
87 static gboolean session_state_cmp(ObSessionState *s, ObClient *c);
88 static void session_state_free(ObSessionState *state);
89
90 void session_startup(gint argc, gchar **argv)
91 {
92 gchar *dir;
93
94 if (!ob_sm_use) return;
95
96 sm_argc = argc;
97 sm_argv = argv;
98
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));
104 }
105
106 if (ob_sm_save_file != NULL) {
107 if (ob_sm_restore) {
108 ob_debug_type(OB_DEBUG_SM, "Loading from session file %s\n",
109 ob_sm_save_file);
110 session_load_file(ob_sm_save_file);
111 }
112 } else {
113 gchar *filename;
114
115 /* this algo is from metacity */
116 filename = g_strdup_printf("%u-%u-%u.obs",
117 (guint)time(NULL),
118 (guint)getpid(),
119 g_random_int());
120 ob_sm_save_file = g_build_filename(dir, filename, NULL);
121 g_free(filename);
122 }
123
124 if (session_connect()) {
125 session_setup_program();
126 session_setup_user();
127 session_setup_restart_style(TRUE);
128 session_setup_pid();
129 session_setup_priority();
130 session_setup_clone_command();
131 }
132
133 g_free(dir);
134 }
135
136 void session_shutdown(gboolean permanent)
137 {
138 if (!ob_sm_use) return;
139
140 if (sm_conn) {
141 /* if permanent is true then we will change our session state so that
142 the SM won't run us again */
143 if (permanent)
144 session_setup_restart_style(FALSE);
145
146 SmcCloseConnection(sm_conn, 0, NULL);
147
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);
152 }
153 }
154 }
155
156 /*! Connect to the session manager and set up our callback functions */
157 static gboolean session_connect()
158 {
159 SmcCallbacks cb;
160 gchar *oldid;
161 gchar sm_err[SM_ERR_LEN];
162
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;
172
173 /* connect to the server */
174 oldid = ob_sm_id;
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 |
179 SmcDieProcMask |
180 SmcSaveCompleteProcMask |
181 SmcShutdownCancelledProcMask,
182 &cb, oldid, &ob_sm_id,
183 SM_ERR_LEN-1, sm_err);
184 g_free(oldid);
185 ob_debug_type(OB_DEBUG_SM, "Connected to SM with id: %s\n", ob_sm_id);
186 if (sm_conn == NULL)
187 ob_debug("Failed to connect to session manager: %s\n", sm_err);
188 return sm_conn != NULL;
189 }
190
191 static void session_setup_program()
192 {
193 SmPropValue vals = {
194 .value = sm_argv[0],
195 .length = strlen(sm_argv[0]) + 1
196 };
197 SmProp prop = {
198 .name = g_strdup(SmProgram),
199 .type = g_strdup(SmARRAY8),
200 .num_vals = 1,
201 .vals = &vals
202 };
203 SmProp *list = &prop;
204 ob_debug_type(OB_DEBUG_SM, "Setting program: %s\n", sm_argv[0]);
205 SmcSetProperties(sm_conn, 1, &list);
206 g_free(prop.name);
207 g_free(prop.type);
208 }
209
210 static void session_setup_user()
211 {
212 char *user = g_strdup(g_get_user_name());
213
214 SmPropValue vals = {
215 .value = user,
216 .length = strlen(user) + 1
217 };
218 SmProp prop = {
219 .name = g_strdup(SmUserID),
220 .type = g_strdup(SmARRAY8),
221 .num_vals = 1,
222 .vals = &vals
223 };
224 SmProp *list = &prop;
225 ob_debug_type(OB_DEBUG_SM, "Setting user: %s\n", user);
226 SmcSetProperties(sm_conn, 1, &list);
227 g_free(prop.name);
228 g_free(prop.type);
229 g_free(user);
230 }
231
232 static void session_setup_restart_style(gboolean restart)
233 {
234 gchar restart_hint = restart ? SmRestartImmediately : SmRestartIfRunning;
235
236 SmPropValue vals = {
237 .value = &restart_hint,
238 .length = 1
239 };
240 SmProp prop = {
241 .name = g_strdup(SmRestartStyleHint),
242 .type = g_strdup(SmCARD8),
243 .num_vals = 1,
244 .vals = &vals
245 };
246 SmProp *list = &prop;
247 ob_debug_type(OB_DEBUG_SM, "Setting restart: %d\n", restart);
248 SmcSetProperties(sm_conn, 1, &list);
249 g_free(prop.name);
250 g_free(prop.type);
251 }
252
253 static void session_setup_pid()
254 {
255 gchar *pid = g_strdup_printf("%ld", (glong) getpid());
256
257 SmPropValue vals = {
258 .value = pid,
259 .length = strlen(pid) + 1
260 };
261 SmProp prop = {
262 .name = g_strdup(SmProcessID),
263 .type = g_strdup(SmARRAY8),
264 .num_vals = 1,
265 .vals = &vals
266 };
267 SmProp *list = &prop;
268 ob_debug_type(OB_DEBUG_SM, "Setting pid: %s\n", pid);
269 SmcSetProperties(sm_conn, 1, &list);
270 g_free(prop.name);
271 g_free(prop.type);
272 g_free(pid);
273 }
274
275 /*! This is a gnome-session-manager extension */
276 static void session_setup_priority()
277 {
278 gchar priority = 20; /* 20 is a lower prioity to run before other apps */
279
280 SmPropValue vals = {
281 .value = &priority,
282 .length = 1
283 };
284 SmProp prop = {
285 .name = g_strdup("_GSM_Priority"),
286 .type = g_strdup(SmCARD8),
287 .num_vals = 1,
288 .vals = &vals
289 };
290 SmProp *list = &prop;
291 ob_debug_type(OB_DEBUG_SM, "Setting priority: %d\n", priority);
292 SmcSetProperties(sm_conn, 1, &list);
293 g_free(prop.name);
294 g_free(prop.type);
295 }
296
297 static void session_setup_clone_command()
298 {
299 gint i;
300
301 SmPropValue *vals = g_new(SmPropValue, sm_argc);
302 SmProp prop = {
303 .name = g_strdup(SmCloneCommand),
304 .type = g_strdup(SmLISTofARRAY8),
305 .num_vals = sm_argc,
306 .vals = vals
307 };
308 SmProp *list = &prop;
309
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);
315 }
316
317 SmcSetProperties(sm_conn, 1, &list);
318 g_free(prop.name);
319 g_free(prop.type);
320 g_free(vals);
321 }
322
323 static void session_setup_restart_command()
324 {
325 gint i;
326
327 SmPropValue *vals = g_new(SmPropValue, sm_argc + 4);
328 SmProp prop = {
329 .name = g_strdup(SmRestartCommand),
330 .type = g_strdup(SmLISTofARRAY8),
331 .num_vals = sm_argc + 4,
332 .vals = vals
333 };
334 SmProp *list = &prop;
335
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);
341 }
342
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);
349
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);
356
357 SmcSetProperties(sm_conn, 1, &list);
358 g_free(prop.name);
359 g_free(prop.type);
360 g_free(vals[i].value);
361 g_free(vals[i+2].value);
362 g_free(vals);
363 }
364
365 static ObSMSaveData *sm_save_get_data()
366 {
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
371 the save.. */
372 savedata->focus_client = focus_client;
373 savedata->desktop = screen_desktop;
374 return savedata;
375 }
376
377 static void sm_save_yourself_2(SmcConn conn, SmPointer data)
378 {
379 gboolean success;
380 ObSMSaveData *savedata = data;
381
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);
389 g_free(savedata);
390
391 /* tell the session manager how to restore this state */
392 if (success) session_setup_restart_command();
393
394 ob_debug_type(OB_DEBUG_SM, "Saving is done (success = %d)\n", success);
395 SmcSaveYourselfDone(conn, success);
396 }
397
398
399 static void sm_save_yourself(SmcConn conn, SmPointer data, gint save_type,
400 Bool shutdown, gint interact_style, Bool fast)
401 {
402 ObSMSaveData *savedata = NULL;
403 gchar *vendor;
404
405 ob_debug_type(OB_DEBUG_SM, "Session save requested\n");
406
407 vendor = SmcVendor(sm_conn);
408 ob_debug_type(OB_DEBUG_SM, "Session manager's vendor: %s\n", vendor);
409
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();
415 }
416 free(vendor);
417
418 if (!SmcRequestSaveYourselfPhase2(conn, sm_save_yourself_2, savedata)) {
419 ob_debug_type(OB_DEBUG_SM, "Requst for phase 2 failed\n");
420 g_free(savedata);
421 SmcSaveYourselfDone(conn, FALSE);
422 }
423 }
424
425 static void sm_die(SmcConn conn, SmPointer data)
426 {
427 ob_debug_type(OB_DEBUG_SM, "Die requested\n");
428 ob_exit(0);
429 }
430
431 static void sm_save_complete(SmcConn conn, SmPointer data)
432 {
433 ob_debug_type(OB_DEBUG_SM, "Save complete\n");
434 }
435
436 static void sm_shutdown_cancelled(SmcConn conn, SmPointer data)
437 {
438 ob_debug_type(OB_DEBUG_SM, "Shutdown cancelled\n");
439 }
440
441 static gboolean session_save_to_file(const ObSMSaveData *savedata)
442 {
443 FILE *f;
444 GList *it;
445 gboolean success = TRUE;
446
447 f = fopen(ob_sm_save_file, "w");
448 if (!f) {
449 success = FALSE;
450 g_message(_("Unable to save the session to '%s': %s"),
451 ob_sm_save_file, g_strerror(errno));
452 } else {
453 fprintf(f, "<?xml version=\"1.0\"?>\n\n");
454 fprintf(f, "<openbox_session>\n\n");
455
456 fprintf(f, "<desktop>%d</desktop>\n", savedata->desktop);
457
458 fprintf(f, "<numdesktops>%d</numdesktops>\n", screen_num_desktops);
459
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");
470
471 if (screen_desktop_names) {
472 gint i;
473
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");
478 }
479
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;
483 ObClient *c;
484 gchar *t;
485
486 if (WINDOW_IS_CLIENT(it->data))
487 c = WINDOW_AS_CLIENT(it->data);
488 else
489 continue;
490
491 if (!client_normal(c))
492 continue;
493
494 if (!c->sm_client_id) {
495 ob_debug_type(OB_DEBUG_SM, "Client %s does not have a "
496 "session id set\n",
497 c->title);
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",
502 c->title);
503 continue;
504 }
505 }
506
507 ob_debug_type(OB_DEBUG_SM, "Saving state for client %s\n",
508 c->title);
509
510 prex = c->area.x;
511 prey = c->area.y;
512 prew = c->area.width;
513 preh = c->area.height;
514 if (c->fullscreen) {
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;
519 }
520 if (c->max_horz) {
521 prex = c->pre_max_area.x;
522 prew = c->pre_max_area.width;
523 }
524 if (c->max_vert) {
525 prey = c->pre_max_area.y;
526 preh = c->pre_max_area.height;
527 }
528
529 if (c->sm_client_id)
530 fprintf(f, "<window id=\"%s\">\n", c->sm_client_id);
531 else
532 fprintf(f, "<window command=\"%s\">\n", c->wm_command);
533
534 t = g_markup_escape_text(c->name, -1);
535 fprintf(f, "\t<name>%s</name>\n", t);
536 g_free(t);
537
538 t = g_markup_escape_text(c->class, -1);
539 fprintf(f, "\t<class>%s</class>\n", t);
540 g_free(t);
541
542 t = g_markup_escape_text(c->role, -1);
543 fprintf(f, "\t<role>%s</role>\n", t);
544 g_free(t);
545
546 fprintf(f, "\t<windowtype>%d</windowtype>\n", c->type);
547
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);
553 if (c->shaded)
554 fprintf(f, "\t<shaded />\n");
555 if (c->iconic)
556 fprintf(f, "\t<iconic />\n");
557 if (c->skip_pager)
558 fprintf(f, "\t<skip_pager />\n");
559 if (c->skip_taskbar)
560 fprintf(f, "\t<skip_taskbar />\n");
561 if (c->fullscreen)
562 fprintf(f, "\t<fullscreen />\n");
563 if (c->above)
564 fprintf(f, "\t<above />\n");
565 if (c->below)
566 fprintf(f, "\t<below />\n");
567 if (c->max_horz)
568 fprintf(f, "\t<max_horz />\n");
569 if (c->max_vert)
570 fprintf(f, "\t<max_vert />\n");
571 if (c->undecorated)
572 fprintf(f, "\t<undecorated />\n");
573 if (savedata->focus_client == c)
574 fprintf(f, "\t<focused />\n");
575 fprintf(f, "</window>\n\n");
576 }
577
578 fprintf(f, "</openbox_session>\n");
579
580 if (fflush(f)) {
581 success = FALSE;
582 g_message(_("Error while saving the session to '%s': %s"),
583 ob_sm_save_file, g_strerror(errno));
584 }
585 fclose(f);
586 }
587
588 return success;
589 }
590
591 static void session_state_free(ObSessionState *state)
592 {
593 if (state) {
594 g_free(state->id);
595 g_free(state->command);
596 g_free(state->name);
597 g_free(state->class);
598 g_free(state->role);
599
600 g_free(state);
601 }
602 }
603
604 static gboolean session_state_cmp(ObSessionState *s, ObClient *c)
605 {
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)");
621
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)))
624 {
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
632 know better ! */
633 (!s->command || c->type == s->type));
634 }
635 return FALSE;
636 }
637
638 GList* session_state_find(ObClient *c)
639 {
640 GList *it;
641
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)) {
645 s->matched = TRUE;
646 break;
647 }
648 }
649 return it;
650 }
651
652 static void session_load_file(const gchar *path)
653 {
654 ObtParseInst *i;
655 xmlNodePtr node, n, m;
656 GList *it, *inext;
657
658 i = obt_parse_instance_new();
659
660 if (!obt_parse_load_file(i, path, "openbox_session")) {
661 obt_parse_instance_unref(i);
662 return;
663 }
664 node = obt_parse_root(i);
665
666 if ((n = obt_parse_find_node(node->children, "desktop")))
667 session_desktop = obt_parse_node_int(n);
668
669 if ((n = obt_parse_find_node(node->children, "numdesktops")))
670 session_num_desktops = obt_parse_node_int(n);
671
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;
683 }
684
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"))
688 {
689 session_desktop_names = g_slist_append(session_desktop_names,
690 obt_parse_node_string(m));
691 }
692 }
693
694 for (node = obt_parse_find_node(node->children, "window"); node != NULL;
695 node = obt_parse_find_node(node->next, "window"))
696 {
697 ObSessionState *state;
698
699 state = g_new0(ObSessionState, 1);
700
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);
731
732 state->shaded =
733 obt_parse_find_node(node->children, "shaded") != NULL;
734 state->iconic =
735 obt_parse_find_node(node->children, "iconic") != NULL;
736 state->skip_pager =
737 obt_parse_find_node(node->children, "skip_pager") != NULL;
738 state->skip_taskbar =
739 obt_parse_find_node(node->children, "skip_taskbar") != NULL;
740 state->fullscreen =
741 obt_parse_find_node(node->children, "fullscreen") != NULL;
742 state->above =
743 obt_parse_find_node(node->children, "above") != NULL;
744 state->below =
745 obt_parse_find_node(node->children, "below") != NULL;
746 state->max_horz =
747 obt_parse_find_node(node->children, "max_horz") != NULL;
748 state->max_vert =
749 obt_parse_find_node(node->children, "max_vert") != NULL;
750 state->undecorated =
751 obt_parse_find_node(node->children, "undecorated") != NULL;
752 state->focused =
753 obt_parse_find_node(node->children, "focused") != NULL;
754
755 /* save this. they are in the file in stacking order, so preserve
756 that order here */
757 session_saved_state = g_list_append(session_saved_state, state);
758 continue;
759
760 session_load_bail:
761 session_state_free(state);
762 }
763
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.
767
768 This is going to be an O(2^n) kind of operation unfortunately.
769 */
770 for (it = session_saved_state; it; it = inext) {
771 GList *jt, *jnext;
772 gboolean founddup = FALSE;
773 ObSessionState *s1 = it->data;
774
775 inext = g_list_next(it);
776
777 for (jt = g_list_next(it); jt; jt = jnext) {
778 ObSessionState *s2 = jt->data;
779 gboolean match;
780
781 jnext = g_list_next(jt);
782
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;
787 else
788 match = FALSE;
789
790 if (match &&
791 !strcmp(s1->name, s2->name) &&
792 !strcmp(s1->class, s2->class) &&
793 !strcmp(s1->role, s2->role))
794 {
795 session_state_free(s2);
796 session_saved_state =
797 g_list_delete_link(session_saved_state, jt);
798 founddup = TRUE;
799 }
800 }
801
802 if (founddup) {
803 session_state_free(s1);
804 session_saved_state = g_list_delete_link(session_saved_state, it);
805 }
806 }
807
808 obt_parse_instance_unref(i);
809 }
810
811 #endif
This page took 0.069765 seconds and 5 git commands to generate.