Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/VLC/modules/video_output/wayland/   (VLC Media Plyer ©)  Datei vom 23.9.2026 mit Größe 24 kB image not shown  

Quelle  xdg-shell.c   Sprache: C

 

/**
 * @file xdg-shell.c
 * @brief Desktop shell surface provider module for VLC media player
 */

/*****************************************************************************
 * Copyright © 2014, 2017 Rémi Denis-Courmont
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/


#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <assert.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <poll.h>

#include <wayland-client.h>
#include <wayland-cursor.h>
#ifdef XDG_SHELL
# include "xdg-shell-client-protocol.h"
# include "xdg-decoration-client-protocol.h"
#else
# define xdg_wm_base wl_shell
# define xdg_wm_base_add_listener(s, l, q) (void)0
# define xdg_wm_base_destroy wl_shell_destroy
# define xdg_wm_base_get_xdg_surface wl_shell_get_shell_surface
# define xdg_wm_base_pong wl_shell_pong
# define xdg_surface wl_shell_surface
# define xdg_surface_listener wl_shell_surface_listener
# define xdg_surface_add_listener wl_shell_surface_add_listener
# define xdg_surface_destroy wl_shell_surface_destroy
# define xdg_surface_get_toplevel(s) (s)
# define xdg_surface_set_window_geometry(s,x,y,w,h) (void)0
# define xdg_toplevel wl_shell_surface
# define xdg_toplevel_add_listener(s, l, q) (void)0
# define xdg_toplevel_destroy(s) (void)0
# define xdg_toplevel_set_title wl_shell_surface_set_title
# define xdg_toplevel_set_app_id(s, i) (void)0
# define xdg_toplevel_set_fullscreen(s, o) \
         wl_shell_surface_set_fullscreen(s, 1, 0, o)
# define xdg_toplevel_unset_fullscreen wl_shell_surface_set_toplevel
#endif

#include <vlc_common.h>
#include <vlc_threads.h>
#include <vlc_plugin.h>
#include <vlc_window.h>

#include "input.h"
#include "output.h"

typedef struct
{
    struct wl_registry *registry;
    struct wl_compositor *compositor;
    struct wl_shm *shm;
    struct xdg_wm_base *wm_base;
    struct xdg_surface *surface;
    struct xdg_toplevel *toplevel;
#ifdef XDG_SHELL
    struct zxdg_decoration_manager_v1 *deco_manager;
    struct zxdg_toplevel_decoration_v1 *deco;
#endif

    uint32_t default_output;

    struct
    {
        unsigned width;
        unsigned height;
    } set;
    struct
    {
        unsigned width;
        unsigned height;
        struct
        {
            unsigned width;
            unsigned height;
            bool fullscreen;
        } latch;
        vlc_sem_t configured;
    } wm;
    struct
    {
        unsigned width;
        unsigned height;
    } bounds;

    struct output_list *outputs;
    struct wl_list seats;
    struct wl_cursor_theme *cursor_theme;
    struct wl_cursor *cursor;
    struct wl_surface *cursor_surface;

    vlc_mutex_t lock;
    vlc_thread_t thread;
} vout_window_sys_t;

static void cleanup_wl_display_read(void *data)
{
    struct wl_display *display = data;

    wl_display_cancel_read(display);
}

/** Background thread for Wayland shell events handling */
static void *Thread(void *data)
{
    vlc_thread_set_name("vlc-wayland-evt");

    vlc_window_t *wnd = data;
    vout_window_sys_t *sys = wnd->sys;
    struct wl_display *display = wnd->display.wl;
    struct pollfd ufd[1];

    int canc = vlc_savecancel();
    vlc_cleanup_push(cleanup_wl_display_read, display);

    ufd[0].fd = wl_display_get_fd(display);
    ufd[0].events = POLLIN;

    for (;;)
    {
        int timeout;

        while (wl_display_prepare_read(display) != 0)
            wl_display_dispatch_pending(display);

        wl_display_flush(display);
        timeout = seat_next_timeout(&sys->seats);
        vlc_restorecancel(canc);

        int val = poll(ufd, 1, timeout);

        canc = vlc_savecancel();
        if (val == 0)
            seat_timeout(&sys->seats);

        wl_display_read_events(display);
        wl_display_dispatch_pending(display);
    }
    vlc_assert_unreachable();
    vlc_cleanup_pop();
    //vlc_restorecancel(canc);
    //return NULL;
}

