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