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 **) ®[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; } -