diff --git a/inc/common/macro.h b/inc/common/macro.h
index c585059c7ad39800c1fde456f2f4a517eb57217f..ff1accded7f4f0f320713404dd4a457b2d10e226 100644
--- a/inc/common/macro.h
+++ b/inc/common/macro.h
@@ -174,3 +174,20 @@ typedef volatile enum {
 #define STR_NMATCH(str1, str2, n)       (! strncasecmp(str1, str2, n))
 
 #define sqlite3_column_chars BRACKETS_THAT(const char *) sqlite3_column_text
+
+#define GET_VA_COUNT(...)   PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
+#define PP_NARG_(...)       PP_ARG_N(__VA_ARGS__)
+#define PP_ARG_N( _1, _2, _3, _4, _5, _6, _7, _8, _9,_10,   \
+                  _11,_12,_13,_14,_15,_16,_17,_18,_19,_20,  \
+                  _21,_22,_23,_24,_25,_26,_27,_28,_29,_30,  \
+                  _31,_32,_33,_34,_35,_36,_37,_38,_39,_40,  \
+                  _41,_42,_43,_44,_45,_46,_47,_48,_49,_50,  \
+                  _51,_52,_53,_54,_55,_56,_57,_58,_59,_60,  \
+                  _61,_62,_63,N,...) N
+#define PP_RSEQ_N() 63,62,61,60,                   \
+                    59,58,57,56,55,54,53,52,51,50, \
+                    49,48,47,46,45,44,43,42,41,40, \
+                    39,38,37,36,35,34,33,32,31,30, \
+                    29,28,27,26,25,24,23,22,21,20, \
+                    19,18,17,16,15,14,13,12,11,10, \
+                    9,8,7,6,5,4,3,2,1,0
diff --git a/inc/common/queue.h b/inc/common/queue.h
index 5d5e5115f2658086054e999a6bab423f4226b1ba..0779f98eaa4db683325b41fe3ed635ca5e59e81e 100644
--- a/inc/common/queue.h
+++ b/inc/common/queue.h
@@ -3,13 +3,38 @@
 #include <pthread.h>
 #include <common/common.h>
 
+enum {
+    _LKT_PLAY_STOP   = 0,
+    _LKT_PLAY_PLAY   = 1,
+    _LKT_PLAY_PAUSE  = 2,
+    _LKT_PLAY_TOGGLE = 3,
+};
+
+#define LKT_PLAY_STOP   ((void *) (size_t) _LKT_PLAY_STOP)
+#define LKT_PLAY_PLAY   ((void *) (size_t) _LKT_PLAY_PLAY)
+#define LKT_PLAY_PAUSE  ((void *) (size_t) _LKT_PLAY_PAUSE)
+#define LKT_PLAY_TOGGLE ((void *) (size_t) _LKT_PLAY_TOGGLE)
+
 enum lkt_event_type {
-    lkt_event_null      = 0,            /* NULL         */
-    lkt_event_play_pos  = (1 << 1),     /* size_t       */
-    lkt_event_play_file = (1 << 2),     /* const char*  */
+    lkt_event_null          = 0,        // NULL
+    lkt_event_play_pos      = (1 << 1), // size_t
+    lkt_event_play_file     = (1 << 2), // XXX: UNUSED //
+    lkt_event_play_next     = (1 << 3), // NULL
+    lkt_event_play_prev     = (1 << 4), // NULL
+    lkt_event_play_toggle   = (1 << 5), // size_t, `LKT_PLAY_.*`
+    lkt_event_prop_vol      = (1 << 6), // size_t
+    lkt_event_prop_dur      = (1 << 7), // size_t
+    lkt_event_prop_time     = (1 << 8), // size_t
+    lkt_event_skip_current  = (1 << 9), // NULL
 };
 
-#define lkt_event_play (lkt_event_play_pos | lkt_event_play_file)
+#define lkt_event_play ( lkt_event_play_pos | lkt_event_play_file |     \
+                         lkt_event_play_next | lkt_event_play_prev |    \
+                         lkt_event_play_toggle | lkt_event_skip_current \
+                       )
+#define lkt_event_prop ( lkt_event_prop_vol | lkt_event_prop_dur |      \
+                         lkt_event_prop_time                            \
+                       )
 
 typedef struct {
     unsigned int type;
diff --git a/inc/lektor/commands.h b/inc/lektor/commands.h
index dae78100702bc29dd707a051f5a8bab8b611ce01..34201ae7f36b9bc65a53827a0e52e73b532cdb1d 100644
--- a/inc/lektor/commands.h
+++ b/inc/lektor/commands.h
@@ -2,7 +2,6 @@
 
 #include <common/common.h>
 #include <lektor/net.h>
-#include <lektor/window.h>
 #include <lektor/database.h>
 
 #include <stdbool.h>
@@ -19,37 +18,35 @@ bool command_currentsong(struct lkt_state *srv, size_t c);
 bool command_status     (struct lkt_state *srv, size_t c);
 
 /* Controlling playback */
-bool command_next    (volatile sqlite3 *db, struct lkt_win *win,                                   mpd_idle_flag *watch_mask_ptr);
-bool command_pause   (volatile sqlite3 *db, struct lkt_win *win,                                   mpd_idle_flag *watch_mask_ptr);
-bool command_previous(volatile sqlite3 *db, struct lkt_win *win,                                   mpd_idle_flag *watch_mask_ptr);
-bool command_play    (volatile sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr);
-bool command_stop    (volatile sqlite3 *db, struct lkt_win *win,                                   mpd_idle_flag *watch_mask_ptr);
+bool command_next    (struct lkt_state *srv);
+bool command_pause   (struct lkt_state *srv);
+bool command_previous(struct lkt_state *srv);
+bool command_play    (struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX]);
+bool command_stop    (struct lkt_state *srv);
 
-bool command_set_pos(volatile sqlite3 *db, struct lkt_win *win, mpd_idle_flag *watch_mask_ptr, int index);
+bool command_set_pos(struct lkt_state *srv, int index);
 
 /* The queue */
-bool command_add    (volatile sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr,
-                     int priority);
-bool command_addid  (volatile sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr);
-bool command_del    (volatile sqlite3 *db, struct lkt_win *win, char *pos_range,                  mpd_idle_flag *watch_mask_ptr);
-bool command_delid  (volatile sqlite3 *db, struct lkt_win *win, char *id,                         mpd_idle_flag *watch_mask_ptr);
-bool command_clear  (volatile sqlite3 *db,                                                        mpd_idle_flag *watch_mask_ptr);
-bool command_crop   (volatile sqlite3 *db,                                                        mpd_idle_flag *watch_mask_ptr);
-bool command_move   (volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX],                      mpd_idle_flag *watch_mask_ptr);
-bool command_shuffle(volatile sqlite3 *db,                                                        mpd_idle_flag *watch_mask_ptr);
-bool command_playid (volatile sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr);
-bool command_dump   (volatile sqlite3 *db,                      char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr);
+bool command_add    (struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX], int priority);
+bool command_addid  (struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX]);
+bool command_delid  (struct lkt_state *srv, char *id);
+bool command_clear  (struct lkt_state *srv);
+bool command_crop   (struct lkt_state *srv);
+bool command_move   (struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX]);
+bool command_shuffle(struct lkt_state *srv);
+bool command_playid (struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX]);
+bool command_dump   (struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX]);
 
 bool command_queue_list(struct lkt_state *srv, size_t c, char *args[LKT_MESSAGE_ARGS_MAX]);
 
 /* The playlists */
-bool command_plt_create(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr);
-bool command_plt_remove(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr);
-bool command_plt_clear (volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr);
-bool command_plt_rename(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr);
-bool command_plt_export(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr);
-bool command_plt_import(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr);
-bool command_plt_add   (volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr);
+bool command_plt_create(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX]);
+bool command_plt_remove(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX]);
+bool command_plt_clear (struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX]);
+bool command_plt_rename(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX]);
+bool command_plt_export(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX]);
+bool command_plt_import(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX]);
+bool command_plt_add   (struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX]);
 
 /* The help */
 bool command_help(struct lkt_state *srv, size_t c);
diff --git a/inc/lektor/config.def b/inc/lektor/config.def
index fc0ba35475ef56cb60b14923504ddbc9bd6b09a4..001f44d3d611e4baa975dcac7b2532f0ff088b9a 100644
--- a/inc/lektor/config.def
+++ b/inc/lektor/config.def
@@ -11,8 +11,7 @@ value("kara_dir",       "/home/kara")
 value("db_path",        "/home/kara/kara.db")
 
 section("repo")
-value_opt("path",       "STATIC")
-value("load_function",  "load_repo_https")
+value("module",         "repo")
 value("name",           "Kurisu")
 value("url",            "https://kurisu.iiens.net")
 value("json",           "https://kurisu.iiens.net/api")
@@ -20,8 +19,7 @@ value("id_json",        "https://kurisu.iiens.net/api?id=%ld")
 value("id_kara",        "https://kurisu.iiens.net/download.php?id=%ld")
 
 section("player")
-value_opt("path",       "STATIC")
-value("load_function",  "load_sdl2")
+value("module",         "sdl2")
 value("autoclear",      "true")
 value("def_random",     "false")
 value("def_consume",    "false")
diff --git a/inc/lektor/module/module_sdl2.h b/inc/lektor/module/module_sdl2.h
deleted file mode 100644
index 9a3b79170c97e1b3ed5c15628637a4189790f402..0000000000000000000000000000000000000000
--- a/inc/lektor/module/module_sdl2.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#pragma once
-
-#include <stdbool.h>
-#include <sqlite3.h>
-#include <lektor/window.h>
-
-#if defined(_STATIC_MODULES)
-/* The only function with a setted filename */
-int load_sdl2(void *mod, struct lkt_state *srv, void *handle);
-#endif
-
-/* Below there are needed functions for a window module.
- * Names are not fixed but they follow a convention (to get a code easy
- * to read). They should not be used in lektor! They will be loaded into
- * the struct lkt_win by the module_set_function.
- */
-bool module_sdl2_new(struct lkt_win *const win);
-void module_sdl2_close(struct lkt_win *const win);
-void module_sdl2_free(struct lkt_win *const win);
-
-bool module_sdl2_toggle_pause(struct lkt_win *const win);
-bool module_sdl2_load_file(struct lkt_win *const win, const char *filepath);
-bool module_sdl2_set_volume(struct lkt_win *const win, int vol);
-
-bool module_sdl2_get_duration(struct lkt_win *const win, int *dur_sec);
-bool module_sdl2_get_elapsed(struct lkt_win *const win, int *elapsed_sec);
-
-bool module_sdl2_handle_events(struct lkt_win *const win, volatile sqlite3 *db, mpd_idle_flag *mpd_idle_events);
diff --git a/inc/lektor/module/module_x11.h b/inc/lektor/module/module_x11.h
deleted file mode 100644
index 14c9fb7e9bdd448a3a39dd49ca1c341836128723..0000000000000000000000000000000000000000
--- a/inc/lektor/module/module_x11.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#pragma once
-
-#include <stdbool.h>
-#include <sqlite3.h>
-#include <lektor/window.h>
-
-#if defined(_STATIC_MODULES)
-/* The only function with a setted filename */
-int load_x11(void *mod, struct lkt_state *srv, void *handle);
-#endif
-
-/* Below there are needed functions for a window module.
- * Names are not fixed but they follow a convention (to get a code easy
- * to read). They should not be used in lektor! They will be loaded into
- * the struct lkt_win by the module_set_function.
- */
-bool module_x11_new(struct lkt_win *const win);
-void module_x11_close(struct lkt_win *const win);
-void module_x11_free(struct lkt_win *const win);
-void module_x11_attach(struct lkt_win *const win, void *server);
-
-bool module_x11_toggle_pause(struct lkt_win *const win);
-bool module_x11_load_file(struct lkt_win *const win, const char *filepath);
-bool module_x11_set_volume(struct lkt_win *const win, int vol);
-
-bool module_x11_get_duration(struct lkt_win *const win, int *dur_sec);
-bool module_x11_get_elapsed(struct lkt_win *const win, int *elapsed_sec);
-
-bool module_x11_handle_events(struct lkt_win *const win, volatile sqlite3 *db, mpd_idle_flag *mpd_idle_events);
diff --git a/inc/lektor/module/mpv.h b/inc/lektor/module/mpv.h
index ab28af195e1430dccaaa06cde9745d47f83f17c5..48ed12ce2ca9db57a57db41cc72205c6a6a41a3d 100644
--- a/inc/lektor/module/mpv.h
+++ b/inc/lektor/module/mpv.h
@@ -1,9 +1,10 @@
 #pragma once
 
