You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
260 lines
7.3 KiB
260 lines
7.3 KiB
/*****************************************************************************
|
|
* Copyright (C) 2023 VLC authors and VideoLAN
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU 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 "compositor_wayland_module.h"
|
|
#include <vlc_common.h>
|
|
#include <vlc_plugin.h>
|
|
#include <wayland-client.h>
|
|
|
|
#include <assert.h>
|
|
|
|
typedef struct
|
|
{
|
|
struct wl_display* display;
|
|
struct wl_event_queue* queue;
|
|
struct wl_compositor* compositor;
|
|
struct wl_subcompositor* subcompositor;
|
|
|
|
struct wl_surface* interface_surface;
|
|
|
|
struct wl_surface* video_surface;
|
|
struct wl_subsurface* video_subsurface;
|
|
|
|
int buffer_scale;
|
|
} qtwayland_priv_t;
|
|
|
|
static void registry_global_cb(void* data, struct wl_registry* registry,
|
|
uint32_t id, const char* iface, uint32_t version)
|
|
{
|
|
VLC_UNUSED(version);
|
|
|
|
qtwayland_t* obj = (qtwayland_t*)data;
|
|
qtwayland_priv_t* sys = (qtwayland_priv_t*)obj->p_sys;
|
|
|
|
if (!strcmp(iface, "wl_subcompositor"))
|
|
sys->subcompositor = (struct wl_subcompositor*)wl_registry_bind(registry, id, &wl_subcompositor_interface, version);
|
|
if (!strcmp(iface, "wl_compositor"))
|
|
sys->compositor = (struct wl_compositor*)wl_registry_bind(registry, id, &wl_compositor_interface, version);
|
|
}
|
|
|
|
static void registry_global_remove_cb(void* data, struct wl_registry* registry, uint32_t id)
|
|
{
|
|
VLC_UNUSED(data);
|
|
VLC_UNUSED(registry);
|
|
VLC_UNUSED(id);
|
|
}
|
|
|
|
static const struct wl_registry_listener registry_cbs = {
|
|
registry_global_cb,
|
|
registry_global_remove_cb,
|
|
};
|
|
|
|
static int SetupInterface(qtwayland_t* obj, void* qpni_interface_surface, int scale)
|
|
{
|
|
qtwayland_priv_t* sys = (qtwayland_priv_t*)obj->p_sys;
|
|
|
|
if (! qpni_interface_surface)
|
|
return VLC_EGENERIC;
|
|
|
|
sys->interface_surface = (struct wl_surface*)qpni_interface_surface;
|
|
sys->buffer_scale = scale;
|
|
|
|
return VLC_SUCCESS;
|
|
}
|
|
|
|
|
|
static int SetupVoutWindow(qtwayland_t* obj, vlc_window_t* wnd)
|
|
{
|
|
qtwayland_priv_t* sys = (qtwayland_priv_t*)obj->p_sys;
|
|
|
|
sys->video_surface = wl_compositor_create_surface(sys->compositor);
|
|
if (!sys->video_surface)
|
|
return VLC_EGENERIC;
|
|
|
|
wl_surface_set_buffer_scale(sys->video_surface, sys->buffer_scale);
|
|
|
|
struct wl_region* region = wl_compositor_create_region(sys->compositor);
|
|
if (!region)
|
|
{
|
|
wl_surface_destroy(sys->video_surface);
|
|
sys->video_surface = NULL;
|
|
return VLC_EGENERIC;
|
|
}
|
|
wl_region_add(region, 0, 0, 0, 0);
|
|
wl_surface_set_input_region(sys->video_surface, region);
|
|
|
|
wl_region_destroy(region);
|
|
wl_surface_commit(sys->video_surface);
|
|
|
|
//setup vout window
|
|
wnd->type = VLC_WINDOW_TYPE_WAYLAND;
|
|
wnd->handle.wl = sys->video_surface;
|
|
wnd->display.wl = sys->display;
|
|
|
|
return VLC_SUCCESS;
|
|
}
|
|
|
|
static void TeardownVoutWindow(struct qtwayland_t* obj)
|
|
{
|
|
qtwayland_priv_t* sys = (qtwayland_priv_t*)obj->p_sys;
|
|
vlc_assert(sys->video_surface);
|
|
wl_surface_destroy(sys->video_surface);
|
|
sys->video_surface = NULL;
|
|
}
|
|
|
|
static void Enable(qtwayland_t* obj, const vlc_window_cfg_t * conf)
|
|
{
|
|
VLC_UNUSED(conf);
|
|
|
|
qtwayland_priv_t* sys = (qtwayland_priv_t*)obj->p_sys;
|
|
|
|
vlc_assert(sys->video_subsurface == NULL);
|
|
vlc_assert(sys->video_surface);
|
|
vlc_assert(sys->interface_surface);
|
|
|
|
sys->video_subsurface = wl_subcompositor_get_subsurface(sys->subcompositor, sys->video_surface, sys->interface_surface);
|
|
wl_subsurface_place_below(sys->video_subsurface, sys->interface_surface);
|
|
wl_subsurface_set_desync(sys->video_subsurface);
|
|
wl_surface_commit(sys->video_surface);
|
|
}
|
|
|
|
static void Disable(qtwayland_t* obj)
|
|
{
|
|
qtwayland_priv_t* sys = (qtwayland_priv_t*)obj->p_sys;
|
|
vlc_assert(sys->video_subsurface);
|
|
|
|
wl_subsurface_destroy(sys->video_subsurface);
|
|
sys->video_subsurface = NULL;
|
|
wl_surface_commit(sys->video_surface);
|
|
}
|
|
|
|
static void Move(struct qtwayland_t* obj, int x, int y)
|
|
{
|
|
qtwayland_priv_t* sys = (qtwayland_priv_t*)obj->p_sys;
|
|
wl_subsurface_set_position(sys->video_subsurface, x, y);
|
|
wl_surface_commit(sys->video_surface);
|
|
}
|
|
|
|
static void Resize(struct qtwayland_t* obj, size_t width, size_t height)
|
|
{
|
|
VLC_UNUSED(obj);
|
|
VLC_UNUSED(width);
|
|
VLC_UNUSED(height);
|
|
}
|
|
|
|
static void Close(qtwayland_t* obj)
|
|
{
|
|
qtwayland_priv_t* sys = (qtwayland_priv_t*)(obj->p_sys);
|
|
wl_display_flush(sys->display);
|
|
|
|
wl_subcompositor_destroy(sys->subcompositor);
|
|
wl_compositor_destroy(sys->compositor);
|
|
wl_event_queue_destroy(sys->queue);
|
|
}
|
|
|
|
static bool Init(qtwayland_t* obj, void* qpni_display)
|
|
{
|
|
qtwayland_priv_t* sys = (qtwayland_priv_t*)(obj->p_sys);
|
|
struct wl_display* display = (struct wl_display*)(qpni_display);
|
|
|
|
sys->display = display;
|
|
if (!display)
|
|
{
|
|
msg_Err(obj, "wayland display is missing");
|
|
goto error;
|
|
}
|
|
|
|
sys->queue = wl_display_create_queue(display);
|
|
void* wrapper = wl_proxy_create_wrapper(display);
|
|
wl_proxy_set_queue((struct wl_proxy*)wrapper, sys->queue);
|
|
|
|
struct wl_registry* registry = wl_display_get_registry((struct wl_display*)wrapper);
|
|
wl_proxy_wrapper_destroy(wrapper);
|
|
|
|
wl_registry_add_listener(registry, ®istry_cbs, obj);
|
|
wl_display_roundtrip_queue(display, sys->queue);
|
|
|
|
wl_registry_destroy(registry);
|
|
|
|
if (!sys->compositor || !sys->subcompositor )
|
|
goto error;
|
|
|
|
return true;
|
|
|
|
error:
|
|
if (sys->subcompositor)
|
|
wl_subcompositor_destroy(sys->subcompositor);
|
|
if (sys->compositor)
|
|
wl_compositor_destroy(sys->compositor);
|
|
if (sys->queue)
|
|
wl_event_queue_destroy(sys->queue);
|
|
sys->compositor = NULL;
|
|
sys->subcompositor = NULL;
|
|
sys->queue = NULL;
|
|
|
|
return false;
|
|
}
|
|
|
|
static int Open(vlc_object_t* p_this)
|
|
{
|
|
qtwayland_t* obj = (qtwayland_t*)p_this;
|
|
|
|
struct wl_display *dpy = wl_display_connect( NULL );
|
|
if( dpy == NULL )
|
|
{
|
|
//not using wayland
|
|
return VLC_EGENERIC;
|
|
}
|
|
|
|
wl_display_disconnect( dpy );
|
|
|
|
qtwayland_priv_t* sys = (qtwayland_priv_t*)vlc_obj_calloc(p_this, 1, sizeof(qtwayland_priv_t));
|
|
if (!sys)
|
|
return VLC_ENOMEM;
|
|
|
|
|
|
//module functions
|
|
obj->init = Init;
|
|
obj->close = Close;
|
|
|
|
//interface functions
|
|
obj->setupInterface = SetupInterface;
|
|
|
|
//video functions
|
|
obj->setupVoutWindow = SetupVoutWindow;
|
|
obj->teardownVoutWindow = TeardownVoutWindow;
|
|
obj->enable = Enable;
|
|
obj->disable = Disable;
|
|
obj->move = Move;
|
|
obj->resize = Resize;
|
|
|
|
obj->p_sys = sys;
|
|
|
|
return VLC_SUCCESS;
|
|
}
|
|
|
|
vlc_module_begin()
|
|
set_shortname(N_("QtWayland"))
|
|
set_description(N_(" calls for compositing with Qt"))
|
|
set_capability("qtwayland", 10)
|
|
set_callback(Open)
|
|
vlc_module_end()
|
|
|