From 24e362a595fed7bdf6cd9cc310c19bfb4e6a4df5 Mon Sep 17 00:00:00 2001
From: Elliu <elliu@hashi.re>
Date: Wed, 22 Dec 2021 22:50:25 +0100
Subject: [PATCH] Moving C code in headers to .c files to allow includes from
 C++

---
 CMakeLists.txt                               |   2 +
 inc/lektor/common.h                          |   2 +-
 inc/lektor/lib/strv.h                        | 297 +++----------------
 inc/lektor/net.h                             |   4 +-
 inc/lektor/queue.h                           | 101 +------
 src/base/os.c                                |   2 +-
 src/database/queue.c                         | 108 +++++++
 src/lib/strv.c                               | 262 ++++++++++++++++
 src/main/server.c                            |   2 +
 src/module/module_qt_window.c                |  24 +-
 src/module/module_qt_window.h                |  31 ++
 src/module/qt_window/mpvwidget.hh            |   2 +
 src/module/qt_window/mpvwidget_interface.cpp |  18 +-
 src/module/qt_window/mpvwidget_interface.h   |  10 +-
 src/module/thread.c                          |  81 +++++
 src/module/thread.h                          |  87 +-----
 16 files changed, 591 insertions(+), 442 deletions(-)
 create mode 100644 src/lib/strv.c
 create mode 100644 src/module/module_qt_window.h
 create mode 100644 src/module/thread.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