static void ResizeAck(vlc_window_t *wnd, unsigned width, unsigned height,
                      void *data)
{
#ifdef XDG_SHELL
    vout_window_sys_t *sys = wnd->sys;
    uint32_t *serial = data;

    if (serial != NULL)
        xdg_surface_ack_configure(sys->surface, *serial);

    xdg_surface_set_window_geometry(sys->surface, 0, 0, width, height);
#else
    (void) wnd; (void) width; (void) height; (void) data;
#endif
}

static void ReportSize(vlc_window_t *wnd, void *data)
{
    vout_window_sys_t *sys = wnd->sys;
    /* Zero wm.width or zero wm.height means the client should choose.
     * DO NOT REPORT those values to video output... */

    unsigned width, height;

    if (sys->wm.width != 0 && sys->wm.height != 0)
    {
        width = sys->wm.width;
        height = sys->wm.height;
    }
    else if (sys->bounds.width != 0 && sys->bounds.height != 0
     && (sys->bounds.width < sys->set.width
      || sys->bounds.height < sys->set.height))
    {
        width = sys->bounds.width;
        height = sys->bounds.height;
    }
    else
    {
        width = sys->set.width;
        height = sys->set.height;
    }

    wnd->owner.cbs->resized(wnd, width, height, ResizeAck, data);
}

static void Resize(vlc_window_t *wnd, unsigned width, unsigned height)
{
    vout_window_sys_t *sys = wnd->sys;

#ifdef XDG_SHELL
    /* The minimum size must be smaller or equal to the maximum size
     * at _all_ times. This gets a bit cumbersome. */

    xdg_toplevel_set_min_size(sys->toplevel, 0, 0);
    xdg_toplevel_set_max_size(sys->toplevel, width, height);
    xdg_toplevel_set_min_size(sys->toplevel, width, height);
#endif

    vlc_mutex_lock(&sys->lock);
    sys->set.width = width;
    sys->set.height = height;
    ReportSize(wnd, NULL);
    vlc_mutex_unlock(&sys->lock);
    wl_display_flush(wnd->display.wl);
}

static void Close(vlc_window_t *);

static void UnsetFullscreen(vlc_window_t *wnd)
{
    vout_window_sys_t *sys = wnd->sys;

    xdg_toplevel_unset_fullscreen(sys->toplevel);
    wl_display_flush(wnd->display.wl);
}

static void SetFullscreen(vlc_window_t *wnd, const char *idstr)
{
    vout_window_sys_t *sys = wnd->sys;
    struct wl_output *output = NULL;

    if (idstr != NULL)
        output = output_find_by_name(sys->outputs, idstr);
    else
    if (sys->default_output != 0)
        output = output_find_by_id(sys->outputs, sys->default_output);

    xdg_toplevel_set_fullscreen(sys->toplevel, output);
    wl_display_flush(wnd->display.wl);
}

#ifdef XDG_SHELL
static void SetDecoration(vlc_window_t *wnd, bool decorated)
{
    vout_window_sys_t *sys = wnd->sys;
    const uint_fast32_t deco_mode = decorated
        ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE
        : ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;

    if (sys->deco != NULL)
        zxdg_toplevel_decoration_v1_set_mode(sys->deco, deco_mode);
    else
    if (deco_mode != ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE)
        msg_Err(wnd, "server-side decoration not supported");
}
#endif

