diff --git a/inc/lektor/module/module_sdl2.h b/inc/lektor/module/module_sdl2.h
new file mode 100644
index 0000000000000000000000000000000000000000..18cdee5c44f7d59e3b6418be5db25b2dda9cfa3c
--- /dev/null
+++ b/inc/lektor/module/module_sdl2.h
@@ -0,0 +1,28 @@
+#pragma once
+
+#include <lektor/defines.h>
+#include <stdbool.h>
+#include <sqlite3.h>
+#include <lektor/window.h>
+
+/* The only function with a setted filename */
+int module_set_function(void *mod, void *handle);
+
+/* 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 *new_paused);
+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_is_paused(struct lkt_win *const win, bool *ret);
+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, sqlite3 *db, enum mpd_idle_flag *mpd_idle_events);
diff --git a/inc/lektor/module/mpv.h b/inc/lektor/module/mpv.h
new file mode 100644
index 0000000000000000000000000000000000000000..1626d47f2d351652ce08f28a7cb0cb9a722eb3f0
--- /dev/null
+++ b/inc/lektor/module/mpv.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#include <mpv/client.h>
+
+void lmpv_free(mpv_handle **ctx);
+mpv_handle *lmpv_new(unsigned long int wid);
diff --git a/meson.build b/meson.build
index d2a9b13198dc8a6f0fe4b556dec2eaa97ccba990..09a39d454cb5c67fc4e263707cbf00ab8a945cb1 100644
--- a/meson.build
+++ b/meson.build
@@ -19,6 +19,7 @@ cc      = meson.get_compiler('c')
 libdl   = cc.find_library('dl')
 dep_x11 = dependency('x11', required : false)
 dep_mpv = dependency('mpv', required : false)
+dep_sdl = dependency('sdl2', required : false)
 
 # Sources
 
@@ -88,9 +89,19 @@ lkt = executable( 'lkt'
 # X11 window module
 if dep_x11.found() and dep_mpv.found()
   lib_mod_x11 = shared_library ( '_module_x11'
-                               , files(['src/module/module_x11.c'])
+                               , files(['src/module/module_x11.c', 'src/module/mpv.c'])
                                , include_directories : includes
                                , dependencies : [ dep_x11, dep_mpv ]
                                , link_with : lib
                                )
 endif
+
+# SQL2 window module
+if dep_sdl.found() and dep_mpv.found()
+  lib_mod_sdl = shared_library ( '_module_sdl2'
+                               , files(['src/module/module_sdl2.c', 'src/module/mpv.c'])
+                               , include_directories : includes
+                               , dependencies : [ dep_sdl, dep_mpv ]
+                               , link_with : lib
+                               )
+endif
diff --git a/src/module/module_sdl2.c b/src/module/module_sdl2.c
new file mode 100644
index 0000000000000000000000000000000000000000..cdda96b2e4ba854ddb05aca03c1db1e7b504ed8a
--- /dev/null
+++ b/src/module/module_sdl2.c
@@ -0,0 +1,447 @@
+#include <lektor/module/module_sdl2.h>
+#include <lektor/module/mpv.h>
+#include <lektor/macro.h>
+#include <lektor/defines.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <SDL.h>
+#include <mpv/render_gl.h>
+#include <mpv/client.h>
+
+#define WIDTH   400
+#define HEIGHT  200
+
+struct module_sdl2_window {
+    /* Related to SDL2 */
+    SDL_Window *window;
+    SDL_GLContext glcontext;
+
+    /* 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  //
+};
+
+/* Private functions. */
+
+static Uint32 wakeup_on_mpv_render_update, wakeup_on_mpv_events;
+
+static void
+die(const char *msg)
+{
+    fprintf(stderr, "%s\n", msg);
+    exit(1);
+}
+
+static void *
+get_proc_address_mpv(void *fn_ctx, const char *name)
+{
+    (void) fn_ctx;
+    return SDL_GL_GetProcAddress(name);
+}
+
+static void
+on_mpv_events(void *ctx)
+{
+    (void) ctx;
+    SDL_Event event = { .type = wakeup_on_mpv_events };
+    SDL_PushEvent(&event);
+}
+
+static void
+on_mpv_render_update(void *ctx)
+{
+    (void) ctx;
+    SDL_Event event = { .type = wakeup_on_mpv_render_update };
+    SDL_PushEvent(&event);
+}
+
+int
+main(int argc, char *argv[])
+{
+    if (argc != 2)
+        die("pass a single media file as argument");
+
+    mpv_handle *mpv = mpv_create();
+    if (!mpv)
+        die("context init failed");
+
+    // Some minor options can only be set before mpv_initialize().
+    if (mpv_initialize(mpv) < 0)
+        die("mpv init failed");
+
+    // Jesus Christ SDL, you suck!
+    SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "no");
+
+    if (SDL_Init(SDL_INIT_VIDEO) < 0)
+        die("SDL init failed");
+
+    SDL_Window *window =
+        SDL_CreateWindow("hi", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+                         1000, 500, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN |
+                         SDL_WINDOW_RESIZABLE);
+    if (!window)
+        die("failed to create SDL window");
+
+    SDL_GLContext glcontext = SDL_GL_CreateContext(window);
+    if (!glcontext)
+        die("failed to create SDL GL context");
+
+    mpv_render_param params[] = {
+        {MPV_RENDER_PARAM_API_TYPE, MPV_RENDER_API_TYPE_OPENGL},
+        {
+            MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &(mpv_opengl_init_params)
+            {
+                .get_proc_address = get_proc_address_mpv,
+            }
+        },
+        // Tell libmpv that you will call mpv_render_context_update() on render
+        // context update callbacks, and that you will _not_ block on the core
+        // ever (see <libmpv/render.h> "Threading" section for what libmpv
+        // functions you can call at all when this is active).
+        // In particular, this means you must call e.g. mpv_command_async()
+        // instead of mpv_command().
+        // If you want to use synchronous calls, either make them on a separate
+        // thread, or remove the option below (this will disable features like
+        // DR and is not recommended anyway).
+        {
+            MPV_RENDER_PARAM_ADVANCED_CONTROL, &(int)
+            {
+                1
+            }
+        },
+        {0}
+    };
+
+    // This makes mpv use the currently set GL context. It will use the callback
+    // (passed via params) to resolve GL builtin functions, as well as extensions.
+    mpv_render_context *mpv_gl;
+    if (mpv_render_context_create(&mpv_gl, mpv, params) < 0)
+        die("failed to initialize mpv GL context");
+
+    // We use events for thread-safe notification of the SDL main loop.
+    // Generally, the wakeup callbacks (set further below) should do as least
+    // work as possible, and merely wake up another thread to do actual work.
+    // On SDL, waking up the mainloop is the ideal course of action. SDL's
+    // SDL_PushEvent() is thread-safe, so we use that.
+    wakeup_on_mpv_render_update = SDL_RegisterEvents(1);
+    wakeup_on_mpv_events = SDL_RegisterEvents(1);
+    if (wakeup_on_mpv_render_update == (Uint32) - 1 ||
+        wakeup_on_mpv_events == (Uint32) - 1)
+        die("could not register events");
+
+    // When normal mpv events are available.
+    mpv_set_wakeup_callback(mpv, on_mpv_events, NULL);
+
+    // When there is a need to call mpv_render_context_update(), which can
+    // request a new frame to be rendered.
+    // (Separate from the normal event handling mechanism for the sake of
+    //  users which run OpenGL on a different thread.)
+    mpv_render_context_set_update_callback(mpv_gl, on_mpv_render_update, NULL);
+
+    // Play this file.
+    const char *cmd[] = {"loadfile", argv[1], NULL};
+    mpv_command_async(mpv, 0, cmd);
+
+    while (1) {
+        SDL_Event event;
+        if (SDL_WaitEvent(&event) != 1)
+            die("event loop error");
+        int redraw = 0;
+        switch (event.type) {
+        case SDL_QUIT:
+            goto done;
+        case SDL_WINDOWEVENT:
+            if (event.window.event == SDL_WINDOWEVENT_EXPOSED)
+                redraw = 1;
+            break;
+        case SDL_KEYDOWN:
+            if (event.key.keysym.sym == SDLK_SPACE) {
+                const char *cmd_pause[] = {"cycle", "pause", NULL};
+                mpv_command_async(mpv, 0, cmd_pause);
+            }
+            if (event.key.keysym.sym == SDLK_s) {
+                // Also requires MPV_RENDER_PARAM_ADVANCED_CONTROL if you want
+                // screenshots to be rendered on GPU (like --vo=gpu would do).
+                const char *cmd_scr[] = {"screenshot-to-file",
+                                         "screenshot.png",
+                                         "window",
+                                         NULL
+                                        };
+                printf("attempting to save screenshot to %s\n", cmd_scr[1]);
+                mpv_command_async(mpv, 0, cmd_scr);
+            }
+            break;
+        default:
+            // Happens when there is new work for the render thread (such as
+            // rendering a new video frame or redrawing it).
+            if (event.type == wakeup_on_mpv_render_update) {
+                uint64_t flags = mpv_render_context_update(mpv_gl);
+                if (flags & MPV_RENDER_UPDATE_FRAME)
+                    redraw = 1;
+            }
+            // Happens when at least 1 new event is in the mpv event queue.
+            if (event.type == wakeup_on_mpv_events) {
+                // Handle all remaining mpv events.
+                while (1) {
+                    mpv_event *mp_event = mpv_wait_event(mpv, 0);
+                    if (mp_event->event_id == MPV_EVENT_NONE)
+                        break;
+                    printf("event: %s\n", mpv_event_name(mp_event->event_id));
+                }
+            }
+        }
+        if (redraw) {
+            int w, h;
+            SDL_GetWindowSize(window, &w, &h);
+            mpv_render_param params[] = {
+                // Specify the default framebuffer (0) as target. This will
+                // render onto the entire screen. If you want to show the video
+                // in a smaller rectangle or apply fancy transformations, you'll
+                // need to render into a separate FBO and draw it manually.
+                {
+                    MPV_RENDER_PARAM_OPENGL_FBO, &(mpv_opengl_fbo)
+                    {
+                        .fbo = 0,
+                        .w = w,
+                        .h = h,
+                    }
+                },
+                {
+                    MPV_RENDER_PARAM_FLIP_Y, &(int)
+                    {
+                        1
+                    }
+                },
+                {0}
+            };
+            mpv_render_context_render(mpv_gl, params);
+            SDL_GL_SwapWindow(window);
+        }
+    }
+done:
+
+    // Destroy the GL renderer and all of the GL objects it allocated. If video
+    // is still running, the video track will be deselected.
+    mpv_render_context_free(mpv_gl);
+
+    mpv_detach_destroy(mpv);
+
+    printf("properly terminated\n");
+    return 0;
+}
+
+/* Exported functions */
+
+extern int
+module_set_function(void *arg__, void *handle__)
+{
+    if (NULL == arg__ || handle__ == NULL)
+        return 1;
+
+    struct lkt_win *win = (struct lkt_win *) arg__;
+
+    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->is_paused = module_sdl2_is_paused;
+    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 0;
+}
+
+bool
+module_sdl2_new(struct lkt_win *const win)
+{
+    if (win == NULL)
+        return false;
+
+    struct module_sdl2_window *sdl2 = win->window;
+
+    if (sdl2 == NULL) {
+        sdl2 = calloc(1, sizeof(struct module_sdl2_window));
+        memset(sdl2, 0, sizeof(struct module_sdl2_window));
+
+        if (sdl2 == NULL) {
+            fprintf(stderr, " ! module_sdl2_new: failed to allocate window, no memory\n");
+            return false;
+        }
+
+        /* CREATE THE SDL2 WINDOW TODO */
+
+        fprintf(stderr, " . module_sdl2_new: successfully created the X11 window\n");
+    }
+
+    if (sdl2->mpv == NULL) {
+        sdl2->mpv = lmpv_new(0);
+        if (sdl2->mpv == NULL)
+            return false;
+    }
+
+    win->window = sdl2;
+    return true;
+}
+
+void
+module_sdl2_close(struct lkt_win *const win)
+{
+    if (win == NULL || win->window == NULL)
+        return;
+
+    struct module_sdl2_window *const sdl2 = win->window;
+    lmpv_free(&sdl2->mpv);
+}
+
+void
+module_sdl2_free(struct lkt_win *const win)
+{
+    module_sdl2_close(win);
+}
+
+bool
+module_sdl2_toggle_pause(struct lkt_win *const win, bool *new_paused)
+{
+    if (win == NULL || win->window == NULL)
+        return false;
+
+    mpv_handle *ctx = ((struct module_sdl2_window *) win->window)->mpv;
+
+    if (!ctx) {
+        fprintf(stderr, " ! module_sdl2_toggle_pause: failed due to missing mpv ctx\n");
+        return false;
+    }
+
+    const char *cmd[] = {"cycle", "pause", "up", NULL};
+    int status;
+
+    if ((status = mpv_command(ctx, cmd)) < 0) {
+        fprintf(stderr, "module_sdl2_toggle_pause: Failed issue command: %s\n",
+                mpv_error_string(status));
+        return false;
+    }
+
+    return module_sdl2_is_paused(win, new_paused);
+}
+
+bool
+module_sdl2_load_file(struct lkt_win *const win, const char *filepath)
+{
+    if (win == NULL || win->window == NULL)
+        return false;
+
+    struct module_sdl2_window *sdl2 = win->window;
+    mpv_handle *ctx = sdl2->mpv;
+
+    if (!ctx) {
+        fprintf(stderr, " ! module_sdl2_load_file: failed due to missing mpv ctx\n");
+        return false;
+    }
+
+    if (access(filepath, R_OK)) {
+        fprintf(stderr, " ! module_sdl2_load_file: Faild to read file: %s\n", filepath);
+        return false;
+    }
+
+    const char *cmd[] = {"loadfile", filepath, "replace", NULL};
+    int status;
+
+    if ((status = mpv_command(ctx, cmd)) < 0) {
+        fprintf(stderr, " ! module_sdl2_load_file: Failed to add '%s': %s\n",
+                filepath, mpv_error_string(status));
+        return false;
+    }
+
+    sdl2->mpv_duration = 0;
+    sdl2->mpv_time_pos = 0;
+
+    fprintf(stderr, " . module_x11_load_file: added file %s\n", filepath);
+    return true;
+}
+
+bool
+module_sdl2_set_volume(struct lkt_win *const win, int vol)
+{
+    if (win == NULL || win->window == NULL)
+        return false;
+
+    mpv_handle *ctx = ((struct module_sdl2_window *) win->window)->mpv;
+
+    if (!ctx) {
+        fprintf(stderr, " ! module_sdl2_set_volume: failed due to missing mpv ctx\n");
+        return false;
+    }
+
+    int status;
+    char str[5];
+    memset(str, 0, 5);
+    snprintf(str, 4, "%d", vol);
+    const char *cmd[] = {"set", "ao-volume", str, NULL};
+
+    if ((status = mpv_command(ctx, cmd)) < 0) {
+        fprintf(stderr, " ! module_x11_set_volume: Failed to execute command: %s\n",
+                mpv_error_string(status));
+        return false;
+    }
+
+    return true;
+}
+
+bool
+module_sdl2_is_paused(struct lkt_win *const win, bool *ret)
+{
+    if (win == NULL || win->window == NULL)
+        return false;
+
+    mpv_handle *ctx = ((struct module_sdl2_window *) win->window)->mpv;
+    int status;
+
+    if (!ctx) {
+        fprintf(stderr, " ! module_sdl2_is_paused: failed due to missing mpv ctx\n");
+        return false;
+    }
+
+    if ((status = mpv_get_property(ctx, "pause", MPV_FORMAT_FLAG, &ret)) < 0) {
+        fprintf(stderr, "module_sdl2_is_paused: Failed to get pause property: %s\n",
+                mpv_error_string(status));
+        return false;
+    }
+
+    return true;
+}
+
+bool
+module_sdl2_get_duration(struct lkt_win *const win, int *dur_sec)
+{
+    if (win == NULL || win->window == NULL)
+        return false;
+
+    struct module_sdl2_window *sdl2 = win->window;
+    *dur_sec = sdl2->mpv_duration;
+
+    return true;
+}
+
+bool
+module_sdl2_get_elapsed(struct lkt_win *const win, int *elapsed_sec)
+{
+    if (win == NULL || win->window == NULL)
+        return false;
+
+    struct module_sdl2_window *sdl2 = win->window;
+    *elapsed_sec = sdl2->mpv_time_pos;
+
+    return true;
+}
+
+bool
+module_sdl2_handle_events(struct lkt_win *const win, sqlite3 *db, enum mpd_idle_flag *mpd_idle_events)
+{
+}
diff --git a/src/module/module_x11.c b/src/module/module_x11.c
index 49a2e8132527b9ea154975bfc6fecbd86dcc34b7..a7885660af5606bd897432bcc8906b4c8e09a16e 100644
--- a/src/module/module_x11.c
+++ b/src/module/module_x11.c
@@ -1,4 +1,5 @@
 #include <lektor/module/module_x11.h>
