Subject: GNOME Hints Patch

From: Jay Painter <[email-masked]>
Date: Tue, 23 Feb 1999 00:20:10 -0800 (PST)

I'm currently downloading the 2.2 source which I'll merge my GNOME patch
in with.  It currently supports the GNOME pager and root menu clicks.
Session management and layers are still pending, but I remember seeing a
patch for layers posted to this list about a month ago, if an update of
that patch is available it would make my life easier.

Regards,
Jay

-----------------------------------------------------------------------
Jay Painter -- [email-masked] -- [email-masked] -- [email-masked]
http://www.serv.net/~jpaint/

--
Visit the official FVWM web page at <URL:http://fvwm.math.uh.edu/>.
To unsubscribe from the list, send "unsubscribe fvwm-workers" in the
body of a message to [email-masked].
To report problems, send mail to [email-masked].

---

From: Matthias Clasen <[email-masked]>
Date: Tue, 23 Feb 1999 12:28:55 +0100

> that patch is available it would make my life easier.

Jay, I posted the layers and session management (and some more) patches. 
Give me a few days and I'll repost updated versions of my stuff. 

Matthias

-- 
Matthias Clasen, 
Tel. 0761/203-5606
Email: [email-masked]
Mathematisches Institut, Albert-Ludwigs-Universitaet Freiburg
--
Visit the official FVWM web page at <URL:http://fvwm.math.uh.edu/>.
To unsubscribe from the list, send "unsubscribe fvwm-workers" in the
body of a message to [email-masked].
To report problems, send mail to [email-masked].

---

From: Dan Espen <[email-masked]>
Date: Tue, 23 Feb 1999 09:14:26 -0500

> Give me a few days and I'll repost updated versions of my stuff. 

I'm not paying close attention,  but I'm getting the impression  there
is some  relationship between Jay's Gnome  work, and Matthias's layers
and session work.

The unfinished business  I referred to in the  subject line has  to do
with post 2.2 development.  I vaguely remember  someone saying that we
would be granting more CVS update access after 2.2 shipped.

I think we have at least 2 likely candidates.

In my  opinion, this should not a  an exclusive  club.  The current 5?
updaters is not nearly enough.  Any other opinions?

--
Dan Espen
444 Hoes Lane  Room RRC 1C-214           E-mail: [email-masked]
Piscataway, NJ 08854                     Phone: (732) 699-5570
--
Visit the official FVWM web page at <URL:http://fvwm.math.uh.edu/>.
To unsubscribe from the list, send "unsubscribe fvwm-workers" in the
body of a message to [email-masked].
To report problems, send mail to [email-masked].

---

From: Steve Robbins <[email-masked]>
Date: Tue, 23 Feb 1999 09:50:04 -0500 (EST)

> updaters is not nearly enough.  Any other opinions?

The CVS club should absolutely *not* be exclusive.  I think the consensus
was something along the lines of, "you can get CVS write access by
continually posting good patches to the list."  

This begs the question of how to evaluate the "goodness" of the patches. 
I suppose that would be done by the current CVS writers.  I haven't been
paying attention to the patches in question, so I can't make any comment
on that.

My feeling is that if we trust you to write to the CVS repository, we
should also trust your judgement about giving others commit access.

--
Steve Robbins                              <[email-masked]>

Speeding motorcycle ... won't you take me ...

---

From: Jason L Tibbitts III <[email-masked]>
Date: 23 Feb 1999 10:48:18 -0600

>>>>> "SR" == Steve Robbins <[email-masked]> writes:

SR> I think the consensus was something along the lines of, "you can get
SR> CVS write access by continually posting good patches to the list."

That was the case.  I think that at least Matthias' patches have been of
quite high quality; I haven't read over Jay's patches.  (Or have we only
seen work on fvwm1 from Jay).

Matthias seems to me like a code hackin' fool; I think it would benefit the
laziness of others greatly if we gave him access and let him do all of the
work.  ^_^

SR> My feeling is that if we trust you to write to the CVS repository, we
SR> should also trust your judgement about giving others commit access.

And remember that we can always back things out.

 - J<

---

From: Tim Phipps <[email-masked]>
Date: Tue, 23 Feb 1999 16:58:48 +0000

> laziness of others greatly if we gave him access and let him do all of the

Exactly. You lot did it to me (and you will pay for it 8-) so I think we
should inflict CVS access on him (and Chris Rankin).

Cheers,
Tim.

---

From: Matthias Clasen <[email-masked]>
Date: Wed, 24 Feb 1999 01:14:55 +0100

> should inflict CVS access on him (and Chris Rankin).

OK, so now I have tu hurry to get my patches posted before I have to check
them in myself :-)

Session management functionality for fvwm-2.2:

If a session manager is running and has 
announced itself through the environment variable
SESSION_MANAGER, fvwm will connect to it. 

If you initiate a checkpoint for your session, fvwm 
saves much of its state to a file with a unique name
of the form .fvwm<unique suffix>. This file is 
created in the directory SM_SAVE_DIR, if that
environment variable is set and in the users
home directory otherwise. 

Fvwm currently saves and restores the following 
per window state:

* window geometry including desk and page
* focus style
* iconification and icon position including
  desk and page
* maximization plus maximized geometry
* shadedness
* various other window flags: sticky, ontop,
  windowlistskip, suppressicon, noicontitle,
  lenience, stickyicon, circulateskipicon,
  circulateskip

Additionally, fvwm saves and restores the following
global state:

* stacking order
* current desk, viewport and desktop size
* edgescroll amount, scroll and move resistance,
  edgescroll wrap
* snapattraction including mode and grid
* clicktime, colormap focus style, color limit,
* several global options: smartplacementisclever,
  clicktofocuspassesclick, clicktofocusraises,
  mousefocusclickraises, stipledtitles, modifyusp,
  capturehonorsstartsonpage, recapturehonorsstartsonpage,
  activeplacementhonorsstartsonpage
* mwm or fvwm emulation

Note that fvwm doesn't save any information regarding
styles, decors, functions or menus. If you change anything
wrt. to these resources during a session (eg by issuing
"Style" commands via FvwmTalk), these changes will be lost
after saving and restarting the session. To become permanent,
such changes have to be added to the config file.

Note further that the current implementation has the following
anomaly when used on a multi-screen display: Starting fvwm
for the first time, it will manage all screens by forking a copy
of itself for each screen. Every copy knows its parent and issuing
a "Quit" command to any instance of fvwm will kill the master and
thus all copies of fvwm. When you save and restart the session,
the session manager brings up a copy of fvwm on each screen, but
this time they are started as individual instances managing one 
screen only. Thus a "Quit" will now kill only the copy it was sent
to. I don't think this is a very serious problem, since with session 
management, you are supposed to quit a session through the session 
manager anyway. If it is really needed, "Exec exec killall fvwm2" 
will still kill all copies of fvwm.

To apply the patch:

cd fvwm-2.2/fvwm; patch -p 1 < this-mail

Note that you will have to tell patch that the files 
configure.in and config.h.in are in the parent directory.

diff -cN fvwm-base/Makefile.am fvwm/Makefile.am
*** fvwm-base/Makefile.am	Wed Jan 20 02:50:14 1999
--- fvwm/Makefile.am	Tue Feb 23 21:11:05 1999
***************
*** 5,11 ****
  EXTRA_DIST = $(man_MANS)
  man_MANS = fvwm2.1
  
! fvwm2_SOURCES = add_window.c bindings.c borders.c \
  builtins.c colormaps.c colors.c complex.c decorations.c defaults.h \
  events.c focus.c functions.c fvwm.c fvwm.h fvwmdebug.c fvwmdebug.h icons.c \
  menus.c menus.h misc.c misc.h modconf.c module.c module.h move.c \
--- 5,11 ----
  EXTRA_DIST = $(man_MANS)
  man_MANS = fvwm2.1
  
! fvwm2_SOURCES = session.c add_window.c bindings.c borders.c \
  builtins.c colormaps.c colors.c complex.c decorations.c defaults.h \
  events.c focus.c functions.c fvwm.c fvwm.h fvwmdebug.c fvwmdebug.h icons.c \
  menus.c menus.h misc.c misc.h modconf.c module.c module.h move.c \
diff -cN fvwm-base/Makefile.in fvwm/Makefile.in
*** fvwm-base/Makefile.in	Mon Feb 22 19:12:39 1999
--- fvwm/Makefile.in	Tue Feb 23 21:11:05 1999
***************
*** 88,94 ****
  EXTRA_DIST = $(man_MANS)
  man_MANS = fvwm2.1
  
! fvwm2_SOURCES = add_window.c bindings.c borders.c builtins.c colormaps.c colors.c complex.c decorations.c defaults.h events.c focus.c functions.c fvwm.c fvwm.h fvwmdebug.c fvwmdebug.h icons.c menus.c menus.h misc.c misc.h modconf.c module.c module.h move.c parse.h placement.c read.c resize.c screen.h style.c virtual.c windows.c

  fvwm2_DEPENDENCIES = $(top_builddir)/libs/libfvwm.a