static int Enable(vlc_window_t *wnd, const vlc_window_cfg_t *restrict cfg)
{
    vout_window_sys_t *sys = wnd->sys;
    struct wl_display *display = wnd->display.wl;

    if (cfg->is_fullscreen)
        xdg_toplevel_set_fullscreen(sys->toplevel, NULL);
    else
        xdg_toplevel_unset_fullscreen(sys->toplevel);

#ifdef XDG_SHELL
    SetDecoration(wnd, cfg->is_decorated);
#else
    if (cfg->is_decorated)
        return VLC_EGENERIC;
#endif
    Resize(wnd, cfg->width, cfg->height);
    wl_surface_commit(wnd->handle.wl);
    wl_display_flush(display);
#ifdef XDG_SHELL
    vlc_sem_wait(&sys->wm.configured);
#endif
    return VLC_SUCCESS;
}

static const struct vlc_window_operations ops = {
    .enable = Enable,
    .resize = Resize,
    .destroy = Close,
    .unset_fullscreen = UnsetFullscreen,
    .set_fullscreen = SetFullscreen,
};

#ifdef XDG_SHELL
static void xdg_toplevel_configure_cb(void *data,
                                      struct xdg_toplevel *toplevel,
                                      int32_t width, int32_t height,
                                      struct wl_array *states)
{
    vlc_window_t *wnd = data;
    vout_window_sys_t *sys = wnd->sys;
    const uint32_t *state;

    msg_Dbg(wnd, "new configuration: %"PRId32"x%"PRId32, width, height);
    sys->wm.latch.width = width;
    sys->wm.latch.height = height;
    sys->wm.latch.fullscreen = false;

    wl_array_for_each(state, states)
    {
        msg_Dbg(wnd, " - state 0x%04"PRIX32, *state);

        switch (*state)
        {
            case XDG_TOPLEVEL_STATE_FULLSCREEN:
                sys->wm.latch.fullscreen = true;
                break;
        }
    }

    (void) toplevel;
}

static void xdg_toplevel_close_cb(void *data, struct xdg_toplevel *toplevel)
{
    vlc_window_t *wnd = data;

    vlc_window_ReportClose(wnd);
    (void) toplevel;
}

#ifdef XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION
static void xdg_toplevel_configure_bounds_cb(
        void *data, struct xdg_toplevel* toplevel,
        int32_t width, int32_t height
){
    // TODO for tiling window managers
    vlc_window_t *wnd = data;
    vout_window_sys_t *sys = wnd->sys;

    msg_Dbg(wnd, "window configure bounds: %" PRId32 "x%" PRId32,
            width, height);
    (void)toplevel;
    sys->bounds.width = width;
    sys->bounds.height = height;
}
#endif

static const struct xdg_toplevel_listener xdg_toplevel_cbs =
{
    xdg_toplevel_configure_cb,
    xdg_toplevel_close_cb,
#ifdef XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION
    xdg_toplevel_configure_bounds_cb,
#endif
#ifdef XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION
    NULL, /* We don't support wm_capabilities for now */
#endif
};

static void xdg_surface_configure_cb(void *data, struct xdg_surface *surface,
                                     uint32_t serial)
{
    vlc_window_t *wnd = data;
    vout_window_sys_t *sys = wnd->sys;

    if (sys->wm.latch.fullscreen)
        vlc_window_ReportFullscreen(wnd, NULL);
    else
        vlc_window_ReportWindowed(wnd);

    vlc_mutex_lock(&sys->lock);
    sys->wm.width = sys->wm.latch.width;
    sys->wm.height = sys->wm.latch.height;
    ReportSize(wnd, &serial);
    vlc_mutex_unlock(&sys->lock);

    vlc_sem_post(&sys->wm.configured);
    (void) surface;
}

static const struct xdg_surface_listener xdg_surface_cbs =
{
    xdg_surface_configure_cb,
};

static void xdg_wm_base_ping_cb(void *data, struct xdg_wm_base *wm_base,
                                uint32_t serial)
{
    (void) data;
    xdg_wm_base_pong(wm_base, serial);
}