+#include <lektor/module/mpv.h>
 #include <lektor/database.h>
 #include <lektor/commands.h>
 
@@ -211,21 +212,6 @@ lx11_handle(struct module_x11_window *win)
  *
  */
 
-static inline void
-lmpv_free(mpv_handle **ctx)
-{
-    if (!*ctx) {
-        fprintf(stderr, " ! lmpv_free: failed due to missing mpv ctx\n");
-        return;
-    }
-
-    static const char *cmd[] = {"quit", NULL};
-    mpv_command(*ctx, cmd);
-    mpv_destroy(*ctx);
-    *ctx = NULL;
-    fprintf(stderr, " * lmpv_free: mpv context destroyed\n");
-}
-
 static inline bool
 lmpv_handle(struct lkt_win *win, sqlite3 *db, enum mpd_idle_flag *mpd_idle_events)
 {
@@ -301,90 +287,6 @@ end:
     return sta;
 }
 
-static mpv_handle *
-lmpv_new(unsigned long int wid)
-{
-    mpv_handle *ctx = mpv_create();
-    int status;
-
-    if (!ctx) {
-        fprintf(stderr, " ! lmpv_new: failed creating context\n");
-        return NULL;
-    }
-
-    if ((status = mpv_set_option_string(ctx, "input-default-bindings", "yes")) < 0) {
-        fprintf(stderr, " ! lmpv_new: failed to set input-default-bindings: %s\n",
-                mpv_error_string(status));
-        return NULL;
-    }
-
-    if ((status = mpv_set_option_string(ctx, "input-vo-keyboard", "yes")) < 0) {
-        fprintf(stderr, " ! lmpv_new: failed to set input-vo-keyboard: %s\n",
-                mpv_error_string(status));
-        return NULL;
-    }
-
-    if ((status = mpv_set_option_string(ctx, "replaygain", "track")) < 0) {
-        fprintf(stderr, " ! lmpv_new: failed to set replaygain: %s\n",
-                mpv_error_string(status));
-        return NULL;
-    }
-
-    if ((status = mpv_set_option_string(ctx, "gpu-context", "x11")) < 0) {
-        fprintf(stderr, " ! lmpv_new: failed to set gpu-context: %s\n",
-                mpv_error_string(status));
-        return NULL;
-    }
-
-    if ((status = mpv_set_property(ctx, "wid", MPV_FORMAT_INT64, &wid)) < 0) {
-        fprintf(stderr, " ! lmpv_new: failed to set wid: %s\n",
-                mpv_error_string(status));
-        return NULL;
-    }
-
-    if ((status = mpv_set_option_string(ctx, "demuxer-max-bytes", "10M")) < 0) {
-        fprintf(stderr, " ! lmpv_new: failed to set demuxer-max-bytes: %s\n",
-                mpv_error_string(status));
-        return NULL;
-    }
-
-    if ((status = mpv_set_option_string(ctx, "profile", "low-latency")) < 0) {
-        fprintf(stderr, " ! lmpv_new: failed to set demuxer-max-bytes: %s\n",
-                mpv_error_string(status));
-        return NULL;
-    }
-
-    if ((status = mpv_set_property_string(ctx, "hwdec", "yes")) < 0) {
-        fprintf(stderr, " ! lmpv_new: failed to set hwdec to no: %s\n",
-                mpv_error_string(status));
-        return NULL;
-    }
-
-    if ((status = mpv_initialize(ctx)) < 0) {
-        fprintf(stderr, " ! lmpv_new: failed to initialize mpv: %s\n",
-                mpv_error_string(status));
-        return NULL;
-    }
-
-    if ((status = mpv_observe_property(ctx, 0, "ao-volume", MPV_FORMAT_INT64)) < 0)
-        goto error;
-
-    if ((status = mpv_observe_property(ctx, 0, "duration", MPV_FORMAT_INT64)) < 0)
-        goto error;
-
-    if ((status = mpv_observe_property(ctx, 0, "time-pos", MPV_FORMAT_INT64)) < 0)
-        goto error;
-
-    if ((status = mpv_observe_property(ctx, 0, "pause", MPV_FORMAT_FLAG)) < 0)
-        goto error;
-
-    fprintf(stderr, " * lmpv_new: successfully created a mpv context\n");
-    return ctx;
-error:
-    lmpv_free(&ctx);
-    return NULL;
-}
-
 /*
  *
  * NOW: THE SETTED FUNCTIONS FOR THE WINDOW MODULE :NOW
diff --git a/src/module/mpv.c b/src/module/mpv.c
new file mode 100644
index 0000000000000000000000000000000000000000..b81c1c47433a564cc5013a1d5760a0746dc89635
--- /dev/null
+++ b/src/module/mpv.c
@@ -0,0 +1,112 @@
+#include <lektor/module/mpv.h>
+#include <stdio.h>
+
+void
+lmpv_free(mpv_handle **ctx)
+{
+    if (!*ctx) {
+        fprintf(stderr, " ! lmpv_free: failed due to missing mpv ctx\n");
+        return;
+    }
+
+    static const char *cmd[] = {"quit", NULL};
+    mpv_command(*ctx, cmd);
+    mpv_destroy(*ctx);
+    *ctx = NULL;
+    fprintf(stderr, " * lmpv_free: mpv context destroyed\n");
+}
+
+void *
+lmpv_prepare(void)
+{
+    mpv_handle *ctx = mpv_create();
+    int status;
+
+    if (!ctx) {
+        fprintf(stderr, " ! lmpv_new: failed creating context\n");
+        return NULL;
+    }
+
+    if ((status = mpv_set_option_string(ctx, "input-default-bindings", "yes")) < 0) {
+        fprintf(stderr, " ! lmpv_new: failed to set input-default-bindings: %s\n",
+                mpv_error_string(status));
+        return NULL;
+    }
+
+    if ((status = mpv_set_option_string(ctx, "input-vo-keyboard", "yes")) < 0) {
+        fprintf(stderr, " ! lmpv_new: failed to set input-vo-keyboard: %s\n",
+                mpv_error_string(status));
+        return NULL;
+    }
+
+    if ((status = mpv_set_option_string(ctx, "replaygain", "track")) < 0) {
+        fprintf(stderr, " ! lmpv_new: failed to set replaygain: %s\n",
+                mpv_error_string(status));
+        return NULL;
+    }
+
+    if ((status = mpv_set_option_string(ctx, "gpu-context", "x11")) < 0) {
+        fprintf(stderr, " ! lmpv_new: failed to set gpu-context: %s\n",
+                mpv_error_string(status));
+        return NULL;
+    }
+
+    if ((status = mpv_set_option_string(ctx, "demuxer-max-bytes", "10M")) < 0) {
+        fprintf(stderr, " ! lmpv_new: failed to set demuxer-max-bytes: %s\n",
+                mpv_error_string(status));
+        return NULL;
+    }
+
+    if ((status = mpv_set_option_string(ctx, "profile", "low-latency")) < 0) {
+        fprintf(stderr, " ! lmpv_new: failed to set demuxer-max-bytes: %s\n",
+                mpv_error_string(status));
+        return NULL;
+    }
+
+    if ((status = mpv_set_property_string(ctx, "hwdec", "yes")) < 0) {
+        fprintf(stderr, " ! lmpv_new: failed to set hwdec to no: %s\n",
+                mpv_error_string(status));
+        return NULL;
+    }
+
+    return ctx;
+}
+
+int
+lmpv_observe_properties(mpv_handle *ctx)
+{
+    return (mpv_observe_property(ctx, 0, "ao-volume", MPV_FORMAT_INT64) < 0)    &&
+           (mpv_observe_property(ctx, 0, "duration", MPV_FORMAT_INT64) < 0)     &&
+           (mpv_observe_property(ctx, 0, "time-pos", MPV_FORMAT_INT64) < 0)     &&
+           (mpv_observe_property(ctx, 0, "pause", MPV_FORMAT_FLAG) < 0);
+}
+
+mpv_handle *
+lmpv_new(unsigned long int wid)
+{
+    mpv_handle *ctx = lmpv_prepare();
+    int status;
+
+    if ((status = mpv_set_property(ctx, "wid", MPV_FORMAT_INT64, &wid)) < 0) {
+        fprintf(stderr, " ! lmpv_new: failed to set wid: %s\n",
+                mpv_error_string(status));
+        goto error;
+    }
+
+    if ((status = mpv_initialize(ctx)) < 0) {
+        fprintf(stderr, " ! lmpv_new: failed to initialize mpv: %s\n",
+                mpv_error_string(status));
+        goto error;
+    }
+
+    if (!lmpv_observe_properties(ctx)) {
+        fprintf(stderr, " * lmpv_new: failed to observe properties\n");
+        goto error;
+    }
+
+    fprintf(stderr, " * lmpv_new: successfully created a mpv context\n");
+    return ctx;
+error:
+    lmpv_free(&ctx);
+    return NULL;
+}