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