diff --git a/neercs/Makefile.am b/neercs/Makefile.am
index 3e33025..6324453 100644
--- a/neercs/Makefile.am
+++ b/neercs/Makefile.am
@@ -6,13 +6,15 @@ endif
 neercs_SOURCES = \
     neercs.cpp neercs.h \
     \
+    $(old_sources) \
+    \
     video/render.cpp video/render.h \
     video/text-render.cpp video/text-render.h \
     video/simple.lolfx \
     video/blurh.lolfx video/blurv.lolfx \
     video/remanency.lolfx video/glow.lolfx video/postfx.lolfx video/radial.lolfx \
     video/text.lolfx
-neercs_CPPFLAGS = @LOL_CFLAGS@ @PIPI_CFLAGS@ @CACA_CFLAGS@
+neercs_CPPFLAGS = @LOL_CFLAGS@ @PIPI_CFLAGS@ @CACA_CFLAGS@ -Iold
 neercs_LDADD =
 neercs_LDFLAGS = $(top_builddir)/src/liblol.a \
                  @LOL_LIBS@ @PIPI_LIBS@ @CACA_LIBS@ @UTIL_LIBS@ @PAM_LIBS@
@@ -31,3 +33,32 @@ SUFFIXES = .lolfx
 .lolfx.o:
 	$(LOLFX_BUILD)
 
+old_sources = \
+    old/actions.c \
+    old/ansi.c \
+    old/attach.c \
+    old/client.c \
+    old/configuration.c \
+    old/effects.c \
+    old/grab.c \
+    old/help.c \
+    old/input.c \
+    old/lock.c \
+    old/main.c \
+    old/mygetopt.c \
+    old/mygetopt.h \
+    old/mytrace.c \
+    old/mytrace.h \
+    old/neercs.h \
+    old/python/interpreter.c \
+    old/python/py_module.c \
+    old/python/py_module.h \
+    old/recurrent.c \
+    old/screen_list.c \
+    old/screensaver.c \
+    old/screens.c \
+    old/server.c \
+    old/term.c \
+    old/widgets.c \
+    old/widgets.h \
+    old/wm.c
diff --git a/neercs/neercs.cpp b/neercs/neercs.cpp
index 415b5ff..70699f0 100644
--- a/neercs/neercs.cpp
+++ b/neercs/neercs.cpp
@@ -43,7 +43,12 @@ using namespace lol;
 #include "neercs.h"
 #include "video/render.h"
 
-Neercs::Neercs()
+extern "C"
+{
+#include "old/neercs.h"
+}
+
+Neercs::Neercs(int argc, char **argv)
   : m_ready(false),
     m_caca(caca_create_canvas(10, 10)),
     m_render(new Render(m_caca)),
@@ -140,7 +145,7 @@ int main(int argc, char **argv)
     _chdir("../..");
 #endif
 
-    new Neercs();
+    new Neercs(argc, argv);
     new DebugFps(2, 2);
     app.ShowPointer(false);
 
