From 18cf73cdf923950edb86d9cdc8c12e22a6e0625a Mon Sep 17 00:00:00 2001
From: Olivier Fourdan <fourdan.olivier@wanadoo.fr>
Date: Thu, 6 Feb 2003 16:22:50 +0000
Subject: [PATCH] Add missing bits for full session management

(Old svn revision: 10902)
---
 TODO            |  14 +-
 aclocal.m4      |   2 +
 configure       |   2 +
 src/Makefile.am |   2 +
 src/Makefile.in |  41 +++-
 src/client.c    | 121 ++++++++----
 src/client.h    |   9 +
 src/events.c    |   1 +
 src/hints.c     | 163 ++++++++++++---
 src/hints.h     |  22 ++-
 src/main.c      |  27 ++-
 src/session.c   | 517 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/session.h   |  46 +++++
 13 files changed, 876 insertions(+), 91 deletions(-)
 create mode 100644 src/session.c
 create mode 100644 src/session.h

diff --git a/TODO b/TODO
index 079f0c60a..d4654f191 100644
--- a/TODO
+++ b/TODO
@@ -1,16 +1,6 @@
 Things to do
 ============
 
-* Implement freedesktop.org standards                           ** DONE **
-* Use pango for font redering (aa text, multibytes, etc)        ** DONE **
-* Add new buttons for menu and stick/unstick
-* Implement window menu                                         ** PARTIAL **
-* Implement xsettings
-* Implement session management
-* Reimplement Xinerama support
-* Implement autoraise window using GTK timeout                  ** DONE **
-* Make transient windows stay stacked above their parents       ** DONE **
-* Implement GTK event loop                                      ** DONE **
-* Implement GTK menus                                           ** DONE **
-* Bugfix on MapRequest (crash when mapping/unmapping quickly)   ** DONE **
+Add your favorite wish list here :
 
+* Multiscreen mode (not Xinerama)
diff --git a/aclocal.m4 b/aclocal.m4
index 8554ec102..26657935b 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -4655,6 +4655,8 @@ glib_DEFUN([GLIB_WITH_NLS],
 	    [CATOBJEXT=.mo
              DATADIRNAME=lib])
 	  INSTOBJEXT=.mo
+	else
+	  gt_cv_have_gettext=no
 	fi
       fi
     ])
diff --git a/configure b/configure
index 575f4c6a2..8b482e790 100755
--- a/configure
+++ b/configure
@@ -8814,6 +8814,8 @@ CATOBJEXT=.mo
 fi
 rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
 	  INSTOBJEXT=.mo
+	else
+	  gt_cv_have_gettext=no
 	fi
       fi
 
diff --git a/src/Makefile.am b/src/Makefile.am
index e53847eda..46d232014 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -21,6 +21,8 @@ xfwm4_SOURCES = \
 	parserc.h \
 	pixmap.c \
 	pixmap.h \
+	session.c \
+	session.h \
 	settings.c \
 	settings.h \
 	tabwin.c \
diff --git a/src/Makefile.in b/src/Makefile.in
index ae856f00a..b83968899 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -178,6 +178,8 @@ xfwm4_SOURCES = \
 	parserc.h \
 	pixmap.c \
 	pixmap.h \
+	session.c \
+	session.h \
 	settings.c \
 	settings.h \
 	tabwin.c \
@@ -207,8 +209,8 @@ am_xfwm4_OBJECTS = xfwm4-client.$(OBJEXT) xfwm4-events.$(OBJEXT) \
 	xfwm4-keyboard.$(OBJEXT) xfwm4-main.$(OBJEXT) \
 	xfwm4-menu.$(OBJEXT) xfwm4-misc.$(OBJEXT) \
 	xfwm4-parserc.$(OBJEXT) xfwm4-pixmap.$(OBJEXT) \
-	xfwm4-settings.$(OBJEXT) xfwm4-tabwin.$(OBJEXT) \
-	xfwm4-workspaces.$(OBJEXT)
+	xfwm4-session.$(OBJEXT) xfwm4-settings.$(OBJEXT) \
+	xfwm4-tabwin.$(OBJEXT) xfwm4-workspaces.$(OBJEXT)
 xfwm4_OBJECTS = $(am_xfwm4_OBJECTS)
 xfwm4_DEPENDENCIES =
 xfwm4_LDFLAGS =
@@ -225,6 +227,7 @@ am__depfiles_maybe = depfiles
 @AMDEP_TRUE@	./$(DEPDIR)/xfwm4-misc.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/xfwm4-parserc.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/xfwm4-pixmap.Po \
+@AMDEP_TRUE@	./$(DEPDIR)/xfwm4-session.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/xfwm4-settings.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/xfwm4-tabwin.Po \
 @AMDEP_TRUE@	./$(DEPDIR)/xfwm4-workspaces.Po
@@ -299,6 +302,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xfwm4-misc.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xfwm4-parserc.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xfwm4-pixmap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xfwm4-session.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xfwm4-settings.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xfwm4-tabwin.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xfwm4-workspaces.Po@am__quote@
@@ -669,6 +673,39 @@ xfwm4-pixmap.lo: pixmap.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xfwm4_CFLAGS) $(CFLAGS) -c -o xfwm4-pixmap.lo `test -f 'pixmap.c' || echo '$(srcdir)/'`pixmap.c
 