static const struct xdg_wm_base_listener xdg_wm_base_cbs =
{
    xdg_wm_base_ping_cb,
};

static void xdg_toplevel_decoration_configure_cb(void *data,
                                      struct zxdg_toplevel_decoration_v1 *deco,
                                                 uint32_t mode)
{
    vlc_window_t *wnd = data;

    msg_Dbg(wnd, "new decoration mode: %"PRIu32, mode);
    (void) deco;
}

static const struct zxdg_toplevel_decoration_v1_listener
                                                  xdg_toplevel_decoration_cbs =
{
    xdg_toplevel_decoration_configure_cb,
};
#else
static void wl_shell_surface_configure_cb(void *data,
                                          struct wl_shell_surface *toplevel,
                                          uint32_t edges,
                                          int32_t width, int32_t height)
{
    vlc_window_t *wnd = data;

    msg_Dbg(wnd, "new configuration: %"PRId32"x%"PRId32, width, height);
    vlc_window_ReportSize(wnd, width, height);
    (void) toplevel; (void) edges;
}

static void wl_shell_surface_ping_cb(void *data,
                                     struct wl_shell_surface *surface,
                                     uint32_t serial)
{
    (void) data;
    wl_shell_surface_pong(surface, serial);
}

static void wl_shell_surface_popup_done_cb(void *data,
                                           struct wl_shell_surface *surface)
{
    (void) data; (void) surface;
}

static const struct wl_shell_surface_listener wl_shell_surface_cbs =
{
    wl_shell_surface_ping_cb,
    wl_shell_surface_configure_cb,
    wl_shell_surface_popup_done_cb,
};
#define xdg_surface_cbs wl_shell_surface_cbs
#endif

static void register_wl_compositor(void *data, struct wl_registry *registry,
                                   uint32_t name, uint32_t vers)
{
    vlc_window_t *wnd = data;
    vout_window_sys_t *sys = wnd->sys;

    if (likely(sys->compositor == NULL))
        sys->compositor = wl_registry_bind(registry, name,
                                           &wl_compositor_interface, vers);
}

static void register_wl_output(void *data, struct wl_registry *registry,
                               uint32_t name, uint32_t vers)
{
    vlc_window_t *wnd = data;
    vout_window_sys_t *sys = wnd->sys;

    output_create(sys->outputs, registry, name, vers);
}

static void register_wl_seat(void *data, struct wl_registry *registry,
                             uint32_t name, uint32_t vers)
{
    vlc_window_t *wnd = data;
    vout_window_sys_t *sys = wnd->sys;

    seat_create(wnd, registry, name, vers, &sys->seats);
}

#ifndef XDG_SHELL
static void register_wl_shell(void *data, struct wl_registry *registry,
                              uint32_t name, uint32_t vers)
{
    vlc_window_t *wnd = data;
    vout_window_sys_t *sys = wnd->sys;

    if (likely(sys->wm_base == NULL))
        sys->wm_base = wl_registry_bind(registry, name, &wl_shell_interface,
                                        vers);
}
#endif

static void register_wl_shm(void *data, struct wl_registry *registry,
                            uint32_t name, uint32_t vers)
{
    vlc_window_t *wnd = data;
    vout_window_sys_t *sys = wnd->sys;

    if (likely(sys->shm == NULL))
        sys->shm = wl_registry_bind(registry, name, &wl_shm_interface, vers);
}

#ifdef XDG_SHELL
static void register_xdg_wm_base(void *data, struct wl_registry *registry,
                                 uint32_t name, uint32_t vers)
{
    vlc_window_t *wnd = data;
    vout_window_sys_t *sys = wnd->sys;

    if (likely(sys->wm_base == NULL))
        sys->wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface,
                                        vers);
}