diff --git a/neercs/neercs.h b/neercs/neercs.h
index cefe7da..caf008e 100644
--- a/neercs/neercs.h
+++ b/neercs/neercs.h
@@ -14,7 +14,7 @@
 class Neercs : public WorldEntity
 {
 public:
-    Neercs();
+    Neercs(int argc, char **argv);
     virtual ~Neercs();
 
     char const *GetName() { return "<neercs>"; }
diff --git a/neercs/old/actions.c b/neercs/old/actions.c
new file mode 100644
index 0000000..4a882c3
--- /dev/null
+++ b/neercs/old/actions.c
@@ -0,0 +1,63 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                2008-2010 Pascal Terjan <pterjan@linuxfr.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include "config.h"
+#include <caca.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include "neercs.h"
+
+void dump_to_file(struct screen_list *screen_list)
+{
+    char filename[14] = "hardcopy.0";
+    int n = 0;
+    struct stat bufstat;
+    void * export;
+    size_t len, wrote;
+    FILE * out;
+
+    /* FIXME maybe use glob and get next one directly */
+    while (n<9999 && !stat(filename, &bufstat))
+    {
+        n++;
+        sprintf(&filename[9], "%d", n);
+    }
+    if (n>=9999)
+    {
+        debug("Too many hardcopy files in current directory\n");
+        return;
+    }
+
+    export = caca_export_canvas_to_memory(screen_list->cv, "ansi", &len);
+    if (!export)
+    {
+        debug("Failed to export to ansi\n");
+        return;
+    }
+
+    out = fopen(filename, "w");
+    if (!out)
+    {
+        debug("Failed to open output file %s: %s\n", filename, strerror(errno));
+        return;
+    }
+    wrote = fwrite(export, len, 1, out);
+    if (!wrote)
+    {
+        debug("Failed to write to output file: %s\n", strerror(errno));
+        return;
+    }
+    free(export);
+}
diff --git a/neercs/old/ansi.c b/neercs/old/ansi.c
new file mode 100644
index 0000000..2689e22
--- /dev/null
+++ b/neercs/old/ansi.c
@@ -0,0 +1,1149 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                2008-2010 Pascal Terjan <pterjan@linuxfr.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+#include "config.h"
+#include <string.h>
+#include <caca.h>
+#include "neercs.h"
+
+
+/* DEC ACS with common extensions */
+static uint32_t dec_acs(uint32_t uc)
+{
+    switch (uc)
+    {
+    case '+':
+        return 0x2192;          /* RIGHTWARDS ARROW */
+    case ',':
+        return 0x2190;          /* LEFTWARDS ARROW */
+    case '-':
+        return 0x2191;          /* UPWARDS ARROW */
+    case '.':
+        return 0x2193;          /* DOWNWARDS ARROW */
+    case '0':
+        return 0x25AE;          /* BLACK VERTICAL RECTANGLE */
+    case '_':
+        return 0x25AE;          /* BLACK VERTICAL RECTANGLE */
+    case '`':
+        return 0x25C6;          /* BLACK DIAMOND */
+    case 'a':
+        return 0x2592;          /* MEDIUM SHADE */
+    case 'b':
+        return 0x2409;          /* SYMBOL FOR HORIZONTAL TABULATION */
+    case 'c':
+        return 0x240C;          /* SYMBOL FOR FORM FEED */
+    case 'd':
+        return 0x240D;          /* SYMBOL FOR CARRIAGE RETURN */
+    case 'e':
+        return 0x240A;          /* SYMBOL FOR LINE FEED */
+    case 'f':
+        return 0x00B0;          /* DEGREE SIGN */
+    case 'g':
+        return 0x00B1;          /* PLUS-MINUS SIGN */
+    case 'h':
+        return 0x2424;          /* SYMBOL FOR NEWLINE */
+    case 'i':
+        return 0x240B;          /* SYMBOL FOR VERTICAL TABULATION */
+    case 'j':
+        return 0x2518;          /* BOX DRAWINGS LIGHT UP AND LEFT */
+    case 'k':
+        return 0x2510;          /* BOX DRAWINGS LIGHT DOWN AND LEFT */
+    case 'l':
+        return 0x250C;          /* BOX DRAWINGS LIGHT DOWN AND RIGHT */
+    case 'm':
+        return 0x2514;          /* BOX DRAWINGS LIGHT UP AND RIGHT */
+    case 'n':
+        return 0x253C;          /* BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
+    case 'o':
+        return 0x23BA;          /* HORIZONTAL SCAN LINE-1 */
+    case 'p':
+        return 0x23BB;          /* HORIZONTAL SCAN LINE-3 */
+    case 'q':
+        return 0x2500;          /* BOX DRAWINGS LIGHT HORIZONTAL */
+    case 'r':
+        return 0x23BC;          /* HORIZONTAL SCAN LINE-7 */
+    case 's':
+        return 0x23BD;          /* HORIZONTAL SCAN LINE-9 */
+    case 't':
+        return 0x251C;          /* BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
+    case 'u':
+        return 0x2524;          /* BOX DRAWINGS LIGHT VERTICAL AND LEFT */
+    case 'v':
+        return 0x2534;          /* BOX DRAWINGS LIGHT UP AND HORIZONTAL */
+    case 'w':
+        return 0x252C;          /* BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
+    case 'x':
+        return 0x2502;          /* BOX DRAWINGS LIGHT VERTICAL */
+    case 'y':
+        return 0x2264;          /* LESS-THAN OR EQUAL TO */
+    case 'z':
+        return 0x2265;          /* GREATER-THAN OR EQUAL TO */
+    case '{':
+        return 0x03C0;          /* GREEK SMALL LETTER PI */
+    case '|':
+        return 0x2260;          /* NOT EQUAL TO */
+    case '}':
+        return 0x00A3;          /* POUND SIGN */
+    case '~':
+        return 0x00B7;          /* MIDDLE DOT */
+    default:
+        return uc;
+    }
+};
+
+static void reset_conv_state(struct screen *);
+
+#define LITERAL2CHAR(i0,i1) (((i0) << 8) | (i1))
+
+#define LITERAL3CHAR(i0,i1,i2) LITERAL2CHAR(LITERAL2CHAR(i0, i1), i2)
+
+static void ansi_parse_grcm(struct screen *,
+                            unsigned int, unsigned int const *);
+
+inline int handle_single_char(unsigned char c, int *x, int *y,
+                              struct screen_list *screen_list,
+                              struct screen *sc);
+inline int handle_duplet(unsigned char const *buffer, struct screen *sc,
+                         unsigned int *skip, int top, int bottom, int width,
+                         int height);
+
+
+inline int handle_single_char(unsigned char c, int *x, int *y,
+                              struct screen_list *screen_list,
+                              struct screen *sc)
+{
+    if (c == '\r')
+    {
+        *x = 0;
+    }
+
+    else if (c == '\n')
+    {
+        *x = 0;
+        *y = *y + 1;
+    }
+    else if (c == '\a')
+    {
+        if (!sc->bell)
+            screen_list->in_bell = 10;
+        sc->bell = 1;
+    }
+
+    else if (c == '\t')
+    {
+        *x = (*x + 7) & ~7;
+    }
+
+    else if (c == '\x08')
+    {
+        if (*x > 0)
+            *x = *x - 1;
+    }
+    else if (c == '\x0b')
+    {
+        /* Vertical tab */
+        /* Not sure about the real meaning of it, just y++ for now */
+        if (*y < caca_get_canvas_height(sc->cv))
+            *y = *y + 1;
+    }
+    else if (c == '\x0e')
+    {
+        /* Shift Out (Ctrl-N) -> Switch to Alternate Character Set: invokes
+           the G1 character set. */
+        sc->conv_state.glr[0] = 1;
+    }
+
+    else if (c == '\x0f')
+    {
+        /* Shift In (Ctrl-O) -> Switch to Standard Character Set: invokes the
+           G0 character set. */
+        sc->conv_state.glr[0] = 0;
+    }
+    else
+    {
+        return 1;
+    }
+    return 0;
+}
+
+inline int handle_duplet(unsigned char const *buffer, struct screen *sc,
+                         unsigned int *skip, int top, int bottom, int width,
+                         int height)
+{
+    int i = 0, j, k;
+    unsigned int dummy = 0;
+
+    /* Single Shift Select of G2 Character Set (SS2: 0x8e): affects next
+       character only */
+    if (buffer[i] == '\033' && buffer[i + 1] == 'N')
+    {
+        sc->conv_state.ss = 2;
+        *skip += 1;
+    }
+    /* Reverse Index (RI) go up one line, reverse scroll if necessary */
+    else if (buffer[i] == '\033' && buffer[i + 1] == 'M')
+    {
+        /* FIXME : not sure about the meaning of 'go up one line' and 'if
+           necessary' words. Implemented as a scroller only. */
+        for (j = bottom - 1; j > top; j--)
+        {
+            for (k = 0; k < width; k++)
+            {
+                caca_put_char(sc->cv, k, j, caca_get_char(sc->cv, k, j - 1));
+                caca_put_attr(sc->cv, k, j, caca_get_attr(sc->cv, k, j - 1));
+            }
+        }
+        caca_draw_line(sc->cv, 0, top - 1, width - 1, top - 1, ' ');
+        *skip += 1;
+    }
+
+    /* Single Shift Select of G3 Character Set (SS2: 0x8f): affects next
+       character only */
+    else if (buffer[i] == '\033' && buffer[i + 1] == 'O')
+    {
+        sc->conv_state.ss = 3;
+        *skip += 1;
+    }
+
+    /* LOCKING-SHIFT TWO (LS2), ISO 2022, ECMA-48 (1986), ISO 6429 : 1988 */
+    else if (buffer[i] == '\033' && buffer[i + 1] == 'n')
+    {
+        sc->conv_state.glr[0] = 2;
+        *skip += 1;
+    }
+
+    /* LOCKING-SHIFT THREE (LS3) ISO 2022, ECMA-48 (1986), ISO 6429 : 1988 */
+    else if (buffer[i] == '\033' && buffer[i + 1] == 'o')
+    {
+        sc->conv_state.glr[0] = 3;
+        *skip += 1;
+    }
+
+    /* RESET TO INITIAL STATE (RIS), ECMA-48 (1986), ISO 6429 : 1988 */
+    else if (buffer[i] == '\033' && buffer[i + 1] == 'c')
+    {
+        sc->dfg = CACA_DEFAULT;
+        sc->dbg = CACA_DEFAULT;
+
+        caca_set_color_ansi(sc->cv, sc->dfg, sc->dbg);
+        sc->clearattr = caca_get_attr(sc->cv, -1, -1);
+        ansi_parse_grcm(sc, 1, &dummy);
+
+        reset_conv_state(sc);
+        *skip += 1;
+    }
+
+    /* Coding Method Delimiter (CMD), ECMA-48 (1991), ISO/IEC 6429:1992 (ISO
+       IR 189) */
+    else if (buffer[i] == '\033' && buffer[i + 1] == 'd')
+    {
+        reset_conv_state(sc);
+        *skip += 1;
+    }
+    else
+    {
+        return 1;
+    }
+
+    return 0;
+}
+
+
+long int import_term(struct screen_list *screen_list, struct screen *sc,
+                     void const *data, unsigned int size)
+{
+    unsigned char const *buffer = (unsigned char const *)data;
+    unsigned int i, j, k, skip, dummy = 0;
+    unsigned int width, height, top, bottom;
+    uint32_t savedattr;
+    int x = 0, y = 0, save_x = 0, save_y = 0;
+    char b[100];
+
+    debug("ansi : import_term\n");
+
+    width = caca_get_canvas_width(sc->cv);
+    height = caca_get_canvas_height(sc->cv);
+    x = caca_get_cursor_x(sc->cv);
+    y = caca_get_cursor_y(sc->cv);
+    top = 1;
+    bottom = height;
+
+    if (!sc->init)
+    {
+        sc->dfg = CACA_LIGHTGRAY;
+        sc->dbg = CACA_BLACK;
+
+        caca_set_color_ansi(sc->cv, sc->dfg, sc->dbg);
+        sc->clearattr = caca_get_attr(sc->cv, -1, -1);
+
+        ansi_parse_grcm(sc, 1, &dummy);
+
+        reset_conv_state(sc);
+
+        sc->init = 1;
+    }
+
+    for (i = 0; i < size; i += skip)
+    {
+        uint32_t ch = 0;
+        int wch = 0;
+
+        skip = 1;
+
+        /* Control codes (ASCII < \x20) */
+        if (!handle_single_char(buffer[i], &x, &y, screen_list, sc))
+        {
+        }
+
+        /* If there are not enough characters to parse the escape sequence,
+           wait until the next try. We require 3. */
+
+        else if (buffer[i] == '\033' && i + 2 >= size)
+            break;
+
+
+        else if (!handle_duplet(&buffer[i], sc, &skip,
+                                top, bottom, width, height))
+        {
+
+        }
+
+
+        /* GZDM4, G0-Designators, multi, 94^n chars [grandfathered short form
+           from ISO 2022:1986] */
+        else if (buffer[i] == '\033' && buffer[i + 1] == '$'
+                 && (buffer[i + 2] >= '@') && (buffer[i + 2] <= 'C'))
+        {
+            sc->conv_state.gn[0] = LITERAL2CHAR('$', buffer[i + 2]);
+            skip += 2;
+        }
+
+        /* GnDMx Gn-Designators, 9x^n chars; need one more char to distinguish
+           these */
+        else if (buffer[i] == '\033' && buffer[i + 1] == '$'
+                 && (i + 3 >= size))
+            break;
+
+        /* GZD4 G0-Designator, 94 chars */
+        else if (buffer[i] == '\033' && buffer[i + 1] == '(')
+        {
+            sc->conv_state.gn[0] = buffer[i + 2];
+            skip += 2;
+        }
+
+        /* G1D4 G1-Designator, 94 chars */
+        else if (buffer[i] == '\033' && buffer[i + 1] == ')')
+        {
+            sc->conv_state.gn[1] = buffer[i + 2];
+            skip += 2;
+        }
+
+        /* G2D4 G2-Designator, 94 chars */
+        else if (buffer[i] == '\033' && buffer[i + 1] == '*')
+        {
+            sc->conv_state.gn[2] = buffer[i + 2];
+            skip += 2;
+        }
+
+        /* G3D4 G3-Designator, 94 chars */
+        else if (buffer[i] == '\033' && buffer[i + 1] == '+')
+        {
+            sc->conv_state.gn[3] = buffer[i + 2];
+            skip += 2;
+        }
+
+        /* G2D6 G2-Designator, 96 chars */
+        else if (buffer[i] == '\033' && buffer[i + 1] == '.')
+        {
+            sc->conv_state.gn[2] = LITERAL2CHAR('.', buffer[i + 2]);
+            skip += 2;
+        }
+
+        /* G3D6 G3-Designator, 96 chars */
+        else if (buffer[i] == '\033' && buffer[i + 1] == '/')
+        {
+            sc->conv_state.gn[3] = LITERAL2CHAR('.', buffer[i + 2]);
+            skip += 2;
+        }
+
+        /* GZDM4 G0-Designator, 94^n chars */
+        else if (buffer[i] == '\033' && buffer[i + 1] == '$'
+                 && buffer[i + 2] == '(')
+        {
+            sc->conv_state.gn[0] = LITERAL2CHAR('$', buffer[i + 3]);
+            skip += 3;
+        }
+
+        /* G1DM4 G1-Designator, 94^n chars */
+        else if (buffer[i] == '\033' && buffer[i + 1] == '$'
+                 && buffer[i + 2] == ')')
+        {
+            sc->conv_state.gn[1] = LITERAL2CHAR('$', buffer[i + 3]);
+            skip += 3;
+        }
+
+        /* G2DM4 G2-Designator, 94^n chars */
+        else if (buffer[i] == '\033' && buffer[i + 1] == '$'
+                 && buffer[i + 2] == '*')
+        {
+            sc->conv_state.gn[2] = LITERAL2CHAR('$', buffer[i + 3]);
+            skip += 3;
+        }
+
+        /* G3DM4 G3-Designator, 94^n chars */
+        else if (buffer[i] == '\033' && buffer[i + 1] == '$'
+                 && buffer[i + 2] == '+')
+        {
+            sc->conv_state.gn[3] = LITERAL2CHAR('$', buffer[i + 3]);
+            skip += 3;
+        }
+
+        /* G2DM6 G2-Designator, 96^n chars */
+        else if (buffer[i] == '\033' && buffer[i + 1] == '$'
+                 && buffer[i + 2] == '.')
+        {
+            sc->conv_state.gn[2] = LITERAL3CHAR('$', '.', buffer[i + 3]);
+            skip += 3;
+        }
+
+        /* G3DM6 G3-Designator, 96^n chars */
+        else if (buffer[i] == '\033' && buffer[i + 1] == '$'
+                 && buffer[i + 2] == '/')
+        {
+            sc->conv_state.gn[3] = LITERAL3CHAR('$', '.', buffer[i + 3]);
+            skip += 3;
+        }
+        else if (buffer[i] == '\033' && buffer[i + 1] == '#')
+        {
+            debug("ansi private '#' sequence\n");
+
+            switch (buffer[i + 2])
+            {
+            case '8':          /* DECALN Fills the entire screen area with
+                                   uppercase Es for screen focus and
+                                   alignment. */
+                for (j = 0; j < height; j++)
+                {
+                    for (k = 0; k < width; k++)
+                    {
+                        caca_put_char(sc->cv, k, j, 'E');
+                    }
+                }
+                x = 0;
+                y = 0;
+                skip += 2;
+                break;
+
+            default:
+                debug("Unknow private sequence 'ESC#%c'\n", buffer[i + 2]);
+                continue;
+            }
+
+        }
+        /* Interpret escape commands, as per Standard ECMA-48 "Control
+           Functions for Coded Character Sets", 5.4. Control sequences. */
+        else if (buffer[i] == '\033' && buffer[i + 1] == '[')
+        {
+            unsigned int argc = 0, argv[101];
+            unsigned int param, inter, junk, final;
+
+            if (buffer[i + 2] == '?')
+            {
+                debug("CSI? %c%c%c%c%c\n",
+                      buffer[i + 3], buffer[i + 4], buffer[i + 5],
+                      buffer[i + 6], buffer[i + 7]);
+            }
+
+            /* Compute offsets to parameter bytes, intermediate bytes and to
+               the final byte. Only the final byte is mandatory, there can be
+               zero of the others. 0 param=2 inter final final+1
+               +-----+------------------+---------------------+-----------------+
+               | CSI | parameter bytes | intermediate bytes | final byte | | |
+               0x30 - 0x3f | 0x20 - 0x2f | 0x40 - 0x7e | | ^[[ | 0123456789:;<=>?
+               | SPC !"#$%&'()*+,-./ | azAZ@[\]^_`{|}~ |
+               +-----+------------------+---------------------+-----------------+ */
+            param = 2;
+
+            /* vttest use to interleave control characters (\014 CR or \010
+               BS) into CSI sequences, either directly after ESC[ or after
+               param. Can't find anything related to this in any documentation
+               nor XTerm sources, thought. */
+
+            for (junk = param; i + junk < size; junk++)
+                if (buffer[i + junk] < 0x20)
+                {
+                    handle_single_char(buffer[i + junk], &x, &y, screen_list,
+                                       sc);
+                }
+                else
+                {
+                    break;
+                }
+
+            /* Intermediate offset */
+            for (inter = junk; i + inter < size; inter++)
+                if (buffer[i + inter] < 0x30 || buffer[i + inter] > 0x3f)
+                {
+                    break;
+                }
+            /* Interleaved character */
+            for (junk = inter; i + junk < size; junk++)
+                if (buffer[i + junk] < 0x20)
+                {
+                    handle_single_char(buffer[i + junk], &x, &y, screen_list,
+                                       sc);
+                }
+                else
+                {
+                    break;
+                }
+
+            /* Final Byte offset */
+            for (final = junk; i + final < size; final++)
+                if (buffer[i + final] < 0x20 || buffer[i + final] > 0x2f)
+                {
+                    break;
+                }
+            if (i + final >= size
+                || buffer[i + final] < 0x40 || buffer[i + final] > 0x7e)
+            {
+                debug("ansi Invalid Final Byte (%d %c)\n", buffer[i + final],
+                      buffer[i + final]);
+                break;          /* Invalid Final Byte */
+            }
+
+            skip += final;
+
+            /* Sanity checks */
+            if (param < inter && buffer[i + param] >= 0x3c)
+            {
+                /* Private sequence, only parse what we know */
+                debug("ansi import: private sequence \"^[[%.*s\"",
+                      final - param + 1, buffer + i + param);
+                /* FIXME better parsing */
+                if (buffer[i + 2] == '?')
+                {
+                    char arg[5];
+                    int a = 0;
+                    int c, p;
+                    for (p = 0; p < 4; p++)
+                    {
+                        if (buffer[i + 3 + p] >= '0'
+                            && buffer[i + 3 + p] <= '9')
+                        {
+                            arg[a] = buffer[i + 3 + p];
+                            arg[a + 1] = 0;
+                            a++;
+                            debug("private a now '%s'\n", arg);
+                        }
+                        else
+                        {
+                            break;
+                        }
+                    }
+                    char *end;
+                    int Pm = strtol(arg, &end, 10);
+
+                    c = buffer[i + 3 + (end - arg)];
+
+                    debug("ansi private mouse : command %c, arg %d", c, Pm);
+                    if (c == 'h')       /* DECSET DEC Private Mode Set */
+                    {
+
+                        switch (Pm)
+                        {
+                            /* FIXME Handle different modes */
+                        case 9:
+                            debug("mouse : X10 mode\n");
+                            sc->report_mouse = MOUSE_X10;
+                            break;
+                        case 1000:     /* Send Mouse X & Y on button press
+                                           and release.  */
+                                debug("mouse : VT200 mode\n");
+                            sc->report_mouse = MOUSE_VT200;
+                            break;
+                        case 1001:     /* Use Hilite Mouse Tracking.  */
+                                debug("mouse : VT200_HIGHLIGHT mode\n");
+                            sc->report_mouse = MOUSE_VT200_HIGHLIGHT;
+                            break;
+                        case 1002:     /* Use Cell Motion Mouse Tracking. */
+                                debug("mouse : BTN mode\n");
+                            sc->report_mouse = MOUSE_BTN_EVENT;
+                            break;
+                        case 1003:     /* Use All Motion Mouse Tracking.  */
+                                debug("mouse : ANY mode\n");
+                            sc->report_mouse = MOUSE_ANY_EVENT;
+                            break;
+                        default:
+                            break;
+                        }
+                    }
+                    else if (c == 'l')  /* DECRST DEC Private Mode Reset */
+                    {
+                        Pm = atoi(arg);
+                        switch (Pm)
+                        {
+                            /* FIXME Handle different modes */
+                        case 9:
+                        case 1000:     /* Send Mouse X & Y on button press
+                                           and release.  */
+                        case 1001:     /* Use Hilite Mouse Tracking.  */
+                        case 1002:     /* Use Cell Motion Mouse Tracking. */
+                        case 1003:     /* Use All Motion Mouse Tracking.  */
+                            sc->report_mouse = MOUSE_NONE;
+                            debug("ansi private mouse : NOT reporting mouse");
+                            break;
+                        default:
+                            break;
+                        }
+                    }
+                }
+                continue;       /* Private sequence, skip it entirely */
+            }
+
+            if (final - param > 100)
+                continue;       /* Suspiciously long sequence, skip it */
+
+            /* Parse parameter bytes as per ECMA-48 5.4.2: Parameter string
+               format */
+            if (param < inter)
+            {
+                argv[0] = 0;
+                for (j = param; j < inter; j++)
+                {
+                    if (buffer[i + j] == ';')
+                        argv[++argc] = 0;
+                    else if (buffer[i + j] >= '0' && buffer[i + j] <= '9')
+                        argv[argc] = 10 * argv[argc] + (buffer[i + j] - '0');
+                }
+                argc++;
+            }
+
+            /* Interpret final byte. The code representations are given in
+               ECMA-48 5.4: Control sequences, and the code definitions are
+               given in ECMA-48 8.3: Definition of control functions. */
+            debug("ansi import: command '%c'", buffer[i + final]);
+            switch (buffer[i + final])
+            {
+            case 'A':          /* CUU (0x41) - Cursor Up */
+                y -= argc ? argv[0] : 1;
+                if (y < 0)
+                    y = 0;
+                break;
+            case 'B':          /* CUD (0x42) - Cursor Down */
+                y += argc ? argv[0] : 1;
+                break;
+            case 'C':          /* CUF (0x43) - Cursor Right */
+                x += argc ? argv[0] : 1;
+                break;
+            case 'D':          /* CUB (0x44) - Cursor Left */
+                x -= argc ? argv[0] : 1;
+                if (x < 0)
+                    x = 0;
+                break;
+            case 'G':          /* CHA (0x47) - Cursor Character Absolute */
+                x = (argc && argv[0] > 0) ? argv[0] - 1 : 0;
+                break;
+            case 'H':          /* CUP (0x48) - Cursor Position */
+                x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0;
+                y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0;
+                debug("ansi CUP : Cursor at %dx%d\n", x, y);
+                break;
+            case 'J':          /* ED (0x4a) - Erase In Page */
+                savedattr = caca_get_attr(sc->cv, -1, -1);
+                caca_set_attr(sc->cv, sc->clearattr);
+                if (!argc || argv[0] == 0)
+                {
+                    caca_draw_line(sc->cv, x, y, width, y, ' ');
+                    caca_fill_box(sc->cv, 0, y + 1, width, height - 1, ' ');
+                }
+                else if (argv[0] == 1)
+                {
+                    caca_fill_box(sc->cv, 0, 0, width, y, ' ');
+                    caca_draw_line(sc->cv, 0, y, x, y, ' ');
+                }
+                else if (argv[0] == 2)
+                {
+                    // x = y = 0;
+                    caca_fill_box(sc->cv, 0, 0, width, height, ' ');
+                }
+                caca_set_attr(sc->cv, savedattr);
+                break;
+            case 'K':          /* EL (0x4b) - Erase In Line */
+                debug("ansi EL : cursor at %dx%d\n", x, y);
+                if (!argc || argv[0] == 0)
+                {
+                    caca_draw_line(sc->cv, x, y, width, y, ' ');
+                }
+                else if (argv[0] == 1)
+                {
+                    caca_draw_line(sc->cv, 0, y, x, y, ' ');
+                }
+                else if (argv[0] == 2)
+                {
+                    caca_draw_line(sc->cv, 0, y, width, y, ' ');
+                }
+                break;
+            case 'L':          /* IL - Insert line */
+                {
+                    unsigned int nb_lines = argc ? argv[0] : 1;
+                    for (j = bottom - 1; j >= (unsigned int)y + nb_lines; j--)
+                    {
+                        for (k = 0; k < width; k++)
+                        {
+                            caca_put_char(sc->cv, k, j,
+                                          caca_get_char(sc->cv, k,
+                                                        j - nb_lines));
+                            caca_put_attr(sc->cv, k, j,
+                                          caca_get_attr(sc->cv, k,
+                                                        j - nb_lines));
+                        }
+                        caca_draw_line(sc->cv, 0, j - nb_lines, width,
+                                       j - nb_lines, ' ');
+                    }
+                }
+                break;
+            case 'P':          /* DCH (0x50) - Delete Character */
+                if (!argc || argv[0] == 0)
+                    argv[0] = 1;        /* echo -ne 'foobar\r\e[0P\n' */
+
+                for (j = x; (unsigned int)(j + argv[0]) < width; j++)
+                {
+                    caca_put_char(sc->cv, j, y,
+                                  caca_get_char(sc->cv, j + argv[0], y));
+                    caca_put_attr(sc->cv, j, y,
+                                  caca_get_attr(sc->cv, j + argv[0], y));
+                }
+                break;
+#if 0
+                savedattr = caca_get_attr(sc->cv, -1, -1);
+                caca_set_attr(sc->cv, sc->clearattr);
+                for (; (unsigned int)j < width; j++)
+                    caca_put_char(sc->cv, j, y, ' ');
+                caca_set_attr(sc->cv, savedattr);
+#endif
+            case 'X':          /* ECH (0x58) - Erase Character */
+                if (argc && argv[0])
+                {
+                    savedattr = caca_get_attr(sc->cv, -1, -1);
+                    caca_set_attr(sc->cv, sc->clearattr);
+                    caca_draw_line(sc->cv, x, y, x + argv[0] - 1, y, ' ');
+                    caca_set_attr(sc->cv, savedattr);
+                }
+            case 'c':          /* DA -- Device Attributes */
+                /*
+                   0 Base VT100, no options 1 Processor options (STP) 2
+                   Advanced video option (AVO) 3 AVO and STP 4 Graphics
+                   processor option (GPO) 5 GPO and STP 6 GPO and AVO 7 GPO,
+                   STP, and AVO */
+                /* Warning, argument is Pn */
+                debug("ansi Got command c, argc %d, argv[0] (%d)\n", argc,
+                      argv[0], argv[0]);
+                if (!argc || argv[0] == 0)
+                {
+                    send_ansi_sequence(screen_list, "\x1b[?1;0c");
+                }
+                else
+                {
+                    switch (argv[0])
+                    {
+                    case 1:
+                        send_ansi_sequence(screen_list, "\x1b[?\x1;\x1c");
+                        break;
+                    case 2:
+                        send_ansi_sequence(screen_list, "\x1b[?\x1;\x2c");
+                        break;
+                    case 3:
+                        send_ansi_sequence(screen_list, "\x1b[?\x1;\x3c");
+                        break;
+                    case 4:
+                        send_ansi_sequence(screen_list, "\x1b[?\x1;\x4c");
+                        break;
+                    case 5:
+                        send_ansi_sequence(screen_list, "\x1b[?\x1;\x5c");
+                        break;
+                    case 6:
+                        send_ansi_sequence(screen_list, "\x1b[?\x1;\x6c");
+                        break;
+                    case 7:
+                        send_ansi_sequence(screen_list, "\x1b[?\x1;\x7c");
+                        break;
+                    default:
+                        debug("Unsupported DA option '%d'\n", argv[0]);
+                        break;
+                    }
+                }
+                break;
+            case 'd':          /* VPA (0x64) - Line Position Absolute */
+                y = (argc && argv[0] > 0) ? argv[0] - 1 : 0;
+                break;
+            case 'f':          /* HVP (0x66) - Character And Line Position */
+                x = (argc > 1 && argv[1] > 0) ? argv[1] - 1 : 0;
+                y = (argc > 0 && argv[0] > 0) ? argv[0] - 1 : 0;
+                break;
+            case 'g':          /* TBC -- Tabulation Clear */
+                break;
+            case 'r':          /* FIXME */
+                if (argc == 2)  /* DCSTBM - Set top and bottom margin */
+                {
+                    debug("DCSTBM %d %d", argv[0], argv[1]);
+                    top = argv[0];
+                    bottom = argv[1];
+                }
+                else
+                    debug("ansi import: command r with %d params", argc);
+                break;
+            case 'h':          /* SM (0x68) - FIXME */
+                debug("ansi import: set mode %i", argc ? (int)argv[0] : -1);
+                break;
+            case 'l':          /* RM (0x6c) - FIXME */
+                debug("ansi import: reset mode %i", argc ? (int)argv[0] : -1);
+                break;
+            case 'm':          /* SGR (0x6d) - Select Graphic Rendition */
+                if (argc)
+                    ansi_parse_grcm(sc, argc, argv);
+                else
+                    ansi_parse_grcm(sc, 1, &dummy);
+                break;
+            case 'n':
+                debug("ansi command n, argc %d, argv[0] %d\n", argc, argv[0]);
+                if (!argc)
+                    break;
+
+                switch (argv[0])
+                {
+                case 5:
+                    /* Term ok */
+                    send_ansi_sequence(screen_list, "\x1b[0n");
+                    break;
+                case 6:
+                    /* Cursor Position */
+                    sprintf(b, "\x1b[%d;%dR", y + 1, x + 1);
+                    send_ansi_sequence(screen_list, b);
+                    break;
+                }
+
+                break;
+            case 's':          /* Private (save cursor position) */
+                save_x = x;
+                save_y = y;
+                break;
+            case 'u':          /* Private (reload cursor position) */
+                x = save_x;
+                y = save_y;
+                break;
+            default:
+                debug("ansi import: unknown command \"^[%.*s\"",
+                      final - param + 1, buffer + i + param);
+                break;
+            }
+        }
+
+        /* Parse OSC stuff. */
+        else if (buffer[i] == '\033' && buffer[i + 1] == ']')
+        {
+            char *string;
+            unsigned int command = 0;
+            unsigned int mode = 2, semicolon, final;
+
+            for (semicolon = mode; i + semicolon < size; semicolon++)
+            {
+                if (buffer[i + semicolon] < '0' || buffer[i + semicolon] > '9')
+                    break;
+                command = 10 * command + (buffer[i + semicolon] - '0');
+            }
+
+            if (i + semicolon >= size || buffer[i + semicolon] != ';')
+                break;          /* Invalid Mode */
+
+            for (final = semicolon + 1; i + final < size; final++)
+                if (buffer[i + final] < 0x20)
+                    break;
+
+            if (i + final >= size || buffer[i + final] != '\a')
+                break;          /* Not enough data or no bell found */
+            /* FIXME: XTerm also reacts to <ESC><backslash> and <ST> */
+            /* FIXME: differenciate between not enough data (try again) and
+               invalid data (print shit) */
+
+            skip += final;
+
+            string = malloc(final - (semicolon + 1) + 1);
+            memcpy(string, buffer + i + (semicolon + 1),
+                   final - (semicolon + 1));
+            string[final - (semicolon + 1)] = '\0';
+            debug("ansi import: got OSC command %i string '%s'", command,
+                  string);
+            if (command == 0 || command == 2)
+            {
+                if (sc->title)
+                    free(sc->title);
+                sc->title = string;
+            }
+            else
+                free(string);
+        }
+
+        /* Get the character we’re going to paste */
+        else
+        {
+            size_t bytes;
+
+            if (i + 6 < size)
+            {
+                ch = caca_utf8_to_utf32((char const *)(buffer + i), &bytes);
+            }
+            else
+            {
+                /* Add a trailing zero to what we're going to read */
+                char tmp[7];
+                memcpy(tmp, buffer + i, size - i);
+                tmp[size - i] = '\0';
+                ch = caca_utf8_to_utf32(tmp, &bytes);
+            }
+
+            if (!bytes)
+            {
+                /* If the Unicode is invalid, assume it was latin1. */
+                ch = buffer[i];
+                bytes = 1;
+            }
+
+            /* very incomplete ISO-2022 implementation tailored to DEC ACS */
+            if (sc->conv_state.cs == '@')
+            {
+                if (((ch > ' ') && (ch <= '~'))
+                    &&
+                    (sc->conv_state.
+                     gn[sc->conv_state.ss ? sc->conv_state.
+                        gn[sc->conv_state.ss] : sc->conv_state.glr[0]] == '0'))
+                {
+                    ch = dec_acs(ch);
+                }
+                else if (((ch > 0x80) && (ch < 0xff))
+                         && (sc->conv_state.gn[sc->conv_state.glr[1]] == '0'))
+                {
+                    ch = dec_acs(ch + ' ' - 0x80);
+                }
+            }
+            sc->conv_state.ss = 0;      /* no single-shift (GL) */
+
+            wch = caca_utf32_is_fullwidth(ch) ? 2 : 1;
+
+            skip += bytes - 1;
+        }
+
+        /* Wrap long lines or grow horizontally */
+        while ((unsigned int)x + wch > width)
+        {
+            x -= width;
+            y++;
+        }
+
+        /* Scroll or grow vertically */
+        if ((unsigned int)y >= bottom)
+        {
+            int lines = (y - bottom) + 1;
+
+            savedattr = caca_get_attr(sc->cv, -1, -1);
+
+            for (j = top - 1; j + lines < bottom; j++)
+            {
+                for (k = 0; k < width; k++)
+                {
+                    caca_put_char(sc->cv, k, j,
+                                  caca_get_char(sc->cv, k, j + lines));
+                    caca_put_attr(sc->cv, k, j,
+                                  caca_get_attr(sc->cv, k, j + lines));
+                }
+            }
+            caca_set_attr(sc->cv, sc->clearattr);
+            caca_fill_box(sc->cv, 0, bottom - lines, width, bottom - 1, ' ');
+            y -= lines;
+            caca_set_attr(sc->cv, savedattr);
+        }
+
+        /* Now paste our character, if any */
+        if (wch)
+        {
+            caca_put_char(sc->cv, x, y, ch);
+            x += wch;
+        }
+    }
+
+    caca_gotoxy(sc->cv, x, y);
+
+    if (i)
+        sc->changed = 1;
+    return i;
+}
+
+/* Coding Method Delimiter (CMD), ECMA-48 (1991), ISO/IEC 6429:1992 (ISO IR
+   189) */
+
+static void reset_conv_state(struct screen *sc)
+{
+    sc->conv_state.cs = '@';    /* ISO-2022 coding system */
+    sc->conv_state.cn[0] = '@'; /* ISO 646 C0 control charset */
+    sc->conv_state.cn[1] = 'C'; /* ISO 6429-1983 C1 control charset */
+    sc->conv_state.glr[0] = 0;  /* G0 in GL */
+    sc->conv_state.glr[1] = 2;  /* G2 in GR */
+    sc->conv_state.gn[0] = 'B'; /* US-ASCII G0 charset */
+    sc->conv_state.gn[1] = '0'; /* DEC ACS G1 charset */
+    sc->conv_state.gn[2] = LITERAL2CHAR('.', 'A');      /* ISO 8859-1 G2
+                                                           charset */
+    sc->conv_state.gn[3] = LITERAL2CHAR('.', 'A');      /* ISO 8859-1 G3
+                                                           charset */
+    sc->conv_state.ss = 0;      /* no single-shift (GL) */
+    sc->conv_state.ctrl8bit = 1;
+}
+
+/* XXX : ANSI loader helper */
+
+static void ansi_parse_grcm(struct screen *sc,
+                            unsigned int argc, unsigned int const *argv)
+{
+    static uint8_t const ansi2caca[] = {
+        CACA_BLACK, CACA_RED, CACA_GREEN, CACA_BROWN,
+        CACA_BLUE, CACA_MAGENTA, CACA_CYAN, CACA_LIGHTGRAY
+    };
+
+    unsigned int j;
+    uint8_t efg, ebg;           /* Effective (libcaca) fg/bg */
+
+    for (j = 0; j < argc; j++)
+    {
+        /* Defined in ECMA-48 8.3.117: SGR - SELECT GRAPHIC RENDITION */
+        if (argv[j] >= 30 && argv[j] <= 37)
+            sc->fg = ansi2caca[argv[j] - 30];
+        else if (argv[j] >= 40 && argv[j] <= 47)
+            sc->bg = ansi2caca[argv[j] - 40];
+        else if (argv[j] >= 90 && argv[j] <= 97)
+            sc->fg = ansi2caca[argv[j] - 90] + 8;
+        else if (argv[j] >= 100 && argv[j] <= 107)
+            sc->bg = ansi2caca[argv[j] - 100] + 8;
+        else
+            switch (argv[j])
+            {
+            case 0:            /* default rendition */
+                sc->fg = sc->dfg;
+                sc->bg = sc->dbg;
+                sc->bold = sc->blink = sc->italics = sc->negative
+                    = sc->concealed = sc->underline = sc->faint = sc->strike
+                    = sc->proportional = 0;
+                break;
+            case 1:            /* bold or increased intensity */
+                sc->bold = 1;
+                break;
+            case 2:            /* faint, decreased intensity or second colour
+                                 */
+                sc->faint = 1;
+                break;
+            case 3:            /* italicized */
+                sc->italics = 1;
+                break;
+            case 4:            /* singly underlined */
+                sc->underline = 1;
+                break;
+            case 5:            /* slowly blinking (less then 150 per minute) */
+            case 6:            /* rapidly blinking (150 per minute or more) */
+                sc->blink = 1;
+                break;
+            case 7:            /* negative image */
+                sc->negative = 1;
+                break;
+            case 8:            /* concealed characters */
+                sc->concealed = 1;
+                break;
+            case 9:            /* crossed-out (characters still legible but
+                                   marked as to be deleted */
+                sc->strike = 1;
+                break;
+            case 21:           /* doubly underlined */
+                sc->underline = 1;
+                break;
+            case 22:           /* normal colour or normal intensity (neither
+                                   bold nor faint) */
+                sc->bold = sc->faint = 0;
+                break;
+            case 23:           /* not italicized, not fraktur */
+                sc->italics = 0;
+                break;
+            case 24:           /* not underlined (neither singly nor doubly) */
+                sc->underline = 0;
+                break;
+            case 25:           /* steady (not blinking) */
+                sc->blink = 0;
+                break;
+            case 26:           /* (reserved for proportional spacing as
+                                   specified in CCITT Recommendation T.61) */
+                sc->proportional = 1;
+                break;
+            case 27:           /* positive image */
+                sc->negative = 0;
+                break;
+            case 28:           /* revealed characters */
+                sc->concealed = 0;
+                break;
+            case 29:           /* not crossed out */
+                sc->strike = 0;
+                break;
+            case 38:           /* (reserved for future standardization,
+                                   intended for setting character foreground
+                                   colour as specified in ISO 8613-6 [CCITT
+                                   Recommendation T.416]) */
+                break;
+            case 39:           /* default display colour
+                                   (implementation-defined) */
+                sc->fg = sc->dfg;
+                break;
+            case 48:           /* (reserved for future standardization,
+                                   intended for setting character background
+                                   colour as specified in ISO 8613-6 [CCITT
+                                   Recommendation T.416]) */
+                break;
+            case 49:           /* default background colour
+                                   (implementation-defined) */
+                sc->bg = sc->dbg;
+                break;
+            case 50:           /* (reserved for cancelling the effect of the
+                                   rendering aspect established by parameter
+                                   value 26) */
+                sc->proportional = 0;
+                break;
+            default:
+                debug("ansi import: unknown sgr %i", argv[j]);
+                break;
+            }
+    }
+
+    if (sc->concealed)
+    {
+        efg = ebg = CACA_TRANSPARENT;
+    }
+    else
+    {
+        efg = sc->negative ? sc->bg : sc->fg;
+        ebg = sc->negative ? sc->fg : sc->bg;
+
+        if (sc->bold)
+        {
+            if (efg < 8)
+                efg += 8;
+            else if (efg == CACA_DEFAULT)
+                efg = CACA_WHITE;
+        }
+    }
+
+    caca_set_color_ansi(sc->cv, efg, ebg);
+}
diff --git a/neercs/old/attach.c b/neercs/old/attach.c
new file mode 100644
index 0000000..8a57d5e
--- /dev/null
+++ b/neercs/old/attach.c
@@ -0,0 +1,424 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                2008-2010 Pascal Terjan <pterjan@linuxfr.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <glob.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <caca.h>
+
+#include "config.h"
+#include "neercs.h"
+
+char *build_socket_path(char *socket_dir, char *session_name,
+                        enum socket_type socktype)
+{
+    char *path, *dir;
+    path = (char *)malloc(PATH_MAX + 1);
+    dir = socket_dir;
+    if (!dir)
+        dir = getenv("NEERCSDIR");
+    if (!dir)
+        dir = getenv("TMPDIR");
+    if (!dir)
+        dir = "/tmp";
+    if (path)
+        snprintf(path, PATH_MAX + 1, "%s/neercs.%s%s.sock", dir, session_name,
+                 socktype ? "" : ".srv");
+    return path;
+}
+
+static char *socket_to_session(char const *sockpath)
+{
+    char *p, *s;
+    p = strrchr(sockpath, '/');
+    if (!p)
+    {
+        debug("Invalid socket path %s", sockpath);
+        return NULL;
+    }
+    p += 8;                     /* skip neercs. */
+    s = strdup(p);
+    p = strrchr(s, '.');
+    *p = '\0';                  /* drop .sock */
+    p = strrchr(s, '.');
+    *p = '\0';                  /* drop .srv */
+    p = strdup(s);
+    free(s);
+    return p;
+}
+
+int create_socket(struct screen_list *screen_list, enum socket_type socktype)
+{
+    int sock;
+    struct sockaddr_un myaddr;
+
+    sock = socket(AF_UNIX, SOCK_DGRAM, 0);
+
+    if (sock < 0)
+    {
+        perror("create_socket:socket");
+        return errno;
+    }
+
+    memset(&myaddr, 0, sizeof(struct sockaddr_un));
+
+    myaddr.sun_family = AF_UNIX;
+    strncpy(myaddr.sun_path, screen_list->comm.socket_path[socktype],
+            sizeof(myaddr.sun_path) - 1);
+
+    unlink(screen_list->comm.socket_path[socktype]);
+
+    if (bind(sock, (struct sockaddr *)&myaddr, sizeof(struct sockaddr_un)) < 0)
+    {
+        free(screen_list->comm.socket_path[socktype]);
+        screen_list->comm.socket_path[socktype] = NULL;
+        close(sock);
+        perror("create_socket:bind");
+        return errno;
+    }
+    fcntl(sock, F_SETFL, O_NONBLOCK);
+
+    debug("Listening on %s (%d)", screen_list->comm.socket_path[socktype], sock);
+
+    screen_list->comm.socket[socktype] = sock;
+
+    return 0;
+}
+
+char **list_sockets(char *socket_dir, char *session_name)
+{
+    char *pattern, *dir;
+    glob_t globbuf;
+
+    globbuf.gl_pathv = NULL;
+
+    pattern = (char *)malloc(PATH_MAX + 1);
+
+    dir = socket_dir;
+    if (!dir)
+        dir = getenv("NEERCSDIR");
+    if (!dir)
+        dir = getenv("TMPDIR");
+    if (!dir)
+        dir = "/tmp";
+
+    if (!pattern)
+        return globbuf.gl_pathv;
+
+    if (session_name && strlen(session_name) + strlen(dir) + 13 < PATH_MAX)
+        sprintf(pattern, "%s/neercs.%s.srv.sock", dir, session_name);
+    else
+        snprintf(pattern, PATH_MAX, "%s/neercs.*.srv.sock", dir);
+    pattern[PATH_MAX] = '\0';
+
+    debug("Looking for sockets in the form %s", pattern);
+
+    glob(pattern, 0, NULL, &globbuf);
+
+    free(pattern);
+
+    return globbuf.gl_pathv;
+}
+
+char *connect_socket(struct screen_list *screen_list,
+                     enum socket_type socktype)
+{
+    int sock;
+    struct sockaddr_un addr;
+
+    debug("Connecting to %s", screen_list->comm.socket_path[socktype]);
+
+    /* Open the socket */
+    if ((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
+    {
+        debug("Failed to create socket\n");
+        perror("connect_server:socket");
+        return NULL;
+    }
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    strcpy(addr.sun_path, screen_list->comm.socket_path[socktype]);
+    if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+    {
+        debug("Failed to connect to %s: %s",
+              screen_list->comm.socket_path[socktype], strerror(errno));
+        close(sock);
+        return NULL;
+    }
+    fcntl(sock, F_SETFL, O_NONBLOCK);
+
+    screen_list->comm.socket[socktype] = sock;
+
+    if (socktype == SOCK_SERVER)
+    {
+        return socket_to_session(screen_list->comm.socket_path[socktype]);
+    }
+    else
+        return NULL;
+}
+
+int request_attach(struct screen_list *screen_list)
+{
+    char buf[41];
+    int bytes;
+
+    bytes = snprintf(buf, sizeof(buf) - 1, "ATTACH %10d %10d %10d",
+                     caca_get_canvas_width(screen_list->cv),
+                     caca_get_canvas_height(screen_list->cv),
+                     screen_list->delay);
+    buf[bytes] = '\0';
+    debug("Requesting attach: %s", buf);
+    return write(screen_list->comm.socket[SOCK_SERVER], buf, strlen(buf)) <= 0;
+}
+
+static char *select_socket(struct screen_list *screen_list)
+{
+    char **sockets = NULL, **usable_sockets = NULL;
+    int i, sock, nb_usable_sockets = 0;
+    char *ret = NULL;
+
+    sockets = list_sockets(screen_list->comm.socket_dir, screen_list->comm.session_name);
+    if (sockets)
+    {
+        for (i = 0; sockets[i]; i++);
+
+        /* Return the socket or NULL if there is not more than one match */
+        if (i <= 1)
+        {
+            if (sockets[0])
+                ret = strdup(sockets[0]);
+            goto end;
+        }
+
+        /* Else ask the user to chose one */
+        usable_sockets = malloc(i * sizeof(char *));
+        for (i = 0; sockets[i]; i++)
+        {
+            struct sockaddr_un addr;
+            if ((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
+            {
+                perror("select_socket:socket");
+                goto end;
+            }
+            memset(&addr, 0, sizeof(addr));
+            addr.sun_family = AF_UNIX;
+            strcpy(addr.sun_path, sockets[i]);
+            if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+            {
+                switch (errno)
+                {
+                case EACCES:
+                    debug("Connection refused on %s", sockets[i]);
+                    break;
+                case ECONNREFUSED:
+                    fprintf(stderr, "%s is dead\n", sockets[i]);
+                    break;
+                default:
+                    fprintf(stderr, "Unknown error on %s:%s\n", sockets[i],
+                            strerror(errno));
+                }
+            }
+            else
+            {
+                usable_sockets[nb_usable_sockets] = strdup(sockets[i]);
+                debug("%s is usable", usable_sockets[nb_usable_sockets]);
+                nb_usable_sockets++;
+                close(sock);
+            }
+        }
+        if (!nb_usable_sockets)
+            goto end;
+        if (nb_usable_sockets == 1)
+        {
+            ret = strdup(usable_sockets[0]);
+            goto end;
+        }
+        else
+        {
+            caca_event_t ev;
+            enum caca_event_type t;
+            int current_line = 1;
+            int refresh = 1;
+            screen_list->cv = caca_create_canvas(0, 0);
+            screen_list->dp = caca_create_display(screen_list->cv);
+            if (!screen_list->dp)
+                goto end;
+            caca_set_cursor(screen_list->dp, 0);
+            caca_set_display_title(screen_list->dp, PACKAGE_STRING);
+            while (1)
+            {
+                if (refresh)
+                {
+                    caca_set_color_ansi(screen_list->cv, CACA_BLUE, CACA_BLUE);
+                    caca_fill_box(screen_list->cv,
+                                  0, 0,
+                                  caca_get_canvas_width(screen_list->cv),
+                                  caca_get_canvas_height(screen_list->cv),
+                                  '#');
+                    caca_set_color_ansi(screen_list->cv, CACA_DEFAULT,
+                                        CACA_BLUE);
+                    caca_draw_cp437_box(screen_list->cv, 0, 0,
+                                        caca_get_canvas_width(screen_list->cv),
+                                        caca_get_canvas_height(screen_list->
+                                                               cv));
+                    caca_printf(screen_list->cv, 2, 2,
+                                "Please select a session to reconnect:");
+                    for (i = 0; i < nb_usable_sockets; i++)
+                    {
+                        if (i == current_line - 1)
+                        {
+                            caca_set_attr(screen_list->cv, CACA_BOLD);
+                            caca_set_color_ansi(screen_list->cv, CACA_GREEN,
+                                                CACA_BLUE);
+                            caca_put_char(screen_list->cv, 1, i + 3, '>');
+                        }
+                        else
+                        {
+                            caca_set_attr(screen_list->cv, 0);
+                            caca_set_color_ansi(screen_list->cv,
+                                                CACA_LIGHTGRAY, CACA_BLUE);
+                            caca_put_char(screen_list->cv, 1, i + 3, ' ');
+                        }
+                        caca_printf(screen_list->cv,
+                                    3, i + 3,
+                                    "%s",
+                                    socket_to_session(usable_sockets[i]));
+                    }
+                    caca_refresh_display(screen_list->dp);
+                    refresh = 0;
+                }
+
+                if (!caca_get_event(screen_list->dp,
+                                    CACA_EVENT_KEY_PRESS
+                                    | CACA_EVENT_RESIZE
+                                    | CACA_EVENT_QUIT, &ev, 10000))
+                    continue;
+
+                t = caca_get_event_type(&ev);
+
+                if (t & CACA_EVENT_KEY_PRESS)
+                {
+                    unsigned int c = caca_get_event_key_ch(&ev);
+                    switch (c)
+                    {
+                    case CACA_KEY_UP:
+                        if (current_line > 1)
+                            current_line--;
+                        break;
+                    case CACA_KEY_DOWN:
+                        if (current_line < nb_usable_sockets)
+                            current_line++;
+                        break;
+                    case CACA_KEY_RETURN:
+                        ret = strdup(usable_sockets[current_line - 1]);
+                        goto end;
+                        break;
+                    case CACA_KEY_ESCAPE:
+                        goto end;
+                        break;
+                    default:
+                        break;
+                    }
+                    refresh = 1;
+                }
+                else if (t & CACA_EVENT_RESIZE)
+                {
+                    refresh = 1;
+                }
+                else if (t & CACA_EVENT_QUIT)
+                    goto end;
+            }
+        }
+    }
+
+  end:
+    if (sockets)
+    {
+        for (i = 0; sockets[i]; i++)
+            free(sockets[i]);
+        free(sockets);
+    }
+    if (usable_sockets)
+    {
+        for (i = 0; i < nb_usable_sockets; i++)
+            free(usable_sockets[i]);
+        free(usable_sockets);
+    }
+    if (screen_list->dp)
+    {
+        caca_free_display(screen_list->dp);
+        screen_list->dp = NULL;
+    }
+    if (screen_list->cv)
+    {
+        caca_free_canvas(screen_list->cv);
+        screen_list->cv = NULL;
+    }
+    return ret;
+}
+
+void attach(struct screen_list *screen_list)
+{
+    screen_list->comm.socket_path[SOCK_SERVER] = select_socket(screen_list);
+
+    if (screen_list->comm.socket_path[SOCK_SERVER])
+    {
+        char *session;
+        session = connect_socket(screen_list, SOCK_SERVER);
+        if (session)
+        {
+            debug("Connected to session %s", session);
+            /* Create main canvas and associated caca window */
+            screen_list->cv = caca_create_canvas(0, 0);
+            screen_list->dp = caca_create_display(screen_list->cv);
+            if (!screen_list->dp)
+                return;
+            caca_set_display_time(screen_list->dp, screen_list->delay * 1000);
+            caca_set_cursor(screen_list->dp, 1);
+
+            screen_list->comm.socket_path[SOCK_CLIENT] =
+                build_socket_path(screen_list->comm.socket_dir, session,
+                                  SOCK_CLIENT);
+            create_socket(screen_list, SOCK_CLIENT);
+            request_attach(screen_list);
+            if (screen_list->comm.session_name)
+                free(screen_list->comm.session_name);
+            screen_list->comm.session_name = session;
+        }
+        else
+        {
+            fprintf(stderr, "Failed to attach!\n");
+            free(screen_list->comm.socket_path[SOCK_SERVER]);
+            screen_list->comm.socket_path[SOCK_SERVER] = NULL;
+            screen_list->sys.attach = 0;
+        }
+    }
+    else
+    {
+        fprintf(stderr, "No socket found!\n");
+        screen_list->sys.attach = 0;
+    }
+}
+
diff --git a/neercs/old/client.c b/neercs/old/client.c
new file mode 100644
index 0000000..725092c
--- /dev/null
+++ b/neercs/old/client.c
@@ -0,0 +1,298 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                2008-2011 Pascal Terjan <pterjan@linuxfr.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <time.h>
+#include <pwd.h>
+
+#include <errno.h>
+#include <caca.h>
+
+#include "neercs.h"
+
+#define NEERCS_RECV_BUFSIZE 128*1024
+
+
+int start_client(struct screen_list *screen_list)
+{
+    char *sess = NULL;
+    create_socket(screen_list, SOCK_CLIENT);
+    while ((sess = connect_socket(screen_list, SOCK_SERVER)) == NULL)
+        usleep(100);
+    free(sess);
+
+    /* Create main canvas and associated caca window */
+    screen_list->cv = caca_create_canvas(0, 0);
+    screen_list->dp = caca_create_display(screen_list->cv);
+    screen_list->mouse_button = 0;
+
+    if (!screen_list->dp)
+        return -3;
+
+    caca_set_display_time(screen_list->dp, screen_list->delay * 1000);
+    caca_set_cursor(screen_list->dp, 1);
+
+    request_attach(screen_list);
+
+    return 0;
+}
+
+int send_event(caca_event_t ev, struct screen_list *screen_list)
+{
+    enum caca_event_type t;
+    char buf[64];
+    int bytes = 0;
+
+    t = caca_get_event_type(&ev);
+
+    if (t & CACA_EVENT_KEY_PRESS)
+    {
+        bytes =  snprintf(buf, sizeof(buf) - 1, "KEY %d",
+                          caca_get_event_key_ch(&ev));
+        debug("Sending key press to server: %s", buf);
+    }
+    else if (t & CACA_EVENT_RESIZE)
+    {
+        bytes = snprintf(buf, sizeof(buf) - 1, "RESIZE %10d %10d",
+                         caca_get_event_resize_width(&ev),
+                         caca_get_event_resize_height(&ev));
+    }
+    else if (t & CACA_EVENT_MOUSE_PRESS)
+    {
+        screen_list->mouse_button = caca_get_event_mouse_button(&ev);
+        bytes = snprintf(buf, sizeof(buf) - 1, "MOUSEP %10d %10d %10d",
+                         caca_get_mouse_x(screen_list->dp),
+                         caca_get_mouse_y(screen_list->dp),
+                         screen_list->mouse_button);
+    }
+    else if (t & CACA_EVENT_MOUSE_RELEASE)
+    {
+        bytes = snprintf(buf, sizeof(buf) - 1, "MOUSER %10d %10d %10d",
+                         caca_get_mouse_x(screen_list->dp),
+                         caca_get_mouse_y(screen_list->dp),
+                         screen_list->mouse_button);
+        screen_list->mouse_button = 0;
+    }
+    else if (t & CACA_EVENT_MOUSE_MOTION)
+    {
+        int x = caca_get_mouse_x(screen_list->dp);
+        int y = caca_get_mouse_y(screen_list->dp);
+        int b = screen_list->mouse_button;
+        debug("Mouse motion, button %d", b);
+        if (x != screen_list->old_x || y != screen_list->old_y)
+        {
+            screen_list->old_x = caca_get_mouse_x(screen_list->dp);
+            screen_list->old_y = caca_get_mouse_y(screen_list->dp);
+
+            bytes = snprintf(buf, sizeof(buf) - 1, "MOUSEM %10d %10d %10d",
+                             caca_get_mouse_x(screen_list->dp),
+                             caca_get_mouse_y(screen_list->dp),
+                             b>=0?b:0);
+        }
+    }
+    else if (t & CACA_EVENT_QUIT)
+    {
+        bytes = snprintf(buf, sizeof(buf) - 1, "QUIT");
+    }
+    if (bytes)
+    {
+        ssize_t r;
+        buf[bytes] = '\0';
+        debug("Sending '%s', %d bytes", buf, bytes);
+        r = write(screen_list->comm.socket[SOCK_SERVER], buf, bytes+1);
+        while (r < 0 && errno == EAGAIN)
+        {
+            usleep(20);
+            r = write(screen_list->comm.socket[SOCK_SERVER], buf, bytes+1);
+        }
+        return r < 0;
+    }
+    return 0;
+}
+
+int send_delay(struct screen_list *screen_list)
+{
+    debug("Sending DELAY\n");
+    char buf[18];
+    int bytes;
+    bytes = snprintf(buf, sizeof(buf) - 1, "DELAY %10d", screen_list->delay);
+    buf[bytes] = '\0';
+    return write(screen_list->comm.socket[SOCK_SERVER], buf, strlen(buf)) <= 0;
+}
+
+/** \brief Main client loop.
+ *
+ * This is the main client loop.
+ *
+ * Repeat forever:
+ *  - if data is available on the client socket, read it and interpret it:
+ *    - "DETACH": exit the loop
+ *    - "UPDATE": update screen with the given canvas data
+ *    - "REFRESH": refresh the whole display
+ *    - "CURSOR": set cursor position
+ *    - "TITLE": set window or display title
+ *  - wait for an input event with a 10ms timeout
+ */
+void mainloop(struct screen_list *screen_list)
+{
+    char *buf = NULL;
+    screen_list->last_key_time = get_us();
+
+    while (mainloop_tick(&buf, screen_list))
+        ;
+
+    free(buf);
+}
+
+int mainloop_tick(char **pbuf, struct screen_list *screen_list)
+{
+    caca_event_t ev;
+    int ret = 0;
+    ssize_t n;
+    if (!screen_list)
+        return 0;
+    if (!*pbuf)
+        *pbuf = malloc(NEERCS_RECV_BUFSIZE);
+    if (!*pbuf)
+    {
+        debug("Failed to allocate memory");
+        return 0;
+    }
+    if (screen_list->comm.socket[SOCK_CLIENT]
+        && (n =
+            read(screen_list->comm.socket[SOCK_CLIENT], *pbuf,
+                 NEERCS_RECV_BUFSIZE - 1)) > 0)
+    {
+        *pbuf[n] = 0;
+        debug("Received from server: '%s' (%d bytes)", *pbuf, n);
+        if (!strncmp("DETACH", *pbuf, 6))
+        {
+            /* ret = 1; Not used */
+            return 1;
+        }
+        else if (!strncmp("UPDATE ", *pbuf, 7))
+        {
+            int x, y;
+            ssize_t l2 = 0, lb = 0;
+            char *buf2;
+            size_t l = 0;
+            /* FIXME check the length before calling atoi */
+            x = atoi(*pbuf + 8);
+            y = atoi(*pbuf + 19);
+
+            /* 0 means we have valid data but incomplete, so read the rest
+             */
+            while (l == 0)
+            {
+                buf2 = realloc(*pbuf, l2 + NEERCS_RECV_BUFSIZE);
+                if (!buf2)
+                {
+                    debug("Failed to allocate memory");
+                    return 0;
+                }
+                *pbuf = buf2;
+                fcntl(screen_list->comm.socket[SOCK_CLIENT], F_SETFL, 0);
+                lb = read(screen_list->comm.socket[SOCK_CLIENT], *pbuf + l2,
+                          NEERCS_RECV_BUFSIZE - 1);
+                if (lb < 0)
+                {
+                    debug
+                        ("Failed to read the end of the refresh message (%s)",
+                         strerror(errno));
+                    l = -1;
+                }
+                else
+                {
+                    l2 += lb;
+                    l = caca_import_area_from_memory(screen_list->cv, x, y,
+                                                     *pbuf, l2, "caca");
+                }
+            }
+            fcntl(screen_list->comm.socket[SOCK_CLIENT], F_SETFL,
+                  O_NONBLOCK);
+        }
+        else if (!strncmp("REFRESH ", *pbuf, 8))
+        {
+            int dt, x, y;
+            /* FIXME check the length before calling atoi */
+            x = atoi(*pbuf + 8);
+            y = atoi(*pbuf + 19);
+            caca_gotoxy(screen_list->cv, x, y);
+            caca_refresh_display(screen_list->dp);
+            dt = caca_get_display_time(screen_list->dp);
+
+            /* Adjust refresh delay so that the server do not compute
+               useless things */
+            if (dt > 2 * 1000 * screen_list->delay
+                && screen_list->delay <= 100)
+            {
+                screen_list->delay *= 2;
+                send_delay(screen_list);
+            }
+            else if (dt < screen_list->delay * 1000 * 1.2 &&
+                     screen_list->delay >=
+                     3 * screen_list->requested_delay / 2)
+            {
+                screen_list->delay = 2 * screen_list->delay / 3;
+                send_delay(screen_list);
+            }
+            screen_list->comm.attached = 1;
+        }
+        else if (!strncmp("CURSOR ", *pbuf, 7))
+        {
+            caca_set_cursor(screen_list->dp, atoi(*pbuf + 7));
+        }
+        else if (!strncmp("TITLE ", *pbuf, 6))
+        {
+            caca_set_display_title(screen_list->dp, *pbuf + 6);
+            caca_refresh_display(screen_list->dp);
+        }
+        else
+        {
+            debug("Unknown message received from server: %s", *pbuf);
+        }
+    }
+
+    /* Wait to have finished attaching before handling events */
+    if (screen_list->comm.attached)
+    {
+        ret = caca_get_event(screen_list->dp,
+                             CACA_EVENT_KEY_PRESS
+                             | CACA_EVENT_MOUSE_PRESS
+                             | CACA_EVENT_MOUSE_RELEASE
+                             | CACA_EVENT_MOUSE_MOTION
+                             | CACA_EVENT_RESIZE
+                             | CACA_EVENT_QUIT, &ev, 10000);
+        if (ret)
+            ret = send_event(ev, screen_list);
+        if (ret)
+        {
+            debug("Failed send event, quitting: %s\n", strerror(errno));
+            return 1;
+        }
+    }
+
+    return 1;
+}
diff --git a/neercs/old/configuration.c b/neercs/old/configuration.c
new file mode 100644
index 0000000..66a544e
--- /dev/null
+++ b/neercs/old/configuration.c
@@ -0,0 +1,568 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include "neercs.h"
+
+
+struct config_line *get_config(const char *name);
+int set_window_manager(const char *argv, struct screen_list *screen_list);
+int set_cube_duration(const char *argv, struct screen_list *screen_list);
+int set_thumbnails(const char *argv, struct screen_list *screen_list);
+int set_status_bar(const char *argv, struct screen_list *screen_list);
+int set_screensaver_timeout(const char *argv, struct screen_list *screen_list);
+int set_autolock_timeout(const char *argv, struct screen_list *screen_list);
+int set_lock_on_detach(const char *argv, struct screen_list *screen_list);
+int set_socket_dir(const char *argv, struct screen_list *screen_list);
+int set_delay(const char *argv, struct screen_list *screen_list);
+int set_eyecandy(const char *argv, struct screen_list *screen_list);
+int set_border(const char *argv, struct screen_list *screen_list);
+char *get_window_manager(struct screen_list *screen_list);
+char *get_cube_duration(struct screen_list *screen_list);
+char *get_thumbnails(struct screen_list *screen_list);
+char *get_status_bar(struct screen_list *screen_list);
+char *get_screensaver_timeout(struct screen_list *screen_list);
+char *get_autolock_timeout(struct screen_list *screen_list);
+char *get_lock_on_detach(struct screen_list *screen_list);
+char *get_socket_dir(struct screen_list *screen_list);
+char *get_delay(struct screen_list *screen_list);
+char *get_eyecandy(struct screen_list *screen_list);
+char *get_border(struct screen_list *screen_list);
+
+/* Options definition and associated function pointer */
+struct config_line config_option[] = {
+    {.name = "window_manager",.set = set_window_manager,.get =
+     get_window_manager},
+    {.name = "eyecandy",.set = set_eyecandy,.get = get_eyecandy},
+    {.name = "borders",.set = set_border,.get = get_border},
+    {.name = "cube_duration",.set = set_cube_duration,.get =
+     get_cube_duration},
+    {.name = "thumbnails",.set = set_thumbnails,.get = get_thumbnails},
+    {.name = "status_bar",.set = set_status_bar,.get = get_status_bar},
+    {.name = "screensaver_timeout",.set = set_screensaver_timeout,.get =
+     get_screensaver_timeout},
+    {.name = "autolock_timeout",.set = set_autolock_timeout,.get =
+     get_autolock_timeout},
+    {.name = "lock_on_detach",.set = set_lock_on_detach,.get =
+     get_lock_on_detach},
+    {.name = "socket_dir",.set = set_socket_dir,.get = get_socket_dir},
+    {.name = "delay",.set = set_delay,.get = get_delay},
+
+    {.name = "last",.set = NULL},
+};
+
+
+
+int read_configuration_file(char *filename, struct screen_list *screen_list)
+{
+    FILE *fp;
+    struct stat st;
+    int size = 0, i = 0, total = 0, offset = 0, l = 1;
+    char *buffer = NULL;
+
+    screen_list->config = NULL;
+
+    /* Check if file exist */
+    if (stat(filename, &st) < 0)
+    {
+        return -1;
+    }
+    /* Get its size */
+    size = st.st_size;
+    if (!size)
+    {
+        fprintf(stderr, "File too short\n");
+        return -1;
+    }
+
+    /* Open it */
+    fp = fopen(filename, "r");
+    if (!fp)
+    {
+        return -1;
+    }
+
+    buffer = malloc(size + 1);
+    if (!buffer)
+    {
+        fclose(fp);
+        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__,
+                __LINE__);
+        return -1;
+    }
+    /* Read it */
+    while ((i = fread(buffer + total, 1, size, fp)) > 0)
+    {
+        total += i;
+    }
+    buffer[total] = '\n';
+
+    fclose(fp);
+
+    /* Parse it */
+    while ((i =
+            parse_conf_line(buffer + offset, total - offset, screen_list)) > 0)
+    {
+        offset += i;
+        l++;
+    }
+
+    free(buffer);
+
+    /* Fill neercs configuration with it */
+    fill_config(screen_list);
+
+    return 1;
+}
+
+struct config_line *get_config_option(void)
+{
+    return config_option;
+}
+
+int parse_conf_line(char *buf, int size, struct screen_list *screen_list)
+{
+    int i, s = 0, c = 0;
+    char *line = NULL;
+    int l = 0;
+    int in_quote = 0, end_spaces = 0;
+    static struct option *prev = NULL;
+
+    if (size <= 0)
+        return -1;
+
+    /* Find EOL */
+    for (i = 0; i < size; i++)
+    {
+        if (buf[i] == '\n')
+        {
+            s = i + 1;
+            break;
+        }
+    }
+
+    /* Strip comments and trailing spaces */
+    for (i = 0; i < s; i++)
+    {
+        if (buf[i] == ';' && !in_quote)
+        {
+            break;
+        }
+        else if (buf[i] == '\n')
+        {
+            break;
+        }
+        else if (buf[i] == ' ' && !c)
+        {
+        }
+        else
+        {
+            if (line == NULL)
+            {
+                line = malloc(2);
+                if (!line)
+                {
+                    fprintf(stderr, "Can't allocate memory at %s:%d\n",
+                            __FUNCTION__, __LINE__);
+                    return -1;
+                }
+            }
+            else
+            {
+                line = realloc(line, l + 2);
+                if (!line)
+                {
+                    fprintf(stderr, "Can't allocate memory at %s:%d\n",
+                            __FUNCTION__, __LINE__);
+                    return -1;
+                }
+            }
+            if (buf[i] == '"')
+                in_quote = !in_quote;
+            if (buf[i] == ' ')
+                end_spaces++;
+            else
+                end_spaces = 0;
+
+            line[l] = buf[i];
+            line[l + 1] = 0;
+            l++;
+            c = 1;
+        }
+    }
+
+    if (c == 0)
+    {
+        /* This line is empty, do nothing */
+    }
+    else
+    {
+        struct option *option = malloc(sizeof(struct option));
+        if (!option)
+        {
+            fprintf(stderr, "Can't allocate memory at %s:%d\n",
+                    __FUNCTION__, __LINE__);
+            return -1;
+        }
+        option->next = NULL;
+        l -= end_spaces;
+        line = realloc(line, l + 1);
+        line[l] = 0;
+
+        get_key_value(line, option);
+
+        if (!screen_list->config)
+            screen_list->config = option;
+
+        if (prev)
+            prev->next = option;
+
+        prev = option;
+    }
+    free(line);
+    return s;
+}
+
+int get_key_value(char *line, struct option *option)
+{
+    unsigned int i, o = 0, b = 0, end_spaces = 0;
+    char *cur = NULL;
+    option->value = NULL;
+    option->key = NULL;
+
+    /* Line is a section delimiter */
+    if (line[0] == '[')
+    {
+        option->value = malloc(strlen(line) - 1);
+        if (!option->value)
+        {
+            fprintf(stderr, "Can't allocate memory at %s:%d\n",
+                    __FUNCTION__, __LINE__);
+            return -1;
+        }
+        memcpy(option->value, line + 1, strlen(line) - 1);
+        option->value[strlen(line) - 2] = 0;
+        return 0;
+    }
+
+    cur = malloc(1);
+    if (!cur)
+    {
+        fprintf(stderr, "Can't allocate memory at %s:%d\n",
+                __FUNCTION__, __LINE__);
+        return -1;
+    }
+    cur[0] = 0;
+
+    for (i = 0; i < strlen(line); i++)
+    {
+        if (line[i] == ' ' && !b)
+            continue;
+
+
+        if (line[i] == '=')
+        {
+            b = 0;
+            cur[o - end_spaces] = 0;
+            cur = realloc(cur, (o - end_spaces) + 1);
+            if (!cur)
+            {
+                fprintf(stderr, "Can't allocate memory at %s:%d\n",
+                        __FUNCTION__, __LINE__);
+                return -1;
+            }
+            o = 0;
+            option->key = cur;
+            cur = malloc(1);
+        }
+        else
+        {
+            if (line[i] == ' ')
+                end_spaces++;
+            else
+                end_spaces = 0;
+
+            cur = realloc(cur, o + 2);
+            if (!cur)
+            {
+                fprintf(stderr, "Can't allocate memory at %s:%d\n",
+                        __FUNCTION__, __LINE__);
+                return -1;
+            }
+            cur[o] = line[i];
+            o++;
+            b = 1;
+
+        }
+    }
+    cur[o] = 0;
+    option->value = cur;
+    return 0;
+}
+
+
+
+struct config_line *get_config(const char *name)
+{
+    int i = 0;
+
+    debug("Looking for '%s'\n", name);
+
+    while (strncmp(config_option[i].name, "last", strlen("last")))
+    {
+        debug("%d Testing against '%s'\n", i, config_option[i].name);
+        if (!strncmp(name, config_option[i].name, strlen(name)))
+        {
+            debug("Found\n");
+            return &config_option[i];
+        }
+        i++;
+    }
+    return NULL;
+}
+
+
+
+int fill_config(struct screen_list *screen_list)
+{
+    int i = 0;
+    struct option *option = screen_list->config;
+
+    while (option)
+    {
+        if (option->key == NULL)
+        {
+            option = option->next;
+            continue;
+        }
+
+        struct config_line *c = get_config(option->key);
+        if (c)
+        {
+            c->set((const char *)option->value, screen_list);
+        }
+        option = option->next;
+    }
+
+    return i;
+}
+
+
+
+/*
+ * Options setters
+ */
+
+#define IS_OPTION(t) (!strncmp(argv, t, strlen(argv)))
+#define IS_OPTION_TRUE (IS_OPTION("true") || IS_OPTION("True") || IS_OPTION("1"))
+
+int set_window_manager(const char *argv, struct screen_list *screen_list)
+{
+    if (IS_OPTION("full"))
+        screen_list->wm_type = WM_FULL;
+    else if (IS_OPTION("hsplit"))
+        screen_list->wm_type = WM_HSPLIT;
+    else if (IS_OPTION("vsplit"))
+        screen_list->wm_type = WM_VSPLIT;
+    else if (IS_OPTION("card"))
+        screen_list->wm_type = WM_CARD;
+    else
+    {
+        fprintf(stderr, "Unknown window manager '%s'\n", argv);
+        return -1;
+    }
+    return 0;
+}
+
+int set_cube_duration(const char *argv, struct screen_list *screen_list)
+{
+    screen_list->cube.duration = atoi(argv) * 1000000;
+    return 0;
+}
+
+int set_thumbnails(const char *argv, struct screen_list *screen_list)
+{
+    if (IS_OPTION_TRUE)
+        screen_list->modals.mini = 1;
+    else
+        screen_list->modals.mini = 0;
+    return 0;
+
+}
+
+int set_status_bar(const char *argv, struct screen_list *screen_list)
+{
+    if (IS_OPTION_TRUE)
+        screen_list->modals.status = 1;
+    else
+        screen_list->modals.status = 0;
+    return 0;
+}
+
+int set_screensaver_timeout(const char *argv, struct screen_list *screen_list)
+{
+    screen_list->screensaver.timeout = atoi(argv) * 1000000;
+    /* if timeout is 0, set it to 0xFFFFFFFFFFFFFFFF */
+    if (!screen_list->screensaver.timeout)
+        screen_list->screensaver.timeout -= 1;
+    return 0;
+}
+
+int set_autolock_timeout(const char *argv, struct screen_list *screen_list)
+{
+    if (screen_list->lock.autolock_timeout == 0 ||
+        screen_list->lock.autolock_timeout == ((long long unsigned int)0) - 1)
+    {
+        screen_list->lock.autolock_timeout = atoi(argv) * 1000000;
+        /* if timeout is 0, set it to 0xFFFFFFFFFFFFFFFF */
+        if (!screen_list->lock.autolock_timeout)
+            screen_list->lock.autolock_timeout -= 1;
+    }
+    return 0;
+}
+
+int set_lock_on_detach(const char *argv, struct screen_list *screen_list)
+{
+    if (IS_OPTION_TRUE)
+        screen_list->lock.lock_on_detach = 1;
+    else
+        screen_list->lock.lock_on_detach = 0;
+    return 0;
+}
+
+int set_eyecandy(const char *argv, struct screen_list *screen_list)
+{
+    if (IS_OPTION_TRUE)
+        screen_list->eyecandy = 1;
+    else
+        screen_list->eyecandy = 0;
+    return 0;
+}
+
+int set_border(const char *argv, struct screen_list *screen_list)
+{
+    if (IS_OPTION_TRUE)
+        screen_list->border_size = 1;
+    else
+        screen_list->border_size = 0;
+    return 0;
+}
+
+int set_socket_dir(const char *argv, struct screen_list *screen_list)
+{
+    screen_list->comm.socket_dir = strdup(argv);
+    return 0;
+}
+
+int set_delay(const char *argv, struct screen_list *screen_list)
+{
+    screen_list->requested_delay = atoi(argv);
+    screen_list->delay = atoi(argv);
+    return 0;
+}
+
+char *get_window_manager(struct screen_list *screen_list)
+{
+    debug("Window manager is %d", screen_list->wm_type);
+    switch (screen_list->wm_type)
+    {
+    case WM_FULL:
+        return "full";
+    case WM_CARD:
+        return "card";
+    case WM_VSPLIT:
+        return "vsplit";
+    case WM_HSPLIT:
+        return "hsplit";
+    default:
+        return "invalid window manager";
+    }
+    return NULL;                /* Not reached */
+}
+
+char *get_cube_duration(struct screen_list *screen_list)
+{
+    char *r = malloc(100);
+    sprintf(r, "%f", (float)screen_list->cube.duration / 1000000.0f);
+    return r;
+}
+
+char *get_thumbnails(struct screen_list *screen_list)
+{
+    if (screen_list->modals.mini)
+        return "true";
+    return "false";
+}
+
+char *get_status_bar(struct screen_list *screen_list)
+{
+    if (screen_list->modals.status)
+        return "true";
+    return "false";
+}
+
+char *get_eyecandy(struct screen_list *screen_list)
+{
+    if (screen_list->eyecandy)
+        return "true";
+    return "false";
+}
+
+char *get_border(struct screen_list *screen_list)
+{
+    if (screen_list->border_size)
+        return "true";
+    return "false";
+}
+
+char *get_screensaver_timeout(struct screen_list *screen_list)
+{
+    char *r = malloc(100);
+    sprintf(r, "%f", (float)screen_list->screensaver.timeout / 1000000.0f);
+    return r;
+}
+
+char *get_autolock_timeout(struct screen_list *screen_list)
+{
+    char *r = malloc(100);
+    sprintf(r, "%f", (float)screen_list->lock.autolock_timeout / 1000000.0f);
+    return r;
+}
+
+char *get_lock_on_detach(struct screen_list *screen_list)
+{
+    if (screen_list->lock.lock_on_detach)
+        return "true";
+    else
+        return "false";
+}
+
+char *get_socket_dir(struct screen_list *screen_list)
+{
+    return screen_list->comm.socket_dir;
+}
+
+char *get_delay(struct screen_list *screen_list)
+{
+    char *r = malloc(100);
+    sprintf(r, "%d", screen_list->requested_delay);
+    return r;
+}
diff --git a/neercs/old/effects.c b/neercs/old/effects.c
new file mode 100644
index 0000000..7999141
--- /dev/null
+++ b/neercs/old/effects.c
@@ -0,0 +1,278 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <caca.h>
+
+#include "neercs.h"
+
+void draw_thumbnails(struct screen_list *screen_list)
+{
+    char const *const *fonts;
+    caca_dither_t *d;
+    caca_font_t *f;
+    uint8_t *buf;
+    int i, y =
+        caca_get_canvas_height(screen_list->cv) - 6 - screen_list->modals.status;
+    int miniw, minih;
+
+    if (screen_list->count)
+    {
+        fonts = caca_get_font_list();
+        f = caca_load_font(fonts[0], 0);
+
+        miniw = caca_get_canvas_width(screen_list->screen[0]->cv)
+            * caca_get_font_width(f);
+        minih = caca_get_canvas_height(screen_list->screen[0]->cv)
+            * caca_get_font_height(f);
+        buf = malloc(4 * miniw * minih);
+
+#if defined(HAVE_ENDIAN_H)
+        if (__BYTE_ORDER == __BIG_ENDIAN)
+#else
+        /* This is compile-time optimised with at least -O1 or -Os */
+        uint32_t const tmp = 0x12345678;
+        if (*(uint8_t const *)&tmp == 0x12)
+#endif
+            d = caca_create_dither(32, miniw, minih, 4 * miniw,
+                                   0xff0000, 0xff00, 0xff, 0x0);
+        else
+            d = caca_create_dither(32, miniw, minih, 4 * miniw,
+                                   0xff00, 0xff0000, 0xff000000, 0x0);
+
+        for (i = 0; i < screen_list->count; i++)
+        {
+            if (!screen_list->screen[i]->changed && !screen_list->changed)
+                continue;
+            caca_render_canvas(screen_list->screen[i]->cv, f, buf,
+                               miniw, minih, miniw * 4);
+            caca_dither_bitmap(screen_list->cv, 20 * i, y, 19, 6, d, buf);
+            caca_set_color_ansi(screen_list->cv, CACA_WHITE, CACA_BLUE);
+
+            if (screen_list->pty == i)
+                caca_draw_cp437_box(screen_list->cv, 20 * i, y, 19, 6);
+            caca_printf(screen_list->cv, 20 * i, y, "(%i)", i + 1);
+        }
+
+        caca_free_dither(d);
+        caca_free_font(f);
+
+        free(buf);
+    }
+
+}
+
+/* FIXME, make this stuff more configurable */
+void draw_status(struct screen_list *screen_list)
+{
+    int x = 0, y = caca_get_canvas_height(screen_list->cv) - 1;
+
+
+    /* caca_fill_box(screen_list->cv, x, y,
+       caca_get_canvas_width(screen_list->cv), 1, '#'); */
+
+    /* Hour */
+    {
+        time_t now = time((time_t *) 0);
+        struct tm *t = localtime(&now);
+        char hour[256];
+        sprintf(hour, "%02d:%02d", t->tm_hour, t->tm_min);
+
+        caca_set_color_ansi(screen_list->cv, CACA_LIGHTBLUE, CACA_BLUE);
+        caca_printf(screen_list->cv, x, y, "[");
+
+        caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_BLUE);
+        caca_printf(screen_list->cv, x + 1, y, hour);
+        caca_set_color_ansi(screen_list->cv, CACA_LIGHTBLUE, CACA_BLUE);
+        caca_printf(screen_list->cv, x + strlen(hour) + 1, y, "]");
+        x += 7;
+
+    }
+
+    /* Window */
+    {
+        char text[256];
+        sprintf(text, "%d/%d", screen_list->pty + 1, screen_list->count);
+        caca_set_color_ansi(screen_list->cv, CACA_BLUE, CACA_BLUE);
+        caca_put_char(screen_list->cv, x, y, '#');
+        x++;
+        caca_set_color_ansi(screen_list->cv, CACA_LIGHTBLUE, CACA_BLUE);
+        caca_printf(screen_list->cv, x, y, "Window:");
+        caca_set_color_ansi(screen_list->cv, CACA_BLUE, CACA_BLUE);
+        caca_put_char(screen_list->cv, x + 7, y, '#');
+        caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_BLUE);
+        caca_printf(screen_list->cv, x + 8, y, text);
+        x += 8 + strlen(text);
+    }
+
+    /* Window Manager */
+    {
+        char text[256];
+
+        switch (screen_list->wm_type)
+        {
+        case WM_CARD:
+            strcpy(text, "card");
+            break;
+        case WM_HSPLIT:
+            strcpy(text, "hsplit");
+            break;
+        case WM_VSPLIT:
+            strcpy(text, "vsplit");
+            break;
+        case WM_FULL:
+        default:
+            strcpy(text, "full");
+            break;
+
+        }
+
+        caca_set_color_ansi(screen_list->cv, CACA_BLUE, CACA_BLUE);
+        caca_put_char(screen_list->cv, x, y, '#');
+        x++;
+        caca_set_color_ansi(screen_list->cv, CACA_LIGHTBLUE, CACA_BLUE);
+        caca_printf(screen_list->cv, x, y, "WM:");
+        caca_set_color_ansi(screen_list->cv, CACA_BLUE, CACA_BLUE);
+        caca_put_char(screen_list->cv, x + 3, y, '#');
+        caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_BLUE);
+        caca_printf(screen_list->cv, x + 4, y, text);
+        x += 4 + strlen(text);
+    }
+
+    /* Help (must be the last one ) */
+    {
+        char text[256];
+        sprintf(text, "Help: ctrl-a-?");
+        caca_set_color_ansi(screen_list->cv, CACA_BLUE, CACA_BLUE);
+        while (x <
+               (int)(caca_get_canvas_width(screen_list->cv) - strlen(text)))
+        {
+            caca_put_char(screen_list->cv, x, y, '#');
+            x++;
+        }
+        caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_BLUE);
+        caca_printf(screen_list->cv, x, y, text);
+    }
+
+
+}
+
+
+
+int update_window_list(int c, struct screen_list *screen_list)
+{
+    debug("Got %x\n", c);
+
+    switch (c)
+    {
+    case 0x111:
+        if (screen_list->modals.cur_in_list > 0)
+            screen_list->modals.cur_in_list--;
+        break;
+    case 0x112:
+        if (screen_list->modals.cur_in_list < screen_list->count - 1)
+            screen_list->modals.cur_in_list++;
+        break;
+    case 0xd:
+        screen_list->modals.window_list = 0;
+        screen_list->prevpty = screen_list->pty;
+        screen_list->pty = screen_list->modals.cur_in_list;
+        break;
+    case 0x22:
+        screen_list->modals.window_list = 0;
+        break;
+    default:
+        break;
+    }
+
+    return 1;
+}
+
+void draw_list(struct screen_list *screen_list)
+{
+    int i;
+    int w = (caca_get_canvas_width(screen_list->cv));
+    int h = (caca_get_canvas_height(screen_list->cv));
+
+    debug("Drawing list\n");
+    caca_set_color_ansi(screen_list->cv, CACA_BLACK, CACA_BLACK);
+    caca_fill_box(screen_list->cv, 0, 0, w, h, '#');
+    caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_DEFAULT);
+    caca_draw_cp437_box(screen_list->cv, 0, 0, w, h);
+
+    caca_printf(screen_list->cv, 2, 1, "Num         Name");
+    for (i = 0; i < screen_list->count; i++)
+    {
+        char line[1024];
+        if (screen_list->modals.cur_in_list == i)
+            caca_set_color_ansi(screen_list->cv, CACA_BLACK, CACA_WHITE);
+        else
+            caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_DEFAULT);
+        sprintf(line, "%d           %s", i + 1, screen_list->screen[i]->title);
+
+        caca_printf(screen_list->cv, 2, i + 3, line);
+    }
+}
+
+/* Close a window by animating it collapsing */
+/* Total close time */
+#define DELAY 500000.0f
+int close_screen_recurrent(struct screen_list *screen_list,
+                           struct recurrent *rec, void *user,
+                           long long unsigned int t)
+{
+    long long unsigned int delta = t - rec->start_time;
+
+    screen_list->dont_update_coords = 1;
+    screen_list->delay = 0;
+    rec->kill_me = 0;
+    if (delta >= DELAY || (!screen_list->eyecandy))
+    {
+        rec->kill_me = 1;
+        remove_screen(screen_list, screen_list->pty, 1);
+        screen_list->pty = screen_list->prevpty>screen_list->count?screen_list->count:screen_list->prevpty;
+        screen_list->prevpty = 0;
+        screen_list->dont_update_coords = 0;
+    }
+    else
+    {
+        float r = 1 - ((DELAY - (DELAY - delta)) / DELAY);
+        caca_canvas_t *old, *new;
+        struct screen *s = screen_list->screen[screen_list->pty];
+        int w = s->orig_w * r;
+        int h = s->orig_h * r;
+
+        /* libcaca canvas resize function is bugged, do it by hand */
+        old = s->cv;
+        new = caca_create_canvas(w, h);
+        caca_blit(new, 0, 0, old, NULL);
+        s->cv = new;
+        caca_free_canvas(old);
+        set_tty_size(s->fd, w, h);
+
+        s->w = w;
+        s->h = h;
+
+        s->x = (s->orig_x * r) + ((s->orig_w / 2) - s->w / 2);
+        s->y = (s->orig_y * r) + ((s->orig_h / 2) - s->h / 2);
+    }
+    screen_list->changed = 1;
+    return 1;
+}
diff --git a/neercs/old/grab.c b/neercs/old/grab.c
new file mode 100644
index 0000000..a3f1c31
--- /dev/null
+++ b/neercs/old/grab.c
@@ -0,0 +1,393 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2008-2010 Pascal Terjan <pterjan@linuxfr.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include "config.h"
+
+#define _XOPEN_SOURCE 500       /* getsid() */
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <glob.h>
+#include <libgen.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#if defined HAVE_LINUX_KDEV_T_H
+#   include <linux/kdev_t.h>
+#   include <linux/major.h>
+#endif
+
+#include "neercs.h"
+#include "mytrace.h"
+
+int grab_process(long pid, char *ptyname, int ptyfd, int *newpid)
+{
+#if defined HAVE_LINUX_KDEV_T_H
+    char fdstr[1024];
+    struct mytrace *parent, *child;
+    int i = 0, fd = 0, ret;
+    char to_open[128];
+    int mode[128];
+    int fds[128];
+    struct stat stat_buf;
+    struct termios tos;
+    int validtos = 0;
+    DIR *fddir;
+    struct dirent *fddirent;
+
+    debug("pty is %s", ptyname);
+
+    parent = mytrace_attach(pid);
+    if (!parent)
+    {
+        fprintf(stderr, "Cannot access process %ld\n", pid);
+        return -1;
+    }
+
+    child = mytrace_fork(parent);
+
+    snprintf(fdstr, sizeof(fdstr), "/proc/%ld/fd", pid);
+    fddir = opendir(fdstr);
+
+    /* Look for file descriptors that are PTYs */
+    while ((fddirent = readdir(fddir)) && i < (int)sizeof(to_open) - 1)
+    {
+        fd = atoi(fddirent->d_name);
+        fds[i] = fd;
+        to_open[i] = 0;
+        lstat(fdstr, &stat_buf);
+        if ((stat_buf.st_mode & S_IRUSR) && (stat_buf.st_mode & S_IWUSR))
+            mode[i] = O_RDWR;
+        else if (stat_buf.st_mode & S_IWUSR)
+            mode[i] = O_WRONLY;
+        else
+            mode[i] = O_RDONLY;
+
+        snprintf(fdstr, sizeof(fdstr), "/proc/%ld/fd/%s", pid,
+                 fddirent->d_name);
+
+        if (stat(fdstr, &stat_buf) < 0)
+            continue;
+
+        if (!S_ISCHR(stat_buf.st_mode)
+            || MAJOR(stat_buf.st_rdev) != UNIX98_PTY_SLAVE_MAJOR)
+            continue;
+
+        debug("found pty %d for pid %d", fd, pid);
+
+        if (!validtos)
+        {
+            ret = mytrace_tcgets(child, fd, &tos);
+            if (ret < 0)
+            {
+                perror("mytrace_tcgets");
+            }
+            else
+            {
+                validtos = 1;
+            }
+        }
+        to_open[i] = 1;
+        i++;
+    }
+    closedir(fddir);
+
+    if (i >= (int)sizeof(to_open) - 1)
+    {
+        fprintf(stderr, "too many open pty\n");
+        mytrace_detach(child);
+        return -1;
+    }
+
+    ret = mytrace_exec(parent, "/usr/bin/reset");
+    if (ret < 0)
+        mytrace_exit(parent, 0);
+    mytrace_detach(parent);
+    waitpid(pid, NULL, 0);      /* Wait for reset to finish before displaying */
+    mytrace_write(child, 2, "\033[H\033[2J", 7);
+    mytrace_write(child, 2, "\n[Process stolen by neercs]\r\n\n", 30);
+
+    pid = mytrace_getpid(child);
+    *newpid = pid;
+
+    /* Set the process's session ID */
+    debug("Running setsid on process %ld (sid=%d)", pid, getsid(pid));
+
+    ret = mytrace_setpgid(child, 0, getsid(pid));
+    if (ret < 0)
+    {
+        fprintf(stderr, "syscall setpgid failed\n");
+        mytrace_detach(child);
+        return -1;
+    }
+
+    if (ret != 0)
+    {
+        fprintf(stderr, "setpgid returned %d\n", ret);
+        mytrace_detach(child);
+        return -1;
+    }
+
+    ret = mytrace_setsid(child);
+    if (ret < 0)
+    {
+        fprintf(stderr, "syscall setsid failed\n");
+        mytrace_detach(child);
+        return -1;
+    }
+
+    debug("pid %ld has now sid %d", pid, getsid(pid));
+
+    /* Reopen PTY file descriptors */
+    for (; i >= 0; i--)
+    {
+        if (!to_open[i])
+            continue;
+        ret = mytrace_close(child, fds[i]);
+        if (ret < 0)
+        {
+            perror("mytrace_close");
+            continue;
+        }
+        fd = mytrace_open(child, ptyname, mode[i]);
+        if (fd < 0)
+        {
+            perror("mytrace_open");
+            continue;
+        }
+
+        /* FIXME Only needed once */
+        mytrace_sctty(child, fd);
+
+        if (validtos)
+        {
+            ret = mytrace_tcsets(child, fd, &tos);
+            if (ret < 0)
+            {
+                perror("mytrace_tcsets");
+            }
+            validtos = 0;
+        }
+        ret = mytrace_dup2(child, fd, fds[i]);
+        if (ret < 0)
+        {
+            perror("mytrace_dup2");
+        }
+    }
+
+    kill(pid, SIGWINCH);
+    mytrace_detach(child);
+
+    close(ptyfd);
+    return 0;
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
+
+struct process
+{
+    long pid;
+    char *cmdline;
+};
+
+static int list_process(struct process **process_list)
+{
+    glob_t pglob;
+    unsigned int i, n = 0;
+    glob("/proc/[0-9]*", GLOB_NOSORT, NULL, &pglob);
+    *process_list = malloc(pglob.gl_pathc * sizeof(struct process));
+    for (i = 0; i < pglob.gl_pathc; i++)
+    {
+        glob_t pglob2;
+        unsigned int j;
+        char *fds;
+        (*process_list)[n].pid = atoi(basename(pglob.gl_pathv[i]));
+        /* Don't allow grabbing ourselves */
+        if ((*process_list)[n].pid == getpid())
+            continue;
+        /* FIXME check value of r */
+        int r = asprintf(&fds, "%s/fd/*", pglob.gl_pathv[i]);
+        (void) r;
+        glob(fds, GLOB_NOSORT, NULL, &pglob2);
+        free(fds);
+        for (j = 0; j < pglob2.gl_pathc; j++)
+        {
+            char path[4096];
+            ssize_t l = readlink(pglob2.gl_pathv[j], path, sizeof(path));
+            if (l <= 0)
+                continue;
+            path[l] = '\0';
+            if (strstr(path, "/dev/pt"))
+            {
+                char *cmdfile;
+                int fd;
+                /* FIXME check value of r */
+                r = asprintf(&cmdfile, "%s/cmdline", pglob.gl_pathv[i]);
+                (void) r;
+                fd = open(cmdfile, O_RDONLY);
+                free(cmdfile);
+                if (fd)
+                {
+                    /* FIXME check value of r */
+                    r = read(fd, path, sizeof(path));
+                    (void) r;
+                    (*process_list)[n].cmdline = strdup(path);
+                    close(fd);
+                    n++;
+                    break;
+                }
+            }
+        }
+        globfree(&pglob2);
+    }
+    globfree(&pglob);
+    return n;
+}
+
+long select_process(struct screen_list *screen_list)
+{
+    caca_event_t ev;
+    enum caca_event_type t;
+    int current_line = 1;
+    int refresh = 1;
+    int nb_process, i;
+    int ret = 0;
+    int start = 0;
+    struct process *process_list;
+
+    nb_process = list_process(&process_list);
+
+    screen_list->cv = caca_create_canvas(0, 0);
+    screen_list->dp = caca_create_display(screen_list->cv);
+    if (!screen_list->dp)
+        goto end;
+    caca_set_cursor(screen_list->dp, 0);
+    caca_set_display_title(screen_list->dp, PACKAGE_STRING);
+    while (1)
+    {
+        if (refresh)
+        {
+            caca_set_color_ansi(screen_list->cv, CACA_BLUE, CACA_BLUE);
+            caca_fill_box(screen_list->cv,
+                          0, 0,
+                          caca_get_canvas_width(screen_list->cv),
+                          caca_get_canvas_height(screen_list->cv), '#');
+            caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_BLUE);
+            caca_draw_cp437_box(screen_list->cv,
+                                0, 0,
+                                caca_get_canvas_width(screen_list->cv),
+                                caca_get_canvas_height(screen_list->cv));
+            caca_printf(screen_list->cv, 2, 2,
+                        "Please select a process to grab:");
+            for (i = 0;
+                 i < nb_process
+                 && i < caca_get_canvas_height(screen_list->cv) - 4; i++)
+            {
+                if (i == current_line - 1)
+                {
+                    caca_set_attr(screen_list->cv, CACA_BOLD);
+                    caca_set_color_ansi(screen_list->cv, CACA_GREEN,
+                                        CACA_BLUE);
+                    caca_put_char(screen_list->cv, 1, i + 3, '>');
+                }
+                else
+                {
+                    caca_set_attr(screen_list->cv, 0);
+                    caca_set_color_ansi(screen_list->cv, CACA_LIGHTGRAY,
+                                        CACA_BLUE);
+                    caca_put_char(screen_list->cv, 1, i + 3, ' ');
+                }
+                caca_printf(screen_list->cv,
+                            3, i + 3,
+                            "%5d %s",
+                            process_list[i + start].pid,
+                            process_list[i + start].cmdline);
+            }
+            caca_refresh_display(screen_list->dp);
+            refresh = 0;
+        }
+
+        if (!caca_get_event(screen_list->dp,
+                            CACA_EVENT_KEY_PRESS
+                            | CACA_EVENT_RESIZE | CACA_EVENT_QUIT, &ev, 10000))
+            continue;
+
+        t = caca_get_event_type(&ev);
+
+        if (t & CACA_EVENT_KEY_PRESS)
+        {
+            unsigned int c = caca_get_event_key_ch(&ev);
+            switch (c)
+            {
+            case CACA_KEY_UP:
+                if (current_line > 1)
+                    current_line--;
+                if (current_line < start && start > 0)
+                    start--;
+                break;
+            case CACA_KEY_DOWN:
+                if (current_line < nb_process)
+                    current_line++;
+                if (current_line >
+                    start + caca_get_canvas_height(screen_list->cv) - 3)
+                    start++;
+                break;
+            case CACA_KEY_RETURN:
+                ret = process_list[current_line - 1].pid;
+                goto end;
+                break;
+            case CACA_KEY_ESCAPE:
+                goto end;
+                break;
+            default:
+                break;
+            }
+            refresh = 1;
+        }
+        else if (t & CACA_EVENT_RESIZE)
+        {
+            refresh = 1;
+        }
+        else if (t & CACA_EVENT_QUIT)
+            goto end;
+    }
+
+  end:
+    if (screen_list->dp)
+    {
+        caca_free_display(screen_list->dp);
+        screen_list->dp = NULL;
+    }
+    if (screen_list->cv)
+    {
+        caca_free_canvas(screen_list->cv);
+        screen_list->cv = NULL;
+    }
+    if (nb_process > 0)
+    {
+        for (i = 0; i < nb_process; i++)
+        {
+            free(process_list[i].cmdline);
+        }
+        free(process_list);
+    }
+    return ret;
+}
diff --git a/neercs/old/help.c b/neercs/old/help.c
new file mode 100644
index 0000000..253ff53
--- /dev/null
+++ b/neercs/old/help.c
@@ -0,0 +1,76 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <caca.h>
+
+#include "neercs.h"
+
+int help_handle_key(struct screen_list *screen_list, unsigned int c)
+{
+    if (c == CACA_KEY_ESCAPE || c == '?')
+    {
+        screen_list->modals.help = 0;
+        screen_list->changed = 1;
+        return 1;
+    }
+    else
+    {
+        return 0;
+    }
+}
+
+void draw_help(struct screen_list *screen_list)
+{
+    int w = 65, h = 20;
+    int x = (caca_get_canvas_width(screen_list->cv) - w) / 2;
+    int y = (caca_get_canvas_height(screen_list->cv) - h) / 2;
+
+
+    caca_set_color_ansi(screen_list->cv, CACA_BLUE, CACA_BLUE);
+    caca_fill_box(screen_list->cv, x, y, w, h, '#');
+    caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_BLUE);
+    caca_draw_cp437_box(screen_list->cv, x, y, w, h);
+
+    x += 2;
+    y++;
+    caca_printf(screen_list->cv,
+                (caca_get_canvas_width(screen_list->cv) -
+                 strlen(PACKAGE_STRING)) / 2, y - 1, PACKAGE_STRING);
+    caca_printf(screen_list->cv, x, y++, "Copyright (c) 2006-2010");
+    caca_printf(screen_list->cv, x, y++, "              Sam Hocevar <sam@zoy.org>");
+    caca_printf(screen_list->cv, x, y++, "              Jean-Yves Lamoureux <jylam@lnxscene.org>");
+    caca_printf(screen_list->cv, x, y++, "              Pascal Terjan <pterjan@linuxfr.org>");
+    caca_printf(screen_list->cv, x, y++, "");
+    caca_printf(screen_list->cv, x, y++, "");
+    caca_printf(screen_list->cv, x, y++, "All shortcuts are in format 'ctrl-a-X' where X is :");
+    caca_printf(screen_list->cv, x, y++, "n:        Next window");
+    caca_printf(screen_list->cv, x, y++, "p:        Previous window");
+    caca_printf(screen_list->cv, x, y++, "w:        Switch window manager");
+    caca_printf(screen_list->cv, x, y++, "c:        Create new window");
+    caca_printf(screen_list->cv, x, y++, "m:        Thumbnails");
+    caca_printf(screen_list->cv, x, y++, "d:        Detach");
+    caca_printf(screen_list->cv, x, y++, "k:        Close window and kill associated process");
+    caca_printf(screen_list->cv, x, y++, "h:        Dump screen into a file");
+    caca_printf(screen_list->cv, x, y++, "?:        This help");
+    caca_printf(screen_list->cv, x, y++, "");
+    caca_printf(screen_list->cv, x, y++, "");
+    caca_printf(screen_list->cv, x, y, "See http://caca.zoy.org/wiki/neercs for more informations");
+}
diff --git a/neercs/old/input.c b/neercs/old/input.c
new file mode 100644
index 0000000..d36b5e7
--- /dev/null
+++ b/neercs/old/input.c
@@ -0,0 +1,192 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                2008-2010 Pascal Terjan <pterjan@linuxfr.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+#include "config.h"
+#include <caca.h>
+#include <string.h>
+#include "neercs.h"
+
+struct kconv
+{
+    unsigned int key;
+    char *val;
+    int size;
+};
+
+struct kconv kconv[] = {
+    {CACA_KEY_UP, "\033OA", 3},
+    {CACA_KEY_DOWN, "\033OB", 3},
+    {CACA_KEY_RIGHT, "\033OC", 3},
+    {CACA_KEY_LEFT, "\033OD", 3},
+    {CACA_KEY_PAGEUP, "\033[5~", 4},
+    {CACA_KEY_PAGEDOWN, "\033[6~", 4},
+    {CACA_KEY_HOME, "\033[1~", 4},
+    {CACA_KEY_INSERT, "\033[2~", 4},
+    {CACA_KEY_DELETE, "\033[3~", 4},
+    {CACA_KEY_END, "\033[4~", 4},
+    {CACA_KEY_F1, "\033[11~", 5},
+    {CACA_KEY_F2, "\033[12~", 5},
+    {CACA_KEY_F3, "\033[13~", 5},
+    {CACA_KEY_F4, "\033[14~", 5},
+    {CACA_KEY_F5, "\033[15~", 5},
+    {CACA_KEY_F6, "\033[17~", 5},
+    {CACA_KEY_F7, "\033[18~", 5},
+    {CACA_KEY_F8, "\033[19~", 5},
+    {CACA_KEY_F9, "\033[20~", 5},
+    {CACA_KEY_F10, "\033[21~", 5},
+    {CACA_KEY_F11, "\033[23~", 5},
+    {CACA_KEY_F12, "\033[24~", 5},
+};
+
+
+
+void *convert_input_ansi(unsigned int *c, int *size)
+{
+    unsigned int i;
+    for (i = 0; i < sizeof(kconv) / sizeof(struct kconv); i++)
+    {
+        if (*c == kconv[i].key)
+        {
+            *size = kconv[i].size;
+            return kconv[i].val;
+        }
+    }
+
+    *size = 1;
+    return c;
+}
+
+
+
+int handle_command_input(struct screen_list *screen_list, unsigned int c)
+{
+    int refresh = 0;
+
+    debug("Key %x\n", c);
+    screen_list->changed = 1;
+
+    if (c >= '0' && c <= '9')
+    {
+        int n = c - 49;
+        if (n < screen_list->count)
+        {
+            screen_list->prevpty = screen_list->pty;
+            screen_list->pty = n == -1 ? 10 : n;
+            return 1;
+        }
+        else
+        {
+            return 0;
+        }
+    }
+
+    switch (c)
+    {
+    case 0x01:                 // CACA_KEY_CTRL_A:
+        screen_list->pty ^= screen_list->prevpty;
+        screen_list->prevpty ^= screen_list->pty;
+        screen_list->pty ^= screen_list->prevpty;
+        refresh = 1;
+        break;
+    case 'm':
+    case 0x0d:                 // CACA_KEY_CTRL_M:
+        screen_list->modals.mini = !screen_list->modals.mini;
+        refresh = 1;
+        break;
+    case 'n':
+    case ' ':
+    case '\0':
+    case 0x0e:                 // CACA_KEY_CTRL_N:
+        screen_list->prevpty = screen_list->pty;
+        screen_list->pty = (screen_list->pty + 1) % screen_list->count;
+        if (screen_list->pty != screen_list->prevpty)
+        {
+            screen_list->last_switch = get_us();
+            screen_list->cube.in_switch = 1;
+            screen_list->cube.side = 0;
+        }
+        refresh = 1;
+        break;
+    case 'p':
+    case 0x10:                 // CACA_KEY_CTRL_P:
+        screen_list->prevpty = screen_list->pty;
+        screen_list->pty =
+            (screen_list->pty + screen_list->count - 1) % screen_list->count;
+        if (screen_list->pty != screen_list->prevpty)
+        {
+            screen_list->last_switch = get_us();
+            screen_list->cube.in_switch = 1;
+            screen_list->cube.side = 1;
+        }
+        refresh = 1;
+        break;
+    case 'c':
+    case 0x03:                 // CACA_KEY_CTRL_C:
+        screen_list->prevpty = screen_list->pty;
+        screen_list->pty =
+            add_screen(screen_list,
+                       create_screen(screen_list->width,
+                                     screen_list->height,
+                                     screen_list->sys.default_shell));
+        refresh = 1;
+        break;
+    case 'w':
+    case 0x17:                 // CACA_KEY_CTRL_W:
+        screen_list->wm_type = (screen_list->wm_type == (WM_MAX - 1) ?
+                                screen_list->wm_type = 0 :
+                                screen_list->wm_type + 1);
+        refresh = 1;
+        break;
+    case 'k':
+    case 0x0b:                 // CACA_KEY_CTRL_K:
+        add_recurrent(screen_list->recurrent_list, close_screen_recurrent,
+                      screen_list->cv);
+        refresh = 1;
+        break;
+    case 'x':
+    case 0x18:                 // CACA_KEY_CTRL_X:
+        memset(screen_list->lock.lockpass, 0, 1024);
+        screen_list->lock.locked = 1;
+        screen_list->lock.lock_offset = 0;
+        refresh = 1;
+        break;
+    case 'h':
+    case 0x08:                 // CACA_KEY_CTRL_H:
+        dump_to_file(screen_list);
+        break;
+    case '?':
+        screen_list->modals.help = !screen_list->modals.help;
+        refresh = 1;
+        break;
+    case '"':
+    case 0x34:                 // CTRL+"
+        screen_list->modals.cur_in_list = screen_list->pty;
+        screen_list->modals.window_list = !screen_list->modals.window_list;
+        refresh = 1;
+        break;
+    case 'd':
+    case 0x04:                 // CACA_KEY_CTRL_D:
+        detach(screen_list);
+        break;
+#ifdef USE_PYTHON
+    case 'e':
+    case 0x05:
+        debug("py : command is %d, setting to 1 (at %p)\n", screen_list->modals.python_command, &screen_list->modals.python_command);
+        screen_list->modals.python_command = 1;
+        refresh = 1;
+        break;
+#endif
+    }
+    return refresh;
+
+}
diff --git a/neercs/old/lock.c b/neercs/old/lock.c
new file mode 100644
index 0000000..925c297
--- /dev/null
+++ b/neercs/old/lock.c
@@ -0,0 +1,221 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <caca.h>
+#include <time.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+
+#if defined USE_LOCK
+#if defined HAVE_PAM_PAM_MISC_H
+#   include <pam/pam_appl.h>
+#   include <pam/pam_misc.h>
+#else
+#   include <security/pam_appl.h>
+#   include <security/pam_misc.h>
+#endif
+#   include <pwd.h>
+#endif
+
+#include "neercs.h"
+
+#if defined USE_LOCK
+static int convpam(int num_msg, const struct pam_message **msg,
+                   struct pam_response **resp, void *appdata_ptr);
+#endif
+
+int update_lock(int c, struct screen_list *screen_list)
+{
+    int refresh = 0;
+
+#if defined USE_LOCK
+    if (!screen_list->lock.locked)
+        return 0;
+
+    if (c == 0x08)              // BACKSPACE
+    {
+        if (screen_list->lock.lock_offset)
+        {
+            screen_list->lock.lockpass[screen_list->lock.lock_offset - 1] = 0;
+            screen_list->lock.lock_offset--;
+        }
+    }
+    else if (c == 0x0d)         // RETURN
+    {
+        memset(screen_list->lock.lockmsg, 0, 1024);
+        if (validate_lock(screen_list, getenv("USER"), screen_list->lock.lockpass))
+        {
+            memset(screen_list->lock.lockpass, 0, 1024);
+            screen_list->lock.locked = 0;
+            screen_list->lock.lock_offset = 0;
+            refresh = 1;
+        }
+        else
+        {
+            memset(screen_list->lock.lockpass, 0, 1024);
+            screen_list->lock.lock_offset = 0;
+            refresh = 1;
+        }
+    }
+    else
+    {
+        if (screen_list->lock.lock_offset < 1023)
+        {
+            screen_list->lock.lockpass[screen_list->lock.lock_offset++] = c;
+            screen_list->lock.lockpass[screen_list->lock.lock_offset] = 0;
+        }
+    }
+#endif
+
+    return refresh;
+}
+
+void draw_lock(struct screen_list *screen_list)
+{
+#if defined USE_LOCK
+    unsigned int i;
+    char buffer[1024];
+    caca_canvas_t *cv = screen_list->cv;
+
+    gethostname(buffer, sizeof(buffer) - 1);
+
+    int w = 65, h = 20;
+    int x = (caca_get_canvas_width(cv) - w) / 2;
+    int y = (caca_get_canvas_height(cv) - h) / 2;
+
+
+    caca_set_color_ansi(cv, CACA_BLUE, CACA_BLUE);
+    caca_fill_box(cv, x, y, w, h, '#');
+    caca_set_color_ansi(cv, CACA_DEFAULT, CACA_BLUE);
+    caca_draw_cp437_box(cv, x, y, w, h);
+
+    x += 2;
+    y++;
+    caca_printf(cv,
+                (caca_get_canvas_width(cv) -
+                 strlen(PACKAGE_STRING " locked")) / 2, y - 1,
+                PACKAGE_STRING " locked");
+
+    caca_printf(cv, x, y++, "Please type in your password for %s@%s :",
+                getenv("USER"), buffer);
+    y += 2;
+
+    x = (caca_get_canvas_width(cv) / 2) -
+        ((strlen(screen_list->lock.lockpass) / 2) + strlen("Password : "));
+    caca_printf(cv, x, y, "Password : ");
+    x += strlen("Password : ");
+    for (i = 0; i < strlen(screen_list->lock.lockpass); i++)
+    {
+        caca_put_str(cv, x, y, "*");
+        x++;
+    }
+
+
+    if (strlen(screen_list->lock.lockmsg))
+    {
+        x = ((caca_get_canvas_width(cv) - w) / 2) +
+            (strlen(screen_list->lock.lockmsg));
+        y += 2;
+        caca_set_color_ansi(cv, CACA_RED, CACA_BLUE);
+        caca_printf(cv, x, y, "Error : %s", screen_list->lock.lockmsg);
+    }
+#endif
+}
+
+
+#if defined USE_LOCK
+
+/* FIXME, handle this without assuming this is a password auth */
+static int convpam(int num_msg, const struct pam_message **msg,
+                   struct pam_response **resp, void *appdata_ptr)
+{
+
+    struct pam_response *aresp;
+    int i;
+    aresp = calloc(num_msg, sizeof(*aresp));
+
+    for (i = 0; i < num_msg; ++i)
+    {
+        switch (msg[i]->msg_style)
+        {
+        case PAM_PROMPT_ECHO_ON:
+        case PAM_PROMPT_ECHO_OFF:
+            aresp[i].resp = strdup(appdata_ptr);
+            aresp[i].resp_retcode = 0;
+            break;
+        case PAM_ERROR_MSG:
+            break;
+        default:
+            printf("Unknow message type from PAM\n");
+            break;
+        }
+    }
+
+    *resp = aresp;
+    return (PAM_SUCCESS);
+}
+#endif
+
+int validate_lock(struct screen_list *screen_list, char *user, char *pass)
+{
+#if USE_LOCK
+    int ret;
+    pam_handle_t *pamh = NULL;
+    char buffer[100];
+    const char *service = "neercs";
+    struct pam_conv conv = {
+        convpam,
+        pass,
+    };
+
+    ret = pam_start(service, user, &conv, &pamh);
+    if (ret != PAM_SUCCESS)
+        return 0;
+    pam_set_item(pamh, PAM_RUSER, user);
+
+    ret = gethostname(buffer, sizeof(buffer) - 1);
+    if (ret)
+    {
+        perror("failed to look up hostname");
+        ret = pam_end(pamh, PAM_ABORT);
+        sprintf(screen_list->lock.lockmsg, "Can't get hostname");
+        pam_end(pamh, PAM_SUCCESS);
+        return 0;
+    }
+
+    ret = pam_set_item(pamh, PAM_RHOST, buffer);
+    if (ret != PAM_SUCCESS)
+    {
+        sprintf(screen_list->lock.lockmsg, "Can't set hostname");
+        pam_end(pamh, PAM_SUCCESS);
+        return 0;
+    }
+
+    ret = pam_authenticate(pamh, 0);
+    if (ret != PAM_SUCCESS)
+    {
+        sprintf(screen_list->lock.lockmsg, "Can't authenticate");
+        pam_end(pamh, PAM_SUCCESS);
+        return 0;
+    }
+
+    ret = pam_end(pamh, PAM_SUCCESS);
+#endif
+
+    return 1;
+}
diff --git a/neercs/old/main.c b/neercs/old/main.c
new file mode 100644
index 0000000..621fcdf
--- /dev/null
+++ b/neercs/old/main.c
@@ -0,0 +1,324 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                2008-2010 Pascal Terjan <pterjan@linuxfr.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <time.h>
+
+
+
+#if !defined HAVE_GETOPT_LONG
+#   include "mygetopt.h"
+#elif defined HAVE_GETOPT_H
+#   include <getopt.h>
+#endif
+#if defined HAVE_GETOPT_LONG
+#   define mygetopt getopt_long
+#   define myoptind optind
+#   define myoptarg optarg
+#   define myoption option
+#endif
+#include <errno.h>
+#include <caca.h>
+
+#include "neercs.h"
+
+
+void version(void)
+{
+    printf("%s\n", PACKAGE_STRING);
+    printf("Copyright (C) 2006, 2008 Sam Hocevar <sam@zoy.org>\n");
+    printf
+        ("                         Jean-Yves Lamoureux <jylam@lnxscene.org>\n\n");
+    printf
+        ("This is free software.  You may redistribute copies of it under the\n");
+    printf
+        ("terms of the Do What The Fuck You Want To Public License, Version 2\n");
+    printf("<http://sam.zoy.org/wtfpl/>.\n");
+    printf("There is NO WARRANTY, to the extent permitted by law.\n");
+    printf("\n");
+    printf
+        ("For more informations, visit http://libcaca.zoy.org/wiki/neercs\n");
+}
+
+void usage(int argc, char **argv)
+{
+    printf("%s\n", PACKAGE_STRING);
+    printf("Usage : %s [command1] [command2] ... [commandN]\n", argv[0]);
+    printf("Example : %s zsh top \n\n", argv[0]);
+    printf("Options :\n");
+    printf("\t--config\t-c <file>\t\tuse given config file\n");
+    printf("\t--pid\t\t-P [pid]\t\tgrab process\n");
+    printf("\t\t\t-r [session]\t\treattach to a detached neercs\n");
+    printf
+        ("\t\t\t-R [session]\t\treattach if possible, otherwise start a new session\n");
+    printf("\t\t\t-S <name>\t\tname this session <name> instead of <pid>\n");
+    printf("\t--lock-after\t-l [n]\t\t\tlock screen after n seconds\n");
+    printf("\t--version\t-v \t\t\tdisplay version and exit\n");
+    printf("\t--help\t\t-h \t\t\tthis help\n");
+}
+
+#if 0
+int main(int argc, char **argv)
+{
+    struct screen_list *screen_list = init_neercs(argc, argv);
+    if (!screen_list)
+        return -1;
+
+    mainloop(screen_list);
+}
+#endif
+
+struct screen_list *init_neercs(int argc, char **argv)
+{
+    struct screen_list *screen_list = NULL;
+    int args;
+
+    int mainret = -1;
+
+    screen_list = create_screen_list();
+    screen_list->sys.default_shell = getenv("SHELL");
+
+    args = argc - 1;
+    if (screen_list->sys.default_shell == NULL && args <= 0)
+    {
+        fprintf(stderr,
+                "Environment variable SHELL not set and no arguments given. kthxbye.\n");
+        free_screen_list(screen_list);
+        return NULL;
+    }
+
+    if (handle_command_line(argc, argv, screen_list) < 0)
+    {
+        free_screen_list(screen_list);
+        return NULL;
+    }
+
+    /* Read global configuration first */
+    read_configuration_file("/etc/neercsrc", screen_list);
+
+    /* Then local one */
+    if (screen_list->sys.user_path)
+    {
+        read_configuration_file(screen_list->sys.user_path, screen_list);
+        free(screen_list->sys.user_path);
+    }
+
+    if (screen_list->sys.attach)
+    {
+        if (screen_list->sys.nb_to_grab || screen_list->sys.to_start)
+        {
+            fprintf(stderr,
+                    "-R can not be associated with commands or pids!\n");
+            free_screen_list(screen_list);
+            return NULL;
+        }
+
+        attach(screen_list);
+
+        if (screen_list->sys.forceattach && !screen_list->sys.attach)
+        {
+            free_screen_list(screen_list);
+            return NULL;
+        }
+    }
+
+    /* Build default session name */
+    if (!screen_list->comm.session_name)
+    {
+        char mypid[32];         /* FIXME Compute the length of PID_MAX ? */
+        snprintf(mypid, 31, "%d", getpid());
+        mypid[31] = '\0';
+        screen_list->comm.session_name = strdup(mypid);
+        if (!screen_list->comm.session_name)
+        {
+            fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__,
+                    __LINE__);
+            free_screen_list(screen_list);
+            return NULL;
+        }
+    }
+    if (!screen_list->comm.socket_path[SOCK_CLIENT])
+        screen_list->comm.socket_path[SOCK_CLIENT] =
+            build_socket_path(screen_list->comm.socket_dir,
+                              screen_list->comm.session_name, SOCK_CLIENT);
+
+    if (!screen_list->comm.socket_path[SOCK_SERVER])
+        screen_list->comm.socket_path[SOCK_SERVER] =
+            build_socket_path(screen_list->comm.socket_dir,
+                              screen_list->comm.session_name, SOCK_SERVER);
+
+    /* Fork the server if needed */
+    if (!screen_list->sys.attach)
+    {
+        debug("Spawning a new server");
+        if (start_server(screen_list))
+        {
+            free_screen_list(screen_list);
+            return NULL;
+        }
+        if (start_client(screen_list))
+        {
+            free_screen_list(screen_list);
+            return NULL;
+        }
+    }
+
+    return screen_list;
+}
+
+int handle_command_line(int argc, char *argv[],
+                        struct screen_list *screen_list)
+{
+    int s = 0, i;
+    for (;;)
+    {
+        int option_index = 0;
+        int pidopt;
+        static struct myoption long_options[] = {
+            {"config", 1, NULL, 'c'},
+#if defined USE_GRAB
+            {"pid", 0, NULL, 'P'},
+#endif
+            {"lock-after", 1, NULL, 'l'},
+            {"help", 0, NULL, 'h'},
+            {"version", 0, NULL, 'v'},
+            {NULL, 0, NULL, 0},
+        };
+#if defined USE_GRAB
+        int c =
+            mygetopt(argc, argv, "c:S:R::l::r::P::hv", long_options,
+                     &option_index);
+#else
+        int c =
+            mygetopt(argc, argv, "c:S:R::l::r::hv", long_options,
+                     &option_index);
+#endif
+        if (c == -1)
+            break;
+
+        switch (c)
+        {
+        case 'c':              /* --config */
+            if (screen_list->sys.user_path)
+                free(screen_list->sys.user_path);
+            screen_list->sys.user_path = strdup(myoptarg);
+            s += 2;
+            break;
+        case 'S':
+            if (!screen_list->comm.session_name)
+                screen_list->comm.session_name = strdup(myoptarg);
+            s += 2;
+            break;
+        case 'P':              /* --pid */
+            if (myoptarg)
+            {
+                pidopt = atoi(myoptarg);
+                if (pidopt <= 0)
+                {
+                    fprintf(stderr, "Invalid pid %d\n", pidopt);
+                    if (screen_list->sys.to_grab)
+                        free(screen_list->sys.to_grab);
+                    return -1;
+                }
+            }
+            else
+                pidopt = select_process(screen_list);
+            if (pidopt <= 0)
+            {
+                s += 1;
+                break;
+            }
+            if (!screen_list->sys.to_grab)
+            {
+                /* At most argc-1-s times -P <pid> + final 0 */
+                screen_list->sys.to_grab =
+                    (int *)malloc(((argc - 1 - s) / 2 + 1) * sizeof(int));
+                if (!screen_list->sys.to_grab)
+                {
+                    fprintf(stderr, "Can't allocate memory at %s:%d\n",
+                            __FUNCTION__, __LINE__);
+                    return -1;
+                }
+            }
+            screen_list->sys.to_grab[screen_list->sys.nb_to_grab++] = pidopt;
+            screen_list->sys.to_grab[screen_list->sys.nb_to_grab] = 0;
+            s += 2;
+            break;
+        case 'l':
+            screen_list->lock.autolock_timeout = atoi(myoptarg) * 1000000;
+            if (screen_list->lock.autolock_timeout == 0)
+                screen_list->lock.autolock_timeout -= 1;
+            break;
+        case 'r':
+            screen_list->sys.forceattach = 1;
+        case 'R':
+            if (screen_list->sys.attach)
+            {
+                fprintf(stderr, "Attaching can only be requested once\n");
+                return -1;
+            }
+            if (myoptarg)
+            {
+                if (screen_list->comm.session_name)
+                    free(screen_list->comm.session_name);
+                screen_list->comm.session_name = strdup(myoptarg);
+                s += 1;
+            }
+            screen_list->sys.attach = 1;
+            s += 1;
+            break;
+        case 'h':              /* --help */
+            usage(argc, argv);
+            return -1;
+            break;
+        case 'v':              /* --version */
+            version();
+            return -1;
+            break;
+        case -2:
+            return -1;
+        default:
+            fprintf(stderr, "Unknown argument #%d\n", myoptind);
+            return -1;
+            break;
+        }
+    }
+    if (s >= 0 && s < argc - 1)
+    {
+        screen_list->sys.to_start = (char **)malloc((argc - s) * sizeof(char *));
+        if (!screen_list->sys.to_start)
+        {
+            fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__,
+                    __LINE__);
+            return -1;
+        }
+        for (i = 0; i < (argc - 1) - s; i++)
+        {
+            screen_list->sys.to_start[i] = strdup(argv[i + s + 1]);
+        }
+        screen_list->sys.to_start[argc - 1 - s] = NULL;
+    }
+    return s;
+}
diff --git a/neercs/old/mini-client.c b/neercs/old/mini-client.c
new file mode 100644
index 0000000..ed06f8f
--- /dev/null
+++ b/neercs/old/mini-client.c
@@ -0,0 +1,94 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2011 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                2008-2010 Pascal Terjan <pterjan@linuxfr.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#if defined HAVE_CONFIG_H
+#   include "config.h"
+#endif
+
+#include <stdio.h> /* BUFSIZ */
+#include <string.h> /* strncmp() */
+
+#include <caca.h>
+
+#include "mini-neercs.h"
+#include "mini-socket.h"
+
+static caca_display_t *dp;
+static caca_canvas_t *cv;
+static nrx_socket_t *insock, *outsock;
+
+void client_init(void)
+{
+    int i, usec = 10000;
+
+    cv = caca_create_canvas(0, 0);
+    dp = caca_create_display(cv);
+    caca_set_display_title(dp, "Press Esc to quit");
+
+    insock = socket_open("/tmp/neercs.sock.client", 1);
+
+    for (i = 0; i < 10; i++)
+    {
+        outsock = socket_open("/tmp/neercs.sock", 0);
+        if (outsock)
+            break;
+        usleep(usec);
+        usec += usec;
+    }
+
+    socket_puts(outsock, "CONNECT /tmp/neercs.sock.client");
+}
+
+int client_step(void)
+{
+    caca_event_t ev;
+    int ret;
+
+    /* Handle client sockets */
+    ret = socket_select(insock, 1000);
+    if (ret > 0)
+    {
+        char buf[BUFSIZ];
+        ssize_t bytes = socket_read(insock, buf, BUFSIZ);
+        if (bytes <= 0)
+            return 1;
+
+        /* Parse message */
+        if (!strncmp(buf, "OK", strlen("OK")))
+        {
+            fprintf(stderr, "neercs: connection established\n");
+socket_puts(insock, "TEST insock");
+        }
+    }
+
+    /* Handle libcaca events */
+    if(caca_get_event(dp, CACA_EVENT_KEY_PRESS, &ev, 1000)
+        && caca_get_event_key_ch(&ev) == CACA_KEY_ESCAPE)
+        return 0;
+
+    return 1;
+}
+
+void client_fini(void)
+{
+    socket_puts(outsock, "QUIT /tmp/neercs.sock.client");
+
+    caca_free_display(dp);
+    caca_free_canvas(cv);
+    if (insock)
+        socket_close(insock);
+    if (outsock)
+        socket_close(outsock);
+}
+
diff --git a/neercs/old/mini-neercs.c b/neercs/old/mini-neercs.c
new file mode 100644
index 0000000..bfb7003
--- /dev/null
+++ b/neercs/old/mini-neercs.c
@@ -0,0 +1,52 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                2008-2010 Pascal Terjan <pterjan@linuxfr.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#if defined HAVE_CONFIG_H
+#   include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h> /* perror() */
+#include <unistd.h> /* fork() */
+
+#include "mini-neercs.h"
+
+int main(void)
+{
+    pid_t pid;
+
+    pid = fork();
+
+    if (pid < 0)
+    {
+        perror("fork");
+        return EXIT_FAILURE;
+    }
+
+    if (pid > 0)
+    {
+        client_init();
+        while(client_step()) ;
+        client_fini();
+    }
+    else
+    {
+        server_init();
+        while(server_step()) ;
+        server_fini();
+    }
+
+    return EXIT_SUCCESS;
+}
+
diff --git a/neercs/old/mini-neercs.h b/neercs/old/mini-neercs.h
new file mode 100644
index 0000000..d898a8b
--- /dev/null
+++ b/neercs/old/mini-neercs.h
@@ -0,0 +1,22 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                2008-2010 Pascal Terjan <pterjan@linuxfr.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+void client_init(void);
+int client_step(void);
+void client_fini(void);
+
+void server_init(void);
+int server_step(void);
+void server_fini(void);
+
diff --git a/neercs/old/mini-server.c b/neercs/old/mini-server.c
new file mode 100644
index 0000000..5dd556d
--- /dev/null
+++ b/neercs/old/mini-server.c
@@ -0,0 +1,80 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2011 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                2008-2010 Pascal Terjan <pterjan@linuxfr.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#if defined HAVE_CONFIG_H
+#   include "config.h"
+#endif
+
+#include <stdio.h> /* BUFSIZ */
+#include <string.h> /* strncmp() */
+
+#include "mini-neercs.h"
+#include "mini-socket.h"
+
+static nrx_socket_t *insock, *outsock;
+
+void server_init(void)
+{
+while (!insock)
+    insock = socket_open("/tmp/neercs.sock", 1);
+}
+
+int server_step(void)
+{
+    char buf[BUFSIZ];
+    ssize_t bytes;
+    int ret;
+
+    if (outsock)
+    {
+        ret = socket_select(outsock, 1000);
+        if (ret <= 0)
+            goto nothing;
+
+        bytes = socket_read(outsock, buf, BUFSIZ);
+        if (bytes <= 0)
+            goto nothing;
+    }
+nothing:
+
+    ret = socket_select(insock, 1000);
+    if (ret <= 0)
+        return 1;
+
+    bytes = socket_read(insock, buf, BUFSIZ);
+    if (bytes <= 0)
+        return 1;
+
+    /* Parse message */
+    if (!strncmp(buf, "CONNECT ", strlen("CONNECT ")))
+    {
+        outsock = socket_open(buf + strlen("CONNECT "), 0);
+        socket_puts(outsock, "OK");
+    }
+    else if (!strncmp(buf, "QUIT ", strlen("QUIT ")))
+    {
+        return 0;
+    }
+
+    return 1;
+}
+
+void server_fini(void)
+{
+    if (insock)
+        socket_close(insock);
+    if (outsock)
+        socket_close(outsock);
+}
+
diff --git a/neercs/old/mini-socket.c b/neercs/old/mini-socket.c
new file mode 100644
index 0000000..3d303a5
--- /dev/null
+++ b/neercs/old/mini-socket.c
@@ -0,0 +1,297 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2011 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                2008-2010 Pascal Terjan <pterjan@linuxfr.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#if defined HAVE_CONFIG_H
+#   include "config.h"
+#endif
+
+#include <stdio.h> /* perror() */
+#include <stdlib.h> /* malloc(), free() */
+#include <unistd.h> /* unlink() */
+#include <fcntl.h> /* fcntl() */
+#include <string.h> /* memcpy() */
+#include <sys/select.h> /* select() */
+#include <sys/types.h> /* bind(), connect() */
+#include <sys/socket.h> /* bind(), connect() */
+#include <sys/stat.h>  /* stat(), struct stat */
+#include <sys/un.h> /* AF_UNIX */
+#include <errno.h> /* AF_UNIX */
+#include <time.h> /* time */
+
+#include "mini-neercs.h"
+#include "mini-socket.h"
+
+#define SIZEOF_SUN_PATH (sizeof(((struct sockaddr_un *)NULL)->sun_path))
+
+#define offsetof(s, f) ((int)(intptr_t)((s *)NULL)->f)
+
+struct nrx_socket
+{
+#if 1
+    /* Linux sockets */
+    int fd;
+    int server;
+    int connected;
+    char path[SIZEOF_SUN_PATH];
+#else
+#   error No socket implementation
+#endif
+};
+
+#define QLEN 10
+
+int
+serv_listen(const char *name)
+{
+    int                 fd, len, err, rval;
+    struct sockaddr_un  un;
+
+    /* create a UNIX domain stream socket */
+    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+       return(-1);
+    unlink(name);   /* in case it already exists */
+
+    /* fill in socket address structure */
+    memset(&un, 0, sizeof(un));
+    un.sun_family = AF_UNIX;
+    strcpy(un.sun_path, name);
+    len = offsetof(struct sockaddr_un, sun_path) + strlen(name);
+
+    /* bind the name to the descriptor */
+    if (bind(fd, (struct sockaddr *)&un, len) < 0) {
+        rval = -2;
+        goto errout;
+    }
+    if (listen(fd, QLEN) < 0) { /* tell kernel we're a server */
+        rval = -3;
+        goto errout;
+    }
+    return(fd);
+
+errout:
+    err = errno;
+    close(fd);
+    errno = err;
+    return(rval);
+}
+
+#define STALE   30  /* client's name can't be older than this (sec) */
+
+/*
+ * Wait for a client connection to arrive, and accept it.
+ * We also obtain the client's user ID from the pathname
+ * that it must bind before calling us.
+ * Returns new fd if all OK, <0 on error
+ */
+int
+serv_accept(int listenfd, uid_t *uidptr)
+{
+    int                 clifd, len, err, rval;
+    time_t              staletime;
+    struct sockaddr_un  un;
+    struct stat         statbuf;
+
+    len = sizeof(un);
+    if ((clifd = accept(listenfd, (struct sockaddr *)&un, &len)) < 0)
+        return(-1);     /* often errno=EINTR, if signal caught */
+
+    /* obtain the client's uid from its calling address */
+    len -= offsetof(struct sockaddr_un, sun_path); /* len of pathname */
+    un.sun_path[len] = 0;           /* null terminate */
+
+    if (stat(un.sun_path, &statbuf) < 0) {
+        rval = -2;
+        goto errout;
+    }
+#ifdef S_ISSOCK     /* not defined for SVR4 */
+    if (S_ISSOCK(statbuf.st_mode) == 0) {
+        rval = -3;      /* not a socket */
+        goto errout;
+    }
+#endif
+    if ((statbuf.st_mode & (S_IRWXG | S_IRWXO)) ||
+        (statbuf.st_mode & S_IRWXU) != S_IRWXU) {
+          rval = -4;     /* is not rwx------ */
+          goto errout;
+    }
+
+    staletime = time(NULL) - STALE;
+    if (statbuf.st_atime < staletime ||
+        statbuf.st_ctime < staletime ||
+        statbuf.st_mtime < staletime) {
+          rval = -5;    /* i-node is too old */
+          goto errout;
+    }
+    if (uidptr != NULL)
+        *uidptr = statbuf.st_uid;   /* return uid of caller */
+    unlink(un.sun_path);        /* we're done with pathname now */
+    return(clifd);
+
+errout:
+    err = errno;
+    close(clifd);
+    errno = err;
+    return(rval);
+}
+
+#define CLI_PATH    "/var/tmp/"      /* +5 for pid = 14 chars */
+#define CLI_PERM    S_IRWXU          /* rwx for user only */
+
+/*
+ * Create a client endpoint and connect to a server.
+ * Returns fd if all OK, <0 on error.
+ */
+int
+cli_conn(const char *name)
+{
+    int                fd, len, err, rval;
+    struct sockaddr_un un;
+
+    /* create a UNIX domain stream socket */
+    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+        return(-1);
+
+    /* fill socket address structure with our address */
+    memset(&un, 0, sizeof(un));
+    un.sun_family = AF_UNIX;
+    sprintf(un.sun_path, "%s%05d", CLI_PATH, getpid());
+    len = offsetof(struct sockaddr_un, sun_path) + strlen(un.sun_path);
+
+    unlink(un.sun_path);        /* in case it already exists */
+    if (bind(fd, (struct sockaddr *)&un, len) < 0) {
+        rval = -2;
+        goto errout;
+    }
+    if (chmod(un.sun_path, CLI_PERM) < 0) {
+        rval = -3;
+        goto errout;
+    }
+    /* fill socket address structure with server's address */
+    memset(&un, 0, sizeof(un));
+    un.sun_family = AF_UNIX;
+    strcpy(un.sun_path, name);
+    len = offsetof(struct sockaddr_un, sun_path) + strlen(name);
+    if (connect(fd, (struct sockaddr *)&un, len) < 0) {
+        rval = -4;
+        goto errout;
+    }
+    return(fd);
+
+errout:
+    err = errno;
+    close(fd);
+    errno = err;
+    return(rval);
+}
+
+nrx_socket_t * socket_open(char const *path, int server)
+{
+    nrx_socket_t * sock;
+    struct sockaddr_un addr;
+    int ret, fd;
+
+#if 0
+    fd = socket(AF_UNIX, SOCK_STREAM, 0);
+    //fd = socket(AF_UNIX, SOCK_DGRAM, 0);
+    if (fd < 0)
+    {
+        perror("socket creation");
+        return NULL;
+    }
+
+    memset(&addr, 0, sizeof(struct sockaddr_un));
+    addr.sun_family = AF_UNIX;
+    strncpy(addr.sun_path, path, SIZEOF_SUN_PATH - 1);
+
+    if (server)
+    {
+        unlink(path);
+        ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+    }
+    else
+    {
+        ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
+    }
+
+    if (ret < 0)
+    {
+        perror(server ? "socket binding" : "socket connection");
+        close(fd);
+        return NULL;
+    }
+
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+#endif
+if (server)
+    fd = serv_listen(path);
+else
+    fd = cli_conn(path);
+if (fd < 0) return NULL;
+
+    sock = malloc(sizeof(*sock));
+    sock->fd = fd;
+    sock->server = server;
+    sock->connected = 0;
+    strncpy(sock->path, path, SIZEOF_SUN_PATH - 1);
+
+    return sock;
+}
+
+int socket_select(nrx_socket_t *sock, int usecs)
+{
+    fd_set rfds;
+    struct timeval tv;
+    int ret;
+
+    FD_ZERO(&rfds);
+    FD_SET(sock->fd, &rfds);
+
+    tv.tv_sec = usecs / 1000000;
+    tv.tv_usec = usecs % 1000000;
+
+    ret = select(sock->fd + 1, &rfds, NULL, NULL, &tv);
+    if (ret < 0)
+        return -1;
+
+    if (FD_ISSET(sock->fd, &rfds))
+        return 1;
+
+    return 0;
+}
+
+int socket_puts(nrx_socket_t *sock, char const *str)
+{
+    int ret;
+fprintf(stderr, "pid %i sending %i bytes on %s: %s\n", getpid(), (int)strlen(str), sock->path, str);
+    ret = write(sock->fd, str, strlen(str));
+    return ret;
+}
+
+ssize_t socket_read(nrx_socket_t *sock, void *buf, size_t count)
+{
+    int ret;
+    ret = read(sock->fd, buf, count);
+if (ret >= 0) ((char *)buf)[ret] = 0;
+if (ret >= 0) fprintf(stderr, "pid %i recving %i bytes on %s: %s\n", getpid(), ret, sock->path, (char *)buf);
+    return ret;
+}
+
+void socket_close(nrx_socket_t *sock)
+{
+    close(sock->fd);
+    if (sock->server)
+        unlink(sock->path);
+    free(sock);
+}
+
diff --git a/neercs/old/mini-socket.h b/neercs/old/mini-socket.h
new file mode 100644
index 0000000..709e5fa
--- /dev/null
+++ b/neercs/old/mini-socket.h
@@ -0,0 +1,24 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                2008-2010 Pascal Terjan <pterjan@linuxfr.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include <sys/types.h>
+
+typedef struct nrx_socket nrx_socket_t;
+
+nrx_socket_t * socket_open(char const *path, int server);
+int socket_select(nrx_socket_t *sock, int usecs);
+int socket_puts(nrx_socket_t *sock, char const *str);
+ssize_t socket_read(nrx_socket_t *sock, void *buf, size_t count);
+void socket_close(nrx_socket_t *socket);
+
diff --git a/neercs/old/mygetopt.c b/neercs/old/mygetopt.c
new file mode 100644
index 0000000..44f6863
--- /dev/null
+++ b/neercs/old/mygetopt.c
@@ -0,0 +1,125 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+/*
+ *  mygetopt.c: getopt_long reimplementation
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "caca_types.h"
+
+#include "mygetopt.h"
+
+int myoptind = 1;
+char *myoptarg = NULL;
+
+/* XXX: this getopt_long implementation should not be trusted for other
+   applications without any serious peer reviewing. It “just works” with
+   zzuf but may fail miserably in other programs. */
+int mygetopt(int argc, char *const _argv[], const char *optstring,
+             const struct myoption *longopts, int *longindex)
+{
+    char **argv = (char **)(uintptr_t) _argv;
+    char *flag;
+    int i;
+
+    if (myoptind >= argc)
+        return -1;
+
+    flag = argv[myoptind];
+
+    if (flag[0] == '-' && flag[1] != '-')
+    {
+        char *tmp;
+        int ret = flag[1];
+
+        if (ret == '\0')
+            return -1;
+
+        tmp = strchr(optstring, ret);
+        if (!tmp || ret == ':')
+            return '?';
+
+        myoptind++;
+        if (tmp[1] == ':')
+        {
+            if (flag[2] != '\0')
+                myoptarg = flag + 2;
+            else if (myoptind >= argc)
+            {
+                if (tmp[2] != ':')
+                {
+                    fprintf(stderr, "%s: `%s' needs an argument\n", argv[0],
+                            flag);
+                    return -2;
+                }
+            }
+            else
+                myoptarg = argv[myoptind++];
+            return ret;
+        }
+
+        if (flag[2] != '\0')
+        {
+            flag[1] = '-';
+            myoptind--;
+            argv[myoptind]++;
+        }
+
+        return ret;
+    }
+
+    if (flag[0] == '-' && flag[1] == '-')
+    {
+        if (flag[2] == '\0')
+            return -1;
+
+        for (i = 0; longopts[i].name; i++)
+        {
+            size_t l = strlen(longopts[i].name);
+
+            if (strncmp(flag + 2, longopts[i].name, l))
+                continue;
+
+            switch (flag[2 + l])
+            {
+            case '=':
+                if (!longopts[i].has_arg)
+                    goto bad_opt;
+                if (longindex)
+                    *longindex = i;
+                myoptind++;
+                myoptarg = flag + 2 + l + 1;
+                return longopts[i].val;
+            case '\0':
+                if (longindex)
+                    *longindex = i;
+                myoptind++;
+                if (longopts[i].has_arg)
+                    myoptarg = argv[myoptind++];
+                return longopts[i].val;
+            default:
+                break;
+            }
+        }
+      bad_opt:
+        fprintf(stderr, "%s: unrecognized option `%s'\n", argv[0], flag);
+        return '?';
+    }
+
+    return -1;
+}
diff --git a/neercs/old/mygetopt.h b/neercs/old/mygetopt.h
new file mode 100644
index 0000000..f5d50a0
--- /dev/null
+++ b/neercs/old/mygetopt.h
@@ -0,0 +1,30 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+/*
+ *  mygetopt.h: getopt_long reimplementation
+ */
+
+struct myoption
+{
+    const char *name;
+    int has_arg;
+    int *flag;
+    int val;
+};
+
+extern int myoptind;
+extern char *myoptarg;
+
+int mygetopt(int, char * const[], const char *, const struct myoption *, int *);
+
diff --git a/neercs/old/mytrace.c b/neercs/old/mytrace.c
new file mode 100644
index 0000000..7d8a7f0
--- /dev/null
+++ b/neercs/old/mytrace.c
@@ -0,0 +1,785 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2008-2010 Pascal Terjan <pterjan@linuxfr.org>
+ *                2008-2010 Sam Hocevar <sam@hocevar.net>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined USE_GRAB
+#   include <sys/ioctl.h>
+#   include <sys/ptrace.h>
+#   include <sys/stat.h>
+#   include <sys/syscall.h>
+#   include <sys/user.h>
+#   include <sys/wait.h>
+#endif
+
+#include "neercs.h"
+#include "mytrace.h"
+
+#if defined USE_GRAB
+static int memcpy_from_target(struct mytrace *t,
+                              char *dest, long src, size_t n);
+static int memcpy_into_target(struct mytrace *t,
+                              long dest, char const *src, size_t n);
+static long remote_syscall(struct mytrace *t, long call,
+                           long arg1, long arg2, long arg3);
+#   if defined DEBUG
+static void print_registers(pid_t pid);
+#   else
+#       define print_registers(x) do {} while(0)
+#   endif
+
+#define X(x) #x
+#define STRINGIFY(x) X(x)
+
+#define SYSCALL_X86     0x80cd  /* CD 80 = int $0x80 */
+#define SYSCALL_X86_NEW 0xf3eb  /* EB F3 = jmp <__kernel_vsyscall+0x3> */
+#define SYSENTER        0x340f  /* 0F 34 = sysenter */
+#define SYSCALL_AMD64   0x050fL /* 0F 05 = syscall */
+
+#if defined __x86_64__
+#   define RAX rax
+#   define RBX rbx
+#   define RCX rcx
+#   define RDX rdx
+#   define RSP rsp
+#   define RBP rbp
+#   define RIP rip
+#   define RDI rdi
+#   define RSI rsi
+#   define FMT "%016lx"
+#else
+#   define RAX eax
+#   define RBX ebx
+#   define RCX ecx
+#   define RDX edx
+#   define RSP esp
+#   define RBP ebp
+#   define RIP eip
+#   define RDI edi
+#   define RSI esi
+#   define FMT "%08lx"
+#endif
+
+#define MYCALL_OPEN     0
+#define MYCALL_CLOSE    1
+#define MYCALL_WRITE    2
+#define MYCALL_DUP2     3
+#define MYCALL_SETPGID  4
+#define MYCALL_SETSID   5
+#define MYCALL_KILL     6
+#define MYCALL_FORK     7
+#define MYCALL_EXIT     8
+#define MYCALL_EXECVE   9
+#define MYCALL_IOCTL   10
+
+#if defined __x86_64__
+/* from unistd_32.h on an amd64 system */
+int syscalls32[] = { 5, 6, 4, 63, 57, 66, 37, 2, 1, 11, 54 };
+
+int syscalls64[] =
+#else
+int syscalls32[] =
+#endif
+{ SYS_open, SYS_close, SYS_write, SYS_dup2, SYS_setpgid, SYS_setsid,
+    SYS_kill, SYS_fork, SYS_exit, SYS_execve, SYS_ioctl
+};
+
+char const *syscallnames[] =
+    { "open", "close", "write", "dup2", "setpgid", "setsid", "kill", "fork",
+    "exit", "execve", "ioctl"
+};
+
+#endif /* USE_GRAB */
+
+struct mytrace
+{
+    pid_t pid, child;
+};
+
+struct mytrace *mytrace_attach(long int pid)
+{
+#if defined USE_GRAB
+    struct mytrace *t;
+    int status;
+
+    if (ptrace(PTRACE_ATTACH, pid, 0, 0) < 0)
+    {
+        perror("PTRACE_ATTACH (attach)");
+        return NULL;
+    }
+    if (waitpid(pid, &status, 0) < 0)
+    {
+        perror("waitpid");
+        return NULL;
+    }
+    if (!WIFSTOPPED(status))
+    {
+        fprintf(stderr, "traced process was not stopped\n");
+        ptrace(PTRACE_DETACH, pid, 0, 0);
+        return NULL;
+    }
+
+    t = malloc(sizeof(struct mytrace));
+    t->pid = pid;
+    t->child = 0;
+
+    return t;
+#else
+    errno = ENOSYS;
+    return NULL;
+#endif
+}
+
+struct mytrace *mytrace_fork(struct mytrace *t)
+{
+#if defined USE_GRAB
+    struct mytrace *child;
+
+    ptrace(PTRACE_SETOPTIONS, t->pid, NULL, PTRACE_O_TRACEFORK);
+    remote_syscall(t, MYCALL_FORK, 0, 0, 0);
+    waitpid(t->child, NULL, 0);
+
+    child = malloc(sizeof(struct mytrace));
+    child->pid = t->child;
+    child->child = 0;
+
+    return child;
+#else
+    errno = ENOSYS;
+    return NULL;
+#endif
+}
+
+int mytrace_detach(struct mytrace *t)
+{
+#if defined USE_GRAB
+    ptrace(PTRACE_DETACH, t->pid, 0, 0);
+    free(t);
+
+    return 0;
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
+
+long mytrace_getpid(struct mytrace *t)
+{
+#if defined USE_GRAB
+    return t->pid;
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
+
+int mytrace_open(struct mytrace *t, char const *path, int mode)
+{
+#if defined USE_GRAB
+    char backup_data[4096];
+    struct user_regs_struct regs;
+    size_t size = strlen(path) + 1;
+    int ret, err;
+
+    if (ptrace(PTRACE_GETREGS, t->pid, NULL, &regs) < 0)
+    {
+        perror("PTRACE_GETREGS (open)\n");
+        return -1;
+    }
+
+    /* Backup the data that we will use */
+    if (memcpy_from_target(t, backup_data, regs.RSP, size) < 0)
+        return -1;
+
+    memcpy_into_target(t, regs.RSP, path, size);
+
+    ret = remote_syscall(t, MYCALL_OPEN, regs.RSP, O_RDWR, 0755);
+    err = errno;
+
+    /* Restore the data */
+    memcpy_into_target(t, regs.RSP, backup_data, size);
+
+    errno = err;
+    return ret;
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
+
+int mytrace_close(struct mytrace *t, int fd)
+{
+#if defined USE_GRAB
+    return remote_syscall(t, MYCALL_CLOSE, fd, 0, 0);
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
+
+int mytrace_write(struct mytrace *t, int fd, char const *data, size_t len)
+{
+#if defined USE_GRAB
+    struct user_regs_struct regs;
+    char *backup_data;
+    int ret, err;
+
+    if (ptrace(PTRACE_GETREGS, t->pid, NULL, &regs) < 0)
+    {
+        perror("PTRACE_GETREGS (write)\n");
+        return -1;
+    }
+
+    backup_data = malloc(len);
+
+    /* Backup the data that we will use */
+    if (memcpy_from_target(t, backup_data, regs.RSP, len) < 0)
+        return -1;
+
+    memcpy_into_target(t, regs.RSP, data, len);
+
+    ret = remote_syscall(t, MYCALL_WRITE, fd, regs.RSP, len);
+    err = errno;
+
+    /* Restore the data */
+    memcpy_into_target(t, regs.RSP, backup_data, len);
+
+    errno = err;
+    return ret;
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
+
+int mytrace_dup2(struct mytrace *t, int oldfd, int newfd)
+{
+#if defined USE_GRAB
+    return remote_syscall(t, MYCALL_DUP2, oldfd, newfd, 0);
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
+
+int mytrace_setpgid(struct mytrace *t, long pid, long pgid)
+{
+#if defined USE_GRAB
+    return remote_syscall(t, MYCALL_SETPGID, pid, pgid, 0);
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
+
+int mytrace_setsid(struct mytrace *t)
+{
+#if defined USE_GRAB
+    return remote_syscall(t, MYCALL_SETSID, 0, 0, 0);
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
+
+int mytrace_kill(struct mytrace *t, long pid, int sig)
+{
+#if defined USE_GRAB
+    return remote_syscall(t, MYCALL_KILL, pid, sig, 0);
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
+
+int mytrace_exit(struct mytrace *t, int status)
+{
+#if defined USE_GRAB
+    ptrace(PTRACE_SETOPTIONS, t->pid, NULL, PTRACE_O_TRACEEXIT);
+    return remote_syscall(t, MYCALL_EXIT, status, 0, 0);
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
+
+int mytrace_exec(struct mytrace *t, char const *command)
+{
+#if defined USE_GRAB
+    struct user_regs_struct regs;
+    char *env, *p;
+    long p2, envaddr, argvaddr, envptraddr;
+    char envpath[PATH_MAX + 1];
+    ssize_t envsize = 16 * 1024;
+    int ret, fd, l, l2;
+    char *nullp = NULL;
+    ssize_t r;
+
+    ptrace(PTRACE_SETOPTIONS, t->pid, NULL, PTRACE_O_TRACEEXEC);
+
+    if (ptrace(PTRACE_GETREGS, t->pid, NULL, &regs) < 0)
+    {
+        perror("PTRACE_GETREGS (exec)\n");
+        return -1;
+    }
+
+    debug("PTRACE_GETREGS done");
+    env = malloc(envsize);
+    if (!env)
+        return -1;
+
+    snprintf(envpath, PATH_MAX, "/proc/%d/environ", t->pid);
+
+    fd = open(envpath, O_RDONLY);
+    if (fd == -1)
+        return -1;
+    r = read(fd, env, envsize);
+    close(fd);
+    if (r == -1)
+        return -1;
+    while (r == envsize)
+    {
+        free(env);
+        env = malloc(envsize);
+        if (!env)
+            return -1;
+        fd = open(envpath, O_RDONLY);
+        r = read(fd, env, envsize);
+        close(fd);
+        if (r == -1)
+            return -1;
+    }
+    envsize = r;
+    l2 = sizeof(char *);        /* Size of a pointer */
+    p2 = regs.RSP;
+
+    /* First argument is the command string */
+    l = strlen(command) + 1;
+    memcpy_into_target(t, p2, command, l);
+    p2 += l;
+
+    /* Second argument is argv */
+    argvaddr = p2;
+    /* argv[0] is a pointer to the command string */
+    memcpy_into_target(t, p2, (char *)&regs.RSP, l2);
+    p2 += l2;
+    /* Then follows a NULL pointer */
+    memcpy_into_target(t, p2, (char *)&nullp, l2);
+    p2 += l2;
+
+    /* Third argument is the environment */
+    /* First, copy all the strings */
+    memcpy_into_target(t, p2, env, envsize);
+    envaddr = p2;
+    p2 += envsize;
+    /* Then write an array of pointers to the strings */
+    envptraddr = p2;
+    p = env;
+    while (p < env + envsize)
+    {
+        long diffp = p - env + envaddr;
+        memcpy_into_target(t, p2, (char *)&diffp, l2);
+        p2 += l2;
+        p += strlen(p) + 1;
+    }
+    /* And have a NULL pointer at the end of the array */
+    memcpy_into_target(t, p2, (char *)&nullp, l2);
+    free(env);
+
+    ret = remote_syscall(t, MYCALL_EXECVE, regs.RSP, argvaddr, envptraddr);
+
+    return ret;
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
+
+int mytrace_tcgets(struct mytrace *t, int fd, struct termios *tos)
+{
+#if defined USE_GRAB
+    char backup_data[4096];
+    struct user_regs_struct regs;
+    size_t size = sizeof(struct termios);
+    int ret, err;
+
+    if (ptrace(PTRACE_GETREGS, t->pid, NULL, &regs) < 0)
+    {
+        perror("PTRACE_GETREGS (tcgets)\n");
+        return -1;
+    }
+
+    /* Backup the data that we will use */
+    if (memcpy_from_target(t, backup_data, regs.RSP, size) < 0)
+        return -1;
+
+    ret = remote_syscall(t, MYCALL_IOCTL, fd, TCGETS, regs.RSP);
+    err = errno;
+
+    memcpy_from_target(t, (char *)tos, regs.RSP, size);
+
+    /* Restore the data */
+    memcpy_into_target(t, regs.RSP, backup_data, size);
+
+    errno = err;
+    return ret;
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
+
+int mytrace_tcsets(struct mytrace *t, int fd, struct termios *tos)
+{
+#if defined USE_GRAB
+    char backup_data[4096];
+    struct user_regs_struct regs;
+    size_t size = sizeof(struct termios);
+    int ret, err;
+
+    if (ptrace(PTRACE_GETREGS, t->pid, NULL, &regs) < 0)
+    {
+        perror("PTRACE_GETREGS (tcsets)\n");
+        return -1;
+    }
+
+    /* Backup the data that we will use */
+    if (memcpy_from_target(t, backup_data, regs.RSP, size) < 0)
+        return -1;
+
+    memcpy_into_target(t, regs.RSP, (char *)tos, size);
+
+    ret = remote_syscall(t, MYCALL_IOCTL, fd, TCSETS, regs.RSP);
+    err = errno;
+
+    /* Restore the data */
+    memcpy_into_target(t, regs.RSP, backup_data, size);
+
+    errno = err;
+    return ret;
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
+
+int mytrace_sctty(struct mytrace *t, int fd)
+{
+#if defined USE_GRAB
+    ptrace(PTRACE_SETOPTIONS, t->pid, NULL, PTRACE_O_TRACEEXIT);
+    return remote_syscall(t, MYCALL_IOCTL, fd, TIOCSCTTY, 0);
+#else
+    errno = ENOSYS;
+    return -1;
+#endif
+}
+
+/*
+ * XXX: the following functions are local
+ */
+
+#if defined USE_GRAB
+static int memcpy_from_target(struct mytrace *t,
+                              char *dest, long src, size_t n)
+{
+    static int const align = sizeof(long) - 1;
+
+    while (n)
+    {
+        long data;
+        size_t todo = sizeof(long) - (src & align);
+
+        if (n < todo)
+            todo = n;
+
+        data = ptrace(PTRACE_PEEKTEXT, t->pid, src - (src & align), 0);
+        if (errno)
+        {
+            perror("ptrace_peektext (memcpy_from_target)");
+            return -1;
+        }
+        memcpy(dest, (char *)&data + (src & align), todo);
+
+        dest += todo;
+        src += todo;
+        n -= todo;
+    }
+
+    return 0;
+}
+
+static int memcpy_into_target(struct mytrace *t,
+                              long dest, char const *src, size_t n)
+{
+    static int const align = sizeof(long) - 1;
+
+    while (n)
+    {
+        long data;
+        size_t todo = sizeof(long) - (dest & align);
+
+        if (n < todo)
+            todo = n;
+        if (todo != sizeof(long))
+        {
+            data = ptrace(PTRACE_PEEKTEXT, t->pid, dest - (dest & align), 0);
+            if (errno)
+            {
+                perror("ptrace_peektext (memcpy_into_target)");
+                return -1;
+            }
+        }
+
+        memcpy((char *)&data + (dest & align), src, todo);
+        if (ptrace(PTRACE_POKETEXT, t->pid, dest - (dest & align), data) < 0)
+        {
+            perror("ptrace_poketext (memcpy_into_target)");
+            return -1;
+        }
+
+        src += todo;
+        dest += todo;
+        n -= todo;
+    }
+
+    return 0;
+}
+
+static long remote_syscall(struct mytrace *t, long call,
+                           long arg1, long arg2, long arg3)
+{
+    /* Method for remote syscall: - wait until the traced application exits
+       from a syscall - save registers - rewind eip/rip to point on the
+       syscall instruction - single step: execute syscall instruction -
+       retrieve resulting registers - restore registers */
+    struct user_regs_struct regs, oldregs;
+    long oinst;
+    int bits;
+    int offset = 2;
+
+    if (call < 0
+        || call >= (long)(sizeof(syscallnames) / sizeof(*syscallnames)))
+    {
+        fprintf(stderr, "unknown remote syscall %li\n", call);
+        return -1;
+    }
+
+    debug("remote syscall %s(0x%lx, 0x%lx, 0x%lx)",
+          syscallnames[call], arg1, arg2, arg3);
+
+#if defined __x86_64__
+    bits = 64;
+#else
+    bits = 32;
+#endif
+
+    for (;;)
+    {
+        if (ptrace(PTRACE_GETREGS, t->pid, NULL, &oldregs) < 0)
+        {
+            perror("PTRACE_GETREGS (syscall 1)\n");
+            return -1;
+        }
+
+        oinst = ptrace(PTRACE_PEEKTEXT, t->pid, oldregs.RIP - 2, 0) & 0xffff;
+
+#if defined __x86_64__
+        if (oinst == SYSCALL_AMD64)
+            break;
+#endif
+        if (oinst == SYSCALL_X86 || oinst == SYSCALL_X86_NEW)
+        {
+            bits = 32;
+            break;
+        }
+
+        if (ptrace(PTRACE_SYSCALL, t->pid, NULL, 0) < 0)
+        {
+            perror("ptrace_syscall (1)");
+            return -1;
+        }
+        waitpid(t->pid, NULL, 0);
+        if (ptrace(PTRACE_SYSCALL, t->pid, NULL, 0) < 0)
+        {
+            perror("ptrace_syscall (2)");
+            return -1;
+        }
+        waitpid(t->pid, NULL, 0);
+    }
+
+    print_registers(t->pid);
+
+    if (oinst == SYSCALL_X86_NEW)
+    {
+        /* Get back to sysenter */
+        while ((ptrace(PTRACE_PEEKTEXT, t->pid, oldregs.RIP - offset, 0) &
+                0xffff) != 0x340f)
+            offset++;
+        oldregs.RBP = oldregs.RSP;
+    }
+
+    regs = oldregs;
+    regs.RIP = regs.RIP - offset;
+#if defined __x86_64__
+    if (bits == 64)
+    {
+        regs.RAX = syscalls64[call];
+        regs.RDI = arg1;
+        regs.RSI = arg2;
+        regs.RDX = arg3;
+    }
+    else
+#endif
+    {
+        regs.RAX = syscalls32[call];
+        regs.RBX = arg1;
+        regs.RCX = arg2;
+        regs.RDX = arg3;
+    }
+
+    if (ptrace(PTRACE_SETREGS, t->pid, NULL, &regs) < 0)
+    {
+        perror("PTRACE_SETREGS (syscall 1)\n");
+        return -1;
+    }
+
+    for (;;)
+    {
+        int status;
+
+        print_registers(t->pid);
+
+        if (ptrace(PTRACE_SINGLESTEP, t->pid, NULL, NULL) < 0)
+        {
+            perror("PTRACE_SINGLESTEP (syscall)\n");
+            return -1;
+        }
+        waitpid(t->pid, &status, 0);
+
+        if (WIFEXITED(status))
+            return 0;
+
+        if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP)
+            continue;
+
+        /* Fuck Linux: there is no macro for this */
+        switch ((status >> 16) & 0xffff)
+        {
+        case PTRACE_EVENT_FORK:
+            if (ptrace(PTRACE_GETEVENTMSG, t->pid, 0, &t->child) < 0)
+            {
+                perror("PTRACE_GETEVENTMSG (syscall)\n");
+                return -1;
+            }
+            debug("PTRACE_GETEVENTMSG %d", t->child);
+            continue;
+        case PTRACE_EVENT_EXIT:
+            debug("PTRACE_EVENT_EXIT");
+            /* The process is about to exit, don't do anything else */
+            return 0;
+        case PTRACE_EVENT_EXEC:
+            debug("PTRACE_EVENT_EXEC");
+            return 0;
+        }
+
+        break;
+    }
+
+    print_registers(t->pid);
+
+    if (ptrace(PTRACE_GETREGS, t->pid, NULL, &regs) < 0)
+    {
+        perror("PTRACE_GETREGS (syscall 2)\n");
+        return -1;
+    }
+
+    if (ptrace(PTRACE_SETREGS, t->pid, NULL, &oldregs) < 0)
+    {
+        perror("PTRACE_SETREGS (syscall 2)\n");
+        return -1;
+    }
+    print_registers(t->pid);
+
+    debug("syscall %s returned %ld", syscallnames[call], regs.RAX);
+
+    if ((long)regs.RAX < 0)
+    {
+        errno = -(long)regs.RAX;
+        perror("syscall");
+        return -1;
+    }
+
+    return regs.RAX;
+}
+
+/* For debugging purposes only. Prints register and stack information. */
+#if defined DEBUG
+static void print_registers(pid_t pid)
+{
+    union
+    {
+        long int l;
+        unsigned char data[sizeof(long int)];
+    } inst;
+    struct user_regs_struct regs;
+    int i;
+
+    if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
+    {
+        perror("PTRACE_GETREGS (syscall 2)");
+        exit(errno);
+    }
+
+    fprintf(stderr, "  / %s: " FMT "   ", STRINGIFY(RAX), regs.RAX);
+    fprintf(stderr, "%s: " FMT "\n", STRINGIFY(RBX), regs.RBX);
+    fprintf(stderr, "  | %s: " FMT "   ", STRINGIFY(RCX), regs.RCX);
+    fprintf(stderr, "%s: " FMT "\n", STRINGIFY(RDX), regs.RDX);
+    fprintf(stderr, "  | %s: " FMT "   ", STRINGIFY(RDI), regs.RDI);
+    fprintf(stderr, "%s: " FMT "\n", STRINGIFY(RSI), regs.RSI);
+    fprintf(stderr, "  | %s: " FMT "   ", STRINGIFY(RSP), regs.RSP);
+    fprintf(stderr, "%s: " FMT "\n", STRINGIFY(RIP), regs.RIP);
+
+    inst.l = ptrace(PTRACE_PEEKTEXT, pid, regs.RIP - 4, 0);
+    fprintf(stderr, "  | code: ... %02x %02x %02x %02x <---> ",
+            inst.data[0], inst.data[1], inst.data[2], inst.data[3]);
+    inst.l = ptrace(PTRACE_PEEKTEXT, pid, regs.RIP, 0);
+    fprintf(stderr, "%02x %02x %02x %02x ...\n",
+            inst.data[0], inst.data[1], inst.data[2], inst.data[3]);
+
+    fprintf(stderr, "  \\ stack: ... ");
+    for (i = -16; i < 24; i += sizeof(long))
+    {
+        inst.l = ptrace(PTRACE_PEEKDATA, pid, regs.RSP + i, 0);
+#if defined __x86_64__
+        fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x %02x ",
+                inst.data[0], inst.data[1], inst.data[2], inst.data[3],
+                inst.data[4], inst.data[5], inst.data[6], inst.data[7]);
+#else
+        fprintf(stderr, "%02x %02x %02x %02x ",
+                inst.data[0], inst.data[1], inst.data[2], inst.data[3]);
+#endif
+        if (i == 0)
+            fprintf(stderr, "[%s] ", STRINGIFY(RSP));
+    }
+    fprintf(stderr, "...\n");
+}
+#endif /* DEBUG */
+
+#endif /* USE_GRAB */
diff --git a/neercs/old/mytrace.h b/neercs/old/mytrace.h
new file mode 100644
index 0000000..d0f9d61
--- /dev/null
+++ b/neercs/old/mytrace.h
@@ -0,0 +1,33 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2008-2010 Sam Hocevar <sam@hocevar.net>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include <termios.h>
+
+struct mytrace;
+
+struct mytrace* mytrace_attach(long int pid);
+struct mytrace* mytrace_fork(struct mytrace *t);
+int mytrace_detach(struct mytrace *t);
+long mytrace_getpid(struct mytrace *t);
+
+int mytrace_open(struct mytrace *t, char const *path, int mode);
+int mytrace_write(struct mytrace *t, int fd, char const *data, size_t len);
+int mytrace_close(struct mytrace *t, int fd);
+int mytrace_dup2(struct mytrace *t, int oldfd, int newfd);
+int mytrace_setpgid(struct mytrace *t, long pid, long pgid);
+int mytrace_setsid(struct mytrace *t);
+int mytrace_kill(struct mytrace *t, long pid, int sig);
+int mytrace_exit(struct mytrace *t, int status);
+int mytrace_exec(struct mytrace *t, char const *command);
+int mytrace_tcgets(struct mytrace *t, int fd, struct termios *tos);
+int mytrace_tcsets(struct mytrace *t, int fd, struct termios *tos);
+int mytrace_sctty(struct mytrace *t, int fd);
diff --git a/neercs/old/neercs.h b/neercs/old/neercs.h
new file mode 100644
index 0000000..9536547
--- /dev/null
+++ b/neercs/old/neercs.h
@@ -0,0 +1,430 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#ifndef _NEERCS_H_
+#define _NEERCS_H_
+
+#include <stdint.h>
+#include <caca.h>
+
+#include "widgets.h"
+
+enum wm_types
+{
+    WM_FULL,
+    WM_CARD,
+    WM_HSPLIT,
+    WM_VSPLIT,
+
+    WM_MAX,
+};
+
+enum mouse_report
+{
+    MOUSE_NONE,
+    MOUSE_X10,
+    MOUSE_VT200,
+    MOUSE_VT200_HIGHLIGHT,
+    MOUSE_BTN_EVENT,
+    MOUSE_ANY_EVENT,
+};
+
+
+/* ISO-2022 Conversion State */
+struct iso2022_conv_state
+{
+    /* cs = coding system/coding method: */
+    /* (with standard return) */
+    /* '@' = ISO-2022, */
+    /* 'G' = UTF-8 without implementation level, */
+    /* '8' = UTF-8 (Linux console and imitators), */
+    /* and many others that are rarely used; */
+    /* (without standard return) */
+    /* '/G' = UTF-8 Level 1, */
+    /* '/H' = UTF-8 Level 2, */
+    /* '/I' = UTF-8 Level 3, */
+    /* and many others that are rarely used */
+    uint32_t cs;
+    /* ctrl8bit = allow 8-bit controls */
+    uint8_t ctrl8bit;
+    /* cn[0] = C0 control charset (0x00 ... 0x1f):
+     * '@' = ISO 646,
+     * '~' = empty,
+     * and many others that are rarely used */
+    /* cn[1] = C1 control charset (0x80 ... 0x9f):
+     * 'C' = ISO 6429-1983,
+     * '~' = empty,
+     * and many others that are rarely used */
+    uint32_t cn[2];
+    /* glr[0] = GL graphic charset (94-char. 0x21 ... 0x7e,
+     *                              94x94-char. 0x21/0x21 ... 0x7e/0x7e),
+     * and
+     * glr[1] = GR graphic charset (94-char. 0xa1 ... 0xfe,
+     *                              96-char. 0xa0 ... 0xff,
+     *                              94x94-char. 0xa1/0xa1 ... 0xfe/0xfe,
+     *                              96x96-char. 0xa0/0xa0 ... 0xff/0xff):
+     * 0 = G0, 1 = G1, 2 = G2, 3 = G3 */
+    uint8_t glr[2];
+    /* gn[i] = G0/G1/G2/G3 graphic charset state:
+     * (94-char. sets)
+     * '0' = DEC ACS (VT100 and imitators),
+     * 'B' = US-ASCII,
+     * and many others that are rarely used for e.g. various national ASCII variations;
+     * (96-char. sets)
+     * '.A' = ISO 8859-1 "Latin 1" GR,
+     * '.~' = empty 96-char. set,
+     * and many others that are rarely used for e.g. ISO 8859-n GR;
+     * (double-byte 94x94-charsets)
+     * '$@' = Japanese Character Set ("old JIS") (JIS C 6226:1978),
+     * '$A' = Chinese Character Set (GB 2312),
+     * '$B' = Japanese Character Set (JIS X0208/JIS C 6226:1983),
+     * '$C' = Korean Graphic Character Set (KSC 5601:1987),
+     * '$D' = Supplementary Japanese Graphic Character Set (JIS X0212),
+     * '$E' = CCITT Chinese Set (GB 2312 + GB 8565),
+     * '$G' = CNS 11643 plane 1,
+     * '$H' = CNS 11643 plane 2,
+     * '$I' = CNS 11643 plane 3,
+     * '$J' = CNS 11643 plane 4,
+     * '$K' = CNS 11643 plane 5,
+     * '$L' = CNS 11643 plane 6,
+     * '$M' = CNS 11643 plane 7,
+     * '$O' = JIS X 0213 plane 1,
+     * '$P' = JIS X 0213 plane 2,
+     * '$Q' = JIS X 0213-2004 Plane 1,
+     * and many others that are rarely used for e.g. traditional
+     * ideographic Vietnamese and BlissSymbolics;
+     * (double-byte 96x96-charsets)
+     * none standardized or in use on terminals AFAIK (Mule does use
+     * some internally)
+     */
+    uint32_t gn[4];
+    /* ss = single-shift state: 0 = GL, 2 = G2, 3 = G3 */
+    uint8_t ss;
+};
+
+struct screen
+{
+    /* Graphics stuff */
+    int init;
+    caca_canvas_t *cv;
+    uint32_t clearattr;
+    uint8_t fg, bg;   /* ANSI-context fg/bg */
+    uint8_t dfg, dbg; /* Default fg/bg */
+    uint8_t bold, blink, italics, negative, concealed, underline;
+    uint8_t faint, strike, proportional; /* unsupported */
+    struct iso2022_conv_state conv_state; /* charset mess */
+
+    /* Other stuff */
+    int visible;                 /* Draw canvas and border flag */
+    int fd;                      /* pty fd */
+    unsigned char *buf;          /* text buffer */
+    long int total;              /* buffer length */
+    char *title;                 /* tty title */
+    int bell;                    /* bell occuring */
+    unsigned int scroll, s1, s2; /* FIXME, ANSI scroll properties */
+    int pid;                     /* running program pid */
+    int changed;                 /* content was updated */
+
+    int x, y;                    /* Canvas position */
+    int w, h;                    /* Canvas size */
+
+    int orig_x, orig_y;          /* Used by recurrents */
+    int orig_w, orig_h;          /* Used by recurrents */
+
+    int report_mouse;            /* ANSI */
+};
+
+enum socket_type
+{
+    SOCK_SERVER=0,
+    SOCK_CLIENT=1
+};
+
+struct cube_props
+{
+    int in_switch;
+    int side;
+    long long unsigned int duration;
+};
+
+struct interpreter_props
+{
+    /* Input box */
+    struct input_box *box;
+};
+
+struct screensaver
+{
+    /* ScreenSaver stuff */
+    long long unsigned int timeout;     /* Screensaver timeout in us */
+    int in_screensaver;
+    void *data;
+};
+
+struct comm
+{
+    /* Detaching */
+    int attached;                /* Are we attached to a terminal or a server */
+    int socket[2];               /* Sockets to write to the server / to the client */
+    char *socket_path[2];        /* Sockets to write to the server / to the client */
+    char *socket_dir;            /* Where to create the socket */
+    char *session_name;          /* Name of the session */
+};
+
+struct lock
+{
+    int locked;
+    int lock_offset;
+    int lock_on_detach;
+    long long unsigned int  autolock_timeout;
+    char lockpass[1024];
+    char lockmsg[1024];
+};
+
+struct modals
+{
+    /* Add-ons*/
+    int mini;                    /* Thumbnails */
+    int status;                  /* Status bar */
+    int help;                    /* Help */
+    int python_command;          /* Python command */
+    int window_list;             /* Window list */
+    int cur_in_list;             /* Window list */
+};
+
+struct sys
+{
+    char *default_shell;
+    char *user_path;
+    int  *to_grab;
+    char **to_start;
+    int  nb_to_grab;
+    int  attach, forceattach;
+};
+
+struct screen_list
+{
+    int outfd;                   /* Debug */
+    int in_bell;                 /* Bell occuring in a window  */
+    int was_in_bell;
+    int dont_update_coords;      /* Used by recurrents */
+    int changed;                 /* Global redraw (e.g. adding a screen) */
+    int delay;                   /* Minimal time between two refresh (ms) */
+    int requested_delay;
+    int force_refresh;
+    int need_refresh;            /* If we skipped a refresh, do it next time */
+    int command;
+    int eyecandy;                /* Eye Candy */
+
+    long long unsigned int last_key_time;
+    long long unsigned int last_refresh_time;
+
+    struct comm comm;            /* Client/Server communications */
+    struct lock lock;            /* Lock */
+    struct modals modals;        /* Modal windows */
+    struct interpreter_props interpreter_props; /* Python interpreter */
+    struct screensaver screensaver;/* Screensaver stuff */
+
+    int pty, prevpty;            /* Current and previous window */
+    int count;                   /* Window count */
+    int wm_type;                 /* Window manager type */
+    int border_size;             /* Borders */
+    struct cube_props cube;      /* Cube */
+    long long unsigned int last_switch; /* Cube */
+
+    struct screen **screen;      /* Windows */
+    struct option *config;       /* Option parsing and configuration */
+    struct sys sys;              /* System stuff */
+
+    struct recurrent_list *recurrent_list;  /* Recurrents functions */
+
+    char *title;                 /* Window title */
+    int width, height;           /* caca window size */
+    int old_x, old_y;            /* Mouse */
+    int mouse_button;
+    caca_canvas_t *cv;
+    caca_display_t *dp;
+};
+
+/* Configuration */
+struct option
+{
+    char *key;
+    char *value;
+
+    struct option *next;
+};
+struct config_line
+{
+    const char name[32];
+    int  (*set) (const char *argv, struct screen_list * screen_list);
+    char* (*get) (struct screen_list * screen_list);
+};
+
+/* Recurrents */
+struct recurrent
+{
+    int (*function)(struct screen_list*, struct recurrent* rec, void *user, long long unsigned int t);
+    void *user;
+    long long unsigned int  start_time;
+    int kill_me;
+};
+
+struct recurrent_list
+{
+    int count;
+    struct recurrent **recurrent;
+};
+
+
+
+void version(void);
+void usage(int argc, char **argv);
+struct screen_list *init_neercs(int argc, char **argv);
+
+int handle_command_line(int argc, char *argv[], struct screen_list *screen_list);
+
+struct screen_list *create_screen_list(void);
+void free_screen_list(struct screen_list *screen_list);
+
+int start_client(struct screen_list * screen_list);
+/** \defgroup client neercs client
+ * @{ */
+void mainloop(struct screen_list *screen_list);
+int mainloop_tick(char **pbuf, struct screen_list *screen_list);
+/** }@ */
+
+
+int create_pty(char *cmd, unsigned int w, unsigned int h, int *cpid);
+int create_pty_grab(long pid, unsigned int w, unsigned int h, int *cpid);
+int grab_process(long pid, char *ptyname, int ptyfd, int *newpid);
+long select_process(struct screen_list* screen_list);
+
+long int import_term(struct screen_list *screen_list, struct screen *sc, void const *data, unsigned int size);
+int set_tty_size(int fd, unsigned int w, unsigned int h);
+int update_terms(struct screen_list* screen_list);
+void refresh_screens(struct screen_list *screen_list);
+int update_screens_contents(struct screen_list* screen_list);
+int install_fds(struct screen_list *screen_list);
+long long get_us(void);
+
+void attach(struct screen_list* screen_list);
+int detach(struct screen_list* screen_list);
+int request_attach(struct screen_list* screen_list);
+char * build_socket_path(char *socket_dir, char *session_name, enum socket_type socktype);
+int create_socket(struct screen_list* screen_list, enum socket_type socktype);
+char * connect_socket(struct screen_list* screen_list, enum socket_type socktype);
+char ** list_sockets(char *socket_dir, char *session_name);
+int start_server(struct screen_list *screen_list);
+int send_event(caca_event_t ev, struct screen_list* screen_list);
+int send_delay(struct screen_list* screen_list);
+int send_ansi_sequence(struct screen_list *screen_list, char *str);
+
+/* Screens management */
+struct screen* create_screen(int w, int h, char *command);
+struct screen* create_screen_grab(int w, int h, int pid);
+int destroy_screen(struct screen *s);
+int add_screen(struct screen_list *list, struct screen *s);
+int remove_screen(struct screen_list *list, int n, int please_kill);
+void resize_screen(struct screen *s, int z, int h);
+
+/* Window managers */
+void update_windows_props(struct screen_list *screen_list);
+void update_windows_props_cards(struct screen_list *screen_list);
+void update_windows_props_hsplit(struct screen_list *screen_list);
+void update_windows_props_full(struct screen_list *screen_list);
+void update_windows_props_vsplit(struct screen_list *screen_list);
+void update_windows_props_cube(struct screen_list *screen_list);
+
+void wm_refresh(struct screen_list *screen_list);
+void wm_refresh_card(struct screen_list *screen_list);
+void wm_refresh_cube(struct screen_list *screen_list);
+void wm_refresh_full(struct screen_list *screen_list);
+void wm_refresh_hsplit(struct screen_list *screen_list);
+void wm_refresh_vsplit(struct screen_list *screen_list);
+int switch_screen_recurrent(struct screen_list* screen_list, struct recurrent* rec, void *user, long long unsigned int t);
+
+
+/* Effects and addons */
+void draw_thumbnails(struct screen_list *screen_list);
+void draw_status(struct screen_list *screen_list);
+void draw_help(struct screen_list *screen_list);
+int help_handle_key(struct screen_list *screen_list, unsigned int c);
+int update_window_list(int c, struct screen_list *screen_list);
+void draw_list(struct screen_list *screen_list);
+void draw_lock(struct screen_list *screen_list);
+int update_lock(int c, struct screen_list *screen_list);
+int validate_lock(struct screen_list *screen_list, char *user, char *pass);
+
+int close_screen_recurrent(struct screen_list*, struct recurrent* rec, void *user, long long unsigned int t);
+
+/* Input to ANSI */
+void *convert_input_ansi(unsigned int *c, int *size);
+int  handle_command_input(struct screen_list*screen_list, unsigned int c);
+
+
+/* Screensavers */
+void screensaver_init(struct screen_list *screen_list);
+void screensaver_kill(struct screen_list *screen_list);
+
+void draw_screensaver(struct screen_list *screen_list);
+void screensaver_flying_toasters(struct screen_list *screen_list);
+
+void screensaver_flying_toasters_init(struct screen_list *screen_list);
+
+void screensaver_flying_toasters_kill(struct screen_list *screen_list);
+
+/* Actions */
+void dump_to_file(struct screen_list *screen_list);
+
+/* Recurrents */
+int handle_recurrents(struct screen_list* screen_list);
+int add_recurrent(struct recurrent_list *list,
+                  int (*function)(struct screen_list*, struct recurrent* rec, void *user, long long unsigned int t),
+                  void *user);
+int remove_recurrent(struct recurrent_list *list, int n);
+
+
+
+/* Configuration file */
+int read_configuration_file(char *filename, struct screen_list *screen_list);
+int parse_conf_line(char *buf, int size, struct screen_list *screen_list);
+int get_key_value(char *line, struct option *option);
+int fill_config(struct screen_list *screen_list);
+struct config_line *get_config(const char *name);
+struct config_line *get_config_option(void);
+
+/* Python interpreter */
+#ifdef USE_PYTHON
+int python_init(struct screen_list *sl);
+int python_close(struct screen_list *sl);
+int  python_command_handle_key(struct screen_list *screen_list, unsigned int c);
+void draw_python_command(struct screen_list *screen_list);
+#endif
+
+#if defined DEBUG
+#   include <stdio.h>
+#   include <stdarg.h>
+static inline void debug(const char *format, ...)
+{
+    va_list args;
+    va_start(args, format);
+    fprintf(stderr, "** neercs debug ** ");
+    vfprintf(stderr, format, args);
+    fprintf(stderr, "\n");
+    va_end(args);
+}
+#else
+#   define debug(format, ...) do {} while(0)
+#endif
+#endif /* _NEERCS_H_ */
diff --git a/neercs/old/python/interpreter.c b/neercs/old/python/interpreter.c
new file mode 100644
index 0000000..267d860
--- /dev/null
+++ b/neercs/old/python/interpreter.c
@@ -0,0 +1,197 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2009-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include "config.h"
+
+#ifdef USE_PYTHON
+
+#include <Python.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+
+#include <caca.h>
+
+#include "neercs.h"
+#include "py_module.h"
+
+static int python_execute(struct screen_list *sl);
+char *getStringFromPyObject(PyObject * p);
+static char *getPythonError(void);
+
+#if ! defined HAVE_PYTHON26
+static PyObject *PyUnicode_FromString(char const *str)
+{
+    PyObject *tmp, *ret;
+    tmp = PyString_FromString(str);
+    if (!tmp)
+        return NULL;
+    ret = PyString_AsDecodedObject(tmp, "utf-8", "replace");
+    Py_DECREF(tmp);
+    return ret;
+}
+#endif
+
+int python_command_handle_key(struct screen_list *screen_list, unsigned int c)
+{
+    int ret = widget_ibox_handle_key(screen_list->interpreter_props.box, c);
+
+    if (ret == INPUT_BOX_ESC)
+    {
+        widget_ibox_destroy(screen_list->interpreter_props.box);
+        screen_list->interpreter_props.box = NULL;
+        screen_list->modals.python_command = 0;
+    }
+    else if (ret == INPUT_BOX_RET)
+    {
+        python_execute(screen_list);
+    }
+    screen_list->changed = 1;
+
+    return 1;
+}
+
+void draw_python_command(struct screen_list *screen_list)
+{
+    if (!screen_list->interpreter_props.box)
+    {
+        screen_list->interpreter_props.box =
+            widget_ibox_init(screen_list->cv, 65, 6);
+        debug("py Init %p\n", screen_list->interpreter_props.box);
+    }
+    widget_ibox_draw(screen_list->interpreter_props.box);
+}
+
+/* Actual Python interpreter stuff */
+int python_init(struct screen_list *sl)
+{
+    initNeercsModule(sl);
+
+    return 0;
+}
+
+int python_close(struct screen_list *sl)
+{
+    widget_ibox_destroy(sl->interpreter_props.box);
+    sl->interpreter_props.box = NULL;
+
+    Py_Finalize();
+    return 0;
+}
+
+
+static int python_execute(struct screen_list *sl)
+{
+    char *command = widget_ibox_get_text(sl->interpreter_props.box);
+    if (!command || strlen(command) < 1)
+        return -1;
+    int err = 0;
+
+    debug("py Executing '%s'\n", command);
+
+
+    PyObject *pModule, *pName;
+
+    /* Module from which to call the function */
+    pName = PyUnicode_FromString("neercs");
+    if (!pName)
+    {
+        widget_ibox_set_error(sl->interpreter_props.box, getPythonError());
+        err = 1;
+        debug("py Error 1\n");
+        goto end;
+    }
+
+    pModule = PyImport_Import(pName);
+    Py_DECREF(pName);
+
+    if (pModule != NULL)
+    {
+        PyObject *dictionary = PyModule_GetDict(pModule);
+
+        getExportedValues(dictionary);
+
+        PyObject *o =
+            PyRun_String(command, Py_single_input,
+                         dictionary, NULL);
+        if (!o)
+        {
+            widget_ibox_set_error(sl->interpreter_props.box, getPythonError());
+            err = 1;
+        }
+        else
+        {
+            setExportedValues(dictionary);
+
+            widget_ibox_set_msg(sl->interpreter_props.box, getStringFromPyObject(o));
+            err = 1;
+        }
+
+        Py_DECREF(pModule);
+    }
+    else
+    {
+        widget_ibox_set_error(sl->interpreter_props.box, getPythonError());
+        err = 1;
+    }
+
+  end:
+
+    if (!err)
+    {
+        widget_ibox_destroy(sl->interpreter_props.box);
+        sl->interpreter_props.box = NULL;
+        sl->modals.python_command = 0;
+    }
+    sl->changed = 1;
+
+    return 0;
+}
+
+static char *getPythonError(void)
+{
+    char *err;
+    PyObject *type, *value, *traceback;
+    PyErr_Fetch(&type, &value, &traceback);
+
+    char *evalue = getStringFromPyObject(value);
+
+    int r = asprintf(&err, "%s", evalue);
+    (void)r;
+    return err;
+}
+
+char *getStringFromPyObject(PyObject * p)
+{
+    PyObject *str = PyObject_Repr(p);
+    char *tmp;
+#if defined HAVE_PYTHON26
+    tmp = PyBytes_AS_STRING(PyUnicode_AsEncodedString(str, "utf-8", "Error ~"));
+#else
+    tmp = PyString_AsString(str);
+#endif
+    return strdup(tmp);
+}
+
+
+#endif
diff --git a/neercs/old/python/py_module.c b/neercs/old/python/py_module.c
new file mode 100644
index 0000000..17ce2b6
--- /dev/null
+++ b/neercs/old/python/py_module.c
@@ -0,0 +1,193 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2009-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include "config.h"
+
+#ifdef USE_PYTHON
+
+#include <Python.h>
+#include "py_module.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <caca.h>
+
+#include "neercs.h"
+
+/* FIXME : Find a way to pass a user pointer to PyModuleDef or something */
+static struct screen_list *screen_list;
+
+#if defined HAVE_PYTHON3
+static PyObject *PyInit_neercs(void);
+#else
+static void PyInit_neercs(void);
+#endif
+static void removeTrailingStuff(char *b);
+
+
+static void addVariableFromConfig(PyObject * dictionary,
+                                  const char *varname, const char *configname)
+{
+    char *v = get_config(configname)->get(screen_list);
+    if (v != NULL)
+    {
+        PyObject *value = Py_BuildValue("s", v);
+        PyDict_SetItemString(dictionary, varname, value);
+    }
+
+    debug("py get '%s' to '%s'\n", varname,
+          get_config(configname)->get(screen_list));
+}
+
+static void removeTrailingStuff(char *b)
+{
+    if(!b)
+        return;
+    if(b[0]=='\'')
+    {
+        memmove(b, &b[1], strlen(b)-1);
+        b[strlen(b)-2] = 0;
+    }
+}
+
+void setExportedValues(PyObject * dictionary)
+{
+    struct config_line *config_option = get_config_option();
+    int i = 0;
+
+    while (strncmp(config_option[i].name, "last", strlen("last")))
+    {
+        /* Get variable */
+        PyObject *res =
+            PyDict_GetItemString(dictionary, config_option[i].name);
+
+        /* Got it */
+        if (res)
+        {
+            /* Get object representation
+             * FIXME : find a way to check object's type */
+            PyObject *str = PyObject_Repr(res);
+
+            /* Make sure it's a string */
+            char *err =
+#if defined HAVE_PYTHON3
+                PyBytes_AS_STRING(PyUnicode_AsEncodedString
+                                  (str, "utf-8", "Error ~"));
+#elif defined HAVE_PYTHON2
+                PyString_AsString(str);
+#endif
+            /* FIXME leak leak leak */
+            char *s = strdup(err);
+
+            if (s != NULL)
+            {
+                /* Representation can include '' around strings */
+                removeTrailingStuff(s);
+                get_config(config_option[i].name)->set(s, screen_list);
+            }
+        }
+        i++;
+    }
+}
+
+void getExportedValues(PyObject * dictionary)
+{
+    struct config_line *config_option = get_config_option();
+    int i = 0;
+    while (strncmp(config_option[i].name, "last", strlen("last")))
+    {
+        addVariableFromConfig(dictionary, config_option[i].name,
+                              config_option[i].name);
+        i++;
+    }
+}
+
+static PyObject *neercs_get(PyObject * self, PyObject * args)
+{
+    char *s = NULL;
+
+    debug("Get using list at %p", screen_list);
+
+    if (!PyArg_ParseTuple(args, "s", &s))
+    {
+        PyErr_SetString(PyExc_ValueError, "Can't parse argument");
+        debug("py Can't parse");
+        return NULL;
+    }
+    debug("py Argument : '%s'", s);
+    struct config_line *c = get_config(s);
+
+    if (c)
+        return Py_BuildValue("s", c->get(screen_list));
+
+
+    PyErr_SetString(PyExc_ValueError,
+                    "Can't get value for specified variable");
+    return NULL;
+}
+
+static PyObject *neercs_version(PyObject * self, PyObject * args)
+{
+    return Py_BuildValue("s", PACKAGE_VERSION);
+}
+
+static PyMethodDef NeercsMethods[] =
+{
+    { "version", neercs_version, METH_NOARGS, "Return the neercs version." },
+    { "get", neercs_get, METH_VARARGS,
+      "Return the specified variable's value." },
+    { NULL, NULL, 0, NULL }
+};
+
+#if defined HAVE_PYTHON3
+static PyObject *PyInit_neercs(void)
+{
+    static PyModuleDef NeercsModule =
+    {
+        PyModuleDef_HEAD_INIT, "neercs", NULL, -1, NeercsMethods,
+        NULL, NULL, NULL, NULL
+    };
+
+    return PyModule_Create(&NeercsModule);
+}
+
+#elif defined HAVE_PYTHON2
+static void PyInit_neercs(void)
+{
+    PyMethodDef *m = NeercsMethods;
+    PyObject *mod = PyModule_New("neercs");
+    PyModule_AddStringConstant(mod, "__file__", "<synthetic>");
+
+    for (m = NeercsMethods; m->ml_name; m++)
+        PyModule_AddObject(mod, m->ml_name, PyCFunction_New(m, NULL));
+}
+#endif
+
+void initNeercsModule(struct screen_list *sl)
+{
+    screen_list = sl;
+    PyImport_AppendInittab("neercs", &PyInit_neercs);
+    Py_Initialize();
+}
+
+#endif
diff --git a/neercs/old/python/py_module.h b/neercs/old/python/py_module.h
new file mode 100644
index 0000000..bae9e32
--- /dev/null
+++ b/neercs/old/python/py_module.h
@@ -0,0 +1,25 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2009-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include "config.h"
+
+#ifdef USE_PYTHON
+
+#include <Python.h>
+#include "neercs.h"
+
+void initNeercsModule(struct screen_list *sl);
+void getExportedValues(PyObject * dictionary);
+void setExportedValues(PyObject * dictionary);
+
+
+#endif
diff --git a/neercs/old/recurrent.c b/neercs/old/recurrent.c
new file mode 100644
index 0000000..7c8de1b
--- /dev/null
+++ b/neercs/old/recurrent.c
@@ -0,0 +1,112 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "neercs.h"
+
+
+int handle_recurrents(struct screen_list *screen_list)
+{
+    int refresh = 0, i;
+    /* Recurrent functions */
+    for (i = 0; i < screen_list->recurrent_list->count; i++)
+    {
+        if (screen_list->recurrent_list->recurrent[i]->function)
+        {
+            refresh |=
+                screen_list->recurrent_list->recurrent[i]->
+                function(screen_list,
+                         screen_list->recurrent_list->recurrent[i],
+                         screen_list->recurrent_list->recurrent[i]->user,
+                         get_us());
+        }
+    }
+    /* Delete recurrent functions */
+    for (i = 0; i < screen_list->recurrent_list->count; i++)
+    {
+        if (screen_list->recurrent_list->recurrent[i]->kill_me)
+        {
+            remove_recurrent(screen_list->recurrent_list, i);
+            refresh = 1;
+            i = 0;
+        }
+    }
+    return refresh;
+}
+
+
+/* Add recurrent function. It will be called at each main loop iteration,
+   unless it is removed */
+int add_recurrent(struct recurrent_list *list,
+                  int (*func) (struct screen_list *, struct recurrent * rec,
+                               void *user, long long unsigned int t),
+                  void *user)
+{
+    if (list == NULL || func == NULL)
+        return -1;
+
+    list->recurrent = (struct recurrent **)realloc(list->recurrent,
+                                                   sizeof(struct recurrent *)
+                                                   * (list->count + 1));
+
+    if (!list->recurrent)
+        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__,
+                __LINE__);
+
+    list->recurrent[list->count] = malloc(sizeof(struct recurrent));
+
+    list->recurrent[list->count]->kill_me = 0;
+    list->recurrent[list->count]->function = func;
+    list->recurrent[list->count]->user = user;
+    list->recurrent[list->count]->start_time = get_us();
+    list->count++;
+
+    return list->count - 1;
+}
+
+
+/* Remove recurrent. Do *NOT* call this from a recurrent function. */
+int remove_recurrent(struct recurrent_list *list, int n)
+{
+
+    if (n >= list->count)
+        return -1;
+
+    memmove(&list->recurrent[n],
+            &list->recurrent[n + 1],
+            sizeof(struct recurrent *) * (list->count - (n + 1)));
+
+    free(list->recurrent[n]);
+    list->recurrent = (struct recurrent **)realloc(list->recurrent,
+                                                   sizeof(sizeof
+                                                          (struct recurrent *))
+                                                   * (list->count));
+    if (!list->recurrent)
+        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__,
+                __LINE__);
+
+
+
+    list->count--;
+    return 0;
+}
diff --git a/neercs/old/screen_list.c b/neercs/old/screen_list.c
new file mode 100644
index 0000000..a9871c1
--- /dev/null
+++ b/neercs/old/screen_list.c
@@ -0,0 +1,216 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pwd.h>
+
+#include <caca.h>
+
+#include "neercs.h"
+
+struct screen_list *create_screen_list(void)
+{
+
+    struct screen_list *screen_list = NULL;
+    struct passwd *user_info;
+    char *user_dir = NULL;
+
+    /* Create screen list */
+    screen_list = (struct screen_list *)malloc(sizeof(struct screen_list));
+    if (!screen_list)
+    {
+        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__,
+                __LINE__);
+        return NULL;
+    }
+    screen_list->screen =
+    (struct screen **)malloc(sizeof(sizeof(struct screen *)));
+    if (!screen_list->screen)
+    {
+        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__,
+                __LINE__);
+        free(screen_list);
+        return NULL;
+    }
+
+    screen_list->count = 0;
+    screen_list->modals.mini = 1;
+    screen_list->modals.help = 0;
+    screen_list->modals.status = 1;
+    screen_list->modals.window_list = 0;
+    screen_list->modals.python_command = 0;
+    screen_list->eyecandy = 1;
+    screen_list->border_size = 1;
+    screen_list->title = NULL;
+    screen_list->wm_type = WM_VSPLIT;
+    screen_list->in_bell = 0;
+    screen_list->changed = 0;
+    screen_list->requested_delay = 0;
+    screen_list->delay = 1000 / 60;     /* Don't refresh more than 60 times
+                                         per second */
+    screen_list->pty = screen_list->prevpty = 0;
+    screen_list->dont_update_coords = 0;
+    screen_list->screensaver.timeout = (60*5) * 1000000;
+    screen_list->screensaver.data = NULL;
+    screen_list->screensaver.in_screensaver = 0;
+    screen_list->lock.autolock_timeout = -1;
+    screen_list->lock.locked = 0;
+    screen_list->lock.lock_offset = 0;
+    screen_list->lock.lock_on_detach = 0;
+    screen_list->comm.attached = 0;
+    screen_list->comm.socket[SOCK_SERVER] = 0;
+    screen_list->comm.socket[SOCK_CLIENT] = 0;
+    screen_list->comm.socket_dir = NULL;
+    screen_list->comm.socket_path[SOCK_SERVER] = NULL;
+    screen_list->comm.socket_path[SOCK_CLIENT] = NULL;
+    screen_list->comm.session_name = NULL;
+    screen_list->sys.default_shell = NULL;
+    screen_list->sys.user_path = NULL;
+    screen_list->sys.to_grab = NULL;
+    screen_list->sys.to_start = NULL;
+    screen_list->sys.nb_to_grab = 0;
+    screen_list->sys.attach = 0;
+    screen_list->sys.forceattach = 0;
+    screen_list->need_refresh = 0;
+
+    screen_list->force_refresh = 0;
+    screen_list->cube.in_switch = 0;
+    screen_list->cube.duration = 1000000;
+
+    screen_list->interpreter_props.box = NULL;
+
+    screen_list->recurrent_list = NULL;
+    screen_list->cv = NULL;
+    screen_list->dp = NULL;
+
+    memset(screen_list->lock.lockmsg, 0, 1024);
+    memset(screen_list->lock.lockpass, 0, 1024);
+
+    /* Build local config file path */
+    user_dir = getenv("HOME");
+    if (!user_dir)
+    {
+        user_info = getpwuid(getuid());
+        if (user_info)
+        {
+            user_dir = user_info->pw_dir;
+        }
+    }
+    if (user_dir)
+    {
+        screen_list->sys.user_path =
+        malloc(strlen(user_dir) + strlen("/.neercsrc") + 1);
+        sprintf(screen_list->sys.user_path, "%s/%s", user_dir, ".neercsrc");
+    }
+
+
+    screen_list->recurrent_list =
+    (struct recurrent_list *)malloc(sizeof(struct recurrent_list));
+    screen_list->recurrent_list->recurrent =
+    (struct recurrent **)malloc(sizeof(struct recurrent *));
+    if (!screen_list->recurrent_list->recurrent)
+    {
+        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__,
+                __LINE__);
+        free(screen_list);
+        free(screen_list->screen);
+        return NULL;
+    }
+    screen_list->recurrent_list->count = 0;
+
+    return screen_list;
+}
+
+void free_screen_list(struct screen_list *screen_list)
+{
+    int i;
+    struct option *option;
+
+    if (screen_list->dp)
+        caca_free_display(screen_list->dp);
+
+    if (screen_list->cv)
+        caca_free_canvas(screen_list->cv);
+
+    for (i = 0; i < screen_list->count; i++)
+    {
+        destroy_screen(screen_list->screen[i]);
+    }
+
+    if (screen_list->comm.socket_path[SOCK_SERVER])
+    {
+        /* FIXME test that we are the server */
+        if (!screen_list->dp)
+            unlink(screen_list->comm.socket_path[SOCK_SERVER]);
+        free(screen_list->comm.socket_path[SOCK_SERVER]);
+    }
+
+    if (screen_list->comm.socket_path[SOCK_CLIENT])
+    {
+        /* FIXME test that we are the client */
+        if (screen_list->dp)
+
+            unlink(screen_list->comm.socket_path[SOCK_CLIENT]);
+        free(screen_list->comm.socket_path[SOCK_CLIENT]);
+    }
+
+    if (screen_list->comm.socket[SOCK_CLIENT])
+        close(screen_list->comm.socket[SOCK_CLIENT]);
+
+    if (screen_list->comm.socket[SOCK_SERVER])
+        close(screen_list->comm.socket[SOCK_SERVER]);
+
+    if (screen_list->screen)
+        free(screen_list->screen);
+
+    option = screen_list->config;
+
+    while (option)
+    {
+        struct option *kromeugnon = option;
+        option = option->next;
+        if (kromeugnon->key)
+            free(kromeugnon->key);
+        if (kromeugnon->value)
+            free(kromeugnon->value);
+        free(kromeugnon);
+    }
+
+    for (i = 0; i < screen_list->recurrent_list->count; i++)
+    {
+        remove_recurrent(screen_list->recurrent_list, i);
+        i = 0;
+    }
+
+    if (screen_list->recurrent_list->recurrent)
+        free(screen_list->recurrent_list->recurrent);
+    if (screen_list->recurrent_list)
+        free(screen_list->recurrent_list);
+
+    if (screen_list->comm.session_name)
+        free(screen_list->comm.session_name);
+
+    if (screen_list->title)
+        free(screen_list->title);
+
+    free(screen_list);
+}
diff --git a/neercs/old/screens.c b/neercs/old/screens.c
new file mode 100644
index 0000000..94e2954
--- /dev/null
+++ b/neercs/old/screens.c
@@ -0,0 +1,334 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <caca.h>
+
+#include "neercs.h"
+
+struct screen *create_screen_grab(int w, int h, int pid)
+{
+    struct screen *s = (struct screen *)malloc(sizeof(struct screen));
+
+    s->cv = caca_create_canvas(w, h);
+    caca_set_color_ansi(s->cv, CACA_BLACK, CACA_BLACK);
+    caca_clear_canvas(s->cv);
+    s->init = 0;
+
+    s->buf = NULL;
+    s->title = NULL;
+    s->total = 0;
+    s->w = w;
+    s->h = h;
+    s->bell = 0;
+    s->report_mouse = MOUSE_NONE;
+
+    s->fd = create_pty_grab(pid, w, h, &s->pid);
+
+    if (s->fd < 0)
+    {
+        caca_free_canvas(s->cv);
+        free(s);
+        return NULL;
+    }
+    return s;
+}
+
+struct screen *create_screen(int w, int h, char *command)
+{
+    struct screen *s = (struct screen *)malloc(sizeof(struct screen));
+
+    s->cv = caca_create_canvas(w, h);
+    caca_set_color_ansi(s->cv, CACA_BLACK, CACA_BLACK);
+    caca_clear_canvas(s->cv);
+    s->init = 0;
+
+    s->buf = NULL;
+    s->title = NULL;
+    s->total = 0;
+    s->w = w + 1;
+    s->h = h + 1;
+    s->bell = 0;
+    s->visible = 1;
+    s->scroll = 0;
+    s->report_mouse = MOUSE_NONE;
+    s->fd = create_pty(command, w, h, &s->pid);
+
+    s->orig_w = s->w;
+    s->orig_h = s->h;
+    s->orig_x = s->x;
+    s->orig_y = s->y;
+
+
+    if (s->fd < 0)
+    {
+        caca_free_canvas(s->cv);
+        free(s);
+        return NULL;
+    }
+    return s;
+}
+
+int destroy_screen(struct screen *s)
+{
+    if (s->fd >= 0)
+        close(s->fd);
+    if (s->buf)
+        free(s->buf);
+    if (s->title)
+        free(s->title);
+    s->buf = NULL;
+    if (s->cv)
+        caca_free_canvas(s->cv);
+    s->cv = NULL;
+    free(s);
+    return 1;
+}
+
+int add_screen(struct screen_list *list, struct screen *s)
+{
+    if (list == NULL || s == NULL)
+        return -1;
+
+    else
+    {
+        list->screen = (struct screen **)realloc(list->screen,
+                                                 sizeof(sizeof
+                                                        (struct screen *)) *
+                                                 (list->count + 1));
+        if (!list->screen)
+            fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__,
+                    __LINE__);
+        list->screen[list->count] = s;
+        list->count++;
+    }
+
+    list->changed = 1;
+
+    return list->count - 1;
+}
+
+int remove_screen(struct screen_list *list, int n, int please_kill)
+{
+
+    if (n >= list->count)
+        return -1;
+
+    if (please_kill)
+    {
+        int status = 0;
+        int ret = 0;
+        /* FIXME */
+        close(list->screen[n]->fd);
+        list->screen[n]->fd = -1;
+        kill(list->screen[n]->pid, SIGINT);
+        ret = waitpid(list->screen[n]->pid, &status,
+                      WNOHANG | WUNTRACED | WCONTINUED);
+        if (!ret)
+            kill(list->screen[n]->pid, SIGQUIT);
+        ret = waitpid(list->screen[n]->pid, &status,
+                      WNOHANG | WUNTRACED | WCONTINUED);
+        if (!ret)
+            kill(list->screen[n]->pid, SIGABRT);
+        ret = waitpid(list->screen[n]->pid, &status,
+                      WNOHANG | WUNTRACED | WCONTINUED);
+        if (!ret)
+            kill(list->screen[n]->pid, SIGKILL);
+
+    }
+    destroy_screen(list->screen[n]);
+
+    memmove(&list->screen[n],
+            &list->screen[n + 1],
+            sizeof(struct screen *) * (list->count - (n + 1)));
+
+    list->screen = (struct screen **)realloc(list->screen,
+                                             sizeof(sizeof(struct screen *))
+                                             * (list->count));
+    if (!list->screen)
+        fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__,
+                __LINE__);
+
+
+
+    list->count--;
+    list->changed = 1;
+    return 1;
+}
+
+
+
+void refresh_screens(struct screen_list *screen_list)
+{
+    int i;
+
+    if (!screen_list->count)
+        return;
+
+
+    screen_list->width = caca_get_canvas_width(screen_list->cv);
+    screen_list->height =
+        caca_get_canvas_height(screen_list->cv) - (screen_list->modals.mini * 6) -
+        screen_list->modals.status;
+
+    if (!screen_list->dont_update_coords)
+    {
+        update_windows_props(screen_list);
+    }
+
+    if (screen_list->changed)
+    {
+        caca_set_color_ansi(screen_list->cv, CACA_DEFAULT, CACA_DEFAULT);
+        caca_clear_canvas(screen_list->cv);
+    }
+
+    wm_refresh(screen_list);
+
+    caca_gotoxy(screen_list->cv,
+                screen_list->screen[screen_list->pty]->x +
+                caca_get_cursor_x(screen_list->screen[screen_list->pty]->cv),
+                screen_list->screen[screen_list->pty]->y +
+                caca_get_cursor_y(screen_list->screen[screen_list->pty]->cv));
+
+
+    if (screen_list->modals.mini)
+    {
+        draw_thumbnails(screen_list);
+    }
+    if (screen_list->modals.status)
+    {
+        draw_status(screen_list);
+    }
+    if (screen_list->modals.help)
+    {
+        draw_help(screen_list);
+    }
+    if (screen_list->modals.window_list)
+    {
+        draw_list(screen_list);
+    }
+#ifdef USE_PYTHON
+    debug("py : command is %d (at %p)\n", screen_list->modals.python_command, &screen_list->modals.python_command);
+    if(screen_list->modals.python_command)
+    {
+         draw_python_command(screen_list);
+    }
+#endif
+    screen_list->changed = 0;
+    for (i = screen_list->count - 1; i >= 0; i--)
+        screen_list->screen[i]->changed = 0;
+}
+
+
+int update_screens_contents(struct screen_list *screen_list)
+{
+    int i, refresh = 0;
+    int maxfd = 0;
+    struct timeval tv;
+    fd_set fdset;
+    int ret;
+
+    /* Read data, if any */
+    FD_ZERO(&fdset);
+    for (i = 0; i < screen_list->count; i++)
+    {
+        if (screen_list->screen[i]->fd >= 0)
+            FD_SET(screen_list->screen[i]->fd, &fdset);
+        if (screen_list->screen[i]->fd > maxfd)
+            maxfd = screen_list->screen[i]->fd;
+    }
+    tv.tv_sec = 0;
+    tv.tv_usec = 50000;
+    ret = select(maxfd + 1, &fdset, NULL, NULL, &tv);
+
+    if (ret < 0)
+    {
+        if (errno == EINTR)
+            ;                   /* We probably got a SIGWINCH, ignore it */
+        else
+        {
+            /* FIXME: Useless since break will mean that we return 0 But I
+               don't know what was the purpose of this code */
+            for (i = 0; i < screen_list->count; i++)
+                if (screen_list->screen[i]->total)
+                    break;
+            if (i == screen_list->count)
+                return 0;
+        }
+    }
+    else if (ret)
+    {
+
+        for (i = 0; i < screen_list->count; i++)
+        {
+            /* FIXME: try a new strategy: read all filedescriptors until each
+               of them starved at least once. */
+
+            if (screen_list->screen[i]->fd < 0 ||
+                !FD_ISSET(screen_list->screen[i]->fd, &fdset))
+                continue;
+
+            for (;;)
+            {
+                ssize_t nr;
+
+                screen_list->screen[i]->buf =
+                    realloc(screen_list->screen[i]->buf,
+                            screen_list->screen[i]->total + 1024);
+                if (!screen_list->screen[i]->buf)
+                    fprintf(stderr, "Can't allocate memory at %s:%d\n",
+                            __FUNCTION__, __LINE__);
+
+                nr = read(screen_list->screen[i]->fd,
+                          screen_list->screen[i]->buf +
+                          screen_list->screen[i]->total, 1024);
+
+                if (nr > 0)
+                {
+                    screen_list->screen[i]->total += nr;
+                    continue;
+                }
+
+                if (nr == 0 || errno != EWOULDBLOCK)
+                {
+                    remove_screen(screen_list, i, 0);
+                    if (i < screen_list->prevpty)
+                        screen_list->prevpty--;
+                    if (i == screen_list->pty)
+                    {
+                        screen_list->pty = screen_list->prevpty;
+                        screen_list->prevpty = 0;
+                    }
+                    if (i < (screen_list->pty))
+                        (screen_list->pty)--;
+                    /* Don't skip the element which is now at position i */
+                    i--;
+                    refresh = 1;
+                }
+
+                break;
+            }
+        }
+    }
+    return refresh;
+}
diff --git a/neercs/old/screensaver.c b/neercs/old/screensaver.c
new file mode 100644
index 0000000..9e9ab89
--- /dev/null
+++ b/neercs/old/screensaver.c
@@ -0,0 +1,187 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <caca.h>
+
+#include "neercs.h"
+
+
+void screensaver_init(struct screen_list *screen_list)
+{
+    screensaver_flying_toasters_init(screen_list);
+}
+
+void screensaver_kill(struct screen_list *screen_list)
+{
+    screensaver_flying_toasters_kill(screen_list);
+}
+
+void draw_screensaver(struct screen_list *screen_list)
+{
+    screensaver_flying_toasters(screen_list);
+}
+
+
+
+
+/* Flying Toasters */
+
+#define COUNT 15
+#define PRECISION 100
+
+char toaster_text[3][99] = { {
+ "      __._ \n"
+ "   .-'== _',\n"
+ "  <|_= .-'  |\n"
+ "   | --|   \\'.-_ \n"
+ "   |   | \\  \" _.\n"
+ "    `-_|.-\\_.-\n"},
+{
+ "      __._ \n"
+ "   .-'== _',\n"
+ "  \\|_= .-'  |\n"
+ "   | --|  __'-.\n"
+ "   |   | ___.-\n"
+ "    `-_|.-\n"},
+{
+ "   _- __._\n"
+ "  /.-'== _',_.-.\n"
+ "  \\|_= .-'/  _.'\n"
+ "   | --| / .-\n"
+ "   |   |  _.|\n"
+ "    `-_|.-\n"}
+};
+
+char toaster_mask[3][99] = { {
+
+ "      __._ \n"
+ "   .-'== _',\n"
+ "  <|_=X.-'XX|\n"
+ "   |X--|XXX\\'.-_ \n"
+ "   |XXX|X\\XX\"X_.\n"
+ "    `-_|.-\\_.-\n"},
+    {
+
+ "      __._ \n"
+ "   .-'== _',\n"
+ "  \\|_= .-'XX|\n"
+ "   |X--|XX__'-.\n"
+ "   |XXX|X___.-\n"
+ "    `-_|.-\n"},
+{
+ "   _- __._\n"
+ "  /.-'== _',_.-.\n"
+ "  \\|_= .-'/XX_.'\n"
+ "   |X--|X/X.-\n"
+ "   |XXX|XX_.|\n"
+ "    `-_|.-\n"}
+};
+
+struct flying_toaster
+{
+    int x[COUNT], y[COUNT], s[COUNT];
+    caca_canvas_t **toaster;
+    caca_canvas_t **mask;
+};
+
+void screensaver_flying_toasters_init(struct screen_list *screen_list)
+{
+    struct flying_toaster *flying_toaster;
+    int w = caca_get_canvas_width(screen_list->cv);
+    int h = caca_get_canvas_height(screen_list->cv);
+    int i;
+
+    flying_toaster = malloc(sizeof(struct flying_toaster));
+    flying_toaster->toaster =
+        (caca_canvas_t **) malloc(sizeof(caca_canvas_t *) * 3);
+    flying_toaster->mask =
+        (caca_canvas_t **) malloc(sizeof(caca_canvas_t *) * 3);
+
+    for (i = 0; i < 3; i++)
+    {
+        flying_toaster->toaster[i] = caca_create_canvas(0, 0);
+        flying_toaster->mask[i] = caca_create_canvas(0, 0);
+        caca_import_canvas_from_memory(flying_toaster->toaster[i],
+                                       toaster_text[i],
+                                       strlen(toaster_text[i]), "utf8");
+        caca_import_canvas_from_memory(flying_toaster->mask[i],
+                                       toaster_mask[i],
+                                       strlen(toaster_mask[i]), "utf8");
+    }
+
+    for (i = 0; i < COUNT; i++)
+    {
+        flying_toaster->x[i] = (rand() % w) * PRECISION;
+        flying_toaster->y[i] = (rand() % h) * PRECISION;
+        flying_toaster->s[i] = (rand() % 3) * PRECISION;
+    }
+
+
+    screen_list->screensaver.data = flying_toaster;
+}
+
+void screensaver_flying_toasters_kill(struct screen_list *screen_list)
+{
+    struct flying_toaster *flying_toaster = screen_list->screensaver.data;
+
+    caca_free_canvas(flying_toaster->toaster[0]);
+    caca_free_canvas(flying_toaster->toaster[1]);
+    caca_free_canvas(flying_toaster->toaster[2]);
+    free(flying_toaster->toaster);
+    free(flying_toaster);
+    screen_list->screensaver.data = NULL;
+}
+
+void screensaver_flying_toasters(struct screen_list *screen_list)
+{
+    struct flying_toaster *d = screen_list->screensaver.data;
+    int i, w, h, x, y, s;
+    if (!d)
+        return;
+
+    w = caca_get_canvas_width(screen_list->cv);
+    h = caca_get_canvas_height(screen_list->cv);
+
+    caca_set_color_ansi(screen_list->cv, CACA_WHITE, CACA_BLACK);
+    caca_clear_canvas(screen_list->cv);
+
+    for (i = 0; i < COUNT; i++)
+    {
+        x = d->x[i] / PRECISION;
+        y = d->y[i] / PRECISION;
+        s = d->s[i] / PRECISION;
+
+        caca_blit(screen_list->cv, x, y, d->toaster[s], d->mask[s]);
+
+        d->x[i] -= 40;
+        d->y[i] += 10;
+
+        if (d->x[i] / PRECISION + caca_get_canvas_width(d->toaster[s]) <= 0)
+            d->x[i] = ((rand() % w) / 3 + w) * PRECISION;
+        if (d->y[i] / PRECISION >= h)
+            d->y[i] = ((rand() % h) / 2 - h) * PRECISION;
+
+        d->s[i] = ((d->s[i] + 24) % (3 * PRECISION));
+    }
+}
diff --git a/neercs/old/server.c b/neercs/old/server.c
new file mode 100644
index 0000000..3c450e2
--- /dev/null
+++ b/neercs/old/server.c
@@ -0,0 +1,680 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                2008-2010 Pascal Terjan <pterjan@linuxfr.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <time.h>
+#include <pwd.h>
+
+#include <errno.h>
+#include <caca.h>
+
+#include "neercs.h"
+
+static void server_init(struct screen_list *screen_list);
+static void refresh_screen(struct screen_list *screen_list, int refresh);
+static int handle_key(struct screen_list *screen_list, unsigned int c,
+                      int refresh);
+static int handle_attach(struct screen_list *screen_list, char *buf);
+
+static int send_to_client(const char *msg, int size,
+                          struct screen_list *screen_list)
+{
+    int ret;
+    if (!screen_list->comm.socket[SOCK_CLIENT])
+        connect_socket(screen_list, SOCK_CLIENT);
+    if (!screen_list->comm.socket[SOCK_CLIENT])
+        ret = -1;
+    else
+        ret = write(screen_list->comm.socket[SOCK_CLIENT], msg, size);
+    if (ret < 0 && errno != EAGAIN)
+    {
+        fprintf(stderr, "Failed to send message to client: %s\n",
+                strerror(errno));
+        if (screen_list->comm.attached)
+            detach(screen_list);
+    }
+    return ret;
+}
+
+static int set_title(struct screen_list *screen_list)
+{
+    char buf[1024];
+    int bytes;
+    char *title = NULL;
+
+    if (screen_list->comm.attached)
+    {
+        if (screen_list->pty < screen_list->count &&
+            screen_list->screen[screen_list->pty]->title)
+            title = screen_list->screen[screen_list->pty]->title;
+        else
+            title = PACKAGE_STRING;
+    }
+
+    if (screen_list->title)
+    {
+        if (!strcmp(screen_list->title, title))
+            return 0;
+        free(screen_list->title);
+    }
+
+    screen_list->title = strdup(title);
+
+    bytes = snprintf(buf, sizeof(buf) - 1, "TITLE %s", title);
+    buf[bytes] = '\0';
+    return send_to_client(buf, strlen(buf), screen_list);
+}
+
+static int set_cursor(int state, struct screen_list *screen_list)
+{
+    char buf[16];
+    int bytes;
+
+    bytes = snprintf(buf, sizeof(buf) - 1, "CURSOR %d", state);
+    buf[bytes] = '\0';
+
+    return send_to_client(buf, strlen(buf), screen_list);
+}
+
+static int request_refresh(struct screen_list *screen_list)
+{
+    int ndirty = caca_get_dirty_rect_count(screen_list->cv);
+    if (!ndirty)
+        return 0;
+    if (!screen_list->comm.socket[SOCK_CLIENT])
+        connect_socket(screen_list, SOCK_CLIENT);
+    if (screen_list->comm.socket[SOCK_CLIENT])
+    {
+        size_t bufsize, towrite;
+        ssize_t written, ret;
+        socklen_t optlen = sizeof(bufsize);
+        size_t bytes;
+        void *buf;
+        char buf2[32];
+        int x, y, i;
+
+        getsockopt(screen_list->comm.socket[SOCK_CLIENT], SOL_SOCKET,
+                   SO_SNDBUF, &bufsize, &optlen);
+        bufsize /= 2;
+        debug("bufsize=%d", bufsize);
+
+        for (i = 0; i < ndirty; i++)
+        {
+            int w, h;
+            caca_get_dirty_rect(screen_list->cv, i, &x, &y, &w, &h);
+            debug("dirty @%d,%d %dx%d [%dx%d]", x, y, w, h,
+                  caca_get_canvas_width(screen_list->cv),
+                  caca_get_canvas_height(screen_list->cv));
+            buf =
+                caca_export_area_to_memory(screen_list->cv, x, y, w, h, "caca",
+                                           &bytes);
+            debug("Requesting refresh for %d", bytes);
+            towrite = bytes;
+            written = 0;
+            sprintf(buf2, "UPDATE %10d %10d", x, y);
+            ret = send_to_client(buf2, strlen(buf2) + 1, screen_list);
+            if (ret < 29)
+            {
+                free(buf);
+                return -1;
+            }
+            /* Block to write the end of the message */
+            fcntl(screen_list->comm.socket[SOCK_CLIENT], F_SETFL, 0);
+            while (towrite > 0)
+            {
+                ssize_t n;
+                debug("Wrote %d, %d remaining", written, towrite);
+                n = send_to_client((char *)buf + written,
+                                   towrite > bufsize ? bufsize : towrite,
+                                   screen_list);
+                if (n < 0)
+                {
+                    debug("Can't refresh (%s), with %d bytes (out of %d)",
+                          strerror(errno),
+                          towrite > bufsize ? bufsize : towrite, towrite);
+                    return -1;
+                }
+                written += n;
+                towrite -= n;
+            }
+            fcntl(screen_list->comm.socket[SOCK_CLIENT], F_SETFL, O_NONBLOCK);
+            free(buf);
+        }
+        sprintf(buf2, "REFRESH %10d %10d", caca_get_cursor_x(screen_list->cv),
+                caca_get_cursor_y(screen_list->cv));
+        /* FIXME check value of r */
+        int r = send_to_client(buf2, strlen(buf2) + 1, screen_list);
+        (void)r;
+        caca_clear_dirty_rect_list(screen_list->cv);
+    }
+    return 0;
+}
+
+int detach(struct screen_list *screen_list)
+{
+    screen_list->comm.attached = 0;
+    if (screen_list->lock.lock_on_detach)
+        screen_list->lock.locked = 1;
+    if (screen_list->comm.socket[SOCK_CLIENT])
+    {
+        send_to_client("DETACH", 6, screen_list);
+        close(screen_list->comm.socket[SOCK_CLIENT]);
+        screen_list->comm.socket[SOCK_CLIENT] = 0;
+    }
+    return 0;
+}
+
+static int server_iteration(struct screen_list *screen_list)
+{
+    int i;
+    int eof = 0, refresh;
+
+    int quit = 0;
+    ssize_t n;
+    char buf[128];
+
+    /* Read program output */
+    refresh = update_screens_contents(screen_list);
+
+    /* Check if we got something from the client */
+    while (screen_list->comm.socket[SOCK_SERVER]
+           && (n =
+               read(screen_list->comm.socket[SOCK_SERVER], buf,
+                    sizeof(buf) - 1)) > 0)
+    {
+        buf[n] = 0;
+        debug("Received command %s", buf);
+        if (!strncmp("ATTACH ", buf, 7))
+        {
+            refresh |= handle_attach(screen_list, buf);
+        }
+        else if (!strncmp("QUIT", buf, 4))
+        {
+            quit = 1;
+        }
+        else if (!strncmp("DELAY ", buf, 6))
+        {
+            /* FIXME check the length before calling atoi */
+            screen_list->delay = atoi(buf + 6);
+        }
+        else if (!strncmp("RESIZE ", buf, 7))
+        {
+            caca_free_canvas(screen_list->cv);
+            /* FIXME check the length before calling atoi */
+            screen_list->cv =
+                caca_create_canvas(atoi(buf + 7), atoi(buf + 18));
+            screen_list->changed = 1;
+            refresh = 1;
+        }
+        else if (!strncmp("KEY ", buf, 4))
+        {
+            unsigned int c = atoi(buf + 4);
+            refresh |= handle_key(screen_list, c, refresh);
+        }
+        else if (!strncmp("MOUSEP ", buf, 6))
+        {
+            debug("Got mouse press '%s'\n", buf);
+            int x, y, b;
+            x = 1 + atoi(buf + 7) - screen_list->screen[screen_list->pty]->x;
+            y = 1 + atoi(buf + 18) - screen_list->screen[screen_list->pty]->y;
+            b = atoi(buf + 28);
+
+            switch (screen_list->screen[screen_list->pty]->report_mouse)
+            {
+            case MOUSE_VT200:
+            case MOUSE_VT200_HIGHLIGHT:
+            case MOUSE_BTN_EVENT:
+            case MOUSE_ANY_EVENT:
+                sprintf(buf, "\x1b[M%c%c%c", 32 + (b - 1), x + 32, y + 32);
+                debug("mousea send ESC[M %d %d %d", (b - 1), x + 32, y + 32);
+                send_ansi_sequence(screen_list, buf);
+                break;
+            case MOUSE_X10:
+                sprintf(buf, "\x1b[M%c%c%c", 32 + (b - 1), 32 + x, 32 + y);
+                debug("mousex send ESC[M %d %d %d", 32 + (b - 1), 32 + x,
+                      32 + y);
+                send_ansi_sequence(screen_list, buf);
+                break;
+            case MOUSE_NONE:
+                break;
+
+            }
+        }
+        else if (!strncmp("MOUSER ", buf, 6))
+        {
+            debug("Got mouse release '%s'\n", buf);
+            int x, y, b;
+            x = 1 + atoi(buf + 7) - screen_list->screen[screen_list->pty]->x;
+            y = 1 + atoi(buf + 18) - screen_list->screen[screen_list->pty]->y;
+            b = atoi(buf + 28);
+
+            switch (screen_list->screen[screen_list->pty]->report_mouse)
+            {
+            case MOUSE_VT200:
+            case MOUSE_VT200_HIGHLIGHT:
+            case MOUSE_BTN_EVENT:
+            case MOUSE_ANY_EVENT:
+                sprintf(buf, "\x1b[M%c%c%c", 32 + 3, x + 32, y + 32);
+                send_ansi_sequence(screen_list, buf);
+                break;
+            case MOUSE_X10:
+                sprintf(buf, "\x1b[M%c%c%c", 32 + 3, 32 + x, 32 + y);
+                send_ansi_sequence(screen_list, buf);
+                break;
+            case MOUSE_NONE:
+                break;
+            }
+        }
+
+        else if (!strncmp("MOUSEM ", buf, 6))
+        {
+            debug("Got mouse motion '%s'\n", buf);
+            int x, y, b;
+            x = 1 + atoi(buf + 7) - screen_list->screen[screen_list->pty]->x;
+            y = 1 + atoi(buf + 18) - screen_list->screen[screen_list->pty]->y;
+            b = atoi(buf + 28);
+
+            switch (screen_list->screen[screen_list->pty]->report_mouse)
+            {
+            case MOUSE_X10:    // X10 reports mouse clicks only
+                if (b)
+                {
+                    sprintf(buf, "\x1b[M%c%c%c", 32 + (b - 1), x + 32, y + 32);
+                    send_ansi_sequence(screen_list, buf);
+                }
+                break;
+            case MOUSE_VT200:
+            case MOUSE_VT200_HIGHLIGHT:
+            case MOUSE_BTN_EVENT:
+                if (b)
+                {
+                    sprintf(buf, "\x1b[M%c%c%c", 32 + (b - 1), x + 32, y + 32);
+                    send_ansi_sequence(screen_list, buf);
+                }
+            case MOUSE_ANY_EVENT:
+                sprintf(buf, "\x1b[M%c%c%c", 32 + (b - 1), x + 32, y + 32);
+                send_ansi_sequence(screen_list, buf);
+                break;
+            case MOUSE_NONE:
+                break;
+            }
+        }
+        else
+        {
+            fprintf(stderr, "Unknown command received: %s\n", buf);
+        }
+    }
+
+    /* No more screens, exit */
+    if (!screen_list->count)
+        return -1;
+
+    /* User requested to exit */
+    if (quit)
+        return -2;
+
+    /* Update each screen canvas */
+    refresh |= update_terms(screen_list);
+
+    /* Launch recurrents if any */
+    refresh |= handle_recurrents(screen_list);
+
+    /* Refresh screen */
+    refresh_screen(screen_list, refresh);
+
+    eof = 1;
+    for (i = 0; i < screen_list->count; i++)
+        if (screen_list->screen[i]->fd >= 0)
+            eof = 0;
+    if (eof)
+        return -3;
+
+    return 0;
+}
+
+static void server_main(struct screen_list *screen_list)
+{
+    screen_list->last_key_time = 0;
+    screen_list->comm.attached = 0;
+    screen_list->command = 0;
+    screen_list->was_in_bell = 0;
+    screen_list->last_refresh_time = 0;
+
+    server_init(screen_list);
+#ifdef USE_PYTHON
+    python_init(screen_list);
+#endif
+
+    for (;;)
+    {
+        if (server_iteration(screen_list))
+            break;
+    }
+
+    detach(screen_list);
+
+    free_screen_list(screen_list);
+
+#ifdef USE_PYTHON
+    python_close(screen_list);
+#endif
+
+    exit(0);
+}
+
+static void refresh_screen(struct screen_list *screen_list, int refresh)
+{
+    if (!screen_list->comm.attached)
+    {
+        /* No need to refresh Don't use the CPU too much Would be better to
+           select on terms + socket */
+        sleep(1);
+    }
+    else
+    {
+        long long unsigned int current_time = get_us();
+        long long int tdiff =
+            (current_time - screen_list->last_refresh_time) / 1000;
+
+        refresh |= screen_list->need_refresh;
+
+        if (screen_list->force_refresh)
+        {
+            wm_refresh(screen_list);
+            refresh = 1;
+        }
+
+        /* Draw lock window */
+        if (screen_list->lock.locked)
+        {
+            /* FIXME don't redraw it each iteration */
+            draw_lock(screen_list);
+            refresh = 1;
+        }
+#ifdef USE_LOCK
+        else if ((current_time - screen_list->last_key_time >=
+                  screen_list->lock.autolock_timeout))
+        {
+            screen_list->lock.locked = 1;
+            refresh = 1;
+        }
+#endif
+        else if ((current_time - screen_list->last_key_time >=
+                  screen_list->screensaver.timeout))
+        {
+            if (!screen_list->screensaver.in_screensaver)
+            {
+                screensaver_init(screen_list);
+                screen_list->screensaver.in_screensaver = 1;
+                set_cursor(0, screen_list);
+            }
+            draw_screensaver(screen_list);
+            refresh = 1;
+        }
+        else if (refresh || screen_list->was_in_bell)
+        {
+            if (tdiff >= screen_list->delay)
+            {
+                refresh_screens(screen_list);
+                set_title(screen_list);
+                refresh = 1;
+            }
+        }
+        if (refresh)
+        {
+            if (tdiff >= screen_list->delay)
+            {
+                request_refresh(screen_list);
+                screen_list->last_refresh_time = current_time;
+                screen_list->need_refresh = 0;
+            }
+            else
+            {
+                debug("Skipping refresh (%lld < %d)", tdiff,
+                      screen_list->delay);
+                screen_list->need_refresh = 1;
+            }
+        }
+    }
+}
+
+static void server_init(struct screen_list *screen_list)
+{
+    int i;
+    debug("Screen list at %p\n", screen_list);
+
+    /* Create socket and bind it */
+    create_socket(screen_list, SOCK_SERVER);
+
+    /* Connect to the client */
+    connect_socket(screen_list, SOCK_CLIENT);
+
+    screen_list->width = screen_list->height = 80;
+
+    /* Create main canvas */
+    screen_list->cv = caca_create_canvas(screen_list->width,
+                                         screen_list->height
+                                         + screen_list->modals.mini * 6
+                                         + screen_list->modals.status);
+
+    if (!screen_list->sys.to_grab && !screen_list->sys.to_start)
+    {
+        add_screen(screen_list,
+                   create_screen(screen_list->width,
+                                 screen_list->height,
+                                 screen_list->sys.default_shell));
+    }
+
+    /* Attach processes */
+    if (screen_list->sys.to_grab)
+    {
+        for (i = 0; screen_list->sys.to_grab[i]; i++)
+        {
+            add_screen(screen_list,
+                       create_screen_grab(screen_list->width,
+                                          screen_list->height,
+                                          screen_list->sys.to_grab[i]));
+        }
+        free(screen_list->sys.to_grab);
+        screen_list->sys.to_grab = NULL;
+    }
+
+    /* Launch command line processes */
+    if (screen_list->sys.to_start)
+    {
+        for (i = 0; screen_list->sys.to_start[i]; i++)
+        {
+            add_screen(screen_list,
+                       create_screen(screen_list->width,
+                                     screen_list->height,
+                                     screen_list->sys.to_start[i]));
+            free(screen_list->sys.to_start[i]);
+        }
+        free(screen_list->sys.to_start);
+        screen_list->sys.to_start = NULL;
+    }
+
+    screen_list->last_key_time = get_us();
+}
+
+static int handle_attach(struct screen_list *screen_list, char *buf)
+{
+    /* If we were attached to someone else, detach first */
+    if (screen_list->comm.attached)
+        detach(screen_list);
+    screen_list->comm.attached = 1;
+    caca_free_canvas(screen_list->cv);
+    screen_list->cv = caca_create_canvas(atoi(buf + 7), atoi(buf + 18));
+    screen_list->delay = atoi(buf + 29);
+    screen_list->changed = 1;
+    return 1;
+}
+
+static int handle_key(struct screen_list *screen_list, unsigned int c,
+                      int refresh)
+{
+    char *str = NULL;
+    int size = 0;
+
+    if (screen_list->modals.help)
+    {
+        return help_handle_key(screen_list, c);
+    }
+#ifdef USE_PYTHON
+    if (screen_list->modals.python_command)
+    {
+        return python_command_handle_key(screen_list, c);
+    }
+#endif
+
+    /* CTRL-A has been pressed before, handle this as a command, except that
+       CTRL-A a sends literal CTRL-A */
+    if (screen_list->command && (c != 'a'))
+    {
+        screen_list->command = 0;
+        refresh |= handle_command_input(screen_list, c);
+    }
+    else
+    {
+        /* Not in command mode */
+        screen_list->last_key_time = get_us();
+        set_cursor(1, screen_list);
+
+        /* Kill screensaver */
+        if (screen_list->screensaver.in_screensaver)
+        {
+            screensaver_kill(screen_list);
+            screen_list->screensaver.in_screensaver = 0;
+            screen_list->changed = 1;
+            refresh = 1;
+            return refresh;
+        }
+        /* Handle lock window */
+        if (screen_list->lock.locked)
+        {
+            refresh |= update_lock(c, screen_list);
+            screen_list->changed = 1;
+        }
+        else if (screen_list->modals.window_list)
+        {
+            refresh |= update_window_list(c, screen_list);
+            screen_list->changed = 1;
+        }
+        else
+        {
+            switch (c)
+            {
+            case 0x01:         // CACA_KEY_CTRL_A:
+                screen_list->command = 1;
+                break;
+            default:
+                /* CTRL-A a sends literal CTRL-A */
+                if (screen_list->command && (c == 'a'))
+                {
+                    c = 0x01;
+                }
+                /* Normal key, convert it if needed */
+                str = convert_input_ansi(&c, &size);
+                /* FIXME check value of r */
+                int r = write(screen_list->screen[screen_list->pty]->fd, str,
+                              size);
+                (void)r;
+                break;
+            }
+        }
+    }
+    return refresh;
+}
+
+int send_ansi_sequence(struct screen_list *screen_list, char *str)
+{
+    debug("Sending ansi '%s'\n", str);
+    return write(screen_list->screen[screen_list->pty]->fd, str, strlen(str));
+}
+
+
+int install_fds(struct screen_list *screen_list)
+{
+    int fd;
+    close(0);
+    close(1);
+    close(2);
+    fd = open("/dev/null", O_RDWR, 0);
+    if (fd < 0)
+    {
+        perror("Failed to open /dev/null");
+        return -2;
+    }
+    dup2(fd, 0);
+#ifndef DEBUG
+    dup2(fd, 1);
+    dup2(fd, 2);
+    if (fd > 2)
+        close(fd);
+#else
+    if (fd != 0)
+        close(fd);
+    screen_list->outfd =
+        open("/tmp/neercs-debug.txt", O_TRUNC | O_RDWR | O_CREAT,
+             S_IRUSR | S_IWUSR);
+    dup2(screen_list->outfd, 1);
+    dup2(screen_list->outfd, 2);
+    if (screen_list->outfd > 2)
+        close(screen_list->outfd);
+#endif
+    return 0;
+}
+
+int start_server(struct screen_list *screen_list)
+{
+    pid_t pid;
+
+    pid = fork();
+    if (pid < 0)
+    {
+        perror("Failed to create child process");
+        return -1;
+    }
+    if (pid == 0)
+    {
+        int r = install_fds(screen_list);
+        if (r)
+            return r;
+        setsid();
+
+        server_main(screen_list);
+        /* Never returns */
+    }
+
+    return 0;
+}
+
+long long get_us(void)
+{
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    return (tv.tv_sec * (1000000) + tv.tv_usec);
+}
diff --git a/neercs/old/term.c b/neercs/old/term.c
new file mode 100644
index 0000000..032f9b5
--- /dev/null
+++ b/neercs/old/term.c
@@ -0,0 +1,133 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include "config.h"
+
+#define _XOPEN_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <termios.h>
+#if defined HAVE_PTY_H
+#   include <pty.h>             /* for openpty and forkpty */
+#elif defined HAVE_UTIL_H
+#   include <util.h>            /* for OS X, OpenBSD and NetBSD */
+#elif defined HAVE_LIBUTIL_H
+#   include <libutil.h>         /* for FreeBSD */
+#endif
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <caca.h>
+
+#include "neercs.h"
+
+
+int create_pty(char *cmd, unsigned int w, unsigned int h, int *cpid)
+{
+    char **argv;
+    int fd;
+    pid_t pid;
+
+    pid = forkpty(&fd, NULL, NULL, NULL);
+    if (pid < 0)
+    {
+        fprintf(stderr, "forkpty() error\n");
+        return -1;
+    }
+    else if (pid == 0)
+    {
+        set_tty_size(0, w, h);
+        putenv("CACA_DRIVER=slang");
+        putenv("TERM=xterm");
+        argv = malloc(2 * sizeof(char *));
+        if (!argv)
+        {
+            fprintf(stderr, "Can't allocate memory at %s:%d\n", __FUNCTION__,
+                    __LINE__);
+            return -1;
+        }
+        argv[0] = cmd;
+        argv[1] = NULL;
+        execvp(cmd, argv);
+        fprintf(stderr, "execvp() error\n");
+        return -1;
+    }
+
+    *cpid = pid;
+
+    fcntl(fd, F_SETFL, O_NDELAY);
+    return fd;
+}
+
+int create_pty_grab(long pid, unsigned int w, unsigned int h, int *newpid)
+{
+    int fdm, fds;
+
+    int ret = openpty(&fdm, &fds, NULL, NULL, NULL);
+
+    if (ret < 0)
+    {
+        fprintf(stderr, "open() error\n");
+        return -1;
+    }
+
+    set_tty_size(0, w, h);
+    grab_process(pid, ptsname(fdm), fds, newpid);
+
+    fcntl(fdm, F_SETFL, O_NDELAY);
+    return fdm;
+}
+
+int set_tty_size(int fd, unsigned int w, unsigned int h)
+{
+    struct winsize ws;
+
+    memset(&ws, 0, sizeof(ws));
+    ws.ws_row = h;
+    ws.ws_col = w;
+    ioctl(fd, TIOCSWINSZ, (char *)&ws);
+
+    return 0;
+}
+
+
+
+int update_terms(struct screen_list *screen_list)
+{
+    int i, refresh = 0;
+    for (i = 0; i < screen_list->count; i++)
+    {
+        if (screen_list->screen[i]->total && !screen_list->dont_update_coords)
+        {
+            unsigned long int bytes;
+
+            bytes = import_term(screen_list,
+                                screen_list->screen[i],
+                                screen_list->screen[i]->buf,
+                                screen_list->screen[i]->total);
+
+            if (bytes > 0)
+            {
+                screen_list->screen[i]->total -= bytes;
+                memmove(screen_list->screen[i]->buf,
+                        screen_list->screen[i]->buf + bytes,
+                        screen_list->screen[i]->total);
+                if (screen_list->screen[i]->visible || screen_list->modals.mini)
+                    refresh = 1;
+            }
+        }
+    }
+    return refresh;
+}
diff --git a/neercs/old/widgets.c b/neercs/old/widgets.c
new file mode 100644
index 0000000..a181660
--- /dev/null
+++ b/neercs/old/widgets.c
@@ -0,0 +1,176 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2009-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+
+#include "widgets.h"
+
+static void widget_ibox_add_char(struct input_box *box, unsigned int c);
+static void widget_ibox_del_char(struct input_box *box);
+
+struct input_box *widget_ibox_init(caca_canvas_t *cv, int w, int h)
+{
+    struct input_box *box = malloc(sizeof(struct input_box));
+    if (!box)
+        return NULL;
+    box->cv = cv;
+    box->w = w;
+    box->h = h;
+    box->command = NULL;
+    box->output_err = NULL;
+    box->output_res = NULL;
+
+    return box;
+}
+
+
+int widget_ibox_draw(struct input_box *box)
+{
+    int x = (caca_get_canvas_width(box->cv) - box->w) / 2;
+    int y = (caca_get_canvas_height(box->cv) - box->h) / 2;
+
+    caca_set_color_ansi(box->cv, CACA_BLUE, CACA_BLUE);
+    caca_fill_box(box->cv, x, y, box->w, box->h, '#');
+    caca_set_color_ansi(box->cv, CACA_DEFAULT, CACA_BLUE);
+    caca_draw_cp437_box(box->cv, x, y, box->w, box->h);
+    caca_printf(box->cv, x, y, "Mini-command");
+
+    caca_printf(box->cv, x + 2, y + 2,
+                "[___________________________________________________________]");
+
+    if (box->command)
+    {
+        caca_printf(box->cv, x + 3, y + 2, "%s", box->command);
+        caca_gotoxy(box->cv, x + 3 + box->x, y + 2);
+    }
+    else
+    {
+        caca_gotoxy(box->cv, x + 3, y + 2);
+    }
+
+    if (box->output_err)
+    {
+        caca_set_color_ansi(box->cv, CACA_RED, CACA_BLUE);
+        caca_printf(box->cv, x + 2, y + 4, box->output_err);
+    }
+    if (box->output_res)
+    {
+        caca_set_color_ansi(box->cv, CACA_LIGHTGREEN, CACA_BLUE);
+        caca_printf(box->cv, x + 2, y + 4, box->output_res);
+    }
+
+    return 0;
+}
+
+char *widget_ibox_get_text(struct input_box *box)
+{
+    return box->command;
+}
+
+void widget_ibox_destroy(struct input_box *box)
+{
+    if(!box) return;
+    if (box->command)
+        free(box->command);
+    if (box->output_err)
+        free(box->output_err);
+    if (box->output_res)
+        free(box->output_res);
+}
+
+void widget_ibox_set_error(struct input_box *box, char *err)
+{
+    box->output_err = err;
+}
+
+void widget_ibox_set_msg(struct input_box *box, char *msg)
+{
+    box->output_res = msg;
+}
+
+int widget_ibox_handle_key(struct input_box *box, unsigned int c)
+{
+    if (c == CACA_KEY_ESCAPE)
+    {
+        if (box->command)
+        {
+            free(box->command);
+            box->command = NULL;
+        }
+        return INPUT_BOX_ESC;
+    }
+    else if (c == CACA_KEY_LEFT)
+    {
+        if (box->x)
+            box->x--;
+    }
+    else if (c == CACA_KEY_RIGHT)
+    {
+        if (box->x < box->size - 1)
+            box->x++;
+    }
+    else if (c == CACA_KEY_RETURN)
+    {
+        return INPUT_BOX_RET;
+    }
+    else
+    {
+        if (c >= ' ' && c < 127)
+            widget_ibox_add_char(box, c);
+        else if (c == 8)
+        {
+            widget_ibox_del_char(box);
+        }
+    }
+    return INPUT_BOX_NOTHING;
+}
+
+
+
+static void widget_ibox_add_char(struct input_box *box, unsigned int c)
+{
+    /* FIXME handle return values */
+    if (!box->command)
+    {
+        box->size = 1;
+        box->x = 0;
+        box->command = (char *)malloc(2);
+        box->command[0] = 0;
+    }
+    else
+    {
+        box->command = (char *)realloc(box->command, box->size + 1);
+    }
+    memmove(&box->command[box->x + 1],
+            &box->command[box->x], (box->size - box->x));
+
+    box->command[box->x] = c;
+    box->x++;
+    box->size++;
+}
+
+static void widget_ibox_del_char(struct input_box *box)
+{
+    if (box->x < 1)
+        return;
+    if (box->size > 1)
+        box->size--;
+    else
+        return;
+
+    memcpy(&box->command[box->x - 1], &box->command[box->x], box->size - box->x);
+
+    box->command = (char *)realloc(box->command, box->size);
+
+    if (box->x)
+        box->x--;
+    box->command[box->size - 1] = 0;
+}
diff --git a/neercs/old/widgets.h b/neercs/old/widgets.h
new file mode 100644
index 0000000..b8e045d
--- /dev/null
+++ b/neercs/old/widgets.h
@@ -0,0 +1,47 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2009-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <caca.h>
+
+
+enum input_box_code
+{
+    INPUT_BOX_ESC,
+    INPUT_BOX_RET,
+    INPUT_BOX_NOTHING,
+};
+
+struct input_box
+{
+    caca_canvas_t *cv;
+    int x, y;
+    int w, h;
+    int size;
+    char *command;
+    char *output_err;
+    char *output_res;
+};
+
+struct input_box *widget_ibox_init(caca_canvas_t * cv, int w, int h);
+int widget_ibox_draw(struct input_box *box);
+int widget_ibox_handle_key(struct input_box *box, unsigned int c);
+char* widget_ibox_get_text(struct input_box *box);
+void widget_ibox_destroy(struct input_box *box);
+void widget_ibox_set_error(struct input_box *box, char *err);
+void widget_ibox_set_msg(struct input_box *box, char *msg);
diff --git a/neercs/old/wm.c b/neercs/old/wm.c
new file mode 100644
index 0000000..006192a
--- /dev/null
+++ b/neercs/old/wm.c
@@ -0,0 +1,513 @@
+/*
+ *  neercs        console-based window manager
+ *  Copyright (c) 2006-2010 Sam Hocevar <sam@hocevar.net>
+ *                2008-2010 Jean-Yves Lamoureux <jylam@lnxscene.org>
+ *                All Rights Reserved
+ *
+ *  This program is free software. It comes without any warranty, to
+ *  the extent permitted by applicable law. You can redistribute it
+ *  and/or modify it under the terms of the Do What The Fuck You Want
+ *  To Public License, Version 2, as published by Sam Hocevar. See
+ *  http://sam.zoy.org/wtfpl/COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <caca.h>
+
+#include "neercs.h"
+
+
+void resize_screen(struct screen *s, int w, int h)
+{
+    caca_canvas_t *old, *new;
+
+    if (w == s->w && h == s->h)
+        return;
+    if (w <= 0 || h <= 0)
+        return;
+
+    s->changed = 1;
+
+    s->w = w;
+    s->h = h;
+
+    /*
+     * caca_set_canvas_boundaries() is bugged as hell, so let's resize it by
+     * hands
+     */
+    old = s->cv;
+    new = caca_create_canvas(w, h);
+    caca_blit(new, 0, 0, old, NULL);
+    s->cv = new;
+    caca_gotoxy(new, caca_get_cursor_x(old), caca_get_cursor_y(old));
+    caca_free_canvas(old);
+    set_tty_size(s->fd, w, h);
+
+    s->orig_w = s->w;
+    s->orig_h = s->h;
+    s->orig_x = s->x;
+    s->orig_y = s->y;
+}
+
+void update_windows_props(struct screen_list *screen_list)
+{
+    debug("%s, %d screens, type %d\n", __FUNCTION__, screen_list->count,
+          screen_list->wm_type);
+
+    if (!screen_list->count)
+        return;
+
+    switch (screen_list->wm_type)
+    {
+    case WM_CARD:
+        update_windows_props_cards(screen_list);
+        break;
+    case WM_HSPLIT:
+        update_windows_props_hsplit(screen_list);
+        break;
+    case WM_VSPLIT:
+        update_windows_props_vsplit(screen_list);
+        break;
+    case WM_FULL:
+    default:
+        update_windows_props_full(screen_list);
+        break;
+    }
+}
+
+void update_windows_props_hsplit(struct screen_list *screen_list)
+{
+    int i;
+    int w =
+        (screen_list->width / screen_list->count) -
+        (screen_list->border_size * 2);
+    int h = screen_list->height - (screen_list->border_size * 2);
+
+    for (i = 0; i < screen_list->count; i++)
+    {
+        screen_list->screen[i]->x = (i * w) + screen_list->border_size;
+        screen_list->screen[i]->y = screen_list->border_size;
+        screen_list->screen[i]->visible = 1;
+        if (i != screen_list->count - 1)
+        {
+            resize_screen(screen_list->screen[i], w - 1, h);
+        }
+        else
+        {
+            resize_screen(screen_list->screen[i],
+                          screen_list->width - i * w - 2, h);
+        }
+    }
+}
+
+void update_windows_props_vsplit(struct screen_list *screen_list)
+{
+    int i;
+    int w = screen_list->width - (screen_list->border_size * 2);
+    int h = (screen_list->height) / screen_list->count;
+
+    for (i = 0; i < screen_list->count; i++)
+    {
+        screen_list->screen[i]->x = screen_list->border_size;
+        screen_list->screen[i]->y = (i * h) + (screen_list->border_size);
+        screen_list->screen[i]->visible = 1;
+        if (i != screen_list->count - 1)
+        {
+            resize_screen(screen_list->screen[i], w,
+                          h - (screen_list->border_size * 2));
+        }
+        else
+        {
+            resize_screen(screen_list->screen[i],
+                          w,
+                          screen_list->height - i * h -
+                          (screen_list->border_size * 2));
+        }
+    }
+}
+
+
+void update_windows_props_full(struct screen_list *screen_list)
+{
+    int i;
+    int w = screen_list->width - (screen_list->border_size * 2);
+    int h = screen_list->height - (screen_list->border_size * 2);
+
+    for (i = 0; i < screen_list->count; i++)
+    {
+        screen_list->screen[i]->visible = 0;
+        screen_list->screen[i]->x = screen_list->border_size;
+        screen_list->screen[i]->y = screen_list->border_size;
+
+        resize_screen(screen_list->screen[i], w, h);
+    }
+    screen_list->screen[screen_list->pty]->visible = 1;
+}
+
+
+void update_windows_props_cards(struct screen_list *screen_list)
+{
+    int i;
+    int w = (screen_list->width - screen_list->count * 3) + 1;
+    int h = (screen_list->height - screen_list->count) - 1;
+    int x = 1;
+    int y = screen_list->count;
+
+    for (i = 0; i < screen_list->count; i++)
+    {
+        screen_list->screen[i]->visible = 1;
+        screen_list->screen[i]->x = x;
+        screen_list->screen[i]->y = y;
+
+        resize_screen(screen_list->screen[i], w, h);
+        x += 3;
+        y--;
+    }
+}
+
+/* Window managers refresh */
+
+void wm_refresh(struct screen_list *screen_list)
+{
+    /* FIXME : move set_color to a relevant place */
+    caca_set_color_ansi(screen_list->cv, CACA_LIGHTRED, CACA_BLACK);
+
+    switch (screen_list->wm_type)
+    {
+    case WM_CARD:
+        wm_refresh_card(screen_list);
+        break;
+    case WM_HSPLIT:
+        wm_refresh_hsplit(screen_list);
+        break;
+    case WM_VSPLIT:
+        wm_refresh_hsplit(screen_list);
+        break;
+    case WM_FULL:
+    default:
+        wm_refresh_cube(screen_list);
+        break;
+    }
+}
+
+static void wm_bell(struct screen_list *screen_list)
+{
+    if (screen_list->screen[screen_list->pty]->bell)
+    {
+        caca_set_color_ansi(screen_list->cv, CACA_RED, CACA_BLACK);
+        screen_list->in_bell--;
+        screen_list->force_refresh = 1;
+        if (!screen_list->in_bell)
+        {
+            screen_list->was_in_bell = 1;
+            screen_list->screen[screen_list->pty]->bell = 0;
+        }
+    }
+    else
+    {
+        if (screen_list->was_in_bell)
+        {
+            screen_list->screen[screen_list->pty]->bell = 0;
+            screen_list->force_refresh = 1;
+            screen_list->was_in_bell = 0;
+            screen_list->changed = 1;
+        }
+        caca_set_color_ansi(screen_list->cv, CACA_LIGHTGREEN, CACA_BLACK);
+    }
+}
+
+static void wm_box(struct screen_list *screen_list, int pty)
+{
+    if (!screen_list->screen[pty]->changed && !screen_list->changed)
+        return;
+
+    if (!screen_list->border_size)
+        return;
+
+    /* Color determined by wm_bell() */
+    caca_draw_cp437_box(screen_list->cv,
+                        screen_list->screen[pty]->x - 1,
+                        screen_list->screen[pty]->y - 1,
+                        screen_list->screen[pty]->w + 2,
+                        screen_list->screen[pty]->h + 2);
+
+    if (screen_list->screen[pty]->title)
+    {
+        caca_printf(screen_list->cv,
+                    screen_list->screen[pty]->x,
+                    screen_list->screen[pty]->y - 1,
+                    " %.*s ",
+                    screen_list->screen[pty]->w - 3,
+                    screen_list->screen[pty]->title);
+    }
+}
+
+static void wm_blit_current_screen(struct screen_list *screen_list)
+{
+    if (screen_list->screen[screen_list->pty]->changed || screen_list->changed)
+        caca_blit(screen_list->cv,
+                  screen_list->screen[screen_list->pty]->x,
+                  screen_list->screen[screen_list->pty]->y,
+                  screen_list->screen[screen_list->pty]->cv, NULL);
+}
+
+void wm_refresh_card(struct screen_list *screen_list)
+{
+    int i;
+
+    for (i = screen_list->count - 1; i >= 0; i--)
+    {
+        if (i != screen_list->pty && screen_list->screen[i]->visible &&
+            (screen_list->screen[i]->changed || screen_list->changed))
+        {
+            caca_blit(screen_list->cv,
+                      screen_list->screen[i]->x,
+                      screen_list->screen[i]->y,
+                      screen_list->screen[i]->cv, NULL);
+
+            wm_box(screen_list, i);
+        }
+    }
+
+    /* Force 'changed' to force redraw */
+    screen_list->screen[screen_list->pty]->changed = 1;
+    wm_blit_current_screen(screen_list);
+    wm_bell(screen_list);
+    wm_box(screen_list, screen_list->pty);
+}
+
+void wm_refresh_full(struct screen_list *screen_list)
+{
+    wm_blit_current_screen(screen_list);
+    wm_bell(screen_list);
+    wm_box(screen_list, screen_list->pty);
+}
+
+void wm_refresh_vsplit(struct screen_list *screen_list)
+{
+    int i;
+
+    for (i = screen_list->count - 1; i >= 0; i--)
+    {
+        if (i != screen_list->pty && screen_list->screen[i]->visible &&
+            (screen_list->screen[i]->changed || screen_list->changed))
+        {
+            caca_blit(screen_list->cv,
+                      screen_list->screen[i]->x,
+                      screen_list->screen[i]->y,
+                      screen_list->screen[i]->cv, NULL);
+
+            wm_box(screen_list, i);
+        }
+    }
+
+    wm_blit_current_screen(screen_list);
+    wm_bell(screen_list);
+    wm_box(screen_list, screen_list->pty);
+}
+
+void wm_refresh_hsplit(struct screen_list *screen_list)
+{
+    int i;
+
+    for (i = screen_list->count - 1; i >= 0; i--)
+    {
+        if (i != screen_list->pty && screen_list->screen[i]->visible &&
+            (screen_list->screen[i]->changed || screen_list->changed))
+        {
+            caca_blit(screen_list->cv,
+                      screen_list->screen[i]->x,
+                      screen_list->screen[i]->y,
+                      screen_list->screen[i]->cv, NULL);
+
+            wm_box(screen_list, i);
+        }
+    }
+
+    wm_blit_current_screen(screen_list);
+    wm_bell(screen_list);
+    wm_box(screen_list, screen_list->pty);
+}
+
+
+static float
+get_direction(float p1x, float p1y, float p2x, float p2y, float p3x, float p3y)
+{
+    float d1x, d1y, d2x, d2y;
+
+    d1x = p3x - p1x;
+    d1y = p3y - p1y;
+    d2x = p3x - p2x;
+    d2y = p3y - p2y;
+    return (d1x * d2y) - (d1y * d2x);
+}
+
+
+/* 3D Cube. Yeah I know, it's a mess. Just look anywhere else. */
+static void draw_face(caca_canvas_t * cv,
+                      int p1x, int p1y,
+                      int p2x, int p2y,
+                      int p3x, int p3y,
+                      int p4x, int p4y, caca_canvas_t * tex,
+                      int color, int borders)
+{
+    if (get_direction(p1x, p1y, p2x, p2y, p3x, p3y) >= 0)
+    {
+        int coords[6];
+        float uv[6];
+        coords[0] = p1x;
+        coords[1] = p1y;
+        coords[2] = p2x;
+        coords[3] = p2y;
+        coords[4] = p3x;
+        coords[5] = p3y;
+        uv[0] = 1;
+        uv[1] = 1;
+        uv[2] = 0;
+        uv[3] = 1;
+        uv[4] = 0;
+        uv[5] = 0;
+        caca_fill_triangle_textured(cv, coords, tex, uv);
+        coords[0] = p1x;
+        coords[1] = p1y;
+        coords[2] = p3x;
+        coords[3] = p3y;
+        coords[4] = p4x;
+        coords[5] = p4y;
+        uv[0] = 1;
+        uv[1] = 1;
+        uv[2] = 0;
+        uv[3] = 0;
+        uv[4] = 1;
+        uv[5] = 0;
+        caca_fill_triangle_textured(cv, coords, tex, uv);
+        caca_set_color_ansi(cv, color, CACA_BLACK);
+        if (borders)
+        {
+            caca_draw_thin_line(cv, p1x, p1y, p2x, p2y);
+            caca_draw_thin_line(cv, p2x, p2y, p3x, p3y);
+            caca_draw_thin_line(cv, p3x, p3y, p4x, p4y);
+            caca_draw_thin_line(cv, p4x, p4y, p1x, p1y);
+        }
+    }
+}
+
+
+void wm_refresh_cube(struct screen_list *screen_list)
+{
+    int i;
+
+    if (!screen_list->cube.in_switch || !screen_list->eyecandy)
+    {
+        wm_refresh_full(screen_list);
+        // screen_list->force_refresh = 0;
+    }
+    else
+    {
+        long long unsigned int cur_time = get_us() - screen_list->last_switch;
+
+        if (cur_time >= screen_list->cube.duration || screen_list->count == 1)
+        {
+            screen_list->changed = 1;
+            screen_list->force_refresh = 1;
+            screen_list->cube.in_switch = 0;
+        }
+        else
+        {
+            float cube[12][3] = {
+                {-1, -1, 1},
+                {1, -1, 1},
+                {1, 1, 1},
+                {-1, 1, 1},
+
+                {1, -1, 1},
+                {1, -1, -1},
+                {1, 1, -1},
+                {1, 1, 1},
+
+                {-1, -1, -1},
+                {-1, -1, 1},
+                {-1, 1, 1},
+                {-1, 1, -1},
+            };
+
+            float cube_transformed[12][3];
+            float cube_projected[12][2];
+            float fov = 0.5f;
+            float angle =
+                90.0f * ((float)cur_time / (float)screen_list->cube.duration);
+
+            angle *= (M_PI / 180.0f);
+
+            if (screen_list->cube.side == 1)
+                angle = -angle;
+
+            float sina = sin(angle);
+            float cosa = cos(angle);
+
+            for (i = 0; i < 12; i++)
+            {
+                cube_transformed[i][2] = cube[i][2] * cosa - cube[i][0] * sina;
+                cube_transformed[i][0] = cube[i][2] * sina + cube[i][0] * cosa;
+                cube_transformed[i][1] = cube[i][1];
+
+                cube_transformed[i][2] -= 3;
+
+                cube_projected[i][0] =
+                    cube_transformed[i][0] / (cube_transformed[i][2] * fov);
+                cube_projected[i][1] =
+                    cube_transformed[i][1] / (cube_transformed[i][2] * fov);
+
+                cube_projected[i][0] /= 2.0f;
+                cube_projected[i][1] /= 2.0f;
+                cube_projected[i][0] += 0.5f;
+                cube_projected[i][1] += 0.5f;
+
+                cube_projected[i][0] *= screen_list->width;
+                cube_projected[i][1] *= screen_list->height;
+            }
+
+            caca_set_color_ansi(screen_list->cv, CACA_WHITE, CACA_BLACK);
+            caca_clear_canvas(screen_list->cv);
+
+            caca_canvas_t *first =
+                screen_list->screen[screen_list->prevpty]->cv;
+            caca_canvas_t *second = screen_list->screen[screen_list->pty]->cv;
+
+            draw_face(screen_list->cv,
+                      cube_projected[0][0], cube_projected[0][1],
+                      cube_projected[1][0], cube_projected[1][1],
+                      cube_projected[2][0], cube_projected[2][1],
+                      cube_projected[3][0], cube_projected[3][1],
+                      first, CACA_LIGHTGREEN, screen_list->border_size);
+
+
+            if (screen_list->cube.side)
+            {
+                draw_face(screen_list->cv,
+                          cube_projected[4][0], cube_projected[4][1],
+                          cube_projected[5][0], cube_projected[5][1],
+                          cube_projected[6][0], cube_projected[6][1],
+                          cube_projected[7][0], cube_projected[7][1],
+                          second, CACA_LIGHTGREEN, screen_list->border_size);
+            }
+            else
+            {
+                draw_face(screen_list->cv,
+                          cube_projected[8][0], cube_projected[8][1],
+                          cube_projected[9][0], cube_projected[9][1],
+                          cube_projected[10][0], cube_projected[10][1],
+                          cube_projected[11][0], cube_projected[11][1],
+                          second, CACA_LIGHTGREEN, screen_list->border_size);
+            }
+
+            screen_list->changed = 1;
+            screen_list->force_refresh = 1;
+            screen_list->cube.in_switch = 1;
+        }
+    }
+}