+xfwm4-session.o: session.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xfwm4_CFLAGS) $(CFLAGS) -MT xfwm4-session.o -MD -MP -MF "$(DEPDIR)/xfwm4-session.Tpo" \
+@am__fastdepCC_TRUE@	  -c -o xfwm4-session.o `test -f 'session.c' || echo '$(srcdir)/'`session.c; \
+@am__fastdepCC_TRUE@	then mv "$(DEPDIR)/xfwm4-session.Tpo" "$(DEPDIR)/xfwm4-session.Po"; \
+@am__fastdepCC_TRUE@	else rm -f "$(DEPDIR)/xfwm4-session.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@	fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='session.c' object='xfwm4-session.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/xfwm4-session.Po' tmpdepfile='$(DEPDIR)/xfwm4-session.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xfwm4_CFLAGS) $(CFLAGS) -c -o xfwm4-session.o `test -f 'session.c' || echo '$(srcdir)/'`session.c
+
+xfwm4-session.obj: session.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xfwm4_CFLAGS) $(CFLAGS) -MT xfwm4-session.obj -MD -MP -MF "$(DEPDIR)/xfwm4-session.Tpo" \
+@am__fastdepCC_TRUE@	  -c -o xfwm4-session.obj `if test -f 'session.c'; then $(CYGPATH_W) 'session.c'; else $(CYGPATH_W) '$(srcdir)/session.c'; fi`; \
+@am__fastdepCC_TRUE@	then mv "$(DEPDIR)/xfwm4-session.Tpo" "$(DEPDIR)/xfwm4-session.Po"; \
+@am__fastdepCC_TRUE@	else rm -f "$(DEPDIR)/xfwm4-session.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@	fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='session.c' object='xfwm4-session.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/xfwm4-session.Po' tmpdepfile='$(DEPDIR)/xfwm4-session.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xfwm4_CFLAGS) $(CFLAGS) -c -o xfwm4-session.obj `if test -f 'session.c'; then $(CYGPATH_W) 'session.c'; else $(CYGPATH_W) '$(srcdir)/session.c'; fi`
+
+xfwm4-session.lo: session.c
+@am__fastdepCC_TRUE@	if $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xfwm4_CFLAGS) $(CFLAGS) -MT xfwm4-session.lo -MD -MP -MF "$(DEPDIR)/xfwm4-session.Tpo" \
+@am__fastdepCC_TRUE@	  -c -o xfwm4-session.lo `test -f 'session.c' || echo '$(srcdir)/'`session.c; \
+@am__fastdepCC_TRUE@	then mv "$(DEPDIR)/xfwm4-session.Tpo" "$(DEPDIR)/xfwm4-session.Plo"; \
+@am__fastdepCC_TRUE@	else rm -f "$(DEPDIR)/xfwm4-session.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@	fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='session.c' object='xfwm4-session.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/xfwm4-session.Plo' tmpdepfile='$(DEPDIR)/xfwm4-session.TPlo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xfwm4_CFLAGS) $(CFLAGS) -c -o xfwm4-session.lo `test -f 'session.c' || echo '$(srcdir)/'`session.c
+
 xfwm4-settings.o: settings.c
 @am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(xfwm4_CFLAGS) $(CFLAGS) -MT xfwm4-settings.o -MD -MP -MF "$(DEPDIR)/xfwm4-settings.Tpo" \
 @am__fastdepCC_TRUE@	  -c -o xfwm4-settings.o `test -f 'settings.c' || echo '$(srcdir)/'`settings.c; \
diff --git a/src/client.c b/src/client.c
index 04b49bb56..f634e9f10 100644
--- a/src/client.c
+++ b/src/client.c
@@ -35,6 +35,7 @@
 #include "workspaces.h"
 #include "settings.h"
 #include "tabwin.h"
+#include "session.h"
 #include "debug.h"
 #include "my_intl.h"
 
@@ -697,7 +698,10 @@ static void clientGetInitialNetWmDesktop(Client * c)
     DBG("entering clientGetInitialNetWmDesktop\n");
     DBG("client \"%s\" (%#lx)\n", c->name, c->window);
 
-    c->win_workspace = workspace;
+    if (!CLIENT_FLAG_TEST(c, CLIENT_FLAG_SESSION_MANAGED))
+    {
+        c->win_workspace = workspace;
+    }
     if(getNetHint(dpy, c->window, net_wm_desktop, &val))
     {
         DBG("atom net_wm_desktop detected\n");
@@ -1838,6 +1842,53 @@ void clientUpdateMWMHints(Client * c)
     }
 }
 
+static inline void clientFree(Client *c)
+{    
+    g_return_if_fail (c != NULL);
+    
+    DBG("entering clientFree\n");
+    DBG("freeing client \"%s\" (%#lx)\n", c->name, c->window);
+
+    if(c->name)
+    {
+        free(c->name);
+    }
+    if(c->size)
+    {
+        XFree(c->size);
+    }
+    if(c->wmhints)
+    {
+        XFree(c->wmhints);
+    }
+    if(c->ncmap > 0)
+    {
+        XFree(c->cmap_windows);
+    }
+    if(c->class.res_name)
+    {
+        XFree(c->class.res_name);
+    }
+    if(c->class.res_class)
+    {
+        XFree(c->class.res_class);
+    }
+    if(c->client_id)
+    {
+        XFree(c->client_id);
+    }
+    if(c->window_role)
+    {
+        XFree(c->window_role);
+    }
+    if((c->wm_command) && (c->wm_command_count))
+    {
+        XFreeStringList(c->wm_command);
+    }
+    
+    free(c);
+}
+
 void clientFrame(Window w)
 {
     XWindowAttributes attr;
@@ -1904,8 +1955,23 @@ void clientFrame(Window w)
         c->ncmap = 0;
     }
 
+    c->class.res_name = NULL;
+    c->class.res_class = NULL;
+    XGetClassHint (dpy, w, &c->class);
     c->wmhints = XGetWMHints(dpy, c->window);
-
+    getClientID(dpy, c->window, &(c->client_id));
+    c->client_leader = getClientLeader(dpy, c->window);
+    if (c->client_leader != None)
+    {
+        getWindowRole(dpy, c->client_leader, &(c->window_role));
+    }
+    else
+    {
+        c->window_role = NULL;
+    }
+    c->wm_command_count = 0;
+    getWindowCommand(dpy, c->window, &(c->wm_command), &(c->wm_command_count));
+    
     /* Initialize structure */
     c->client_flag = (CLIENT_FLAG_HAS_BORDER | CLIENT_FLAG_HAS_MENU | CLIENT_FLAG_HAS_MAXIMIZE | CLIENT_FLAG_HAS_HIDE | CLIENT_FLAG_HAS_CLOSE | CLIENT_FLAG_HAS_MOVE | CLIENT_FLAG_HAS_RESIZE);
 