static void register_xdg_decoration_manager(void *data,
                                            struct wl_registry *registry,
                                            uint32_t name, uint32_t vers)
{
    vlc_window_t *wnd = data;
    vout_window_sys_t *sys = wnd->sys;

    if (likely(sys->deco_manager == NULL))
        sys->deco_manager = wl_registry_bind(registry, name,
                                  &zxdg_decoration_manager_v1_interface, vers);
}
#endif

struct registry_handler
{
    const char *iface;
    void (*global)(void *, struct wl_registry *, uint32_t, uint32_t);
    uint32_t max_version;
};


#ifdef XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION
#define VLC_XDG_WM_BASE_VERSION XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION
#else
#define VLC_XDG_WM_BASE_VERSION 1
#endif

static const struct registry_handler global_handlers[] =
{
     { "wl_compositor", register_wl_compositor, 2 },
     { "wl_output", register_wl_output, 4 },
     { "wl_seat", register_wl_seat, UINT32_C(-1) },
#ifndef XDG_SHELL
     { "wl_shell", register_wl_shell, 1 },
#endif
     { "wl_shm", register_wl_shm, 1 },
#ifdef XDG_SHELL
     { "xdg_wm_base", register_xdg_wm_base, VLC_XDG_WM_BASE_VERSION },
     { "zxdg_decoration_manager_v1", register_xdg_decoration_manager, 1 },
#endif
};

static int rghcmp(const void *a, const void *b)
{
    const char *iface = a;
    const struct registry_handler *handler = b;

    return strcmp(iface, handler->iface);
}

static void registry_global_cb(void *data, struct wl_registry *registry,
                               uint32_t name, const char *iface, uint32_t vers)
{
    vlc_window_t *wnd = data;
    const struct registry_handler *h;

    msg_Dbg(wnd, "global %3"PRIu32": %s version %"PRIu32, name, iface, vers);

    h = bsearch(iface, global_handlers, ARRAY_SIZE(global_handlers),
                sizeof (*h), rghcmp);
    if (h != NULL)
    {
        uint32_t version = (vers < h->max_version) ? vers : h->max_version;

        h->global(data, registry, name, version);
    }
}

static void registry_global_remove_cb(void *data, struct wl_registry *registry,
                                      uint32_t name)
{
    vlc_window_t *wnd = data;
    vout_window_sys_t *sys = wnd->sys;

    msg_Dbg(wnd, "global remove %3"PRIu32, name);

    if (seat_destroy_one(&sys->seats, name) == 0)
        return;

    struct wl_output *output = output_find_by_id(sys->outputs, name);
    if (output != NULL) {
        output_destroy(sys->outputs, output);
        return;
    }

    (void) registry;
}

static const struct wl_registry_listener registry_cbs =
{
    registry_global_cb,
    registry_global_remove_cb,
};

struct wl_surface *window_get_cursor(vlc_window_t *wnd, int32_t *restrict hsx,
                                     int32_t *restrict hsy)
{
    vout_window_sys_t *sys = wnd->sys;

    if (unlikely(sys->cursor == NULL))
        return NULL;

    assert(sys->cursor->image_count > 0);

    /* TODO? animated cursor (more than one image) */
    struct wl_cursor_image *img = sys->cursor->images[0];
    struct wl_surface *surface = sys->cursor_surface;

    if (likely(surface != NULL))
    {
        wl_surface_attach(surface, wl_cursor_image_get_buffer(img), 0, 0);
        wl_surface_damage(surface, 0, 0, img->width, img->height);
        wl_surface_commit(surface);
    }

    *hsx = img->hotspot_x;
    *hsy = img->hotspot_y;
    return surface;
}

/**
 * Creates a Wayland shell surface.
 */