--- 88,94 ----
  EXTRA_DIST = $(man_MANS)
  man_MANS = fvwm2.1
  
! fvwm2_SOURCES = session.c add_window.c bindings.c borders.c builtins.c colormaps.c colors.c complex.c decorations.c defaults.h events.c focus.c functions.c fvwm.c fvwm.h fvwmdebug.c fvwmdebug.h icons.c menus.c menus.h misc.c misc.h modconf.c module.c module.h move.c parse.h placement.c read.c resize.c screen.h style.c virtual.c windows.c

  fvwm2_DEPENDENCIES = $(top_builddir)/libs/libfvwm.a
***************
*** 111,117 ****
  X_LIBS = @X_LIBS@
  X_EXTRA_LIBS = @X_EXTRA_LIBS@
  X_PRE_LIBS = @X_PRE_LIBS@
! fvwm2_OBJECTS =  add_window.o bindings.o borders.o builtins.o \
  colormaps.o colors.o complex.o decorations.o events.o focus.o \
  functions.o fvwm.o fvwmdebug.o icons.o menus.o misc.o modconf.o \
  module.o move.o placement.o read.o resize.o style.o virtual.o windows.o
--- 111,117 ----
  X_LIBS = @X_LIBS@
  X_EXTRA_LIBS = @X_EXTRA_LIBS@
  X_PRE_LIBS = @X_PRE_LIBS@
! fvwm2_OBJECTS =  session.o add_window.o bindings.o borders.o builtins.o \
  colormaps.o colors.o complex.o decorations.o events.o focus.o \
  functions.o fvwm.o fvwmdebug.o icons.o menus.o misc.o modconf.o \
  module.o move.o placement.o read.o resize.o style.o virtual.o windows.o
***************
*** 132,137 ****
--- 132,144 ----
  
  TAR = tar
  GZIP_ENV = --best
+ DEP_FILES =  .deps/add_window.P .deps/bindings.P .deps/borders.P \
+ .deps/builtins.P .deps/colormaps.P .deps/colors.P .deps/complex.P \
+ .deps/decorations.P .deps/events.P .deps/focus.P .deps/functions.P \
+ .deps/fvwm.P .deps/fvwmdebug.P .deps/icons.P .deps/menus.P .deps/misc.P \
+ .deps/modconf.P .deps/module.P .deps/move.P .deps/placement.P \
+ .deps/read.P .deps/resize.P .deps/session.P .deps/style.P \
+ .deps/virtual.P .deps/windows.P
  SOURCES = $(fvwm2_SOURCES)
  OBJECTS = $(fvwm2_OBJECTS)
  