@@ -1931,6 +1997,12 @@ void clientFrame(Window w)
         c->win_layer = WIN_LAYER_NORMAL;
     }
 
+    /* Reload from session */
+    if (sessionMatchWinToSM (c))
+    {
+        CLIENT_FLAG_SET(c, CLIENT_FLAG_SESSION_MANAGED);
+    }
+
     CLIENT_FLAG_SET(c, (CLIENT_FLAG_TEST(c, CLIENT_FLAG_STICKY)) ? CLIENT_FLAG_STICKY : 0);
     CLIENT_FLAG_SET(c, (CLIENT_FLAG_TEST(c, CLIENT_FLAG_SHADED)) ? CLIENT_FLAG_SHADED : 0);
     CLIENT_FLAG_SET(c, (c->win_state & (WIN_STATE_MAXIMIZED_VERT | WIN_STATE_MAXIMIZED)) ? CLIENT_FLAG_MAXIMIZED_VERT : 0);
@@ -1960,27 +2032,21 @@ void clientFrame(Window w)
     }
 
     /* Once we know the type of window, we can initialize window position */
-    if(attr.map_state != IsViewable)
+    if(!CLIENT_FLAG_TEST(c, CLIENT_FLAG_SESSION_MANAGED))
     {
-        clientInitPosition(c);
-    }
-    else
-    {
-        clientGravitate(c, APPLY);
+        if (attr.map_state != IsViewable)
+	{
+            clientInitPosition(c);
+	}
+	else
+	{
+            clientGravitate(c, APPLY);
+	}
     }
-
     gdk_x11_grab_server();
     if(XGetGeometry(dpy, w, &dummy_root, &dummy_x, &dummy_y, &dummy_width, &dummy_height, &dummy_bw, &dummy_depth) == 0)
     {
-        if(c->name)
-        {
-            free(c->name);
-        }
-        if(c->size)
-        {
-            XFree(c->size);
-        }
-        free(c);
+        clientFree(c);
         gdk_x11_ungrab_server();
         return;
     }
@@ -2084,24 +2150,7 @@ void clientUnframe(Client * c, int remap)
     {
         workspaceUpdateArea(margins, gnome_margins);
     }
-    if(c->name)
-    {
-        free(c->name);
-    }
-    if(c->size)
-    {
-        XFree(c->size);
-    }
-    if(c->wmhints)
-    {
-        XFree(c->wmhints);
-    }
-    if(c->ncmap > 0)
-    {
-        XFree(c->cmap_windows);
-    }
-    free(c);
-    DBG("client_count=%d\n", client_count);
+    clientFree(c);
 }
 
 void clientFrameAll()
diff --git a/src/client.h b/src/client.h
index b1d575843..3746d0b93 100644
--- a/src/client.h
+++ b/src/client.h
@@ -106,6 +106,8 @@
 #define CLIENT_FLAG_WM_TAKEFOCUS       (1L<<25)
 #define CLIENT_FLAG_RESIZING           (1L<<26)
 #define CLIENT_FLAG_MOVING             (1L<<27)
+#define CLIENT_FLAG_NAME_CHANGED       (1L<<28)
+#define CLIENT_FLAG_SESSION_MANAGED    (1L<<29)
 
 /* Convenient macros */
 #define CLIENT_FLAG_TEST(c,f)			(c->client_flag & (f))
@@ -145,14 +147,17 @@ struct _Client
     Window sides[3];
     Window corners[4];
     Window buttons[BUTTON_COUNT];
+    Window client_leader;
     Colormap cmap;
     unsigned long win_hints;
     unsigned long win_state;
     unsigned long win_layer;
+
     int win_workspace;
     Atom type_atom;
     XSizeHints *size;
     XWMHints *wmhints;
+    XClassHint class;
     Client *next;
     Client *prev;
     WindowType type;
@@ -176,6 +181,10 @@ struct _Client
     int ncmap;
     int button_pressed[BUTTON_COUNT];
     int struts[4];
+    char *client_id;
+    char *window_role;
+    int wm_command_count;
+    char **wm_command;
     char *name;
     unsigned long client_flag;
 };
diff --git a/src/events.c b/src/events.c
index 7be178099..259b26344 100644
--- a/src/events.c
+++ b/src/events.c
@@ -809,6 +809,7 @@ static inline void handlePropertyNotify(XPropertyEvent * ev)
                 free(c->name);
             }
             getWindowName(dpy, c->window, &c->name);
+	    CLIENT_FLAG_SET(c, CLIENT_FLAG_NAME_CHANGED);
             frameDraw(c);
         }
         else if(ev->atom == motif_wm_hints)
diff --git a/src/hints.c b/src/hints.c
index dfbfb2a00..62149fce1 100644
--- a/src/hints.c
+++ b/src/hints.c
@@ -140,7 +140,7 @@ unsigned long getWMState(Display * dpy, Window w)
         state = *data;
         XFree(data);
     }
-    return (state);
+    return state;
 }
 
 void setWMState(Display * dpy, Window w, unsigned long state)
@@ -173,11 +173,11 @@ PropMwmHints *getMotifHints(Display * dpy, Window w)
 
     if((XGetWindowProperty(dpy, w, motif_wm_hints, 0L, 20L, False, motif_wm_hints, &real_type, &real_format, &items_read, &items_left, (unsigned char **)&data) == Success) && (items_read))
     {
-        return (data);
+        return data;
     }
     else
     {
-        return (NULL);
+        return NULL;
     }
 }
 
@@ -227,7 +227,7 @@ unsigned int getWMProtocols(Display * dpy, Window w)
     {
         XFree(protocols);
     }
-    return (result);
+    return result;
 }
 
 
@@ -247,10 +247,11 @@ void initGnomeHints(Display * dpy)
     win_workspace = XInternAtom(dpy, "_WIN_WORKSPACE", False);
 }
 