static int Open(vlc_window_t *wnd)
{
    vout_window_sys_t *sys = malloc(sizeof (*sys));
    if (unlikely(sys == NULL))
        return VLC_ENOMEM;

    sys->compositor = NULL;
    sys->shm = NULL;
    sys->wm_base = NULL;
    sys->surface = NULL;
    sys->toplevel = NULL;
    sys->cursor_theme = NULL;
    sys->cursor = NULL;
#ifdef XDG_SHELL
    sys->deco_manager = NULL;
    sys->deco = NULL;
#endif
    sys->default_output = var_InheritInteger(wnd, "wl-output");
    sys->wm.width = 0;
    sys->wm.height = 0;
    sys->wm.latch.width = 0;
    sys->wm.latch.height = 0;
    sys->wm.latch.fullscreen = false;
    sys->set.width = 0;
    sys->set.height = 0;
    sys->bounds.width = 0;
    sys->bounds.height = 0;
    sys->outputs = output_list_create(wnd);
    wl_list_init(&sys->seats);
    sys->cursor_theme = NULL;
    sys->cursor_surface = NULL;
    vlc_mutex_init(&sys->lock);
    vlc_sem_init(&sys->wm.configured, 0);
    wnd->sys = sys;
    wnd->handle.wl = NULL;

    /* Connect to the display server */
    char *dpy_name = var_InheritString(wnd, "wl-display");
    struct wl_display *display = wl_display_connect(dpy_name);

    free(dpy_name);

    if (display == NULL)
    {
        output_list_destroy(sys->outputs);
        free(sys);
        return VLC_EGENERIC;
    }

    /* Find the interesting singleton(s) */
    sys->registry = wl_display_get_registry(display);
    if (sys->registry == NULL)
        goto error;

    wl_registry_add_listener(sys->registry, ®istry_cbs, wnd);
    wl_display_roundtrip(display); /* complete registry enumeration */

    if (sys->compositor == NULL || sys->wm_base == NULL)
        goto error;

    /* Create a surface */
    struct wl_surface *surface = wl_compositor_create_surface(sys->compositor);
    if (surface == NULL)
        goto error;

    xdg_wm_base_add_listener(sys->wm_base, &xdg_wm_base_cbs, NULL);

    struct xdg_surface *xdg_surface =
        xdg_wm_base_get_xdg_surface(sys->wm_base, surface);
    if (xdg_surface == NULL)
        goto error;

    sys->surface = xdg_surface;
    xdg_surface_add_listener(xdg_surface, &xdg_surface_cbs, wnd);

    struct xdg_toplevel *toplevel = xdg_surface_get_toplevel(xdg_surface);
    if (toplevel == NULL)
        goto error;

    sys->toplevel = toplevel;
    xdg_toplevel_add_listener(toplevel, &xdg_toplevel_cbs, wnd);

    char *title = var_InheritString(wnd, "video-title");
    xdg_toplevel_set_title(toplevel,
                           (title != NULL) ? title : _("VLC media player"));
    free(title);

    char *app_id = var_InheritString(wnd, "app-id");
    if (app_id != NULL)
    {
        xdg_toplevel_set_app_id(toplevel, app_id);
        free(app_id);
    }

    if (sys->shm != NULL)
    {
        sys->cursor_theme = wl_cursor_theme_load(NULL, 32, sys->shm);
        if (sys->cursor_theme != NULL)
            sys->cursor = wl_cursor_theme_get_cursor(sys->cursor_theme,
                                                     "left_ptr");

        sys->cursor_surface = wl_compositor_create_surface(sys->compositor);
    }
    if (sys->cursor == NULL)
        msg_Err(wnd, "failed to load cursor");

#ifdef XDG_SHELL
    if (sys->deco_manager != NULL)
        sys->deco = zxdg_decoration_manager_v1_get_toplevel_decoration(
                                                  sys->deco_manager, toplevel);
    if (sys->deco != NULL)
        zxdg_toplevel_decoration_v1_add_listener(sys->deco,
                                                 &xdg_toplevel_decoration_cbs,
                                                 wnd);
#endif

    wnd->type = VLC_WINDOW_TYPE_WAYLAND;
    wnd->handle.wl = surface;
    wnd->display.wl = display;
    wnd->ops = &ops;

    if (vlc_clone(&sys->thread, Thread, wnd))
        goto error;

    return VLC_SUCCESS;

error:
    seat_destroy_all(&sys->seats);
    output_list_destroy(sys->outputs);
#ifdef XDG_SHELL
    if (sys->deco != NULL)
        zxdg_toplevel_decoration_v1_destroy(sys->deco);
    if (sys->deco_manager != NULL)
        zxdg_decoration_manager_v1_destroy(sys->deco_manager);
#endif
    if (sys->cursor_surface != NULL)
        wl_surface_destroy(sys->cursor_surface);
    if (sys->cursor_theme != NULL)
        wl_cursor_theme_destroy(sys->cursor_theme);
    if (sys->toplevel != NULL)
        xdg_toplevel_destroy(sys->toplevel);
    if (sys->surface != NULL)
        xdg_surface_destroy(sys->surface);
    if (sys->wm_base != NULL)
        xdg_wm_base_destroy(sys->wm_base);
    if (wnd->handle.wl != NULL)
        wl_surface_destroy(wnd->handle.wl);
    if (sys->shm != NULL)
        wl_shm_destroy(sys->shm);
    if (sys->compositor != NULL)
        wl_compositor_destroy(sys->compositor);
    if (sys->registry != NULL)
        wl_registry_destroy(sys->registry);
    wl_display_disconnect(display);
    free(sys);
    return VLC_EGENERIC;
}