***************
*** 139,147 ****
  .SUFFIXES:
  .SUFFIXES: .S .c .o .s
  $(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
! 	cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps fvwm/Makefile
  
! Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
  	cd $(top_builddir) \
  	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
  
--- 146,154 ----
  .SUFFIXES:
  .SUFFIXES: .S .c .o .s
  $(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
! 	cd $(top_srcdir) && $(AUTOMAKE) --gnu fvwm/Makefile
  
! Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(BUILT_SOURCES)
  	cd $(top_builddir) \
  	  && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
  
***************
*** 171,179 ****
  	  rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \
  	done
  
- .c.o:
- 	$(COMPILE) -c $<
- 
  .s.o:
  	$(COMPILE) -c $<
  
--- 178,183 ----
***************
*** 267,272 ****
--- 271,281 ----
  subdir = fvwm
  
  distdir: $(DISTFILES)
+ 	here=`cd $(top_builddir) && pwd`; \
+ 	top_distdir=`cd $(top_distdir) && pwd`; \
+ 	distdir=`cd $(distdir) && pwd`; \
+ 	cd $(top_srcdir) \
+ 	  && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --gnu fvwm/Makefile
  	@for file in $(DISTFILES); do \
  	  d=$(srcdir); \
  	  if test -d $$d/$$file; then \
***************
*** 277,329 ****
  	    || cp -p $$d/$$file $(distdir)/$$file || :; \
  	  fi; \
  	done
- add_window.o: add_window.c ../config.h fvwm.h ../libs/fvwmlib.h \
- 	fvwmdebug.h screen.h misc.h defaults.h menus.h module.h
- bindings.o: bindings.c ../config.h fvwm.h ../libs/fvwmlib.h fvwmdebug.h \
- 	misc.h defaults.h menus.h parse.h screen.h module.h
- borders.o: borders.c ../config.h fvwm.h ../libs/fvwmlib.h fvwmdebug.h \
- 	misc.h defaults.h menus.h parse.h screen.h module.h
- colormaps.o: colormaps.c ../config.h fvwm.h ../libs/fvwmlib.h \
- 	fvwmdebug.h misc.h defaults.h menus.h parse.h screen.h module.h
- colors.o: colors.c ../config.h fvwm.h ../libs/fvwmlib.h fvwmdebug.h \
- 	menus.h misc.h defaults.h parse.h screen.h
- complex.o: complex.c ../config.h fvwm.h ../libs/fvwmlib.h fvwmdebug.h \
- 	menus.h misc.h defaults.h parse.h screen.h module.h
- decorations.o: decorations.c ../config.h fvwm.h ../libs/fvwmlib.h \
- 	fvwmdebug.h misc.h defaults.h menus.h screen.h parse.h \
- 	../libs/lang-strings.h
- events.o: events.c ../config.h fvwm.h ../libs/fvwmlib.h fvwmdebug.h \
- 	menus.h misc.h defaults.h parse.h screen.h module.h
- focus.o: focus.c ../config.h fvwm.h ../libs/fvwmlib.h fvwmdebug.h \
- 	menus.h misc.h defaults.h parse.h screen.h module.h
- functions.o: functions.c ../config.h fvwm.h ../libs/fvwmlib.h \
- 	fvwmdebug.h menus.h misc.h defaults.h parse.h screen.h module.h
- fvwmdebug.o: fvwmdebug.c ../config.h fvwm.h ../libs/fvwmlib.h \
- 	fvwmdebug.h
- icons.o: icons.c ../config.h fvwm.h ../libs/fvwmlib.h fvwmdebug.h misc.h \
- 	defaults.h menus.h parse.h screen.h module.h
- menus.o: menus.c ../config.h fvwm.h ../libs/fvwmlib.h fvwmdebug.h \
- 	menus.h misc.h defaults.h parse.h screen.h
- misc.o: misc.c ../config.h fvwm.h ../libs/fvwmlib.h fvwmdebug.h menus.h \
- 	misc.h defaults.h parse.h screen.h module.h
- modconf.o: modconf.c ../config.h fvwm.h ../libs/fvwmlib.h fvwmdebug.h \
- 	menus.h misc.h defaults.h parse.h screen.h module.h
- module.o: module.c ../config.h fvwm.h ../libs/fvwmlib.h fvwmdebug.h \
- 	menus.h misc.h defaults.h parse.h screen.h module.h
- move.o: move.c ../config.h fvwm.h ../libs/fvwmlib.h fvwmdebug.h menus.h \
- 	misc.h defaults.h parse.h screen.h module.h
- placement.o: placement.c ../config.h fvwm.h ../libs/fvwmlib.h \
- 	fvwmdebug.h menus.h misc.h defaults.h parse.h screen.h
- resize.o: resize.c ../config.h fvwm.h ../libs/fvwmlib.h fvwmdebug.h \
- 	misc.h defaults.h menus.h screen.h parse.h
- style.o: style.c ../config.h fvwm.h ../libs/fvwmlib.h fvwmdebug.h \
- 	menus.h misc.h defaults.h parse.h screen.h
- virtual.o: virtual.c ../config.h fvwm.h ../libs/fvwmlib.h fvwmdebug.h \
- 	menus.h misc.h defaults.h parse.h screen.h module.h
- windows.o: windows.c ../config.h ../libs/fvwmlib.h fvwm.h \
- 	../libs/fvwmlib.h fvwmdebug.h menus.h misc.h defaults.h parse.h \
- 	screen.h
  
  info-am:
  info: info-am
  dvi-am:
--- 286,323 ----
  	    || cp -p $$d/$$file $(distdir)/$$file || :; \
  	  fi; \
  	done
  
+ DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+ 
+ -include $(DEP_FILES)
+ 
+ mostlyclean-depend:
+ 
+ clean-depend:
+ 
+ distclean-depend:
+ 	-rm -rf .deps
+ 
+ maintainer-clean-depend:
+ 
+ %.o: %.c
+ 	@echo '$(COMPILE) -c $<'; \
+ 	$(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ 	@-cp .deps/$(*F).pp .deps/$(*F).P; \
+ 	tr ' ' '\012' < .deps/$(*F).pp \
+ 	  | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ 	    >> .deps/$(*F).P; \
+ 	rm .deps/$(*F).pp
+ 
+ %.lo: %.c
+ 	@echo '$(LTCOMPILE) -c $<'; \
+ 	$(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+ 	@-sed -e 's/^\([^:]*\)\.o[ 	]*:/\1.lo \1.o :/' \
+ 	  < .deps/$(*F).pp > .deps/$(*F).P; \
+ 	tr ' ' '\012' < .deps/$(*F).pp \
+ 	  | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+ 	    >> .deps/$(*F).P; \
+ 	rm -f .deps/$(*F).pp
  info-am:
  info: info-am
  dvi-am:
***************
*** 361,383 ****
  
  maintainer-clean-generic:
  mostlyclean-am:  mostlyclean-binPROGRAMS mostlyclean-compile \
! 		mostlyclean-tags mostlyclean-generic
  
  mostlyclean: mostlyclean-am
  
! clean-am:  clean-binPROGRAMS clean-compile clean-tags clean-generic \
! 		mostlyclean-am
  
  clean: clean-am
  
  distclean-am:  distclean-binPROGRAMS distclean-compile distclean-tags \
! 		distclean-generic clean-am
  
  distclean: distclean-am
  
  maintainer-clean-am:  maintainer-clean-binPROGRAMS \
  		maintainer-clean-compile maintainer-clean-tags \
! 		maintainer-clean-generic distclean-am
  	@echo "This command is intended for maintainers to use;"
  	@echo "it deletes files that may require special tools to rebuild."
  
--- 355,378 ----
  
  maintainer-clean-generic:
  mostlyclean-am:  mostlyclean-binPROGRAMS mostlyclean-compile \
! 		mostlyclean-tags mostlyclean-depend mostlyclean-generic
  
  mostlyclean: mostlyclean-am
  
! clean-am:  clean-binPROGRAMS clean-compile clean-tags clean-depend \
! 		clean-generic mostlyclean-am
  
  clean: clean-am
  
  distclean-am:  distclean-binPROGRAMS distclean-compile distclean-tags \
! 		distclean-depend distclean-generic clean-am
  
  distclean: distclean-am
  
  maintainer-clean-am:  maintainer-clean-binPROGRAMS \
  		maintainer-clean-compile maintainer-clean-tags \
! 		maintainer-clean-depend maintainer-clean-generic \
! 		distclean-am
  	@echo "This command is intended for maintainers to use;"
  	@echo "it deletes files that may require special tools to rebuild."
  
***************
*** 388,395 ****
  mostlyclean-compile distclean-compile clean-compile \
  maintainer-clean-compile install-man1 uninstall-man1 install-man \
  uninstall-man tags mostlyclean-tags distclean-tags clean-tags \
! maintainer-clean-tags distdir info-am info dvi-am dvi check check-am \
! installcheck-am installcheck install-exec-am install-exec \
  install-data-am install-data install-am install uninstall-am uninstall \
  all-redirect all-am all installdirs mostlyclean-generic \
  distclean-generic clean-generic maintainer-clean-generic clean \
--- 383,391 ----
  mostlyclean-compile distclean-compile clean-compile \
  maintainer-clean-compile install-man1 uninstall-man1 install-man \
  uninstall-man tags mostlyclean-tags distclean-tags clean-tags \
! maintainer-clean-tags distdir mostlyclean-depend distclean-depend \
! clean-depend maintainer-clean-depend info-am info dvi-am dvi check \
! check-am installcheck-am installcheck install-exec-am install-exec \
  install-data-am install-data install-am install uninstall-am uninstall \
  all-redirect all-am all installdirs mostlyclean-generic \
  distclean-generic clean-generic maintainer-clean-generic clean \
diff -cN fvwm-base/add_window.c fvwm/add_window.c
*** fvwm-base/add_window.c	Tue Feb 16 17:11:42 1999
--- fvwm/add_window.c	Tue Feb 23 21:11:05 1999
***************
*** 106,111 ****
--- 106,115 ----
    XrmValue rm_value;
    XTextProperty text_prop;
    extern Boolean PPosOverride;
+ #ifdef SESSION
+   int do_shade, do_maximize;
+   int x_max, y_max, w_max, h_max;
+ #endif
  
    NeedToResizeToo = False;
    /* allocate space for the fvwm window */
***************
*** 117,122 ****
--- 121,129 ----
    tmp_win->flags = 0;
    tmp_win->tmpflags.ViewportMoved = 0;
    tmp_win->tmpflags.IconifiedByParent = 0;
+ #ifdef SESSION
+   tmp_win->tmpflags.NameChanged = 0;
+ #endif
    tmp_win->w = w;
  
    tmp_win->cmap_windows = (Window *)NULL;
***************
*** 400,405 ****
--- 407,420 ----
    tmp_win->stack_prev = &Scr.FvwmRoot;
    Scr.FvwmRoot.stack_next = tmp_win;
  
+ #ifdef SESSION
+   /* 
+       MatchWinToSM changes tmp_win->attr and tmp_win->stack_{prev,next}.
+       Thus it is important have this call *after* PlaceWindow and the
+       stacking order initialization.
+   */
+   MatchWinToSM(tmp_win, &x_max, &y_max, &w_max, &h_max, &do_shade, &do_maximize);
+ #endif
  
    /* create windows */
    tmp_win->frame_x = tmp_win->attr.x + tmp_win->old_bw - tmp_win->bw;
***************
*** 411,416 ****
--- 426,432 ----
    ConstrainSize(tmp_win, &tmp_win->frame_width, &tmp_win->frame_height, False,
  		0, 0);
  
+   
    valuemask = CWBorderPixel | CWCursor | CWEventMask;
    if(Scr.d_depth < 2)
      {
***************
*** 665,672 ****
--- 681,702 ----
    tmp_win->frame_width = 0;
    height = tmp_win->frame_height;
    tmp_win->frame_height = 0;
+ 
    SetupFrame (tmp_win, tmp_win->frame_x, tmp_win->frame_y,width,height, True);
  
+ #ifdef SESSION
+   if (do_shade) { 
+     WindowShade(&Event, tmp_win->w, tmp_win, C_WINDOW, "", 0);
+   }
+ 
+   if (do_maximize) { 
+     /* This is essentially Maximize, only we want the given dimensions */
+     tmp_win->flags |= MAXIMIZED;
+     ConstrainSize (tmp_win, &w_max, &h_max, False, 0, 0);
+     SetupFrame(tmp_win, x_max, y_max, w_max, h_max, TRUE);
+     SetBorder(tmp_win, Scr.Hilite == tmp_win, True, True, None);
+   }
+ #endif
    /* wait until the window is iconified and the icon window is mapped
     * before creating the icon window
     */
***************
*** 695,701 ****
--- 725,747 ----
  	  XSaveContext(dpy,tmp_win->corners[i],FvwmContext, (caddr_t) tmp_win);
  	}
      }
+ #ifndef SESSION
    RaiseWindow(tmp_win);
+ #else
+   { 
+     XWindowChanges xwc;
+     unsigned long vm;
+     if (tmp_win->stack_next == &Scr.FvwmRoot) {
+       xwc.stack_mode = Below;
+       vm = CWStackMode;
+     } else {
+       xwc.sibling = tmp_win->stack_next->frame;
+       xwc.stack_mode = Above;
+       vm = CWSibling|CWStackMode;
+     }
+     XConfigureWindow(dpy, tmp_win->frame, vm, &xwc);
+   }
+ #endif
    KeepOnTop();
    MyXUngrabServer(dpy);
  
diff -cN fvwm-base/events.c fvwm/events.c
*** fvwm-base/events.c	Tue Feb 16 17:11:43 1999
--- fvwm/events.c	Tue Feb 23 21:11:05 1999
***************
*** 476,481 ****
--- 476,484 ----
        free_window_names (Tmp_win, True, False);
  
        Tmp_win->name = (char *)text_prop.value;
+ #ifdef SESSION
+       Tmp_win->tmpflags.NameChanged = 1;
+ #endif
        if (Tmp_win->name == NULL)
          Tmp_win->name = NoName;
        BroadcastName(M_WINDOW_NAME,Tmp_win->w,Tmp_win->frame,
***************
*** 831,836 ****
--- 834,845 ----
      }
    if(!PPosOverride)
      KeepOnTop();
+ 
+ #ifdef SESSION 
+   /* just to be on the safe side, we make sure that STARTICONIC
+      can only influence the initial transition from withdrawn state */
+   Tmp_win->flags &= ~STARTICONIC; 
+ #endif
  }

***************
*** 1530,1535 ****
--- 1539,1547 ----
  int My_XNextEvent(Display *dpy, XEvent *event)
  {
    extern int fd_width, x_fd;
+ #ifdef SESSION 
+   extern int sm_fd;
+ #endif
    fd_set in_fdset, out_fdset;
    Window targetWindow;
    int i;
***************
*** 1556,1561 ****
--- 1568,1576 ----
  
    FD_ZERO(&in_fdset);
    FD_SET(x_fd,&in_fdset);
+ #ifdef SESSION
+   if (sm_fd >= 0) FD_SET(sm_fd, &in_fdset);
+ #endif
    FD_ZERO(&out_fdset);
    for(i=0; i<npipes; i++)
      {
***************
*** 1606,1611 ****
--- 1621,1631 ----
  	    }
  	}
      } /* for */
+ 
+ #ifdef SESSION
+   if ((sm_fd >= 0) && (FD_ISSET(sm_fd, &in_fdset))) ProcessICEMSGS();
+ #endif
+ 
    }
    DBUG("My_XNextEvent","leaving My_XNextEvent");
    return 0;