-#include <sqlite3.h>
 #include <mpv/client.h>
-#include <lektor/net.h>
 #include <common/common.h>
+#include <common/queue.h>
+#include <lektor/reg.h>
+#include <sqlite3.h>
 
 void lmpv_free(mpv_handle **ctx);
 mpv_handle *lmpv_new(unsigned long int wid, volatile sqlite3 *db);
@@ -13,5 +14,6 @@ mpv_handle *lmpv_prepare(volatile sqlite3 *db);
 int lmpv_set_volume(mpv_handle *ctx, int vol);
 int lmpv_load_file(mpv_handle *ctx, const char *file);
 int lmpv_toggle_pause(mpv_handle *ctx);
-int lmpv_handle(struct lkt_win *win, mpv_handle *ctx, volatile sqlite3 *db, mpd_idle_flag *mpd_idle_flag,
-                volatile int *time_pos, volatile int *time_duration);
+int lmpv_handle(struct lkt_module *mod, mpv_handle *ctx, struct queue *queue,
+                volatile int *time_pos, volatile int *time_duration,
+                volatile int *state);
diff --git a/inc/lektor/net.h b/inc/lektor/net.h
index e9985dfc49d267bc0ff314e1f099954e08da16d8..c17fc4657f682d1b737b57826bd5949bb72e7e28 100644
--- a/inc/lektor/net.h
+++ b/inc/lektor/net.h
@@ -4,8 +4,8 @@
 #include <common/queue.h>
 #include <lektor/mkv.h>
 #include <lektor/config.h>
-#include <lektor/window.h>
 #include <lektor/thread.h>
+#include <lektor/reg.h>
 #include <lektor/uri.h>
 
 #include <pthread.h>
@@ -43,7 +43,7 @@ struct lkt_repo {
 };
 
 /* Load the repo as a module */
-int load_repo_https(void *mod, struct lkt_state *srv, void *handle);
+int load_repo_https(va_list *);
 
 /* Download stuff */
 int repo_get_id          (struct lkt_repo *const repo, const uint64_t id, struct kara_metadata *mdt);
@@ -82,12 +82,10 @@ struct lkt_state {
     mpd_idle_flag mpd_idle_events;
     pthread_mutex_t lock;
 
-    struct lkt_repo repo;
-    struct lkt_win win;
+    struct lkt_module window_mod;
+    struct lkt_module repo_mod;
 };
 
-void lkt_set_event_available(struct lkt_state *srv, enum lkt_event_type type);
-
 /* Send a message to the connected client. */
 void lkt_state_send(struct lkt_state *srv, size_t c, struct lkt_message *msg);
 
@@ -99,7 +97,7 @@ void lkt_set_continuation(struct lkt_state *srv, size_t c, int i);
 
 /* Get the mask to watch for events for a given client, to be used with the `idle` command.
  * Return a pointer to the client's mask */
-int lkt_client_get_mask(struct lkt_state *srv, size_t c);
+int  lkt_client_get_mask(struct lkt_state *srv, size_t c);
 void lkt_client_add_mask(struct lkt_state *srv, size_t c, mpd_idle_flag add);
 void lkt_client_clear_mask(struct lkt_state *srv, size_t c);
 
diff --git a/inc/lektor/reg.h b/inc/lektor/reg.h
index 50049e703f5da7e27fd324c65586af08b08a0ff3..ba8a6021bd4400bccfc1e833e11f7bdc7feace54 100644
--- a/inc/lektor/reg.h
+++ b/inc/lektor/reg.h
@@ -1,30 +1,64 @@
-#pragma once
+#if ! defined(__REG_H__)
+#define __REG_H__
 
 struct lkt_state;
 
+#include <common/macro.h>
+#include <stdarg.h>
+
+typedef int (*reg_func)(va_list *);
+
 /* Store functions with a name, so that all the lib will have acces to it
    with a name that can be generated or red from a config file. */
 struct module_reg {
     const char *name;
-    void (*func)(void);
+    union {
+        reg_func func;
+        struct module_reg **obj; /* First item of the array */
+    };
+};
+
+/* A module */
+struct lkt_module {
+    struct module_reg *reg;
+    void *handle;
+    void *data;
 };
 
-extern struct module_reg *reg;
+#define REG_EXPORT_NAME     "__reg__"
+#define REG_BEGIN(reg)      struct module_reg reg[] = {
+#define REG_ADD(f)          { .name = #f,   .func = f    },
+#define REG_ADD_NAMED(n, f) { .name = n,    .func = f    },
+#define REG_REGISTER(n, s)  { .name = n,    .obj  = &s   },
+#define REG_END()           { .name = NULL, .func = NULL } };
+#define REG_DEFINE(reg)     struct module_reg reg* = NULL;
+
+/* Use only once per .so files or you will have some problems... */
+#if ! defined(_STATIC_MODULES)
+#define REG_EXPORT(__reg)   struct module_reg *__reg__ = __reg;
+#else
+#define REG_EXPORT(__reg)
+#endif
+
+/* Import a reg */
+#define REG_DECLARE(reg)    extern struct module_reg *reg;
+#define REG_IMPORT(reg, as)             \
+    REG_DECLARE(reg)                    \
+    static struct module_reg *as = reg;
 
-#define REG_BEGIN(reg)          struct module_reg reg[] = {
-#define REG_ADD(__f)            { .name = #__f,  .func = (void(*)(void)) __f    },
-#define REG_ADD_NAMED(__n, __f) { .name = __n,   .func = (void(*)(void)) __f    },
-#define REG_END()               { .name = NULL,  .func = NULL                   } };
+/* Call a function from a reg. */
+#define MOD_CALL(module, name, ...)     \
+    reg_call((module).reg, name, 1 + (GET_VA_COUNT(__VA_ARGS__)), &(module).data, __VA_ARGS__)
+int reg_call(struct module_reg *reg, const char *name, int count, ...);
 
-/* If handle is NULL, file is unused and the reg is red. Otherwise,
-   we use dlfcn to search for the symbol which is returned. If *handle
-   is NULL, it will be created by opening the file. */
-void *reg_pick(const char *file, void **handle, const char *symbol);
+/* Import a module, from a file (mod is a filepath) or from the __reg__ in the
+   current file. If the `mod` contains one of the following "/.\'\"\\", it is
+   treated as a file. The function will first try to treat is as a module in the
+   __reg__.
+   Returns 0 on success, something else on error. */
+int reg_import(const char *mod, struct module_reg **ret, void **handle);
 
-/* Set the ref for this .a / .so file */
-void reg_set(struct module_reg *);
+/* Set the __reg__ pointer. */
+void reg_export(struct module_reg *reg);
 
-/* Load a module by its name. Also initialize the mod pointer. No check on data
-   type is done, it is up to the user to check if the structure passed as a
-   `void*` is the right structure. */
-int load_module_by_name(struct lkt_state *srv, const char *name, void *mod);
+#endif /* __REG_H__ */
diff --git a/inc/lektor/window.h b/inc/lektor/window.h
deleted file mode 100644
index 462f9fa7a5fc052fc896c6a7453d57307c6164a2..0000000000000000000000000000000000000000
--- a/inc/lektor/window.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#pragma once
-
-/* The window is a module */
-
-#include <common/common.h>
-#include <stdbool.h>
-#include <sqlite3.h>
-
-typedef void *lkt_win_element_t;    /* The real window struct, an opaque type   */
-struct lkt_state;                   /* Forward definition of the server         */
-
-/* The window with the selected correct functions, this is done because we may
-   need an SDL2, a X11 or a QT window, and may want to select the one to use at
-   run time. */
-struct lkt_win {
-    lkt_win_element_t window;           /* the opaque window type that depend on the module */
-    void *handle;                       /* the libdl handle                                 */
-    struct lkt_state *srv;              /* The server, must be set before the new call      */
-
-    /* Create and free the window */
-    bool (*new)(struct lkt_win *win);   /* Create a window or only the mpv context  */
-    void (*close)(struct lkt_win *win); /* Close the mpv context, not the window    */
-    void (*free)(struct lkt_win *win);  /* Entirelly liberate all the resources     */
-
-    /* Playback control */
-    bool (*toggle_pause)(struct lkt_win *win);
-    bool (*load_file)(struct lkt_win *win, const char *filepath);
-    bool (*set_volume)(struct lkt_win *win, int vol);
-
-    /* Get playback properties */
-    bool (*get_duration)(struct lkt_win *win, int *dur_sec);
-    bool (*get_elapsed)(struct lkt_win *win, int *elapsed_sec);
-
-    /* Handle loop event */
-    bool (*handle_events)(struct lkt_win *win, volatile sqlite3 *db,
-                          mpd_idle_flag *mpd_idle_events);
-};
diff --git a/meson.build b/meson.build
index c5955d01dfd1975683f4823c8836a3f29f837b13..c73a83c2b77a585050199de16d311ac03bd6888f 100644
--- a/meson.build
+++ b/meson.build
@@ -33,9 +33,6 @@ if get_option('static_modules').enabled()
   if get_option('module_sdl').enabled()
     add_global_arguments('-D_STATIC_SDL2', language: 'c')
   endif
-  if get_option('module_x11').enabled()
-    add_global_arguments('-D_STATIC_X11', language: 'c')
-  endif
 endif
 
 ## Module list
@@ -126,20 +123,6 @@ else
   bin_deps = [ declare_dependency( link_with: lib.get_shared_lib(), include_directories: includes) ]
 endif
 
-# X11 window module
-if get_option('module_x11').enabled()
-  assert(dep_x11.found() and dep_mpv.found(), 'Asking to build x11 module, but missing dependencies')
-  lib_mod_x11 = both_libraries ( '_module_x11'
-                               , files(['src/module/module_x11.c', 'src/module/mpv.c'])
-                               , include_directories: includes
-                               , dependencies: [ dep_x11, dep_mpv, bin_deps ]
-                               , install: get_option('static_modules').disabled()
-                               , install_dir: 'lib/lektor' )
-  if get_option('static_modules').enabled()
-    lektor_modules += [ lib_mod_x11.get_static_lib() ]
-  endif
-endif
-
 # SQL2 window module
 if get_option('module_sdl').enabled()
   assert(dep_x11.found() and dep_mpv.found(), 'Asking to build x11 module, but missing dependencies')
diff --git a/meson_options.txt b/meson_options.txt
index ff8b1283e7c64efb6aed784e39ad250c1b6a3ad4..9791739bdcb0f6034c5d537074d5d3adb1d3e768 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -1,7 +1,4 @@
 option('static_modules', type: 'feature', value: 'enabled'
       , description: 'Build modules and link them statically with lektord')
-
 option('module_sdl', type: 'feature', value: 'enabled', description: 'Build the sdl module')
-option('module_x11', type: 'feature', value: 'enabled', description: 'Build the x11 module')
-
 option('static_liblektor', type: 'boolean', value: true, description: 'Link the liblektor statically')
diff --git a/src/commands.c b/src/commands.c
index 5b32c96822f13739745be2b82b5bbba58e135b72..54c7e5b8f45db415cda28b1f05cbbdeb72f50eb3 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -58,7 +58,7 @@ command_update(struct lkt_state *srv, size_t c, char *argv[LKT_MESSAGE_ARGS_MAX]
     RETURN_UNLESS(lkt_client_auth(srv, c, false), "Failed to authentificate user", false);
     srv->mpd_idle_events |= MPD_IDLE_UPDATE;
     srv->mpd_idle_events |= MPD_IDLE_DATABASE;
-    return ! repo_update(&srv->repo);
+    return ! repo_update(srv->repo_mod.data);
 }
 
 static inline void *
@@ -128,16 +128,14 @@ command_status(struct lkt_state *srv, size_t c)
 {
     struct lkt_message *out;
     struct lkt_queue_state queue_state;
-    struct lkt_win *win;
     int elapsed, duration, songid = 0;
     const char *play_state;
 
     RETURN_UNLESS(srv, "Invalid argument", false);
-    win = &srv->win;
     RETURN_UNLESS(database_queue_state(srv->db, &queue_state), "Can't determine playback status", false);
     database_queue_current_kara(srv->db, NULL, &songid);
-    win->get_elapsed(win, &elapsed);
-    win->get_duration(win, &duration);
+    MOD_CALL(srv->window_mod, "get_elapsed", &elapsed);
+    MOD_CALL(srv->window_mod, "get_duration", &duration);
 
     out = lkt_message_new();
     play_state = queue_state.current <= 0
@@ -164,43 +162,48 @@ command_status(struct lkt_state *srv, size_t c)
 }
 
 bool