/**
 * Destroys a XDG shell surface.
 */

static void Close(vlc_window_t *wnd)
{
    vout_window_sys_t *sys = wnd->sys;

    vlc_cancel(sys->thread);
    vlc_join(sys->thread, NULL);

    seat_destroy_all(&sys->seats);
    output_list_destroy(sys->outputs);
#ifdef XDG_SHELL
    if (sys->deco != NULL)
        zxdg_toplevel_decoration_v1_destroy(sys->deco);
    if (sys->deco_manager != NULL)
        zxdg_decoration_manager_v1_destroy(sys->deco_manager);
#endif
    if (sys->cursor_surface != NULL)
        wl_surface_destroy(sys->cursor_surface);
    if (sys->cursor_theme != NULL)
        wl_cursor_theme_destroy(sys->cursor_theme);
    xdg_toplevel_destroy(sys->toplevel);
    xdg_surface_destroy(sys->surface);
    xdg_wm_base_destroy(sys->wm_base);
    wl_surface_destroy(wnd->handle.wl);
    if (sys->shm != NULL)
        wl_shm_destroy(sys->shm);
    wl_compositor_destroy(sys->compositor);
    wl_registry_destroy(sys->registry);
    wl_display_disconnect(wnd->display.wl);
    free(sys);
}


#define DISPLAY_TEXT N_("Wayland display")
#define DISPLAY_LONGTEXT N_( \
    "Video will be rendered with this Wayland display. " \
    "If empty, the default display will be used.")

#define OUTPUT_TEXT N_("Fullscreen output")
#define OUTPUT_LONGTEXT N_( \
    "Fullscreen mode with use the output with this name by default.")

vlc_module_begin()
#ifdef XDG_SHELL
    set_shortname(N_("XDG shell"))
    set_description(N_("XDG shell surface"))
#else
    set_shortname(N_("WL shell"))
    set_description(N_("Wayland shell surface"))
#endif
    set_subcategory(SUBCAT_VIDEO_VOUT)
#ifdef XDG_SHELL
    set_capability("vout window", 20)
#else
    set_capability("vout window", 10)
#endif
    set_callback(Open)

    add_string("wl-display", NULL, DISPLAY_TEXT, DISPLAY_LONGTEXT)
    add_integer("wl-output", 0, OUTPUT_TEXT, OUTPUT_LONGTEXT)
        change_integer_range(0, UINT32_MAX)
        change_volatile()
vlc_module_end()

Messung
CHZG
839310092

¤ Dauer der Verarbeitung: 0.6 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.