mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-12 17:38:19 +00:00
[client] wayland: move libdecor and xdg into seperate backends
This allows us to build with libdecor enabled as the selection to use it is decided upon at runtime if the compositor `gnome-shell` is detected. If the libdecor development headers are installed, by default it will now be compiled in unless overridden by the user at compile time.
This commit is contained in:
parent
d592f13f88
commit
aa9dbe654d
@ -45,12 +45,6 @@ add_feature_info(ENABLE_UBSAN ENABLE_UBSAN "UndefinedBehaviorSanitizer support."
|
||||
option(ENABLE_X11 "Build with X11 support" ON)
|
||||
add_feature_info(ENABLE_X11 ENABLE_X11 "X11 support.")
|
||||
|
||||
option(ENABLE_WAYLAND "Build with Wayland support" ON)
|
||||
add_feature_info(ENABLE_WAYLAND ENABLE_WAYLAND "Wayland support.")
|
||||
|
||||
option(ENABLE_LIBDECOR "Build with libdecor support" OFF)
|
||||
add_feature_info(ENABLE_LIBDECOR ENABLE_LIBDECOR "libdecor support.")
|
||||
|
||||
option(ENABLE_PIPEWIRE "Build with PipeWire audio output support" ON)
|
||||
add_feature_info(ENABLE_PIPEWIRE ENABLE_PIPEWIRE "PipeWire audio support.")
|
||||
|
||||
|
@ -18,6 +18,9 @@ function(add_displayserver name)
|
||||
add_subdirectory(${name})
|
||||
endfunction()
|
||||
|
||||
option(ENABLE_WAYLAND "Build with Wayland support" ON)
|
||||
add_feature_info(ENABLE_WAYLAND ENABLE_WAYLAND "Wayland support.")
|
||||
|
||||
# Add/remove displayservers here!
|
||||
if (ENABLE_WAYLAND)
|
||||
add_displayserver(Wayland)
|
||||
|
@ -8,19 +8,7 @@ pkg_check_modules(DISPLAYSERVER_Wayland REQUIRED IMPORTED_TARGET
|
||||
xkbcommon
|
||||
)
|
||||
|
||||
set(DISPLAYSERVER_Wayland_OPT_PKGCONFIG_LIBRARIES "")
|
||||
set(displayserver_Wayland_SHELL_SRC "")
|
||||
|
||||
if (ENABLE_LIBDECOR)
|
||||
pkg_check_modules(DISPLAYSERVER_Wayland_LIBDECOR REQUIRED IMPORTED_TARGET
|
||||
libdecor-0
|
||||
)
|
||||
list(APPEND DISPLAYSERVER_Wayland_OPT_PKGCONFIG_LIBRARIES PkgConfig::DISPLAYSERVER_Wayland_LIBDECOR)
|
||||
list(APPEND displayserver_Wayland_SHELL_SRC shell_libdecor.c)
|
||||
add_compile_definitions(ENABLE_LIBDECOR)
|
||||
else()
|
||||
list(APPEND displayserver_Wayland_SHELL_SRC shell_xdg.c)
|
||||
endif()
|
||||
find_program(WAYLAND_SCANNER_EXECUTABLE NAMES wayland-scanner)
|
||||
|
||||
add_library(displayserver_Wayland STATIC
|
||||
activation.c
|
||||
@ -36,66 +24,19 @@ add_library(displayserver_Wayland STATIC
|
||||
registry.c
|
||||
wayland.c
|
||||
window.c
|
||||
${displayserver_Wayland_SHELL_SRC}
|
||||
)
|
||||
|
||||
add_subdirectory(protocol)
|
||||
add_subdirectory(desktops)
|
||||
|
||||
target_link_libraries(displayserver_Wayland
|
||||
PkgConfig::DISPLAYSERVER_Wayland
|
||||
${DISPLAYSERVER_Wayland_OPT_PKGCONFIG_LIBRARIES}
|
||||
lg_common
|
||||
wayland_protocol
|
||||
wayland_desktops
|
||||
)
|
||||
|
||||
target_include_directories(displayserver_Wayland
|
||||
PRIVATE
|
||||
src
|
||||
.
|
||||
)
|
||||
|
||||
find_program(WAYLAND_SCANNER_EXECUTABLE NAMES wayland-scanner)
|
||||
|
||||
macro(wayland_generate protocol_file output_file)
|
||||
add_custom_command(OUTPUT "${output_file}.h"
|
||||
COMMAND "${WAYLAND_SCANNER_EXECUTABLE}" client-header "${protocol_file}" "${output_file}.h"
|
||||
DEPENDS "${protocol_file}"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_command(OUTPUT "${output_file}.c"
|
||||
COMMAND "${WAYLAND_SCANNER_EXECUTABLE}" private-code "${protocol_file}" "${output_file}.c"
|
||||
DEPENDS "${protocol_file}"
|
||||
VERBATIM)
|
||||
|
||||
target_sources(displayserver_Wayland PRIVATE "${output_file}.h" "${output_file}.c")
|
||||
endmacro()
|
||||
|
||||
set(WAYLAND_PROTOCOLS_BASE "${PROJECT_TOP}/repos/wayland-protocols")
|
||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/wayland")
|
||||
include_directories("${CMAKE_BINARY_DIR}/wayland")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-shell-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/stable/presentation-time/presentation-time.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-presentation-time-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/stable/viewporter/viewporter.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-viewporter-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-decoration-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/relative-pointer/relative-pointer-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-relative-pointer-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-pointer-constraints-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-keyboard-shortcuts-inhibit-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-idle-inhibit-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/xdg-output/xdg-output-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-output-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/staging/xdg-activation/xdg-activation-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-activation-v1-client-protocol")
|
||||
|
58
client/displayservers/Wayland/desktops/CMakeLists.txt
Normal file
58
client/displayservers/Wayland/desktops/CMakeLists.txt
Normal file
@ -0,0 +1,58 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
project(wayland_desktops LANGUAGES C)
|
||||
|
||||
set(DESKTOP_H "${CMAKE_BINARY_DIR}/include/dynamic/wayland_desktops.h")
|
||||
set(DESKTOP_C "${CMAKE_BINARY_DIR}/src/wayland_desktops.c")
|
||||
|
||||
file(WRITE ${DESKTOP_H} "#include \"interface/desktop.h\"\n\n")
|
||||
file(APPEND ${DESKTOP_H} "extern struct WL_DesktopOps * WL_Desktops[];\n\n")
|
||||
|
||||
file(WRITE ${DESKTOP_C} "#include \"interface/desktop.h\"\n\n")
|
||||
file(APPEND ${DESKTOP_C} "#include <stddef.h>\n\n")
|
||||
|
||||
set(DESKTOPS "_")
|
||||
set(DESKTOPS_LINK "_")
|
||||
function(add_desktop name)
|
||||
set(DESKTOPS "${DESKTOPS};${name}" PARENT_SCOPE)
|
||||
set(DESKTOPS_LINK "${DESKTOPS_LINK};wayland_desktop_${name}" PARENT_SCOPE)
|
||||
add_subdirectory(${name})
|
||||
endfunction()
|
||||
|
||||
# Add/remove desktops here!
|
||||
|
||||
# the first entry here is the default
|
||||
add_desktop(xdg)
|
||||
|
||||
pkg_check_modules(LIBDECOR REQUIRED IMPORTED_TARGET libdecor-0)
|
||||
if(LIBDECOR_FOUND)
|
||||
option(ENABLE_LIBDECOR "Build with libdecor support" ON)
|
||||
else()
|
||||
option(ENABLE_LIBDECOR "Build with libdecor support" OFF)
|
||||
endif()
|
||||
add_feature_info(ENABLE_LIBDECOR ENABLE_LIBDECOR "libdecor support.")
|
||||
if (ENABLE_LIBDECOR)
|
||||
add_desktop(libdecor)
|
||||
endif()
|
||||
|
||||
list(REMOVE_AT DESKTOPS 0)
|
||||
list(REMOVE_AT DESKTOPS_LINK 0)
|
||||
|
||||
list(LENGTH DESKTOPS DESKTOP_COUNT)
|
||||
file(APPEND ${DESKTOP_H} "#define WL_DESKTOP_COUNT ${DESKTOP_COUNT}\n")
|
||||
|
||||
foreach(desktop ${DESKTOPS})
|
||||
file(APPEND ${DESKTOP_C} "extern struct WL_DesktopOps WLD_${desktop};\n")
|
||||
endforeach()
|
||||
|
||||
file(APPEND ${DESKTOP_C} "\nconst struct WL_DesktopOps * WL_Desktops[] =\n{\n")
|
||||
foreach(desktop ${DESKTOPS})
|
||||
file(APPEND ${DESKTOP_C} " &WLD_${desktop},\n")
|
||||
endforeach()
|
||||
file(APPEND ${DESKTOP_C} " NULL\n};")
|
||||
|
||||
add_library(wayland_desktops STATIC ${DESKTOP_C})
|
||||
target_link_libraries(wayland_desktops ${DESKTOPS_LINK})
|
||||
target_include_directories(wayland_desktops
|
||||
PRIVATE
|
||||
../
|
||||
)
|
@ -0,0 +1,16 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
project(wayland_desktop_libdecor LANGUAGES C)
|
||||
|
||||
add_library(wayland_desktop_libdecor STATIC
|
||||
libdecor.c
|
||||
)
|
||||
|
||||
target_link_libraries(wayland_desktop_libdecor
|
||||
lg_common
|
||||
wayland_protocol
|
||||
PkgConfig::LIBDECOR
|
||||
)
|
||||
|
||||
include_directories(
|
||||
"../../"
|
||||
)
|
269
client/displayservers/Wayland/desktops/libdecor/libdecor.c
Normal file
269
client/displayservers/Wayland/desktops/libdecor/libdecor.c
Normal file
@ -0,0 +1,269 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* 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., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "interface/desktop.h"
|
||||
#include "wayland-xdg-shell-client-protocol.h"
|
||||
|
||||
#include "wayland.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#include <libdecor.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "app.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
// Maximum number of fds we can process at once in waylandWait
|
||||
#define MAX_EPOLL_EVENTS 10
|
||||
|
||||
typedef struct LibDecorState
|
||||
{
|
||||
bool configured;
|
||||
struct libdecor * libdecor;
|
||||
struct libdecor_frame * libdecorFrame;
|
||||
|
||||
int32_t width, height;
|
||||
bool needsResize;
|
||||
bool fullscreen;
|
||||
uint32_t resizeSerial;
|
||||
}
|
||||
LibDecorState;
|
||||
|
||||
static LibDecorState state = {0};
|
||||
|
||||
struct libdecor_configuration
|
||||
{
|
||||
uint32_t serial;
|
||||
|
||||
bool has_window_state;
|
||||
enum libdecor_window_state window_state;
|
||||
|
||||
bool has_size;
|
||||
int window_width;
|
||||
int window_height;
|
||||
};
|
||||
|
||||
static void libdecorHandleError(struct libdecor * context, enum libdecor_error error,
|
||||
const char *message)
|
||||
{
|
||||
DEBUG_ERROR("Got libdecor error (%d): %s", error, message);
|
||||
}
|
||||
|
||||
static void libdecorFrameConfigure(struct libdecor_frame * frame,
|
||||
struct libdecor_configuration * configuration, void * opaque)
|
||||
{
|
||||
if (!state.configured)
|
||||
{
|
||||
xdg_surface_ack_configure(libdecor_frame_get_xdg_surface(frame), configuration->serial);
|
||||
state.configured = true;
|
||||
return;
|
||||
}
|
||||
|
||||
int width, height;
|
||||
if (libdecor_configuration_get_content_size(configuration, frame, &width, &height))
|
||||
{
|
||||
state.width = width;
|
||||
state.height = height;
|
||||
|
||||
struct libdecor_state * s = libdecor_state_new(width, height);
|
||||
libdecor_frame_commit(state.libdecorFrame, s, NULL);
|
||||
libdecor_state_free(s);
|
||||
}
|
||||
|
||||
enum libdecor_window_state windowState;
|
||||
if (libdecor_configuration_get_window_state(configuration, &windowState))
|
||||
state.fullscreen = windowState & LIBDECOR_WINDOW_STATE_FULLSCREEN;
|
||||
|
||||
state.resizeSerial = configuration->serial;
|
||||
waylandNeedsResize();
|
||||
}
|
||||
|
||||
static void libdecorFrameClose(struct libdecor_frame * frame, void * opaque)
|
||||
{
|
||||
app_handleCloseEvent();
|
||||
}
|
||||
|
||||
static void libdecorFrameCommit(struct libdecor_frame * frame, void * opaque)
|
||||
{
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
static struct libdecor_interface libdecorListener =
|
||||
{
|
||||
libdecorHandleError,
|
||||
};
|
||||
|
||||
static struct libdecor_frame_interface libdecorFrameListener =
|
||||
{
|
||||
libdecorFrameConfigure,
|
||||
libdecorFrameClose,
|
||||
libdecorFrameCommit,
|
||||
};
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
static void libdecorCallback(uint32_t events, void * opaque)
|
||||
{
|
||||
libdecor_dispatch(state.libdecor, 0);
|
||||
}
|
||||
|
||||
static bool libdecor_shellInit(
|
||||
struct wl_display * display, struct wl_surface * surface,
|
||||
const char * title, bool fullscreen,
|
||||
bool maximize, bool borderless, bool resizable)
|
||||
{
|
||||
state.libdecor = libdecor_new(display, &libdecorListener);
|
||||
state.libdecorFrame = libdecor_decorate(state.libdecor, surface,
|
||||
&libdecorFrameListener, NULL);
|
||||
|
||||
libdecor_frame_set_app_id(state.libdecorFrame, "looking-glass-client");
|
||||
libdecor_frame_set_title(state.libdecorFrame, title);
|
||||
libdecor_frame_map(state.libdecorFrame);
|
||||
|
||||
if (resizable)
|
||||
libdecor_frame_set_capabilities(state.libdecorFrame,
|
||||
LIBDECOR_ACTION_RESIZE);
|
||||
else
|
||||
libdecor_frame_unset_capabilities(state.libdecorFrame,
|
||||
LIBDECOR_ACTION_RESIZE);
|
||||
|
||||
while (!state.configured)
|
||||
libdecor_dispatch(state.libdecor, 0);
|
||||
|
||||
if (!waylandPollRegister(libdecor_get_fd(state.libdecor),
|
||||
libdecorCallback, NULL, EPOLLIN))
|
||||
{
|
||||
DEBUG_ERROR("Failed register display to epoll: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void libdecor_shellAckConfigureIfNeeded(void)
|
||||
{
|
||||
if (state.resizeSerial)
|
||||
{
|
||||
xdg_surface_ack_configure(
|
||||
libdecor_frame_get_xdg_surface(state.libdecorFrame), state.resizeSerial);
|
||||
state.resizeSerial = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void libdecor_setFullscreen(bool fs)
|
||||
{
|
||||
if (fs)
|
||||
libdecor_frame_set_fullscreen(state.libdecorFrame, NULL);
|
||||
else
|
||||
libdecor_frame_unset_fullscreen(state.libdecorFrame);
|
||||
|
||||
libdecor_frame_set_visibility(state.libdecorFrame, !fs);
|
||||
}
|
||||
|
||||
static bool libdecor_getFullscreen(void)
|
||||
{
|
||||
return state.fullscreen;
|
||||
}
|
||||
|
||||
static void libdecor_minimize(void)
|
||||
{
|
||||
libdecor_frame_set_minimized(state.libdecorFrame);
|
||||
}
|
||||
|
||||
static void libdecor_shellResize(int w, int h)
|
||||
{
|
||||
if (!libdecor_frame_is_floating(state.libdecorFrame))
|
||||
return;
|
||||
|
||||
state.width = w;
|
||||
state.height = h;
|
||||
|
||||
struct libdecor_state * s = libdecor_state_new(w, h);
|
||||
libdecor_frame_commit(state.libdecorFrame, s, NULL);
|
||||
libdecor_state_free(s);
|
||||
|
||||
waylandNeedsResize();
|
||||
}
|
||||
|
||||
static void libdecor_setSize(int w, int h)
|
||||
{
|
||||
state.width = w;
|
||||
state.height = h;
|
||||
}
|
||||
|
||||
static void libdecor_getSize(int * w, int * h)
|
||||
{
|
||||
*w = state.width;
|
||||
*h = state.height;
|
||||
}
|
||||
|
||||
static bool libdecor_registryGlobalHandler(void * data,
|
||||
struct wl_registry * registry, uint32_t name, const char * interface,
|
||||
uint32_t version)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool libdecor_pollInit(struct wl_display * display)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void libdecor_pollWait(struct wl_display * display, int epollFd,
|
||||
unsigned int time)
|
||||
{
|
||||
libdecor_dispatch(state.libdecor, 0);
|
||||
|
||||
struct epoll_event events[MAX_EPOLL_EVENTS];
|
||||
int count;
|
||||
if ((count = epoll_wait(epollFd, events, MAX_EPOLL_EVENTS, time)) < 0)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
DEBUG_INFO("epoll failed: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
struct WaylandPoll * poll = events[i].data.ptr;
|
||||
if (!poll->removed)
|
||||
poll->callback(events[i].events, poll->opaque);
|
||||
}
|
||||
}
|
||||
|
||||
WL_DesktopOps WLD_libdecor =
|
||||
{
|
||||
.name = "libdecor",
|
||||
.compositor = "gnome-shell",
|
||||
.shellInit = libdecor_shellInit,
|
||||
.shellAckConfigureIfNeeded = libdecor_shellAckConfigureIfNeeded,
|
||||
.setFullscreen = libdecor_setFullscreen,
|
||||
.getFullscreen = libdecor_getFullscreen,
|
||||
.minimize = libdecor_minimize,
|
||||
.shellResize = libdecor_shellResize,
|
||||
.setSize = libdecor_setSize,
|
||||
.getSize = libdecor_getSize,
|
||||
.registryGlobalHandler = libdecor_registryGlobalHandler,
|
||||
.pollInit = libdecor_pollInit,
|
||||
.pollWait = libdecor_pollWait
|
||||
};
|
15
client/displayservers/Wayland/desktops/xdg/CMakeLists.txt
Normal file
15
client/displayservers/Wayland/desktops/xdg/CMakeLists.txt
Normal file
@ -0,0 +1,15 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
project(wayland_desktop_xdg LANGUAGES C)
|
||||
|
||||
add_library(wayland_desktop_xdg STATIC
|
||||
xdg.c
|
||||
)
|
||||
|
||||
target_link_libraries(wayland_desktop_xdg
|
||||
lg_common
|
||||
wayland_protocol
|
||||
)
|
||||
|
||||
include_directories(
|
||||
"../../"
|
||||
)
|
314
client/displayservers/Wayland/desktops/xdg/xdg.c
Normal file
314
client/displayservers/Wayland/desktops/xdg/xdg.c
Normal file
@ -0,0 +1,314 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* 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., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "wayland.h"
|
||||
#include "wayland-xdg-shell-client-protocol.h"
|
||||
#include "wayland-xdg-decoration-unstable-v1-client-protocol.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "app.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
// Maximum number of fds we can process at once in waylandWait
|
||||
#define MAX_EPOLL_EVENTS 10
|
||||
|
||||
typedef struct XDGState
|
||||
{
|
||||
bool configured;
|
||||
|
||||
struct xdg_wm_base * wmBase;
|
||||
struct xdg_surface * surface;
|
||||
struct xdg_toplevel * toplevel;
|
||||
struct zxdg_decoration_manager_v1 * decorationManager;
|
||||
struct zxdg_toplevel_decoration_v1 * toplevelDecoration;
|
||||
|
||||
int32_t width, height;
|
||||
uint32_t resizeSerial;
|
||||
bool fullscreen;
|
||||
bool floating;
|
||||
int displayFd;
|
||||
}
|
||||
XDGState;
|
||||
|
||||
static XDGState state = {0};
|
||||
|
||||
// XDG WM base listeners.
|
||||
|
||||
static void xdgWmBasePing(void * data, struct xdg_wm_base * xdgWmBase, uint32_t serial)
|
||||
{
|
||||
xdg_wm_base_pong(xdgWmBase, serial);
|
||||
}
|
||||
|
||||
static const struct xdg_wm_base_listener xdgWmBaseListener = {
|
||||
.ping = xdgWmBasePing,
|
||||
};
|
||||
|
||||
// XDG Surface listeners.
|
||||
|
||||
static void xdgSurfaceConfigure(void * data, struct xdg_surface * xdgSurface,
|
||||
uint32_t serial)
|
||||
{
|
||||
if (state.configured)
|
||||
{
|
||||
state.resizeSerial = serial;
|
||||
waylandNeedsResize();
|
||||
}
|
||||
else
|
||||
{
|
||||
xdg_surface_ack_configure(xdgSurface, serial);
|
||||
state.configured = true;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct xdg_surface_listener xdgSurfaceListener = {
|
||||
.configure = xdgSurfaceConfigure,
|
||||
};
|
||||
|
||||
// XDG Toplevel listeners.
|
||||
|
||||
static void xdgToplevelConfigure(void * data, struct xdg_toplevel * xdgToplevel,
|
||||
int32_t width, int32_t height, struct wl_array * states)
|
||||
{
|
||||
state.width = width;
|
||||
state.height = height;
|
||||
state.fullscreen = false;
|
||||
state.floating = true;
|
||||
|
||||
enum xdg_toplevel_state * s;
|
||||
wl_array_for_each(s, states)
|
||||
{
|
||||
switch (*s)
|
||||
{
|
||||
case XDG_TOPLEVEL_STATE_FULLSCREEN:
|
||||
state.fullscreen = true;
|
||||
// fallthrough
|
||||
case XDG_TOPLEVEL_STATE_MAXIMIZED:
|
||||
case XDG_TOPLEVEL_STATE_TILED_LEFT:
|
||||
case XDG_TOPLEVEL_STATE_TILED_RIGHT:
|
||||
case XDG_TOPLEVEL_STATE_TILED_TOP:
|
||||
case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
|
||||
state.floating = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void xdgToplevelClose(void * data, struct xdg_toplevel * xdgToplevel)
|
||||
{
|
||||
app_handleCloseEvent();
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_listener xdgToplevelListener = {
|
||||
.configure = xdgToplevelConfigure,
|
||||
.close = xdgToplevelClose,
|
||||
};
|
||||
|
||||
bool xdg_shellInit(struct wl_display * display, struct wl_surface * surface,
|
||||
const char * title, bool fullscreen, bool maximize, bool borderless,
|
||||
bool resizable)
|
||||
{
|
||||
if (!state.wmBase)
|
||||
{
|
||||
DEBUG_ERROR("Compositor missing xdg_wm_base, will not proceed");
|
||||
return false;
|
||||
}
|
||||
|
||||
xdg_wm_base_add_listener(state.wmBase, &xdgWmBaseListener, NULL);
|
||||
|
||||
state.surface = xdg_wm_base_get_xdg_surface(state.wmBase, surface);
|
||||
xdg_surface_add_listener(state.surface, &xdgSurfaceListener, NULL);
|
||||
|
||||
state.toplevel = xdg_surface_get_toplevel(state.surface);
|
||||
xdg_toplevel_add_listener(state.toplevel, &xdgToplevelListener, NULL);
|
||||
xdg_toplevel_set_title(state.toplevel, title);
|
||||
xdg_toplevel_set_app_id(state.toplevel, "looking-glass-client");
|
||||
|
||||
if (fullscreen)
|
||||
xdg_toplevel_set_fullscreen(state.toplevel, NULL);
|
||||
|
||||
if (maximize)
|
||||
xdg_toplevel_set_maximized(state.toplevel);
|
||||
|
||||
if (state.decorationManager)
|
||||
{
|
||||
state.toplevelDecoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
|
||||
state.decorationManager, state.toplevel);
|
||||
if (state.toplevelDecoration)
|
||||
{
|
||||
zxdg_toplevel_decoration_v1_set_mode(state.toplevelDecoration,
|
||||
borderless ?
|
||||
ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE :
|
||||
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void xdg_shellAckConfigureIfNeeded(void)
|
||||
{
|
||||
if (state.resizeSerial)
|
||||
{
|
||||
xdg_surface_ack_configure(state.surface, state.resizeSerial);
|
||||
state.resizeSerial = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void xdg_setFullscreen(bool fs)
|
||||
{
|
||||
if (fs)
|
||||
xdg_toplevel_set_fullscreen(state.toplevel, NULL);
|
||||
else
|
||||
xdg_toplevel_unset_fullscreen(state.toplevel);
|
||||
}
|
||||
|
||||
static bool xdg_getFullscreen(void)
|
||||
{
|
||||
return state.fullscreen;
|
||||
}
|
||||
|
||||
static void xdg_minimize(void)
|
||||
{
|
||||
xdg_toplevel_set_minimized(state.toplevel);
|
||||
}
|
||||
|
||||
static void xdg_shellResize(int w, int h)
|
||||
{
|
||||
if (!state.floating)
|
||||
return;
|
||||
|
||||
state.width = w;
|
||||
state.height = h;
|
||||
xdg_surface_set_window_geometry(state.surface, 0, 0, w, h);
|
||||
|
||||
waylandNeedsResize();
|
||||
}
|
||||
|
||||
static void xdg_setSize(int w, int h)
|
||||
{
|
||||
state.width = w;
|
||||
state.height = h;
|
||||
}
|
||||
|
||||
static void xdg_getSize(int * w, int * h)
|
||||
{
|
||||
*w = state.width;
|
||||
*h = state.height;
|
||||
}
|
||||
|
||||
static bool xdg_registryGlobalHandler(void * data,
|
||||
struct wl_registry * registry, uint32_t name, const char * interface,
|
||||
uint32_t version)
|
||||
{
|
||||
if (!strcmp(interface, xdg_wm_base_interface.name))
|
||||
{
|
||||
state.wmBase = wl_registry_bind(registry, name,
|
||||
&xdg_wm_base_interface, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!strcmp(interface, zxdg_decoration_manager_v1_interface.name))
|
||||
{
|
||||
state.decorationManager = wl_registry_bind(registry, name,
|
||||
&zxdg_decoration_manager_v1_interface, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void waylandDisplayCallback(uint32_t events, void * opaque)
|
||||
{
|
||||
struct wl_display * display = (struct wl_display *)opaque;
|
||||
if (events & EPOLLERR)
|
||||
wl_display_cancel_read(display);
|
||||
else
|
||||
wl_display_read_events(display);
|
||||
wl_display_dispatch_pending(display);
|
||||
}
|
||||
|
||||
static bool xdg_pollInit(struct wl_display * display)
|
||||
{
|
||||
state.displayFd = wl_display_get_fd(display);
|
||||
if (!waylandPollRegister(state.displayFd, waylandDisplayCallback,
|
||||
display, EPOLLIN))
|
||||
{
|
||||
DEBUG_ERROR("Failed register display to epoll: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void xdg_pollWait(struct wl_display * display, int epollFd,
|
||||
unsigned int time)
|
||||
{
|
||||
while (wl_display_prepare_read(display))
|
||||
wl_display_dispatch_pending(display);
|
||||
wl_display_flush(display);
|
||||
|
||||
struct epoll_event events[MAX_EPOLL_EVENTS];
|
||||
int count;
|
||||
if ((count = epoll_wait(epollFd, events, MAX_EPOLL_EVENTS, time)) < 0)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
DEBUG_INFO("epoll failed: %s", strerror(errno));
|
||||
wl_display_cancel_read(display);
|
||||
return;
|
||||
}
|
||||
|
||||
bool sawDisplay = false;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
struct WaylandPoll * poll = events[i].data.ptr;
|
||||
if (!poll->removed)
|
||||
poll->callback(events[i].events, poll->opaque);
|
||||
if (poll->fd == state.displayFd)
|
||||
sawDisplay = true;
|
||||
}
|
||||
|
||||
if (!sawDisplay)
|
||||
wl_display_cancel_read(display);
|
||||
}
|
||||
|
||||
WL_DesktopOps WLD_xdg =
|
||||
{
|
||||
.name = "xdg",
|
||||
.compositor = "",
|
||||
.shellInit = xdg_shellInit,
|
||||
.shellAckConfigureIfNeeded = xdg_shellAckConfigureIfNeeded,
|
||||
.setFullscreen = xdg_setFullscreen,
|
||||
.getFullscreen = xdg_getFullscreen,
|
||||
.minimize = xdg_minimize,
|
||||
.shellResize = xdg_shellResize,
|
||||
.setSize = xdg_setSize,
|
||||
.getSize = xdg_getSize,
|
||||
.registryGlobalHandler = xdg_registryGlobalHandler,
|
||||
.pollInit = xdg_pollInit,
|
||||
.pollWait = xdg_pollWait
|
||||
};
|
@ -89,18 +89,21 @@ void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface, const struct
|
||||
if (wlWm.needsResize)
|
||||
{
|
||||
bool skipResize = false;
|
||||
wl_egl_window_resize(wlWm.eglWindow, wl_fixed_to_int(wlWm.width * wlWm.scale),
|
||||
wl_fixed_to_int(wlWm.height * wlWm.scale), 0, 0);
|
||||
|
||||
if (wlWm.width == 0 || wlWm.height == 0)
|
||||
int width, height;
|
||||
wlWm.desktop->getSize(&width, &height);
|
||||
wl_egl_window_resize(wlWm.eglWindow, wl_fixed_to_int(width * wlWm.scale),
|
||||
wl_fixed_to_int(height * wlWm.scale), 0, 0);
|
||||
|
||||
if (width == 0 || height == 0)
|
||||
skipResize = true;
|
||||
else if (wlWm.fractionalScale)
|
||||
{
|
||||
wl_surface_set_buffer_scale(wlWm.surface, 1);
|
||||
if (!wlWm.viewport)
|
||||
wlWm.viewport = wp_viewporter_get_viewport(wlWm.viewporter, wlWm.surface);
|
||||
wp_viewport_set_source(wlWm.viewport, 0, 0, wlWm.width * wlWm.scale, wlWm.height * wlWm.scale);
|
||||
wp_viewport_set_destination(wlWm.viewport, wlWm.width, wlWm.height);
|
||||
wp_viewport_set_source(wlWm.viewport, 0, 0, width * wlWm.scale, height * wlWm.scale);
|
||||
wp_viewport_set_destination(wlWm.viewport, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -120,18 +123,18 @@ void waylandEGLSwapBuffers(EGLDisplay display, EGLSurface surface, const struct
|
||||
}
|
||||
|
||||
struct wl_region * region = wl_compositor_create_region(wlWm.compositor);
|
||||
wl_region_add(region, 0, 0, wlWm.width, wlWm.height);
|
||||
wl_region_add(region, 0, 0, width, height);
|
||||
wl_surface_set_opaque_region(wlWm.surface, region);
|
||||
wl_region_destroy(region);
|
||||
|
||||
app_handleResizeEvent(wlWm.width, wlWm.height, wl_fixed_to_double(wlWm.scale),
|
||||
app_handleResizeEvent(width, height, wl_fixed_to_double(wlWm.scale),
|
||||
(struct Border) {0, 0, 0, 0});
|
||||
app_invalidateWindow(true);
|
||||
waylandStopWaitFrame();
|
||||
wlWm.needsResize = skipResize;
|
||||
}
|
||||
|
||||
waylandShellAckConfigureIfNeeded();
|
||||
wlWm.desktop->shellAckConfigureIfNeeded();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -590,10 +590,13 @@ void waylandWarpPointer(int x, int y, bool exiting)
|
||||
return;
|
||||
}
|
||||
|
||||
int width, height;
|
||||
wlWm.desktop->getSize(&width, &height);
|
||||
|
||||
if (x < 0) x = 0;
|
||||
else if (x >= wlWm.width) x = wlWm.width - 1;
|
||||
else if (x >= width) x = width - 1;
|
||||
if (y < 0) y = 0;
|
||||
else if (y >= wlWm.height) y = wlWm.height - 1;
|
||||
else if (y >= height) y = height - 1;
|
||||
|
||||
struct wl_region * region = wl_compositor_create_region(wlWm.compositor);
|
||||
wl_region_add(region, x, y, 1, 1);
|
||||
|
64
client/displayservers/Wayland/interface/desktop.h
Normal file
64
client/displayservers/Wayland/interface/desktop.h
Normal file
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* 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., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _H_WAYLAND_DESKTOP_H_
|
||||
#define _H_WAYLAND_DESKTOP_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
typedef struct WL_DesktopOps
|
||||
{
|
||||
// the friendly name
|
||||
const char * name;
|
||||
|
||||
// the compositor process name to match
|
||||
const char * compositor;
|
||||
|
||||
bool (*shellInit)(
|
||||
struct wl_display * display, struct wl_surface * surface,
|
||||
const char * title, bool fullscreen, bool maximize,
|
||||
bool borderless, bool resizable);
|
||||
|
||||
void (*shellAckConfigureIfNeeded)(void);
|
||||
|
||||
void (*setFullscreen)(bool fs);
|
||||
|
||||
bool (*getFullscreen)(void);
|
||||
|
||||
void (*minimize)(void);
|
||||
|
||||
void (*shellResize)(int w, int h);
|
||||
|
||||
void (*setSize)(int w, int h);
|
||||
|
||||
void (*getSize)(int * w, int * h);
|
||||
|
||||
bool (*registryGlobalHandler)(
|
||||
void * data, struct wl_registry * registry,
|
||||
uint32_t name, const char * interface, uint32_t version);
|
||||
|
||||
bool (*pollInit)(struct wl_display * display);
|
||||
|
||||
void (*pollWait)(struct wl_display * display, int epollFd, unsigned int time);
|
||||
}
|
||||
WL_DesktopOps;
|
||||
|
||||
#endif
|
@ -30,23 +30,6 @@
|
||||
#include "common/debug.h"
|
||||
#include "common/locking.h"
|
||||
|
||||
#ifdef ENABLE_LIBDECOR
|
||||
#include <libdecor.h>
|
||||
#endif
|
||||
|
||||
#define EPOLL_EVENTS 10 // Maximum number of fds we can process at once in waylandWait
|
||||
|
||||
#ifndef ENABLE_LIBDECOR
|
||||
static void waylandDisplayCallback(uint32_t events, void * opaque)
|
||||
{
|
||||
if (events & EPOLLERR)
|
||||
wl_display_cancel_read(wlWm.display);
|
||||
else
|
||||
wl_display_read_events(wlWm.display);
|
||||
wl_display_dispatch_pending(wlWm.display);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool waylandPollInit(void)
|
||||
{
|
||||
wlWm.epollFd = epoll_create1(EPOLL_CLOEXEC);
|
||||
@ -61,58 +44,12 @@ bool waylandPollInit(void)
|
||||
LG_LOCK_INIT(wlWm.pollLock);
|
||||
LG_LOCK_INIT(wlWm.pollFreeLock);
|
||||
|
||||
#ifndef ENABLE_LIBDECOR
|
||||
wlWm.displayFd = wl_display_get_fd(wlWm.display);
|
||||
if (!waylandPollRegister(wlWm.displayFd, waylandDisplayCallback, NULL, EPOLLIN))
|
||||
{
|
||||
DEBUG_ERROR("Failed register display to epoll: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
return wlWm.desktop->pollInit(wlWm.display);
|
||||
}
|
||||
|
||||
void waylandWait(unsigned int time)
|
||||
{
|
||||
#ifdef ENABLE_LIBDECOR
|
||||
libdecor_dispatch(wlWm.libdecor, 0);
|
||||
#else
|
||||
while (wl_display_prepare_read(wlWm.display))
|
||||
wl_display_dispatch_pending(wlWm.display);
|
||||
wl_display_flush(wlWm.display);
|
||||
#endif
|
||||
|
||||
struct epoll_event events[EPOLL_EVENTS];
|
||||
int count;
|
||||
if ((count = epoll_wait(wlWm.epollFd, events, EPOLL_EVENTS, time)) < 0)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
DEBUG_INFO("epoll failed: %s", strerror(errno));
|
||||
#ifndef ENABLE_LIBDECOR
|
||||
wl_display_cancel_read(wlWm.display);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#ifndef ENABLE_LIBDECOR
|
||||
bool sawDisplay = false;
|
||||
#endif
|
||||
for (int i = 0; i < count; ++i) {
|
||||
struct WaylandPoll * poll = events[i].data.ptr;
|
||||
if (!poll->removed)
|
||||
poll->callback(events[i].events, poll->opaque);
|
||||
#ifndef ENABLE_LIBDECOR
|
||||
if (poll->fd == wlWm.displayFd)
|
||||
sawDisplay = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef ENABLE_LIBDECOR
|
||||
if (!sawDisplay)
|
||||
wl_display_cancel_read(wlWm.display);
|
||||
#endif
|
||||
|
||||
wlWm.desktop->pollWait(wlWm.display, wlWm.epollFd, time);
|
||||
INTERLOCKED_SECTION(wlWm.pollFreeLock,
|
||||
{
|
||||
struct WaylandPoll * node;
|
||||
|
71
client/displayservers/Wayland/protocol/CMakeLists.txt
Normal file
71
client/displayservers/Wayland/protocol/CMakeLists.txt
Normal file
@ -0,0 +1,71 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
project(wayland_protocol LANGUAGES C)
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(WAYLAND REQUIRED IMPORTED_TARGET
|
||||
wayland-client
|
||||
wayland-cursor
|
||||
xkbcommon
|
||||
)
|
||||
|
||||
find_program(WAYLAND_SCANNER_EXECUTABLE NAMES wayland-scanner)
|
||||
|
||||
add_library(wayland_protocol STATIC
|
||||
)
|
||||
|
||||
macro(wayland_generate protocol_file output_file)
|
||||
add_custom_command(OUTPUT "${output_file}.h"
|
||||
COMMAND "${WAYLAND_SCANNER_EXECUTABLE}" client-header "${protocol_file}" "${output_file}.h"
|
||||
DEPENDS "${protocol_file}"
|
||||
VERBATIM)
|
||||
|
||||
add_custom_command(OUTPUT "${output_file}.c"
|
||||
COMMAND "${WAYLAND_SCANNER_EXECUTABLE}" private-code "${protocol_file}" "${output_file}.c"
|
||||
DEPENDS "${protocol_file}"
|
||||
VERBATIM)
|
||||
|
||||
target_sources(wayland_protocol PRIVATE "${output_file}.h" "${output_file}.c")
|
||||
endmacro()
|
||||
|
||||
set(WAYLAND_PROTOCOLS_BASE "${PROJECT_TOP}/repos/wayland-protocols")
|
||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/wayland")
|
||||
include_directories("${CMAKE_BINARY_DIR}/wayland")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/stable/xdg-shell/xdg-shell.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-shell-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/stable/presentation-time/presentation-time.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-presentation-time-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/stable/viewporter/viewporter.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-viewporter-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-decoration-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/relative-pointer/relative-pointer-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-relative-pointer-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-pointer-constraints-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-keyboard-shortcuts-inhibit-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-idle-inhibit-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/unstable/xdg-output/xdg-output-unstable-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-output-unstable-v1-client-protocol")
|
||||
wayland_generate(
|
||||
"${WAYLAND_PROTOCOLS_BASE}/staging/xdg-activation/xdg-activation-v1.xml"
|
||||
"${CMAKE_BINARY_DIR}/wayland/wayland-xdg-activation-v1-client-protocol")
|
||||
|
||||
target_link_libraries(wayland_protocol
|
||||
PkgConfig::WAYLAND
|
||||
)
|
||||
|
||||
target_include_directories(wayland_protocol
|
||||
PUBLIC
|
||||
"${CMAKE_BINARY_DIR}/wayland"
|
||||
)
|
@ -40,13 +40,6 @@ static void registryGlobalHandler(void * data, struct wl_registry * registry,
|
||||
wlWm.compositor = wl_registry_bind(wlWm.registry, name,
|
||||
// we only need v3 to run, but v4 can use eglSwapBuffersWithDamageKHR
|
||||
&wl_compositor_interface, version > 4 ? 4 : version);
|
||||
#ifndef ENABLE_LIBDECOR
|
||||
else if (!strcmp(interface, xdg_wm_base_interface.name))
|
||||
wlWm.xdgWmBase = wl_registry_bind(wlWm.registry, name, &xdg_wm_base_interface, 1);
|
||||
else if (!strcmp(interface, zxdg_decoration_manager_v1_interface.name))
|
||||
wlWm.xdgDecorationManager = wl_registry_bind(wlWm.registry, name,
|
||||
&zxdg_decoration_manager_v1_interface, 1);
|
||||
#endif
|
||||
else if (!strcmp(interface, wp_presentation_interface.name))
|
||||
wlWm.presentation = wl_registry_bind(wlWm.registry, name,
|
||||
&wp_presentation_interface, 1);
|
||||
@ -75,6 +68,9 @@ static void registryGlobalHandler(void * data, struct wl_registry * registry,
|
||||
else if (!strcmp(interface, xdg_activation_v1_interface.name))
|
||||
wlWm.xdgActivation = wl_registry_bind(wlWm.registry, name,
|
||||
&xdg_activation_v1_interface, 1);
|
||||
else if (wlWm.desktop->registryGlobalHandler(
|
||||
data, registry, name, interface, version))
|
||||
return;
|
||||
}
|
||||
|
||||
static void registryGlobalRemoveHandler(void * data,
|
||||
|
@ -1,178 +0,0 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* 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., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "wayland.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#include <libdecor.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "app.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
struct libdecor_configuration {
|
||||
uint32_t serial;
|
||||
|
||||
bool has_window_state;
|
||||
enum libdecor_window_state window_state;
|
||||
|
||||
bool has_size;
|
||||
int window_width;
|
||||
int window_height;
|
||||
};
|
||||
|
||||
static void libdecorHandleError(struct libdecor * context, enum libdecor_error error,
|
||||
const char *message)
|
||||
{
|
||||
DEBUG_ERROR("Got libdecor error (%d): %s", error, message);
|
||||
}
|
||||
|
||||
static void libdecorFrameConfigure(struct libdecor_frame * frame,
|
||||
struct libdecor_configuration * configuration, void * opaque)
|
||||
{
|
||||
if (!wlWm.configured)
|
||||
{
|
||||
xdg_surface_ack_configure(libdecor_frame_get_xdg_surface(frame), configuration->serial);
|
||||
wlWm.configured = true;
|
||||
return;
|
||||
}
|
||||
|
||||
int width, height;
|
||||
if (libdecor_configuration_get_content_size(configuration, frame, &width, &height))
|
||||
{
|
||||
wlWm.width = width;
|
||||
wlWm.height = height;
|
||||
|
||||
struct libdecor_state * state = libdecor_state_new(wlWm.width, wlWm.height);
|
||||
libdecor_frame_commit(wlWm.libdecorFrame, state, NULL);
|
||||
libdecor_state_free(state);
|
||||
}
|
||||
|
||||
enum libdecor_window_state windowState;
|
||||
if (libdecor_configuration_get_window_state(configuration, &windowState))
|
||||
wlWm.fullscreen = windowState & LIBDECOR_WINDOW_STATE_FULLSCREEN;
|
||||
|
||||
wlWm.needsResize = true;
|
||||
wlWm.resizeSerial = configuration->serial;
|
||||
app_invalidateWindow(true);
|
||||
waylandStopWaitFrame();
|
||||
}
|
||||
|
||||
static void libdecorFrameClose(struct libdecor_frame * frame, void * opaque)
|
||||
{
|
||||
app_handleCloseEvent();
|
||||
}
|
||||
|
||||
static void libdecorFrameCommit(struct libdecor_frame * frame, void * opaque)
|
||||
{
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
static struct libdecor_interface libdecorListener = {
|
||||
libdecorHandleError,
|
||||
};
|
||||
|
||||
static struct libdecor_frame_interface libdecorFrameListener = {
|
||||
libdecorFrameConfigure,
|
||||
libdecorFrameClose,
|
||||
libdecorFrameCommit,
|
||||
};
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
static void libdecorCallback(uint32_t events, void * opaque)
|
||||
{
|
||||
libdecor_dispatch(wlWm.libdecor, 0);
|
||||
}
|
||||
|
||||
bool waylandShellInit(const char * title, bool fullscreen, bool maximize, bool borderless, bool resizable)
|
||||
{
|
||||
wlWm.libdecor = libdecor_new(wlWm.display, &libdecorListener);
|
||||
wlWm.libdecorFrame = libdecor_decorate(wlWm.libdecor, wlWm.surface, &libdecorFrameListener, NULL);
|
||||
|
||||
libdecor_frame_set_app_id(wlWm.libdecorFrame, "looking-glass-client");
|
||||
libdecor_frame_set_title(wlWm.libdecorFrame, title);
|
||||
libdecor_frame_map(wlWm.libdecorFrame);
|
||||
|
||||
if (resizable)
|
||||
libdecor_frame_set_capabilities(wlWm.libdecorFrame, LIBDECOR_ACTION_RESIZE);
|
||||
else
|
||||
libdecor_frame_unset_capabilities(wlWm.libdecorFrame, LIBDECOR_ACTION_RESIZE);
|
||||
|
||||
while (!wlWm.configured)
|
||||
libdecor_dispatch(wlWm.libdecor, 0);
|
||||
|
||||
if (!waylandPollRegister(libdecor_get_fd(wlWm.libdecor), libdecorCallback, NULL, EPOLLIN))
|
||||
{
|
||||
DEBUG_ERROR("Failed register display to epoll: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void waylandShellAckConfigureIfNeeded(void)
|
||||
{
|
||||
if (wlWm.resizeSerial)
|
||||
{
|
||||
xdg_surface_ack_configure(libdecor_frame_get_xdg_surface(wlWm.libdecorFrame), wlWm.resizeSerial);
|
||||
wlWm.resizeSerial = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void waylandSetFullscreen(bool fs)
|
||||
{
|
||||
if (fs)
|
||||
libdecor_frame_set_fullscreen(wlWm.libdecorFrame, NULL);
|
||||
else
|
||||
libdecor_frame_unset_fullscreen(wlWm.libdecorFrame);
|
||||
|
||||
libdecor_frame_set_visibility(wlWm.libdecorFrame, !fs);
|
||||
}
|
||||
|
||||
bool waylandGetFullscreen(void)
|
||||
{
|
||||
return wlWm.fullscreen;
|
||||
}
|
||||
|
||||
void waylandMinimize(void)
|
||||
{
|
||||
libdecor_frame_set_minimized(wlWm.libdecorFrame);
|
||||
}
|
||||
|
||||
void waylandShellResize(int w, int h)
|
||||
{
|
||||
if (!libdecor_frame_is_floating(wlWm.libdecorFrame))
|
||||
return;
|
||||
|
||||
wlWm.width = w;
|
||||
wlWm.height = h;
|
||||
|
||||
struct libdecor_state * state = libdecor_state_new(w, h);
|
||||
libdecor_frame_commit(wlWm.libdecorFrame, state, NULL);
|
||||
libdecor_state_free(state);
|
||||
|
||||
wlWm.needsResize = true;
|
||||
app_invalidateWindow(true);
|
||||
waylandStopWaitFrame();
|
||||
}
|
@ -1,184 +0,0 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2023 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* 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., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "wayland.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "app.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
// XDG WM base listeners.
|
||||
|
||||
static void xdgWmBasePing(void * data, struct xdg_wm_base * xdgWmBase, uint32_t serial)
|
||||
{
|
||||
xdg_wm_base_pong(xdgWmBase, serial);
|
||||
}
|
||||
|
||||
static const struct xdg_wm_base_listener xdgWmBaseListener = {
|
||||
.ping = xdgWmBasePing,
|
||||
};
|
||||
|
||||
// XDG Surface listeners.
|
||||
|
||||
static void xdgSurfaceConfigure(void * data, struct xdg_surface * xdgSurface,
|
||||
uint32_t serial)
|
||||
{
|
||||
if (wlWm.configured)
|
||||
{
|
||||
wlWm.needsResize = true;
|
||||
wlWm.resizeSerial = serial;
|
||||
app_invalidateWindow(true);
|
||||
waylandStopWaitFrame();
|
||||
}
|
||||
else
|
||||
{
|
||||
xdg_surface_ack_configure(xdgSurface, serial);
|
||||
wlWm.configured = true;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct xdg_surface_listener xdgSurfaceListener = {
|
||||
.configure = xdgSurfaceConfigure,
|
||||
};
|
||||
|
||||
// XDG Toplevel listeners.
|
||||
|
||||
static void xdgToplevelConfigure(void * data, struct xdg_toplevel * xdgToplevel,
|
||||
int32_t width, int32_t height, struct wl_array * states)
|
||||
{
|
||||
wlWm.width = width;
|
||||
wlWm.height = height;
|
||||
wlWm.fullscreen = false;
|
||||
wlWm.floating = true;
|
||||
|
||||
enum xdg_toplevel_state * state;
|
||||
wl_array_for_each(state, states)
|
||||
{
|
||||
switch (*state)
|
||||
{
|
||||
case XDG_TOPLEVEL_STATE_FULLSCREEN:
|
||||
wlWm.fullscreen = true;
|
||||
// fallthrough
|
||||
case XDG_TOPLEVEL_STATE_MAXIMIZED:
|
||||
case XDG_TOPLEVEL_STATE_TILED_LEFT:
|
||||
case XDG_TOPLEVEL_STATE_TILED_RIGHT:
|
||||
case XDG_TOPLEVEL_STATE_TILED_TOP:
|
||||
case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
|
||||
wlWm.floating = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void xdgToplevelClose(void * data, struct xdg_toplevel * xdgToplevel)
|
||||
{
|
||||
app_handleCloseEvent();
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_listener xdgToplevelListener = {
|
||||
.configure = xdgToplevelConfigure,
|
||||
.close = xdgToplevelClose,
|
||||
};
|
||||
|
||||
bool waylandShellInit(const char * title, bool fullscreen, bool maximize, bool borderless, bool resizable)
|
||||
{
|
||||
if (!wlWm.xdgWmBase)
|
||||
{
|
||||
DEBUG_ERROR("Compositor missing xdg_wm_base, will not proceed");
|
||||
return false;
|
||||
}
|
||||
|
||||
xdg_wm_base_add_listener(wlWm.xdgWmBase, &xdgWmBaseListener, NULL);
|
||||
|
||||
wlWm.xdgSurface = xdg_wm_base_get_xdg_surface(wlWm.xdgWmBase, wlWm.surface);
|
||||
xdg_surface_add_listener(wlWm.xdgSurface, &xdgSurfaceListener, NULL);
|
||||
|
||||
wlWm.xdgToplevel = xdg_surface_get_toplevel(wlWm.xdgSurface);
|
||||
xdg_toplevel_add_listener(wlWm.xdgToplevel, &xdgToplevelListener, NULL);
|
||||
xdg_toplevel_set_title(wlWm.xdgToplevel, title);
|
||||
xdg_toplevel_set_app_id(wlWm.xdgToplevel, "looking-glass-client");
|
||||
|
||||
if (fullscreen)
|
||||
xdg_toplevel_set_fullscreen(wlWm.xdgToplevel, NULL);
|
||||
|
||||
if (maximize)
|
||||
xdg_toplevel_set_maximized(wlWm.xdgToplevel);
|
||||
|
||||
if (wlWm.xdgDecorationManager)
|
||||
{
|
||||
wlWm.xdgToplevelDecoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
|
||||
wlWm.xdgDecorationManager, wlWm.xdgToplevel);
|
||||
if (wlWm.xdgToplevelDecoration)
|
||||
{
|
||||
zxdg_toplevel_decoration_v1_set_mode(wlWm.xdgToplevelDecoration,
|
||||
borderless ?
|
||||
ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE :
|
||||
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void waylandShellAckConfigureIfNeeded(void)
|
||||
{
|
||||
if (wlWm.resizeSerial)
|
||||
{
|
||||
xdg_surface_ack_configure(wlWm.xdgSurface, wlWm.resizeSerial);
|
||||
wlWm.resizeSerial = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void waylandSetFullscreen(bool fs)
|
||||
{
|
||||
if (fs)
|
||||
xdg_toplevel_set_fullscreen(wlWm.xdgToplevel, NULL);
|
||||
else
|
||||
xdg_toplevel_unset_fullscreen(wlWm.xdgToplevel);
|
||||
}
|
||||
|
||||
bool waylandGetFullscreen(void)
|
||||
{
|
||||
return wlWm.fullscreen;
|
||||
}
|
||||
|
||||
void waylandMinimize(void)
|
||||
{
|
||||
xdg_toplevel_set_minimized(wlWm.xdgToplevel);
|
||||
}
|
||||
|
||||
void waylandShellResize(int w, int h)
|
||||
{
|
||||
if (!wlWm.floating)
|
||||
return;
|
||||
|
||||
wlWm.width = w;
|
||||
wlWm.height = h;
|
||||
xdg_surface_set_window_geometry(wlWm.xdgSurface, 0, 0, w, h);
|
||||
|
||||
wlWm.needsResize = true;
|
||||
app_invalidateWindow(true);
|
||||
waylandStopWaitFrame();
|
||||
}
|
@ -24,10 +24,13 @@
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <wayland-client.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/option.h"
|
||||
|
||||
#include "dynamic/wayland_desktops.h"
|
||||
|
||||
static struct Option waylandOptions[] =
|
||||
{
|
||||
{
|
||||
@ -68,22 +71,66 @@ static bool waylandProbe(void)
|
||||
return getenv("WAYLAND_DISPLAY") != NULL;
|
||||
}
|
||||
|
||||
static bool getCompositor(char * dst, size_t size)
|
||||
{
|
||||
int fd = wl_display_get_fd(wlWm.display);
|
||||
struct ucred ucred;
|
||||
socklen_t len = sizeof(struct ucred);
|
||||
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1)
|
||||
{
|
||||
DEBUG_ERROR("Failed to get the pid of the socket");
|
||||
return false;
|
||||
}
|
||||
|
||||
char path[64];
|
||||
snprintf(path, sizeof(path), "/proc/%d/comm", ucred.pid);
|
||||
FILE *fp = fopen(path, "r");
|
||||
if (!fp)
|
||||
{
|
||||
DEBUG_ERROR("Failed to open %s", path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fgets(dst, size, fp))
|
||||
{
|
||||
DEBUG_ERROR("Failed to read %s", path);
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
dst[strlen(dst) - 1] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool waylandInit(const LG_DSInitParams params)
|
||||
{
|
||||
memset(&wlWm, 0, sizeof(wlWm));
|
||||
wlWm.desktop = WL_Desktops[0];
|
||||
|
||||
wlWm.display = wl_display_connect(NULL);
|
||||
if (!wlWm.display)
|
||||
return false;
|
||||
|
||||
// select the desktop interface based on the compositor process name
|
||||
char compositor[1024];
|
||||
if (getCompositor(compositor, sizeof(compositor)))
|
||||
{
|
||||
for(int i = 0; i < WL_DESKTOP_COUNT; ++i)
|
||||
if (strcmp(WL_Desktops[i]->compositor, compositor) == 0)
|
||||
{
|
||||
wlWm.desktop = WL_Desktops[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
DEBUG_INFO("Using %s", wlWm.desktop->name);
|
||||
|
||||
wl_list_init(&wlWm.surfaceOutputs);
|
||||
|
||||
wlWm.warpSupport = option_get_bool("wayland", "warpSupport");
|
||||
wlWm.useFractionalScale = option_get_bool("wayland", "fractionScale");
|
||||
|
||||
wlWm.width = params.w;
|
||||
wlWm.height = params.h;
|
||||
|
||||
if (!waylandPollInit())
|
||||
return false;
|
||||
|
||||
@ -108,7 +155,9 @@ static bool waylandInit(const LG_DSInitParams params)
|
||||
if (!waylandInputInit())
|
||||
return false;
|
||||
|
||||
if (!waylandWindowInit(params.title, params.fullscreen, params.maximize, params.borderless, params.resizable))
|
||||
wlWm.desktop->setSize(params.w, params.h);
|
||||
if (!waylandWindowInit(params.title, params.fullscreen, params.maximize,
|
||||
params.borderless, params.resizable))
|
||||
return false;
|
||||
|
||||
if (!waylandEGLInit(params.w, params.h))
|
||||
@ -119,9 +168,6 @@ static bool waylandInit(const LG_DSInitParams params)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
wlWm.width = params.w;
|
||||
wlWm.height = params.h;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -156,6 +202,28 @@ static bool waylandGetProp(LG_DSProperty prop, void * ret)
|
||||
return false;
|
||||
}
|
||||
|
||||
void waylandNeedsResize(void)
|
||||
{
|
||||
wlWm.needsResize = true;
|
||||
app_invalidateWindow(true);
|
||||
waylandStopWaitFrame();
|
||||
}
|
||||
|
||||
static void waylandSetFullscreen(bool fs)
|
||||
{
|
||||
wlWm.desktop->setFullscreen(fs);
|
||||
}
|
||||
|
||||
static bool waylandGetFullscreen(void)
|
||||
{
|
||||
return wlWm.desktop->getFullscreen();
|
||||
}
|
||||
|
||||
static void waylandMinimize(void)
|
||||
{
|
||||
wlWm.desktop->minimize();
|
||||
}
|
||||
|
||||
struct LG_DisplayServerOps LGDS_Wayland =
|
||||
{
|
||||
.name = "Wayland",
|
||||
|
@ -37,11 +37,10 @@
|
||||
#include "common/countedbuffer.h"
|
||||
#include "common/ringbuffer.h"
|
||||
#include "interface/displayserver.h"
|
||||
#include "interface/desktop.h"
|
||||
|
||||
#include "wayland-xdg-shell-client-protocol.h"
|
||||
#include "wayland-presentation-time-client-protocol.h"
|
||||
#include "wayland-viewporter-client-protocol.h"
|
||||
#include "wayland-xdg-decoration-unstable-v1-client-protocol.h"
|
||||
#include "wayland-keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
|
||||
#include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
|
||||
#include "wayland-relative-pointer-unstable-v1-client-protocol.h"
|
||||
@ -100,6 +99,8 @@ struct WaylandDSState
|
||||
bool pointerInSurface;
|
||||
bool focusedOnSurface;
|
||||
|
||||
WL_DesktopOps * desktop;
|
||||
|
||||
struct wl_display * display;
|
||||
struct wl_surface * surface;
|
||||
struct wl_registry * registry;
|
||||
@ -107,13 +108,9 @@ struct WaylandDSState
|
||||
struct wl_shm * shm;
|
||||
struct wl_compositor * compositor;
|
||||
|
||||
int32_t width, height;
|
||||
wl_fixed_t scale;
|
||||
bool fractionalScale;
|
||||
bool needsResize;
|
||||
bool fullscreen;
|
||||
bool floating;
|
||||
uint32_t resizeSerial;
|
||||
bool configured;
|
||||
bool warpSupport;
|
||||
double cursorX, cursorY;
|
||||
@ -134,17 +131,6 @@ struct WaylandDSState
|
||||
RingBuffer photonTimings;
|
||||
GraphHandle photonGraph;
|
||||
|
||||
#ifdef ENABLE_LIBDECOR
|
||||
struct libdecor * libdecor;
|
||||
struct libdecor_frame * libdecorFrame;
|
||||
#else
|
||||
struct xdg_wm_base * xdgWmBase;
|
||||
struct xdg_surface * xdgSurface;
|
||||
struct xdg_toplevel * xdgToplevel;
|
||||
struct zxdg_decoration_manager_v1 * xdgDecorationManager;
|
||||
struct zxdg_toplevel_decoration_v1 * xdgToplevelDecoration;
|
||||
#endif
|
||||
|
||||
const char * cursorThemeName;
|
||||
int cursorSize;
|
||||
int cursorScale;
|
||||
@ -314,14 +300,6 @@ void waylandPresentationFree(void);
|
||||
bool waylandRegistryInit(void);
|
||||
void waylandRegistryFree(void);
|
||||
|
||||
// shell module
|
||||
bool waylandShellInit(const char * title, bool fullscreen, bool maximize, bool borderless, bool resizable);
|
||||
void waylandShellAckConfigureIfNeeded(void);
|
||||
void waylandSetFullscreen(bool fs);
|
||||
bool waylandGetFullscreen(void);
|
||||
void waylandMinimize(void);
|
||||
void waylandShellResize(int w, int h);
|
||||
|
||||
// window module
|
||||
bool waylandWindowInit(const char * title, bool fullscreen, bool maximize, bool borderless, bool resizable);
|
||||
void waylandWindowFree(void);
|
||||
@ -331,3 +309,4 @@ bool waylandIsValidPointerPos(int x, int y);
|
||||
bool waylandWaitFrame(void);
|
||||
void waylandSkipFrame(void);
|
||||
void waylandStopWaitFrame(void);
|
||||
void waylandNeedsResize(void);
|
||||
|
@ -112,7 +112,8 @@ bool waylandWindowInit(const char * title, bool fullscreen, bool maximize, bool
|
||||
|
||||
wl_surface_add_listener(wlWm.surface, &wlSurfaceListener, NULL);
|
||||
|
||||
if (!waylandShellInit(title, fullscreen, maximize, borderless, resizable))
|
||||
if (!wlWm.desktop->shellInit(wlWm.display, wlWm.surface,
|
||||
title, fullscreen, maximize, borderless, resizable))
|
||||
return false;
|
||||
|
||||
wl_surface_commit(wlWm.surface);
|
||||
@ -127,12 +128,14 @@ void waylandWindowFree(void)
|
||||
|
||||
void waylandSetWindowSize(int x, int y)
|
||||
{
|
||||
waylandShellResize(x, y);
|
||||
wlWm.desktop->shellResize(x, y);
|
||||
}
|
||||
|
||||
bool waylandIsValidPointerPos(int x, int y)
|
||||
{
|
||||
return x >= 0 && x < wlWm.width && y >= 0 && y < wlWm.height;
|
||||
int width, height;
|
||||
wlWm.desktop->getSize(&width, &height);
|
||||
return x >= 0 && x < width && y >= 0 && y < height;
|
||||
}
|
||||
|
||||
static void frameHandler(void * opaque, struct wl_callback * callback, unsigned int data)
|
||||
|
Loading…
Reference in New Issue
Block a user