-int getGnomeHint(Display * dpy, Window w, Atom a, long *value)
+gboolean getGnomeHint(Display * dpy, Window w, Atom a, long *value)
 {
     Atom real_type;
-    int real_format, success = False;
+    int real_format;
+    gboolean success = FALSE;
     unsigned long items_read, items_left;
     long *data = NULL;
 
@@ -262,9 +263,9 @@ int getGnomeHint(Display * dpy, Window w, Atom a, long *value)
     {
         *value = *data;
         XFree(data);
-        success = True;
+        success = TRUE;
     }
-    return (success);
+    return success;
 }
 
 void setGnomeHint(Display * dpy, Window w, Atom a, long value)
@@ -365,10 +366,11 @@ void initNetHints(Display * dpy)
     utf8_string = XInternAtom(dpy, "UTF8_STRING", False);
 }
 
-int getNetHint(Display * dpy, Window w, Atom a, long *value)
+gboolean getNetHint(Display * dpy, Window w, Atom a, long *value)
 {
     Atom real_type;
-    int real_format, success = False;
+    int real_format;
+    gboolean success = FALSE;
     unsigned long items_read, items_left;
     long *data = NULL;
 
@@ -380,9 +382,9 @@ int getNetHint(Display * dpy, Window w, Atom a, long *value)
     {
         *value = *data;
         XFree(data);
-        success = True;
+        success = TRUE;
     }
-    return (success);
+    return success;
 }
 
 void set_net_supported_hint(Display * dpy, int screen, Window check_win)
@@ -450,16 +452,16 @@ void set_net_supported_hint(Display * dpy, int screen, Window check_win)
     XChangeProperty(dpy, RootWindow(dpy, screen), net_supporting_wm_check, XA_WINDOW, 32, PropModeReplace, (unsigned char *)data, 1);
 }
 
-static int check_type_and_format(Display * dpy, Window w, Atom a, int expected_format, Atom expected_type, int n_items, int format, Atom type)
+static gboolean check_type_and_format(Display * dpy, Window w, Atom a, int expected_format, Atom expected_type, int n_items, int format, Atom type)
 {
     if((expected_format == format) && (expected_type == type) && (n_items < 0 || n_items > 0))
     {
-        return (True);
+        return TRUE;
     }
-    return (False);
+    return FALSE;
 }
 
-int get_atom_list(Display * dpy, Window w, Atom a, Atom ** atoms_p, int *n_atoms_p)
+gboolean get_atom_list(Display * dpy, Window w, Atom a, Atom ** atoms_p, int *n_atoms_p)
 {
     Atom type;
     int format;
@@ -472,7 +474,7 @@ int get_atom_list(Display * dpy, Window w, Atom a, Atom ** atoms_p, int *n_atoms
 
     if((XGetWindowProperty(dpy, w, a, 0, G_MAXLONG, False, XA_ATOM, &type, &format, &n_atoms, &bytes_after, (unsigned char **)&atoms) != Success) || (type == None))
     {
-        return (False);
+        return FALSE;
     }
 
     if(!check_type_and_format(dpy, w, a, 32, XA_ATOM, -1, format, type))
@@ -483,16 +485,16 @@ int get_atom_list(Display * dpy, Window w, Atom a, Atom ** atoms_p, int *n_atoms
         }
         *atoms_p = NULL;
         *n_atoms_p = 0;
-        return (False);
+        return FALSE;
     }
 
     *atoms_p = atoms;
     *n_atoms_p = n_atoms;
 
-    return (True);
+    return TRUE;
 }
 
-int get_cardinal_list(Display * dpy, Window w, Atom xatom, unsigned long **cardinals_p, int *n_cardinals_p)
+gboolean get_cardinal_list(Display * dpy, Window w, Atom xatom, unsigned long **cardinals_p, int *n_cardinals_p)
 {
     Atom type;
     int format;
@@ -505,19 +507,19 @@ int get_cardinal_list(Display * dpy, Window w, Atom xatom, unsigned long **cardi
 
     if((XGetWindowProperty(dpy, w, xatom, 0, G_MAXLONG, False, XA_CARDINAL, &type, &format, &n_cardinals, &bytes_after, (unsigned char **)&cardinals) != Success) || (type == None))
     {
-        return False;
+        return FALSE;
     }
 
     if(!check_type_and_format(dpy, w, xatom, 32, XA_CARDINAL, -1, format, type))
     {
         XFree(cardinals);
-        return False;
+        return FALSE;
     }
 
     *cardinals_p = cardinals;
     *n_cardinals_p = n_cardinals;
 
-    return True;
+    return TRUE;
 }
 
 void set_net_workarea(Display * dpy, int screen, int nb_workspaces, CARD32 * margins)
@@ -579,7 +581,7 @@ void getTransientFor(Display * dpy, Window w, Window * transient_for)
     DBG("Window (%#lx) is transient for (%#lx)\n", w, *transient_for);
 }
 
-int get_utf8_string(Display * dpy, Window w, Atom xatom, char **str_p)
+gboolean get_utf8_string(Display * dpy, Window w, Atom xatom, char **str_p)
 {
     Atom type;
     int format;
@@ -593,7 +595,7 @@ int get_utf8_string(Display * dpy, Window w, Atom xatom, char **str_p)
     if((XGetWindowProperty(dpy, w, xatom, 0, G_MAXLONG, False, utf8_string, &type, &format, &n_items, &bytes_after, (unsigned char **)&str) != Success) || (type == None))
     {
         DBG("no utf8_string value provided\n");
-        return False;
+        return FALSE;
     }
 
     if(!check_type_and_format(dpy, w, xatom, 8, utf8_string, -1, format, type))
@@ -603,7 +605,7 @@ int get_utf8_string(Display * dpy, Window w, Atom xatom, char **str_p)
         {
             XFree(str);
         }
-        return False;
+        return FALSE;
     }
 
     if(!g_utf8_validate(str, n_items, NULL))
