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