diff -cN fvwm-base/fvwm.c fvwm/fvwm.c
*** fvwm-base/fvwm.c	Wed Jan 27 20:11:49 1999
--- fvwm/fvwm.c	Tue Feb 23 21:11:06 1999
***************
*** 150,155 ****
--- 150,161 ----
    Bool option_error = FALSE;
    int x, y;
  
+ #ifdef SESSION
+   char *client_id = NULL;
+   char *restore_filename = NULL;
+ #endif
+ 
+ 
    g_argv = argv;
    g_argc = argc;
  
***************
*** 165,170 ****
--- 171,190 ----
      {
        debugging = True;
      }
+ #ifdef SESSION
+     else if (strncasecmp(argv[i], "-clientId", 9) == 0)
+       {
+ 	if (++i >= argc)
+ 	  usage();
+ 	client_id = argv[i];
+       }
+     else if (strncasecmp(argv[i], "-restore", 8) == 0)
+       {
+ 	if (++i >= argc)
+ 	  usage();
+ 	restore_filename = argv[i];
+       }
+ #endif
      else if (strncasecmp(argv[i],"-s",2)==0)
      {
        single = True;
***************
*** 410,415 ****
--- 430,444 ----
  
    XSetErrorHandler(FvwmErrorHandler);
  
+ #ifdef SESSION
+   /* 
+      This should be done early enough to have the window states loaded
+      before the first call to AddWindow.  
+    */
+   if (restore_filename)
+     LoadWindowStates(restore_filename); 
+ #endif
+ 
    BlackoutScreen(); /* if they want to hide the capture/startup */
  
    CreateCursors();
***************
*** 438,443 ****
--- 467,482 ----
    {
      ExecuteFunction(default_config_command, NULL,&Event,C_ROOT,-1);
    }
+ 
+ #ifdef SESSION
+   /*
+      This should be done after the initialization is finished, since
+      it directly changes the global state. 
+    */
+   if (restore_filename)
+     LoadGlobalState(restore_filename);
+ #endif
+ 
    DBUG("main","Done running config_commands");
  
    if(Scr.d_depth<2)
***************
*** 516,521 ****
--- 555,565 ----
    if (Scr.ClickTime < 0)
      Scr.ClickTime = -Scr.ClickTime;
    fFvwmInStartup = False;
+ 
+ #ifdef SESSION
+   SessionInit(client_id);
+ #endif
+ 
    DBUG("main","Entering HandleEvents loop...");
  
    HandleEvents();
***************
*** 805,810 ****
--- 849,860 ----
  Atom _XA_OL_DECOR_HEADER;
  Atom _XA_OL_DECOR_ICON_NAME;
  
+ #ifdef SESSION
+ Atom _XA_WM_WINDOW_ROLE;
+ Atom _XA_WM_CLIENT_LEADER;
+ Atom _XA_SM_CLIENT_ID;
+ #endif
+ 
  void InternUsefulAtoms (void)
  {
    /*
***************
*** 833,838 ****
--- 883,894 ----
    _XA_OL_DECOR_RESIZE=XInternAtom(dpy,"_OL_DECOR_RESIZE",False);
    _XA_OL_DECOR_HEADER=XInternAtom(dpy,"_OL_DECOR_HEADER",False);
    _XA_OL_DECOR_ICON_NAME=XInternAtom(dpy,"_OL_DECOR_ICON_NAME",False);
+ 
+ #ifdef SESSION
+   _XA_WM_WINDOW_ROLE=XInternAtom(dpy, "WM_WINDOW_ROLE",False);
+   _XA_WM_CLIENT_LEADER=XInternAtom(dpy, "WM_CLIENT_LEADER",False);
+   _XA_SM_CLIENT_ID=XInternAtom(dpy, "SM_CLIENT_ID",False);
+ #endif
    return;
  }
  
diff -cN fvwm-base/fvwm.h fvwm/fvwm.h
*** fvwm-base/fvwm.h	Tue Jan 12 22:07:42 1999
--- fvwm/fvwm.h	Tue Feb 23 21:11:06 1999
***************
*** 249,254 ****
--- 249,259 ----
        unsigned ViewportMoved : 1; /* To prevent double move in MoveViewport. */
        unsigned IconifiedByParent : 1; /* To prevent iconified transients in a
  				       * parent icon from counting for Next */
+ #ifdef SESSION
+       unsigned NameChanged : 1; /* Set if the client changes its WM_NAME. 
+ 				   The source of twm contains an explanation
+ 				   why we need this information. */
+ #endif
      } tmpflags;
  #endif /* GSFR */
  
***************
*** 275,280 ****
--- 280,286 ----
      Pixel BackPixel;
      unsigned long buttons;
      icon_boxes *IconBoxes;              /* zero or more iconboxes */
+ 
  } FvwmWindow;
  
  /* Window mask for Circulate and Direction functions */
***************
*** 405,410 ****
--- 411,421 ----
  extern Atom _XA_OL_DECOR_RESIZE;
  extern Atom _XA_OL_DECOR_HEADER;
  extern Atom _XA_OL_DECOR_ICON_NAME;
+ #ifdef SESSION
+ extern Atom _XA_WM_WINDOW_ROLE;
+ extern Atom _XA_WM_CLIENT_LEADER;
+ extern Atom _XA_SM_CLIENT_ID;
+ #endif
  
  /* include this down here because FvwmWindows must be defined when including
   * this header file. */
diff -cN fvwm-base/icons.c fvwm/icons.c
*** fvwm-base/icons.c	Thu Jan 14 02:42:52 1999
--- fvwm/icons.c	Tue Feb 23 21:11:06 1999
***************
*** 178,183 ****
--- 178,192 ----
        XDefineCursor(dpy, tmp_win->icon_w, Scr.FvwmCursors[DEFAULT]);
        GrabIconButtons(tmp_win,tmp_win->icon_w);
        GrabIconKeys(tmp_win,tmp_win->icon_w);
+ 
+ #ifdef SESSION
+       {
+         XWindowChanges xwc;
+         xwc.sibling = tmp_win->frame;
+         xwc.stack_mode = Above;   
+         XConfigureWindow(dpy, tmp_win->icon_w, CWSibling|CWStackMode, &xwc);
+       }
+ #endif
      }
    if(tmp_win->icon_pixmap_w != None)
      {
***************
*** 185,191 ****
        XDefineCursor(dpy, tmp_win->icon_pixmap_w, Scr.FvwmCursors[DEFAULT]);
        GrabIconButtons(tmp_win,tmp_win->icon_pixmap_w);
        GrabIconKeys(tmp_win,tmp_win->icon_pixmap_w);
!     }
    return;
  }
  
--- 194,209 ----
        XDefineCursor(dpy, tmp_win->icon_pixmap_w, Scr.FvwmCursors[DEFAULT]);
        GrabIconButtons(tmp_win,tmp_win->icon_pixmap_w);
        GrabIconKeys(tmp_win,tmp_win->icon_pixmap_w);
! 
! #ifdef SESSION
!       {
!         XWindowChanges xwc;
!         xwc.sibling = tmp_win->frame;
!         xwc.stack_mode = Above;   
!         XConfigureWindow(dpy, tmp_win->icon_pixmap_w, CWSibling|CWStackMode, &xwc);
!       }
! #endif
!   }
    return;
  }
  
***************
*** 958,964 ****
--- 976,987 ----
      tmp_win->icon_w_width = tmp_win->icon_p_width;
    }
  
+ #ifdef SESSION
+   if (!((tmp_win->flags & STARTICONIC) &&
+      (tmp_win->flags & ICON_MOVED)))
+ #endif
    AutoPlace(tmp_win);
+ 
    tmp_win->flags |= ICONIFIED;
    tmp_win->flags &= ~ICON_UNMAPPED;
    BroadcastPacket(M_ICONIFY, 11,
***************
*** 974,979 ****
--- 997,1006 ----
                    tmp_win->frame_height);
    BroadcastConfig(M_CONFIGURE_WINDOW,tmp_win);
  
