1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, see: <http://www.gnu.org/licenses/>
14 */
15 /*
16 This file is strongly based on the corresponding files from
17 twm and enlightenment.
18 */
19
20 /* ---------------------------- included header files ---------------------- */
21
22 #include "config.h"
23
24 #include <stdio.h>
25 #ifdef HAVE_GETPWUID
26 #include <pwd.h>
27 #endif
28 #include <signal.h>
29 #include <fcntl.h>
30
31 #include "libs/fvwm_x11.h"
32 #include "libs/fvwmlib.h"
33 #include "libs/FSMlib.h"
34 #include "libs/Strings.h"
35 #include "libs/System.h"
36 #include "fvwm.h"
37 #include "externs.h"
38 #include "execcontext.h"
39 #include "add_window.h"
40 #include "misc.h"
41 #include "screen.h"
42 #include "session.h"
43 #include "module_list.h"
44 #include "module_interface.h"
45 #include "stack.h"
46 #include "icccm2.h"
47 #include "virtual.h"
48 #include "geometry.h"
49 #include "move_resize.h"
50 #include "infostore.h"
51
52 /* ---------------------------- local definitions -------------------------- */
53
54 /*#define FVWM_SM_DEBUG_PROTO*/
55 /*#define FVWM_SM_DEBUG_WINMATCH*/
56
57 /* ---------------------------- local macros ------------------------------- */
58
59 #define xstreq(a,b) ((!a && !b) || (a && b && (strcmp(a,b)==0)))
60
61 /* ---------------------------- imports ------------------------------------ */
62
63 extern Bool Restarting;
64 extern int master_pid;
65 extern char **g_argv;
66 extern int g_argc;
67
68 /* ---------------------------- included code files ------------------------ */
69
70 /* ---------------------------- local types -------------------------------- */
71
72 typedef struct _match
73 {
74 unsigned long win;
75 char *client_id;
76 char *res_name;
77 char *res_class;
78 char *window_role;
79 char *wm_name;
80 int wm_command_count;
81 char **wm_command;
82 int x, y, w, h, icon_x, icon_y;
83 int x_max, y_max, w_max, h_max;
84 int width_defect_max, height_defect_max;
85 int max_x_offset, max_y_offset;
86 struct monitor *m;
87 int desktop;
88 int layer;
89 int default_layer;
90 int placed_by_button;
91 int used;
92 int gravity;
93 unsigned long ewmh_hint_desktop;
94 window_flags flags;
95 } Match;
96
97 /* ---------------------------- forward declarations ----------------------- */
98
99 /* ---------------------------- local variables ---------------------------- */
100
101 static char *previous_sm_client_id = NULL;
102 static char *sm_client_id = NULL;
103 static Bool sent_save_done = 0;
104 static char *real_state_filename = NULL;
105 static Bool going_to_restart = False;
106 static FIceIOErrorHandler prev_handler;
107 static FSmcConn sm_conn = NULL;
108
109 static int num_match = 0;
110 static Match *matches = NULL;
111 static Bool does_file_version_match = False;
112 static Bool do_preserve_state = True;
113
114 /* ---------------------------- exported variables (globals) --------------- */
115
116 int sm_fd = -1;
117
118 /* ---------------------------- local functions ---------------------------- */
119
120 static
duplicate(const char * s)121 char *duplicate(const char *s)
122 {
123 int l;
124 char *r;
125
126 /* TA: FIXME! Use xasprintf() */
127
128 if (!s) return NULL;
129 l = strlen(s);
130 r = fxmalloc (sizeof(char)*(l+1));
131 strncpy(r, s, l+1);
132
133 return r;
134 }
135
get_version_string(void)136 static char *get_version_string(void)
137 {
138 return (VERSION);
139 }
140
unspace_string(const char * str)141 static char *unspace_string(const char *str)
142 {
143 static const char *spaces = " \t\n";
144 char *tr_str = fxstrdup(str);
145 int i;
146
147 if (!tr_str)
148 {
149 return NULL;
150 }
151 for (i = 0; i < strlen(spaces); i++)
152 {
153 char *ptr = tr_str;
154 while ((ptr = strchr(ptr, spaces[i])) != NULL)
155 {
156 *(ptr++) = '_';
157 }
158 }
159
160 return tr_str;
161 }
162
163 /*
164 * It is a bit ugly to have a separate file format for
165 * config files and session save files. The proper way
166 * to do this may be to extend the config file format
167 * to allow the specification of everything we need
168 * to save here. Then the option "-restore xyz" could
169 * be replaced by "-f xyz".
170 */
171 static int
SaveGlobalState(FILE * f)172 SaveGlobalState(FILE *f)
173 {
174 struct monitor *m;
175
176 fprintf(f, "[GLOBAL]\n");
177 TAILQ_FOREACH(m, &monitor_q, entry) {
178 fprintf(f, " [MONITOR] %i\n", (int)m->si->rr_output);
179 fprintf(f, " [DESKTOP] %i\n", m->virtual_scr.CurrentDesk);
180 fprintf(f, " [VIEWPORT] %i %i %i %i\n",
181 m->virtual_scr.Vx, m->virtual_scr.Vy,
182 m->virtual_scr.VxMax, m->virtual_scr.VyMax);
183 fprintf(f, " [SCROLL] %i %i %i %i %i\n",
184 m->virtual_scr.EdgeScrollX, m->virtual_scr.EdgeScrollY,
185 Scr.ScrollDelay,
186 !!(Scr.flags.do_edge_wrap_x),
187 !!(Scr.flags.do_edge_wrap_y));
188 }
189 fprintf(f, " [MISC] %i %i %i\n",
190 Scr.ClickTime, Scr.ColormapFocus, Scr.ColorLimit);
191 fprintf(
192 f, " [STYLE] %i %i\n", Scr.gs.do_emulate_mwm,
193 Scr.gs.do_emulate_win);
194
195 if (get_metainfo_length() > 0) {
196 MetaInfo *mi = get_metainfo(), *mi_i;
197
198 fprintf(f, " [INFOSTORE]\n");
199 for (mi_i = mi; mi_i; mi_i = mi_i->next) {
200 fprintf(f, " [KEY] %s\n", mi_i->key);
201 fprintf(f, " [VALUE] %s\n", mi_i->value);
202 }
203 }
204
205
206 return 1;
207 }
208
set_real_state_filename(char * filename)209 static void set_real_state_filename(char *filename)
210 {
211 if (!SessionSupport)
212 {
213 return;
214 }
215 if (real_state_filename)
216 {
217 free(real_state_filename);
218 }
219 real_state_filename = fxstrdup(filename);
220
221 return;
222 }
223
get_unique_state_filename(void)224 static char *get_unique_state_filename(void)
225 {
226 const char *path = getenv("SM_SAVE_DIR");
227 char *filename;
228 int fd;
229
230 if (!SessionSupport)
231 {
232 return NULL;
233 }
234
235 if (!path)
236 {
237 path = getenv ("HOME");
238 }
239
240 #ifdef HAVE_GETPWUID
241 if (!path)
242 {
243 struct passwd *pwd;
244
245 pwd = getpwuid(getuid());
246 if (pwd)
247 {
248 path = pwd->pw_dir;
249 }
250 }
251 #endif
252 if (!path)
253 {
254 return NULL;
255 }
256 xasprintf(&filename, "%s%s", path, "/.fs-XXXXXX");
257 fd = fvwm_mkstemp(filename);
258 if (fd == -1)
259 {
260 free (filename);
261 filename = NULL;
262 }
263 else
264 {
265 close (fd);
266 }
267
268 return filename;
269 }
270
271 static char *
GetWindowRole(Window window)272 GetWindowRole(Window window)
273 {
274 XTextProperty tp;
275
276 if (XGetTextProperty (dpy, window, &tp, _XA_WM_WINDOW_ROLE))
277 {
278 if (tp.encoding == XA_STRING && tp.format == 8 &&
279 tp.nitems != 0)
280 {
281 return ((char *) tp.value);
282 }
283 }
284 if (XGetTextProperty (dpy, window, &tp, _XA_WINDOW_ROLE))
285 {
286 if (tp.encoding == XA_STRING && tp.format == 8 &&
287 tp.nitems != 0)
288 {
289 return ((char *) tp.value);
290 }
291 }
292
293 return NULL;
294 }
295
296 static char *
GetClientID(FvwmWindow * fw)297 GetClientID(FvwmWindow *fw)
298 {
299 char *client_id = NULL;
300 Window client_leader = None;
301 Window window;
302 XTextProperty tp;
303 Atom actual_type;
304 int actual_format;
305 unsigned long nitems;
306 unsigned long bytes_after;
307 unsigned char *prop = NULL;
308
309 window = FW_W(fw);
310
311 if (XGetWindowProperty(
312 dpy, window, _XA_WM_CLIENT_LEADER, 0L, 1L, False,
313 AnyPropertyType, &actual_type, &actual_format, &nitems,
314 &bytes_after, &prop) == Success)
315 {
316 if (actual_type == XA_WINDOW && actual_format == 32 &&
317 nitems == 1 && bytes_after == 0)
318 {
319 client_leader = (Window)(*(long *)prop);
320 }
321 }
322
323 if (!client_leader && fw->wmhints &&
324 (fw->wmhints->flags & WindowGroupHint))
325 {
326 client_leader = fw->wmhints->window_group;
327 }
328
329 if (client_leader)
330 {
331 if (
332 XGetTextProperty(
333 dpy, client_leader, &tp, _XA_SM_CLIENT_ID))
334 {
335 if (tp.encoding == XA_STRING && tp.format == 8 &&
336 tp.nitems != 0)
337 {
338 client_id = (char *) tp.value;
339 }
340 }
341 }
342
343 if (prop)
344 {
345 XFree (prop);
346 }
347
348 return client_id;
349 }
350
351 /*
352 ** Verify the current fvwm version with the version that stroed the state file.
353 ** No state will be restored if versions don't match.
354 */
VerifyVersionInfo(char * filename)355 static Bool VerifyVersionInfo(char *filename)
356 {
357 FILE *f;
358 char s[4096], s1[4096];
359
360 if (!filename || !*filename)
361 {
362 return False;
363 }
364 if ((f = fopen(filename, "r")) == NULL)
365 {
366 return False;
367 }
368
369 while (fgets(s, sizeof(s), f))
370 {
371 sscanf(s, "%4000s", s1);
372 if (!strcmp(s1, "[FVWM_VERSION]"))
373 {
374 char *current_v = get_version_string();
375 sscanf(s, "%*s %[^\n]", s1);
376 if (strcmp(s1, current_v) == 0)
377 {
378 does_file_version_match = True;
379 }
380 else
381 {
382 fvwm_debug(__func__,
383 "State file version (%s) does not"
384 " match the current version (%s), "
385 "state file is ignored.", s1,
386 current_v);
387 break;
388 }
389 }
390 }
391 fclose(f);
392
393 return does_file_version_match;
394 }
395
396 static int
SaveVersionInfo(FILE * f)397 SaveVersionInfo(FILE *f)
398 {
399 fprintf(f, "[FVWM_VERSION] %s\n", get_version_string());
400
401 return 1;
402 }
403
404 static int
SaveWindowStates(FILE * f)405 SaveWindowStates(FILE *f)
406 {
407 char *client_id;
408 char *window_role;
409 char **wm_command;
410 int wm_command_count;
411 FvwmWindow *ewin;
412 rectangle save_g;
413 rectangle ig;
414 struct monitor *m = monitor_get_current();
415 int i;
416 int layer;
417
418 for (ewin = get_next_window_in_stack_ring(&Scr.FvwmRoot);
419 ewin != &Scr.FvwmRoot;
420 ewin = get_next_window_in_stack_ring(ewin))
421 {
422 Bool is_icon_sticky_across_pages;
423
424 if (!XGetGeometry(
425 dpy, FW_W(ewin), &JunkRoot, &JunkX, &JunkY,
426 (unsigned int*)&JunkWidth,
427 (unsigned int*)&JunkHeight,
428 (unsigned int*)&JunkBW,
429 (unsigned int*)&JunkDepth))
430 {
431 /* Don't save the state of windows that already died
432 * (i.e. modules)! */
433 continue;
434 }
435 is_icon_sticky_across_pages =
436 is_window_sticky_across_pages(ewin);
437
438 wm_command = NULL;
439 wm_command_count = 0;
440
441 client_id = GetClientID(ewin);
442 if (!client_id)
443 {
444 /* no client id, some session manager do not manage
445 * such client ... this can cause problem */
446 if (XGetCommand(
447 dpy, FW_W(ewin), &wm_command,
448 &wm_command_count) &&
449 wm_command && wm_command_count > 0)
450 {
451 /* ok */
452 }
453 else
454 {
455 /* No client id and no WM_COMMAND, the client
456 * cannot be managed by the sessiom manager
457 * skip it! */
458 /* TA: 20110611 - But actually, this breaks
459 * those applications which don't set the
460 * WM_COMMAND XAtom anymore. The ICCCM
461 * deprecated this at version 2.0 -- and its
462 * lack of existence here shouldn't be a
463 * problem. Let newer session managers handle
464 * the error if it even matters.
465 */
466 if (!Restarting)
467 {
468 if (wm_command)
469 {
470 XFreeStringList(wm_command);
471 wm_command = NULL;
472 }
473 /* TA: 20110611 - But see above. We
474 * no longer skip clients who don't
475 * set this legacy field.
476 */
477 /* continue; */
478 }
479 }
480 }
481
482 fprintf(f, "[CLIENT] %lx\n", FW_W(ewin));
483 if (client_id)
484 {
485 fprintf(f, " [CLIENT_ID] %s\n", client_id);
486 XFree(client_id);
487 }
488
489 window_role = GetWindowRole(FW_W(ewin));
490 if (window_role)
491 {
492 fprintf(f, " [WINDOW_ROLE] %s\n", window_role);
493 XFree(window_role);
494 }
495 if (client_id && window_role)
496 {
497 /* we have enough information */
498 }
499 else
500 {
501 if (ewin->class.res_class)
502 {
503 fprintf(f, " [RES_NAME] %s\n",
504 ewin->class.res_name);
505 }
506 if (ewin->class.res_name)
507 {
508 fprintf(f, " [RES_CLASS] %s\n",
509 ewin->class.res_class);
510 }
511 if (ewin->name.name)
512 {
513 fprintf(f, " [WM_NAME] %s\n",
514 ewin->name.name);
515 }
516
517 if (wm_command && wm_command_count > 0)
518 {
519 fprintf(f, " [WM_COMMAND] %i",
520 wm_command_count);
521 for (i = 0; i < wm_command_count; i++)
522 {
523 char *us;
524
525 us = unspace_string(wm_command[i]);
526 fprintf(f, " %s", us);
527 free(us);
528 }
529 fprintf(f, "\n");
530 }
531 } /* !window_role */
532
533 if (wm_command)
534 {
535 XFreeStringList(wm_command);
536 wm_command = NULL;
537 }
538
539 gravity_get_naked_geometry(
540 ewin->hints.win_gravity, ewin, &save_g,
541 &ewin->g.normal);
542 if (IS_STICKY_ACROSS_PAGES(ewin))
543 {
544 save_g.x -= m->virtual_scr.Vx;
545 save_g.y -= m->virtual_scr.Vy;
546 }
547 get_visible_icon_geometry(ewin, &ig);
548 fprintf(
549 f, " [GEOMETRY] %i %i %i %i %i %i %i %i %i %i %i %i"
550 " %i %i %i\n",
551 save_g.x, save_g.y, save_g.width, save_g.height,
552 ewin->g.max.x, ewin->g.max.y, ewin->g.max.width,
553 ewin->g.max.height, ewin->g.max_defect.width,
554 ewin->g.max_defect.height,
555 ig.x + ((!is_icon_sticky_across_pages) ? m->virtual_scr.Vx : 0),
556 ig.y + ((!is_icon_sticky_across_pages) ? m->virtual_scr.Vy : 0),
557 ewin->hints.win_gravity,
558 ewin->g.max_offset.x, ewin->g.max_offset.y);
559 fprintf(f, " [MONITOR] %i\n", (int)ewin->m->si->rr_output);
560 fprintf(f, " [DESK] %i\n", ewin->Desk);
561 /* set the layer to the default layer if the layer has been
562 * set by an ewmh hint */
563 layer = get_layer(ewin);
564 if (layer == ewin->ewmh_hint_layer && layer > 0)
565 {
566 layer = Scr.DefaultLayer;
567 }
568 fprintf(f, " [LAYER] %i %i\n", layer, ewin->default_layer);
569 fprintf(f, " [PLACED_BY_BUTTON] %i\n", ewin->placed_by_button);
570 fprintf(f, " [EWMH_DESKTOP] %lu\n", ewin->ewmh_hint_desktop);
571 fprintf(f, " [FLAGS] ");
572 for (i = 0; i < sizeof(window_flags); i++)
573 {
574 fprintf(f, "%02x ",
575 (int)(((unsigned char *)&(ewin->flags))[i]));
576 }
577 fprintf(f, "\n");
578 }
579 return 1;
580 }
581
582 /* This complicated logic is from twm, where it is explained */
matchWin(FvwmWindow * w,Match * m)583 static Bool matchWin(FvwmWindow *w, Match *m)
584 {
585 char *client_id = NULL;
586 char *window_role = NULL;
587 char **wm_command = NULL;
588 int wm_command_count = 0, i;
589 int found;
590
591 found = 0;
592 client_id = GetClientID(w);
593
594 if (Restarting)
595 {
596 if (FW_W(w) == m->win)
597 {
598 found = 1;
599 }
600 }
601 else if (xstreq(client_id, m->client_id))
602 {
603
604 /* client_id's match */
605
606 window_role = GetWindowRole(FW_W(w));
607
608 if (client_id && (window_role || m->window_role))
609 {
610 /* We have or had a window role, base decision on it */
611 found = xstreq(window_role, m->window_role);
612 }
613 else if (xstreq(w->class.res_name, m->res_name) &&
614 xstreq(w->class.res_class, m->res_class) &&
615 (IS_NAME_CHANGED(w) || IS_NAME_CHANGED(m) ||
616 xstreq(w->name.name, m->wm_name)))
617 {
618 if (client_id)
619 {
620 /* If we have a client_id, we don't
621 * compare WM_COMMAND, since it will be
622 * different. */
623 found = 1;
624 }
625 else
626 {
627 /* for non-SM-aware clients we also
628 * compare WM_COMMAND */
629 if (!XGetCommand(
630 dpy, FW_W(w), &wm_command,
631 &wm_command_count))
632 {
633 wm_command = NULL;
634 wm_command_count = 0;
635 }
636 if (wm_command_count == m->wm_command_count)
637 {
638 for (i = 0; i < wm_command_count; i++)
639 {
640 char *us;
641
642 us = unspace_string(wm_command[i]);
643 if (strcmp(us, m->wm_command[i])!=0)
644 {
645 free(us);
646 break;
647 }
648 free(us);
649 }
650
651 if (i == wm_command_count)
652 {
653 /* migo (21/Oct/1999):
654 * on restarts compare
655 * window ids too */
656 /* But if we restart we only need
657 * to compare window ids
658 * olicha (2005-01-06) */
659 found = 1;
660 }
661 } /* if (wm_command_count ==... */
662 } /* else if res_class, res_name and wm_name agree */
663 } /* else no window roles */
664 } /* if client_id's agree */
665
666 #ifdef FVWM_SM_DEBUG_WINMATCH
667 fvwm_debug(__func__,
668 "\twin(%s, %s, %s, %s, %s,",
669 w->class.res_name, w->class.res_class, w->name.name,
670 (client_id)? client_id:"(null)",
671 (window_role)? window_role:"(null)");
672 if (wm_command)
673 {
674 for (i = 0; i < wm_command_count; i++)
675 {
676 fvwm_debug(__func__, " %s", wm_command[i]);
677 }
678 fvwm_debug(__func__, ",");
679 }
680 else
681 {
682 fvwm_debug(__func__, " no_wmc,");
683 }
684 fvwm_debug(__func__, " %d)", IS_NAME_CHANGED(w));
685 fvwm_debug(__func__, "\n[%d]", found);
686 fvwm_debug(__func__,
687 "\tmat(%s, %s, %s, %s, %s,",
688 m->res_name, m->res_class, m->wm_name,
689 (m->client_id)?m->client_id:"(null)",
690 (m->window_role)?m->window_role:"(null)");
691 if (m->wm_command)
692 {
693 for (i = 0; i < m->wm_command_count; i++)
694 {
695 fvwm_debug(__func__, " %s", m->wm_command[i]);
696 }
697 fvwm_debug(__func__, ",");
698 }
699 else
700 {
701 fvwm_debug(__func__, " no_wmc,");
702 }
703 fvwm_debug(__func__, " %d)\n\n", IS_NAME_CHANGED(m));
704 #endif
705
706 if (client_id)
707 {
708 XFree(client_id);
709 }
710 if (window_role)
711 {
712 XFree(window_role);
713 }
714 if (wm_command)
715 {
716 XFreeStringList (wm_command);
717 }
718
719 return found;
720 }
721
save_state_file(char * filename)722 static int save_state_file(char *filename)
723 {
724 FILE *f;
725 int success;
726
727 if (!filename || !*filename)
728 {
729 return 0;
730 }
731 if ((f = fopen(filename, "w")) == NULL)
732 {
733 return 0;
734 }
735
736 fprintf(f, "# This file is generated by fvwm."
737 " It stores global and window states.\n");
738 fprintf(f, "# Normally, you must never delete this file,"
739 " it will be auto-deleted.\n\n");
740
741 if (SessionSupport && going_to_restart)
742 {
743 fprintf(f, "[REAL_STATE_FILENAME] %s\n", real_state_filename);
744 going_to_restart = False; /* not needed */
745 }
746
747 success = do_preserve_state
748 ? SaveVersionInfo(f) && SaveWindowStates(f) && SaveGlobalState(f)
749 : 1;
750 do_preserve_state = True;
751 if (fclose(f) != 0)
752 return 0;
753
754 return success;
755 }
756
757 static void
set_sm_properties(FSmcConn sm_conn,char * filename,char hint)758 set_sm_properties(FSmcConn sm_conn, char *filename, char hint)
759 {
760 FSmProp prop1, prop2, prop3, prop4, prop5, prop6, prop7, *props[7];
761 FSmPropValue prop1val, prop2val, prop3val, prop4val, prop7val;
762 struct passwd *pwd;
763 char *user_id;
764 char screen_num[32];
765 int numVals, i, priority = 30;
766 Bool is_xsm_detected = False;
767
768 if (!SessionSupport)
769 {
770 return;
771 }
772
773 #ifdef FVWM_SM_DEBUG_PROTO
774 fvwm_debug(__func__,
775 "[FVWM_SMDEBUG][set_sm_properties] state filename: %s%s\n",
776 filename ? filename : "(null)",
777 sm_conn ? "" : " - not connected");
778 #endif
779
780 if (!sm_conn)
781 {
782 return;
783 }
784
785 pwd = getpwuid (getuid());
786 user_id = pwd->pw_name;
787
788 prop1.name = FSmProgram;
789 prop1.type = FSmARRAY8;
790 prop1.num_vals = 1;
791 prop1.vals = &prop1val;
792 prop1val.value = g_argv[0];
793 prop1val.length = strlen (g_argv[0]);
794
795 prop2.name = FSmUserID;
796 prop2.type = FSmARRAY8;
797 prop2.num_vals = 1;
798 prop2.vals = &prop2val;
799 prop2val.value = (FSmPointer) user_id;
800 prop2val.length = strlen (user_id);
801
802 prop3.name = FSmRestartStyleHint;
803 prop3.type = FSmCARD8;
804 prop3.num_vals = 1;
805 prop3.vals = &prop3val;
806 prop3val.value = (FSmPointer) &hint;
807 prop3val.length = 1;
808
809 prop4.name = "_GSM_Priority";
810 prop4.type = FSmCARD8;
811 prop4.num_vals = 1;
812 prop4.vals = &prop4val;
813 prop4val.value = (FSmPointer) &priority;
814 prop4val.length = 1;
815
816 sprintf(screen_num, "%d", (int)Scr.screen);
817
818 prop5.name = FSmCloneCommand;
819 prop5.type = FSmLISTofARRAY8;
820 prop5.vals = (FSmPropValue *)malloc((g_argc + 2) * sizeof (FSmPropValue));
821 numVals = 0;
822 for (i = 0; i < g_argc; i++)
823 {
824 if (strcmp (g_argv[i], "-clientId") == 0 ||
825 strcmp (g_argv[i], "-restore") == 0 ||
826 strcmp (g_argv[i], "-d") == 0 ||
827 (strcmp (g_argv[i], "-s") == 0 && i+1 < g_argc &&
828 g_argv[i+1][0] != '-'))
829 {
830 i++;
831 }
832 else if (strcmp (g_argv[i], "-s") != 0)
833 {
834 prop5.vals[numVals].value = (FSmPointer) g_argv[i];
835 prop5.vals[numVals++].length = strlen (g_argv[i]);
836 }
837 }
838
839 prop5.vals[numVals].value = (FSmPointer) "-s";
840 prop5.vals[numVals++].length = 2;
841
842 prop5.vals[numVals].value = (FSmPointer) screen_num;
843 prop5.vals[numVals++].length = strlen (screen_num);
844
845
846 prop5.num_vals = numVals;
847
848 if (filename)
849 {
850 prop6.name = FSmRestartCommand;
851 prop6.type = FSmLISTofARRAY8;
852
853 prop6.vals = (FSmPropValue *)malloc(
854 (g_argc + 6) * sizeof (FSmPropValue));
855
856 numVals = 0;
857
858 for (i = 0; i < g_argc; i++)
859 {
860 if (strcmp (g_argv[i], "-clientId") == 0 ||
861 strcmp (g_argv[i], "-restore") == 0 ||
862 strcmp (g_argv[i], "-d") == 0 ||
863 (strcmp (g_argv[i], "-s") == 0 && i+1 < g_argc &&
864 g_argv[i+1][0] != '-'))
865 {
866 i++;
867 }
868 else if (strcmp (g_argv[i], "-s") != 0)
869 {
870 prop6.vals[numVals].value =
871 (FSmPointer) g_argv[i];
872 prop6.vals[numVals++].length =
873 strlen (g_argv[i]);
874 }
875 }
876
877 prop6.vals[numVals].value = (FSmPointer) "-s";
878 prop6.vals[numVals++].length = 2;
879
880 prop6.vals[numVals].value = (FSmPointer) screen_num;
881 prop6.vals[numVals++].length = strlen (screen_num);
882
883 prop6.vals[numVals].value = (FSmPointer) "-clientId";
884 prop6.vals[numVals++].length = 9;
885
886 prop6.vals[numVals].value = (FSmPointer) sm_client_id;
887 prop6.vals[numVals++].length = strlen (sm_client_id);
888
889 prop6.vals[numVals].value = (FSmPointer) "-restore";
890 prop6.vals[numVals++].length = 8;
891
892 prop6.vals[numVals].value = (FSmPointer) filename;
893 prop6.vals[numVals++].length = strlen (filename);
894
895 prop6.num_vals = numVals;
896
897 prop7.name = FSmDiscardCommand;
898
899 is_xsm_detected = StrEquals(getenv("SESSION_MANAGER_NAME"), "xsm");
900
901 if (is_xsm_detected)
902 {
903 /* the protocol spec says that the discard command
904 should be LISTofARRAY8 on posix systems, but xsm
905 demands that it be ARRAY8.
906 */
907 char *discardCommand = alloca(
908 (10 + strlen(filename)) * sizeof(char));
909 sprintf (discardCommand, "rm -f '%s'", filename);
910 prop7.type = FSmARRAY8;
911 prop7.num_vals = 1;
912 prop7.vals = &prop7val;
913 prop7val.value = (FSmPointer) discardCommand;
914 prop7val.length = strlen (discardCommand);
915 }
916 else
917 {
918 prop7.type = FSmLISTofARRAY8;
919 prop7.num_vals = 3;
920 prop7.vals =
921 (FSmPropValue *) malloc (
922 3 * sizeof (FSmPropValue));
923 prop7.vals[0].value = "rm";
924 prop7.vals[0].length = 2;
925 prop7.vals[1].value = "-f";
926 prop7.vals[1].length = 2;
927 prop7.vals[2].value = filename;
928 prop7.vals[2].length = strlen (filename);
929 }
930 }
931
932 props[0] = &prop1;
933 props[1] = &prop2;
934 props[2] = &prop3;
935 props[3] = &prop4;
936 props[4] = &prop5;
937 SUPPRESS_UNUSED_VAR_WARNING(props);
938 if (filename)
939 {
940 props[5] = &prop6;
941 props[6] = &prop7;
942 FSmcSetProperties (sm_conn, 7, props);
943
944 free ((char *) prop6.vals);
945 if (!is_xsm_detected)
946 {
947 free ((char *) prop7.vals);
948 }
949 }
950 else
951 {
952 FSmcSetProperties (sm_conn, 5, props);
953 }
954 free ((char *) prop5.vals);
955 }
956
957 static void
callback_save_yourself2(FSmcConn sm_conn,FSmPointer client_data)958 callback_save_yourself2(FSmcConn sm_conn, FSmPointer client_data)
959 {
960 Bool success = 0;
961 char *filename;
962
963
964 if (!SessionSupport)
965 {
966 return;
967 }
968
969 filename = get_unique_state_filename();
970 #ifdef FVWM_SM_DEBUG_PROTO
971 fvwm_debug(__func__, "[FVWM_SMDEBUG][callback_save_yourself2]\n");
972 #endif
973
974 success = save_state_file(filename);
975 if (success)
976 {
977 set_sm_properties(sm_conn, filename, FSmRestartIfRunning);
978 set_real_state_filename(filename);
979 }
980 free(filename);
981
982 FSmcSaveYourselfDone (sm_conn, success);
983 sent_save_done = 1;
984 }
985
986 static void
callback_save_yourself(FSmcConn sm_conn,FSmPointer client_data,int save_style,Bool shutdown,int interact_style,Bool fast)987 callback_save_yourself(FSmcConn sm_conn, FSmPointer client_data,
988 int save_style, Bool shutdown, int interact_style,
989 Bool fast)
990 {
991
992 if (!SessionSupport)
993 {
994 return;
995 }
996
997 #ifdef FVWM_SM_DEBUG_PROTO
998 fvwm_debug(__func__, "[FVWM_SMDEBUG][callback_save_yourself] "
999 "(save=%d, shut=%d, intr=%d, fast=%d)\n",
1000 save_style, shutdown, interact_style, fast);
1001 #endif
1002
1003 if (save_style == FSmSaveGlobal)
1004 {
1005 /* nothing to do */
1006 #ifdef FVWM_SM_DEBUG_PROTO
1007 fvwm_debug(__func__, "[FVWM_SMDEBUG][callback_save_yourself] "
1008 "Global Save type ... do nothing\n");
1009 #endif
1010 FSmcSaveYourselfDone (sm_conn, True);
1011 sent_save_done = 1;
1012 return;
1013
1014 }
1015 #ifdef FVWM_SM_DEBUG_PROTO
1016 fvwm_debug(__func__, "[FVWM_SMDEBUG][callback_save_yourself] "
1017 "Both or Local save type, going to phase 2 ...");
1018 #endif
1019 if (!FSmcRequestSaveYourselfPhase2(
1020 sm_conn, callback_save_yourself2, NULL))
1021 {
1022 FSmcSaveYourselfDone (sm_conn, False);
1023 sent_save_done = 1;
1024 #ifdef FVWM_SM_DEBUG_PROTO
1025 fvwm_debug(__func__, " failed!\n");
1026 #endif
1027 }
1028 else
1029 {
1030 #ifdef FVWM_SM_DEBUG_PROTO
1031 fvwm_debug(__func__, " OK\n");
1032 #endif
1033 sent_save_done = 0;
1034 }
1035
1036 return;
1037 }
1038
1039 static void
callback_die(FSmcConn sm_conn,FSmPointer client_data)1040 callback_die(FSmcConn sm_conn, FSmPointer client_data)
1041 {
1042
1043 if (!SessionSupport)
1044 {
1045 return;
1046 }
1047
1048 #ifdef FVWM_SM_DEBUG_PROTO
1049 fvwm_debug(__func__, "[FVWM_SMDEBUG][callback_die]\n");
1050 #endif
1051
1052 if (FSmcCloseConnection(sm_conn, 0, NULL) != FSmcClosedNow)
1053 {
1054 /* go a head any way ? */
1055 }
1056 sm_fd = -1;
1057
1058 if (master_pid != getpid())
1059 {
1060 kill(master_pid, SIGTERM);
1061 }
1062 Done(0, NULL);
1063 }
1064
1065 static void
callback_save_complete(FSmcConn sm_conn,FSmPointer client_data)1066 callback_save_complete(FSmcConn sm_conn, FSmPointer client_data)
1067 {
1068 if (!SessionSupport)
1069 {
1070 return;
1071 }
1072 #ifdef FVWM_SM_DEBUG_PROTO
1073 fvwm_debug(__func__, "[FVWM_SMDEBUG][callback_save_complete]\n");
1074 #endif
1075
1076 return;
1077 }
1078
1079 static void
callback_shutdown_cancelled(FSmcConn sm_conn,FSmPointer client_data)1080 callback_shutdown_cancelled(FSmcConn sm_conn, FSmPointer client_data)
1081 {
1082 if (!SessionSupport)
1083 {
1084 return;
1085 }
1086
1087 #ifdef FVWM_SM_DEBUG_PROTO
1088 fvwm_debug(__func__, "[FVWM_SMDEBUG][callback_shutdown_cancelled]\n");
1089 #endif
1090
1091 if (!sent_save_done)
1092 {
1093 FSmcSaveYourselfDone(sm_conn, False);
1094 sent_save_done = 1;
1095 }
1096
1097 return;
1098 }
1099
1100 /* the following is taken from xsm */
1101 static void
MyIoErrorHandler(FIceConn ice_conn)1102 MyIoErrorHandler(FIceConn ice_conn)
1103 {
1104 if (!SessionSupport)
1105 {
1106 return;
1107 }
1108
1109 if (prev_handler)
1110 {
1111 (*prev_handler) (ice_conn);
1112 }
1113
1114 return;
1115 }
1116
1117 static void
InstallIOErrorHandler(void)1118 InstallIOErrorHandler(void)
1119 {
1120 FIceIOErrorHandler default_handler;
1121
1122 if (!SessionSupport)
1123 {
1124 return;
1125 }
1126
1127 prev_handler = FIceSetIOErrorHandler (NULL);
1128 default_handler = FIceSetIOErrorHandler (MyIoErrorHandler);
1129 if (prev_handler == default_handler)
1130 {
1131 prev_handler = NULL;
1132 }
1133
1134 return;
1135 }
1136
1137 /* ---------------------------- interface functions ------------------------ */
1138
1139 void
LoadGlobalState(char * filename)1140 LoadGlobalState(char *filename)
1141 {
1142 FILE *f;
1143 char s[4096], s1[4096];
1144 /* char s2[256]; */
1145 char *is_key = NULL, *is_value = NULL;
1146 int n, i1, i2, i3, i4;
1147 struct monitor *mon = NULL;
1148
1149 if (!does_file_version_match)
1150 {
1151 return;
1152 }
1153 if (!filename || !*filename)
1154 {
1155 return;
1156 }
1157 if ((f = fopen(filename, "r")) == NULL)
1158 {
1159 return;
1160 }
1161
1162 while (fgets(s, sizeof(s), f))
1163 {
1164 n = 0;
1165
1166 i1 = 0;
1167 i2 = 0;
1168 i3 = 0;
1169 i4 = 0;
1170
1171 sscanf(s, "%4000s%n", s1, &n);
1172 /* If we are restarting, [REAL_STATE_FILENAME] points
1173 * to the file containing the true session state. */
1174 if (SessionSupport && !strcmp(s1, "[REAL_STATE_FILENAME]"))
1175 {
1176 /* migo: temporarily (?) moved to
1177 LoadWindowStates (trick for gnome-session)
1178 sscanf(s, "%*s %s", s2);
1179 set_sm_properties(sm_conn, s2, FSmRestartIfRunning);
1180 set_real_state_filename(s2);
1181 */
1182 }
1183 else if (!strcmp(s1, "[MONITOR]"))
1184 {
1185 sscanf(s, "%*s %i", &i2);
1186 mon = monitor_by_output(i2);
1187 }
1188 else if (!strcmp(s1, "[DESKTOP]"))
1189 {
1190 sscanf(s, "%*s %i", &i1);
1191 goto_desk(i1, mon);
1192 }
1193 else if (!strcmp(s1, "[VIEWPORT]"))
1194 {
1195 sscanf(s, "%*s %i %i %i %i", &i1, &i2, &i3,
1196 &i4);
1197 /* migo: we don't want to lose DeskTopSize in
1198 * configurations, and it does not work well
1199 * anyways - Gnome is not updated
1200 Scr.VxMax = i3;
1201 Scr.VyMax = i4;
1202 */
1203 MoveViewport(mon, i1, i2, True);
1204 }
1205 else if (!strcmp(s1, "[KEY]"))
1206 {
1207 char *s2;
1208 s2 = s + n;
1209 if (*s2 != 0)
1210 {
1211 s2++;
1212 }
1213 sscanf(s2, "%[^\n]", s1);
1214 is_key = fxstrdup(s1);
1215 }
1216 else if (!strcmp(s1, "[VALUE]"))
1217 {
1218 char *s2;
1219 s2 = s + n;
1220 if (*s2 != 0)
1221 {
1222 s2++;
1223 }
1224 sscanf(s2, "%[^\n]", s1);
1225 is_value = fxstrdup(s1);
1226
1227 if (is_key != NULL && is_value != NULL)
1228 insert_metainfo(is_key, is_value);
1229
1230 free(is_key);
1231 free(is_value);
1232 is_key = is_value = NULL;
1233 }
1234 #if 0
1235 /* migo (08-Dec-1999): we don't want to eliminate config yet */
1236 else if (/*!Restarting*/ 0)
1237 {
1238 /* Matthias: We don't want to restore too much
1239 * state if we are restarting, since that
1240 * would make restarting useless for rereading
1241 * changed rc files. */
1242 if (!strcmp(s1, "[SCROLL]"))
1243 {
1244 sscanf(s, "%*s %i %i %i %i ", &i1,
1245 &i2, &i3, &i4);
1246 Scr.EdgeScrollX = i1;
1247 Scr.EdgeScrollY = i2;
1248 Scr.ScrollDelay = i3;
1249 if (i4)
1250 {
1251 Scr.flags.edge_wrap_x = 1;
1252 }
1253 else
1254 {
1255 Scr.flags.edge_wrap_x = 0;
1256 }
1257 if (i3)
1258 {
1259 Scr.flags.edge_wrap_y = 1;
1260 }
1261 else
1262 {
1263 Scr.flags.edge_wrap_y = 0;
1264 }
1265 }
1266 else if (!strcmp(s1, "[MISC]"))
1267 {
1268 sscanf(s, "%*s %i %i %i", &i1, &i2,
1269 &i3);
1270 Scr.ClickTime = i1;
1271 Scr.ColormapFocus = i2;
1272 Scr.ColorLimit = i3;
1273 }
1274 else if (!strcmp(s1, "[STYLE]"))
1275 {
1276 sscanf(s, "%*s %i %i", &i1, &i2);
1277 Scr.gs.EmulateMWM = i1;
1278 Scr.gs.EmulateWIN = i2;
1279 }
1280 }
1281 #endif
1282 }
1283 fclose(f);
1284
1285 return;
1286 }
1287
1288 void
DisableRestoringState(void)1289 DisableRestoringState(void)
1290 {
1291 num_match = 0;
1292
1293 return;
1294 }
1295
1296 void
LoadWindowStates(char * filename)1297 LoadWindowStates(char *filename)
1298 {
1299 FILE *f;
1300 char s[4096], s1[4096];
1301 char *s2;
1302 int i, pos, pos1;
1303 unsigned long w;
1304 int n;
1305
1306 if (!VerifyVersionInfo(filename))
1307 {
1308 return;
1309 }
1310 if (!filename || !*filename)
1311 {
1312 return;
1313 }
1314 set_real_state_filename(filename);
1315 if ((f = fopen(filename, "r")) == NULL)
1316 {
1317 return;
1318 }
1319
1320 while (fgets(s, sizeof(s), f))
1321 {
1322 n = 0;
1323 sscanf(s, "%4000s%n", s1, &n);
1324 if (!SessionSupport /* migo: temporarily */ &&
1325 !strcmp(s1, "[REAL_STATE_FILENAME]"))
1326 {
1327 sscanf(s, "%*s %s", s1);
1328 set_sm_properties(sm_conn, s1, FSmRestartIfRunning);
1329 set_real_state_filename(s1);
1330 }
1331 else if (!strcmp(s1, "[CLIENT]"))
1332 {
1333 sscanf(s, "%*s %lx", &w);
1334 num_match++;
1335 matches = fxrealloc(
1336 (void *)matches, sizeof(Match), num_match);
1337 matches[num_match - 1].win = w;
1338 matches[num_match - 1].client_id = NULL;
1339 matches[num_match - 1].res_name = NULL;
1340 matches[num_match - 1].res_class = NULL;
1341 matches[num_match - 1].window_role = NULL;
1342 matches[num_match - 1].wm_name = NULL;
1343 matches[num_match - 1].wm_command_count = 0;
1344 matches[num_match - 1].wm_command = NULL;
1345 matches[num_match - 1].x = 0;
1346 matches[num_match - 1].y = 0;
1347 matches[num_match - 1].w = 100;
1348 matches[num_match - 1].h = 100;
1349 matches[num_match - 1].x_max = 0;
1350 matches[num_match - 1].y_max = 0;
1351 matches[num_match - 1].w_max = monitor_get_all_widths();
1352 matches[num_match - 1].h_max = monitor_get_all_heights();
1353 matches[num_match - 1].width_defect_max = 0;
1354 matches[num_match - 1].height_defect_max = 0;
1355 matches[num_match - 1].icon_x = 0;
1356 matches[num_match - 1].icon_y = 0;
1357 matches[num_match - 1].m = NULL;
1358 matches[num_match - 1].desktop = 0;
1359 matches[num_match - 1].layer = 0;
1360 matches[num_match - 1].default_layer = 0;
1361 memset(&(matches[num_match - 1].flags), 0,
1362 sizeof(window_flags));
1363 matches[num_match - 1].used = 0;
1364 }
1365 else if (!strcmp(s1, "[MONITOR]"))
1366 {
1367 struct monitor *m;
1368
1369 if (num_match == 0) {
1370 num_match++;
1371 matches = fxrealloc(
1372 (void *)matches, sizeof(Match), num_match);
1373 }
1374 sscanf(s, "%*s %i", &pos);
1375 m = monitor_by_output(pos);
1376 matches[num_match - 1].m = m;
1377 }
1378 else if (!strcmp(s1, "[GEOMETRY]"))
1379 {
1380 sscanf(s, "%*s %i %i %i %i %i %i %i %i %i %i %i %i"
1381 " %i %i %i",
1382 &(matches[num_match - 1].x),
1383 &(matches[num_match - 1].y),
1384 &(matches[num_match - 1].w),
1385 &(matches[num_match - 1].h),
1386 &(matches[num_match - 1].x_max),
1387 &(matches[num_match - 1].y_max),
1388 &(matches[num_match - 1].w_max),
1389 &(matches[num_match - 1].h_max),
1390 &(matches[num_match - 1].width_defect_max),
1391 &(matches[num_match - 1].height_defect_max),
1392 &(matches[num_match - 1].icon_x),
1393 &(matches[num_match - 1].icon_y),
1394 &(matches[num_match - 1].gravity),
1395 &(matches[num_match - 1].max_x_offset),
1396 &(matches[num_match - 1].max_y_offset));
1397 }
1398 else if (!strcmp(s1, "[DESK]"))
1399 {
1400 sscanf(s, "%*s %i",
1401 &(matches[num_match - 1].desktop));
1402 }
1403 else if (!strcmp(s1, "[LAYER]"))
1404 {
1405 sscanf(s, "%*s %i %i",
1406 &(matches[num_match - 1].layer),
1407 &(matches[num_match - 1].default_layer));
1408 }
1409 else if (!strcmp(s1, "[PLACED_BY_BUTTON]"))
1410 {
1411 sscanf(s, "%*s %i",
1412 &(matches[num_match - 1].placed_by_button));
1413 }
1414 else if (!strcmp(s1, "[EWMH_DESKTOP]"))
1415 {
1416 sscanf(s, "%*s %lu",
1417 &(matches[num_match - 1].ewmh_hint_desktop));
1418 }
1419 else if (!strcmp(s1, "[FLAGS]"))
1420 {
1421 char *ts = s;
1422
1423 /* skip [FLAGS] */
1424 while (*ts != ']')
1425 {
1426 ts++;
1427 }
1428 ts++;
1429
1430 for (i = 0; i < sizeof(window_flags); i++)
1431 {
1432 unsigned int f;
1433 sscanf(ts, "%02x ", &f);
1434 ((unsigned char *)&
1435 (matches[num_match-1].flags))[i] = f;
1436 ts += 3;
1437 }
1438 }
1439 else if (!strcmp(s1, "[CLIENT_ID]"))
1440 {
1441 s2 = s + n;
1442 if (*s2 != 0)
1443 {
1444 s2++;
1445 }
1446 sscanf(s2, "%[^\n]", s1);
1447 matches[num_match - 1].client_id = duplicate(s1);
1448 }
1449 else if (!strcmp(s1, "[WINDOW_ROLE]"))
1450 {
1451 s2 = s + n;
1452 if (*s2 != 0)
1453 {
1454 s2++;
1455 }
1456 sscanf(s2, "%[^\n]", s1);
1457 matches[num_match - 1].window_role = duplicate(s1);
1458 }
1459 else if (!strcmp(s1, "[RES_NAME]"))
1460 {
1461 s2 = s + n;
1462 if (*s2 != 0)
1463 {
1464 s2++;
1465 }
1466 sscanf(s2, "%[^\n]", s1);
1467 matches[num_match - 1].res_name = duplicate(s1);
1468 }
1469 else if (!strcmp(s1, "[RES_CLASS]"))
1470 {
1471 s2 = s + n;
1472 if (*s2 != 0)
1473 {
1474 s2++;
1475 }
1476 sscanf(s2, "%[^\n]", s1);
1477 matches[num_match - 1].res_class = duplicate(s1);
1478 }
1479 else if (!strcmp(s1, "[WM_NAME]"))
1480 {
1481 s2 = s + n;
1482 if (*s2 != 0)
1483 {
1484 s2++;
1485 }
1486 sscanf(s2, "%[^\n]", s1);
1487 matches[num_match - 1].wm_name = duplicate(s1);
1488 }
1489 else if (!strcmp(s1, "[WM_COMMAND]"))
1490 {
1491 sscanf(s, "%*s %i%n",
1492 &matches[num_match - 1].wm_command_count, &pos);
1493 matches[num_match - 1].wm_command = (char **)
1494 fxmalloc(
1495 matches[num_match - 1].
1496 wm_command_count * sizeof (char *));
1497 for (i = 0;
1498 i < matches[num_match - 1].wm_command_count; i++)
1499 {
1500 sscanf (s+pos, "%s%n", s1, &pos1);
1501 pos += pos1;
1502 matches[num_match - 1].wm_command[i] =
1503 duplicate (s1);
1504 }
1505 }
1506 }
1507 fclose(f);
1508
1509 return;
1510 }
1511
1512 /*
1513 This routine (potentially) changes the flags STARTICONIC,
1514 MAXIMIZED, WSHADE and STICKY and the Desk and
1515 attr.x, .y, .width, .height entries. It also changes the
1516 stack_before pointer to return information about the
1517 desired stacking order. It expects the stacking order
1518 to be set up correctly beforehand!
1519 */
1520 Bool
MatchWinToSM(FvwmWindow * ewin,mwtsm_state_args * ret_state_args,initial_window_options_t * win_opts)1521 MatchWinToSM(
1522 FvwmWindow *ewin, mwtsm_state_args *ret_state_args,
1523 initial_window_options_t *win_opts)
1524 {
1525 int i;
1526 struct monitor *m = monitor_get_current();
1527
1528 if (!does_file_version_match)
1529 {
1530 return False;
1531 }
1532 for (i = 0; i < num_match; i++)
1533 {
1534 if (!matches[i].used && matchWin(ewin, &matches[i]))
1535 {
1536 matches[i].used = 1;
1537
1538 if (!Restarting)
1539 {
1540 /* We don't want to restore too much state if
1541 we are restarting, since that would make
1542 * restarting useless for rereading changed
1543 * rc files. */
1544 SET_DO_SKIP_WINDOW_LIST(
1545 ewin,
1546 DO_SKIP_WINDOW_LIST(&(matches[i])));
1547 SET_ICON_SUPPRESSED(
1548 ewin,
1549 IS_ICON_SUPPRESSED(&(matches[i])));
1550 SET_HAS_NO_ICON_TITLE(
1551 ewin, HAS_NO_ICON_TITLE(&(matches[i])));
1552 FPS_LENIENT(
1553 FW_FOCUS_POLICY(ewin),
1554 FP_IS_LENIENT(FW_FOCUS_POLICY(
1555 &(matches[i]))));
1556 SET_ICON_STICKY_ACROSS_PAGES(
1557 ewin, IS_ICON_STICKY_ACROSS_PAGES(
1558 &(matches[i])));
1559 SET_ICON_STICKY_ACROSS_DESKS(
1560 ewin, IS_ICON_STICKY_ACROSS_DESKS(
1561 &(matches[i])));
1562 SET_DO_SKIP_ICON_CIRCULATE(
1563 ewin, DO_SKIP_ICON_CIRCULATE(
1564 &(matches[i])));
1565 SET_DO_SKIP_SHADED_CIRCULATE(
1566 ewin, DO_SKIP_SHADED_CIRCULATE(
1567 &(matches[i])));
1568 SET_DO_SKIP_CIRCULATE(
1569 ewin, DO_SKIP_CIRCULATE(&(matches[i])));
1570 memcpy(
1571 &FW_FOCUS_POLICY(ewin),
1572 &FW_FOCUS_POLICY(&matches[i]),
1573 sizeof(focus_policy_t));
1574 if (matches[i].wm_name)
1575 {
1576 free_window_names(ewin, True, False);
1577 ewin->name.name = matches[i].wm_name;
1578 setup_visible_names(ewin, 1);
1579 }
1580 }
1581 SET_NAME_CHANGED(ewin,IS_NAME_CHANGED(&(matches[i])));
1582 SET_PLACED_BY_FVWM(
1583 ewin, IS_PLACED_BY_FVWM(&(matches[i])));
1584 ret_state_args->do_shade = IS_SHADED(&(matches[i]));
1585 ret_state_args->used_title_dir_for_shading =
1586 USED_TITLE_DIR_FOR_SHADING(&(matches[i]));
1587 ret_state_args->shade_dir = SHADED_DIR(&(matches[i]));
1588 ret_state_args->do_max = IS_MAXIMIZED(&(matches[i]));
1589 SET_USER_STATES(ewin, GET_USER_STATES(&(matches[i])));
1590 SET_ICON_MOVED(ewin, IS_ICON_MOVED(&(matches[i])));
1591 if (IS_ICONIFIED(&(matches[i])))
1592 {
1593 /*
1594 ICON_MOVED is necessary to make fvwm use
1595 icon_[xy]_loc for icon placement
1596 */
1597 win_opts->initial_state = IconicState;
1598 win_opts->flags.use_initial_icon_xy = 1;
1599 win_opts->initial_icon_x = matches[i].icon_x;
1600 win_opts->initial_icon_y = matches[i].icon_y;
1601 if (!IS_STICKY_ACROSS_PAGES(&(matches[i])) &&
1602 !(IS_ICONIFIED(&(matches[i])) &&
1603 IS_ICON_STICKY_ACROSS_PAGES(
1604 &(matches[i]))))
1605 {
1606 win_opts->initial_icon_x -= m->virtual_scr.Vx;
1607 win_opts->initial_icon_y -= m->virtual_scr.Vy;
1608 }
1609 }
1610 ewin->m = matches[i].m;
1611 ewin->g.normal.x = matches[i].x;
1612 ewin->g.normal.y = matches[i].y;
1613 ewin->g.normal.width = matches[i].w;
1614 ewin->g.normal.height = matches[i].h;
1615 ewin->g.max.x = matches[i].x_max;
1616 ewin->g.max.y = matches[i].y_max;
1617 ewin->g.max.width = matches[i].w_max;
1618 ewin->g.max.height = matches[i].h_max;
1619 ewin->g.max_defect.width = matches[i].width_defect_max;
1620 ewin->g.max_defect.height =
1621 matches[i].height_defect_max;
1622 ewin->g.max_offset.x = matches[i].max_x_offset;
1623 ewin->g.max_offset.y = matches[i].max_y_offset;
1624 SET_STICKY_ACROSS_PAGES(
1625 ewin, IS_STICKY_ACROSS_PAGES(&(matches[i])));
1626 SET_STICKY_ACROSS_DESKS(
1627 ewin, IS_STICKY_ACROSS_DESKS(&(matches[i])));
1628 ewin->Desk = (IS_STICKY_ACROSS_DESKS(ewin)) ?
1629 m->virtual_scr.CurrentDesk : matches[i].desktop;
1630 set_layer(ewin, matches[i].layer);
1631 set_default_layer(ewin, matches[i].default_layer);
1632 ewin->placed_by_button = matches[i].placed_by_button;
1633 /* Note: the Modal, skip pager, skip taskbar and
1634 * "stacking order" state are not restored here: there
1635 * are restored in EWMH_ExitStuff */
1636 ewin->ewmh_hint_desktop = matches[i].ewmh_hint_desktop;
1637 SET_HAS_EWMH_INIT_WM_DESKTOP(
1638 ewin, HAS_EWMH_INIT_WM_DESKTOP(&(matches[i])));
1639 SET_HAS_EWMH_INIT_HIDDEN_STATE(
1640 ewin, HAS_EWMH_INIT_HIDDEN_STATE(
1641 &(matches[i])));
1642 SET_HAS_EWMH_INIT_MAXHORIZ_STATE(
1643 ewin, HAS_EWMH_INIT_MAXHORIZ_STATE(
1644 &(matches[i])));
1645 SET_HAS_EWMH_INIT_MAXVERT_STATE(
1646 ewin, HAS_EWMH_INIT_MAXVERT_STATE(
1647 &(matches[i])));
1648 SET_HAS_EWMH_INIT_SHADED_STATE(
1649 ewin, HAS_EWMH_INIT_SHADED_STATE(
1650 &(matches[i])));
1651 SET_HAS_EWMH_INIT_STICKY_STATE(
1652 ewin, HAS_EWMH_INIT_STICKY_STATE(
1653 &(matches[i])));
1654 return True;
1655 }
1656 }
1657
1658 return False;
1659 }
1660
1661 void
RestartInSession(char * filename,Bool is_native,Bool _do_preserve_state)1662 RestartInSession (char *filename, Bool is_native, Bool _do_preserve_state)
1663 {
1664 do_preserve_state = _do_preserve_state;
1665
1666 if (SessionSupport && sm_conn && is_native)
1667 {
1668 going_to_restart = True;
1669
1670 save_state_file(filename);
1671 set_sm_properties(sm_conn, filename, FSmRestartImmediately);
1672
1673 MoveViewport(monitor_get_current(), 0, 0, False);
1674 Reborder();
1675
1676 CloseICCCM2();
1677 XCloseDisplay(dpy);
1678
1679 if ((!FSmcCloseConnection(sm_conn, 0, NULL)) != FSmcClosedNow)
1680 {
1681 /* go a head any way ? */
1682 }
1683
1684 #ifdef FVWM_SM_DEBUG_PROTO
1685 fvwm_debug(__func__, "[FVWM_SMDEBUG]: Exiting, now SM must "
1686 "restart us.\n");
1687 #endif
1688 /* Close all my pipes */
1689 module_kill_all();
1690
1691 exit(0); /* let the SM restart us */
1692 }
1693
1694 save_state_file(filename);
1695 /* return and let Done restart us */
1696
1697 return;
1698 }
1699
SetClientID(char * client_id)1700 void SetClientID(char *client_id)
1701 {
1702 if (!SessionSupport)
1703 {
1704 return;
1705 }
1706 previous_sm_client_id = client_id;
1707
1708 return;
1709 }
1710
1711 void
SessionInit(void)1712 SessionInit(void)
1713 {
1714 char error_string_ret[4096] = "";
1715 FSmPointer context;
1716 FSmcCallbacks callbacks;
1717
1718 if (!SessionSupport)
1719 {
1720 /* -Wall fixes */
1721 MyIoErrorHandler(NULL);
1722 callback_save_yourself2(NULL, NULL);
1723 return;
1724 }
1725
1726 InstallIOErrorHandler();
1727
1728 callbacks.save_yourself.callback = callback_save_yourself;
1729 callbacks.die.callback = callback_die;
1730 callbacks.save_complete.callback = callback_save_complete;
1731 callbacks.shutdown_cancelled.callback = callback_shutdown_cancelled;
1732 callbacks.save_yourself.client_data =
1733 callbacks.die.client_data =
1734 callbacks.save_complete.client_data =
1735 callbacks.shutdown_cancelled.client_data = (FSmPointer) NULL;
1736 SUPPRESS_UNUSED_VAR_WARNING(context);
1737 sm_conn = FSmcOpenConnection(
1738 NULL, &context, FSmProtoMajor, FSmProtoMinor,
1739 FSmcSaveYourselfProcMask | FSmcDieProcMask |
1740 FSmcSaveCompleteProcMask | FSmcShutdownCancelledProcMask,
1741 &callbacks, previous_sm_client_id, &sm_client_id, 4096,
1742 error_string_ret);
1743 if (!sm_conn)
1744 {
1745 /*
1746 Don't annoy users which don't use a session manager
1747 */
1748 if (previous_sm_client_id)
1749 {
1750 fvwm_debug(__func__,
1751 "While connecting to session manager:\n%s.",
1752 error_string_ret);
1753 }
1754 sm_fd = -1;
1755 #ifdef FVWM_SM_DEBUG_PROTO
1756 fvwm_debug(__func__, "[FVWM_SMDEBUG] No SM connection\n");
1757 #endif
1758 }
1759 else
1760 {
1761 sm_fd = FIceConnectionNumber(FSmcGetIceConnection(sm_conn));
1762 #ifdef FVWM_SM_DEBUG_PROTO
1763 fvwm_debug(__func__, "[FVWM_SMDEBUG] Connectecd to a SM\n");
1764 #endif
1765 set_init_function_name(0, "SessionInitFunction");
1766 set_init_function_name(1, "SessionRestartFunction");
1767 set_init_function_name(2, "SessionExitFunction");
1768 /* basically to restet our restart style hint after a
1769 * restart */
1770 set_sm_properties(sm_conn, NULL, FSmRestartIfRunning);
1771 }
1772
1773 return;
1774 }
1775
1776 void
ProcessICEMsgs(void)1777 ProcessICEMsgs(void)
1778 {
1779 FIceProcessMessagesStatus status;
1780
1781 if (!SessionSupport)
1782 {
1783 return;
1784 }
1785
1786 #ifdef FVWM_SM_DEBUG_PROTO
1787 fvwm_debug(__func__, "[FVWM_SMDEBUG][ProcessICEMsgs] %i\n",
1788 (int)sm_fd);
1789 #endif
1790 if (sm_fd < 0)
1791 {
1792 return;
1793 }
1794 status = FIceProcessMessages(FSmcGetIceConnection(sm_conn), NULL, NULL);
1795 if (status == FIceProcessMessagesIOError)
1796 {
1797 fvwm_debug(__func__,
1798 "Connection to session manager lost\n");
1799 sm_conn = NULL;
1800 sm_fd = -1;
1801 }
1802
1803 return;
1804 }
1805
1806 /*
1807 * Fvwm Function implementation: QuitSession, SaveSession, SaveQuitSession.
1808 * migo (15-Jun-1999): I am not sure this is right.
1809 * The session mabager must implement SmsSaveYourselfRequest (xsm doesn't?).
1810 * Alternative implementation may use unix signals, but this does not work
1811 * with all session managers (also must suppose that SM runs locally).
1812 */
get_sm_pid(void)1813 int get_sm_pid(void)
1814 {
1815 const char *session_manager_var = getenv("SESSION_MANAGER");
1816 const char *sm_pid_str_ptr;
1817 int sm_pid = 0;
1818
1819 if (!SessionSupport)
1820 {
1821 return 0;
1822 }
1823
1824 if (!session_manager_var)
1825 {
1826 return 0;
1827 }
1828 sm_pid_str_ptr = strchr(session_manager_var, ',');
1829 if (!sm_pid_str_ptr)
1830 {
1831 return 0;
1832 }
1833 while (sm_pid_str_ptr > session_manager_var && isdigit(*(--sm_pid_str_ptr)))
1834 {
1835 /* nothing */
1836 }
1837 while (isdigit(*(++sm_pid_str_ptr)))
1838 {
1839 sm_pid = sm_pid * 10 + *sm_pid_str_ptr - '0';
1840 }
1841
1842 return sm_pid;
1843 }
1844
1845 /*
1846 * quit_session - hopefully shutdowns the session
1847 */
quit_session(void)1848 Bool quit_session(void)
1849 {
1850 if (!SessionSupport)
1851 {
1852 return False;
1853 }
1854 if (!sm_conn)
1855 {
1856 return False;
1857 }
1858
1859 FSmcRequestSaveYourself(
1860 sm_conn, FSmSaveLocal, True /* shutdown */, FSmInteractStyleAny,
1861 False /* fast */, True /* global */);
1862 return True;
1863
1864 /* migo: xsm does not support RequestSaveYourself, but supports
1865 * signals: */
1866 /*
1867 int sm_pid = get_sm_pid();
1868 if (!sm_pid) return False;
1869 return kill(sm_pid, SIGTERM) == 0 ? True : False;
1870 */
1871 }
1872
1873 /*
1874 * save_session - hopefully saves the session
1875 */
save_session(void)1876 Bool save_session(void)
1877 {
1878 if (!SessionSupport)
1879 {
1880 return False;
1881 }
1882 if (!sm_conn)
1883 {
1884 return False;
1885 }
1886
1887 FSmcRequestSaveYourself(
1888 sm_conn, FSmSaveBoth, False /* shutdown */, FSmInteractStyleAny,
1889 False /* fast */, True /* global */);
1890 return True;
1891
1892 /* migo: xsm does not support RequestSaveYourself, but supports
1893 * signals: */
1894 /*
1895 int sm_pid = get_sm_pid();
1896 if (!sm_pid) return False;
1897 return kill(sm_pid, SIGUSR1) == 0 ? True : False;
1898 */
1899 }
1900
1901 /*
1902 * save_quit_session - hopefully saves and shutdowns the session
1903 */
save_quit_session(void)1904 Bool save_quit_session(void)
1905 {
1906 if (!SessionSupport)
1907 {
1908 return False;
1909 }
1910
1911 if (!sm_conn)
1912 {
1913 return False;
1914 }
1915
1916 FSmcRequestSaveYourself(
1917 sm_conn, FSmSaveBoth, True /* shutdown */, FSmInteractStyleAny,
1918 False /* fast */, True /* global */);
1919 return True;
1920
1921 /* migo: xsm does not support RequestSaveYourself, but supports
1922 * signals: */
1923 /*
1924 if (save_session() == False) return False;
1925 sleep(3); / * doesn't work anyway * /
1926 if (quit_session() == False) return False;
1927 return True;
1928 */
1929 }
1930
1931 /* ---------------------------- builtin commands --------------------------- */
1932
CMD_QuitSession(F_CMD_ARGS)1933 void CMD_QuitSession(F_CMD_ARGS)
1934 {
1935 quit_session();
1936
1937 return;
1938 }
1939
CMD_SaveSession(F_CMD_ARGS)1940 void CMD_SaveSession(F_CMD_ARGS)
1941 {
1942 save_session();
1943
1944 return;
1945 }
1946
CMD_SaveQuitSession(F_CMD_ARGS)1947 void CMD_SaveQuitSession(F_CMD_ARGS)
1948 {
1949 save_quit_session();
1950
1951 return;
1952 }
1953