-command_next(volatile sqlite3 *db, struct lkt_win *win, mpd_idle_flag *watch_mask_ptr)
+command_next(struct lkt_state *srv)
 {
-    *watch_mask_ptr |= MPD_IDLE_PLAYER;
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
     char filepath[PATH_MAX];
-    return database_queue_next(db, filepath) && win->load_file(win, filepath);
+    if (!database_queue_next(srv->db, filepath))
+        return false;
+    return ! MOD_CALL(srv->window_mod, "load", filepath);
 }
 
 bool
-command_pause(volatile sqlite3 *db, struct lkt_win *win, mpd_idle_flag *watch_mask_ptr)
+command_pause(struct lkt_state *srv)
 {
-    *watch_mask_ptr |= MPD_IDLE_PLAYER;
-    return database_queue_toggle_pause(db) && win->toggle_pause(win);
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
+    if (!database_queue_toggle_pause(srv->db))
+        return false;
+    return ! MOD_CALL(srv->window_mod, "toggle", 1);
 }
 
 bool
-command_previous(volatile sqlite3 *db, struct lkt_win *win, mpd_idle_flag *watch_mask_ptr)
+command_previous(struct lkt_state *srv)
 {
-    *watch_mask_ptr |= MPD_IDLE_PLAYER;
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
     char filepath[PATH_MAX];
-    return database_queue_prev(db, filepath) && win->load_file(win, filepath);
+    if (!database_queue_prev(srv->db, filepath))
+        return false;
+    return ! MOD_CALL(srv->window_mod, "load", filepath);
 }
 
 static inline bool
-__play_that_file(volatile sqlite3 *db, struct lkt_win *win, int pos)
+__play_that_file(struct lkt_state *win, int pos)
 {
     char filepath[PATH_MAX];
     RETURN_UNLESS(pos, "Invalid argument", false);
-    RETURN_UNLESS(database_queue_play(db, (int) pos), "DB error", false);
-    RETURN_UNLESS(database_queue_get_current_file(db, filepath), "Can't get current kara", false);
-    RETURN_UNLESS(win->load_file(win, filepath), "Can't load file", false);
+    RETURN_UNLESS(database_queue_play(win->db, (int) pos), "DB error", false);
+    RETURN_UNLESS(database_queue_get_current_file(win->db, filepath), "Can't get current kara", false);
+    RETURN_IF(MOD_CALL(win->window_mod, "load", filepath), "Can't load file", false);
     return true;
 }
 
 bool
-command_play(volatile sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr)
+command_play(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX])
 {
-    *watch_mask_ptr |= MPD_IDLE_PLAYER;
     char *endptr, err;
     long pos = 1;
 
@@ -211,24 +214,24 @@ command_play(volatile sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_A
     }
 
     /* Do the actual job here. */
-    database_queue_stop(db);
-    RETURN_UNLESS(win->new (win), "Can't create window", false);
-    return __play_that_file(db, win, pos);
+    database_queue_stop(srv->db);
+    RETURN_IF(MOD_CALL(srv->window_mod, "new", &srv->queue, srv->db),
+              "Can't create window", false);
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
+    return __play_that_file(srv, pos);
 }
 
 bool
-command_dump(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX],
-             mpd_idle_flag *watch_mask_ptr)
+command_dump(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX])
 {
     RETURN_UNLESS(args[0], "Invalid argument", false);
-    *watch_mask_ptr |= MPD_IDLE_PLAYLIST;
-    return database_queue_dump(db, args[0]);
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
+    return database_queue_dump(srv->db, args[0]);
 }
 
 bool