index d9d8d8d2..4e9cfd55 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -139,6 +139,7 @@ set(lektor_db_SOURCES
     src/database/open.c
     src/database/update.c
     src/database/upgrade.c
+    src/lib/strv.c
 )
 
 set(lektor_module_SOURCES
@@ -150,6 +151,7 @@ set(lektor_module_SOURCES
     src/module/qt_window/mpvwidget.cpp
     src/module/qt_window/mpvwidget_interface.cpp
     src/module/qt_window/qthelper.cpp
+    src/module/thread.c
 )
 
 set(lektor_mkv_SOURCES
diff --git a/inc/lektor/common.h b/inc/lektor/common.h
index e1a4706b..01b985a8 100644
--- a/inc/lektor/common.h
+++ b/inc/lektor/common.h
@@ -207,7 +207,7 @@ void ___lkt_print(const char *section, const char *format, ...);
 #define BUFFER_OUT_MAX   16 /* At most 16 messages per client */
 #define MPD_VERSION      "0.21.16"
 
-typedef volatile enum {
+typedef enum {
     MPD_IDLE_NONE = 0,
 
     MPD_IDLE_DATABASE        = (1 << 1),
diff --git a/inc/lektor/lib/strv.h b/inc/lektor/lib/strv.h
index 151c64fc..d0b84a63 100644
--- a/inc/lektor/lib/strv.h
+++ b/inc/lektor/lib/strv.h
@@ -16,7 +16,7 @@ struct strv {
 #define STRV_FMT     "%.*s"                    /* Format string for a string view */
 #define STRV_ARG(sv) ((sv).count), ((sv).data) /* Unpack the string view */
 
-#define STRV_DEF __attribute__((unused)) static
+#define STRV_DEF __attribute__((unused))
 
 /* Create a string view from a slice or a C string. */
 STRV_DEF struct strv strv_from_slice(const char *data, int count);
@@ -58,265 +58,54 @@ STRV_DEF _Bool strv_equal_nocase(struct strv a, struct strv b);
 
 /* Private implementation of some functions to not include some headers */
 
-static inline char
-strv_ctoupper(char s)
-{
-    return (('a' <= s) && (s <= 'z')) ? 'A' + (s - 'a') : s;
-}
-
-static inline char
-strv_ctolower(char s)
-{
-    return (('A' <= s) && (s <= 'Z')) ? 'a' + (s - 'A') : s;
-}
-
-static inline _Bool
-strv_memcmp(const void *ptr2, const void *ptr1, int count)
-{
-    register const unsigned char *s1 = (const unsigned char *)ptr1;
-    register const unsigned char *s2 = (const unsigned char *)ptr2;
-
-    while (count-- > 0) {
-        if (*s1++ != *s2++)
-            return (_Bool)0;
-    }
+char strv_ctoupper(char s);
 
-    return (_Bool)1;
-}
-
-static inline _Bool
-strv_isspace(char x)
-{
-    return x == ' ' || x == '\t' || x == '\n' || x == '\r' || x == '\v' || x == '\f';
-}
-
-static inline int
-strv_strlen(const char *str)
-{
-    int len = 0;
-    while (str[len]) {
-        len += 1;
-
-        /* Try to avoid overflows */
-        if (len == __INT_MAX__)
-            return 0;
-    }
-    return len;
-}
+char strv_ctolower(char s);
+
+_Bool strv_memcmp(const void *ptr2, const void *ptr1, int count);
+
+_Bool strv_isspace(char x);
+
+int strv_strlen(const char *str);
 
 /* Implementation of the functions */
 
-static struct strv
-strv_from_slice(const char *data, int count)
-{
-    struct strv sv;
-    sv.count = count;
-    sv.data  = data;
-    return sv;
-}
-
-static struct strv
-strv_from_str(const char *cstr)
-{
-    return strv_from_slice(cstr, strv_strlen(cstr));
-}
-
-static _Bool
-strv_as_str(const struct strv sv, char *data, int len)
-{
-    if (sv.count >= len)
-        return (_Bool)0;
-
-    for (int i = 0; i < sv.count; ++i)
-        data[i] = sv.data[i];
-    data[sv.count] = '\0';
-
-    return (_Bool)1;
-}
-
-static struct strv
-strv_trim_l(struct strv sv)
-{
-    int i = 0;
-    while ((i < sv.count) && strv_isspace(sv.data[i]))
-        i += 1;
-    return strv_from_slice(sv.data + i, sv.count - i);
-}
-
-static struct strv
-strv_trim_r(struct strv sv)
-{
-    int i = 0;
-    while ((i < sv.count) && strv_isspace(sv.data[sv.count - 1 - i]))
-        i += 1;
-    return strv_from_slice(sv.data, sv.count - i);
-}
-
-static struct strv
-strv_trim(struct strv sv)
-{
-    return strv_trim_r(strv_trim_l(sv));
-}
-
-static struct strv
-strv_chop_left(struct strv *sv, int n)
-{
-    if (n > sv->count)
-        n = sv->count;
-
-    struct strv result = strv_from_slice(sv->data, n);
-    sv->data += n;
-    sv->count -= n;
-    return result;
-}
-
-static struct strv
-strv_chop_right(struct strv *sv, int n)
-{
-    if (n > sv->count)
-        n = sv->count;
-
-    struct strv result = strv_from_slice(sv->data + sv->count - n, n);
-    sv->count -= n;
-    return result;
-}
-
-static _Bool
-strv_index_of(struct strv sv, char c, int *index)
-{
-    int i = 0;
-    while (i < sv.count && sv.data[i] != c)
-        i += 1;
-
-    if (i < sv.count) {
-        if (index)
-            *index = i;
-        return (_Bool)1;
-    }
+struct strv strv_from_slice(const char *data, int count);
 
-    else
-        return (_Bool)0;
-}
-
-static _Bool
-strv_try_chop_by_delim(struct strv *sv, char delim, struct strv *chunk)
-{
-    int i = 0;
-    while (i < sv->count && sv->data[i] != delim)
-        i += 1;
-
-    struct strv result = strv_from_slice(sv->data, i);
-
-    if (i < sv->count) {
-        i += 1;
-        sv->count -= i;
-        sv->data += i;
-        if (chunk)
-            *chunk = result;
-        return (_Bool)1;
-    }
+struct strv strv_from_str(const char *cstr);
 
-    return (_Bool)0;
-}
-
-static struct strv
-strv_chop_by_delim(struct strv *sv, char delim)
-{
-    int i = 0;
-    while (i < sv->count && sv->data[i] != delim)
-        i += 1;
-
-    const struct strv result = strv_from_slice(sv->data, i);
-    i += (i < sv->count);
-    sv->count -= i;
-    sv->data += i;
-
-    return result;
-}
-
-static _Bool
-strv_starts_with(struct strv sv, struct strv expected_prefix)
-{
-    if (expected_prefix.count <= sv.count) {
-        const struct strv actual_prefix = strv_from_slice(sv.data, expected_prefix.count);
-        return strv_equal(expected_prefix, actual_prefix);
-    }
+_Bool strv_as_str(const struct strv sv, char *data, int len);
 
-    return (_Bool)0;
-}
+struct strv strv_trim_l(struct strv sv);
 
-static _Bool
-strv_ends_with(struct strv sv, struct strv expected_suffix)
-{
-    if (expected_suffix.count <= sv.count) {
-        const struct strv actual_suffix =
-            strv_from_slice(sv.data + sv.count - expected_suffix.count, expected_suffix.count);
-        return strv_equal(expected_suffix, actual_suffix);
-    }
+struct strv strv_trim_r(struct strv sv);
 
-    return (_Bool)0;
-}
-
-static _Bool
-strv_equal(struct strv a, struct strv b)
-{
-    return (a.count != b.count) ? (_Bool)0 : strv_memcmp(a.data, b.data, a.count);
-}
-
-static _Bool
-strv_equal_nocase(struct strv a, struct strv b)
-{
-    if (a.count != b.count)
-        return (_Bool)0;
-    for (int i = 0; i < a.count; ++i) {
-        if (strv_ctoupper(a.data[i]) != strv_ctoupper(b.data[i]))
-            return (_Bool)0;
-    }
-    return (_Bool)1;
-}
-
-static struct strv
-strv_chop_left_while(struct strv *sv, _Bool (*cb)(char))
-{
-    int i = 0;
-    while ((i < sv->count) && cb(sv->data[i]))
-        i += 1;
-    return strv_chop_left(sv, i);
-}
-
-static struct strv
-strv_take_left_while(struct strv sv, _Bool (*cb)(char))
-{
-    int i = 0;
-    while ((i < sv.count) && cb(sv.data[i]))
-        i += 1;
-    return strv_from_slice(sv.data, i);
-}
-
-static int
-strv_len(struct strv sv)
-{
-    return sv.count;
-}
-
-static struct strv
-strv_copy(const struct strv sv)
-{
-    return (struct strv){ .data = sv.data, .count = sv.count };
-}
-
-static int
-strv_to_int(const struct strv sv_init)
-{
-    if (strv_len(sv_init) == 0)
-        return 0;
-
-    int total            = 0;
-    struct strv sv       = strv_copy(sv_init);
-    const _Bool negative = strv_chop_left(&sv, 1).data[0] == '-';
-
-    for (int i = 0; i < sv.count; ++i)
-        total = (total * 10) + (sv.data[i] - '0');
-
-    return (negative) ? -1 * total : total;
-}
+struct strv strv_trim(struct strv sv);
+
+struct strv strv_chop_left(struct strv *sv, int n);
+
+struct strv strv_chop_right(struct strv *sv, int n);
+
+_Bool strv_index_of(struct strv sv, char c, int *index);
+
+_Bool strv_try_chop_by_delim(struct strv *sv, char delim, struct strv *chunk);
+
+struct strv strv_chop_by_delim(struct strv *sv, char delim);
+
+_Bool strv_starts_with(struct strv sv, struct strv expected_prefix);
+
+_Bool strv_ends_with(struct strv sv, struct strv expected_suffix);
+
+_Bool strv_equal(struct strv a, struct strv b);
+
+_Bool strv_equal_nocase(struct strv a, struct strv b);
+
+struct strv strv_chop_left_while(struct strv *sv, _Bool (*cb)(char));
+
+struct strv strv_take_left_while(struct strv sv, _Bool (*cb)(char));
+
+int strv_len(struct strv sv);
+
+struct strv strv_copy(const struct strv sv);
+
+int strv_to_int(const struct strv sv_init);
diff --git a/inc/lektor/net.h b/inc/lektor/net.h
index 82d31f00..3005f427 100644
--- a/inc/lektor/net.h
+++ b/inc/lektor/net.h
@@ -37,8 +37,8 @@ struct lkt_message;
 
 /* Create a message structure. */
 struct lkt_message *lkt_message_new(void);
-struct lkt_message *lkt_message_new_str(const char *restrict msg);
-struct lkt_message *lkt_message_new_fmt(const char *restrict fmt, ...);
+struct lkt_message *lkt_message_new_str(const char * msg);
+struct lkt_message *lkt_message_new_fmt(const char * fmt, ...);
 struct lkt_message *lkt_message_clone(struct lkt_message *msg);
 
 /* Destruct a message structure. */
diff --git a/inc/lektor/queue.h b/inc/lektor/queue.h
index 508cdb99..2d395149 100644
--- a/inc/lektor/queue.h
+++ b/inc/lektor/queue.h
@@ -72,110 +72,21 @@ struct queue {
 
 /* Initialize the queue. Can't fail if the passed argument is not NULL.
  * WARN: In case of out of memory this function will abort the process. */
-PRIVATE_FUNCTION int
-lkt_queue_new(struct queue *ret)
-{
-    if (!ret)
-        return 1;
-
-    pthread_mutex_t mxt = PTHREAD_MUTEX_INITIALIZER;
-    struct queue _ret   = {
-          .contents  = LKT_ALLOC_ARRAY(lkt_event, LKT_DEFAULT_LIST_SIZE),
-          .size      = LKT_DEFAULT_LIST_SIZE,
-          .last      = 0,
-          .available = 0,
-          .lock      = mxt,
-    };
-
-    *ret = _ret;
-    return 0;
-}
+int lkt_queue_new(struct queue *ret);
 
 /* Free the queue. Can't fail. */
-PRIVATE_FUNCTION void
-lkt_queue_free(struct queue *queue)
-{
-    pthread_mutex_lock(&queue->lock);
-    if (queue && queue->contents)
-        free((void *)queue->contents);
-    pthread_mutex_unlock(&queue->lock);
-}
+void lkt_queue_free(struct queue *queue);
 
 /* Is an event of the following type present in the queue?
  * Returns 0 if the type is not present, 1 otherwise. */
-PRIVATE_FUNCTION bool
-lkt_queue_has_event(struct queue *queue, LKT_EVENT_TYPE type)
-{
-    bool ret = false;
-    pthread_mutex_lock(&queue->lock);
-    for (size_t i = 0; i < queue->last; ++i) {
-        if (queue->contents[i].type & type) {
-            ret = true;
-            break;
-        }
-    }
-    pthread_mutex_unlock(&queue->lock);
-    return ret;
-}
+bool lkt_queue_has_event(struct queue *queue, LKT_EVENT_TYPE type);
 
 /* Send an event into the queue */
-PRIVATE_FUNCTION void
-lkt_queue_send(struct queue *queue, LKT_EVENT_TYPE _type, void *_attr)
-{
-    pthread_mutex_lock(&queue->lock);
-    GOTO_UNLESS(queue, "Invalid argument", end)
-
-    volatile lkt_event *new;
-    if (queue->size == queue->last) {
-        new = realloc((void *)queue->contents, queue->size * 2 * sizeof(lkt_event));
-
-        if (NULL == new)
-            goto end;
-
-        queue->contents = new;
-        queue->size *= 2;
-    }
-
-    lkt_event evt = {
-        .type = _type,
-        .attr = _attr,
-    };
-    queue->contents[(queue->last)++] = evt;
-
-    if (!(_type & (unsigned int)queue->available))
-        LOG_WARN("QUEUE", "The event %d is not available, push it anyway", _type);
-end:
-    pthread_mutex_unlock(&queue->lock);
-}
+void lkt_queue_send(struct queue *queue, LKT_EVENT_TYPE _type, void *_attr);
 
-PRIVATE_FUNCTION lkt_event
-lkt_queue_handle(struct queue *queue)
-{
-    pthread_mutex_lock(&queue->lock);
-    lkt_event ret = { 0 };
-    if (!queue || !queue->last)
-        goto end;
-    if (!(queue->contents[0].type & (unsigned int)queue->available) && queue->contents[0].type) {
-        LOG_WARN("QUEUE", "Event %d is not available", queue->contents[0].type);
-        goto end;
-    }
-
-    ret = queue->contents[0];
-    for (size_t i = 1; i < queue->last; ++i)
-        queue->contents[i - 1] = queue->contents[i];
-    queue->last -= 1;
-end:
-    pthread_mutex_unlock(&queue->lock);
-    return ret;
-}
+lkt_event lkt_queue_handle(struct queue *queue);
 
-PRIVATE_FUNCTION void
-lkt_queue_make_available(struct queue *queue, LKT_EVENT_TYPE type)
-{
-    pthread_mutex_lock(&queue->lock);
-    queue->available |= type;
-    pthread_mutex_unlock(&queue->lock);
-}
+void lkt_queue_make_available(struct queue *queue, LKT_EVENT_TYPE type);
 
 #if defined(__cplusplus)
 }
diff --git a/src/base/os.c b/src/base/os.c
index a18c9bad..9c91f2e4 100644
--- a/src/base/os.c
+++ b/src/base/os.c
@@ -22,7 +22,7 @@ lkt_thread_set_name(const char *name)
 {
     const size_t len = strlen(name);
     if (len >= 16) {
-        LOG_FATAL("The name should at least be a 15 character string! Here the length is %zu", len);
+        LOG_FATAL("The name should at most be a 15 character string! Here the length is %zu", len);
     }
 
 #if defined(__linux__)
diff --git a/src/database/queue.c b/src/database/queue.c
index 6d3fce9b..b8f5007d 100644
--- a/src/database/queue.c
+++ b/src/database/queue.c
@@ -1,3 +1,4 @@
+#include <lektor/queue.h>
 #include <lektor/common.h>
 #include <lektor/database.h>
 #include <lektor/mkv.h>
@@ -1176,3 +1177,110 @@ error:
     SQLITE_DO_ROLLBACK(db);
     return false;
 }
+
+/* Initialize the queue. Can't fail if the passed argument is not NULL.
+ * WARN: In case of out of memory this function will abort the process. */
+int
+lkt_queue_new(struct queue *ret)
+{
+    if (!ret)
+        return 1;
+
+    pthread_mutex_t mxt = PTHREAD_MUTEX_INITIALIZER;
+    struct queue _ret   = {
+          .contents  = LKT_ALLOC_ARRAY(lkt_event, LKT_DEFAULT_LIST_SIZE),
+          .size      = LKT_DEFAULT_LIST_SIZE,
+          .last      = 0,
+          .available = 0,
+          .lock      = mxt,
+    };
+
+    *ret = _ret;
+    return 0;
+}
+
+/* Free the queue. Can't fail. */
+void
+lkt_queue_free(struct queue *queue)
+{
+    pthread_mutex_lock(&queue->lock);
+    if (queue && queue->contents)
+        free((void *)queue->contents);
+    pthread_mutex_unlock(&queue->lock);
+}
+
+/* Is an event of the following type present in the queue?
+ * Returns 0 if the type is not present, 1 otherwise. */
+bool
+lkt_queue_has_event(struct queue *queue, LKT_EVENT_TYPE type)
+{
+    bool ret = false;
+    pthread_mutex_lock(&queue->lock);
+    for (size_t i = 0; i < queue->last; ++i) {
+        if (queue->contents[i].type & type) {
+            ret = true;
+            break;
+        }
+    }
+    pthread_mutex_unlock(&queue->lock);
+    return ret;
+}
+
+/* Send an event into the queue */
+void
+lkt_queue_send(struct queue *queue, LKT_EVENT_TYPE _type, void *_attr)
+{
+    pthread_mutex_lock(&queue->lock);
+    GOTO_UNLESS(queue, "Invalid argument", end)
+
+    volatile lkt_event *new;
+    if (queue->size == queue->last) {
+        new = realloc((void *)queue->contents, queue->size * 2 * sizeof(lkt_event));
+
+        if (NULL == new)
+            goto end;
+
+        queue->contents = new;
+        queue->size *= 2;
+    }
+
+    lkt_event evt = {
+        .type = _type,
+        .attr = _attr,
+    };
+    queue->contents[(queue->last)++] = evt;
+
+    if (!(_type & (unsigned int)queue->available))
+        LOG_WARN("QUEUE", "The event %d is not available, push it anyway", _type);
+end:
+    pthread_mutex_unlock(&queue->lock);
+}
+
+lkt_event
+lkt_queue_handle(struct queue *queue)
+{
+    pthread_mutex_lock(&queue->lock);
+    lkt_event ret = { 0 };
+    if (!queue || !queue->last)
+        goto end;
+    if (!(queue->contents[0].type & (unsigned int)queue->available) && queue->contents[0].type) {
+        LOG_WARN("QUEUE", "Event %d is not available", queue->contents[0].type);
+        goto end;
+    }
+
+    ret = queue->contents[0];
+    for (size_t i = 1; i < queue->last; ++i)
+        queue->contents[i - 1] = queue->contents[i];
+    queue->last -= 1;
+end:
+    pthread_mutex_unlock(&queue->lock);
+    return ret;
+}
+
+void
+lkt_queue_make_available(struct queue *queue, LKT_EVENT_TYPE type)
+{
+    pthread_mutex_lock(&queue->lock);
+    queue->available |= type;
+    pthread_mutex_unlock(&queue->lock);
+}
diff --git a/src/lib/strv.c b/src/lib/strv.c
new file mode 100644
index 00000000..818350da
--- /dev/null
+++ b/src/lib/strv.c
@@ -0,0 +1,262 @@
+#include <lektor/lib/strv.h>
+
+char
+strv_ctoupper(char s)
+{
+    return (('a' <= s) && (s <= 'z')) ? 'A' + (s - 'a') : s;
+}
+
+char
+strv_ctolower(char s)
+{
+    return (('A' <= s) && (s <= 'Z')) ? 'a' + (s - 'A') : s;
+}
+
+_Bool
+strv_memcmp(const void *ptr2, const void *ptr1, int count)
+{
+    register const unsigned char *s1 = (const unsigned char *)ptr1;
+    register const unsigned char *s2 = (const unsigned char *)ptr2;
+
+    while (count-- > 0) {
+        if (*s1++ != *s2++)
+            return (_Bool)0;
+    }
+
+    return (_Bool)1;
+}
+
+_Bool
+strv_isspace(char x)
+{
+    return x == ' ' || x == '\t' || x == '\n' || x == '\r' || x == '\v' || x == '\f';
+}
+
+int
+strv_strlen(const char *str)
+{
+    int len = 0;
+    while (str[len]) {
+        len += 1;
+
+        /* Try to avoid overflows */
+        if (len == __INT_MAX__)
+            return 0;
+    }
+    return len;
+}
+
+struct strv
+strv_from_slice(const char *data, int count)
+{
+    struct strv sv;
+    sv.count = count;
+    sv.data  = data;
+    return sv;
+}
+
+struct strv
+strv_from_str(const char *cstr)
+{
+    return strv_from_slice(cstr, strv_strlen(cstr));
+}
+
+_Bool
+strv_as_str(const struct strv sv, char *data, int len)
+{
+    if (sv.count >= len)
+        return (_Bool)0;
+
+    for (int i = 0; i < sv.count; ++i)
+        data[i] = sv.data[i];
+    data[sv.count] = '\0';
+
+    return (_Bool)1;
+}
+
+struct strv
+strv_trim_l(struct strv sv)
+{
+    int i = 0;
+    while ((i < sv.count) && strv_isspace(sv.data[i]))
+        i += 1;
+    return strv_from_slice(sv.data + i, sv.count - i);
+}
+
+struct strv
+strv_trim_r(struct strv sv)
+{
+    int i = 0;
+    while ((i < sv.count) && strv_isspace(sv.data[sv.count - 1 - i]))
+        i += 1;
+    return strv_from_slice(sv.data, sv.count - i);
+}
+
+struct strv
+strv_trim(struct strv sv)
+{
+    return strv_trim_r(strv_trim_l(sv));
+}
+
+struct strv
+strv_chop_left(struct strv *sv, int n)
+{
+    if (n > sv->count)
+        n = sv->count;
+
+    struct strv result = strv_from_slice(sv->data, n);
+    sv->data += n;
+    sv->count -= n;
+    return result;
+}
+
+struct strv
+strv_chop_right(struct strv *sv, int n)
+{
+    if (n > sv->count)
+        n = sv->count;
+
+    struct strv result = strv_from_slice(sv->data + sv->count - n, n);
+    sv->count -= n;
+    return result;
+}
+
+_Bool
+strv_index_of(struct strv sv, char c, int *index)
+{
+    int i = 0;
+    while (i < sv.count && sv.data[i] != c)
+        i += 1;
+
+    if (i < sv.count) {
+        if (index)
+            *index = i;
+        return (_Bool)1;
+    }
+
+    else
+        return (_Bool)0;
+}
+
+_Bool
+strv_try_chop_by_delim(struct strv *sv, char delim, struct strv *chunk)
+{
+    int i = 0;
+    while (i < sv->count && sv->data[i] != delim)
+        i += 1;
+
+    struct strv result = strv_from_slice(sv->data, i);
+
+    if (i < sv->count) {
+        i += 1;
+        sv->count -= i;
+        sv->data += i;
+        if (chunk)
+            *chunk = result;
+        return (_Bool)1;
+    }
+
+    return (_Bool)0;
+}
+
+struct strv
+strv_chop_by_delim(struct strv *sv, char delim)
+{
+    int i = 0;
+    while (i < sv->count && sv->data[i] != delim)
+        i += 1;
+
+    const struct strv result = strv_from_slice(sv->data, i);
+    i += (i < sv->count);
+    sv->count -= i;
+    sv->data += i;
+
+    return result;
+}
+
+_Bool
+strv_starts_with(struct strv sv, struct strv expected_prefix)
+{
+    if (expected_prefix.count <= sv.count) {
+        const struct strv actual_prefix = strv_from_slice(sv.data, expected_prefix.count);
+        return strv_equal(expected_prefix, actual_prefix);
+    }
+
+    return (_Bool)0;
+}
+
+_Bool
+strv_ends_with(struct strv sv, struct strv expected_suffix)
+{
+    if (expected_suffix.count <= sv.count) {
+        const struct strv actual_suffix =
+            strv_from_slice(sv.data + sv.count - expected_suffix.count, expected_suffix.count);
+        return strv_equal(expected_suffix, actual_suffix);
+    }
+
+    return (_Bool)0;
+}
+
+_Bool
+strv_equal(struct strv a, struct strv b)
+{
+    return (a.count != b.count) ? (_Bool)0 : strv_memcmp(a.data, b.data, a.count);
+}
+
+_Bool
+strv_equal_nocase(struct strv a, struct strv b)
+{
+    if (a.count != b.count)
+        return (_Bool)0;
+    for (int i = 0; i < a.count; ++i) {
+        if (strv_ctoupper(a.data[i]) != strv_ctoupper(b.data[i]))
+            return (_Bool)0;
+    }
+    return (_Bool)1;
+}
+
+struct strv
+strv_chop_left_while(struct strv *sv, _Bool (*cb)(char))
+{
+    int i = 0;
+    while ((i < sv->count) && cb(sv->data[i]))
+        i += 1;
+    return strv_chop_left(sv, i);
+}
+
+struct strv
+strv_take_left_while(struct strv sv, _Bool (*cb)(char))
+{
+    int i = 0;
+    while ((i < sv.count) && cb(sv.data[i]))
+        i += 1;
+    return strv_from_slice(sv.data, i);
+}
+
+int
+strv_len(struct strv sv)
+{
+    return sv.count;
+}
+
+struct strv
+strv_copy(const struct strv sv)
+{
+    return (struct strv){ .data = sv.data, .count = sv.count };
+}
+
+int
+strv_to_int(const struct strv sv_init)
+{
+    if (strv_len(sv_init) == 0)
+        return 0;
+
+    int total            = 0;
+    struct strv sv       = strv_copy(sv_init);
+    const _Bool negative = strv_chop_left(&sv, 1).data[0] == '-';
+
+    for (int i = 0; i < sv.count; ++i)
+        total = (total * 10) + (sv.data[i] - '0');
+
+    return (negative) ? -1 * total : total;
+}
diff --git a/src/main/server.c b/src/main/server.c
index 71bf99dd..6891835c 100644
--- a/src/main/server.c
+++ b/src/main/server.c
@@ -17,6 +17,7 @@
 
 #if defined(LKT_STATIC_MODULE)
 REG_DECLARE(sdl2_reg)
+REG_DECLARE(qt_window_reg)
 REG_DECLARE(repo_reg)
 #endif
 
@@ -39,6 +40,7 @@ main(int argc, char *argv[])
 #if defined(LKT_STATIC_MODULE)
     REG_REGISTER("repo", repo_reg)
     REG_REGISTER("sdl2", sdl2_reg)
+    REG_REGISTER("qt_window", qt_window_reg)
 #endif
     REG_END()
 
diff --git a/src/module/module_qt_window.c b/src/module/module_qt_window.c
index 0284b0ed..b542f099 100644
--- a/src/module/module_qt_window.c
+++ b/src/module/module_qt_window.c
@@ -1,10 +1,13 @@
 #define __LKT_MODULE_MAIN_SOURCE__
+#include "module_qt_window.h"
 #include <lektor/lktmodule.h>
-#include "qt_window/mpvwidget_interface.h"
 
-struct module_qt_window_s {
-    MpvWidget* mpv_widget;
-};
+#include "mpv.h"
+#include "thread.h"
+
+#include <sched.h>
+
+#include "qt_window/mpvwidget_interface.h"
 
 /************************
  * Function definitions *
@@ -88,13 +91,22 @@ module_qt_window_new(struct module_qt_window_s **win, struct queue *queue, lkt_d
     (void)mod_free;
     (void)mod_close;
     RETURN_UNLESS(win, "Invalid arguments", false);
+    struct poller_thread_arg *arg;
 
     if (*win == NULL) {
-        *win = (struct module_qt_window_s*)calloc(1, sizeof(struct module_qt_window_s));
+        *win = calloc(1, sizeof(struct module_qt_window_s));
         RETURN_UNLESS(*win, "Out of memory", false);
         memset(*win, 0, sizeof(struct module_qt_window_s));
 
-        (*win)->mpv_widget = ___create_mpv_widget(queue, db);
+        (*win)->queue               = queue;
+        (*win)->db                  = db;
+        (*win)->is_in_preparation   = true;
+
+        arg = LKT_ALLOC_STRUCT(poller_thread_arg);
+        RETURN_UNLESS(arg, "Out of memory", false);
+        arg->args = *win;
+        RETURN_IF(poller_new(&(*win)->self, ___create_mpv_widget, arg), "Failed to launch the SDL thread",
+                  false);
     }
 
     return true;
diff --git a/src/module/module_qt_window.h b/src/module/module_qt_window.h
new file mode 100644
index 00000000..acdd44d9
--- /dev/null
+++ b/src/module/module_qt_window.h
@@ -0,0 +1,31 @@
+#ifndef __LKT_MODULE_QT_WINDOW_H__
+#define __LKT_MODULE_QT_WINDOW_H__
+
+#if defined( __cplusplus)
+extern "C" {
+class MpvWidget;
+#else
+typedef struct MpvWidget MpvWidget;
+#endif
+
+#include <lektor/common.h>
+#include "thread.h"
+
+struct module_qt_window_s {
+    MpvWidget* mpv_widget;
+
+    /* Thread related */
+    struct poller_thread self;
+    volatile int launched;                /* SDL you sucks */
+    volatile bool is_in_preparation;      /* Inside the MPV & SDL init */
+    volatile bool has_preparation_failed; /* The init failed */
+
+    /* Things from the server */
+    struct queue *queue;
+    lkt_db *db;
+};
+
+#if defined(__cplusplus)
+}
+#endif
+#endif // __LKT_MODULE_QT_WINDOW_H__
diff --git a/src/module/qt_window/mpvwidget.hh b/src/module/qt_window/mpvwidget.hh
index 54a1f997..92b2ab99 100644
--- a/src/module/qt_window/mpvwidget.hh
+++ b/src/module/qt_window/mpvwidget.hh
@@ -6,7 +6,9 @@
 #include <mpv/render_gl.h>
 #include <QtGui>
 
+extern "C" {
 #include <lektor/common.h>
+}
 
 class MpvWidget Q_DECL_FINAL: public QOpenGLWidget
 {
diff --git a/src/module/qt_window/mpvwidget_interface.cpp b/src/module/qt_window/mpvwidget_interface.cpp
index 5c6cd9c8..a257c610 100644
--- a/src/module/qt_window/mpvwidget_interface.cpp
+++ b/src/module/qt_window/mpvwidget_interface.cpp
@@ -1,7 +1,19 @@
 #include "mpvwidget_interface.h"
 #include "mpvwidget.hh"
 
-MpvWidget*
-___create_mpv_widget(struct queue *queue, lkt_db* db){
-    return new MpvWidget(queue, db);
+#include <QApplication>
+
+void*
+___create_mpv_widget(struct poller_thread_arg *arg){
+    lkt_thread_set_name("lektord/qt-win");
+
+    struct module_qt_window_s* qt_window = (struct module_qt_window_s*)arg->args;
+
+    int argc = 0;
+    QApplication a(argc, NULL);
+    setlocale(LC_NUMERIC, "C");
+    qt_window->mpv_widget = new MpvWidget(qt_window->queue, qt_window->db);
+    qt_window->mpv_widget->show();
+    a.exec();
+    return NULL;
 }
diff --git a/src/module/qt_window/mpvwidget_interface.h b/src/module/qt_window/mpvwidget_interface.h
index fa62dd73..2d85855e 100644
--- a/src/module/qt_window/mpvwidget_interface.h
+++ b/src/module/qt_window/mpvwidget_interface.h
@@ -3,16 +3,14 @@
 
 #if defined( __cplusplus)
 extern "C" {
-class MpvWidget;
-#else
-typedef struct MpvWidget MpvWidget;
 #endif
 
 #include <lektor/common.h>
+#include "../module_qt_window.h"
 
-MpvWidget* ___create_mpv_widget(struct queue *queue, lkt_db* db);
+void * ___create_mpv_widget(struct poller_thread_arg *arg);
 
-#ifdef __cplusplus
+#if defined(__cplusplus)
 }
 #endif
-#endif
+#endif // __LKT_MODULE_QT_WINDOW_MPVWIDGET_INTERFACE_H__
diff --git a/src/module/thread.c b/src/module/thread.c
new file mode 100644
index 00000000..ce4086b8
--- /dev/null
+++ b/src/module/thread.c
@@ -0,0 +1,81 @@
+#include "thread.h"
+
+void *
+___poller_thread_start(void *args__)
+{
+    struct ___poller_thread_args *args         = (struct ___poller_thread_args *)args__;
+    void *(*start)(struct poller_thread_arg *) = args->start;
+    struct poller_thread_arg *arg              = args->arg;
+    free(args__);
+    return start(arg);
+}
+
+UNUSED int
+poller_new(struct poller_thread *th, void *(*func)(struct poller_thread_arg *), void *args)
+{
+    pthread_mutex_t mtx1     = PTHREAD_MUTEX_INITIALIZER;
+    pthread_mutex_t mtx2     = PTHREAD_MUTEX_INITIALIZER;
+    struct poller_thread th_ = {
+        .input_lock  = mtx1,
+        .output_lock = mtx2,
+    };
+
+    stack_new(&th_.input);
+    stack_new(&th_.output);
+
+    struct ___poller_thread_args *__args;
+    *th               = th_;
+    __args            = LKT_ALLOC_STRUCT(___poller_thread_args);
+    __args->start     = func;
+    __args->arg       = args;
+    __args->arg->self = th;
+
+    if (pthread_create(&(th->th), NULL, ___poller_thread_start, __args)) {
+        LOG_ERROR("THREAD", "Failed to create a poller thread");
+        return 1;
+    }
+
+    LOG_INFO("THREAD", "Create a new poller thread");
+    return 0;
+}
+
+UNUSED int
+poller_join(struct poller_thread *th, void **ret)
+{
+    int sta = pthread_join(th->th, ret);
+    LOG_ERROR_IF(sta, "THREAD", "Failed to join thread");
+
+    stack_free(&th->input);
+    stack_free(&th->output);
+    LOG_WARN("THREAD", "Thread joined");
+
+    memset(th, 0, sizeof(struct poller_thread));
+    return sta;
+}
+
+UNUSED int
+th_append(struct stack *lst, pthread_mutex_t *lock, void *ptr)
+{
+    DO_WITH_LOCK(*lock, error, { stack_push(lst, ptr); });
+    return 0;
+error:
+    return 1;
+}
+
+UNUSED int
+th_pop(struct stack *lst, pthread_mutex_t *lock, void **ptr)
+{
+    RETURN_IF(pthread_mutex_lock(lock), "Failed to lock", 1);
+    int ret = stack_pop(lst, ptr);
+    RETURN_IF(pthread_mutex_unlock(lock), "Failed to lock", 1);
+    return ret;
+}
+
+UNUSED int
+th_head(struct stack *lst, pthread_mutex_t *lock, void **ptr)
+{
+    RETURN_IF(pthread_mutex_lock(lock), "Failed to lock", 1);
+    int ret = stack_head(lst, ptr);
+    RETURN_IF(pthread_mutex_unlock(lock), "Failed to lock", 1);
+    return ret;
+}
diff --git a/src/module/thread.h b/src/module/thread.h
index 5d20cbec..537ac63a 100644
--- a/src/module/thread.h
+++ b/src/module/thread.h
@@ -1,6 +1,10 @@
 #if !defined(__LKT_THREAD_H__)
 #define __LKT_THREAD_H__
 
+#if defined( __cplusplus)
+extern "C" {
+#endif
+
 #include <lektor/lktmodule.h>
 #include <lektor/common.h>
 #include <sys/types.h>
@@ -28,85 +32,17 @@ struct ___poller_thread_args {
     struct poller_thread_arg *arg;
 };
 
-static void *
-___poller_thread_start(void *args__)
-{
-    struct ___poller_thread_args *args         = (struct ___poller_thread_args *)args__;
-    void *(*start)(struct poller_thread_arg *) = args->start;
-    struct poller_thread_arg *arg              = args->arg;
-    free(args__);
-    return start(arg);
-}
-
-UNUSED static int
-poller_new(struct poller_thread *th, void *(*func)(struct poller_thread_arg *), void *args)
-{
-    pthread_mutex_t mtx1     = PTHREAD_MUTEX_INITIALIZER;
-    pthread_mutex_t mtx2     = PTHREAD_MUTEX_INITIALIZER;
-    struct poller_thread th_ = {
-        .input_lock  = mtx1,
-        .output_lock = mtx2,
-    };
-
-    stack_new(&th_.input);
-    stack_new(&th_.output);
+void * ___poller_thread_start(void *args__);
 
-    struct ___poller_thread_args *__args;
-    *th               = th_;
-    __args            = LKT_ALLOC_STRUCT(___poller_thread_args);
-    __args->start     = func;
-    __args->arg       = args;
-    __args->arg->self = th;
+UNUSED int poller_new(struct poller_thread *th, void *(*func)(struct poller_thread_arg *), void *args);
 
-    if (pthread_create(&(th->th), NULL, ___poller_thread_start, __args)) {
-        LOG_ERROR("THREAD", "Failed to create a poller thread");
-        return 1;
-    }
-
-    LOG_INFO("THREAD", "Create a new poller thread");
-    return 0;
-}
+UNUSED int poller_join(struct poller_thread *th, void **ret);
 
-UNUSED static int
-poller_join(struct poller_thread *th, void **ret)
-{
-    int sta = pthread_join(th->th, ret);
-    LOG_ERROR_IF(sta, "THREAD", "Failed to join thread");
+UNUSED int th_append(struct stack *lst, pthread_mutex_t *lock, void *ptr);
 
-    stack_free(&th->input);
-    stack_free(&th->output);
-    LOG_WARN("THREAD", "Thread joined");
+UNUSED int th_pop(struct stack *lst, pthread_mutex_t *lock, void **ptr);
 
-    memset(th, 0, sizeof(struct poller_thread));
-    return sta;
-}
-
-UNUSED static int
-th_append(struct stack *lst, pthread_mutex_t *lock, void *ptr)
-{
-    DO_WITH_LOCK(*lock, error, { stack_push(lst, ptr); });
-    return 0;
-error:
-    return 1;
-}
-
-UNUSED static int
-th_pop(struct stack *lst, pthread_mutex_t *lock, void **ptr)
-{
-    RETURN_IF(pthread_mutex_lock(lock), "Failed to lock", 1);
-    int ret = stack_pop(lst, ptr);
-    RETURN_IF(pthread_mutex_unlock(lock), "Failed to lock", 1);
-    return ret;
-}
-
-UNUSED static int
-th_head(struct stack *lst, pthread_mutex_t *lock, void **ptr)
-{
-    RETURN_IF(pthread_mutex_lock(lock), "Failed to lock", 1);
-    int ret = stack_head(lst, ptr);
-    RETURN_IF(pthread_mutex_unlock(lock), "Failed to lock", 1);
-    return ret;
-}
+UNUSED int th_head(struct stack *lst, pthread_mutex_t *lock, void **ptr);
 
 #define __POLLER_ATOMICS_DEFINE(operation, inout, level)                                  \
     UNUSED static int poller_##operation##inout(struct poller_thread *th, void level ptr) \
@@ -123,4 +59,7 @@ __POLLER_ATOMICS_DEFINE(head,   output, **)
 // clang-format on
 #undef __POLLER_ATOMICS_DEFINE
 
+#if defined(__cplusplus)
+}
+#endif
 #endif /* __LKT_THREAD_H__ */
-- 
GitLab