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