-command_playid(volatile sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr)
+command_playid(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX])
 {
-    *watch_mask_ptr |= MPD_IDLE_PLAYER;
     char *endptr, err;
     int pos = 0;
     long id;
@@ -239,34 +242,33 @@ command_playid(volatile sqlite3 *db, struct lkt_win *win, char *args[LKT_MESSAGE
     RETURN_IF(err, "STRTOL failed", false);
 
     /* Do the work. */
-    database_queue_stop(db);
-    RETURN_UNLESS(win->new (win), "Can't create window", false);
-    database_queue_seekid(db, (int) id, &pos);
-    return __play_that_file(db, win, pos);
+    database_queue_stop(srv->db);
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
+    RETURN_IF(MOD_CALL(srv->window_mod, "new", &srv->queue, srv->db),
+              "Can't create window", false);
+    database_queue_seekid(srv->db, (int) id, &pos);
+    return __play_that_file(srv, pos);
 }
 
 
 bool
-command_stop(volatile sqlite3 *db, struct lkt_win *win, mpd_idle_flag *watch_mask_ptr)
+command_stop(struct lkt_state *srv)
 {
-    RETURN_UNLESS(database_queue_stop(db), "DB error", false);
-    win->close(win);
-    *watch_mask_ptr |= MPD_IDLE_PLAYER;
+    RETURN_UNLESS(database_queue_stop(srv->db), "DB error", false);
+    MOD_CALL(srv->window_mod, "close", 1);
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
     return true;
 }
 
 bool
-command_add(volatile sqlite3 *db, struct lkt_win *win,
-            char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr,
-            int priority)
+command_add(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX], int priority)
 {
     RETURN_UNLESS(args && args[0], "Invalid argument", false);
-    *watch_mask_ptr |= MPD_IDLE_PLAYLIST;
     struct lkt_uri uri;
     int ret;        /* To be modified according to the command (insert or add) later (TODO) */
-    UNUSED(win);    /* No callbacks to the window for the moment */
     RETURN_UNLESS(lkt_uri_from(&uri, args[0]), "Failed to parse query", false);
-    ret = database_queue_add_uri(db, &uri, priority);
+    ret = database_queue_add_uri(srv->db, &uri, priority);
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
     lkt_uri_free(&uri);
     if (!ret)
         LOG_ERROR("COMMAND", "Failed to add with priority %d in queue", priority);
@@ -274,36 +276,34 @@ command_add(volatile sqlite3 *db, struct lkt_win *win,
 }
 
 bool
-command_addid(volatile sqlite3 *db, struct lkt_win *win,
-              char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr)
+command_addid(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX])
 {
-    UNUSED(win);
     RETURN_UNLESS(args, "Invalid argument", false);
     errno = 0;
     int i;
     struct lkt_uri uri = { .type = uri_id };
     for (i = 0; (uri.id = strtol(args[i], NULL, 0)) && ! errno; ++i)
-        errno |= database_queue_add_id(db, uri.id, 1);
-    *watch_mask_ptr |= MPD_IDLE_PLAYLIST;
+        errno |= database_queue_add_id(srv->db, uri.id, 1);
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
     return ! errno;
 }
 
 inline bool
-command_clear(volatile sqlite3 *db, mpd_idle_flag *watch_mask_ptr)
+command_clear(struct lkt_state *srv)
 {
-    *watch_mask_ptr |= MPD_IDLE_PLAYLIST;
-    return database_queue_clear(db);
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
+    return database_queue_clear(srv->db);
 }
 
 inline bool
-command_crop(volatile sqlite3 *db, mpd_idle_flag *watch_mask_ptr)
+command_crop(struct lkt_state *srv)
 {
-    *watch_mask_ptr |= MPD_IDLE_PLAYLIST;
-    return database_queue_crop(db);
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
+    return database_queue_crop(srv->db);
 }
 
 bool
-command_delid(volatile sqlite3 *db, struct lkt_win *win, char *id_str, mpd_idle_flag *watch_mask_ptr)
+command_delid(struct lkt_state *srv, char *id_str)
 {
     long id;
     char *endptr = NULL, err = 0, filepath[PATH_MAX];
@@ -312,11 +312,11 @@ command_delid(volatile sqlite3 *db, struct lkt_win *win, char *id_str, mpd_idle_
     STRTOL(id, id_str, endptr, err);
     RETURN_IF(err, "STRTOL failed", false);
 
-    database_queue_current_kara(db, NULL, &uri);
+    database_queue_current_kara(srv->db, NULL, &uri);
 
     if (id == (long) uri) {
-        if (database_queue_skip_current(db, filepath)) {
-            if (!win->load_file(win, filepath)) {
+        if (database_queue_skip_current(srv->db, filepath)) {
+            if (MOD_CALL(srv->window_mod, "load", filepath)) {
                 LOG_ERROR("COMMAND", "Failed to skip current kara to delete id %ld", id);
                 return false;
             }
@@ -324,22 +324,21 @@ command_delid(volatile sqlite3 *db, struct lkt_win *win, char *id_str, mpd_idle_
 
         else {
             LOG_WARN("COMMAND", "Failed to skip current kara to delete id %ld, stop playback", id);
-            win->close(win);
+            MOD_CALL(srv->window_mod, "close", 1);
         }
     }
 
-    *watch_mask_ptr |= MPD_IDLE_PLAYER;
-    return database_queue_del_id(db, id);
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
+    return database_queue_del_id(srv->db, id);
 }
 
 bool
-command_move(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr)
+command_move(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX])
 {
     long from, to;
     char *endptr, err;
 
     RETURN_UNLESS(args && args[0] && args[1], "Invalid argument", false);
-    *watch_mask_ptr |= MPD_IDLE_PLAYLIST;
 
     /* First argument: from */
     STRTOL(from, args[0], endptr, err);
@@ -349,7 +348,8 @@ command_move(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_fl
     STRTOL(to, args[1], endptr, err);
     RETURN_IF(err, "STRTOL failed", false);
 
-    return database_queue_move(db, from, to);
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
+    return database_queue_move(srv->db, from, to);
 }
 
 bool
@@ -521,7 +521,6 @@ command_set_playback_option(struct lkt_state *srv, size_t c, enum lkt_playback_o
     UNUSED(c);
     long val;
     char *endptr, ret = false;
-    struct lkt_win *win = &srv->win;
 
     if (args == NULL || args[0] == NULL)
         val = 0;
@@ -552,7 +551,7 @@ command_set_playback_option(struct lkt_state *srv, size_t c, enum lkt_playback_o
     case lkt_playback_option_volume:
         ret = database_config_queue(srv->db, "volume", val);
         LOG_INFO("COMMAND", "Set volume to %ld", val);
-        ret &= win->set_volume(win, val);
+        ret &= ! MOD_CALL(srv->window_mod, "set_volume", val);
         srv->mpd_idle_events |= MPD_IDLE_MIXER;
         break;
     case lkt_playback_option_none:
@@ -567,17 +566,17 @@ command_set_playback_option(struct lkt_state *srv, size_t c, enum lkt_playback_o
 }
 
 bool
-command_set_pos(volatile sqlite3 *db, struct lkt_win *win, mpd_idle_flag *watch_mask_ptr, int index)
+command_set_pos(struct lkt_state *srv, int index)
 {
     char filepath[PATH_MAX];
-    *watch_mask_ptr |= MPD_IDLE_PLAYER;
-    RETURN_UNLESS(database_queue_set_current_index(db, index), "Failed to set position in queue", false);
-    RETURN_UNLESS(database_queue_get_current_file(db, filepath), "Failed to get filename", false);
-    return win->load_file(win, filepath);
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
+    RETURN_UNLESS(database_queue_set_current_index(srv->db, index), "Failed to set position in queue", false);
+    RETURN_UNLESS(database_queue_get_current_file(srv->db, filepath), "Failed to get filename", false);
+    return ! MOD_CALL(srv->window_mod, "load", filepath);
 }
 
 bool
-command_plt_add(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr)
+command_plt_add(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX])
 {
     RETURN_UNLESS(args && args[0], "Invalid argument", false);
 
@@ -585,7 +584,7 @@ command_plt_add(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle
     struct lkt_uri uri;
 
     if (args[1] == NULL)
-        ret = database_plt_create(db, args[0]);
+        ret = database_plt_create(srv->db, args[0]);
 
     else {
         if (!lkt_uri_from(&uri, args[1])) {
@@ -593,7 +592,7 @@ command_plt_add(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle
             goto end_plt_add_uri;
         }
 
-        else if (!database_plt_add_uri(db, args[0], &uri)) {
+        else if (!database_plt_add_uri(srv->db, args[0], &uri)) {
             LOG_ERROR("COMMAND", "Failed to add uri '%s' to playlist", args[1]);
             goto end_plt_add_uri;
         }
@@ -604,89 +603,89 @@ end_plt_add_uri:
     }
 
     if (ret)
-        *watch_mask_ptr |= MPD_IDLE_PLAYLIST;
+        srv->mpd_idle_events |= MPD_IDLE_PLAYER;
 
     return ret;
 }
 
 bool
-command_plt_remove(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr)
+command_plt_remove(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX])
 {
     RETURN_UNLESS(args && args[0], "Invalid argument", false);
     char *endptr, err;
     long pos;
 
     if (args[1] == NULL) {
-        *watch_mask_ptr |= MPD_IDLE_PLAYLIST;
-        return database_plt_remove(db, args[0]);
+        srv->mpd_idle_events |= MPD_IDLE_PLAYLIST;
+        return database_plt_remove(srv->db, args[0]);
     }
 
     STRTOL(pos, args[1], endptr, err);
     RETURN_IF(err, "STRTOL failed", false);
-    *watch_mask_ptr |= MPD_IDLE_PLAYLIST;
-    return database_plt_remove_pos(db, args[0], pos);
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
+    return database_plt_remove_pos(srv->db, args[0], pos);
 }
 
 bool
-command_plt_clear(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr)
+command_plt_clear(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX])
 {
     RETURN_UNLESS(args && args[0], "Invalid argument", false);
-    RETURN_UNLESS(database_plt_clear(db, args[0]), "Failed to clear playlist", false);
-    *watch_mask_ptr |= MPD_IDLE_PLAYLIST;
+    RETURN_UNLESS(database_plt_clear(srv->db, args[0]), "Failed to clear playlist", false);
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
     return true;
 }
 
 bool
-command_plt_rename(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr)
+command_plt_rename(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX])
 {
     RETURN_UNLESS(args && args[0] && args[1], "Invalid argument", false);
-    RETURN_UNLESS(database_plt_rename(db, args[0], args[1]), "Failed to rename playlist", false);
-    *watch_mask_ptr |= MPD_IDLE_PLAYLIST;
+    RETURN_UNLESS(database_plt_rename(srv->db, args[0], args[1]), "Failed to rename playlist", false);
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
     return true;
 }
 
 bool
-command_plt_export(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr)
+command_plt_export(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX])
 {
     RETURN_UNLESS(args && args[0] && args[1], "Invalid argument", false);
-    RETURN_UNLESS(database_attach(db, args[0], args[1]), "Failed to attach database", false);
-    RETURN_UNLESS(database_plt_export(db, args[0]), "Failed to export playlist", false);
-    RETURN_UNLESS(database_detach(db, args[0]), "Failed to detach database", false);
+    RETURN_UNLESS(database_attach(srv->db, args[0], args[1]), "Failed to attach database", false);
+    RETURN_UNLESS(database_plt_export(srv->db, args[0]), "Failed to export playlist", false);
+    RETURN_UNLESS(database_detach(srv->db, args[0]), "Failed to detach database", false);
     LOG_INFO("COMMAND", "Exported playlist %s with path '%s'", args[0], args[1]);
-    *watch_mask_ptr |= MPD_IDLE_PLAYLIST;
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
     return true;
 }
 
 bool
-command_plt_import(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr)
+command_plt_import(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX])
 {
     RETURN_UNLESS(args && args[0] && args[1], "Invalid argument", false);
-    RETURN_UNLESS(database_attach(db, args[0], args[1]), "Failed to attach database", false);
-    RETURN_UNLESS(database_plt_import(db, args[0]), "Failed to import playlist", false);
-    RETURN_UNLESS(database_detach(db, args[0]), "Failed to detach playlist", false);
+    RETURN_UNLESS(database_attach(srv->db, args[0], args[1]), "Failed to attach database", false);
+    RETURN_UNLESS(database_plt_import(srv->db, args[0]), "Failed to import playlist", false);
+    RETURN_UNLESS(database_detach(srv->db, args[0]), "Failed to detach playlist", false);
     LOG_INFO("COMMAND", "Imported playlist %s with path '%s'", args[0], args[1]);
-    *watch_mask_ptr |= MPD_IDLE_PLAYLIST;
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
     return true;
 }
 
 bool
-command_plt_add_uri(volatile sqlite3 *db, char *args[LKT_MESSAGE_ARGS_MAX], mpd_idle_flag *watch_mask_ptr)
+command_plt_add_uri(struct lkt_state *srv, char *args[LKT_MESSAGE_ARGS_MAX])
 {
     RETURN_UNLESS(args && args[0] && args[1], "Invalid argument", false);
     struct lkt_uri uri;
     RETURN_UNLESS(lkt_uri_from(&uri, args[1]), "Failed to parse uri", false);
-    bool ret = database_plt_add_uri(db, args[0], &uri);
+    bool ret = database_plt_add_uri(srv->db, args[0], &uri);
     lkt_uri_free(&uri);
     RETURN_UNLESS(ret, "Failed to add uri to plt", false);
-    *watch_mask_ptr |= MPD_IDLE_PLAYLIST;
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
     return true;
 }
 
 bool
-command_shuffle(volatile sqlite3 *db, mpd_idle_flag *watch_mask_ptr)
+command_shuffle(struct lkt_state *srv)
 {
-    RETURN_UNLESS(database_queue_shuffle(db), "Failed to shuffle", false);
-    *watch_mask_ptr |= MPD_IDLE_PLAYER;
+    RETURN_UNLESS(database_queue_shuffle(srv->db), "Failed to shuffle", false);
+    srv->mpd_idle_events |= MPD_IDLE_PLAYER;
     return true;
 }
 
diff --git a/src/main/server.c b/src/main/server.c
index 0e2f5dedf39d1425fc161d99b9c378eb3742b97f..eb9054adff6f3dca159e2efb1fa555c3a1102274 100644
--- a/src/main/server.c
+++ b/src/main/server.c
@@ -16,30 +16,24 @@
 #include <unistd.h>
 #include <string.h>
 #include <strings.h>
-#include <pwd.h>
 #include <pthread.h>
 
-#ifdef _STATIC_SDL2
-#include <lektor/module/module_sdl2.h>
+REG_DECLARE(repo_reg)
+#if defined (_STATIC_MODULES) && (_STATIC_SDL2)
+REG_DECLARE(sdl2_reg)
 #endif
-#ifdef _STATIC_X11
-#include <lektor/module/module_x11.h>
-#endif
-
-REG_BEGIN(server_reg)
-REG_ADD(load_repo_https)
-#ifdef _STATIC_SDL2
-REG_ADD(load_sdl2)
-#endif
-#ifdef _STATIC_X11
-REG_ADD(load_x11)
-#endif
-REG_END()
 
 int
 main(int argc, char *argv[])
 {
-    struct passwd *pw = getpwuid(getuid());
+    REG_BEGIN(server_reg)
+    REG_ADD(load_repo_https)
+    REG_REGISTER("repo", repo_reg)
+#if defined (_STATIC_MODULES) && (_STATIC_SDL2)
+    REG_REGISTER("sdl2", sdl2_reg)
+#endif
+    REG_END()
+
     char exe[PATH_MAX];
     int autoclear, check_exclusive = 1, opt;
     char *conf_file = safe_zero_malloc(PATH_MAX * sizeof(char));
@@ -66,7 +60,7 @@ main(int argc, char *argv[])
     }
 
 normal_launch:
-    reg_set(server_reg);
+    reg_export(server_reg);
     mthread_init();
     pthread_create(&th, NULL, mthread_main, NULL);
     if (read_self_exe(exe, PATH_MAX))
@@ -121,8 +115,17 @@ normal_launch:
     if (!env_get(LKT_ENV_RESTART) && autoclear)
         database_queue_clear(srv.db);
 
-    RETURN_IF(load_module_by_name(&srv, "player", &srv.win),  "Can't load module player", 3);
-    RETURN_IF(load_module_by_name(&srv, "repo",   &srv.repo), "Can't load module repo", 3);
+    lkt_queue_make_available(&srv.queue, lkt_event_prop);
+    char *module = safe_malloc(sizeof(char) * PATH_MAX);
+    database_config_get_text(srv.db, "player", "module", module, PATH_MAX);
+    reg_import(module, &srv.window_mod.reg, &srv.window_mod.handle);
+    reg_import("repo", &srv.repo_mod.reg, &srv.repo_mod.handle);
+    free(module);
+
+    if (MOD_CALL(srv.repo_mod, "new", &srv, srv.repo_mod.handle))
+        return 100;
+    if (MOD_CALL(srv.window_mod, "new", &srv.queue, srv.db))
+        return 101;
 
     /* Get ENV */
     /* Not working -> race condition with player module */
@@ -132,9 +135,8 @@ normal_launch:
         lkt_queue_send(&srv.queue, lkt_event_play_pos, (void *) (size_t) strtol(env_current, NULL, 0));
     }
 
-    LOG_INFO("GENERAL", "Lektor was %s, user: %s, shell: %s, home: %s",
-             env_get(LKT_ENV_RESTART) ? "restarted" : "started",
-             pw->pw_name, pw->pw_shell, pw->pw_dir);
+    LOG_INFO("GENERAL", "Lektor was %s",
+             env_get(LKT_ENV_RESTART) ? "restarted" : "started");
 
     lkt_listen(&srv);
     return EXIT_FAILURE;
diff --git a/src/mkv/mkv.c b/src/mkv/mkv.c
index a108cdcddbb1322c353c6f1666c7b224130fbe70..70e10586529b343c571bf82bcf1d50864f0f8cc8 100644
--- a/src/mkv/mkv.c
+++ b/src/mkv/mkv.c
@@ -608,9 +608,8 @@ kara_read_length(double *len, const char *filename)
         } else {
             if (mkv_read_element_length(&file, &elength) < 0)
                 goto error;
-            if (bufferfd_skip(&file, elength) < 0) {
+            if (bufferfd_skip(&file, elength) < 0)
                 goto error;
-            }
         }
     }
 
diff --git a/src/module/module_sdl2.c b/src/module/module_sdl2.c
index 45b04f2333ec3fa3469e4eb512819f27670a029c..87ee26382d65a9ff73fc88a9de13ed24243ab3ce 100644
--- a/src/module/module_sdl2.c
+++ b/src/module/module_sdl2.c
@@ -1,19 +1,20 @@
 #define _POSIX_C_SOURCE 200809L
 
-#include <lektor/commands.h>
 #include <common/common.h>
-#include <lektor/module/module_sdl2.h>
+#include <common/queue.h>
 #include <lektor/module/mpv.h>
-#include <mthread/mthread.h>
 #include <lektor/thread.h>
 #include <lektor/reg.h>
+#include <lektor/net.h>
 
+#include <sqlite3.h>
 #include <sched.h>
 #include <assert.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <stdarg.h>
 #include <SDL.h>
 #include <mpv/render_gl.h>
 #include <mpv/client.h>
@@ -34,17 +35,27 @@ struct module_sdl2_window {
     volatile mpv_render_context *mpv_gl;
     volatile int mpv_time_pos;  /* Don't write it in the database       */
     volatile int mpv_duration;  /* Because don't need to be persistent  */
+    volatile int state;
 
     /* Thread related */
-    mthread_mutex_t mtx;
     struct poller_thread self;
     volatile int launched;  /* SDL you sucks */
 
     /* Things from the server */
+    struct queue *queue;
     volatile sqlite3 *db;
-    mpd_idle_flag *mpd_idle_events;
 };
 
+/* Function definitions */
+bool module_sdl2_get_elapsed(struct module_sdl2_window *, int *);
+bool module_sdl2_get_duration(struct module_sdl2_window *, int *);
+bool module_sdl2_set_volume(struct module_sdl2_window *, int);
+bool module_sdl2_load_file(struct module_sdl2_window *, const char *);
+bool module_sdl2_toggle_pause(struct module_sdl2_window *);
+void module_sdl2_free(struct module_sdl2_window *);
+void module_sdl2_close(struct module_sdl2_window *);
+bool module_sdl2_new(struct module_sdl2_window **, struct queue *, volatile sqlite3 *);
+
 /* Private functions. */
 
 static inline void *
@@ -101,15 +112,141 @@ init_mpv_gl__(mpv_handle *mpv, mpv_render_context **mpv_gl,
     return 0;
 }
 
+/* va_list version of functions. */
+
+int
+mod_new(va_list *va)
+{
+    va_list copy;
+    struct module_sdl2_window **win;
+    va_copy(copy, *va);
+    win = (struct module_sdl2_window **) va_arg(copy, void **);
+    struct queue *queue  = va_arg(copy, struct queue *);
+    volatile sqlite3 *db = va_arg(copy, volatile sqlite3 *);
+    bool ret = module_sdl2_new(win, queue, db);
+    va_end(copy);
+    return ! ret;
+}
+
+int
+mod_close(va_list *va)
+{
+    va_list copy;
+    struct module_sdl2_window **win;
+    va_copy(copy, *va);
+    win = (struct module_sdl2_window **) va_arg(copy, void **);
+    module_sdl2_close(*win);
+    va_end(copy);
+    return 0;
+}
+
+int
+mod_free(va_list *va)
+{
+    va_list copy;
+    struct module_sdl2_window **win;
+    va_copy(copy, *va);
+    win = (struct module_sdl2_window **) va_arg(copy, void **);
+    module_sdl2_free(*win);
+    va_end(copy);
+    return 0;
+}
+
+int
+mod_toggle_pause(va_list *va)
+{
+    va_list copy;
+    struct module_sdl2_window **win;
+    va_copy(copy, *va);
+    win = (struct module_sdl2_window **) va_arg(copy, void **);
+    bool ret = module_sdl2_toggle_pause(*win);
+    va_end(copy);
+    return ! ret;
+}
+
+int
+mod_load_file(va_list *va)
+{
+    va_list copy;
+    struct module_sdl2_window **win;
+    va_copy(copy, *va);
+    win = (struct module_sdl2_window **) va_arg(copy, void **);
+    const char *file = va_arg(copy, const char *);
+    bool ret = module_sdl2_load_file(*win, file);
+    va_end(copy);
+    return ! ret;
+}
+
+int
+mod_set_volume(va_list *va)
+{
+    va_list copy;
+    struct module_sdl2_window **win;
+    va_copy(copy, *va);
+    win = (struct module_sdl2_window **) va_arg(copy, void **);
+    int volume = va_arg(copy, int);
+    bool ret = module_sdl2_set_volume(*win, volume);
+    va_end(copy);
+    return ! ret;
+}
+
+int
+mod_get_duration(va_list *va)
+{
+    va_list copy;
+    struct module_sdl2_window **win;
+    va_copy(copy, *va);
+    win = (struct module_sdl2_window **) va_arg(copy, void **);
+    int *duration = va_arg(copy, int *);
+    bool ret = module_sdl2_get_duration(*win, duration);
+    va_end(copy);
+    return ! ret;
+}
+
+int
+mod_get_elapsed(va_list *va)
+{
+    va_list copy;
+    struct module_sdl2_window **win;
+    va_copy(copy, *va);
+    win = (struct module_sdl2_window **) va_arg(copy, void **);
+    int *elapsed = va_arg(copy, int *);
+    bool ret = module_sdl2_get_elapsed(*win, elapsed);
+    va_end(copy);
+    return ! ret;
+}
+
+/* The module stuff */
+
+REG_BEGIN(sdl2_reg)
+REG_ADD_NAMED("new",          mod_new)
+REG_ADD_NAMED("free",         mod_free)
+REG_ADD_NAMED("close",        mod_close)
+REG_ADD_NAMED("toggle",       mod_toggle_pause)
+REG_ADD_NAMED("load",         mod_load_file)
+REG_ADD_NAMED("set_volume",   mod_set_volume)
+REG_ADD_NAMED("get_duration", mod_get_duration)
+REG_ADD_NAMED("get_elapsed",  mod_get_elapsed)
+REG_END()
+REG_EXPORT(sdl2_reg)
+
+/* Function implementation */
+
 static void *
 sdl_thread__(struct poller_thread_arg *arg)
 {
-    volatile struct lkt_win *const win       = arg->args;
-    volatile struct module_sdl2_window *sdl2 = win->window;
+    struct module_sdl2_window *sdl2 = arg->args;
     SDL_Event event;
     uint64_t flags;
     int w, h, redraw = 0;
+    bool ctrl = false;
+    const Uint8 *state;
     free(arg);
+    struct lkt_module module = {
+        .handle = NULL,
+        .reg = sdl2_reg,
+        .data = sdl2,
+    };
 
     /* Init the SDL window
        Yeah, SDL you sucks */
@@ -127,7 +264,7 @@ sdl_thread__(struct poller_thread_arg *arg)
 
     /* Init mpv here */
 
-    RETURN_IF(init_mpv__((mpv_handle **) & sdl2->mpv, win->srv->db),
+    RETURN_IF(init_mpv__((mpv_handle **) & sdl2->mpv, sdl2->db),
               "Failed to init mpv", false);
 
     mpv_render_param params[] = {
@@ -167,30 +304,41 @@ loop:
 
     case SDL_WINDOWEVENT:
         if (event.window.event == SDL_WINDOWEVENT_EXPOSED) {
-            lkt_set_event_available(win->srv, lkt_event_play);
+            lkt_queue_make_available(sdl2->queue, lkt_event_play);
+            lkt_queue_make_available(sdl2->queue, lkt_event_prop);
             redraw = 1;
         }
         break;
 
-    case SDL_KEYUP:
-        if (event.key.keysym.sym == SDLK_SPACE) {
-            const char *cmd_pause[] = { "cycle", "pause", NULL };
-            mpv_command_async((mpv_handle *) sdl2->mpv, 0, cmd_pause);
-        }
-
-        else if (event.key.keysym.sym == SDLK_RETURN    ||
-                 event.key.keysym.sym == SDLK_RETURN2   ||
-                 event.key.keysym.sym == SDLK_KP_ENTER)
-            command_next(sdl2->db, (struct lkt_win *) win,
-                         sdl2->mpd_idle_events);
-
-        else if (event.key.keysym.sym == SDLK_LEFT) {
+    case SDL_KEYDOWN:
+        if (event.key.keysym.sym == SDLK_LEFT) {
             const char *cmd_seek[] = { "seek", "-5", "relative", NULL };
             mpv_command_async((mpv_handle *) sdl2->mpv, 0, cmd_seek);
         } else if (event.key.keysym.sym == SDLK_RIGHT) {
             const char *cmd_seek[] = { "seek", "+5", "relative", NULL };
             mpv_command_async((mpv_handle *) sdl2->mpv, 0, cmd_seek);
         }
+        break;
+
+    case SDL_KEYUP:
+        state = SDL_GetKeyboardState(NULL);
+        ctrl = state[SDL_SCANCODE_LCTRL] || state[SDL_SCANCODE_RCTRL];
+
+        if (ctrl && event.key.keysym.sym == SDLK_SPACE) {
+            const char *cmd_pause[] = { "cycle", "pause", NULL };
+            mpv_command_async((mpv_handle *) sdl2->mpv, 0, cmd_pause);
+        }
+
+        else if (event.key.keysym.sym == SDLK_n && ctrl)
+            lkt_queue_send(sdl2->queue, lkt_event_play_next, NULL);
+
+        else if (event.key.keysym.sym == SDLK_p && ctrl)
+            lkt_queue_send(sdl2->queue, lkt_event_play_prev, NULL);
+
+        else if ((event.key.keysym.sym == SDLK_RETURN    ||
+                  event.key.keysym.sym == SDLK_RETURN2   ||
+                  event.key.keysym.sym == SDLK_KP_ENTER) && ctrl)
+            lkt_queue_send(sdl2->queue, lkt_event_play_next, NULL);
 
         else if (event.key.keysym.sym == SDLK_F11) {
             if (sdl2->is_fullscreen)
@@ -204,29 +352,6 @@ loop:
         break;
 
     case SDL_TEXTINPUT:
-        if (STR_MATCH(event.text.text, ">"))
-            command_next(sdl2->db, (struct lkt_win *) win,
-                         sdl2->mpd_idle_events);
-        else if (STR_MATCH(event.text.text, "<"))
-            command_previous(sdl2->db, (struct lkt_win *) win,
-                             sdl2->mpd_idle_events);
-        else if (STR_MATCH(event.text.text, "o")) {
-            const char *cmd[] = { "show-progress", NULL };
-            mpv_command_async((mpv_handle *) sdl2->mpv, 0, cmd);
-        } else if (STR_MATCH(event.text.text, "i")) {
-            struct kara_metadata mdt;
-            int id;
-            char *str;
-            if (database_queue_current_kara(sdl2->db, &mdt, &id)) {
-                mdtcat(&mdt, &str);
-                const char *cmd[] = { "show-text", str, "4000", NULL };
-                /* Same size, only on 64bit arch...
-                   FIXME: Do something else in 32bits */
-                mpv_command_async((mpv_handle *) sdl2->mpv,
-                                  (uint64_t) str, cmd);
-            }
-        } else
-            LOG_ERROR("WINDOW", "Not handled text '%s'", event.text.text);
         break;
 
     default:
@@ -237,10 +362,10 @@ loop:
                 redraw = 1;
         }
 
-        if (event.type == wakeup_on_mpv_events)
-            lmpv_handle((struct lkt_win *) win, (mpv_handle *) sdl2->mpv,
-                        sdl2->db, sdl2->mpd_idle_events, &sdl2->mpv_time_pos,
-                        &sdl2->mpv_duration);
+        if (event.type == wakeup_on_mpv_events) {
+            lmpv_handle(&module, (mpv_handle *) sdl2->mpv, sdl2->queue,
+                        &sdl2->mpv_time_pos, &sdl2->mpv_duration, &sdl2->state);
+        }
     }
 
     if (redraw) {
@@ -273,153 +398,94 @@ end:
     return NULL;
 }
 
-/* Exported functions */
-
 bool
-module_sdl2_new(struct lkt_win *const win)
+module_sdl2_new(struct module_sdl2_window **win, struct queue *queue,
+                volatile sqlite3 *db)
 {
     RETURN_UNLESS(win, "Invalid arguments", false);
     struct poller_thread_arg *arg;
 
-    if (win->window == NULL) {
-        win->window = calloc(1, sizeof(struct module_sdl2_window));
-        RETURN_UNLESS(win->window, "Out of memory", false);
-        memset(win->window, 0, sizeof(struct module_sdl2_window));
+    if (*win == NULL) {
+        *win = calloc(1, sizeof(struct module_sdl2_window));
+        RETURN_UNLESS(*win, "Out of memory", false);
+        memset(*win, 0, sizeof(struct module_sdl2_window));
 
-        /* Yeah, this is how it is done. */
-        mthread_mutex_t mtx = MTHREAD_MUTEX_INITIALIZER;
-        struct module_sdl2_window *sdl2 = win->window;
-        sdl2->mtx = mtx;
-        sdl2->db = win->srv->db;
-        sdl2->mpd_idle_events = &win->srv->mpd_idle_events;
+        (*win)->queue = queue;
+        (*win)->db    = db;
 
         /* Start the SDL thread */
         arg = malloc(sizeof(struct poller_thread_arg));
         RETURN_UNLESS(arg, "Out of memory", false);
-        arg->args = win;
-        RETURN_IF(poller_new(&((struct module_sdl2_window *)win->window)->self,
-                             sdl_thread__, arg),
+        arg->args = *win;
+        RETURN_IF(poller_new(&(*win)->self, sdl_thread__, arg),
                   "Failed to launch the SDL thread", false);
-    }
+    } else
+        LOG_DEBUG("WINDOW", "%s", "SDL window already created");
 
     /* Finish */
-    SDL_SetWindowTitle((SDL_Window *) ((struct module_sdl2_window *)
-                                       win->window)->window, "Lektord");
+    SDL_SetWindowTitle((SDL_Window *) (*win)->window, "Lektord");
     SDL_DisableScreenSaver();
-    ((struct module_sdl2_window *) win->window)->launched = 1;
+    (*win)->launched = 1;
     return true;
 }
 
 void
-module_sdl2_close(struct lkt_win *const win)
+module_sdl2_close(struct module_sdl2_window *win)
 {
     RETURN_UNLESS(win && win->window, "Invalid arguments", NOTHING);
-    struct module_sdl2_window *sdl2 = win->window;
-    sdl2->mpv_time_pos = (sdl2->mpv_duration = 0);
-    RETURN_UNLESS(sdl2->mpv, "Missing mpv ctx", NOTHING);
+    win->mpv_time_pos = win->mpv_duration = 0;
+    RETURN_UNLESS(win->mpv, "Missing mpv ctx", NOTHING);
     static const char *cmd[] = { "stop", NULL };
-    mpv_command_async((mpv_handle *) sdl2->mpv, 0, cmd);
+    mpv_command_async((mpv_handle *) win->mpv, 0, cmd);
     /* TODO: make the SDL window background be black. */
 }
 
 void
-module_sdl2_free(struct lkt_win *const win)
+module_sdl2_free(struct module_sdl2_window *win)
 {
-    RETURN_UNLESS(win && win->window, "Invalid arguments", NOTHING);
-    struct module_sdl2_window *sdl2 = win->window;
-    sdl2->launched = 2;
-    while (sdl2->launched)
+    RETURN_UNLESS(win, "Invalid arguments", NOTHING);
+    win->launched = 2;
+    while (win->launched)
         sched_yield();
-    poller_join(&sdl2->self, NULL);
+    poller_join(&win->self, NULL);
 }
 
 bool
-module_sdl2_toggle_pause(struct lkt_win *const win)
+module_sdl2_toggle_pause(struct module_sdl2_window *win)
 {
-    RETURN_UNLESS(win && win->window, "Invalid arguments", false);
-    return ! lmpv_toggle_pause((mpv_handle *) ((struct module_sdl2_window *)
-                               win->window)->mpv);
+    RETURN_UNLESS(win, "Invalid arguments", false);
+    return ! lmpv_toggle_pause((mpv_handle *) win->mpv);
 }
 
 bool
-module_sdl2_load_file(struct lkt_win *const win, const char *filepath)
+module_sdl2_load_file(struct module_sdl2_window *win, const char *filepath)
 {
-    RETURN_UNLESS(win && win->window, "Invalid arguments", false);
-    struct module_sdl2_window *sdl2 = win->window;
-    bool ret = ! lmpv_load_file((mpv_handle *) sdl2->mpv, filepath);
-    sdl2->mpv_duration = 0;
-    sdl2->mpv_time_pos = 0;
+    RETURN_UNLESS(win, "Invalid arguments", false);
+    bool ret = ! lmpv_load_file((mpv_handle *) win->mpv, filepath);
+    win->mpv_duration = 0;
+    win->mpv_time_pos = 0;
     return ret;
 }
 
 bool
-module_sdl2_set_volume(struct lkt_win *const win, int vol)
+module_sdl2_set_volume(struct module_sdl2_window *win, int vol)
 {
     RETURN_UNLESS(win && win->window, "Invalid arguments", false);
-    return ! lmpv_set_volume((mpv_handle *)
-                             ((struct module_sdl2_window *) win->window)->mpv,
-                             vol);
+    return ! lmpv_set_volume((mpv_handle *) win->mpv, vol);
 }
 
 bool
-module_sdl2_get_duration(struct lkt_win *const win, int *dur_sec)
+module_sdl2_get_duration(struct module_sdl2_window *win, int *dur_sec)
 {
-    RETURN_UNLESS(win && win->window, "Invalid arguments", false);
-    *dur_sec = ((struct module_sdl2_window *) win->window)->mpv_duration;
-    return true;
-}
-
-bool
-module_sdl2_get_elapsed(struct lkt_win *const win, int *elapsed_sec)
-{
-    RETURN_UNLESS(win && win->window, "Invalid arguments", false);
-    *elapsed_sec = ((struct module_sdl2_window *) win->window)->mpv_time_pos;
+    RETURN_UNLESS(win, "Invalid arguments", false);
+    *dur_sec = win->mpv_duration;
     return true;
 }
 
 bool
-module_sdl2_handle_events(struct lkt_win *const win, volatile sqlite3 *db,
-                          mpd_idle_flag *mpd_idle_events)
+module_sdl2_get_elapsed(struct module_sdl2_window *win, int *elapsed_sec)
 {
-    UNUSED(win, db, mpd_idle_events);
+    RETURN_UNLESS(win, "Invalid arguments", false);
+    *elapsed_sec = win->mpv_time_pos;
     return true;
 }
-
-/* The module stuff */
-
-int
-#if ! defined(_STATIC_MODULES)
-module_set_function(void *arg__, struct lkt_state *srv, void *handle__)
-#else
-load_sdl2(void *arg__, struct lkt_state *srv, void *handle__)
-#endif
-{
-    RETURN_UNLESS(arg__, "Invalid argument", 1);
-    struct lkt_win *win = (struct lkt_win *) arg__;
-    win->srv            = srv;
-
-    win->new            = module_sdl2_new;
-    win->close          = module_sdl2_close;
-    win->free           = module_sdl2_free;
-    win->toggle_pause   = module_sdl2_toggle_pause;
-    win->load_file      = module_sdl2_load_file;
-    win->set_volume     = module_sdl2_set_volume;
-    win->get_duration   = module_sdl2_get_duration;
-    win->get_elapsed    = module_sdl2_get_elapsed;
-    win->handle_events  = module_sdl2_handle_events;
-    win->handle         = handle__;
-
-    return !module_sdl2_new(&srv->win);
-}
-
-REG_BEGIN(sdl2_reg)
-REG_ADD_NAMED("new",    module_sdl2_new)
-REG_ADD_NAMED("free",   module_sdl2_free)
-REG_ADD_NAMED("handle", module_sdl2_handle_events)
-REG_ADD(module_sdl2_close)
-REG_ADD(module_sdl2_toggle_pause)
-REG_ADD(module_sdl2_load_file)
-REG_ADD(module_sdl2_set_volume)
-REG_ADD(module_sdl2_get_duration)
-REG_ADD(module_sdl2_get_elapsed)
-REG_END()
diff --git a/src/module/module_x11.c b/src/module/module_x11.c
deleted file mode 100644
index fcce96a6ab83517961665f2531a3386f4f1c96e9..0000000000000000000000000000000000000000
--- a/src/module/module_x11.c
+++ /dev/null
@@ -1,277 +0,0 @@
-#define _POSIX_C_SOURCE 200809L
-
-#include <common/common.h>
-#include <lektor/module/module_x11.h>
-#include <lektor/module/mpv.h>
-#include <lektor/database.h>
-#include <lektor/commands.h>
-#include <lektor/reg.h>
-
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/Xatom.h>
-#include <mpv/client.h>
-
-#define WIDTH   400
-#define HEIGHT  200
-
-struct module_x11_window {
-    /* X11 related, the master and slave window */
-    Display *master_display;
-    Display *child_display;
-    Window master_win;
-    Window child_win;
-
-    /* X11 related, some X11 properties */
-    int screen;
-    XSetWindowAttributes attrs;
-    Atom wm_delete;
-    XColor black;
-    bool is_fullscreen;
-
-    /* Mpv related */
-    mpv_handle *mpv;
-    volatile int mpv_time_pos;  // Don't write it in the database       //
-    volatile int mpv_duration;  // Because don't need to be persistent  //
-};
-
-static inline bool
-lx11_new(struct module_x11_window *ret)
-{
-    ret->master_display = XOpenDisplay(NULL);
-    RETURN_UNLESS(ret->master_display, "Can't open display", false);
-    ret->screen = DefaultScreen(ret->master_display);
-    Colormap colormap = DefaultColormap(ret->master_display, ret->screen);
-    XAllocNamedColor(ret->master_display, colormap, "black",
-                     &ret->black, &ret->black);
-
-    // Initialize container window attributes
-    ret->attrs.event_mask
-        = SubstructureRedirectMask
-          | SubstructureNotifyMask
-          | StructureNotifyMask
-          | ExposureMask
-          | KeyReleaseMask
-          | VisibilityChangeMask
-          ;
-    ret->attrs.do_not_propagate_mask = 1;
-    ret->attrs.background_pixel = ret->black.pixel;
-    unsigned long attrs_mask = CWEventMask
-                               | NoEventMask
-                               | CWBackPixel
-                               ;
-
-    // Create and map container window
-    ret->master_win = XCreateWindow(ret->master_display, RootWindow(ret->master_display, ret->screen),
-                                    0, 0, WIDTH, HEIGHT, 1, CopyFromParent, InputOutput,
-                                    CopyFromParent, attrs_mask, &ret->attrs);
-
-    XMapWindow(ret->master_display, ret->master_win);
-    XStoreName(ret->master_display, ret->master_win, "Lektor Player");
-    ret->wm_delete = XInternAtom(ret->master_display, "WM_DELETE_WINDOW", True);
-    XSetWMProtocols(ret->master_display, ret->master_win, &ret->wm_delete, 1);
-
-    ret->child_display = NULL;
-    ret->child_win = 0;
-
-    return true;
-}
-
-static inline bool
-lx11_handle(struct module_x11_window *win)
-{
-    XEvent event;
-
-    RETURN_UNLESS(win && win->mpv, "Invalid argument", true);
-
-    for (;;) {
-
-        if (!XCheckWindowEvent(win->master_display, win->master_win,
-                               win->attrs.event_mask, &event))
-            return true;
-
-        // Map child window when it requests and store its display and window id
-        if (event.type == MapRequest) {
-            XMapWindow(event.xmaprequest.display, event.xmaprequest.window);
-
-            win->child_display = event.xmaprequest.display;
-            win->child_win = event.xmaprequest.window;
-        }
-
-        // Propagate resize event to child window, and also resize it
-        // after MapRequest
-        if (event.type == ConfigureNotify || event.type == MapRequest) {
-            if (win->child_win) {
-                // Get container window attributes
-                XWindowAttributes attrs;
-                XGetWindowAttributes(win->master_display, win->master_win,
-                                     &attrs);
-
-                // Move and resize child
-                XMoveResizeWindow(win->child_display, win->child_win,
-                                  2, 2, attrs.width - 6, attrs.height - 6);
-            }
-        }
-
-        // Key press
-        if (event.type == KeyRelease) {
-            LOG_INFO("WINDOW", "Release key: 0x%x", event.xkey.keycode);
-            if (event.xkey.keycode == 0x47)
-                XClearWindow(win->master_display, win->master_win);
-        }
-
-        // Refresh container window
-        if (event.type == Expose)
-            XClearWindow(win->master_display, win->master_win);
-
-        // Close button
-        if (event.type == ClientMessage) {
-            if ((long unsigned int) event.xclient.data.l[0] == win->wm_delete)
-                return false;
-        }
-
-    }
-    return true;
-}
-
-bool
-module_x11_new(struct lkt_win *const win)
-{
-    RETURN_UNLESS(win, "Invalid argument", false);
-    struct module_x11_window *x11_win = win->window;
-
-    if (x11_win == NULL) {
-        x11_win = calloc(1, sizeof(struct module_x11_window));
-        memset(x11_win, 0, sizeof(struct module_x11_window));
-        RETURN_UNLESS(x11_win, "Out of memory", false);
-        RETURN_UNLESS(lx11_new(x11_win), "Can't create X11 window", false);
-        LOG_INFO("WINDOW", "%s", "Created the X11 window");
-    }
-
-    if (x11_win->mpv == NULL) {
-        x11_win->mpv = lmpv_new(x11_win->master_win, win->srv->db);
-        RETURN_UNLESS(x11_win->mpv, "Failed to create mpv", false);
-    }
-
-    win->window = x11_win;
-    return true;
-}
-
-void
-module_x11_close(struct lkt_win *const win)
-{
-    RETURN_UNLESS(win && win->window, "Invalid arguments", NOTHING);
-    struct module_x11_window *const x11_win = win->window;
-    lmpv_free(&x11_win->mpv);
-    x11_win->child_display = NULL;
-    x11_win->child_win = (x11_win->mpv_time_pos = (x11_win->mpv_duration = 0));
-}
-
-void
-module_x11_free(struct lkt_win *const win)
-{
-    RETURN_UNLESS(win && win->window, "Invalid arguments", NOTHING);
-    struct module_x11_window *const x11_win = win->window;
-    lmpv_free(&x11_win->mpv);
-    XCloseDisplay(x11_win->master_display);
-    free(x11_win);
-    win->window = NULL;
-}
-
-bool
-module_x11_toggle_pause(struct lkt_win *const win)
-{
-    RETURN_UNLESS(win && win->window, "Invalid arguments", false);
-    return ! lmpv_toggle_pause(((struct module_x11_window *) win->window)->mpv);
-}
-
-bool
-module_x11_load_file(struct lkt_win *const win, const char *filepath)
-{
-    RETURN_UNLESS(win && win->window, "Invalid arguments", false);
-    struct module_x11_window *xwin = win->window;
-    bool ret = ! lmpv_load_file(xwin->mpv, filepath);
-    xwin->mpv_duration = 0;
-    xwin->mpv_time_pos = 0;
-    return ret;
-}
-
-bool
-module_x11_set_volume(struct lkt_win *const win, int vol)
-{
-    RETURN_UNLESS(win && win->window, "Invalid arguments", false);
-    return ! lmpv_set_volume(((struct module_x11_window *) win->window)->mpv,
-                             vol);
-}
-
-bool
-module_x11_get_duration(struct lkt_win *const win, int *dur_sec)
-{
-    RETURN_UNLESS(win && win->window, "Invalid arguments", false);
-    struct module_x11_window *win_x11 = win->window;
-    *dur_sec = win_x11->mpv_duration;
-    return true;
-}
-
-bool
-module_x11_get_elapsed(struct lkt_win *const win, int *elapsed_sec)
-{
-    RETURN_UNLESS(win && win->window, "Invalid arguments", false);
-    struct module_x11_window *win_x11 = win->window;
-    *elapsed_sec = win_x11->mpv_time_pos;
-    return true;
-}
-
-bool
-module_x11_handle_events(struct lkt_win *const win, volatile sqlite3 *db,
-                         mpd_idle_flag *mpd_idle_events)
-{
-    RETURN_UNLESS(win && win->window, "Invalid arguments", false);
-    struct module_x11_window *xwin = win->window;
-    return lx11_handle(xwin) &&
-           ! lmpv_handle(win, xwin->mpv, db, mpd_idle_events,
-                         &xwin->mpv_time_pos, &xwin->mpv_duration);
-}
-
-/* The module stuff */
-
-int
-#if ! defined(_STATIC_MODULES)
-module_set_function(void *arg__, struct lkt_state *srv, void *handle__)
-#else
-load_x11(void *arg__, struct lkt_state *srv, void *handle__)
-#endif
-{
-    RETURN_UNLESS(arg__, "Invalid arguments", 1);
-    struct lkt_win *win = (struct lkt_win *) arg__;
-    win->srv            = srv;
-
-    win->new            = module_x11_new;
-    win->close          = module_x11_close;
-    win->free           = module_x11_free;
-    win->toggle_pause   = module_x11_toggle_pause;
-    win->load_file      = module_x11_load_file;
-    win->set_volume     = module_x11_set_volume;
-    win->get_duration   = module_x11_get_duration;
-    win->get_elapsed    = module_x11_get_elapsed;
-    win->handle_events  = module_x11_handle_events;
-    win->handle         = handle__;
-
-    return !module_x11_new(&srv->win);
-}
-
-REG_BEGIN(x11_reg)
-REG_ADD_NAMED("new",    module_x11_new)
-REG_ADD_NAMED("free",   module_x11_free)
-REG_ADD_NAMED("handle", module_x11_handle_events)
-REG_ADD(module_x11_close)
-REG_ADD(module_x11_toggle_pause)
-REG_ADD(module_x11_load_file)
-REG_ADD(module_x11_set_volume)
-REG_ADD(module_x11_get_duration)
-REG_ADD(module_x11_get_elapsed)
-REG_END()
diff --git a/src/module/mpv.c b/src/module/mpv.c
index 06763230a2e673f62054c8b7238d0dd48d633167..b52c75ee7bb6793ed841635810f83b4a1831f8d3 100644
--- a/src/module/mpv.c
+++ b/src/module/mpv.c
@@ -10,6 +10,12 @@
 #include <unistd.h>
 #include <sqlite3.h>
 
+enum {
+    STATE_STOP  = 0,
+    STATE_PLAY  = 1,
+    STATE_PAUSE = 2,
+};
+
 void
 lmpv_free(mpv_handle **ctx)
 {
@@ -144,37 +150,42 @@ lmpv_toggle_pause(mpv_handle *ctx)
 }
 
 int
-lmpv_handle(struct lkt_win *win, mpv_handle *ctx, volatile sqlite3 *db, mpd_idle_flag *mpd_idle_events,
-            volatile int *time_pos, volatile int *time_duration)
+lmpv_handle(struct lkt_module *mod, mpv_handle *ctx, struct queue *queue,
+            volatile int *time_pos, volatile int *time_duration,
+            volatile int *state)
 {
-    int ao_volume;
-    struct lkt_queue_state state;
+    size_t ao_volume;
     mpv_event *event = NULL;
     mpv_event_property *prop;
-    RETURN_UNLESS(db && mpd_idle_events && ctx && win, "Invalid argument", 1);
-    RETURN_UNLESS(database_queue_state(db, &state), "Failed to get queue state", 1);
+    RETURN_UNLESS(ctx, "Invalid argument", 1);
 
 loop:
     event = mpv_wait_event(ctx, 0);
 
     switch (event->event_id) {
     case MPV_EVENT_PAUSE:
+        *state = STATE_PAUSE;
+        lkt_queue_send(queue, lkt_event_play_toggle, LKT_PLAY_TOGGLE);
+        break;
+
     case MPV_EVENT_UNPAUSE:
-        database_queue_toggle_pause(db);
+        *state = STATE_PLAY;
+        lkt_queue_send(queue, lkt_event_play_toggle, LKT_PLAY_TOGGLE);
         break;
 
     case MPV_EVENT_SHUTDOWN:
         *time_pos = (*time_duration = 0);
-        database_queue_stop(db);
-        win->close(win);
+        *state = STATE_STOP;
+        lkt_queue_send(queue, lkt_event_play_toggle, LKT_PLAY_STOP);
+        reg_call(mod->reg, "close", 1, mod->data);
         return 1;
 
     case MPV_EVENT_NONE:
         return 1;
 
     case MPV_EVENT_IDLE:
-        if (state.current > 0 && *time_pos > 0)
-            command_next(db, win, mpd_idle_events);
+        if (*state != STATE_STOP && *time_pos > 0)
+            lkt_queue_send(queue, lkt_event_play_next, NULL);
         break;
 
     case MPV_EVENT_PROPERTY_CHANGE:
@@ -185,23 +196,30 @@ loop:
         if (STR_MATCH(prop->name, "ao-volume")
             && prop->format == MPV_FORMAT_INT64) {
             ao_volume = *(int *) prop->data;
-            database_config_queue(db, "volume", ao_volume);
+            lkt_queue_send(queue, lkt_event_prop_vol, (void *) ao_volume);
         }
         // File duration //
         if (STR_MATCH(prop->name, "duration")
             && prop->format == MPV_FORMAT_INT64) {
             *time_duration = *(int *) prop->data;
-            database_config_queue(db, "duration", *(int *) prop->data);
+            lkt_queue_send(queue, lkt_event_prop_dur, (void *) (size_t) *time_duration);
         }
         if (STR_MATCH(prop->name, "time-pos")
             && prop->format == MPV_FORMAT_INT64) {
             *time_pos = *(int *) prop->data;
-            database_config_queue(db, "elapsed", *(int *) prop->data);
+            lkt_queue_send(queue, lkt_event_prop_time, (void *) (size_t) *time_pos);
         }
         // Pause state //
         if (STR_MATCH(prop->name, "pause")
-            && prop->format == MPV_FORMAT_FLAG)
-            database_queue_set_paused(db, *(bool *) prop->data);
+            && prop->format == MPV_FORMAT_FLAG) {
+            if (* (bool *) prop->data) {
+                lkt_queue_send(queue, lkt_event_play_toggle, LKT_PLAY_PAUSE);
+                *state = STATE_PAUSE;
+            } else {
+                lkt_queue_send(queue, lkt_event_play_toggle, LKT_PLAY_PLAY);
+                *state = STATE_PLAY;
+            }
+        }
         break;
 
     /* Ignored */
diff --git a/src/module/repo.c b/src/module/repo.c
index 7e9f6ceeab77907ac54fc84289fa7afda7a0c121..84f8967a1623dab65a361ae611c98a1229ab9070 100644
--- a/src/module/repo.c
+++ b/src/module/repo.c
@@ -12,11 +12,13 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <time.h>
+#include <stdarg.h>
 
 #include <common/common.h>
 #include <mthread/mthread.h>
 #include <lektor/database.h>
 #include <lektor/net.h>
+#include <lektor/reg.h>
 
 static volatile unsigned int curl_init = false;
 
@@ -90,12 +92,19 @@ repo_new(struct lkt_repo *const repo_, struct lkt_state *srv)
 }
 
 int
-load_repo_https(void *mod, struct lkt_state *srv, void *handle)
+load_repo_https(va_list *va)
 {
-    UNUSED(handle);
-    RETURN_UNLESS(mod, "Invalid argument", 1);
-    struct lkt_repo *repo = mod;
-    return repo_new(repo, srv);
+    va_list copy;
+    va_copy(copy, *va);
+    struct lkt_repo **repo = (struct lkt_repo **) va_arg(copy, void **);
+    struct lkt_state *srv = va_arg(copy, struct lkt_state *);
+    if (!*repo)
+        *repo = malloc(sizeof(struct lkt_repo));
+    if (!*repo)
+        return 1;
+    int ret = repo_new(*repo, srv);
+    va_end(copy);
+    return ret;
 }
 
 void
@@ -412,10 +421,7 @@ do_it:
         if (current_id == (int) kara.id) {
             LOG_WARN("REPO", "Update currently playing kara %d, skip it",
                      current_id);
-            char *current_path = safe_malloc(PATH_MAX * sizeof(char));
-            database_queue_skip_current(db, current_path);
-            srv->win.load_file(&srv->win, current_path);
-            free(current_path);
+            lkt_queue_send(&srv->queue, lkt_event_skip_current, NULL);
         }
 
         if (!database_update_add(db, kara.filename, &kara.mdt, kara.id, false)) {
@@ -491,3 +497,8 @@ repo_update(struct lkt_repo *const repo)
 {
     return mthread_create(NULL, ATTR_DETACHED, __repo_get_all_id_async, repo);
 }
+
+REG_BEGIN(repo_reg)
+REG_ADD_NAMED("new", load_repo_https)
+REG_END()
+REG_EXPORT(repo_reg)
diff --git a/src/net/listen.c b/src/net/listen.c
index 59ffd99c68c90ee7726d4c9a059d7b7be1301da8..49b3e9771f4cae99fd15023df65a12ed9f7cad10 100644
--- a/src/net/listen.c
+++ b/src/net/listen.c
@@ -50,12 +50,6 @@ struct lkt_client {
     int continuation;
 };
 
-void
-lkt_set_event_available(struct lkt_state *srv, enum lkt_event_type type)
-{
-    lkt_queue_make_available(&srv->queue, type);
-}
-
 static inline bool
 lkt_close_client(struct lkt_state *srv, size_t c)
 {
@@ -183,25 +177,25 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd)
             err = 0;
 
         else if (STR_MATCH(cmd.name, "next"))
-            err = !command_next(srv->db, &srv->win, &srv->mpd_idle_events);
+            err = !command_next(srv);
         else if (STR_MATCH(cmd.name, "pause"))
-            err = !command_pause(srv->db, &srv->win, &srv->mpd_idle_events);
+            err = !command_pause(srv);
         else if (STR_MATCH(cmd.name, "previous"))
-            err = !command_previous(srv->db, &srv->win, &srv->mpd_idle_events);
+            err = !command_previous(srv);
         else if (STR_MATCH(cmd.name, "play"))
-            err = ! command_play(srv->db, &srv->win, cmd.args, &srv->mpd_idle_events);
+            err = ! command_play(srv, cmd.args);
         else if (STR_MATCH(cmd.name, "playid"))
-            err = ! command_playid(srv->db, &srv->win, cmd.args, &srv->mpd_idle_events);
+            err = ! command_playid(srv, cmd.args);
         else if (STR_MATCH(cmd.name, "stop"))
-            err = !command_stop(srv->db, &srv->win, &srv->mpd_idle_events);
+            err = !command_stop(srv);
         else if (STR_MATCH(cmd.name, "clear"))
-            err = !command_clear(srv->db, &srv->mpd_idle_events);
+            err = !command_clear(srv);
         else if (STR_MATCH(cmd.name, "crop"))
-            err = !command_crop(srv->db, &srv->mpd_idle_events);
+            err = !command_crop(srv);
         else if (STR_MATCH(cmd.name, "moveid"))
-            err = !command_move(srv->db, cmd.args, &srv->mpd_idle_events);
+            err = !command_move(srv, cmd.args);
         else if (STR_MATCH(cmd.name, "shuffle"))
-            err = !command_shuffle(srv->db, &srv->mpd_idle_events);
+            err = !command_shuffle(srv);
 
         else if (STR_MATCH(cmd.name, "playlist") || STR_MATCH(cmd.name, "playlistinfo"))
             err = !command_queue_list(srv, c, cmd.args);
@@ -223,37 +217,33 @@ handle_simple_command(struct lkt_state *srv, size_t c, struct lkt_command cmd)
             err = !command_help(srv, c);
 
         else if (STR_MATCH(cmd.name, "__insert"))
-            err = ! command_add(srv->db, &srv->win, cmd.args,
-                                &srv->mpd_idle_events, 5);
+            err = ! command_add(srv, cmd.args, 5);
         else if (STR_MATCH(cmd.name, "searchadd")   ||
                  STR_MATCH(cmd.name, "findadd")     ||
                  STR_MATCH(cmd.name, "add"))
-            err = ! command_add(srv->db, &srv->win, cmd.args,
-                                &srv->mpd_idle_events, 1);
+            err = ! command_add(srv, cmd.args, 1);
         else if (STR_MATCH(cmd.name, "addid"))
-            err = ! command_addid(srv->db, &srv->win, cmd.args,
-                                  &srv->mpd_idle_events);
+            err = ! command_addid(srv, cmd.args);
         else if (STR_MATCH(cmd.name, "deleteid"))
             err = ! (cmd.args[0] != NULL &&
-                     command_delid(srv->db, &srv->win, cmd.args[0],
-                                   &srv->mpd_idle_events));
+                     command_delid(srv, cmd.args[0]));
 
         else if (STR_MATCH(cmd.name, "playlistclear"))
-            err = ! command_plt_clear(srv->db, cmd.args, &srv->mpd_idle_events);
+            err = ! command_plt_clear(srv, cmd.args);
         else if (STR_MATCH(cmd.name, "rename"))
-            err = ! command_plt_rename(srv->db, cmd.args, &srv->mpd_idle_events);
+            err = ! command_plt_rename(srv, cmd.args);
         else if (STR_MATCH(cmd.name, "playlistdelete"))
-            err = ! command_plt_remove(srv->db, cmd.args, &srv->mpd_idle_events);
+            err = ! command_plt_remove(srv, cmd.args);
         else if (STR_MATCH(cmd.name, "playlistadd"))
-            err = ! command_plt_add(srv->db, cmd.args, &srv->mpd_idle_events);
+            err = ! command_plt_add(srv, cmd.args);
         else if (STR_MATCH(cmd.name, "rm") && cmd.args[0] != NULL && cmd.args[1] == NULL)
-            err = ! command_plt_remove(srv->db, cmd.args, &srv->mpd_idle_events);
+            err = ! command_plt_remove(srv, cmd.args);
         else if (STR_MATCH(cmd.name, "save"))
-            err = ! command_plt_export(srv->db, cmd.args, &srv->mpd_idle_events);
+            err = ! command_plt_export(srv, cmd.args);
         else if (STR_MATCH(cmd.name, "__import"))
-            err = ! command_plt_import(srv->db, cmd.args, &srv->mpd_idle_events);
+            err = ! command_plt_import(srv, cmd.args);
         else if (STR_MATCH(cmd.name, "__dump"))
-            err = ! command_dump(srv->db, cmd.args, &srv->mpd_idle_events);
+            err = ! command_dump(srv, cmd.args);
         else if (STR_MATCH(cmd.name, "listplaylist"))
             err = ! command_find(srv, c, cmd.args, cmd.cont, database_search_playlist_init);
 
@@ -726,21 +716,62 @@ static inline void
 handle_queue_events(struct lkt_state *srv)
 {
     lkt_event evt;
-    char *string = malloc(BUFFER_MAX * sizeof(char));
-    if (!string)
-        return;
+    char *string = NULL;
 redo:
     evt = lkt_queue_handle(&srv->queue);
 
     switch (evt.type) {
     case lkt_event_play_pos:
+        if (NULL == (string = malloc(BUFFER_MAX * sizeof(char))))
+            return;
         safe_snprintf(string, BUFFER_MAX, "%ld", (size_t) evt.attr);
-        command_play(srv->db, &srv->win, &string, &srv->mpd_idle_events);
+        command_play(srv, &string);
+        free(string);
+        break;
+
+    case lkt_event_play_next:
+        command_next(srv);
+        break;
+
+    case lkt_event_play_prev:
+        command_previous(srv);
+        break;
+
+    case lkt_event_play_toggle:
+        switch ((size_t) evt.attr) {
+        case _LKT_PLAY_PAUSE:
+        case _LKT_PLAY_PLAY:
+        case _LKT_PLAY_TOGGLE:
+            database_queue_toggle_pause(srv->db);
+            break;
+        case _LKT_PLAY_STOP:
+            database_queue_stop(srv->db);
+            break;
+        }
+        break;
+
+    case lkt_event_prop_vol:
+        database_config_queue(srv->db, "volume", (size_t) evt.attr);
+        break;
+
+    case lkt_event_prop_dur:
+        database_config_queue(srv->db, "duration", (size_t) evt.attr);
+        break;
+
+    case lkt_event_prop_time:
+        database_config_queue(srv->db, "elapsed", (size_t) evt.attr);
+        break;
+
+    case lkt_event_skip_current:
+        if (NULL == (string = malloc(PATH_MAX * sizeof(char))))
+            return;
+        database_queue_skip_current(srv->db, string);
+        MOD_CALL(srv->window_mod, "load", string);
+        free(string);
         break;
 
     case lkt_event_null:
     default:
-        free(string);
         return;
     }
     goto redo;
@@ -766,7 +797,6 @@ lkt_listen(struct lkt_state *srv)
             break;
         if (handle_idle_events(srv) < 0)
             break;
-        srv->win.handle_events(&srv->win, srv->db, &srv->mpd_idle_events);
         handle_queue_events(srv);
     }
 }
diff --git a/src/queue.c b/src/queue.c
index c872e1f43f88ef9e4e22b3ca97e58f37b616cd5e..af034c55401f8657836668db37c4a8f1700ce6f5 100644
--- a/src/queue.c
+++ b/src/queue.c
@@ -44,8 +44,7 @@ void
 lkt_queue_send(struct queue *queue, enum lkt_event_type _type, void *_attr)
 {
     pthread_mutex_lock(&queue->lock);
-    if (!queue)
-        goto end;
+    GOTO_UNLESS(queue, "Invalid argument", end)
 
     volatile lkt_event *new;
     if (queue->size == queue->last) {
@@ -63,6 +62,9 @@ lkt_queue_send(struct queue *queue, enum lkt_event_type _type, void *_attr)
         .attr = _attr,
     };
     queue->contents[(queue->last)++] = evt;
+
+    if (! (_type & queue->available))
+        LOG_WARN("QUEUE", "The event %d is not available, push it anyway", _type);
 end:
     pthread_mutex_unlock(&queue->lock);
 }
@@ -72,13 +74,17 @@ lkt_queue_handle(struct queue *queue)
 {
     pthread_mutex_lock(&queue->lock);
     lkt_event ret = {0};
-
-    if (!queue || !queue->last ||
-        !(queue->contents[0].type & queue->available))
+    if (!queue || !queue->last)
         goto end;
+    if (! (queue->contents[0].type & queue->available) &&
+        queue->contents[0].type) {
+        LOG_WARN("QUEUE", "Event %d is not available", queue->contents[0].type);
+        goto end;
+    }
 
     ret = queue->contents[0];
-    memmove((void *) queue->contents, (void *) (queue->contents + 1), --(queue->last));
+    memmove((void *) queue->contents, (void *) (queue->contents + 1),
+            --(queue->last));
 end:
     pthread_mutex_unlock(&queue->lock);
     return ret;
diff --git a/src/reg.c b/src/reg.c
index c0ba8596d723b93959d92bd01734357811f23a6c..42192654931894ca348f3e5dfdeea8b8e8741517 100644
--- a/src/reg.c
+++ b/src/reg.c
@@ -9,22 +9,42 @@
 #include <stdio.h>
 #include <strings.h>
 #include <stddef.h>
+#include <stdarg.h>
+#include <string.h>
 
-struct module_reg *reg;
+struct module_reg *__reg__;
+
+void
+reg_export(struct module_reg *reg)
+{
+    __reg__ = reg;
+}
 
 void *
-reg_pick(const char *file, void **handle, const char *symbol)
+__reg_get(struct module_reg *reg, const char *name)
 {
     int i;
-    if (!symbol)
-        return NULL;
+    for (i = 0; (reg + i)->name && (reg + i)->obj; ++i) {
+        if (STR_MATCH((reg + i)->name, name))
+            return (reg + i)->obj;
+    }
+    return NULL;
+}
 
-    /* Use the register instead of dlfcn? */
-    if (!file || file[0] == '\0' || STR_MATCH(file, "STATIC") || handle == NULL)
-        goto use_reg;
+reg_func
+__reg_func(struct module_reg *reg, const char *name)
+{
+    int i;
+    for (i = 0; (reg + i)->name && (reg + i)->func; ++i) {
+        if (STR_MATCH((reg + i)->name, name))
+            return (reg + i)->func;
+    }
+    return NULL;
+}
 
-    /* Use dlsym */
-    LOG_INFO("REG", "Using dlfcn to find %s", symbol);
+void *
+__from_file(const char *file, void **handle, const char *symbol)
+{
     char *error;
     *handle = dlopen(file, RTLD_NOW);
 
@@ -44,63 +64,39 @@ reg_pick(const char *file, void **handle, const char *symbol)
     }
 
     return sym;
-
-    /* Read the reg */
-use_reg:
-    LOG_INFO("REG", "Using the reg structure to find %s", symbol);
-    for (i = 0; reg[i].name && reg[i].func; ++i)
-        if (STR_MATCH(reg[i].name, symbol))
-            return *(void **) &reg[i].func;
-
-    return NULL;
-}
-
-void
-reg_set(struct module_reg *_reg)
-{
-    reg = _reg;
 }
 
 int
-load_so(const char *const mod_path, const char *const mod_init, void *mod,
-        struct lkt_state *srv)
+reg_import(const char *mod, struct module_reg **ret, void **handle)
 {
-    /* An init function takes two arguments: the module pointer and a void*
-       which is the handler for the .so file. It the role of the module to
-       store the handle pointer.
-       Uppon successfull completion, the function shall return 0, and return
-       a non zero value if something bad happened. */
-    int (*module_set_function)(void *const, struct lkt_state *, void *const);
-    void *handle = NULL;
-    *(void **) (&module_set_function) = reg_pick(mod_path, &handle, mod_init);
-
-    if (module_set_function)
-        return module_set_function(mod, srv, handle);
-    else {
-        LOG_ERROR("LOAD", "Failed to find init symbol %s "
-                  "in file %s", mod_init, mod_path);
-        return 1;
+    if (strcspn(mod, "/.\'\"\\") != strlen(mod)) {
+        LOG_INFO("REG", "Using the dlsym to find '" REG_EXPORT_NAME
+                 "' in %s", mod);
+        *ret = __from_file(mod, handle, REG_EXPORT_NAME);
+    } else {
+        LOG_INFO("REG", "Using the reg structure to find %s", mod);
+        *ret = __reg_get(__reg__, mod);
+        if (!*ret) {
+            LOG_INFO("REG", "Not found in reg '" REG_EXPORT_NAME "', using "
+                     "the dlsym to find reg '" REG_EXPORT_NAME "' in file %s",
+                     mod);
+        }
     }
+    return *ret != NULL;
 }
 
+
 int
-load_module_by_name(struct lkt_state *srv, const char *name, void *mod)
+reg_call(struct module_reg *reg, const char *name, int count, ...)
 {
-    char mod_path[PATH_MAX], mod_load[INI_MAX_LINE_LEN];
-
-    /* When, don't mind if its not here */
-    if (!database_config_get_text(srv->db, name, "path", mod_path, PATH_MAX)) {
-        LOG_WARN("CONFIG", "No setting 'path' in section '%s'", name);
-        mod_path[0] = '\0';
+    reg_func func = __reg_func(reg, name);
+    if (!func) {
+        LOG_ERROR("REG", "No function named '%s'", name);
+        return 2;
     }
-
-    if (!database_config_get_text(srv->db, name, "load_function",
-                                  mod_load, INI_MAX_LINE_LEN)) {
-        LOG_ERROR("CONFIG", "Module named %s is incomplete or "
-                  "is not defined in config file", name);
-        return 1;
-    }
-
-    return load_so(mod_path, mod_load, mod, srv);
+    va_list va;
+    va_start(va, count);
+    int ret = func(&va);
+    va_end(va);
+    return ret;
 }
-