+ #ifdef SESSION
+   if (!((tmp_win->flags & STARTICONIC) &&
+      (tmp_win->flags & ICON_MOVED)))
+ #endif
    LowerWindow(tmp_win);
    if(tmp_win->Desk == Scr.CurrentDesk)
      {
diff -cN fvwm-base/misc.h fvwm/misc.h
*** fvwm-base/misc.h	Tue Feb 16 17:11:44 1999
--- fvwm/misc.h	Tue Feb 23 21:11:06 1999
***************
*** 484,488 ****
--- 484,499 ----
  #define ERR  2
  void fvwm_msg(int type,char *id,char *msg,...);
  
+ #ifdef SESSION
+ /* session management adapted from enlightenment */
+ void SessionInit(char *client_id);
+ void LoadWindowStates(char *filename);
+ void LoadGlobalState(char *filename);
+ void ProcessICEMSGS(void);
+ void MatchWinToSM(FvwmWindow *t, int *, int *, int *, int *, int *, int *);
+ #endif
+ 
  #endif /* MISC_H */
+ 
+ 
  
diff -cN fvwm-base/session.c fvwm/session.c
*** fvwm-base/session.c	Thu Jan  1 01:00:00 1970
--- fvwm/session.c	Tue Feb 23 23:25:36 1999
***************
*** 0 ****
--- 1,899 ----
+ /* 
+  This file is strongly based on the corresponding files from
+  twm and enlightenment.
+  */
+ #include "config.h"
+ 
+ #ifdef SESSION
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdlib.h>
+ #include <pwd.h>
+ #include <sys/types.h>
+ #include <signal.h>
+ #include "fvwm.h"
+ #include <X11/Xatom.h>
+ #include "screen.h"
+ #include "misc.h"
+  
+ #include <X11/SM/SMlib.h>
+ 
+ extern int master_pid;
+ 
+ 
+ typedef struct _match
+   {
+     char               *client_id;
+     char               *res_name;
+     char               *res_class;
+     char               *window_role;
+     char               *wm_name;
+     int                wm_command_count;
+     char               **wm_command;
+     int                 x, y, w, h, icon_x, icon_y;
+     int                 x_max, y_max, w_max, h_max; 
+     int                 desktop; 
+     int                 used;
+     int                 shaded, name_changed;
+     unsigned long       flags;
+ }
+ Match;
+ 
+ static char        *sm_client_id = NULL;
+ SmcConn             sm_conn = NULL;
+ int                 sm_fd = -1;
+ static int          num_match = 0;
+ Match              *matches = NULL;
+ static Bool sent_save_done = 0;
+ 
+ static
+ char *duplicate(char *s)
+ {
+   int l;
+   char *r;
+ 
+   if (!s) return NULL;
+   l = strlen(s);
+   r = (char *) malloc (sizeof(char)*(l+1));
+   strncpy(r, s, l+1);
+   return r;
+ }
+ 
+ /*
+    It is a bit ugly to have a separate file format for
+    config files and session save files. The proper way
+    to do this may be to extend the config file format
+    to allow the specification of everything we need 
+    to save here. Then the option "-restore xyz" could
+    be replaced by "-f xyz".
+  */
+ static int
+ SaveGlobalState(FILE *f)
+ {
+   int                 i, num, x, y;
+ 
+   fprintf(f, "[GLOBAL]\n");
+   fprintf(f, "  [DESKTOP] %i\n", Scr.CurrentDesk);
+   fprintf(f, "  [VIEWPORT] %i %i %i %i\n", 
+           Scr.Vx, Scr.Vy, Scr.VxMax, Scr.VyMax);
+   fprintf(f, "  [SCROLL] %i %i %i %i %i %i\n", 
+ 	  Scr.EdgeScrollX, Scr.EdgeScrollY, Scr.ScrollResistance, 
+ 	  Scr.MoveResistance,
+ 	  !!(Scr.flags & EdgeWrapX), !!(Scr.flags & EdgeWrapY));
+   fprintf(f, "  [SNAP] %i %i %i %i\n", 
+ 	  Scr.SnapAttraction, Scr.SnapMode, Scr.SnapGridX, Scr.SnapGridY);
+   fprintf(f, "  [MISC] %i %i %i %i %i %i %i %i\n", 
+ 	  Scr.ClickTime, Scr.ColormapFocus,
+ 	  Scr.ColorLimit, Scr.SmartPlacementIsClever, 
+ 	  Scr.ClickToFocusPassesClick, Scr.ClickToFocusRaises,
+ 	  Scr.MouseFocusClickRaises, Scr.StipledTitles);
+   fprintf(f, "  [STYLE] %i %i %i %i %i %i\n",
+ 	  Scr.go.ModifyUSP, Scr.go.CaptureHonorsStartsOnPage,
+ 	  Scr.go.RecaptureHonorsStartsOnPage, 
+ 	  Scr.go.ActivePlacementHonorsStartsOnPage,
+           Scr.gs.EmulateMWM, Scr.gs.EmulateWIN);
+   return 1;
+ }
+ 
+ void 
+ LoadGlobalState(char *filename)
+ {
+    FILE               *f;
+    char                s[4096], s1[4096];
+    int i1, i2, i3, i4, i5, i6, i7, i8;
+ 
+    f = fopen(filename, "r");
+    if (f)
+      {
+        while (fgets(s, sizeof(s), f))
+ 	 {
+            i1 = 0; i2 = 0; i3 = 0; i4 = 0; i5 = 0; i6 = 0;
+            i7 = 0; i8 = 0;
+ 	   sscanf(s, "%4000s", s1);
+ 	   if (!strcmp(s1, "[DESKTOP]")) 
+              {
+ 	       sscanf(s, "%*s %i", &i1);
+                changeDesks(i1);
+              }
+            else if (!strcmp(s1, "[VIEWPORT]"))
+              {
+                sscanf(s, "%*s %i %i %i %i", &i1, &i2, &i3, &i4);
+                Scr.VxMax = i3;
+                Scr.VyMax = i4;
+                MoveViewport(i1, i2, True);
+              }
+            else if (!strcmp(s1, "[SCROLL]"))
+              {
+                sscanf(s, "%*s %i %i %i %i %i %i", &i1, &i2, &i3, &i4, &i5, &i6);
+                Scr.EdgeScrollX = i1; 
+                Scr.EdgeScrollY = i2;
+                Scr.ScrollResistance = i3;
+                Scr.MoveResistance = i4;
+                if (i5) Scr.flags |= EdgeWrapX;
+                else Scr.flags &= ~EdgeWrapX;
+                if (i6) Scr.flags |= EdgeWrapY;
+                else Scr.flags &= ~EdgeWrapY;
+              }
+            else if (!strcmp(s1, "[SNAP]"))
+              {
+                sscanf(s, "%*s %i %i %i %i", &i1, &i2, &i3, &i4);
+                Scr.SnapAttraction = i1;
+                Scr.SnapMode = i2;
+                Scr.SnapGridX = i3;
+                Scr.SnapGridY = i4;
+              }
+            else if (!strcmp(s1, "[MISC]"))
+              {
+                sscanf(s, "%*s %i %i %i %i %i %i %i %i", &i1, &i2, &i3, &i4,
+                       &i5, &i6, &i7, &i8);
+                Scr.ClickTime = i1;
+                Scr.ColormapFocus = i2;
+                Scr.ColorLimit = i3;
+                Scr.SmartPlacementIsClever = i4;
+                Scr.ClickToFocusPassesClick = i5;
+                Scr.ClickToFocusRaises = i6;
+                Scr.MouseFocusClickRaises = i7;
+                Scr.StipledTitles = i8;
+              }
+            else if (!strcmp(s1, "[STYLE]"))
+              {
+                sscanf(s, "%*s %i %i %i %i", &i1, &i2, &i3, &i4, &i5, &i6);
+                Scr.go.ModifyUSP = i1;
+                Scr.go.CaptureHonorsStartsOnPage = i2;
+                Scr.go.RecaptureHonorsStartsOnPage = i3;
+                Scr.go.ActivePlacementHonorsStartsOnPage = i4;
+                Scr.gs.EmulateMWM = i5; 
+                Scr.gs.EmulateWIN = i6; 
+              }
+          }
+       fclose(f);
+    }
+ }
+ 
+ char *
+ GetWindowRole (window)
+      
+      Window window;
+ 
+ {
+   XTextProperty tp;
+ 
+     if (XGetTextProperty (dpy, window, &tp, _XA_WM_WINDOW_ROLE))
+     {
+ 	if (tp.encoding == XA_STRING && tp.format == 8 && tp.nitems != 0)
+ 	    return ((char *) tp.value);
+     }
+ 
+     return NULL;
+ }
+ 
+ char *
+ GetClientID (window)
+ 
+      Window window;
+ 
+ {
+   char *client_id = NULL;
+   Window client_leader;
+     XTextProperty tp;
+     Atom actual_type;
+     int actual_format;
+     unsigned long nitems;
+     unsigned long nbytes;
+     unsigned long bytes_after;
+     unsigned char *prop = NULL;
+ 
+     if (XGetWindowProperty (dpy, window, _XA_WM_CLIENT_LEADER,
+ 	0L, 1L, False, AnyPropertyType,	&actual_type, &actual_format,
+ 	&nitems, &bytes_after, &prop) == Success)
+     {
+ 	if (actual_type == XA_WINDOW && actual_format == 32 &&
+ 	    nitems == 1 && bytes_after == 0)
+ 	{
+ 	    client_leader = *((Window *) prop);
+ 
+ 	    if (XGetTextProperty (dpy, client_leader, &tp, _XA_SM_CLIENT_ID))
+ 	    {
+ 		if (tp.encoding == XA_STRING &&
+ 		    tp.format == 8 && tp.nitems != 0)
+ 		    client_id = (char *) tp.value;
+ 	    }
+ 	}
+ 
+ 	if (prop)
+ 	    XFree (prop);
+     }
+     
+     return client_id;
+ }
+ 
+ static int
+ SaveWindowStates(FILE *f)
+ {
+   char *client_id;
+   char *window_role;
+   char **wm_command;
+   int wm_command_count;
+   FvwmWindow              *ewin;
+   int                 i, num, x, y, xmax, ymax;
+ 
+   for (ewin=Scr.FvwmRoot.stack_next; ewin!=&Scr.FvwmRoot; ewin=ewin->stack_next) 
+     {
+       fprintf(f, "[CLIENT]\n");
+       
+       client_id = GetClientID(ewin->w);
+       if (client_id) 
+ 	{
+ 	  fprintf(f, "  [CLIENT_ID] %s\n", client_id);
+ 	  XFree(client_id);
+ 	}
+       
+       window_role = GetWindowRole(ewin->w);
+       if (window_role) 
+ 	{
+ 	  fprintf(f, "  [WINDOW_ROLE] %s\n", window_role);
+ 	  XFree(window_role);
+ 	}
+       else 
+ 	{
+ 	  if (ewin->class.res_class)
+ 	    fprintf(f, "  [RES_NAME] %s\n", ewin->class.res_name);
+ 	  if (ewin->class.res_name)
+ 	    fprintf(f, "  [RES_CLASS] %s\n", ewin->class.res_class);
+ 	  if (ewin->name)
+ 	    fprintf(f, "  [WM_NAME] %s\n", ewin->name);
+ 	  
+ 	  wm_command = NULL;
+ 	  wm_command_count = 0;
+ 	  XGetCommand (dpy, ewin->w, &wm_command, &wm_command_count);
+ 	  
+ 	  if (wm_command && (wm_command_count > 0))
+ 	    {
+ 	      fprintf(f, "  [WM_COMMAND] %i", wm_command_count);
+ 		for (i = 0; i < wm_command_count; i++)
+ 		  fprintf(f, " %s", wm_command[i]);
+ 	      fprintf(f, "\n");
+ 	      XFreeStringList (wm_command);
+ 	    }
+ 	} /* !window_role */
+       
+       
+       /* 
+ 	 We want to save absolute coordinates for the desk; 
+ 	 I hope the calculation makes sense... everything
+ 	 would be much easier, if the frame/orig positions
+ 	 would be absolute.
+       */
+       i = 0; 
+       xmax = Scr.Vx + ewin->frame_x;
+       while (xmax < 0) {
+ 	xmax += Scr.MyDisplayWidth;
+ 	i--;
+       }
+       i += xmax / Scr.MyDisplayWidth;
+       x = i * Scr.MyDisplayWidth
+ 	+ (ewin->orig_x % Scr.MyDisplayWidth) 
+ 	- ewin->old_bw + ewin->bw;
+       if (x < 0) x += Scr.MyDisplayWidth;
+       
+       i = 0; 
+       ymax = Scr.Vy + ewin->frame_y;
+       while (ymax < 0) {
+ 	ymax += Scr.MyDisplayHeight;
+ 	i--;
+       }
+       i += ymax / Scr.MyDisplayHeight;
+       y = i * Scr.MyDisplayHeight
+ 	+ (ewin->orig_y % Scr.MyDisplayHeight) 
+ 	- ewin->old_bw + ewin->bw;
+       if (y < 0) y += Scr.MyDisplayHeight;
+       
+       fprintf(f, "  [GEOMETRY] %i %i %i %i %i %i %i %i %i %i\n",
+ 	      x, y,
+ 	      ewin->orig_wd - 2*ewin->boundary_width , 
+ 	      ewin->orig_ht - 2*ewin->boundary_width 
+ 	      - ewin->title_height, 
+ 	      xmax, ymax,
+ 	      ewin->frame_width - 2*ewin->boundary_width , 
+ 	      ewin->frame_height - 2*ewin->boundary_width 
+ 	      - ewin->title_height, 
+ 	      Scr.Vx + ewin->icon_x_loc,
+ 	      Scr.Vy + ewin->icon_y_loc);
+       fprintf(f, "  [DESK] %i\n", ewin->Desk);
+       fprintf(f, "  [FLAGS] %lu %i %i\n", ewin->flags, 
+ 	      !!(ewin->buttons & WSHADE), ewin->tmpflags.NameChanged); 
+     }
+   return 1;
+ }
+ 
+ void
+ LoadWindowStates(char *filename)
+ {
+   FILE               *f;
+   char                s[4096], s1[4096];
+   int i, pos;
+ 
+    f = fopen(filename, "r");
+    if (f)
+      {
+        while (fgets(s, sizeof(s), f))
+ 	 {
+ 	   sscanf(s, "%4000s", s1);
+ 	   if (!strcmp(s1, "[CLIENT]"))
+ 	     {
+ 	       num_match++;
+ 	       matches = realloc(matches, sizeof(Match) * num_match);
+ 	       matches[num_match - 1].client_id = NULL;
+ 	       matches[num_match - 1].res_name = NULL;
+ 	       matches[num_match - 1].res_class = NULL;
+ 	       matches[num_match - 1].window_role = NULL;
+ 	       matches[num_match - 1].wm_name = NULL;
+ 	       matches[num_match - 1].wm_command_count = 0;
+ 	       matches[num_match - 1].wm_command = NULL;
+                matches[num_match - 1].x = 0;
+                matches[num_match - 1].y = 0;
+                matches[num_match - 1].w = 100;
+                matches[num_match - 1].h = 100;
+                matches[num_match - 1].x_max = 0;
+                matches[num_match - 1].y_max = 0;
+                matches[num_match - 1].w_max = 100;
+                matches[num_match - 1].h_max = 100;
+                matches[num_match - 1].icon_x = 0;
+                matches[num_match - 1].icon_y = 0;
+                matches[num_match - 1].desktop = 0;
+                matches[num_match - 1].shaded = 0;
+                matches[num_match - 1].name_changed = 0;
+                matches[num_match - 1].flags = 0;
+                matches[num_match - 1].used = 0;
+              } 
+            else if (!strcmp(s1, "[GEOMETRY]"))
+              {
+ 	       sscanf(s, "%*s %i %i %i %i %i %i %i %i %i %i", 
+ 		      &(matches[num_match - 1].x),
+ 		      &(matches[num_match - 1].y),
+ 		      &(matches[num_match - 1].w),
+ 		      &(matches[num_match - 1].h),
+ 		      &(matches[num_match - 1].x_max),
+ 		      &(matches[num_match - 1].y_max),
+ 		      &(matches[num_match - 1].w_max),
+ 		      &(matches[num_match - 1].h_max),
+ 		      &(matches[num_match - 1].icon_x),
+ 		      &(matches[num_match - 1].icon_y));
+              }
+            else if (!strcmp(s1, "[DESK]"))
+              { 
+                sscanf(s, "%*s %i",
+ 		      &(matches[num_match - 1].desktop));
+              }
+            else if (!strcmp(s1, "[FLAGS]"))
+              {
+                sscanf(s, "%*s %lu %i %i",
+ 		      &(matches[num_match - 1].flags),
+ 		      &(matches[num_match - 1].shaded),
+ 		      &(matches[num_match - 1].name_changed)
+ 		      );
+ 	     }
+ 	   else if (!strcmp(s1, "[CLIENT_ID]"))
+ 	     {
+ 	       sscanf(s, "%*s %4000s", s1);
+ 	       matches[num_match - 1].client_id = duplicate(s1);
+ 	     }
+ 	   else if (!strcmp(s1, "[WINDOW_ROLE]"))
+ 	     {
+ 	       sscanf(s, "%*s %4000s", s1);
+ 	       matches[num_match - 1].window_role = duplicate(s1);
+ 	     }
+ 	   else if (!strcmp(s1, "[RES_NAME]"))
+ 	     {
+ 	       sscanf(s, "%*s %4000s", s1);
+ 	       matches[num_match - 1].res_name = duplicate(s1);
+ 	     }
+ 	   else if (!strcmp(s1, "[RES_CLASS]"))
+ 	     {
+ 	       sscanf(s, "%*s %4000s", s1);
+ 	       matches[num_match - 1].res_class = duplicate(s1);
+ 	     }
+ 	   else if (!strcmp(s1, "[WM_NAME]"))
+ 	     {
+ 	       sscanf(s, "%*s %4000s", s1);
+ 	       matches[num_match - 1].wm_name = duplicate(s1);
+ 	     }
+ 	   else if (!strcmp(s1, "[WM_COMMAND]"))
+ 	     {
+ 	       sscanf(s, "%*s %i", &matches[num_match - 1].wm_command_count);
+ 	       matches[num_match - 1].wm_command = 
+ 		 (char **) malloc (matches[num_match - 1].wm_command_count *
+ 				   sizeof (char *));
+ 	       pos = 0;
+ 	       for (i = 0; i < matches[num_match - 1].wm_command_count; i++) 
+ 		 {
+ 		   sscanf (s+pos, "%s%n", s1, &pos);
+ 		   matches[num_match - 1].wm_command[i] = duplicate (s1);
+ 		 }
+ 	     }
+ 	   
+ 	 }
+        fclose(f);
+      }
+ }
+ 
+ /* This complicated logic is from twm, where it is explained */
+ 
+ #define xstreq(a,b) (!a && !b) || (a && b && (strcmp(a,b)==0))
+ 
+ Bool matchWin(FvwmWindow *w, Match *m)
+ {
+   char *client_id = NULL;
+   char *window_role = NULL;
+   char **wm_command = NULL;
+   int wm_command_count = 0, i;
+   int found;
+ 
+   found = 0;
+   client_id = GetClientID(w->w);
+ 
+   if (xstreq(client_id, m->client_id))
+     {
+ 
+       /* client_id's match */
+ 
+       window_role = GetWindowRole(w->w);
+       
+       if (window_role || m->window_role)
+         { 
+           /* We have or had a window role, base decision on it */
+ 
+           found = xstreq(window_role, m->window_role);
+         } 
+       else 
+ 	{
+           /* Compare res_class, res_name and WM_NAME, unless the 
+              user has changed WM_NAME */
+             
+ 	  if (xstreq(w->class.res_name, m->res_name) &&
+ 	      xstreq(w->class.res_class, m->res_class) &&
+ 	      (m->name_changed || 
+                w->tmpflags.NameChanged || 
+                xstreq(w->name, m->wm_name)))
+             {
+               if (client_id)
+                 {
+                   /* If we have a client_id, we don't compare
+                      WM_COMMAND, since it will be different. */
+                   found = 1;
+                 }
+               else
+ 	        {
+                   /* for non-SM-aware clients we also compare WM_COMMAND */
+ 	          XGetCommand (dpy, w->w, &wm_command, &wm_command_count);
+ 	      
+ 	          if (wm_command_count == m->wm_command_count) 
+ 		    {
+ 		      for (i = 0; i < wm_command_count; i++)
+ 		        {
+ 		          if (strcmp (wm_command[i], m->wm_command[i]) != 0)
+ 			    break;
+ 		        }
+             
+                       if (i == wm_command_count)
+                         {
+                           found = 1;
+                         }    
+ 		    } /* if (wm_command_count ==... */
+ 		} /* else no client id */
+ 	    } /* if res_class, res_name and wm_name agree */
+ 	} /* else no window roles */
+     } /* if client_id's agree */
+   
+   if (client_id)
+     XFree (client_id);
+ 
+   if (window_role)
+     XFree (window_role);
+ 
+   if (wm_command)
+     XFreeStringList (wm_command);
+ 
+   return found;
+ }
+ 
+ /*
+    This routine (potentially) changes the flags STARTICONIC,
+    MAXIMIZED, WSHADE and STICKY and the Desk and
+    attr.x, .y, .width, .height entries. It also changes the
+    stack_before pointer to return information about the
+    desired stacking order. It expects the stacking order
+    to be set up correctly beforehand! 
+  */
+ void
+ MatchWinToSM(FvwmWindow *ewin, 
+              int *x_max, int *y_max, int *w_max, int *h_max,
+              int *do_shade, int *do_max)
+ {
+    int                 i, j;
+    FvwmWindow *t;
+ 
+    *do_shade = 0;
+    *do_max = 0;
+    for (i = 0; i < num_match; i++)
+      {
+        if (!matches[i].used && matchWin(ewin, &matches[i]))
+ 	     {
+                
+ 	       matches[i].used = 1;
+                *do_shade = matches[i].shaded;
+                *do_max = !!(matches[i].flags & MAXIMIZED);
+ 	       if (matches[i].flags & ICONIFIED) {
+                  /* 
+                     ICON_MOVED is necessary to make fvwm use icon_[xy]_loc 
+                     for icon placement
+                  */   
+                  ewin->flags |= STARTICONIC|ICON_MOVED;
+                } else { 
+                  ewin->flags &= ~STARTICONIC;
+                }
+ #define FLAG(x) if(matches[i].flags&x) ewin->flags|=x; else ewin->flags&=~x
+                FLAG(ONTOP);
+                FLAG(WINDOWLISTSKIP);
+                FLAG(SUPPRESSICON);
+                FLAG(NOICON_TITLE);
+                FLAG(Lenience); 
+                FLAG(StickyIcon); 
+                FLAG(CirculateSkipIcon);
+                FLAG(CirculateSkip);
+                FLAG(ClickToFocus);
+                FLAG(SloppyFocus);
+ #undef FLAG
+                ewin->name = matches[i].wm_name;
+                ewin->tmpflags.NameChanged = matches[i].name_changed;
+                /* this doesn't work very well if Vx/Vy is not on
+                   a page boundary */
+                ewin->attr.x = matches[i].x - Scr.Vx;
+                ewin->attr.y = matches[i].y - Scr.Vy;
+                
+                *x_max = matches[i].x_max - Scr.Vx;
+                *y_max = matches[i].y_max - Scr.Vy;
+                *w_max = matches[i].w_max; 
+                *h_max = matches[i].h_max;
+ 
+ 	       if (matches[i].flags & STICKY) {
+                  ewin->flags |= STICKY;
+                  while (ewin->attr.x < 0) ewin->attr.x += Scr.MyDisplayWidth;
+                  ewin->attr.x = ewin->attr.x % Scr.MyDisplayWidth;
+                  while (ewin->attr.y < 0) ewin->attr.y += Scr.MyDisplayHeight;
+                  ewin->attr.y = ewin->attr.y % Scr.MyDisplayHeight;
+ 	       } else {
+                  ewin->flags &= ~STICKY;
+ 		 ewin->Desk = matches[i].desktop;
+                }
+   
+                ewin->attr.width = matches[i].w;
+                ewin->attr.height = matches[i].h;
+  
+                /* this is not enough to fight fvwms attempts to 
+                   put icons on the current page */
+                ewin->icon_x_loc = matches[i].icon_x - Scr.Vx;
+                ewin->icon_y_loc = matches[i].icon_y - Scr.Vy; 
+ 
+                /* Find the window to stack this one below. */
+ 
+                for (j = i-1; j >= 0; j--) {
+ 
+                  /* matches are sorted in stacking order */
+ 
+                  if (matches[j].used) {
+ 
+                    for (t = Scr.FvwmRoot.next; t != NULL; t = t->next) { 
+                      if (matchWin(t, &matches[j])) {
+                        ewin->stack_next->stack_prev = ewin->stack_prev;
+                        ewin->stack_prev->stack_next = ewin->stack_next;
+ 
+                        ewin->stack_prev = t;
+                        ewin->stack_next = t->stack_next;
+                        ewin->stack_prev->stack_next = ewin;
+                        ewin->stack_next->stack_prev = ewin;
+                        return;
+                      }
+                    }
+                  } 
+                }
+ 	       return;
+ 	     }
+ 	 }
+ }
+ 
+ extern char **g_argv;
+ extern int g_argc;
+ 
+ static void
+ callback_save_yourself2(SmcConn smc_conn, SmPointer client_data)
+ {
+   FILE *cfg_file = NULL;
+   char *path = NULL;
+   char *filename = NULL;
+   Bool success = 0;
+   SmProp prop1, prop2, prop3, *props[3];
+   SmPropValue prop1val, prop2val, prop3val;
+   char discardCommand[80];
+   int numVals, i;
+   static int first_time = 1;
+   struct passwd       *pwd;
+   
+   pwd = getpwuid(getuid());
+ 
+   if (first_time) 
+     {
+       char hint = SmRestartIfRunning;
+       char *user_id = pwd->pw_name;
+       
+       prop1.name = SmProgram;
+       prop1.type = SmARRAY8;
+       prop1.num_vals = 1;
+       prop1.vals = &prop1val;
+       prop1val.value = g_argv[0];
+       prop1val.length = strlen (g_argv[0]);
+       
+       prop2.name = SmUserID;
+       prop2.type = SmARRAY8;
+       prop2.num_vals = 1;
+       prop2.vals = &prop2val;
+       prop2val.value = (SmPointer) user_id;
+       prop2val.length = strlen (user_id);
+       
+       prop3.name = SmRestartStyleHint;
+       prop3.type = SmCARD8;
+       prop3.num_vals = 1;
+       prop3.vals = &prop3val;
+       prop3val.value = (SmPointer) &hint;
+       prop3val.length = 1;
+       
+       props[0] = &prop1;
+       props[1] = &prop2;
+       props[2] = &prop3;
+       
+       SmcSetProperties (smc_conn, 3, props);
+       
+       first_time = 0; 
+   }
+ 
+   path = getenv ("SM_SAVE_DIR");
+   if (!path)
+     {
+       path = pwd->pw_dir;
+     }
+ 
+   if ((filename = tempnam (path, ".fvwm")) == NULL)
+     goto bad;
+   
+   if (!(cfg_file = fopen (filename, "w")))
+     goto bad;
+ 
+   success = SaveWindowStates(cfg_file);
+   success = SaveGlobalState(cfg_file);
+ 
+   prop1.name = SmRestartCommand;
+   prop1.type = SmLISTofARRAY8;
+ 
+   prop1.vals = (SmPropValue *) malloc ((g_argc + 7) * sizeof (SmPropValue));
+   
+   if (!prop1.vals)
+     {
+       success = False;
+       goto bad;
+     }
+ 
+   numVals = 0;
+   
+   for (i = 0; i < g_argc; i++)
+     {
+       if (strcmp (g_argv[i], "-clientId") == 0 ||
+ 	  strcmp (g_argv[i], "-restore") == 0 ||
+ 	  strcmp (g_argv[i], "-d") == 0)
+ 	{
+ 	  i++;
+ 	} else if (strcmp (g_argv[i], "-s") != 0) {
+ 	  prop1.vals[numVals].value = (SmPointer) g_argv[i];
+ 	  prop1.vals[numVals++].length = strlen (g_argv[i]);
+ 	}
+     }
+   
+   prop1.vals[numVals].value = (SmPointer) "-d";
+   prop1.vals[numVals++].length = 2;
+   
+   prop1.vals[numVals].value = (SmPointer) XDisplayString (dpy);
+   prop1.vals[numVals++].length = strlen (XDisplayString (dpy));
+   
+   prop1.vals[numVals].value = (SmPointer) "-s";
+   prop1.vals[numVals++].length = 2;
+   
+   prop1.vals[numVals].value = (SmPointer) "-clientId";
+   prop1.vals[numVals++].length = 9;
+ 
+   prop1.vals[numVals].value = (SmPointer) sm_client_id;
+   prop1.vals[numVals++].length = strlen (sm_client_id);
+ 
+   prop1.vals[numVals].value = (SmPointer) "-restore";
+   prop1.vals[numVals++].length = 8;
+ 
+   prop1.vals[numVals].value = (SmPointer) filename;
+   prop1.vals[numVals++].length = strlen (filename);
+ 
+   prop1.num_vals = numVals;
+ 
+   sprintf (discardCommand, "rm %s", filename);
+   prop2.name = SmDiscardCommand;
+   prop2.type = SmARRAY8;
+   prop2.num_vals = 1;
+   prop2.vals = &prop2val;
+   prop2val.value = (SmPointer) discardCommand;
+   prop2val.length = strlen (discardCommand);
+   
+   props[0] = &prop1;
+   props[1] = &prop2;
+ 
+   SmcSetProperties (smc_conn, 2, props);
+   free ((char *) prop1.vals);
+ 
+  bad:
+   SmcSaveYourselfDone (smc_conn, success);
+   sent_save_done = 1;
+ 
+   if (cfg_file) fclose (cfg_file);
+   
+   if (filename) free (filename);
+ }
+ 
+ static void
+ callback_save_yourself(SmcConn smc_conn, SmPointer client_data,
+ 		       int save_style, Bool shutdown, int interact_style,
+ 		       Bool fast)
+ {
+   if (!SmcRequestSaveYourselfPhase2(smc_conn, callback_save_yourself2, NULL))
+     {
+       SmcSaveYourselfDone (smc_conn, False);
+       sent_save_done = 1;
+     }
+   else 
+     sent_save_done = 0;
+ }
+ 
+ static void
+ callback_die(SmcConn smc_conn, SmPointer client_data)
+ {
+    SmcCloseConnection(smc_conn, 0, NULL);
+    sm_fd = -1;
+    master_flag = ()? 1 : 0;
+    if (master_pid != getpid())
+       kill(master_pid, SIGTERM);
+    Done(0, NULL);
+ }
+ 
+ static void
+ callback_save_complete(SmcConn smc_conn, SmPointer client_data)
+ {
+ }
+ 
+ static void
+ callback_shutdown_cancelled(SmcConn smc_conn, SmPointer client_data)
+ {
+   if (!sent_save_done) 
+     {
+       SmcSaveYourselfDone(smc_conn, False);
+       sent_save_done = 1;
+     }
+ }
+ 
+ static void InstallIOErrorHandler();
+ 
+ void
+ SessionInit(char *previous_client_id)
+ {
+   char                error_string_ret[4096] = "";
+   static SmPointer    context;
+   SmcCallbacks        callbacks;
+   char               *client_id = NULL;
+   IceConn             ice_conn;
+   
+   InstallIOErrorHandler();
+ 
+   callbacks.save_yourself.callback = callback_save_yourself;
+   callbacks.die.callback = callback_die;
+   callbacks.save_complete.callback = callback_save_complete;
+   callbacks.shutdown_cancelled.callback = callback_shutdown_cancelled;
+   
+   callbacks.save_yourself.client_data =
+     callbacks.die.client_data =
+     callbacks.save_complete.client_data =
+     callbacks.shutdown_cancelled.client_data = (SmPointer) NULL;
+   
+   sm_conn = SmcOpenConnection(NULL, &context, SmProtoMajor, SmProtoMinor,
+ 			      SmcSaveYourselfProcMask | SmcDieProcMask |
+ 			      SmcSaveCompleteProcMask |
+ 			      SmcShutdownCancelledProcMask,
+ 			      &callbacks, previous_client_id, &sm_client_id,
+ 			      4096, error_string_ret);
+   
+   if (!sm_conn)
+     {
+       /* 
+          Don't annoy users which don't use a session manager
+        */ 
+       if (previous_client_id)
+         {
+            fvwm_msg(ERR, "SessionInit", 
+ 	            "While connecting to session manager:\n%s.", 
+                      error_string_ret);
+         }
+       sm_fd = -1;
+     }
+   else
+     {
+       sm_fd = IceConnectionNumber(SmcGetIceConnection(sm_conn));
+     }
+ }
+ 
+ void
+ ProcessICEMSGS(void)
+ {
+    IceProcessMessagesStatus status;
+ 
+    if (sm_fd < 0)
+       return;
+    status = IceProcessMessages(SmcGetIceConnection(sm_conn), NULL, NULL);
+    if (status == IceProcessMessagesIOError)
+      {
+         fvwm_msg(ERR, "ProcessICEMSGS", 
+                  "Connection to session manager lost\n");
+ 	sm_conn = NULL;
+ 	sm_fd = -1;
+      }
+ }
+ 
+ /* the following is taken from xsm */
+ 
+ static IceIOErrorHandler prev_handler;
+ 
+ void
+ MyIoErrorHandler (ice_conn)
+ 
+ IceConn ice_conn;
+ 
+ {
+     if (prev_handler)
+         (*prev_handler) (ice_conn);
+ }
+ 
+ static void
+ InstallIOErrorHandler ()
+ 
+ {
+     IceIOErrorHandler default_handler;
+ 
+     prev_handler = IceSetIOErrorHandler (NULL);
+     default_handler = IceSetIOErrorHandler (MyIoErrorHandler);
+     if (prev_handler == default_handler)
+         prev_handler = NULL;
+ }
+ 
+ 
+ #endif /* SESSION */
diff -cN configure.in.orig configure.in
*** configure.in.orig	Tue Feb 23 21:16:40 1999
--- configure.in	Tue Feb 23 19:21:55 1999
***************
*** 33,38 ****
--- 33,39 ----
  smr_SWITCH(borderstyle, BorderStyle command, on, BORDERSTYLE)
  smr_SWITCH(usedecor, UseDecor style option, on, USEDECOR)
  smr_SWITCH(windowshade, WindowShade function, on, WINDOWSHADE)
+ smr_SWITCH(session, session management functionality, off, SESSION)
  smr_SWITCH(debug-msgs, debugging messages, off, FVWM_DEBUG_MSGS)
  
  dnl FIXME: default value should be derived from computed path to X
diff -cN config.h.in.orig config.h.in
*** config.h.in.orig	Tue Feb 23 21:29:06 1999
--- config.h.in	Tue Feb 23 21:29:15 1999
***************
*** 107,112 ****
--- 107,117 ----
   * "WindowShade" for more information.  */
  #undef WINDOWSHADE
  
+ /* Enables session management functionality. This makes fvwm talk
+  * to a session manager and save and restore its state.
+  */
+ #undef SESSION
+ 
  /* Specify a type for sig_atomic_t if it's not available.  */
  #undef sig_atomic_t

--
Visit the official FVWM web page at <URL:http://www.fvwm.org/>.
To unsubscribe from the list, send "unsubscribe fvwm-workers" in the
body of a message to [email-masked].
To report problems, send mail to [email-masked]

---

From: Dan Espen <[email-masked]>
Date: Thu, 25 Feb 1999 08:47:03 -0500

> OK, so now I have tu hurry to get my patches posted before I have to check

I don't see how hurrying is going to help.
You have 2 votes for update access, get in touch with Jason.

---

From: Jason L Tibbitts III <[email-masked]>
Date: 25 Feb 1999 11:09:55 -0600

>>>>> "DE" == Dan Espen <[email-masked]> writes:

DE> I don't see how hurrying is going to help. You have 2 votes for update
DE> access, get in touch with Jason.

Yes, please do.  Run the bit of Perl from http://www.fvwm.org/cvs.html to
generate a password and mail it to me.  Then you'll be able to commit
(after you do 'cvs login' with the new password) and you'll be able to
manipulate stuff in the bug database.

 - J<