Close fd in CMD_Exec
[fvwm.git] / fvwm / session.c
blobe01c315ec898ea7e99a0a01f2058ba004e64bba8
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.
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.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 This file is strongly based on the corresponding files from
18 twm and enlightenment.
21 /* ---------------------------- included header files ---------------------- */
23 #include "config.h"
25 #include <stdio.h>
26 #ifdef HAVE_GETPWUID
27 #include <pwd.h>
28 #endif
29 #include <signal.h>
30 #include <fcntl.h>
31 #include <X11/Xatom.h>
33 #include "libs/fvwmlib.h"
34 #include "libs/FSMlib.h"
35 #include "libs/Strings.h"
36 #include "libs/System.h"
37 #include "fvwm.h"
38 #include "externs.h"
39 #include "execcontext.h"
40 #include "add_window.h"
41 #include "misc.h"
42 #include "screen.h"
43 #include "session.h"
44 #include "module_list.h"
45 #include "module_interface.h"
46 #include "stack.h"
47 #include "icccm2.h"
48 #include "virtual.h"
49 #include "geometry.h"
50 #include "move_resize.h"
52 /* ---------------------------- local definitions -------------------------- */
54 /*#define FVWM_SM_DEBUG_PROTO*/
55 /*#define FVWM_SM_DEBUG_WINMATCH*/
56 /*#define FVWM_SM_DEBUG_FILES*/
58 /* ---------------------------- local macros ------------------------------- */
60 #define xstreq(a,b) ((!a && !b) || (a && b && (strcmp(a,b)==0)))
62 /* ---------------------------- imports ------------------------------------ */
64 extern Bool Restarting;
65 extern int master_pid;
66 extern char **g_argv;
67 extern int g_argc;
69 /* ---------------------------- included code files ------------------------ */
71 /* ---------------------------- local types -------------------------------- */
73 typedef struct _match
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;
97 /* ---------------------------- forward declarations ----------------------- */
99 /* ---------------------------- local variables ---------------------------- */
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;
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;
114 /* ---------------------------- exported variables (globals) --------------- */
116 int sm_fd = -1;
118 /* ---------------------------- local functions ---------------------------- */
120 static
121 char *duplicate(const char *s)
123 int l;
124 char *r;
126 if (!s) return NULL;
127 l = strlen(s);
128 r = (char *) safemalloc (sizeof(char)*(l+1));
129 strncpy(r, s, l+1);
131 return r;
134 static char *get_version_string(void)
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"; */
142 static char *unspace_string(const char *str)
144 static const char *spaces = " \t\n";
145 char *tr_str = CatString2(str, NULL);
146 int i;
148 if (!tr_str)
150 return NULL;
152 for (i = 0; i < strlen(spaces); i++)
154 char *ptr = tr_str;
155 while ((ptr = strchr(ptr, spaces[i])) != NULL)
157 *(ptr++) = '_';
161 return tr_str;
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".
172 static int
173 SaveGlobalState(FILE *f)
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);
188 return 1;
191 static void set_real_state_filename(char *filename)
193 if (!SessionSupport)
195 return;
197 if (real_state_filename)
199 free(real_state_filename);
201 real_state_filename = safestrdup(filename);
203 return;
206 static char *get_unique_state_filename(void)
208 const char *path = getenv("SM_SAVE_DIR");
209 char *filename;
210 int fd;
212 if (!SessionSupport)
214 return NULL;
217 if (!path)
219 path = getenv ("HOME");
222 #ifdef HAVE_GETPWUID
223 if (!path)
225 struct passwd *pwd;
227 pwd = getpwuid(getuid());
228 if (pwd)
230 path = pwd->pw_dir;
233 #endif
234 if (!path)
236 return NULL;
238 filename = safestrdup(CatString2(path, "/.fs-XXXXXX"));
239 fd = fvwm_mkstemp(filename);
240 if (fd == -1)
242 free (filename);
243 filename = NULL;
245 else
247 close (fd);
250 return filename;
253 static char *
254 GetWindowRole(Window window)
256 XTextProperty tp;
258 if (XGetTextProperty (dpy, window, &tp, _XA_WM_WINDOW_ROLE))
260 if (tp.encoding == XA_STRING && tp.format == 8 &&
261 tp.nitems != 0)
263 return ((char *) tp.value);
266 if (XGetTextProperty (dpy, window, &tp, _XA_WINDOW_ROLE))
268 if (tp.encoding == XA_STRING && tp.format == 8 &&
269 tp.nitems != 0)
271 return ((char *) tp.value);
275 return NULL;
278 static char *
279 GetClientID(FvwmWindow *fw)
281 char *client_id = NULL;
282 Window client_leader = None;
283 Window window;
284 XTextProperty tp;
285 Atom actual_type;
286 int actual_format;
287 unsigned long nitems;
288 unsigned long bytes_after;
289 unsigned char *prop = NULL;
291 window = FW_W(fw);
293 if (XGetWindowProperty(
294 dpy, window, _XA_WM_CLIENT_LEADER, 0L, 1L, False,
295 AnyPropertyType, &actual_type, &actual_format, &nitems,
296 &bytes_after, &prop) == Success)
298 if (actual_type == XA_WINDOW && actual_format == 32 &&
299 nitems == 1 && bytes_after == 0)
301 client_leader = (Window)(*(long *)prop);
305 if (!client_leader && fw->wmhints &&
306 (fw->wmhints->flags & WindowGroupHint))
308 client_leader = fw->wmhints->window_group;
311 if (client_leader)
313 if (
314 XGetTextProperty(
315 dpy, client_leader, &tp, _XA_SM_CLIENT_ID))
317 if (tp.encoding == XA_STRING && tp.format == 8 &&
318 tp.nitems != 0)
320 client_id = (char *) tp.value;
325 if (prop)
327 XFree (prop);
330 return client_id;
334 ** Verify the current fvwm version with the version that stroed the state file.
335 ** No state will be restored if versions don't match.
337 static Bool VerifyVersionInfo(char *filename)
339 FILE *f;
340 char s[4096], s1[4096];
342 if (!filename || !*filename)
344 return False;
346 if ((f = fopen(filename, "r")) == NULL)
348 return False;
351 while (fgets(s, sizeof(s), f))
353 sscanf(s, "%4000s", s1);
354 if (!strcmp(s1, "[FVWM_VERSION]"))
356 char *current_v = get_version_string();
357 sscanf(s, "%*s %[^\n]", s1);
358 if (strcmp(s1, current_v) == 0)
360 does_file_version_match = True;
362 else
364 fvwm_msg(
365 ERR, "VerifyVersionInfo",
366 "State file version (%s) does not"
367 " match the current version (%s), "
368 "state file is ignored.", s1,
369 current_v);
370 break;
374 fclose(f);
376 return does_file_version_match;
379 static int
380 SaveVersionInfo(FILE *f)
382 fprintf(f, "[FVWM_VERSION] %s\n", get_version_string());
384 return 1;
387 static int
388 SaveWindowStates(FILE *f)
390 char *client_id;
391 char *window_role;
392 char **wm_command;
393 int wm_command_count;
394 FvwmWindow *ewin;
395 rectangle save_g;
396 rectangle ig;
397 int i;
398 int layer;
400 for (ewin = get_next_window_in_stack_ring(&Scr.FvwmRoot);
401 ewin != &Scr.FvwmRoot;
402 ewin = get_next_window_in_stack_ring(ewin))
404 Bool is_icon_sticky_across_pages;
406 if (!XGetGeometry(
407 dpy, FW_W(ewin), &JunkRoot, &JunkX, &JunkY,
408 (unsigned int*)&JunkWidth,
409 (unsigned int*)&JunkHeight,
410 (unsigned int*)&JunkBW,
411 (unsigned int*)&JunkDepth))
413 /* Don't save the state of windows that already died
414 * (i.e. modules)! */
415 continue;
417 is_icon_sticky_across_pages =
418 is_window_sticky_across_pages(ewin);
420 wm_command = NULL;
421 wm_command_count = 0;
423 client_id = GetClientID(ewin);
424 if (!client_id)
426 /* no client id, some session manager do not manage
427 * such client ... this can cause problem */
428 if (XGetCommand(
429 dpy, FW_W(ewin), &wm_command,
430 &wm_command_count) &&
431 wm_command && wm_command_count > 0)
433 /* ok */
435 else
437 /* No client id and no WM_COMMAND, the client
438 * cannot be managed by the sessiom manager
439 * skip it! */
440 if (!Restarting)
442 if (wm_command)
444 XFreeStringList(wm_command);
445 wm_command = NULL;
447 continue;
452 fprintf(f, "[CLIENT] %lx\n", FW_W(ewin));
453 if (client_id)
455 fprintf(f, " [CLIENT_ID] %s\n", client_id);
456 XFree(client_id);
459 window_role = GetWindowRole(FW_W(ewin));
460 if (window_role)
462 fprintf(f, " [WINDOW_ROLE] %s\n", window_role);
463 XFree(window_role);
465 if (client_id && window_role)
467 /* we have enough information */
469 else
471 if (ewin->class.res_class)
473 fprintf(f, " [RES_NAME] %s\n",
474 ewin->class.res_name);
476 if (ewin->class.res_name)
478 fprintf(f, " [RES_CLASS] %s\n",
479 ewin->class.res_class);
481 if (ewin->name.name)
483 fprintf(f, " [WM_NAME] %s\n",
484 ewin->name.name);
487 if (wm_command && wm_command_count > 0)
489 fprintf(f, " [WM_COMMAND] %i",
490 wm_command_count);
491 for (i = 0; i < wm_command_count; i++)
493 fprintf(f, " %s",
494 unspace_string(wm_command[i]));
496 fprintf(f, "\n");
498 } /* !window_role */
500 if (wm_command)
502 XFreeStringList(wm_command);
503 wm_command = NULL;
506 gravity_get_naked_geometry(
507 ewin->hints.win_gravity, ewin, &save_g,
508 &ewin->g.normal);
509 if (IS_STICKY_ACROSS_PAGES(ewin))
511 save_g.x -= Scr.Vx;
512 save_g.y -= Scr.Vy;
514 get_visible_icon_geometry(ewin, &ig);
515 fprintf(
516 f, " [GEOMETRY] %i %i %i %i %i %i %i %i %i %i %i %i"
517 " %i %i %i\n",
518 save_g.x, save_g.y, save_g.width, save_g.height,
519 ewin->g.max.x, ewin->g.max.y, ewin->g.max.width,
520 ewin->g.max.height, ewin->g.max_defect.width,
521 ewin->g.max_defect.height,
522 ig.x + ((!is_icon_sticky_across_pages) ? Scr.Vx : 0),
523 ig.y + ((!is_icon_sticky_across_pages) ? Scr.Vy : 0),
524 ewin->hints.win_gravity,
525 ewin->g.max_offset.x, ewin->g.max_offset.y);
526 fprintf(f, " [DESK] %i\n", ewin->Desk);
527 /* set the layer to the default layer if the layer has been
528 * set by an ewmh hint */
529 layer = get_layer(ewin);
530 if (layer == ewin->ewmh_hint_layer && layer > 0)
532 layer = Scr.DefaultLayer;
534 fprintf(f, " [LAYER] %i %i\n", layer, ewin->default_layer);
535 fprintf(f, " [PLACED_BY_BUTTON] %i\n", ewin->placed_by_button);
536 fprintf(f, " [EWMH_DESKTOP] %lu\n", ewin->ewmh_hint_desktop);
537 fprintf(f, " [FLAGS] ");
538 for (i = 0; i < sizeof(window_flags); i++)
540 fprintf(f, "%02x ",
541 (int)(((unsigned char *)&(ewin->flags))[i]));
543 fprintf(f, "\n");
545 return 1;
548 /* This complicated logic is from twm, where it is explained */
549 static Bool matchWin(FvwmWindow *w, Match *m)
551 char *client_id = NULL;
552 char *window_role = NULL;
553 char **wm_command = NULL;
554 int wm_command_count = 0, i;
555 int found;
557 found = 0;
558 client_id = GetClientID(w);
560 if (Restarting)
562 if (FW_W(w) == m->win)
564 found = 1;
567 else if (xstreq(client_id, m->client_id))
570 /* client_id's match */
572 window_role = GetWindowRole(FW_W(w));
574 if (client_id && (window_role || m->window_role))
576 /* We have or had a window role, base decision on it */
577 found = xstreq(window_role, m->window_role);
579 else if (xstreq(w->class.res_name, m->res_name) &&
580 xstreq(w->class.res_class, m->res_class) &&
581 (IS_NAME_CHANGED(w) || IS_NAME_CHANGED(m) ||
582 xstreq(w->name.name, m->wm_name)))
584 if (client_id)
586 /* If we have a client_id, we don't
587 * compare WM_COMMAND, since it will be
588 * different. */
589 found = 1;
591 else
593 /* for non-SM-aware clients we also
594 * compare WM_COMMAND */
595 if (!XGetCommand(
596 dpy, FW_W(w), &wm_command,
597 &wm_command_count))
599 wm_command = NULL;
600 wm_command_count = 0;
602 if (wm_command_count == m->wm_command_count)
604 for (i = 0; i < wm_command_count; i++)
606 if (strcmp(unspace_string(
607 wm_command[i]),
608 m->wm_command[i])!=0)
610 break;
614 if (i == wm_command_count)
616 /* migo (21/Oct/1999):
617 * on restarts compare
618 * window ids too */
619 /* But if we restart we only need
620 * to compare window ids
621 * olicha (2005-01-06) */
622 found = 1;
624 } /* if (wm_command_count ==... */
625 } /* else if res_class, res_name and wm_name agree */
626 } /* else no window roles */
627 } /* if client_id's agree */
629 #ifdef FVWM_SM_DEBUG_WINMATCH
630 fprintf(stderr,
631 "\twin(%s, %s, %s, %s, %s,",
632 w->class.res_name, w->class.res_class, w->name.name,
633 (client_id)? client_id:"(null)",
634 (window_role)? window_role:"(null)");
635 if (wm_command)
637 for (i = 0; i < wm_command_count; i++)
639 fprintf(stderr," %s", wm_command[i]);
641 fprintf(stderr,",");
643 else
645 fprintf(stderr," no_wmc,");
647 fprintf(stderr," %d)", IS_NAME_CHANGED(w));
648 fprintf(stderr,"\n[%d]", found);
649 fprintf(stderr,
650 "\tmat(%s, %s, %s, %s, %s,",
651 m->res_name, m->res_class, m->wm_name,
652 (m->client_id)?m->client_id:"(null)",
653 (m->window_role)?m->window_role:"(null)");
654 if (m->wm_command)
656 for (i = 0; i < m->wm_command_count; i++)
658 fprintf(stderr," %s", m->wm_command[i]);
660 fprintf(stderr,",");
662 else
664 fprintf(stderr," no_wmc,");
666 fprintf(stderr," %d)\n\n", IS_NAME_CHANGED(m));
667 #endif
669 if (client_id)
671 XFree(client_id);
673 if (window_role)
675 XFree(window_role);
677 if (wm_command)
679 XFreeStringList (wm_command);
682 return found;
685 static int save_state_file(char *filename)
687 FILE *f;
688 int success;
690 if (!filename || !*filename)
692 return 0;
694 if ((f = fopen(filename, "w")) == NULL)
696 return 0;
699 fprintf(f, "# This file is generated by fvwm."
700 " It stores global and window states.\n");
701 fprintf(f, "# Normally, you must never delete this file,"
702 " it will be auto-deleted.\n\n");
704 if (SessionSupport && going_to_restart)
706 fprintf(f, "[REAL_STATE_FILENAME] %s\n", real_state_filename);
707 going_to_restart = False; /* not needed */
710 success = do_preserve_state
711 ? SaveVersionInfo(f) && SaveWindowStates(f) && SaveGlobalState(f)
712 : 1;
713 do_preserve_state = True;
714 if (fclose(f) != 0)
715 return 0;
717 #ifdef FVWM_SM_DEBUG_FILES
718 system(CatString3(
719 "mkdir -p /tmp/fs-save; cp ", filename,
720 " /tmp/fs-save"));
721 #endif
722 #if defined(FVWM_SM_DEBUG_PROTO) || defined(FVWM_SM_DEBUG_FILES)
723 fprintf(stderr, "[FVWM_SMDEBUG] Saving %s\n", filename);
724 #endif
726 return success;
729 static void
730 set_sm_properties(FSmcConn sm_conn, char *filename, char hint)
732 FSmProp prop1, prop2, prop3, prop4, prop5, prop6, prop7, *props[7];
733 FSmPropValue prop1val, prop2val, prop3val, prop4val, prop7val;
734 struct passwd *pwd;
735 char *user_id;
736 char screen_num[32];
737 int numVals, i, priority = 30;
738 Bool is_xsm_detected = False;
740 if (!SessionSupport)
742 return;
745 #ifdef FVWM_SM_DEBUG_PROTO
746 fprintf(stderr, "[FVWM_SMDEBUG][set_sm_properties] state filename: %s%s\n",
747 filename ? filename : "(null)", sm_conn ? "" : " - not connected");
748 #endif
750 if (!sm_conn)
752 return;
755 pwd = getpwuid (getuid());
756 user_id = pwd->pw_name;
758 prop1.name = FSmProgram;
759 prop1.type = FSmARRAY8;
760 prop1.num_vals = 1;
761 prop1.vals = &prop1val;
762 prop1val.value = g_argv[0];
763 prop1val.length = strlen (g_argv[0]);
765 prop2.name = FSmUserID;
766 prop2.type = FSmARRAY8;
767 prop2.num_vals = 1;
768 prop2.vals = &prop2val;
769 prop2val.value = (FSmPointer) user_id;
770 prop2val.length = strlen (user_id);
772 prop3.name = FSmRestartStyleHint;
773 prop3.type = FSmCARD8;
774 prop3.num_vals = 1;
775 prop3.vals = &prop3val;
776 prop3val.value = (FSmPointer) &hint;
777 prop3val.length = 1;
779 prop4.name = "_GSM_Priority";
780 prop4.type = FSmCARD8;
781 prop4.num_vals = 1;
782 prop4.vals = &prop4val;
783 prop4val.value = (FSmPointer) &priority;
784 prop4val.length = 1;
786 sprintf(screen_num, "%d", (int)Scr.screen);
788 prop5.name = FSmCloneCommand;
789 prop5.type = FSmLISTofARRAY8;
790 prop5.vals = (FSmPropValue *)malloc((g_argc + 2) * sizeof (FSmPropValue));
791 numVals = 0;
792 for (i = 0; i < g_argc; i++)
794 if (strcmp (g_argv[i], "-clientId") == 0 ||
795 strcmp (g_argv[i], "-restore") == 0 ||
796 strcmp (g_argv[i], "-d") == 0 ||
797 (strcmp (g_argv[i], "-s") == 0 && i+1 < g_argc &&
798 g_argv[i+1][0] != '-'))
800 i++;
802 else if (strcmp (g_argv[i], "-s") != 0)
804 prop5.vals[numVals].value = (FSmPointer) g_argv[i];
805 prop5.vals[numVals++].length = strlen (g_argv[i]);
809 prop5.vals[numVals].value = (FSmPointer) "-s";
810 prop5.vals[numVals++].length = 2;
812 prop5.vals[numVals].value = (FSmPointer) screen_num;
813 prop5.vals[numVals++].length = strlen (screen_num);
816 prop5.num_vals = numVals;
818 if (filename)
820 prop6.name = FSmRestartCommand;
821 prop6.type = FSmLISTofARRAY8;
823 prop6.vals = (FSmPropValue *)malloc(
824 (g_argc + 6) * sizeof (FSmPropValue));
826 numVals = 0;
828 for (i = 0; i < g_argc; i++)
830 if (strcmp (g_argv[i], "-clientId") == 0 ||
831 strcmp (g_argv[i], "-restore") == 0 ||
832 strcmp (g_argv[i], "-d") == 0 ||
833 (strcmp (g_argv[i], "-s") == 0 && i+1 < g_argc &&
834 g_argv[i+1][0] != '-'))
836 i++;
838 else if (strcmp (g_argv[i], "-s") != 0)
840 prop6.vals[numVals].value =
841 (FSmPointer) g_argv[i];
842 prop6.vals[numVals++].length =
843 strlen (g_argv[i]);
847 prop6.vals[numVals].value = (FSmPointer) "-s";
848 prop6.vals[numVals++].length = 2;
850 prop6.vals[numVals].value = (FSmPointer) screen_num;
851 prop6.vals[numVals++].length = strlen (screen_num);
853 prop6.vals[numVals].value = (FSmPointer) "-clientId";
854 prop6.vals[numVals++].length = 9;
856 prop6.vals[numVals].value = (FSmPointer) sm_client_id;
857 prop6.vals[numVals++].length = strlen (sm_client_id);
859 prop6.vals[numVals].value = (FSmPointer) "-restore";
860 prop6.vals[numVals++].length = 8;
862 prop6.vals[numVals].value = (FSmPointer) filename;
863 prop6.vals[numVals++].length = strlen (filename);
865 prop6.num_vals = numVals;
867 prop7.name = FSmDiscardCommand;
869 is_xsm_detected = StrEquals(getenv("SESSION_MANAGER_NAME"), "xsm");
871 if (is_xsm_detected)
873 /* the protocol spec says that the discard command
874 should be LISTofARRAY8 on posix systems, but xsm
875 demands that it be ARRAY8.
877 char *discardCommand = alloca(
878 (10 + strlen(filename)) * sizeof(char));
879 sprintf (discardCommand, "rm -f '%s'", filename);
880 prop7.type = FSmARRAY8;
881 prop7.num_vals = 1;
882 prop7.vals = &prop7val;
883 prop7val.value = (FSmPointer) discardCommand;
884 prop7val.length = strlen (discardCommand);
886 else
888 prop7.type = FSmLISTofARRAY8;
889 prop7.num_vals = 3;
890 prop7.vals =
891 (FSmPropValue *) malloc (
892 3 * sizeof (FSmPropValue));
893 prop7.vals[0].value = "rm";
894 prop7.vals[0].length = 2;
895 prop7.vals[1].value = "-f";
896 prop7.vals[1].length = 2;
897 prop7.vals[2].value = filename;
898 prop7.vals[2].length = strlen (filename);
902 props[0] = &prop1;
903 props[1] = &prop2;
904 props[2] = &prop3;
905 props[3] = &prop4;
906 props[4] = &prop5;
908 if (filename)
910 props[5] = &prop6;
911 props[6] = &prop7;
912 FSmcSetProperties (sm_conn, 7, props);
914 free ((char *) prop6.vals);
915 if (!is_xsm_detected)
917 free ((char *) prop7.vals);
920 else
922 FSmcSetProperties (sm_conn, 5, props);
924 free ((char *) prop5.vals);
927 static void
928 callback_save_yourself2(FSmcConn sm_conn, FSmPointer client_data)
930 Bool success = 0;
931 char *filename;
934 if (!SessionSupport)
936 return;
939 filename = get_unique_state_filename();
940 #ifdef FVWM_SM_DEBUG_PROTO
941 fprintf(stderr, "[FVWM_SMDEBUG][callback_save_yourself2]\n");
942 #endif
944 success = save_state_file(filename);
945 if (success)
947 set_sm_properties(sm_conn, filename, FSmRestartIfRunning);
948 set_real_state_filename(filename);
950 free(filename);
952 FSmcSaveYourselfDone (sm_conn, success);
953 sent_save_done = 1;
956 static void
957 callback_save_yourself(FSmcConn sm_conn, FSmPointer client_data,
958 int save_style, Bool shutdown, int interact_style,
959 Bool fast)
962 if (!SessionSupport)
964 return;
967 #ifdef FVWM_SM_DEBUG_PROTO
968 fprintf(stderr, "[FVWM_SMDEBUG][callback_save_yourself] "
969 "(save=%d, shut=%d, intr=%d, fast=%d)\n",
970 save_style, shutdown, interact_style, fast);
971 #endif
973 if (save_style == FSmSaveGlobal)
975 /* nothing to do */
976 #ifdef FVWM_SM_DEBUG_PROTO
977 fprintf(stderr, "[FVWM_SMDEBUG][callback_save_yourself] "
978 "Global Save type ... do nothing\n");
979 #endif
980 FSmcSaveYourselfDone (sm_conn, True);
981 sent_save_done = 1;
982 return;
985 #ifdef FVWM_SM_DEBUG_PROTO
986 fprintf(stderr, "[FVWM_SMDEBUG][callback_save_yourself] "
987 "Both or Local save type, going to phase 2 ...");
988 #endif
989 if (!FSmcRequestSaveYourselfPhase2(
990 sm_conn, callback_save_yourself2, NULL))
992 FSmcSaveYourselfDone (sm_conn, False);
993 sent_save_done = 1;
994 #ifdef FVWM_SM_DEBUG_PROTO
995 fprintf(stderr, " failed!\n");
996 #endif
998 else
1000 #ifdef FVWM_SM_DEBUG_PROTO
1001 fprintf(stderr, " OK\n");
1002 #endif
1003 sent_save_done = 0;
1006 return;
1009 static void
1010 callback_die(FSmcConn sm_conn, FSmPointer client_data)
1013 if (!SessionSupport)
1015 return;
1018 #ifdef FVWM_SM_DEBUG_PROTO
1019 fprintf(stderr, "[FVWM_SMDEBUG][callback_die]\n");
1020 #endif
1022 if (FSmcCloseConnection(sm_conn, 0, NULL) != FSmcClosedNow)
1024 /* go a head any way ? */
1026 sm_fd = -1;
1028 if (master_pid != getpid())
1030 kill(master_pid, SIGTERM);
1032 Done(0, NULL);
1035 static void
1036 callback_save_complete(FSmcConn sm_conn, FSmPointer client_data)
1038 if (!SessionSupport)
1040 return;
1042 #ifdef FVWM_SM_DEBUG_PROTO
1043 fprintf(stderr, "[FVWM_SMDEBUG][callback_save_complete]\n");
1044 #endif
1046 return;
1049 static void
1050 callback_shutdown_cancelled(FSmcConn sm_conn, FSmPointer client_data)
1052 if (!SessionSupport)
1054 return;
1057 #ifdef FVWM_SM_DEBUG_PROTO
1058 fprintf(stderr, "[FVWM_SMDEBUG][callback_shutdown_cancelled]\n");
1059 #endif
1061 if (!sent_save_done)
1063 FSmcSaveYourselfDone(sm_conn, False);
1064 sent_save_done = 1;
1067 return;
1070 /* the following is taken from xsm */
1071 static void
1072 MyIoErrorHandler(FIceConn ice_conn)
1074 if (!SessionSupport)
1076 return;
1079 if (prev_handler)
1081 (*prev_handler) (ice_conn);
1084 return;
1087 static void
1088 InstallIOErrorHandler(void)
1090 FIceIOErrorHandler default_handler;
1092 if (!SessionSupport)
1094 return;
1097 prev_handler = FIceSetIOErrorHandler (NULL);
1098 default_handler = FIceSetIOErrorHandler (MyIoErrorHandler);
1099 if (prev_handler == default_handler)
1101 prev_handler = NULL;
1104 return;
1107 /* ---------------------------- interface functions ------------------------ */
1109 void
1110 LoadGlobalState(char *filename)
1112 FILE *f;
1113 char s[4096], s1[4096];
1114 /* char s2[256]; */
1115 int i1, i2, i3, i4, i5;
1117 if (!does_file_version_match)
1119 return;
1121 if (!filename || !*filename)
1123 return;
1125 if ((f = fopen(filename, "r")) == NULL)
1127 return;
1130 while (fgets(s, sizeof(s), f))
1132 i1 = 0;
1133 i2 = 0;
1134 i3 = 0;
1135 i4 = 0;
1136 i5 = 0;
1137 sscanf(s, "%4000s", s1);
1138 /* If we are restarting, [REAL_STATE_FILENAME] points
1139 * to the file containing the true session state. */
1140 if (SessionSupport && !strcmp(s1, "[REAL_STATE_FILENAME]"))
1142 /* migo: temporarily (?) moved to
1143 LoadWindowStates (trick for gnome-session)
1144 sscanf(s, "%*s %s", s2);
1145 set_sm_properties(sm_conn, s2, FSmRestartIfRunning);
1146 set_real_state_filename(s2);
1149 else if (!strcmp(s1, "[DESKTOP]"))
1151 sscanf(s, "%*s %i", &i1);
1152 goto_desk(i1);
1154 else if (!strcmp(s1, "[VIEWPORT]"))
1156 sscanf(s, "%*s %i %i %i %i", &i1, &i2, &i3,
1157 &i4);
1158 /* migo: we don't want to lose DeskTopSize in
1159 * configurations, and it does not work well
1160 * anyways - Gnome is not updated
1161 Scr.VxMax = i3;
1162 Scr.VyMax = i4;
1164 MoveViewport(i1, i2, True);
1166 #if 0
1167 /* migo (08-Dec-1999): we don't want to eliminate config yet */
1168 else if (/*!Restarting*/ 0)
1170 /* Matthias: We don't want to restore too much
1171 * state if we are restarting, since that
1172 * would make restarting useless for rereading
1173 * changed rc files. */
1174 if (!strcmp(s1, "[SCROLL]"))
1176 sscanf(s, "%*s %i %i %i %i %i", &i1,
1177 &i2, &i3, &i4, &i5);
1178 Scr.EdgeScrollX = i1;
1179 Scr.EdgeScrollY = i2;
1180 Scr.ScrollDelay = i3;
1181 if (i4)
1183 Scr.flags.edge_wrap_x = 1;
1185 else
1187 Scr.flags.edge_wrap_x = 0;
1189 if (i3)
1191 Scr.flags.edge_wrap_y = 1;
1193 else
1195 Scr.flags.edge_wrap_y = 0;
1198 else if (!strcmp(s1, "[MISC]"))
1200 sscanf(s, "%*s %i %i %i", &i1, &i2,
1201 &i3);
1202 Scr.ClickTime = i1;
1203 Scr.ColormapFocus = i2;
1204 Scr.ColorLimit = i3;
1206 else if (!strcmp(s1, "[STYLE]"))
1208 sscanf(s, "%*s %i %i", &i1, &i2);
1209 Scr.gs.EmulateMWM = i1;
1210 Scr.gs.EmulateWIN = i2;
1213 #endif
1215 fclose(f);
1217 return;
1220 void
1221 DisableRestoringState(void)
1223 num_match = 0;
1225 return;
1228 void
1229 LoadWindowStates(char *filename)
1231 FILE *f;
1232 char s[4096], s1[4096];
1233 char *s2;
1234 int i, pos, pos1;
1235 unsigned long w;
1236 int n;
1238 if (!VerifyVersionInfo(filename))
1240 return;
1242 if (!filename || !*filename)
1244 return;
1246 set_real_state_filename(filename);
1247 if ((f = fopen(filename, "r")) == NULL)
1249 return;
1252 #if defined(FVWM_SM_DEBUG_PROTO) || defined(FVWM_SM_DEBUG_FILES)
1253 fprintf(stderr, "[FVWM_SMDEBUG] Loading %s\n", filename);
1254 #endif
1255 #ifdef FVWM_SM_DEBUG_FILES
1256 system(CatString3(
1257 "mkdir -p /tmp/fs-load; cp ", filename,
1258 " /tmp/fs-load"));
1259 #endif
1261 while (fgets(s, sizeof(s), f))
1263 n = 0;
1264 sscanf(s, "%4000s%n", s1, &n);
1265 if (!SessionSupport /* migo: temporarily */ &&
1266 !strcmp(s1, "[REAL_STATE_FILENAME]"))
1268 sscanf(s, "%*s %s", s1);
1269 set_sm_properties(sm_conn, s1, FSmRestartIfRunning);
1270 set_real_state_filename(s1);
1272 else if (!strcmp(s1, "[CLIENT]"))
1274 sscanf(s, "%*s %lx", &w);
1275 num_match++;
1276 matches = (Match *)saferealloc(
1277 (void *)matches, sizeof(Match) * num_match);
1278 matches[num_match - 1].win = w;
1279 matches[num_match - 1].client_id = NULL;
1280 matches[num_match - 1].res_name = NULL;
1281 matches[num_match - 1].res_class = NULL;
1282 matches[num_match - 1].window_role = NULL;
1283 matches[num_match - 1].wm_name = NULL;
1284 matches[num_match - 1].wm_command_count = 0;
1285 matches[num_match - 1].wm_command = NULL;
1286 matches[num_match - 1].x = 0;
1287 matches[num_match - 1].y = 0;
1288 matches[num_match - 1].w = 100;
1289 matches[num_match - 1].h = 100;
1290 matches[num_match - 1].x_max = 0;
1291 matches[num_match - 1].y_max = 0;
1292 matches[num_match - 1].w_max = Scr.MyDisplayWidth;
1293 matches[num_match - 1].h_max = Scr.MyDisplayHeight;
1294 matches[num_match - 1].width_defect_max = 0;
1295 matches[num_match - 1].height_defect_max = 0;
1296 matches[num_match - 1].icon_x = 0;
1297 matches[num_match - 1].icon_y = 0;
1298 matches[num_match - 1].desktop = 0;
1299 matches[num_match - 1].layer = 0;
1300 matches[num_match - 1].default_layer = 0;
1301 memset(&(matches[num_match - 1].flags), 0,
1302 sizeof(window_flags));
1303 matches[num_match - 1].used = 0;
1305 else if (!strcmp(s1, "[GEOMETRY]"))
1307 sscanf(s, "%*s %i %i %i %i %i %i %i %i %i %i %i %i"
1308 " %i %i %i",
1309 &(matches[num_match - 1].x),
1310 &(matches[num_match - 1].y),
1311 &(matches[num_match - 1].w),
1312 &(matches[num_match - 1].h),
1313 &(matches[num_match - 1].x_max),
1314 &(matches[num_match - 1].y_max),
1315 &(matches[num_match - 1].w_max),
1316 &(matches[num_match - 1].h_max),
1317 &(matches[num_match - 1].width_defect_max),
1318 &(matches[num_match - 1].height_defect_max),
1319 &(matches[num_match - 1].icon_x),
1320 &(matches[num_match - 1].icon_y),
1321 &(matches[num_match - 1].gravity),
1322 &(matches[num_match - 1].max_x_offset),
1323 &(matches[num_match - 1].max_y_offset));
1325 else if (!strcmp(s1, "[DESK]"))
1327 sscanf(s, "%*s %i",
1328 &(matches[num_match - 1].desktop));
1330 else if (!strcmp(s1, "[LAYER]"))
1332 sscanf(s, "%*s %i %i",
1333 &(matches[num_match - 1].layer),
1334 &(matches[num_match - 1].default_layer));
1336 else if (!strcmp(s1, "[PLACED_BY_BUTTON]"))
1338 sscanf(s, "%*s %i",
1339 &(matches[num_match - 1].placed_by_button));
1341 else if (!strcmp(s1, "[EWMH_DESKTOP]"))
1343 sscanf(s, "%*s %lu",
1344 &(matches[num_match - 1].ewmh_hint_desktop));
1346 else if (!strcmp(s1, "[FLAGS]"))
1348 char *ts = s;
1350 /* skip [FLAGS] */
1351 while (*ts != ']')
1353 ts++;
1355 ts++;
1357 for (i = 0; i < sizeof(window_flags); i++)
1359 unsigned int f;
1360 sscanf(ts, "%02x ", &f);
1361 ((unsigned char *)&
1362 (matches[num_match-1].flags))[i] = f;
1363 ts += 3;
1366 else if (!strcmp(s1, "[CLIENT_ID]"))
1368 s2 = s + n;
1369 if (*s2 != 0)
1371 s2++;
1373 sscanf(s2, "%[^\n]", s1);
1374 matches[num_match - 1].client_id = duplicate(s1);
1376 else if (!strcmp(s1, "[WINDOW_ROLE]"))
1378 s2 = s + n;
1379 if (*s2 != 0)
1381 s2++;
1383 sscanf(s2, "%[^\n]", s1);
1384 matches[num_match - 1].window_role = duplicate(s1);
1386 else if (!strcmp(s1, "[RES_NAME]"))
1388 s2 = s + n;
1389 if (*s2 != 0)
1391 s2++;
1393 sscanf(s2, "%[^\n]", s1);
1394 matches[num_match - 1].res_name = duplicate(s1);
1396 else if (!strcmp(s1, "[RES_CLASS]"))
1398 s2 = s + n;
1399 if (*s2 != 0)
1401 s2++;
1403 sscanf(s2, "%[^\n]", s1);
1404 matches[num_match - 1].res_class = duplicate(s1);
1406 else if (!strcmp(s1, "[WM_NAME]"))
1408 s2 = s + n;
1409 if (*s2 != 0)
1411 s2++;
1413 sscanf(s2, "%[^\n]", s1);
1414 matches[num_match - 1].wm_name = duplicate(s1);
1416 else if (!strcmp(s1, "[WM_COMMAND]"))
1418 sscanf(s, "%*s %i%n",
1419 &matches[num_match - 1].wm_command_count, &pos);
1420 matches[num_match - 1].wm_command = (char **)
1421 safemalloc(
1422 matches[num_match - 1].
1423 wm_command_count * sizeof (char *));
1424 for (i = 0;
1425 i < matches[num_match - 1].wm_command_count; i++)
1427 sscanf (s+pos, "%s%n", s1, &pos1);
1428 pos += pos1;
1429 matches[num_match - 1].wm_command[i] =
1430 duplicate (s1);
1434 fclose(f);
1436 return;
1440 This routine (potentially) changes the flags STARTICONIC,
1441 MAXIMIZED, WSHADE and STICKY and the Desk and
1442 attr.x, .y, .width, .height entries. It also changes the
1443 stack_before pointer to return information about the
1444 desired stacking order. It expects the stacking order
1445 to be set up correctly beforehand!
1447 Bool
1448 MatchWinToSM(
1449 FvwmWindow *ewin, mwtsm_state_args *ret_state_args,
1450 initial_window_options_t *win_opts)
1452 int i;
1454 if (!does_file_version_match)
1456 return False;
1458 for (i = 0; i < num_match; i++)
1460 if (!matches[i].used && matchWin(ewin, &matches[i]))
1462 matches[i].used = 1;
1464 if (!Restarting)
1466 /* We don't want to restore too much state if
1467 we are restarting, since that would make
1468 * restarting useless for rereading changed
1469 * rc files. */
1470 SET_DO_SKIP_WINDOW_LIST(
1471 ewin,
1472 DO_SKIP_WINDOW_LIST(&(matches[i])));
1473 SET_ICON_SUPPRESSED(
1474 ewin,
1475 IS_ICON_SUPPRESSED(&(matches[i])));
1476 SET_HAS_NO_ICON_TITLE(
1477 ewin, HAS_NO_ICON_TITLE(&(matches[i])));
1478 FPS_LENIENT(
1479 FW_FOCUS_POLICY(ewin),
1480 FP_IS_LENIENT(FW_FOCUS_POLICY(
1481 &(matches[i]))));
1482 SET_ICON_STICKY_ACROSS_PAGES(
1483 ewin, IS_ICON_STICKY_ACROSS_PAGES(
1484 &(matches[i])));
1485 SET_ICON_STICKY_ACROSS_DESKS(
1486 ewin, IS_ICON_STICKY_ACROSS_DESKS(
1487 &(matches[i])));
1488 SET_DO_SKIP_ICON_CIRCULATE(
1489 ewin, DO_SKIP_ICON_CIRCULATE(
1490 &(matches[i])));
1491 SET_DO_SKIP_SHADED_CIRCULATE(
1492 ewin, DO_SKIP_SHADED_CIRCULATE(
1493 &(matches[i])));
1494 SET_DO_SKIP_CIRCULATE(
1495 ewin, DO_SKIP_CIRCULATE(&(matches[i])));
1496 memcpy(
1497 &FW_FOCUS_POLICY(ewin),
1498 &FW_FOCUS_POLICY(&matches[i]),
1499 sizeof(focus_policy_t));
1500 if (matches[i].wm_name)
1502 free_window_names(ewin, True, False);
1503 ewin->name.name = matches[i].wm_name;
1504 setup_visible_name(ewin, False);
1507 SET_NAME_CHANGED(ewin,IS_NAME_CHANGED(&(matches[i])));
1508 SET_PLACED_BY_FVWM(
1509 ewin, IS_PLACED_BY_FVWM(&(matches[i])));
1510 ret_state_args->do_shade = IS_SHADED(&(matches[i]));
1511 ret_state_args->used_title_dir_for_shading =
1512 USED_TITLE_DIR_FOR_SHADING(&(matches[i]));
1513 ret_state_args->shade_dir = SHADED_DIR(&(matches[i]));
1514 ret_state_args->do_max = IS_MAXIMIZED(&(matches[i]));
1515 SET_USER_STATES(ewin, GET_USER_STATES(&(matches[i])));
1516 SET_ICON_MOVED(ewin, IS_ICON_MOVED(&(matches[i])));
1517 if (IS_ICONIFIED(&(matches[i])))
1520 ICON_MOVED is necessary to make fvwm use
1521 icon_[xy]_loc for icon placement
1523 win_opts->initial_state = IconicState;
1524 win_opts->flags.use_initial_icon_xy = 1;
1525 win_opts->initial_icon_x = matches[i].icon_x;
1526 win_opts->initial_icon_y = matches[i].icon_y;
1527 if (!IS_STICKY_ACROSS_PAGES(&(matches[i])) &&
1528 !(IS_ICONIFIED(&(matches[i])) &&
1529 IS_ICON_STICKY_ACROSS_PAGES(
1530 &(matches[i]))))
1532 win_opts->initial_icon_x -= Scr.Vx;
1533 win_opts->initial_icon_y -= Scr.Vy;
1536 ewin->g.normal.x = matches[i].x;
1537 ewin->g.normal.y = matches[i].y;
1538 ewin->g.normal.width = matches[i].w;
1539 ewin->g.normal.height = matches[i].h;
1540 ewin->g.max.x = matches[i].x_max;
1541 ewin->g.max.y = matches[i].y_max;
1542 ewin->g.max.width = matches[i].w_max;
1543 ewin->g.max.height = matches[i].h_max;
1544 ewin->g.max_defect.width = matches[i].width_defect_max;
1545 ewin->g.max_defect.height =
1546 matches[i].height_defect_max;
1547 ewin->g.max_offset.x = matches[i].max_x_offset;
1548 ewin->g.max_offset.y = matches[i].max_y_offset;
1549 SET_STICKY_ACROSS_PAGES(
1550 ewin, IS_STICKY_ACROSS_PAGES(&(matches[i])));
1551 SET_STICKY_ACROSS_DESKS(
1552 ewin, IS_STICKY_ACROSS_DESKS(&(matches[i])));
1553 ewin->Desk = (IS_STICKY_ACROSS_DESKS(ewin)) ?
1554 Scr.CurrentDesk : matches[i].desktop;
1555 set_layer(ewin, matches[i].layer);
1556 set_default_layer(ewin, matches[i].default_layer);
1557 ewin->placed_by_button = matches[i].placed_by_button;
1558 /* Note: the Modal, skip pager, skip taskbar and
1559 * "stacking order" state are not restored here: there
1560 * are restored in EWMH_ExitStuff */
1561 ewin->ewmh_hint_desktop = matches[i].ewmh_hint_desktop;
1562 SET_HAS_EWMH_INIT_WM_DESKTOP(
1563 ewin, HAS_EWMH_INIT_WM_DESKTOP(&(matches[i])));
1564 SET_HAS_EWMH_INIT_HIDDEN_STATE(
1565 ewin, HAS_EWMH_INIT_HIDDEN_STATE(
1566 &(matches[i])));
1567 SET_HAS_EWMH_INIT_MAXHORIZ_STATE(
1568 ewin, HAS_EWMH_INIT_MAXHORIZ_STATE(
1569 &(matches[i])));
1570 SET_HAS_EWMH_INIT_MAXVERT_STATE(
1571 ewin, HAS_EWMH_INIT_MAXVERT_STATE(
1572 &(matches[i])));
1573 SET_HAS_EWMH_INIT_SHADED_STATE(
1574 ewin, HAS_EWMH_INIT_SHADED_STATE(
1575 &(matches[i])));
1576 SET_HAS_EWMH_INIT_STICKY_STATE(
1577 ewin, HAS_EWMH_INIT_STICKY_STATE(
1578 &(matches[i])));
1579 return True;
1583 return False;
1586 void
1587 RestartInSession (char *filename, Bool is_native, Bool _do_preserve_state)
1589 do_preserve_state = _do_preserve_state;
1591 if (SessionSupport && sm_conn && is_native)
1593 going_to_restart = True;
1595 save_state_file(filename);
1596 set_sm_properties(sm_conn, filename, FSmRestartImmediately);
1598 MoveViewport(0, 0, False);
1599 Reborder();
1601 CloseICCCM2();
1602 XCloseDisplay(dpy);
1604 if (!FSmcCloseConnection(sm_conn, 0, NULL) != FSmcClosedNow)
1606 /* go a head any way ? */
1609 #ifdef FVWM_SM_DEBUG_PROTO
1610 fprintf(stderr, "[FVWM_SMDEBUG]: Exiting, now SM must "
1611 "restart us.\n");
1612 #endif
1613 /* Close all my pipes */
1614 module_kill_all();
1616 exit(0); /* let the SM restart us */
1619 save_state_file(filename);
1620 /* return and let Done restart us */
1622 return;
1625 void SetClientID(char *client_id)
1627 if (!SessionSupport)
1629 return;
1631 previous_sm_client_id = client_id;
1633 return;
1636 void
1637 SessionInit(void)
1639 char error_string_ret[4096] = "";
1640 FSmPointer context;
1641 FSmcCallbacks callbacks;
1643 if (!SessionSupport)
1645 /* -Wall fixes */
1646 MyIoErrorHandler(NULL);
1647 callback_save_yourself2(NULL, NULL);
1648 return;
1651 context = NULL;
1652 InstallIOErrorHandler();
1654 callbacks.save_yourself.callback = callback_save_yourself;
1655 callbacks.die.callback = callback_die;
1656 callbacks.save_complete.callback = callback_save_complete;
1657 callbacks.shutdown_cancelled.callback = callback_shutdown_cancelled;
1658 callbacks.save_yourself.client_data =
1659 callbacks.die.client_data =
1660 callbacks.save_complete.client_data =
1661 callbacks.shutdown_cancelled.client_data = (FSmPointer) NULL;
1662 sm_conn = FSmcOpenConnection(
1663 NULL, &context, FSmProtoMajor, FSmProtoMinor,
1664 FSmcSaveYourselfProcMask | FSmcDieProcMask |
1665 FSmcSaveCompleteProcMask | FSmcShutdownCancelledProcMask,
1666 &callbacks, previous_sm_client_id, &sm_client_id, 4096,
1667 error_string_ret);
1668 if (!sm_conn)
1671 Don't annoy users which don't use a session manager
1673 if (previous_sm_client_id)
1675 fvwm_msg(
1676 ERR, "SessionInit",
1677 "While connecting to session manager:\n%s.",
1678 error_string_ret);
1680 sm_fd = -1;
1681 #ifdef FVWM_SM_DEBUG_PROTO
1682 fprintf(stderr,"[FVWM_SMDEBUG] No SM connection\n");
1683 #endif
1685 else
1687 sm_fd = FIceConnectionNumber(FSmcGetIceConnection(sm_conn));
1688 #ifdef FVWM_SM_DEBUG_PROTO
1689 fprintf(stderr,"[FVWM_SMDEBUG] Connectecd to a SM\n");
1690 #endif
1691 set_init_function_name(0, "SessionInitFunction");
1692 set_init_function_name(1, "SessionRestartFunction");
1693 set_init_function_name(2, "SessionExitFunction");
1694 /* basically to restet our restart style hint after a
1695 * restart */
1696 set_sm_properties(sm_conn, NULL, FSmRestartIfRunning);
1699 return;
1702 void
1703 ProcessICEMsgs(void)
1705 FIceProcessMessagesStatus status;
1707 if (!SessionSupport)
1709 return;
1712 #ifdef FVWM_SM_DEBUG_PROTO
1713 fprintf(stderr,"[FVWM_SMDEBUG][ProcessICEMsgs] %i\n", (int)sm_fd);
1714 #endif
1715 if (sm_fd < 0)
1717 return;
1719 status = FIceProcessMessages(FSmcGetIceConnection(sm_conn), NULL, NULL);
1720 if (status == FIceProcessMessagesIOError)
1722 fvwm_msg(ERR, "ProcessICEMSGS",
1723 "Connection to session manager lost\n");
1724 sm_conn = NULL;
1725 sm_fd = -1;
1728 return;
1732 * Fvwm Function implementation: QuitSession, SaveSession, SaveQuitSession.
1733 * migo (15-Jun-1999): I am not sure this is right.
1734 * The session mabager must implement SmsSaveYourselfRequest (xsm doesn't?).
1735 * Alternative implementation may use unix signals, but this does not work
1736 * with all session managers (also must suppose that SM runs locally).
1738 int get_sm_pid(void)
1740 const char *session_manager_var = getenv("SESSION_MANAGER");
1741 const char *sm_pid_str_ptr;
1742 int sm_pid = 0;
1744 if (!SessionSupport)
1746 return 0;
1749 if (!session_manager_var)
1751 return 0;
1753 sm_pid_str_ptr = strchr(session_manager_var, ',');
1754 if (!sm_pid_str_ptr)
1756 return 0;
1758 while (sm_pid_str_ptr > session_manager_var && isdigit(*(--sm_pid_str_ptr)))
1760 /* nothing */
1762 while (isdigit(*(++sm_pid_str_ptr)))
1764 sm_pid = sm_pid * 10 + *sm_pid_str_ptr - '0';
1767 return sm_pid;
1771 * quit_session - hopefully shutdowns the session
1773 Bool quit_session(void)
1775 if (!SessionSupport)
1777 return False;
1779 if (!sm_conn)
1781 return False;
1784 FSmcRequestSaveYourself(
1785 sm_conn, FSmSaveLocal, True /* shutdown */, FSmInteractStyleAny,
1786 False /* fast */, True /* global */);
1787 return True;
1789 /* migo: xsm does not support RequestSaveYourself, but supports
1790 * signals: */
1792 int sm_pid = get_sm_pid();
1793 if (!sm_pid) return False;
1794 return kill(sm_pid, SIGTERM) == 0 ? True : False;
1799 * save_session - hopefully saves the session
1801 Bool save_session(void)
1803 if (!SessionSupport)
1805 return False;
1807 if (!sm_conn)
1809 return False;
1812 FSmcRequestSaveYourself(
1813 sm_conn, FSmSaveBoth, False /* shutdown */, FSmInteractStyleAny,
1814 False /* fast */, True /* global */);
1815 return True;
1817 /* migo: xsm does not support RequestSaveYourself, but supports
1818 * signals: */
1820 int sm_pid = get_sm_pid();
1821 if (!sm_pid) return False;
1822 return kill(sm_pid, SIGUSR1) == 0 ? True : False;
1827 * save_quit_session - hopefully saves and shutdowns the session
1829 Bool save_quit_session(void)
1831 if (!SessionSupport)
1833 return False;
1836 if (!sm_conn)
1838 return False;
1841 FSmcRequestSaveYourself(
1842 sm_conn, FSmSaveBoth, True /* shutdown */, FSmInteractStyleAny,
1843 False /* fast */, True /* global */);
1844 return True;
1846 /* migo: xsm does not support RequestSaveYourself, but supports
1847 * signals: */
1849 if (save_session() == False) return False;
1850 sleep(3); / * doesn't work anyway * /
1851 if (quit_session() == False) return False;
1852 return True;
1856 /* ---------------------------- builtin commands --------------------------- */
1858 void CMD_QuitSession(F_CMD_ARGS)
1860 quit_session();
1862 return;
1865 void CMD_SaveSession(F_CMD_ARGS)
1867 save_session();
1869 return;
1872 void CMD_SaveQuitSession(F_CMD_ARGS)
1874 save_quit_session();
1876 return;