Skip to content
Extraits de code Groupes Projets
Sélectionner une révision Git
  • 29e4e2afaca94f8cc50ebe8c0a615c93fafab008
  • develop par défaut protégée
  • implement-discord-markdown-update
  • matrix-attachments-order-fix
  • fix-oversized-file-transfer
  • matrix-attachment-order-fix
  • matrix-answer-modified-fix
  • cherry-pick-moise
8 résultats

matrixcommandhandler.ts

Blame
  • Bifurcation depuis ARISE / matrix-appservice-discord
    Le projet source a une visibilité limitée.
    module_sdl2.c 10,28 Kio
    #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>
    #include <stdio.h>
    #include <SDL.h>
    #include <mpv/render_gl.h>
    #include <mpv/client.h>
    
    #define WIDTH   400
    #define HEIGHT  200
    
    static volatile Uint32 wakeup_on_mpv_render_update, wakeup_on_mpv_events;
    
    struct module_sdl2_window {
        /* Related to SDL2 */
        volatile SDL_Window *window;
        volatile SDL_GLContext glcontext;
        int is_fullscreen;
    
        /* Mpv related */
        volatile mpv_handle *mpv;
        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  */
    
        /* Thread related */
        pthread_mutex_t mtx;
        struct lkt_thread self;
        volatile int launched;  /* SDL you sucks */
    };
    
    /* Private functions. */
    
    static inline void *
    get_proc_address_mpv(void *fn_ctx, const char *name)
    {
        (void) fn_ctx;
        return SDL_GL_GetProcAddress(name);
    }
    
    static inline void
    on_mpv_events(void *ctx)
    {
        (void) ctx;
        SDL_Event event = { .type = wakeup_on_mpv_events };
        SDL_PushEvent(&event);
    }
    
    static inline void
    on_mpv_render_update(void *ctx)
    {
        (void) ctx;
        SDL_Event event = { .type = wakeup_on_mpv_render_update };
        SDL_PushEvent(&event);
    }
    
    static inline bool
    init_mpv__(mpv_handle **ctx)
    {
        *ctx = lmpv_prepare();
        int status;
        RETURN_IF((status = mpv_initialize(*ctx)) < 0, mpv_error_string(status), 1);
        RETURN_UNLESS(lmpv_observe_properties(*ctx), "Observe properties failed", 1);
        return 0;
    }
    
    static inline bool
    init_mpv_gl__(mpv_handle *mpv, mpv_render_context **mpv_gl, mpv_render_param *params)
    {
        int status;
        RETURN_IF((status = mpv_render_context_create(mpv_gl, mpv, params)) < 0,
                  mpv_error_string(status), 1);
    
        wakeup_on_mpv_render_update = SDL_RegisterEvents(1);
        wakeup_on_mpv_events = SDL_RegisterEvents(1);
        if (wakeup_on_mpv_render_update == (Uint32) - 1 ||
            wakeup_on_mpv_events == (Uint32) - 1) {
            fprintf(stderr, " . init_mpv_gl__: Failed to register events\n");
            return 1;
        }
    
        mpv_set_wakeup_callback(mpv, on_mpv_events, NULL);
        mpv_render_context_set_update_callback(*mpv_gl, on_mpv_render_update, NULL);
        return 0;
    }
    /* Thread related functions */
    
    static void *
    sdl_thread__(struct lkt_thread_arg *arg)
    {
        volatile struct lkt_win *const win       = arg->args;
        volatile struct module_sdl2_window *sdl2 = win->window;
        SDL_Event event;
        uint64_t flags;
        int w, h, redraw = 0;
        free(arg);
    
        /* Init the SDL window
           Yeah, SDL you sucks */
    
        SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "no"); /* It seems that sdl sucks. */
        RETURN_IF(SDL_Init(SDL_INIT_VIDEO) < 0, "Failed to init SDL", NULL);
    
        sdl2->window = SDL_CreateWindow("lektord", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                                        WIDTH, HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
        RETURN_UNLESS(sdl2->window, "Failed to create the window", NULL);
        sdl2->glcontext = SDL_GL_CreateContext((SDL_Window *) sdl2->window);
        RETURN_UNLESS(sdl2->glcontext, "Failed to create the SDL context", NULL);
    
        /* Init mpv here */
    
        RETURN_IF(init_mpv__((mpv_handle **) & sdl2->mpv),
                  "Failed to init mpv", false);
    
        mpv_render_param params[] = {
            { MPV_RENDER_PARAM_API_TYPE, MPV_RENDER_API_TYPE_OPENGL },
            {
                MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, &(mpv_opengl_init_params)
                {
                    .get_proc_address = get_proc_address_mpv,
                }
            },
            {
                // Can't use mpv_command with that thing, should change to mpv_command_async
                MPV_RENDER_PARAM_ADVANCED_CONTROL, &(int)
                {
                    1
                }
            },
            {0}
        };
    
        RETURN_IF(init_mpv_gl__((mpv_handle *) sdl2->mpv, (mpv_render_context **) &sdl2->mpv_gl, params),
                  "Failed to init mpv_gl", false);
    
        while (!sdl2->launched)
            sched_yield();
    
        fprintf(stderr, " * Started SDL thread\n");
    
    loop:
        if (SDL_PollEvent(&event))
            sched_yield();
    
        switch (event.type) {
        case SDL_QUIT:
            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((mpv_handle *) sdl2->mpv, 0, cmd_pause);
            }
            break;
    
        case SDL_KEYUP:
            if (event.key.keysym.sym == SDLK_F11) {
                if (sdl2->is_fullscreen)
                    SDL_SetWindowFullscreen((SDL_Window *) sdl2->window, 0);
                else
                    SDL_SetWindowFullscreen((SDL_Window *) sdl2->window, SDL_WINDOW_FULLSCREEN);
                /* May use SDL_WINDOW_FULLSCREEN_DESKTOP, need to check. */
                sdl2->is_fullscreen = 1 - sdl2->is_fullscreen;
            }
            break;
    
        default:
            if (event.type == wakeup_on_mpv_render_update) {
                flags = mpv_render_context_update((mpv_render_context *) sdl2->mpv_gl);
                if (flags & MPV_RENDER_UPDATE_FRAME)
                    redraw = 1;
            }
        }
    
        if (redraw) {
            SDL_GetWindowSize((SDL_Window *) 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((mpv_render_context *) sdl2->mpv_gl, params);
            SDL_GL_SwapWindow((SDL_Window *) sdl2->window);
            redraw = 0;
        }
        goto loop;  /* A loop without indentation. */
    }
    
    /* Exported functions */
    
    extern int
    module_set_function(void *arg__, void *handle__)
    {
        RETURN_UNLESS(arg__ && handle__, "Invalid argument", 1);
        struct lkt_win *win = (struct lkt_win *) arg__;
    
        win->new = module_sdl2_new;
        win->close = module_sdl2_close;
        win->free = module_sdl2_free;
        win->toggle_pause = module_sdl2_toggle_pause;
        win->load_file = module_sdl2_load_file;
        win->set_volume = module_sdl2_set_volume;
        win->get_duration = module_sdl2_get_duration;
        win->get_elapsed = module_sdl2_get_elapsed;
        win->handle_events = module_sdl2_handle_events;
        win->handle = handle__;
    
        return 0;
    }
    
    bool
    module_sdl2_new(struct lkt_win *const win)
    {
        RETURN_UNLESS(win, "Invalid arguments", false);
    
        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));
    
            /* Yeah, this is how it is done. */
            pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
            ((struct module_sdl2_window *) win->window)->mtx = mtx;
    
            /* Start the SDL thread */
            struct lkt_thread_arg *arg = calloc(1, sizeof(struct lkt_thread_arg));
            RETURN_UNLESS(arg, "Out of memory", false);
            arg->args = win;
            RETURN_IF(lkt_th_new(&((struct module_sdl2_window *) win->window)->self,
                                 LKT_DEFAULT_LIST_SIZE, sdl_thread__, arg),
                      "Failed to launch the SDL thread", false);
        }
    
        /* Finish */
        SDL_SetWindowTitle((SDL_Window *) ((struct module_sdl2_window *) win->window)->window, "Lektord");
        SDL_DisableScreenSaver();
        ((struct module_sdl2_window *) win->window)->launched = 1;
        return true;
    }
    
    void
    module_sdl2_close(struct lkt_win *const win)
    {
        RETURN_UNLESS(win && win->window, "Invalid arguments", NOTHING);
        struct module_sdl2_window *sdl2 = win->window;
        RETURN_UNLESS(sdl2->mpv, "Missing mpv ctx", NOTHING);
        static const char *cmd[] = { "stop", NULL };
        mpv_command_async((mpv_handle *) sdl2->mpv, 0, cmd);
        /* TODO: make the SDL window background be black. */
    }
    
    void
    module_sdl2_free(struct lkt_win *const win)
    {
        RETURN_UNLESS(win && win->window, "Invalid arguments", NOTHING);
        struct module_sdl2_window *sdl2 = win->window;
        mpv_render_context_free((mpv_render_context *) sdl2->mpv_gl);
        sdl2->mpv_gl = NULL;
        lmpv_free((mpv_handle **) &sdl2->mpv);
    }
    
    bool
    module_sdl2_toggle_pause(struct lkt_win *const win)
    {
        RETURN_UNLESS(win && win->window, "Invalid arguments", false);
        return ! lmpv_toggle_pause((mpv_handle *) ((struct module_sdl2_window *) win->window)->mpv);
    }
    
    bool
    module_sdl2_load_file(struct lkt_win *const 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 ret;
    }
    
    bool
    module_sdl2_set_volume(struct lkt_win *const 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);
    }
    
    bool
    module_sdl2_get_duration(struct lkt_win *const 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 true;
    }
    
    bool
    module_sdl2_handle_events(struct lkt_win *const win, sqlite3 *db, enum mpd_idle_flag *mpd_idle_events)
    {
        struct module_sdl2_window *sdl2 = win->window;
        RETURN_UNLESS(sdl2, "Can't handle events from a NULL window", false);
        return ! lmpv_handle(win, (mpv_handle *) sdl2->mpv, db, mpd_idle_events,
                             (int *) &sdl2->mpv_time_pos, (int *) &sdl2->mpv_duration);
    }