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