]> Dogcows Code - chaz/openbox/blob - openbox/session.c
let you make an xevent listener for all windows
[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_data_home(p), "openbox", "sessions",NULL);
103 obt_paths_unref(p), p = NULL;
104
105 if (!obt_paths_mkdir_path(dir, 0700)) {
106 g_message(_("Unable to make directory '%s': %s"),
107 dir, g_strerror(errno));
108 }
109
110 if (ob_sm_save_file != NULL) {
111 if (ob_sm_restore) {
112 ob_debug_type(OB_DEBUG_SM, "Loading from session file %s\n",
113 ob_sm_save_file);
114 session_load_file(ob_sm_save_file);
115 }
116 } else {
117 gchar *filename;
118
119 /* this algo is from metacity */
120 filename = g_strdup_printf("%u-%u-%u.obs",
121 (guint)time(NULL),
122 (guint)getpid(),
123 g_random_int());
124 ob_sm_save_file = g_build_filename(dir, filename, NULL);
125 g_free(filename);
126 }
127
128 if (session_connect()) {
129 session_setup_program();
130 session_setup_user();
131 session_setup_restart_style(TRUE);
132 session_setup_pid();
133 session_setup_priority();
134 session_setup_clone_command();
135 }
136
137 g_free(dir);
138 }
139
140 void session_shutdown(gboolean permanent)
141 {
142 if (!ob_sm_use) return;
143
144 if (sm_conn) {
145 /* if permanent is true then we will change our session state so that
146 the SM won't run us again */
147 if (permanent)
148 session_setup_restart_style(FALSE);
149
150 SmcCloseConnection(sm_conn, 0, NULL);
151
152 while (session_saved_state) {
153 session_state_free(session_saved_state->data);
154 session_saved_state = g_list_delete_link(session_saved_state,
155 session_saved_state);
156 }
157 }
158 }
159
160 /*! Connect to the session manager and set up our callback functions */
161 static gboolean session_connect()
162 {
163 SmcCallbacks cb;
164 gchar *oldid;
165 gchar sm_err[SM_ERR_LEN];
166
167 /* set up our callback functions */
168 cb.save_yourself.callback = sm_save_yourself;
169 cb.save_yourself.client_data = NULL;
170 cb.die.callback = sm_die;
171 cb.die.client_data = NULL;
172 cb.save_complete.callback = sm_save_complete;
173 cb.save_complete.client_data = NULL;
174 cb.shutdown_cancelled.callback = sm_shutdown_cancelled;
175 cb.shutdown_cancelled.client_data = NULL;
176
177 /* connect to the server */
178 oldid = ob_sm_id;
179 ob_debug_type(OB_DEBUG_SM, "Connecting to SM with id: %s\n",
180 oldid ? oldid : "(null)");
181 sm_conn = SmcOpenConnection(NULL, NULL, 1, 0,
182 SmcSaveYourselfProcMask |
183 SmcDieProcMask |
184 SmcSaveCompleteProcMask |
185 SmcShutdownCancelledProcMask,
186 &cb, oldid, &ob_sm_id,
187 SM_ERR_LEN-1, sm_err);
188 g_free(oldid);
189 ob_debug_type(OB_DEBUG_SM, "Connected to SM with id: %s\n", ob_sm_id);
190 if (sm_conn == NULL)
191 ob_debug("Failed to connect to session manager: %s\n", sm_err);
192 return sm_conn != NULL;
193 }
194
195 static void session_setup_program()
196 {
197 SmPropValue vals = {
198 .value = sm_argv[0],
199 .length = strlen(sm_argv[0]) + 1
200 };
201 SmProp prop = {
202 .name = g_strdup(SmProgram),
203 .type = g_strdup(SmARRAY8),
204 .num_vals = 1,
205 .vals = &vals
206 };
207 SmProp *list = &prop;
208 ob_debug_type(OB_DEBUG_SM, "Setting program: %s\n", sm_argv[0]);
209 SmcSetProperties(sm_conn, 1, &list);
210 g_free(prop.name);
211 g_free(prop.type);
212 }
213
214 static void session_setup_user()
215 {
216 char *user = g_strdup(g_get_user_name());
217
218 SmPropValue vals = {
219 .value = user,
220 .length = strlen(user) + 1
221 };
222 SmProp prop = {
223 .name = g_strdup(SmUserID),
224 .type = g_strdup(SmARRAY8),
225 .num_vals = 1,
226 .vals = &vals
227 };
228 SmProp *list = &prop;
229 ob_debug_type(OB_DEBUG_SM, "Setting user: %s\n", user);
230 SmcSetProperties(sm_conn, 1, &list);
231 g_free(prop.name);
232 g_free(prop.type);
233 g_free(user);
234 }
235
236 static void session_setup_restart_style(gboolean restart)
237 {
238 gchar restart_hint = restart ? SmRestartImmediately : SmRestartIfRunning;
239
240 SmPropValue vals = {
241 .value = &restart_hint,
242 .length = 1
243 };
244 SmProp prop = {
245 .name = g_strdup(SmRestartStyleHint),
246 .type = g_strdup(SmCARD8),
247 .num_vals = 1,
248 .vals = &vals
249 };
250 SmProp *list = &prop;
251 ob_debug_type(OB_DEBUG_SM, "Setting restart: %d\n", restart);
252 SmcSetProperties(sm_conn, 1, &list);
253 g_free(prop.name);
254 g_free(prop.type);
255 }
256
257 static void session_setup_pid()
258 {
259 gchar *pid = g_strdup_printf("%ld", (glong) getpid());
260
261 SmPropValue vals = {
262 .value = pid,
263 .length = strlen(pid) + 1
264 };
265 SmProp prop = {
266 .name = g_strdup(SmProcessID),
267 .type = g_strdup(SmARRAY8),
268 .num_vals = 1,
269 .vals = &vals
270 };
271 SmProp *list = &prop;
272 ob_debug_type(OB_DEBUG_SM, "Setting pid: %s\n", pid);
273 SmcSetProperties(sm_conn, 1, &list);
274 g_free(prop.name);
275 g_free(prop.type);
276 g_free(pid);
277 }
278
279 /*! This is a gnome-session-manager extension */
280 static void session_setup_priority()
281 {
282 gchar priority = 20; /* 20 is a lower prioity to run before other apps */
283
284 SmPropValue vals = {
285 .value = &priority,
286 .length = 1
287 };
288 SmProp prop = {
289 .name = g_strdup("_GSM_Priority"),
290 .type = g_strdup(SmCARD8),
291 .num_vals = 1,
292 .vals = &vals
293 };
294 SmProp *list = &prop;
295 ob_debug_type(OB_DEBUG_SM, "Setting priority: %d\n", priority);
296 SmcSetProperties(sm_conn, 1, &list);
297 g_free(prop.name);
298 g_free(prop.type);
299 }
300
301 static void session_setup_clone_command()
302 {
303 gint i;
304
305 SmPropValue *vals = g_new(SmPropValue, sm_argc);
306 SmProp prop = {
307 .name = g_strdup(SmCloneCommand),
308 .type = g_strdup(SmLISTofARRAY8),
309 .num_vals = sm_argc,
310 .vals = vals
311 };
312 SmProp *list = &prop;
313
314 ob_debug_type(OB_DEBUG_SM, "Setting clone command: (%d)\n", sm_argc);
315 for (i = 0; i < sm_argc; ++i) {
316 vals[i].value = sm_argv[i];
317 vals[i].length = strlen(sm_argv[i]) + 1;
318 ob_debug_type(OB_DEBUG_SM, " %s\n", vals[i].value);
319 }
320
321 SmcSetProperties(sm_conn, 1, &list);
322 g_free(prop.name);
323 g_free(prop.type);
324 g_free(vals);
325 }
326
327 static void session_setup_restart_command()
328 {
329 gint i;
330
331 SmPropValue *vals = g_new(SmPropValue, sm_argc + 4);
332 SmProp prop = {
333 .name = g_strdup(SmRestartCommand),
334 .type = g_strdup(SmLISTofARRAY8),
335 .num_vals = sm_argc + 4,
336 .vals = vals
337 };
338 SmProp *list = &prop;
339
340 ob_debug_type(OB_DEBUG_SM, "Setting restart command: (%d)\n", sm_argc+4);
341 for (i = 0; i < sm_argc; ++i) {
342 vals[i].value = sm_argv[i];
343 vals[i].length = strlen(sm_argv[i]) + 1;
344 ob_debug_type(OB_DEBUG_SM, " %s\n", vals[i].value);
345 }
346
347 vals[i].value = g_strdup("--sm-client-id");
348 vals[i].length = strlen("--sm-client-id") + 1;
349 vals[i+1].value = ob_sm_id;
350 vals[i+1].length = strlen(ob_sm_id) + 1;
351 ob_debug_type(OB_DEBUG_SM, " %s\n", vals[i].value);
352 ob_debug_type(OB_DEBUG_SM, " %s\n", vals[i+1].value);
353
354 vals[i+2].value = g_strdup("--sm-save-file");
355 vals[i+2].length = strlen("--sm-save-file") + 1;
356 vals[i+3].value = ob_sm_save_file;
357 vals[i+3].length = strlen(ob_sm_save_file) + 1;
358 ob_debug_type(OB_DEBUG_SM, " %s\n", vals[i+2].value);
359 ob_debug_type(OB_DEBUG_SM, " %s\n", vals[i+3].value);
360
361 SmcSetProperties(sm_conn, 1, &list);
362 g_free(prop.name);
363 g_free(prop.type);
364 g_free(vals[i].value);
365 g_free(vals[i+2].value);
366 g_free(vals);
367 }
368
369 static ObSMSaveData *sm_save_get_data()
370 {
371 ObSMSaveData *savedata = g_new0(ObSMSaveData, 1);
372 /* save the active desktop and client.
373 we don't bother to preemptively save the other desktop state like
374 number and names of desktops, cuz those shouldn't be changing during
375 the save.. */
376 savedata->focus_client = focus_client;
377 savedata->desktop = screen_desktop;
378 return savedata;
379 }
380
381 static void sm_save_yourself_2(SmcConn conn, SmPointer data)
382 {
383 gboolean success;
384 ObSMSaveData *savedata = data;
385
386 /* save the current state */
387 ob_debug_type(OB_DEBUG_SM, "Session save phase 2 requested\n");
388 ob_debug_type(OB_DEBUG_SM,
389 " Saving session to file '%s'\n", ob_sm_save_file);
390 if (savedata == NULL)
391 savedata = sm_save_get_data();
392 success = session_save_to_file(savedata);
393 g_free(savedata);
394
395 /* tell the session manager how to restore this state */
396 if (success) session_setup_restart_command();
397
398 ob_debug_type(OB_DEBUG_SM, "Saving is done (success = %d)\n", success);
399 SmcSaveYourselfDone(conn, success);
400 }
401
402
403 static void sm_save_yourself(SmcConn conn, SmPointer data, gint save_type,
404 Bool shutdown, gint interact_style, Bool fast)
405 {
406 ObSMSaveData *savedata = NULL;
407 gchar *vendor;
408
409 ob_debug_type(OB_DEBUG_SM, "Session save requested\n");
410
411 vendor = SmcVendor(sm_conn);
412 ob_debug_type(OB_DEBUG_SM, "Session manager's vendor: %s\n", vendor);
413
414 if (!strcmp(vendor, "KDE")) {
415 /* ksmserver guarantees that phase 1 will complete before allowing any
416 clients interaction, so we can save this sanely here before they
417 get messed up from interaction */
418 savedata = sm_save_get_data();
419 }
420 free(vendor);
421
422 if (!SmcRequestSaveYourselfPhase2(conn, sm_save_yourself_2, savedata)) {
423 ob_debug_type(OB_DEBUG_SM, "Requst for phase 2 failed\n");
424 g_free(savedata);
425 SmcSaveYourselfDone(conn, FALSE);
426 }
427 }
428
429 static void sm_die(SmcConn conn, SmPointer data)
430 {
431 ob_debug_type(OB_DEBUG_SM, "Die requested\n");
432 ob_exit(0);
433 }
434
435 static void sm_save_complete(SmcConn conn, SmPointer data)
436 {
437 ob_debug_type(OB_DEBUG_SM, "Save complete\n");
438 }
439
440 static void sm_shutdown_cancelled(SmcConn conn, SmPointer data)
441 {
442 ob_debug_type(OB_DEBUG_SM, "Shutdown cancelled\n");
443 }
444
445 static gboolean session_save_to_file(const ObSMSaveData *savedata)
446 {
447 FILE *f;
448 GList *it;
449 gboolean success = TRUE;
450
451 f = fopen(ob_sm_save_file, "w");
452 if (!f) {
453 success = FALSE;
454 g_message(_("Unable to save the session to '%s': %s"),
455 ob_sm_save_file, g_strerror(errno));
456 } else {
457 fprintf(f, "<?xml version=\"1.0\"?>\n\n");
458 fprintf(f, "<openbox_session>\n\n");
459
460 fprintf(f, "<desktop>%d</desktop>\n", savedata->desktop);
461
462 fprintf(f, "<numdesktops>%d</numdesktops>\n", screen_num_desktops);
463
464 fprintf(f, "<desktoplayout>\n");
465 fprintf(f, " <orientation>%d</orientation>\n",
466 screen_desktop_layout.orientation);
467 fprintf(f, " <startcorner>%d</startcorner>\n",
468 screen_desktop_layout.start_corner);
469 fprintf(f, " <columns>%d</columns>\n",
470 screen_desktop_layout.columns);
471 fprintf(f, " <rows>%d</rows>\n",
472 screen_desktop_layout.rows);
473 fprintf(f, "</desktoplayout>\n");
474
475 if (screen_desktop_names) {
476 gint i;
477
478 fprintf(f, "<desktopnames>\n");
479 for (i = 0; screen_desktop_names[i]; ++i)
480 fprintf(f, " <name>%s</name>\n", screen_desktop_names[i]);
481 fprintf(f, "</desktopnames>\n");
482 }
483
484 /* they are ordered top to bottom in stacking order */
485 for (it = stacking_list; it; it = g_list_next(it)) {
486 gint prex, prey, prew, preh;
487 ObClient *c;
488 gchar *t;
489
490 if (WINDOW_IS_CLIENT(it->data))
491 c = WINDOW_AS_CLIENT(it->data);
492 else
493 continue;
494
495 if (!client_normal(c))
496 continue;
497
498 if (!c->sm_client_id) {
499 ob_debug_type(OB_DEBUG_SM, "Client %s does not have a "
500 "session id set\n",
501 c->title);
502 if (!c->wm_command) {
503 ob_debug_type(OB_DEBUG_SM, "Client %s does not have an "
504 "oldskool wm_command set either. We won't "
505 "be saving its data\n",
506 c->title);
507 continue;
508 }
509 }
510
511 ob_debug_type(OB_DEBUG_SM, "Saving state for client %s\n",
512 c->title);
513
514 prex = c->area.x;
515 prey = c->area.y;
516 prew = c->area.width;
517 preh = c->area.height;
518 if (c->fullscreen) {
519 prex = c->pre_fullscreen_area.x;
520 prey = c->pre_fullscreen_area.x;
521 prew = c->pre_fullscreen_area.width;
522 preh = c->pre_fullscreen_area.height;
523 }
524 if (c->max_horz) {
525 prex = c->pre_max_area.x;
526 prew = c->pre_max_area.width;
527 }
528 if (c->max_vert) {
529 prey = c->pre_max_area.y;
530 preh = c->pre_max_area.height;
531 }
532
533 if (c->sm_client_id)
534 fprintf(f, "<window id=\"%s\">\n", c->sm_client_id);
535 else
536 fprintf(f, "<window command=\"%s\">\n", c->wm_command);
537
538 t = g_markup_escape_text(c->name, -1);
539 fprintf(f, "\t<name>%s</name>\n", t);
540 g_free(t);
541
542 t = g_markup_escape_text(c->class, -1);
543 fprintf(f, "\t<class>%s</class>\n", t);
544 g_free(t);
545
546 t = g_markup_escape_text(c->role, -1);
547 fprintf(f, "\t<role>%s</role>\n", t);
548 g_free(t);
549
550 fprintf(f, "\t<windowtype>%d</windowtype>\n", c->type);
551
552 fprintf(f, "\t<desktop>%d</desktop>\n", c->desktop);
553 fprintf(f, "\t<x>%d</x>\n", prex);
554 fprintf(f, "\t<y>%d</y>\n", prey);
555 fprintf(f, "\t<width>%d</width>\n", prew);
556 fprintf(f, "\t<height>%d</height>\n", preh);
557 if (c->shaded)
558 fprintf(f, "\t<shaded />\n");
559 if (c->iconic)
560 fprintf(f, "\t<iconic />\n");
561 if (c->skip_pager)
562 fprintf(f, "\t<skip_pager />\n");
563 if (c->skip_taskbar)
564 fprintf(f, "\t<skip_taskbar />\n");
565 if (c->fullscreen)
566 fprintf(f, "\t<fullscreen />\n");
567 if (c->above)
568 fprintf(f, "\t<above />\n");
569 if (c->below)
570 fprintf(f, "\t<below />\n");
571 if (c->max_horz)
572 fprintf(f, "\t<max_horz />\n");
573 if (c->max_vert)
574 fprintf(f, "\t<max_vert />\n");
575 if (c->undecorated)
576 fprintf(f, "\t<undecorated />\n");
577 if (savedata->focus_client == c)
578 fprintf(f, "\t<focused />\n");
579 fprintf(f, "</window>\n\n");
580 }
581
582 fprintf(f, "</openbox_session>\n");
583
584 if (fflush(f)) {
585 success = FALSE;
586 g_message(_("Error while saving the session to '%s': %s"),
587 ob_sm_save_file, g_strerror(errno));
588 }
589 fclose(f);
590 }
591
592 return success;
593 }
594
595 static void session_state_free(ObSessionState *state)
596 {
597 if (state) {
598 g_free(state->id);
599 g_free(state->command);
600 g_free(state->name);
601 g_free(state->class);
602 g_free(state->role);
603
604 g_free(state);
605 }
606 }
607
608 static gboolean session_state_cmp(ObSessionState *s, ObClient *c)
609 {
610 ob_debug_type(OB_DEBUG_SM, "Comparing client against saved state: \n");
611 ob_debug_type(OB_DEBUG_SM, " client id: %s \n", c->sm_client_id);
612 ob_debug_type(OB_DEBUG_SM, " client name: %s \n", c->name);
613 ob_debug_type(OB_DEBUG_SM, " client class: %s \n", c->class);
614 ob_debug_type(OB_DEBUG_SM, " client role: %s \n", c->role);
615 ob_debug_type(OB_DEBUG_SM, " client type: %d \n", c->type);
616 ob_debug_type(OB_DEBUG_SM, " client command: %s \n",
617 c->wm_command ? c->wm_command : "(null)");
618 ob_debug_type(OB_DEBUG_SM, " state id: %s \n", s->id);
619 ob_debug_type(OB_DEBUG_SM, " state name: %s \n", s->name);
620 ob_debug_type(OB_DEBUG_SM, " state class: %s \n", s->class);
621 ob_debug_type(OB_DEBUG_SM, " state role: %s \n", s->role);
622 ob_debug_type(OB_DEBUG_SM, " state type: %d \n", s->type);
623 ob_debug_type(OB_DEBUG_SM, " state command: %s \n",
624 s->command ? s->command : "(null)");
625
626 if ((c->sm_client_id && s->id && !strcmp(c->sm_client_id, s->id)) ||
627 (c->wm_command && s->command && !strcmp(c->wm_command, s->command)))
628 {
629 return (!strcmp(s->name, c->name) &&
630 !strcmp(s->class, c->class) &&
631 !strcmp(s->role, c->role) &&
632 /* the check for type is to catch broken clients, like
633 firefox, which open a different window on startup
634 with the same info as the one we saved. only do this
635 check for old windows that dont use xsmp, others should
636 know better ! */
637 (!s->command || c->type == s->type));
638 }
639 return FALSE;
640 }
641
642 GList* session_state_find(ObClient *c)
643 {
644 GList *it;
645
646 for (it = session_saved_state; it; it = g_list_next(it)) {
647 ObSessionState *s = it->data;
648 if (!s->matched && session_state_cmp(s, c)) {
649 s->matched = TRUE;
650 break;
651 }
652 }
653 return it;
654 }
655
656 static void session_load_file(const gchar *path)
657 {
658 ObtParseInst *i;
659 xmlNodePtr node, n, m;
660 GList *it, *inext;
661
662 i = obt_parse_instance_new();
663
664 if (!obt_parse_load_file(i, path, "openbox_session")) {
665 obt_parse_instance_unref(i);
666 return;
667 }
668 node = obt_parse_root(i);
669
670 if ((n = obt_parse_find_node(node->children, "desktop")))
671 session_desktop = obt_parse_node_int(n);
672
673 if ((n = obt_parse_find_node(node->children, "numdesktops")))
674 session_num_desktops = obt_parse_node_int(n);
675
676 if ((n = obt_parse_find_node(node->children, "desktoplayout"))) {
677 /* make sure they are all there for it to be valid */
678 if ((m = obt_parse_find_node(n->children, "orientation")))
679 session_desktop_layout.orientation = obt_parse_node_int(m);
680 if (m && (m = obt_parse_find_node(n->children, "startcorner")))
681 session_desktop_layout.start_corner = obt_parse_node_int(m);
682 if (m && (m = obt_parse_find_node(n->children, "columns")))
683 session_desktop_layout.columns = obt_parse_node_int(m);
684 if (m && (m = obt_parse_find_node(n->children, "rows")))
685 session_desktop_layout.rows = obt_parse_node_int(m);
686 session_desktop_layout_present = m != NULL;
687 }
688
689 if ((n = obt_parse_find_node(node->children, "desktopnames"))) {
690 for (m = obt_parse_find_node(n->children, "name"); m;
691 m = obt_parse_find_node(m->next, "name"))
692 {
693 session_desktop_names = g_slist_append(session_desktop_names,
694 obt_parse_node_string(m));
695 }
696 }
697
698 for (node = obt_parse_find_node(node->children, "window"); node != NULL;
699 node = obt_parse_find_node(node->next, "window"))
700 {
701 ObSessionState *state;
702
703 state = g_new0(ObSessionState, 1);
704
705 if (!obt_parse_attr_string(node, "id", &state->id))
706 if (!obt_parse_attr_string(node, "command", &state->command))
707 goto session_load_bail;
708 if (!(n = obt_parse_find_node(node->children, "name")))
709 goto session_load_bail;
710 state->name = obt_parse_node_string(n);
711 if (!(n = obt_parse_find_node(node->children, "class")))
712 goto session_load_bail;
713 state->class = obt_parse_node_string(n);
714 if (!(n = obt_parse_find_node(node->children, "role")))
715 goto session_load_bail;
716 state->role = obt_parse_node_string(n);
717 if (!(n = obt_parse_find_node(node->children, "windowtype")))
718 goto session_load_bail;
719 state->type = obt_parse_node_int(n);
720 if (!(n = obt_parse_find_node(node->children, "desktop")))
721 goto session_load_bail;
722 state->desktop = obt_parse_node_int(n);
723 if (!(n = obt_parse_find_node(node->children, "x")))
724 goto session_load_bail;
725 state->x = obt_parse_node_int(n);
726 if (!(n = obt_parse_find_node(node->children, "y")))
727 goto session_load_bail;
728 state->y = obt_parse_node_int(n);
729 if (!(n = obt_parse_find_node(node->children, "width")))
730 goto session_load_bail;
731 state->w = obt_parse_node_int(n);
732 if (!(n = obt_parse_find_node(node->children, "height")))
733 goto session_load_bail;
734 state->h = obt_parse_node_int(n);
735
736 state->shaded =
737 obt_parse_find_node(node->children, "shaded") != NULL;
738 state->iconic =
739 obt_parse_find_node(node->children, "iconic") != NULL;
740 state->skip_pager =
741 obt_parse_find_node(node->children, "skip_pager") != NULL;
742 state->skip_taskbar =
743 obt_parse_find_node(node->children, "skip_taskbar") != NULL;
744 state->fullscreen =
745 obt_parse_find_node(node->children, "fullscreen") != NULL;
746 state->above =
747 obt_parse_find_node(node->children, "above") != NULL;
748 state->below =
749 obt_parse_find_node(node->children, "below") != NULL;
750 state->max_horz =
751 obt_parse_find_node(node->children, "max_horz") != NULL;
752 state->max_vert =
753 obt_parse_find_node(node->children, "max_vert") != NULL;
754 state->undecorated =
755 obt_parse_find_node(node->children, "undecorated") != NULL;
756 state->focused =
757 obt_parse_find_node(node->children, "focused") != NULL;
758
759 /* save this. they are in the file in stacking order, so preserve
760 that order here */
761 session_saved_state = g_list_append(session_saved_state, state);
762 continue;
763
764 session_load_bail:
765 session_state_free(state);
766 }
767
768 /* Remove any duplicates. This means that if two windows (or more) are
769 saved with the same session state, we won't restore a session for any
770 of them because we don't know what window to put what on. AHEM FIREFOX.
771
772 This is going to be an O(2^n) kind of operation unfortunately.
773 */
774 for (it = session_saved_state; it; it = inext) {
775 GList *jt, *jnext;
776 gboolean founddup = FALSE;
777 ObSessionState *s1 = it->data;
778
779 inext = g_list_next(it);
780
781 for (jt = g_list_next(it); jt; jt = jnext) {
782 ObSessionState *s2 = jt->data;
783 gboolean match;
784
785 jnext = g_list_next(jt);
786
787 if (s1->id && s2->id)
788 match = strcmp(s1->id, s2->id) == 0;
789 else if (s1->command && s2->command)
790 match = strcmp(s1->command, s2->command) == 0;
791 else
792 match = FALSE;
793
794 if (match &&
795 !strcmp(s1->name, s2->name) &&
796 !strcmp(s1->class, s2->class) &&
797 !strcmp(s1->role, s2->role))
798 {
799 session_state_free(s2);
800 session_saved_state =
801 g_list_delete_link(session_saved_state, jt);
802 founddup = TRUE;
803 }
804 }
805
806 if (founddup) {
807 session_state_free(s1);
808 session_saved_state = g_list_delete_link(session_saved_state, it);
809 }
810 }
811
812 obt_parse_instance_unref(i);
813 }
814
815 #endif
This page took 0.077531 seconds and 4 git commands to generate.