@@ -618,12 +620,12 @@ int get_utf8_string(Display * dpy, Window w, Atom xatom, char **str_p)
         }
         XFree(str);
 
-        return False;
+        return FALSE;
     }
 
     *str_p = str;
 
-    return True;
+    return TRUE;
 }
 
 static char *text_property_to_utf8(Display * dpy, const XTextProperty * prop)
@@ -675,9 +677,13 @@ static char *get_text_property(Display * dpy, Window w, Atom a)
 void getWindowName(Display * dpy, Window w, char **name)
 {
     char *str;
-
+    
     DBG("entering getWindowName\n");
+
+    g_return_if_fail (name != NULL);
     *name = NULL;
+    g_return_if_fail (w != None);
+    
     if(get_utf8_string(dpy, w, net_wm_name, &str))
     {
         *name = strdup(str);
@@ -694,6 +700,103 @@ void getWindowName(Display * dpy, Window w, char **name)
     {
         *name = strdup("");
     }
+}
+
+gboolean getWindowRole(Display * dpy, Window window, char **role)
+{
+    XTextProperty tp;
+
+    DBG("entering GetWindowRole\n");
+    
+    g_return_val_if_fail (role != NULL, FALSE);
+    *role = NULL;
+    g_return_val_if_fail (window != None, FALSE);
+    
+    if(XGetTextProperty(dpy, window, &tp, wm_window_role))
+    {
+        if((tp.value) && (tp.encoding == XA_STRING) && (tp.format == 8) && (tp.nitems != 0))
+        {
+            *role = strdup((char *)tp.value);
+            XFree(tp.value);
+	    return TRUE;
+        }
+    }
+
+    return FALSE;
+}
+
+Window getClientLeader(Display * dpy, Window window)
+{
+    Window client_leader = None;
+    Atom actual_type;
+    int actual_format;
+    unsigned long nitems;
+    unsigned long bytes_after;
+    unsigned char *prop = NULL;
+
+    DBG("entering getClientLeader\n");
+    
+    g_return_val_if_fail (window != None, None);
+    
+    if(XGetWindowProperty(dpy, window, wm_client_leader, 0L, 1L, False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes_after, &prop) == Success)
+    {
+        if((prop) && (actual_type == XA_WINDOW) && (actual_format == 32) && (nitems == 1) && (bytes_after == 0))
+        {
+            client_leader = *((Window *) prop);
+        }
+        if(prop)
+        {
+            XFree(prop);
+        }
+    }
+    return client_leader;
+}
+
+gboolean getClientID(Display * dpy, Window window, char **client_id)
+{
+    Window id;
+    XTextProperty tp;
+
+    DBG("entering getClientID\n");
+
+    g_return_val_if_fail (client_id != NULL, FALSE);
+    *client_id = NULL;
+    g_return_val_if_fail (window != None, FALSE);
+
+    if((id = getClientLeader(dpy, window)))
+    {
+        if(XGetTextProperty(dpy, id, &tp, sm_client_id))
+        {
+            if(tp.encoding == XA_STRING && tp.format == 8 && tp.nitems != 0)
+	    {
+                *client_id = strdup((char *)tp.value);
+                XFree(tp.value);
+	        return TRUE;
+	    }
+        }
+    }
 
-    return;
+    return FALSE;
 }
+
+gboolean getWindowCommand(Display * dpy, Window window, char ***argv, int *argc)
+{
+    Window id;
+
+    *argc = 0;
+    g_return_val_if_fail(window != None, FALSE);
+
+    if(XGetCommand(dpy, window, argv, argc) && (*argc > 0))
+    {
+        return TRUE;
+    }
+    if((id = getClientLeader(dpy, window)))
+    {
+        if(XGetCommand(dpy, id, argv, argc) && (*argc > 0))
+        {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
diff --git a/src/hints.h b/src/hints.h
index c118639fc..a6cce22ec 100644
--- a/src/hints.h
+++ b/src/hints.h
@@ -19,14 +19,15 @@
 
  */
 
-#ifndef __HINTS_H
-#define __HINTS_H
+#ifndef __HINTS_H__
+#define __HINTS_H__
 
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
 #endif
 
 #include <X11/Xatom.h>
+#include <glib.h>
 
 #define MWM_HINTS_FUNCTIONS                     (1L << 0)
 #define MWM_HINTS_DECORATIONS                   (1L << 1)
@@ -181,23 +182,28 @@ void initMotifHints(Display *);
 PropMwmHints *getMotifHints(Display *, Window);
 unsigned int getWMProtocols(Display *, Window);
 void initGnomeHints(Display *);
-int getGnomeHint(Display *, Window, Atom, long *);
+gboolean getGnomeHint(Display *, Window, Atom, long *);
 void setGnomeHint(Display *, Window, Atom, long);
 void getGnomeDesktopMargins(Display *, int, CARD32 *);
 void setGnomeProtocols(Display *, int, Window);
 void initNetHints(Display * dpy);
-int getNetHint(Display *, Window, Atom, long *);
+gboolean getNetHint(Display *, Window, Atom, long *);
 void set_net_supported_hint(Display *, int, Window);
-int get_atom_list(Display *, Window, Atom, Atom **, int *);
-int get_cardinal_list(Display *, Window, Atom, unsigned long **, int *);
+gboolean get_atom_list(Display *, Window, Atom, Atom **, int *);
+gboolean get_cardinal_list(Display *, Window, Atom, unsigned long **, int *);
 void set_net_workarea(Display *, int, int, CARD32 *);
 void init_net_desktop_params(Display *, int, int);
 void set_utf8_string_hint(Display *, Window, Atom, const char *);
 void getTransientFor(Display * dpy, Window w, Window * transient_for);
 void getWindowName(Display * dpy, Window w, char **name);
-int get_utf8_string(Display *, Window, Atom, char **);
+gboolean get_utf8_string(Display *, Window, Atom, char **);
 void getWindowName(Display *, Window, char **);
+gboolean getWindowRole(Display *, Window, char **);
+Window getClientLeader(Display *, Window);
+gboolean getClientID(Display *, Window, char **);
+gboolean getWindowCommand(Display *, Window, char ***, int *);
+
 
 #define setNetHint setGnomeHint
 
-#endif /* __HINTS_H */
+#endif /* __HINTS_H__ */
diff --git a/src/main.c b/src/main.c
index bb16ded67..5f48bc97b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -47,6 +47,7 @@
 #include "menu.h"
 #include "keyboard.h"
 #include "workspaces.h"
+#include "session.h"
 #include "debug.h"
 #include "my_intl.h"
 
@@ -106,6 +107,7 @@ static void cleanUp()
     XFreeCursor(dpy, root_cursor);
     XFreeCursor(dpy, move_cursor);
     xineramaFree();
+    sessionFreeWindowStates();
     for(i = 0; i < 7; i++)
     {
         XFreeCursor(dpy, resize_cursor[i]);
@@ -122,9 +124,24 @@ static void cleanUp()
     closeEventFilter();
 }
 
-static void session_save_phase_2(gpointer client_data)
+static void load_saved_session(void)
 {
-    g_print("TODO: Save session\n");
+    const gchar *home = g_getenv("HOME");
+    gchar *filename;
+    
+    filename = g_build_filename(home, G_DIR_SEPARATOR_S, ".xfwm4-session", NULL);
+    sessionLoadWindowStates(filename);
+    g_free(filename);
+}
+
+static void save_phase_2(gpointer data)
+{
+    const gchar *home = g_getenv("HOME");
+    gchar *filename;
+    
+    filename = g_build_filename(home, G_DIR_SEPARATOR_S, ".xfwm4-session", NULL);
+    sessionSaveWindowStates(filename);
+    g_free(filename);
 }
 
 static void session_die(gpointer client_data)
@@ -194,13 +211,17 @@ static int initialize(int argc, char **argv)
     xinerama_heads = xineramaGetHeads();
 
     client_session = client_session_new(argc, argv, NULL, SESSION_RESTART_IF_RUNNING, 20);
-    client_session->save_phase_2 = session_save_phase_2;
+    client_session->save_phase_2 = save_phase_2;
     client_session->die = session_die;
 
     if(!session_init(client_session))
     {
         g_message(_("%s: Running without session manager"), g_get_prgname());
     }
+    else
+    {
+        load_saved_session();
+    }
 
     margins[MARGIN_TOP] = gnome_margins[MARGIN_TOP] = 0;
     margins[MARGIN_LEFT] = gnome_margins[MARGIN_LEFT] = 0;
diff --git a/src/session.c b/src/session.c
new file mode 100644
index 000000000..9050b456f
--- /dev/null
+++ b/src/session.c
@@ -0,0 +1,517 @@
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* Initially inspired by xfwm, fvwm2, enlightment and twm implementations */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <glib.h>
+
+#include "session.h"
+#include "main.h"
+#include "hints.h"
+#include "client.h"
+
+typedef struct _match
+{
+    unsigned long win;
+    unsigned long client_leader;
+    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;
+    int desktop;
+    unsigned long flags;
+    gboolean used;
+}
+Match;
+
+static int num_match = 0;
+static Match *matches = NULL;
+
+/* 
+   2-pass function to compute new string length,
+   allocate memory and finally copy string 
+   - Returned value must be freed -
+ */
+static gchar *escape_quote(gchar * s)
+{
+    gchar *ns;
+    gchar *idx1, *idx2;
+    gint nbquotes = 0;
+    gint lg = 0;
+
+    g_return_val_if_fail(s != NULL, NULL);
+
+    lg = strlen(s);
+    /* First, count quotes in string */
+    idx1 = s;
+    while(*idx1)
+    {
+        if(*(idx1++) == '"')
+            nbquotes++;
+    }
+    /* If there is no quote in the string, return it */
+    if(!nbquotes)
+        return (g_strdup(s));
+
+    /* Or else, allocate memory for the new string */
+    ns = g_new(gchar, lg + nbquotes + 1);
+    /* And prepend a backslash before any quote found in string */
+    idx1 = s;
+    idx2 = ns;
+    while(*idx1)
+    {
+        if(*idx1 == '"')
+        {
+            *(idx2++) = '\\';
+            *(idx2++) = '"';
+        }
+        else
+        {
+            *(idx2++) = *idx1;
+        }
+        idx1++;
+    }
+    /* Add null char */
+    *idx2 = '\0';
+    return ns;
+}
+
+/* 
+   single-pass function to replace backslash+quotes
+   by quotes. 
+   - Returned value must be freed -
+ */
+static gchar *unescape_quote(gchar * s)
+{
+    gchar *ns;
+    gboolean backslash;
+    gchar *idx1, *idx2;
+    gint lg;
+
+    g_return_val_if_fail(s != NULL, NULL);
+
+    lg = strlen(s);
+    backslash = FALSE;
+    ns = g_new(gchar, lg + 1);
+    idx1 = s;
+    idx2 = ns;
+    while(*idx1)
+    {
+        if(*idx1 == '\\')
+        {
+            *(idx2++) = *idx1;
+            backslash = TRUE;
+        }
+        else if((*idx1 == '"') && backslash)
+        {
+            /* Move backward to override the "\" */
+            *(--idx2) = *idx1;
+            idx2++;
+            backslash = FALSE;
+        }
+        else
+        {
+            *(idx2++) = *idx1;
+            backslash = FALSE;
+        }
+        idx1++;
+    }
+    *idx2 = '\0';
+    return ns;
+}
+
+static gchar *getsubstring(gchar * s, gint * length)
+{
+    gchar pbrk;
+    gchar *ns;
+    gchar *end, *idx1, *idx2, *skip;
+    gint lg;
+    gboolean finished = FALSE, backslash = FALSE;
+
+    lg = *length = 0;
+    g_return_val_if_fail(s != NULL, NULL);
+
+    end = skip = s;
+    while((*skip == ' ') || (*skip == '\t'))
+    {
+        end = ++skip;
+        (*length)++;
+    }
+    if(*skip == '"')
+    {
+        pbrk = '"';
+        end = ++skip;
+        (*length)++;
+    }
+    else
+    {
+        pbrk = ' ';
+    }
+
+    finished = FALSE;
+    while((!finished) && (*end))
+    {
+        if(*end == '\\')
+        {
+            backslash = TRUE;
+        }
+        else if((*end == pbrk) && backslash)
+        {
+            backslash = FALSE;
+        }
+        else if(*end == pbrk)
+        {
+            finished = TRUE;
+        }
+        end++;
+        lg++;
+        (*length)++;
+    }
+    ns = g_new(gchar, lg + 1);
+    /* Skip pbrk character */
+    end--;
+    idx1 = skip;
+    idx2 = ns;
+    do
+    {
+        *(idx2++) = *idx1;
+    }
+    while(++idx1 < end);
+    *idx2 = '\0';
+    return ns;
+}
+
+gboolean sessionSaveWindowStates(gchar *filename)
+{
+    FILE *f;
+    Client *c;
+    gint client_idx;
+
+    g_return_val_if_fail(filename != NULL, FALSE);
+    
+    if((f = fopen(filename, "w")))
+    {
+	for(c = clients, client_idx = 0; client_idx < client_count; c = c->next, client_idx++)
+	{
+            fprintf(f, "[CLIENT] 0x%lx\n", c->window);
+
+            if(c->client_id)
+            {
+        	fprintf(f, "  [CLIENT_ID] %s\n", c->client_id);
+            }
+
+            if(c->client_leader)
+            {
+        	fprintf(f, "  [CLIENT_LEADER] 0x%lx\n", c->client_leader);
+            }
+
+            if(c->window_role)
+            {
+        	fprintf(f, "  [WINDOW_ROLE] %s\n", c->window_role);
+            }
+
+            if(c->class.res_class)
+            {
+        	fprintf(f, "  [RES_NAME] %s\n", c->class.res_name);
+            }
+
+            if(c->class.res_name)
+            {
+        	fprintf(f, "  [RES_CLASS] %s\n", c->class.res_class);
+            }
+
+            if(c->name)
+            {
+        	fprintf(f, "  [WM_NAME] %s\n", c->name);
+            }
+
+            if(c->wm_command_count > 0)
+            {
+        	gint j;
+		fprintf(f, "  [WM_COMMAND] (%i)", c->wm_command_count);
+        	for(j = 0; j < c->wm_command_count; j++)
+        	{
+                    gchar *escaped_string;
+                    escaped_string = escape_quote(c->wm_command[j]);
+                    fprintf(f, " \"%s\"", escaped_string);
+                    g_free(escaped_string);
+        	}
+        	fprintf(f, "\n");
+            }
+
+            fprintf(f, "  [GEOMETRY] (%i,%i,%i,%i)\n", c->x, c->y, c->width, c->height);
+            fprintf(f, "  [DESK] %i\n", c->win_workspace);
+            fprintf(f, "  [FLAGS] 0x%lx\n", CLIENT_FLAG_TEST(c, CLIENT_FLAG_STICKY | CLIENT_FLAG_HIDDEN | CLIENT_FLAG_SHADED | CLIENT_FLAG_NAME_CHANGED));
+	}
+	fclose(f);
+	return TRUE;
+    }
+    return FALSE;
+}
+
+gboolean sessionLoadWindowStates(gchar *filename)
+{
+    FILE *f;
+    char s[4096], s1[4096];
+    int i, pos, pos1;
+    unsigned long w;
+    
+    g_return_val_if_fail(filename != NULL, FALSE);
+    if((f = fopen(filename, "r")))
+    {
+        while(fgets(s, sizeof(s), f))
+        {
+            sscanf(s, "%4000s", s1);
+            if(!strcmp(s1, "[CLIENT]"))
+            {
+                sscanf(s, "%*s %lx", &w);
+                num_match++;
+                matches = realloc(matches, sizeof(Match) * num_match);
+                matches[num_match - 1].win = w;
+                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].desktop = 0;
+                matches[num_match - 1].used = FALSE;
+                matches[num_match - 1].flags = 0;
+            }
+            else if(!strcmp(s1, "[GEOMETRY]"))
+            {
+                sscanf(s, "%*s (%i,%i,%i,%i)", &(matches[num_match - 1].x), &(matches[num_match - 1].y), &(matches[num_match - 1].w), &(matches[num_match - 1].h));
+            }
+            else if(!strcmp(s1, "[DESK]"))
+            {
+                sscanf(s, "%*s %i", &(matches[num_match - 1].desktop));
+            }
+            else if(!strcmp(s1, "[CLIENT_LEADER]"))
+            {
+                sscanf(s, "%*s 0x%lx", &(matches[num_match - 1].client_leader));
+            }
+            else if(!strcmp(s1, "[FLAGS]"))
+            {
+                sscanf(s, "%*s 0x%lx", &(matches[num_match - 1].flags));
+            }
+            else if(!strcmp(s1, "[CLIENT_ID]"))
+            {
+                sscanf(s, "%*s %[^\n]", s1);
+                matches[num_match - 1].client_id = strdup(s1);
+            }
+            else if(!strcmp(s1, "[WINDOW_ROLE]"))
+            {
+                sscanf(s, "%*s %[^\n]", s1);
+                matches[num_match - 1].window_role = strdup(s1);
+            }
+            else if(!strcmp(s1, "[RES_NAME]"))
+            {
+                sscanf(s, "%*s %[^\n]", s1);
+                matches[num_match - 1].res_name = strdup(s1);
+            }
+            else if(!strcmp(s1, "[RES_CLASS]"))
+            {
+                sscanf(s, "%*s %[^\n]", s1);
+                matches[num_match - 1].res_class = strdup(s1);
+            }
+            else if(!strcmp(s1, "[WM_NAME]"))
+            {
+                sscanf(s, "%*s %[^\n]", s1);
+                matches[num_match - 1].wm_name = strdup(s1);
+            }
+            else if(!strcmp(s1, "[WM_COMMAND]"))
+            {
+                sscanf(s, "%*s (%i)%n", &matches[num_match - 1].wm_command_count, &pos);
+                matches[num_match - 1].wm_command = (char **) malloc (sizeof (char *) * (matches[num_match - 1].wm_command_count + 1));
+                for(i = 0; i < matches[num_match - 1].wm_command_count; i++)
+                {
+                    gchar *substring;
+                    substring = getsubstring(s + pos, &pos1);
+                    pos += pos1;
+                    matches[num_match - 1].wm_command[i] = unescape_quote(substring);
+                    g_free(substring);
+                }
+                matches[num_match - 1].wm_command[matches[num_match - 1].wm_command_count] = NULL;
+            }
+
+        }
+        fclose(f);
+	return TRUE;
+    }
+    return FALSE;
+}
+
+void sessionFreeWindowStates(void)
+{
+    int i;
+    for(i = 0; i < num_match; i++)
+    {
+        if(matches[i].client_id)
+        {
+            free(matches[i].client_id);
+	    matches[i].client_id = NULL;
+        }
+        if(matches[i].res_name)
+        {
+            free(matches[i].res_name);
+	    matches[i].res_name = NULL;
+        }
+        if(matches[i].res_class)
+        {
+            free(matches[i].res_class);
+	    matches[i].res_class = NULL;
+        }
+        if(matches[i].window_role)
+        {
+            free(matches[i].window_role);
+	    matches[i].window_role = NULL;
+        }
+        if(matches[i].wm_name)
+        {
+            free(matches[i].wm_name);
+	    matches[i].wm_name = NULL;
+        }
+        if((matches[i].wm_command_count) && (matches[i].wm_command))
+        {
+            XFreeStringList(matches[i].wm_command);
+	    matches[i].wm_command_count = 0;
+	    matches[i].wm_command = NULL;
+        }
+    }
+    if (matches)
+    {
+        free(matches);
+	matches = NULL;
+	num_match = 0;
+    }
+}
+
+/* This complicated logic is from twm, where it is explained */
+
+#define xstreq(a,b) ((!a && !b) || (a && b && (strcmp(a,b)==0)))
+
+static gboolean matchWin(Client * c, Match * m)
+{
+    gboolean found;
+    int i;
+
+    g_return_val_if_fail (c != NULL, FALSE);
+
+    found = FALSE;
+    if(xstreq(c->client_id, m->client_id))
+    {
+        /* client_id's match */
+        if((c->window_role) || (m->window_role))
+        {
+            /* We have or had a window role, base decision on it */
+            found = xstreq(c->window_role, m->window_role);
+        }
+	else
+	{
+            /* Compare res_class, res_name and WM_NAME, unless the
+             * WM_NAME has changed
+             */
+            if(xstreq(c->class.res_name, m->res_name) && (CLIENT_FLAG_TEST(c, CLIENT_FLAG_NAME_CHANGED) || (m->flags & CLIENT_FLAG_NAME_CHANGED) || xstreq(c->name, m->wm_name)))
+            {
+        	if(c->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 */
+                    if(c->wm_command_count == m->wm_command_count)
+                    {
+                	for(i = 0; i < c->wm_command_count; i++)
+                	{
+                            if(strcmp(c->wm_command[i], m->wm_command[i]) != 0)
+                        	break;
+                	}
+
+                	if((i == c->wm_command_count) && (c->wm_command_count))
+                	{
+                            found = TRUE;
+                	}
+                    }           /* if (wm_command_count ==... */
+                    /* We have to deal with a now-SM-aware client, it means that it won't probably
+                     * restore its state in a proper manner.
+                     * Thus, we also mark all other instances of this application as used, to avoid
+                     * dummy side effects in case we found a matching entry.
+                     */
+                    if(found)
+                    {
+                	for(i = 0; i < num_match; i++)
+                	{
+                            if(!(matches[i].used) && !(&matches[i] == m) && (m->client_leader) && (matches[i].client_leader == m->client_leader))
+                            {
+                        	matches[i].used = TRUE;
+                            }
+                	}
+                    }
+        	}
+            }
+	}
+    }
+
+    return found;
+}
+
+gboolean sessionMatchWinToSM(Client *c)
+{
+    int i;
+    
+    g_return_if_fail (c != NULL);
+    for(i = 0; i < num_match; i++)
+    {
+        if(!matches[i].used && matchWin(c, &matches[i]))
+        {
+	    matches[i].used = TRUE;
+            c->x = matches[i].x;
+            c->y = matches[i].y;
+            c->width = matches[i].w;
+            c->height = matches[i].h;
+            c->win_workspace = matches[i].desktop;
+            CLIENT_FLAG_SET(c, matches[i].flags & (CLIENT_FLAG_STICKY | CLIENT_FLAG_SHADED | CLIENT_FLAG_HIDDEN));
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
diff --git a/src/session.h b/src/session.h
new file mode 100644
index 000000000..77b834771
--- /dev/null
+++ b/src/session.h
@@ -0,0 +1,46 @@
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+        xfwm4    - (c) 2003 Olivier Fourdan
+
+ */
+
+#ifndef __SESSION_H__
+#define __SESSION_H__
+
+#include <glib.h>
+#include "client.h"
+
+/*
+**  Save window states to file which name is given in argument.
+*/
+gboolean sessionSaveWindowStates(gchar *);
+
+/*
+**  Load window states to file which name is given in argument.
+*/
+gboolean sessionLoadWindowStates(gchar *);
+
+/*
+** Free allocated structure. Should be called before xfwm4 dies 
+*/
+void sessionFreeWindowStates(void);
+
+/*
+** Search for existing client in saved session and update
+** relevant client fields if found. 
+*/
+gboolean sessionMatchWinToSM(Client *);
+
+#endif /* __CLIENT_H__ */
-- 
GitLab