diff --git a/inc/lektor/macro.h b/inc/lektor/macro.h index 5403ef8ce96f0ebf4efc9bc18e87c0aa8b056eec..05f99875ab0d7d83bdadecd05e5b248bf326c04c 100644 --- a/inc/lektor/macro.h +++ b/inc/lektor/macro.h @@ -38,3 +38,12 @@ #ifndef MIN #define MIN(a, b) ((a) > (b) ? (b) : (a)) #endif /* MIN */ + +#define RETURN_IF(cond, msg, ret) \ + if (cond) { \ + fprintf(stderr, " ! %s: %s\n", __func__, msg); \ + return ret; \ + } + +#define RETURN_UNLESS(cond, msg, ret) RETURN_IF(!(cond), msg, ret) +#define NOTHING /* Usefull to return nothing. */ diff --git a/src/module/module_sdl2.c b/src/module/module_sdl2.c index acbbf45ee7ce6c6ad01e9d247f5c48c966a5fecd..4c4fa4cb0dd703974b921078ace3f45ea17b3f36 100644 --- a/src/module/module_sdl2.c +++ b/src/module/module_sdl2.c @@ -1,7 +1,12 @@ +#define _POSIX_C_SOURCE 200809L + #include <lektor/module/module_sdl2.h> #include <lektor/module/mpv.h> #include <lektor/macro.h> #include <lektor/defines.h> +#include <lektor/thread.h> + +#include <sched.h> #include <string.h> #include <unistd.h> #include <stdlib.h> @@ -24,8 +29,97 @@ struct module_sdl2_window { 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 // + + /* Thread related */ + pthread_mutex_t mtx; + struct lkt_thread self; }; +/* Thread related functions */ + +static void * +sdl_thread__(struct lkt_thread_arg *arg) +{ + struct module_sdl2_window *sdl2 = win->window; + SDL_Event event; + uint64_t flags, redraw = 0; + int w, h; + if (sdl2 == NULL) + return false; + + /* SDL events won't change the database, only the mpv one's will. + Do this to be able to put the SDL stuff inside a thread and don't change + to much things. */ +loop: + if (!SDL_PollEvent(&event)) + sched_yield(); + + switch (event.type) { + case SDL_QUIT: + sched_yield(); + break; + + 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(sdl2->mpv, 0, cmd_pause); + } + break; + + case SDL_KEYUP: + if (event.key.keysym.sym == SDLK_F11) { + if (sdl2->is_fullscreen) { + SDL_SetWindowFullscreen(sdl2->window, 0); + sdl2->is_fullscreen = 0; + } else { + /* May use SDL_WINDOW_FULLSCREEN_DESKTOP, need to check. */ + SDL_SetWindowFullscreen(sdl2->window, SDL_WINDOW_FULLSCREEN); + sdl2->is_fullscreen = 1; + } + } + break; + + default: + if (event.type == wakeup_on_mpv_render_update) { + flags = mpv_render_context_update(sdl2->mpv_gl); + if (flags & MPV_RENDER_UPDATE_FRAME) + redraw = 1; + } + /* Handle mpv events. */ + if (event.type == wakeup_on_mpv_events) + lmpv_handle(win, sdl2->mpv, db, mpd_idle_events, (int *) &sdl2->mpv_time_pos, (int *) &sdl2->mpv_duration); + } + + if (redraw) { + SDL_GetWindowSize(sdl2->window, &w, &h); + /* 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 params[] = { { + 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(sdl2->mpv_gl, params); + SDL_GL_SwapWindow(sdl2->window); + redraw = 0; + } + goto loop; /* A loop without indentation. */ +} + /* Private functions. */ static Uint32 wakeup_on_mpv_render_update, wakeup_on_mpv_events; @@ -89,10 +183,7 @@ init_mpv__(mpv_handle **ctx) mpv_error_string(status)); return 1; } - if (!lmpv_observe_properties(*ctx)) { - fprintf(stderr, " ! init_mpv__: failed to observe properties\n"); - return 1; - } + RETURN_UNLESS(lmpv_observe_properties(*ctx), "Observe properties failed", 1); return 0; } @@ -124,8 +215,7 @@ init_mpv_gl__(mpv_handle *mpv, mpv_render_context **mpv_gl, mpv_render_param *pa bool module_sdl2_new(struct lkt_win *const win) { - if (win == NULL) - return false; + RETURN_UNLESS(win, "Invalid arguments", false); struct module_sdl2_window *sdl2 = win->window; @@ -138,6 +228,10 @@ module_sdl2_new(struct lkt_win *const win) return false; } + /* Yeah, this is how it is done. */ + pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; + sdl2->mtx = mtx; + /* CREATE THE SDL2 WINDOW TODO */ SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "no"); /* It seems that sdl sucks. */ if (SDL_Init(SDL_INIT_VIDEO) < 0) @@ -189,33 +283,31 @@ error: void module_sdl2_close(struct lkt_win *const win) { - if (win == NULL || win->window == NULL) - return; - struct module_sdl2_window *sdl2 = win->window; - mpv_render_context_free(sdl2->mpv_gl); - sdl2->mpv_gl = NULL; - lmpv_free(&sdl2->mpv); + /* TODO: stop mpv. */ + (void) win; } void module_sdl2_free(struct lkt_win *const win) { - module_sdl2_close(win); + RETURN_UNLESS(win && win->window, "Invalid arguments", NOTHING); + struct module_sdl2_window *sdl2 = win->window; + mpv_render_context_free(sdl2->mpv_gl); + sdl2->mpv_gl = NULL; + lmpv_free(&sdl2->mpv); } bool module_sdl2_toggle_pause(struct lkt_win *const win) { - if (win == NULL || win->window == NULL) - return false; + RETURN_UNLESS(win && win->window, "Invalid arguments", false); return ! lmpv_toggle_pause(((struct module_sdl2_window *) win->window)->mpv); } bool module_sdl2_load_file(struct lkt_win *const win, const char *filepath) { - if (win == NULL || win->window == NULL) - return false; + RETURN_UNLESS(win && win->window, "Invalid arguments", false); struct module_sdl2_window *sdl2 = win->window; bool ret = ! lmpv_load_file(sdl2->mpv, filepath); sdl2->mpv_duration = 0; @@ -226,16 +318,14 @@ module_sdl2_load_file(struct lkt_win *const win, const char *filepath) bool module_sdl2_set_volume(struct lkt_win *const win, int vol) { - if (win == NULL || win->window == NULL) - return false; + RETURN_UNLESS(win && win->window, "Invalid arguments", false); return ! lmpv_set_volume(((struct module_sdl2_window *) win->window)->mpv, vol); } bool module_sdl2_get_duration(struct lkt_win *const win, int *dur_sec) { - if (win == NULL || win->window == NULL) - return false; + RETURN_UNLESS(win && win->window, "Invalid arguments", false); *dur_sec = ((struct module_sdl2_window *) win->window)->mpv_duration; return true; } @@ -243,8 +333,7 @@ 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) { - if (win == NULL || win->window == NULL) - return false; + RETURN_UNLESS(win && win->window, "Invalid arguments", false); *elapsed_sec = ((struct module_sdl2_window *) win->window)->mpv_time_pos; return true; } diff --git a/src/module/module_x11.c b/src/module/module_x11.c index 6d51472fffc95478f01d4a54b17b195f5348658c..36787fd3c6726f4e8e68f26ba0cfa64ebfe5b323 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/macro.h> #include <lektor/module/mpv.h> #include <lektor/database.h> #include <lektor/commands.h> @@ -42,9 +43,7 @@ struct module_x11_window { extern int module_set_function(void *arg__, void *handle__) { - if (NULL == arg__ || handle__ == NULL) - return 1; - + RETURN_UNLESS(arg__ && handle__, "Invalid arguments", 1); struct lkt_win *win = (struct lkt_win *) arg__; win->new = module_x11_new; @@ -71,11 +70,7 @@ static inline bool lx11_new(struct module_x11_window *ret) { ret->master_display = XOpenDisplay(NULL); - if (ret->master_display == NULL) { - fprintf(stderr, " ! lkt_x11: can't open display\n"); - return false; - } - + 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); @@ -112,48 +107,12 @@ lx11_new(struct module_x11_window *ret) return true; } -static inline void -lx11_fullscreen(struct module_x11_window *win, bool go_fullscreen) -{ - if (go_fullscreen) { - XSizeHints *size_hints = XAllocSizeHints(); - long hints = 0; - - if (NULL == size_hints) { - fprintf(stderr, "lx11_fullscreen: failed to allocate size hints\n"); - return; - } - - if (XGetWMSizeHints(win->master_display, win->master_win, size_hints, &hints, - XInternAtom(win->master_display, "WM_SIZE_HINTS", False))) { - fprintf(stderr, " ! lx11_fullscreen: failed to get size hints\n"); - goto error; - } - - XLowerWindow(win->master_display, win->master_win); - XUnmapWindow(win->master_display, win->master_win); - XSync(win->master_display, False); - - fprintf(stderr, " . lx11_fullscreen: size hints is: %ld\n", hints); -error: - XFree(size_hints); - } - - Atom atoms[2] = { XInternAtom(win->master_display, "_NET_WM_STATE_FULLSCREEN", go_fullscreen), None }; - XChangeProperty(win->master_display, win->master_win, - XInternAtom(win->master_display, "_NET_WM_STATE", False), - XA_ATOM, 32, PropModeReplace, (const unsigned char *) atoms, 1); - XMapWindow(win->master_display, win->master_win); - XRaiseWindow(win->master_display, win->master_win); -} - static inline bool lx11_handle(struct module_x11_window *win) { XEvent event; - if (!win || !win->mpv) - return true; + RETURN_UNLESS(win && win->mpv, "Invalid argument", true); for (;;) { @@ -184,9 +143,6 @@ lx11_handle(struct module_x11_window *win) // Key press if (event.type == KeyRelease) { fprintf(stderr, " . lx11_handle: released key with keycode: 0x%x\n", event.xkey.keycode); - // if (event.xkey.keycode == 0x5f) - // lx11_fullscreen(win, true); - // if (event.xkey.keycode == 0x47) XClearWindow(win->master_display, win->master_win); } @@ -205,13 +161,6 @@ lx11_handle(struct module_x11_window *win) return true; } -/* - * - * NOW: PRIVATE MPV FUNCTIONS :NOW - * - */ - - /* * * NOW: THE SETTED FUNCTIONS FOR THE WINDOW MODULE :NOW @@ -221,34 +170,20 @@ lx11_handle(struct module_x11_window *win) bool module_x11_new(struct lkt_win *const win) { - (void) lx11_fullscreen; - - if (win == NULL) - return false; - + 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)); - - if (x11_win == NULL) { - fprintf(stderr, " ! module_x11_window: failed to allocate window, no memory\n"); - return false; - } - - if (!lx11_new(x11_win)) { - fprintf(stderr, " ! module_x11_window: failed to create the X11 window\n"); - return false; - } - + RETURN_UNLESS(x11_win, "Out of memory", false); + RETURN_UNLESS(lx11_new(x11_win), "Can't create X11 window", false); fprintf(stderr, " . module_x11_window: successfully created the X11 window\n"); } if (x11_win->mpv == NULL) { x11_win->mpv = lmpv_new(x11_win->master_win); - if (x11_win->mpv == NULL) - return false; + RETURN_UNLESS(x11_win->mpv, "Failed to create mpv", false); } win->window = x11_win; @@ -258,8 +193,7 @@ module_x11_new(struct lkt_win *const win) void module_x11_close(struct lkt_win *const win) { - if (win == NULL || win->window == NULL) - return; + 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; @@ -269,34 +203,25 @@ module_x11_close(struct lkt_win *const win) void module_x11_free(struct lkt_win *const win) { - if (win == NULL || win->window == NULL) - return; - + RETURN_UNLESS(win && win->window, "Invalid arguments", NOTHING); struct module_x11_window *const x11_win = win->window; lmpv_free(&x11_win->mpv); - - if (win == NULL) - return; - XCloseDisplay(x11_win->master_display); free(x11_win); - win->window = NULL; } bool module_x11_toggle_pause(struct lkt_win *const win) { - if (win == NULL || win->window == NULL) - return false; + 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) { - if (win == NULL || win->window == NULL) - return false; + 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; @@ -307,16 +232,14 @@ module_x11_load_file(struct lkt_win *const win, const char *filepath) bool module_x11_set_volume(struct lkt_win *const win, int vol) { - if (win == NULL || win->window == NULL) - return false; + 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) { - if (win == NULL || win->window == NULL) - return false; + RETURN_UNLESS(win && win->window, "Invalid arguments", false); struct module_x11_window *win_x11 = win->window; *dur_sec = win_x11->mpv_duration; return true; @@ -325,8 +248,7 @@ 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) { - if (win == NULL || win->window == NULL) - return false; + 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; @@ -335,8 +257,7 @@ module_x11_get_elapsed(struct lkt_win *const win, int *elapsed_sec) bool module_x11_handle_events(struct lkt_win *const win, sqlite3 *db, enum mpd_idle_flag *mpd_idle_events) { - if (win == NULL || win->window == NULL) - return false; + 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, (int *) &xwin->mpv_time_pos, diff --git a/src/module/mpv.c b/src/module/mpv.c index c9e9d2e633bf0c2483c101633a9c37eb1e4b2c7a..7da8819800501cc5ecf3b34ca824169c9667ca8d 100644 --- a/src/module/mpv.c +++ b/src/module/mpv.c @@ -1,6 +1,7 @@ #include <lektor/module/mpv.h> #include <lektor/commands.h> #include <lektor/database.h> +#include <lektor/macro.h> #include <stdio.h> #include <string.h> #include <unistd.h> @@ -9,11 +10,7 @@ void lmpv_free(mpv_handle **ctx) { - if (!*ctx) { - fprintf(stderr, " ! lmpv_free: failed due to missing mpv ctx\n"); - return; - } - + RETURN_UNLESS(ctx, "Missing mpv ctx", NOTHING); static const char *cmd[] = {"quit", NULL}; mpv_command(*ctx, cmd); mpv_destroy(*ctx); @@ -26,54 +23,22 @@ 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 low-latency: %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_UNLESS(ctx, "Failed to create context", NULL); + +#define MPV_SET_OPTION(opt, value) \ + if ((status = mpv_set_option_string(ctx, opt, value)) < 0) { \ + fprintf(stderr, " . %s: Failed to set %s to %s: %s\n", \ + __func__, opt, value, mpv_error_string(status)); \ + return NULL; \ + } + + MPV_SET_OPTION("input-default-bindings", "yes"); + MPV_SET_OPTION("input-vo-keyboard", "yes"); + MPV_SET_OPTION("replaygain", "track"); + MPV_SET_OPTION("gpu-context", "x11"); + MPV_SET_OPTION("demuxer-max-bytes", "10M"); + MPV_SET_OPTION("profile", "low-latency"); + MPV_SET_OPTION("hwdec", "yes"); return ctx; } @@ -119,17 +84,12 @@ error: int lmpv_set_volume(mpv_handle *ctx, int vol) { - if (!ctx) { - fprintf(stderr, " ! lmpv_set_volume: failed due to missing mpv ctx\n"); - return 1; - } - + RETURN_UNLESS(ctx, "Missing mpv ctx", 1); 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_async(ctx, 0, cmd)) < 0) { fprintf(stderr, " ! lmpv_set_volume: Failed to execute command: %s\n", mpv_error_string(status)); @@ -141,19 +101,10 @@ lmpv_set_volume(mpv_handle *ctx, int vol) int lmpv_load_file(mpv_handle *ctx, const char *file) { - if (!ctx) { - fprintf(stderr, " ! lmpv_load_file: failed due to missing mpv ctx\n"); - return 1; - } - - if (access(file, R_OK)) { - fprintf(stderr, " ! lmpv_load_file: Faild to read file: %s\n", file); - return 1; - } - + RETURN_UNLESS(ctx, "Missing mpv ctx", 1); + RETURN_IF(access(file, R_OK), "Failed to read file", 1); const char *cmd[] = {"loadfile", file, "replace", NULL}; int status; - if ((status = mpv_command_async(ctx, 0, cmd)) < 0) { fprintf(stderr, " ! lmpv_load_file: Failed to add '%s': %s\n", file, mpv_error_string(status)); @@ -165,14 +116,9 @@ lmpv_load_file(mpv_handle *ctx, const char *file) int lmpv_toggle_pause(mpv_handle *ctx) { - if (!ctx) { - fprintf(stderr, " ! lmpv_toggle_pause: failed due to missing mpv ctx\n"); - return 1; - } - + RETURN_UNLESS(ctx, "Missing mpv ctx", 1); const char *cmd[] = {"cycle", "pause", "up", NULL}; int status; - if ((status = mpv_command_async(ctx, 0, cmd)) < 0) { fprintf(stderr, "lmpv_toggle_pause: Failed issue command: %s\n", mpv_error_string(status)); @@ -185,16 +131,12 @@ int lmpv_handle(struct lkt_win *win, mpv_handle *ctx, sqlite3 *db, enum mpd_idle_flag *mpd_idle_events, int *time_pos, int *time_duration) { - int ao_volume, sta = 1; + int ao_volume; struct lkt_queue_state state; mpv_event *event = NULL; mpv_event_property *prop; - - if (!ctx || !win) - goto end; - - if (!database_queue_state(db, &state)) - goto end; + RETURN_UNLESS(ctx && win, "Invalid argument", 1); + RETURN_UNLESS(database_queue_state(db, &state), "Failed to get queue state", 1); loop: event = mpv_wait_event(ctx, 0); @@ -208,10 +150,10 @@ loop: case MPV_EVENT_SHUTDOWN: database_queue_stop(db); win->close(win); - goto end; + return 1; case MPV_EVENT_NONE: - goto end; + return 1; case MPV_EVENT_IDLE: if (state.current > 0 && *time_pos > 0) @@ -249,7 +191,4 @@ loop: break; } goto loop; /* A loop without indentation. */ - sta = 0; -end: - return sta; }