Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/intern
diff options
context:
space:
mode:
Diffstat (limited to 'intern')
-rw-r--r--intern/cycles/blender/addon/properties.py17
-rw-r--r--intern/cycles/blender/addon/ui.py14
-rw-r--r--intern/cycles/blender/session.cpp6
-rw-r--r--intern/cycles/device/CMakeLists.txt3
-rw-r--r--intern/cycles/device/oneapi/device_impl.cpp24
-rw-r--r--intern/cycles/integrator/path_trace_work_gpu.cpp4
-rw-r--r--intern/cycles/kernel/CMakeLists.txt7
-rw-r--r--intern/cycles/kernel/camera/projection.h26
-rw-r--r--intern/cycles/kernel/types.h1
-rw-r--r--intern/cycles/scene/camera.cpp1
-rw-r--r--intern/cycles/test/CMakeLists.txt1
-rw-r--r--intern/cycles/test/util_md5_test.cpp16
-rw-r--r--intern/cycles/util/md5.cpp9
-rw-r--r--intern/cycles/util/types_float3.h5
-rw-r--r--intern/ffmpeg/tests/ffmpeg_codecs.cc2
-rw-r--r--intern/ghost/CMakeLists.txt4
-rw-r--r--intern/ghost/intern/GHOST_ContextGLX.cpp2
-rw-r--r--intern/ghost/intern/GHOST_ImeWin32.h2
-rw-r--r--intern/ghost/intern/GHOST_System.h2
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp1249
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.h6
-rw-r--r--intern/ghost/intern/GHOST_Window.h8
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.cpp5
-rw-r--r--intern/guardedalloc/MEM_guardedalloc.h2
-rw-r--r--intern/guardedalloc/intern/leak_detector.cc2
-rw-r--r--intern/wayland_dynload/intern/wayland_dynload_client.c5
-rw-r--r--intern/wayland_dynload/intern/wayland_dynload_cursor.c2
-rw-r--r--intern/wayland_dynload/intern/wayland_dynload_egl.c2
-rw-r--r--intern/wayland_dynload/intern/wayland_dynload_libdecor.c2
-rw-r--r--intern/wayland_dynload/intern/wayland_dynload_utils.c9
-rw-r--r--intern/wayland_dynload/intern/wayland_dynload_utils.h3
31 files changed, 953 insertions, 488 deletions
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 425d123e9e6..f5cd88f6b6a 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -60,13 +60,14 @@ enum_filter_types = (
)
enum_panorama_types = (
- ('EQUIRECTANGULAR', "Equirectangular", "Render the scene with a spherical camera, also known as Lat Long panorama"),
- ('FISHEYE_EQUIDISTANT', "Fisheye Equidistant", "Ideal for fulldomes, ignore the sensor dimensions"),
+ ('EQUIRECTANGULAR', "Equirectangular", "Spherical camera for environment maps, also known as Lat Long panorama", 0),
+ ('EQUIANGULAR_CUBEMAP_FACE', "Equiangular Cubemap Face", "Single face of an equiangular cubemap", 5),
+ ('MIRRORBALL', "Mirror Ball", "Mirror ball mapping for environment maps", 3),
+ ('FISHEYE_EQUIDISTANT', "Fisheye Equidistant", "Ideal for fulldomes, ignore the sensor dimensions", 1),
('FISHEYE_EQUISOLID', "Fisheye Equisolid",
- "Similar to most fisheye modern lens, takes sensor dimensions into consideration"),
- ('MIRRORBALL', "Mirror Ball", "Uses the mirror ball mapping"),
+ "Similar to most fisheye modern lens, takes sensor dimensions into consideration", 2),
('FISHEYE_LENS_POLYNOMIAL', "Fisheye Lens Polynomial",
- "Defines the lens projection as polynomial to allow real world camera lenses to be mimicked"),
+ "Defines the lens projection as polynomial to allow real world camera lenses to be mimicked", 4),
)
enum_curve_shape = (
@@ -1636,11 +1637,13 @@ class CyclesPreferences(bpy.types.AddonPreferences):
col.label(text="and AMD driver version 22.10 or newer", icon='BLANK1')
elif device_type == 'ONEAPI':
import sys
- col.label(text="Requires Intel GPU with Xe-HPG architecture", icon='BLANK1')
if sys.platform.startswith("win"):
+ col.label(text="Requires Intel GPU with Xe-HPG architecture", icon='BLANK1')
col.label(text="and Windows driver version 101.3430 or newer", icon='BLANK1')
elif sys.platform.startswith("linux"):
- col.label(text="and Linux driver version xx.xx.23904 or newer", icon='BLANK1')
+ col.label(text="Requires Intel GPU with Xe-HPG architecture and", icon='BLANK1')
+ col.label(text=" - Linux driver version xx.xx.23904 or newer", icon='BLANK1')
+ col.label(text=" - oneAPI Level-Zero Loader", icon='BLANK1')
elif device_type == 'METAL':
col.label(text="Requires Apple Silicon with macOS 12.2 or newer", icon='BLANK1')
col.label(text="or AMD with macOS 12.3 or newer", icon='BLANK1')
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index f763fe0eb0b..305accc8f1a 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -150,6 +150,16 @@ def get_effective_preview_denoiser(context):
return 'OIDN'
+def use_mnee(context):
+ # The MNEE kernel doesn't compile on macOS < 13.
+ if use_metal(context):
+ import platform
+ v, _, _ = platform.mac_ver()
+ if float(v) < 13.0:
+ return False
+ return True
+
+
class CYCLES_RENDER_PT_sampling(CyclesButtonsPanel, Panel):
bl_label = "Sampling"
@@ -1235,7 +1245,7 @@ class CYCLES_OBJECT_PT_shading_caustics(CyclesButtonsPanel, Panel):
@classmethod
def poll(cls, context):
- return CyclesButtonsPanel.poll(context) and not use_metal(context) and context.object.type != 'LIGHT'
+ return CyclesButtonsPanel.poll(context) and use_mnee(context) and context.object.type != 'LIGHT'
def draw(self, context):
layout = self.layout
@@ -1449,7 +1459,7 @@ class CYCLES_LIGHT_PT_light(CyclesButtonsPanel, Panel):
sub.active = not (light.type == 'AREA' and clamp.is_portal)
sub.prop(clamp, "cast_shadow")
sub.prop(clamp, "use_multiple_importance_sampling", text="Multiple Importance")
- if not use_metal(context):
+ if use_mnee(context):
sub.prop(clamp, "is_caustics_light", text="Shadow Caustics")
if light.type == 'AREA':
diff --git a/intern/cycles/blender/session.cpp b/intern/cycles/blender/session.cpp
index f9a83b2dc4b..6641e2b8ac5 100644
--- a/intern/cycles/blender/session.cpp
+++ b/intern/cycles/blender/session.cpp
@@ -497,9 +497,9 @@ void BlenderSession::render_frame_finish()
session->full_buffer_written_cb = function_null;
/* The display driver is the source of drawing context for both drawing and possible graphics
- * interop objects in the path trace. Once the frame is finished the OpenGL context might be
- * freed form Blender side. Need to ensure that all GPU resources are freed prior to that
- * point.
+ * interoperability objects in the path trace. Once the frame is finished the OpenGL context
+ * might be freed form Blender side. Need to ensure that all GPU resources are freed prior to
+ * that point.
* Ideally would only do this when OpenGL context is actually destroyed, but there is no way to
* know when this happens (at least in the code at the time when this comment was written).
* The penalty of re-creating resources on every frame is unlikely to be noticed. */
diff --git a/intern/cycles/device/CMakeLists.txt b/intern/cycles/device/CMakeLists.txt
index 5296d819e42..bfca3ab6aea 100644
--- a/intern/cycles/device/CMakeLists.txt
+++ b/intern/cycles/device/CMakeLists.txt
@@ -224,7 +224,8 @@ include_directories(SYSTEM ${INC_SYS})
cycles_add_library(cycles_device "${LIB}" ${SRC})
if(WITH_CYCLES_DEVICE_ONEAPI)
- # Need to have proper rebuilding in case of changes in cycles_kernel_oneapi due external project behaviour
+ # Need to have proper rebuilding in case of changes
+ # in cycles_kernel_oneapi due external project behavior.
add_dependencies(cycles_device cycles_kernel_oneapi)
endif()
diff --git a/intern/cycles/device/oneapi/device_impl.cpp b/intern/cycles/device/oneapi/device_impl.cpp
index 3588b75713b..d0ddd69289c 100644
--- a/intern/cycles/device/oneapi/device_impl.cpp
+++ b/intern/cycles/device/oneapi/device_impl.cpp
@@ -668,8 +668,9 @@ int OneapiDevice::parse_driver_build_version(const sycl::device &device)
std::vector<sycl::device> OneapiDevice::available_devices()
{
bool allow_all_devices = false;
- if (getenv("CYCLES_ONEAPI_ALL_DEVICES") != nullptr)
+ if (getenv("CYCLES_ONEAPI_ALL_DEVICES") != nullptr) {
allow_all_devices = true;
+ }
const std::vector<sycl::platform> &oneapi_platforms = sycl::platform::get_platforms();
@@ -686,15 +687,16 @@ std::vector<sycl::device> OneapiDevice::available_devices()
platform.get_devices(sycl::info::device_type::gpu);
for (const sycl::device &device : oneapi_devices) {
+ bool filter_out = false;
if (!allow_all_devices) {
- bool filter_out = false;
-
/* For now we support all Intel(R) Arc(TM) devices and likely any future GPU,
* assuming they have either more than 96 Execution Units or not 7 threads per EU.
* Official support can be broaden to older and smaller GPUs once ready. */
- if (device.is_gpu() && platform.get_backend() == sycl::backend::ext_oneapi_level_zero) {
- /* Filtered-out defaults in-case these values aren't available through too old L0
- * runtime. */
+ if (!device.is_gpu() || platform.get_backend() != sycl::backend::ext_oneapi_level_zero) {
+ filter_out = true;
+ }
+ else {
+ /* Filtered-out defaults in-case these values aren't available. */
int number_of_eus = 96;
int threads_per_eu = 7;
if (device.has(sycl::aspect::ext_intel_gpu_eu_count)) {
@@ -718,13 +720,9 @@ std::vector<sycl::device> OneapiDevice::available_devices()
}
}
}
- else if (!allow_all_devices) {
- filter_out = true;
- }
-
- if (!filter_out) {
- available_devices.push_back(device);
- }
+ }
+ if (!filter_out) {
+ available_devices.push_back(device);
}
}
}
diff --git a/intern/cycles/integrator/path_trace_work_gpu.cpp b/intern/cycles/integrator/path_trace_work_gpu.cpp
index 48f6cf3c903..547e8d50a22 100644
--- a/intern/cycles/integrator/path_trace_work_gpu.cpp
+++ b/intern/cycles/integrator/path_trace_work_gpu.cpp
@@ -100,8 +100,8 @@ void PathTraceWorkGPU::alloc_integrator_soa()
integrator_state_soa_volume_stack_size_ = max(integrator_state_soa_volume_stack_size_,
requested_volume_stack_size);
- /* Deterine the number of path states. Deferring this for as long as possible allows the backend
- * to make better decisions about memory availability. */
+ /* Determine the number of path states. Deferring this for as long as possible allows the
+ * back-end to make better decisions about memory availability. */
if (max_num_paths_ == 0) {
size_t single_state_size = estimate_single_state_size(kernel_features);
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index 81c5f593974..3779fdc697a 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -866,8 +866,8 @@ if(WITH_CYCLES_DEVICE_ONEAPI)
else()
list(APPEND sycl_compiler_flags -fPIC)
- # We avoid getting __FAST_MATH__ to be defined when building on CentOS 7 until the compilation crash
- # it triggers at either AoT or JIT stages gets fixed.
+ # We avoid getting __FAST_MATH__ to be defined when building on CentOS 7 until the compilation
+ # crash it triggers at either AoT or JIT stages gets fixed.
list(APPEND sycl_compiler_flags -fhonor-nans)
# add $ORIGIN to cycles_kernel_oneapi.so rpath so libsycl.so and
@@ -881,7 +881,8 @@ if(WITH_CYCLES_DEVICE_ONEAPI)
OUTPUT ${cycles_kernel_oneapi_lib}
COMMAND ${CMAKE_COMMAND} -E env
"LD_LIBRARY_PATH=${sycl_compiler_root}/../lib:${OCLOC_INSTALL_DIR}/lib:${IGC_INSTALL_DIR}/lib"
- "PATH=${OCLOC_INSTALL_DIR}/bin:${sycl_compiler_root}:$ENV{PATH}" # env PATH is for compiler to find ld
+ # `$ENV{PATH}` is for compiler to find `ld`.
+ "PATH=${OCLOC_INSTALL_DIR}/bin:${sycl_compiler_root}:$ENV{PATH}"
${SYCL_COMPILER} $<$<CONFIG:Debug>:-g>$<$<CONFIG:RelWithDebInfo>:-g> ${sycl_compiler_flags}
DEPENDS ${cycles_oneapi_kernel_sources})
endif()
diff --git a/intern/cycles/kernel/camera/projection.h b/intern/cycles/kernel/camera/projection.h
index c9fe3a6c7fb..1d16aa35abe 100644
--- a/intern/cycles/kernel/camera/projection.h
+++ b/intern/cycles/kernel/camera/projection.h
@@ -201,11 +201,35 @@ ccl_device float2 direction_to_mirrorball(float3 dir)
return make_float2(u, v);
}
+/* Single face of a equiangular cube map projection as described in
+ https://blog.google/products/google-ar-vr/bringing-pixels-front-and-center-vr-video/ */
+ccl_device float3 equiangular_cubemap_face_to_direction(float u, float v)
+{
+ u = (1.0f - u);
+
+ u = tanf(u * M_PI_2_F - M_PI_4_F);
+ v = tanf(v * M_PI_2_F - M_PI_4_F);
+
+ return make_float3(1.0f, u, v);
+}
+
+ccl_device float2 direction_to_equiangular_cubemap_face(float3 dir)
+{
+ float u = atan2f(dir.y, dir.x) * 2.0f / M_PI_F + 0.5f;
+ float v = atan2f(dir.z, dir.x) * 2.0f / M_PI_F + 0.5f;
+
+ u = 1.0f - u;
+
+ return make_float2(u, v);
+}
+
ccl_device_inline float3 panorama_to_direction(ccl_constant KernelCamera *cam, float u, float v)
{
switch (cam->panorama_type) {
case PANORAMA_EQUIRECTANGULAR:
return equirectangular_range_to_direction(u, v, cam->equirectangular_range);
+ case PANORAMA_EQUIANGULAR_CUBEMAP_FACE:
+ return equiangular_cubemap_face_to_direction(u, v);
case PANORAMA_MIRRORBALL:
return mirrorball_to_direction(u, v);
case PANORAMA_FISHEYE_EQUIDISTANT:
@@ -230,6 +254,8 @@ ccl_device_inline float2 direction_to_panorama(ccl_constant KernelCamera *cam, f
switch (cam->panorama_type) {
case PANORAMA_EQUIRECTANGULAR:
return direction_to_equirectangular_range(dir, cam->equirectangular_range);
+ case PANORAMA_EQUIANGULAR_CUBEMAP_FACE:
+ return direction_to_equiangular_cubemap_face(dir);
case PANORAMA_MIRRORBALL:
return direction_to_mirrorball(dir);
case PANORAMA_FISHEYE_EQUIDISTANT:
diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h
index 8f7cfd19169..24c5a6a4540 100644
--- a/intern/cycles/kernel/types.h
+++ b/intern/cycles/kernel/types.h
@@ -490,6 +490,7 @@ enum PanoramaType {
PANORAMA_FISHEYE_EQUISOLID = 2,
PANORAMA_MIRRORBALL = 3,
PANORAMA_FISHEYE_LENS_POLYNOMIAL = 4,
+ PANORAMA_EQUIANGULAR_CUBEMAP_FACE = 5,
PANORAMA_NUM_TYPES,
};
diff --git a/intern/cycles/scene/camera.cpp b/intern/cycles/scene/camera.cpp
index 240e5d9c128..255dd320ec7 100644
--- a/intern/cycles/scene/camera.cpp
+++ b/intern/cycles/scene/camera.cpp
@@ -84,6 +84,7 @@ NODE_DEFINE(Camera)
static NodeEnum panorama_type_enum;
panorama_type_enum.insert("equirectangular", PANORAMA_EQUIRECTANGULAR);
+ panorama_type_enum.insert("equiangular_cubemap_face", PANORAMA_EQUIANGULAR_CUBEMAP_FACE);
panorama_type_enum.insert("mirrorball", PANORAMA_MIRRORBALL);
panorama_type_enum.insert("fisheye_equidistant", PANORAMA_FISHEYE_EQUIDISTANT);
panorama_type_enum.insert("fisheye_equisolid", PANORAMA_FISHEYE_EQUISOLID);
diff --git a/intern/cycles/test/CMakeLists.txt b/intern/cycles/test/CMakeLists.txt
index b126247de5f..c3ae81ed1db 100644
--- a/intern/cycles/test/CMakeLists.txt
+++ b/intern/cycles/test/CMakeLists.txt
@@ -34,6 +34,7 @@ set(SRC
render_graph_finalize_test.cpp
util_aligned_malloc_test.cpp
util_math_test.cpp
+ util_md5_test.cpp
util_path_test.cpp
util_string_test.cpp
util_task_test.cpp
diff --git a/intern/cycles/test/util_md5_test.cpp b/intern/cycles/test/util_md5_test.cpp
new file mode 100644
index 00000000000..abc147b70a1
--- /dev/null
+++ b/intern/cycles/test/util_md5_test.cpp
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: Apache-2.0
+ * Copyright 2011-2022 Blender Foundation */
+
+#include "testing/testing.h"
+
+#include "util/md5.h"
+
+CCL_NAMESPACE_BEGIN
+
+TEST(util, util_md5_string)
+{
+ /* The hash is calculated using `echo -n "Hello, World\!" | md5 | tr '[:lower:]' '[:upper:]'`. */
+ EXPECT_EQ(util_md5_string("Hello, World!"), "65A8E27D8879283831B664BD8B7F0AD4");
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/util/md5.cpp b/intern/cycles/util/md5.cpp
index 1c7e6b9bf3e..3342d7a509a 100644
--- a/intern/cycles/util/md5.cpp
+++ b/intern/cycles/util/md5.cpp
@@ -347,13 +347,18 @@ void MD5Hash::finish(uint8_t digest[16])
string MD5Hash::get_hex()
{
+ constexpr char kHexDigits[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
uint8_t digest[16];
char buf[16 * 2 + 1];
finish(digest);
- for (int i = 0; i < 16; i++)
- sprintf(buf + i * 2, "%02X", (unsigned int)digest[i]);
+ for (int i = 0; i < 16; i++) {
+ buf[i * 2 + 0] = kHexDigits[digest[i] / 0x10];
+ buf[i * 2 + 1] = kHexDigits[digest[i] % 0x10];
+ }
buf[sizeof(buf) - 1] = '\0';
return string(buf);
diff --git a/intern/cycles/util/types_float3.h b/intern/cycles/util/types_float3.h
index 87c6b1d3654..34430945c38 100644
--- a/intern/cycles/util/types_float3.h
+++ b/intern/cycles/util/types_float3.h
@@ -10,7 +10,12 @@
CCL_NAMESPACE_BEGIN
#ifndef __KERNEL_NATIVE_VECTOR_TYPES__
+# ifdef __KERNEL_ONEAPI__
+/* Define float3 as packed for oneAPI. */
+struct float3
+# else
struct ccl_try_align(16) float3
+# endif
{
# ifdef __KERNEL_GPU__
/* Compact structure for GPU. */
diff --git a/intern/ffmpeg/tests/ffmpeg_codecs.cc b/intern/ffmpeg/tests/ffmpeg_codecs.cc
index e5c33202417..10cbe4b938b 100644
--- a/intern/ffmpeg/tests/ffmpeg_codecs.cc
+++ b/intern/ffmpeg/tests/ffmpeg_codecs.cc
@@ -40,7 +40,7 @@ bool test_acodec(const AVCodec *codec, AVSampleFormat fmt)
if (ctx) {
ctx->sample_fmt = fmt;
ctx->sample_rate = 48000;
- ctx->channel_layout = AV_CH_LAYOUT_MONO;
+ av_channel_layout_from_mask(&ctx->ch_layout, AV_CH_LAYOUT_MONO);
ctx->bit_rate = 128000;
int open = avcodec_open2(ctx, codec, NULL);
if (open >= 0) {
diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt
index fb10530bfae..ea21d831b0c 100644
--- a/intern/ghost/CMakeLists.txt
+++ b/intern/ghost/CMakeLists.txt
@@ -385,9 +385,9 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
"${WAYLAND_PROTOCOLS_DIR}/unstable/primary-selection/primary-selection-unstable-v1.xml"
)
- add_definitions(-DWITH_GHOST_WAYLAND)
-
unset(INC_DST)
+
+ add_definitions(-DWITH_GHOST_WAYLAND)
endif()
if(WITH_INPUT_NDOF)
diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp
index 93708983f37..d9f2df21ee0 100644
--- a/intern/ghost/intern/GHOST_ContextGLX.cpp
+++ b/intern/ghost/intern/GHOST_ContextGLX.cpp
@@ -140,7 +140,7 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
/* End Inline GLEW. */
/* -------------------------------------------------------------------- */
#else
- /* Important to initialize only glxew (_not_ GLEW),
+ /* Important to initialize only GLXEW (_not_ GLEW),
* since this breaks w/ Mesa's `swrast`, see: T46431. */
glxewInit();
#endif /* USE_GLXEW_INIT_WORKAROUND */
diff --git a/intern/ghost/intern/GHOST_ImeWin32.h b/intern/ghost/intern/GHOST_ImeWin32.h
index 85c8ed7b4bd..cb6d8a770cf 100644
--- a/intern/ghost/intern/GHOST_ImeWin32.h
+++ b/intern/ghost/intern/GHOST_ImeWin32.h
@@ -266,7 +266,7 @@ class GHOST_ImeWin32 {
* Parameters
* * window_handle [in] (HWND)
* Represents the window handle of the caller.
- * * caret_rect [in] (const gfx::Rect&)
+ * * caret_rect [in] (`const gfx::Rect&`)
* Represent the rectangle of the input caret.
* This rectangle is used for controlling the positions of IME windows.
* * complete [in] (bool)
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h
index 810f828a8a1..924a4bff790 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -76,7 +76,7 @@ class GHOST_System : public GHOST_ISystem {
GHOST_ITimerTask *installTimer(uint64_t delay,
uint64_t interval,
GHOST_TimerProcPtr timerProc,
- GHOST_TUserDataPtr userData = NULL);
+ GHOST_TUserDataPtr userData = nullptr);
/**
* Removes a timer.
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index 23f7c5060c0..3a0ba5cd21a 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -96,13 +96,12 @@ static void gwl_registry_entry_remove_all(GWL_Display *display);
struct GWL_RegistryHandler;
static int gwl_registry_handler_interface_slot_max();
+static int gwl_registry_handler_interface_slot_from_string(const char *interface);
static const struct GWL_RegistryHandler *gwl_registry_handler_from_interface_slot(
int interface_slot);
/* -------------------------------------------------------------------- */
-/** \name Local Defines
- *
- * Control local functionality, compositors specific workarounds.
+/** \name Workaround Compositor Specific Bugs
* \{ */
/**
@@ -142,7 +141,7 @@ static bool use_gnome_confine_hack = false;
/**
* KDE (plasma 5.26.1) has a bug where the cursor surface needs to be committed
* (via `wl_surface_commit`) when it was hidden and is being set to visible again, see: T102048.
- * TODO: report this bug up-stream.
+ * See: https://bugs.kde.org/show_bug.cgi?id=461001
*/
#define USE_KDE_TABLET_HIDDEN_CURSOR_HACK
@@ -155,6 +154,18 @@ static bool use_gnome_confine_hack = false;
# define USE_GNOME_NEEDS_LIBDECOR_HACK
#endif
+/* -------------------------------------------------------------------- */
+/** \name Local Defines
+ *
+ * Control local functionality, compositors specific workarounds.
+ * \{ */
+
+/**
+ * Fix short-cut part of keyboard reading code not properly handling some keys, see: T102194.
+ * \note This is similar to X11 workaround by the same name, see: T47228.
+ */
+#define USE_NON_LATIN_KB_WORKAROUND
+
#define WL_NAME_UNSET uint32_t(-1)
/** \} */
@@ -197,6 +208,19 @@ static bool use_gnome_confine_hack = false;
*/
#define KEY_GRAVE 41
+#ifdef USE_NON_LATIN_KB_WORKAROUND
+# define KEY_1 2
+# define KEY_2 3
+# define KEY_3 4
+# define KEY_4 5
+# define KEY_5 6
+# define KEY_6 7
+# define KEY_7 8
+# define KEY_8 9
+# define KEY_9 10
+# define KEY_0 11
+#endif
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -279,15 +303,6 @@ static void gwl_simple_buffer_free_data(GWL_SimpleBuffer *buffer)
buffer->data_size = 0;
}
-static void gwl_simple_buffer_set_and_take_ownership(GWL_SimpleBuffer *buffer,
- const char *data,
- size_t data_size)
-{
- free(const_cast<char *>(buffer->data));
- buffer->data = data;
- buffer->data_size = data_size;
-}
-
static void gwl_simple_buffer_set_from_string(GWL_SimpleBuffer *buffer, const char *str)
{
free(const_cast<char *>(buffer->data));
@@ -297,14 +312,6 @@ static void gwl_simple_buffer_set_from_string(GWL_SimpleBuffer *buffer, const ch
buffer->data = data;
}
-static char *gwl_simple_buffer_as_string(const GWL_SimpleBuffer *buffer)
-{
- char *buffer_str = static_cast<char *>(malloc(buffer->data_size + 1));
- memcpy(buffer_str, buffer->data, buffer->data_size);
- buffer_str[buffer->data_size] = '\0';
- return buffer_str;
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -328,7 +335,7 @@ struct GWL_Cursor {
bool is_hardware = true;
/** When true, a custom image is used to display the cursor (stored in `wl_image`). */
bool is_custom = false;
- struct wl_surface *wl_surface = nullptr;
+ struct wl_surface *wl_surface_cursor = nullptr;
struct wl_buffer *wl_buffer = nullptr;
struct wl_cursor_image wl_image = {0};
struct wl_cursor_theme *wl_theme = nullptr;
@@ -376,10 +383,14 @@ struct GWL_TabletTool {
struct GWL_DataOffer {
struct wl_data_offer *id = nullptr;
std::unordered_set<std::string> types;
- std::atomic<bool> in_use = false;
struct {
/**
+ * Prevents freeing after #wl_data_device_listener.leave,
+ * before #wl_data_device_listener.drop.
+ */
+ bool in_use = false;
+ /**
* Bit-mask with available drop options.
* #WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY, #WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE.. etc.
* The application that initializes the drag may set these depending on modifiers held
@@ -468,7 +479,7 @@ struct GWL_SeatStatePointer {
* The wl_surface last used with this pointing device
* (events with this pointing device will be sent here).
*/
- struct wl_surface *wl_surface = nullptr;
+ struct wl_surface *wl_surface_window = nullptr;
GHOST_Buttons buttons = GHOST_Buttons();
};
@@ -530,7 +541,7 @@ struct GWL_SeatStateKeyboard {
* The wl_surface last used with this pointing device
* (events with this pointing device will be sent here).
*/
- struct wl_surface *wl_surface = nullptr;
+ struct wl_surface *wl_surface_window = nullptr;
};
/**
@@ -580,7 +591,6 @@ static void gwl_xdg_decor_system_destroy(struct GWL_Display *display, GWL_XDG_De
struct GWL_PrimarySelection_DataOffer {
struct zwp_primary_selection_offer_v1 *id = nullptr;
- std::atomic<bool> in_use = false;
std::unordered_set<std::string> types;
};
@@ -678,12 +688,22 @@ struct GWL_Seat {
* Keep a state with no modifiers active, use for symbol lookups.
*/
struct xkb_state *xkb_state_empty = nullptr;
+
+ /**
+ * Keep a state with shift enabled, use to access predictable number access for AZERTY keymaps.
+ * If shift is not supported by the key-map, this is set to NULL.
+ */
+ struct xkb_state *xkb_state_empty_with_shift = nullptr;
/**
* Keep a state with number-lock enabled, use to access predictable key-pad symbols.
* If number-lock is not supported by the key-map, this is set to NULL.
*/
struct xkb_state *xkb_state_empty_with_numlock = nullptr;
+#ifdef USE_NON_LATIN_KB_WORKAROUND
+ bool xkb_use_non_latin_workaround = false;
+#endif
+
/** Keys held matching `xkb_state`. */
struct GWL_KeyboardDepressedState key_depressed;
@@ -710,7 +730,7 @@ struct GWL_Seat {
GHOST_ITimerTask *timer = nullptr;
} key_repeat;
- struct wl_surface *wl_surface_focus_dnd = nullptr;
+ struct wl_surface *wl_surface_window_focus_dnd = nullptr;
struct wl_data_device *wl_data_device = nullptr;
/** Drag & Drop. */
@@ -766,8 +786,16 @@ struct GWL_RegistryEntry;
struct GWL_Display {
GHOST_SystemWayland *system = nullptr;
+ /**
+ * True when initializing registration, while updating all other entries wont cause problems,
+ * it will preform many redundant update calls.
+ */
+ bool registry_skip_update_all = false;
+
+ /** Registry entries, kept to allow updating & removal at run-time. */
struct GWL_RegistryEntry *registry_entry = nullptr;
+ struct wl_registry *wl_registry = nullptr;
struct wl_display *wl_display = nullptr;
struct wl_compositor *wl_compositor = nullptr;
@@ -781,22 +809,44 @@ struct GWL_Display {
struct wl_shm *wl_shm = nullptr;
std::vector<GWL_Output *> outputs;
std::vector<GWL_Seat *> seats;
+ /**
+ * Support a single active seat at once, this isn't an exact or correct mapping from WAYLAND.
+ * Only allow input from different seats, not full concurrent multi-seat support.
+ *
+ * The main purpose of having an active seat is an alternative from always using the first
+ * seat which prevents events from any other seat.
+ *
+ * NOTE(@campbellbarton): This could be extended and developed further extended to support
+ * an active seat per window (for e.g.), basic support is sufficient for now as currently isn't
+ * a widely used feature.
+ */
+ int seats_active_index = 0;
+ /* Managers. */
struct wl_data_device_manager *wl_data_device_manager = nullptr;
struct zwp_tablet_manager_v2 *wp_tablet_manager = nullptr;
struct zwp_relative_pointer_manager_v1 *wp_relative_pointer_manager = nullptr;
- struct zwp_pointer_constraints_v1 *wp_pointer_constraints = nullptr;
- struct zwp_pointer_gestures_v1 *wp_pointer_gestures = nullptr;
-
struct zwp_primary_selection_device_manager_v1 *wp_primary_selection_device_manager = nullptr;
- GWL_SimpleBuffer clipboard;
- GWL_SimpleBuffer clipboard_primary;
- std::mutex clipboard_mutex;
+ struct zwp_pointer_constraints_v1 *wp_pointer_constraints = nullptr;
+ struct zwp_pointer_gestures_v1 *wp_pointer_gestures = nullptr;
};
+/**
+ * Free the #GWL_Display and it's related members.
+ *
+ * \note This may run on a partially initialized struct,
+ * so it can't be assumed all members are set.
+ */
static void gwl_display_destroy(GWL_Display *display)
{
+ /* For typical WAYLAND use this will always be set.
+ * However when WAYLAND isn't running, this will early-exit and be null. */
+ if (display->wl_registry) {
+ wl_registry_destroy(display->wl_registry);
+ display->wl_registry = nullptr;
+ }
+
/* Unregister items in reverse order. */
gwl_registry_entry_remove_all(display);
@@ -824,13 +874,38 @@ static void gwl_display_destroy(GWL_Display *display)
wl_display_disconnect(display->wl_display);
}
- {
- std::lock_guard lock{display->clipboard_mutex};
- gwl_simple_buffer_free_data(&display->clipboard);
- gwl_simple_buffer_free_data(&display->clipboard_primary);
+ delete display;
+}
+
+static int gwl_display_seat_index(GWL_Display *display, const GWL_Seat *seat)
+{
+ std::vector<GWL_Seat *>::iterator iter = std::find(
+ display->seats.begin(), display->seats.end(), seat);
+ const int index = (iter != display->seats.cend()) ? std::distance(display->seats.begin(), iter) :
+ -1;
+ GHOST_ASSERT(index != -1, "invalid internal state");
+ return index;
+}
+
+static GWL_Seat *gwl_display_seat_active_get(const GWL_Display *display)
+{
+ if (UNLIKELY(display->seats.empty())) {
+ return nullptr;
}
+ return display->seats[display->seats_active_index];
+}
- delete display;
+static bool gwl_display_seat_active_set(GWL_Display *display, const GWL_Seat *seat)
+{
+ if (UNLIKELY(display->seats.empty())) {
+ return false;
+ }
+ const int index = gwl_display_seat_index(display, seat);
+ if (index == display->seats_active_index) {
+ return false;
+ }
+ display->seats_active_index = index;
+ return true;
}
/** \} */
@@ -840,22 +915,42 @@ static void gwl_display_destroy(GWL_Display *display)
* \{ */
struct GWL_RegisteryAdd_Params {
- struct GWL_Display *display = nullptr;
- struct wl_registry *wl_registry = nullptr;
uint32_t name = 0;
- uint32_t version = 0;
/** Index within `gwl_registry_handlers`. */
int interface_slot = 0;
+ uint32_t version = 0;
};
/**
* Add callback for object registry.
+ * \note Any operations that depend on other interfaces being registered must be performed in the
+ * #GWL_RegistryHandler_UpdateFn callback as the order interfaces are added is out of our control.
+ *
* \param display: The display which holes a reference to the global object.
* \param params: Various arguments needed for registration.
*/
using GWL_RegistryHandler_AddFn = void (*)(GWL_Display *display,
const GWL_RegisteryAdd_Params *params);
+struct GWL_RegisteryUpdate_Params {
+ uint32_t name = 0;
+ /** Index within `gwl_registry_handlers`. */
+ int interface_slot = 0;
+ uint32_t version = 0;
+
+ /** Set to #GWL_RegistryEntry.user_data. */
+ void *user_data = nullptr;
+};
+
+/**
+ * Optional update callback to refresh internal data when another interface has been added/removed.
+ *
+ * \param display: The display which holes a reference to the global object.
+ * \param params: Various arguments needed for updating.
+ */
+using GWL_RegistryHandler_UpdateFn = void (*)(GWL_Display *display,
+ const GWL_RegisteryUpdate_Params *params);
+
/**
* Remove callback for object registry.
* \param display: The display which holes a reference to the global object.
@@ -872,7 +967,11 @@ struct GWL_RegistryHandler {
/** Pointer to the name (not the name it's self), needed as the values aren't set on startup. */
const char *const *interface_p = nullptr;
+ /** Add the interface. */
GWL_RegistryHandler_AddFn add_fn = nullptr;
+ /** Optional update the interface (when other interfaces have been added/removed). */
+ GWL_RegistryHandler_UpdateFn update_fn = nullptr;
+ /** Remove the interface. */
GWL_RegistryEntry_RemoveFn remove_fn = nullptr;
};
@@ -899,6 +998,10 @@ struct GWL_RegistryEntry {
*/
uint32_t name = WL_NAME_UNSET;
/**
+ * Version passed by the add callback.
+ */
+ uint32_t version;
+ /**
* The index in `gwl_registry_handlers`,
* useful for accessing the interface name (for logging for example).
*/
@@ -906,14 +1009,14 @@ struct GWL_RegistryEntry {
};
static void gwl_registry_entry_add(GWL_Display *display,
- const int interface_slot,
- const uint32_t name,
+ const GWL_RegisteryAdd_Params *params,
void *user_data)
{
GWL_RegistryEntry *reg = new GWL_RegistryEntry;
- reg->interface_slot = interface_slot;
- reg->name = name;
+ reg->interface_slot = params->interface_slot;
+ reg->name = params->name;
+ reg->version = params->version;
reg->user_data = user_data;
reg->next = display->registry_entry;
@@ -1005,6 +1108,49 @@ static void gwl_registry_entry_remove_all(GWL_Display *display)
display->registry_entry = nullptr;
}
+/**
+ * Run GWL_RegistryHandler.update_fn an all registered interface instances.
+ * This is needed to refresh the state of interfaces that may reference other interfaces.
+ * Called when interfaces are added/removed.
+ *
+ * \param interface_slot_exclude: Skip updating slots of this type.
+ * Note that while harmless dependencies only exist between different types,
+ * so there is no reason to update all other outputs that an output was removed (for e.g.).
+ * Pass as -1 to update all slots.
+ *
+ * NOTE(@campbellbarton): Updating all other items on a single change is typically worth avoiding.
+ * In practice this isn't a problem as so there are so few elements in `display->registry_entry`,
+ * so few use update functions and adding/removal at runtime is rarely called (plugging/unplugging)
+ * hardware for e.g. So while it's possible to store dependency links to avoid unnecessary
+ * looping over data - it ends up being a non issue.
+ */
+static void gwl_registry_entry_update_all(GWL_Display *display, const int interface_slot_exclude)
+{
+ GHOST_ASSERT(interface_slot_exclude == -1 || (uint(interface_slot_exclude) <
+ uint(gwl_registry_handler_interface_slot_max())),
+ "Invalid exclude slot");
+
+ for (GWL_RegistryEntry *reg = display->registry_entry; reg; reg = reg->next) {
+ if (reg->interface_slot == interface_slot_exclude) {
+ continue;
+ }
+ const GWL_RegistryHandler *handler = gwl_registry_handler_from_interface_slot(
+ reg->interface_slot);
+ if (handler->update_fn == nullptr) {
+ continue;
+ }
+
+ GWL_RegisteryUpdate_Params params = {
+ .name = reg->name,
+ .interface_slot = reg->interface_slot,
+ .version = reg->version,
+
+ .user_data = reg->user_data,
+ };
+ handler->update_fn(display, &params);
+ }
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1201,7 +1347,7 @@ static GHOST_TTabletMode tablet_tool_map_type(enum zwp_tablet_tool_v2_type wp_ta
static const int default_cursor_size = 24;
-static const std::unordered_map<GHOST_TStandardCursor, const char *> cursors = {
+static const std::unordered_map<GHOST_TStandardCursor, const char *> ghost_wl_cursors = {
{GHOST_kStandardCursorDefault, "left_ptr"},
{GHOST_kStandardCursorRightArrow, "right_ptr"},
{GHOST_kStandardCursorLeftArrow, "left_ptr"},
@@ -1242,23 +1388,23 @@ static const std::unordered_map<GHOST_TStandardCursor, const char *> cursors = {
{GHOST_kStandardCursorCopy, "copy"},
};
-static constexpr const char *mime_text_plain = "text/plain";
-static constexpr const char *mime_text_utf8 = "text/plain;charset=utf-8";
-static constexpr const char *mime_text_uri = "text/uri-list";
+static constexpr const char *ghost_wl_mime_text_plain = "text/plain";
+static constexpr const char *ghost_wl_mime_text_utf8 = "text/plain;charset=utf-8";
+static constexpr const char *ghost_wl_mime_text_uri = "text/uri-list";
-static const std::unordered_map<std::string, GHOST_TDragnDropTypes> mime_dnd = {
- {mime_text_plain, GHOST_kDragnDropTypeString},
- {mime_text_utf8, GHOST_kDragnDropTypeString},
- {mime_text_uri, GHOST_kDragnDropTypeFilenames},
+static const char *ghost_wl_mime_preference_order[] = {
+ ghost_wl_mime_text_uri,
+ ghost_wl_mime_text_utf8,
+ ghost_wl_mime_text_plain,
};
-
-static const std::vector<std::string> mime_preference_order = {
- mime_text_uri,
- mime_text_utf8,
- mime_text_plain,
+/* Aligned to `ghost_wl_mime_preference_order`. */
+static const GHOST_TDragnDropTypes ghost_wl_mime_preference_order_type[] = {
+ GHOST_kDragnDropTypeString,
+ GHOST_kDragnDropTypeString,
+ GHOST_kDragnDropTypeFilenames,
};
-static const std::vector<std::string> mime_send = {
+static const char *ghost_wl_mime_send[] = {
"UTF8_STRING",
"COMPOUND_TEXT",
"TEXT",
@@ -1388,7 +1534,7 @@ static void keyboard_depressed_state_key_event(GWL_Seat *seat,
static void keyboard_depressed_state_push_events_from_change(
GWL_Seat *seat, const GWL_KeyboardDepressedState &key_depressed_prev)
{
- GHOST_IWindow *win = ghost_wl_surface_user_data(seat->keyboard.wl_surface);
+ GHOST_IWindow *win = ghost_wl_surface_user_data(seat->keyboard.wl_surface_window);
GHOST_SystemWayland *system = seat->system;
/* Separate key up and down into separate passes so key down events always come after key up.
@@ -1475,7 +1621,7 @@ static void relative_pointer_handle_relative_motion(
const wl_fixed_t /*dy_unaccel*/)
{
GWL_Seat *seat = static_cast<GWL_Seat *>(data);
- if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) {
+ if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) {
CLOG_INFO(LOG, 2, "relative_motion");
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
const wl_fixed_t scale = win->scale();
@@ -1508,7 +1654,7 @@ static CLG_LogRef LOG_WL_DATA_SOURCE = {"ghost.wl.handle.data_source"};
static void dnd_events(const GWL_Seat *const seat, const GHOST_TEventType event)
{
/* NOTE: `seat->data_offer_dnd_mutex` must already be locked. */
- if (wl_surface *wl_surface_focus = seat->wl_surface_focus_dnd) {
+ if (wl_surface *wl_surface_focus = seat->wl_surface_window_focus_dnd) {
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
const wl_fixed_t scale = win->scale();
const int event_xy[2] = {
@@ -1517,9 +1663,10 @@ static void dnd_events(const GWL_Seat *const seat, const GHOST_TEventType event)
};
const uint64_t time = seat->system->getMilliSeconds();
- for (const std::string &type : mime_preference_order) {
- seat->system->pushEvent(new GHOST_EventDragnDrop(
- time, event, mime_dnd.at(type), win, UNPACK2(event_xy), nullptr));
+ for (size_t i = 0; i < ARRAY_SIZE(ghost_wl_mime_preference_order_type); i++) {
+ const GHOST_TDragnDropTypes type = ghost_wl_mime_preference_order_type[i];
+ seat->system->pushEvent(
+ new GHOST_EventDragnDrop(time, event, type, win, UNPACK2(event_xy), nullptr));
}
}
}
@@ -1528,7 +1675,7 @@ static void dnd_events(const GWL_Seat *const seat, const GHOST_TEventType event)
* Read from `fd` into a buffer which is returned.
* \return the buffer or null on failure.
*/
-static const char *read_file_as_buffer(const int fd, size_t *r_len)
+static char *read_file_as_buffer(const int fd, const bool nil_terminate, size_t *r_len)
{
struct ByteChunk {
ByteChunk *next;
@@ -1564,14 +1711,23 @@ static const char *read_file_as_buffer(const int fd, size_t *r_len)
char *buf = nullptr;
if (ok) {
- buf = static_cast<char *>(malloc(len));
+ buf = static_cast<char *>(malloc(len + (nil_terminate ? 1 : 0)));
if (UNLIKELY(buf == nullptr)) {
CLOG_WARN(LOG, "unable to allocate file buffer: %zu bytes", len);
ok = false;
}
}
- *r_len = ok ? len : 0;
+ if (ok) {
+ *r_len = len;
+ if (nil_terminate) {
+ buf[len] = '\0';
+ }
+ }
+ else {
+ *r_len = 0;
+ }
+
char *buf_stride = buf;
while (chunk_first) {
if (ok) {
@@ -1588,53 +1744,62 @@ static const char *read_file_as_buffer(const int fd, size_t *r_len)
return buf;
}
-static const char *read_buffer_from_data_offer(GWL_DataOffer *data_offer,
- const char *mime_receive,
- std::mutex *mutex,
- size_t *r_len)
+static char *read_buffer_from_data_offer(GWL_DataOffer *data_offer,
+ const char *mime_receive,
+ std::mutex *mutex,
+ const bool nil_terminate,
+ size_t *r_len)
{
int pipefd[2];
- if (UNLIKELY(pipe(pipefd) != 0)) {
+ const bool pipefd_ok = pipe(pipefd) == 0;
+ if (pipefd_ok) {
+ wl_data_offer_receive(data_offer->id, mime_receive, pipefd[1]);
+ close(pipefd[1]);
+ }
+ else {
CLOG_WARN(LOG, "error creating pipe: %s", std::strerror(errno));
- return nullptr;
}
- wl_data_offer_receive(data_offer->id, mime_receive, pipefd[1]);
- close(pipefd[1]);
- data_offer->in_use.store(false);
+ /* Only for DND (A no-op to disable for clipboard data-offer). */
+ data_offer->dnd.in_use = false;
if (mutex) {
mutex->unlock();
}
/* WARNING: `data_offer` may be freed from now on. */
-
- const char *buf = read_file_as_buffer(pipefd[0], r_len);
- close(pipefd[0]);
+ char *buf = nullptr;
+ if (pipefd_ok) {
+ buf = read_file_as_buffer(pipefd[0], nil_terminate, r_len);
+ close(pipefd[0]);
+ }
return buf;
}
-static const char *read_buffer_from_primary_selection_offer(
- GWL_PrimarySelection_DataOffer *data_offer,
- const char *mime_receive,
- std::mutex *mutex,
- size_t *r_len)
+static char *read_buffer_from_primary_selection_offer(GWL_PrimarySelection_DataOffer *data_offer,
+ const char *mime_receive,
+ std::mutex *mutex,
+ const bool nil_terminate,
+ size_t *r_len)
{
int pipefd[2];
- if (UNLIKELY(pipe(pipefd) != 0)) {
+ const bool pipefd_ok = pipe(pipefd) == 0;
+ if (pipefd_ok) {
+ zwp_primary_selection_offer_v1_receive(data_offer->id, mime_receive, pipefd[1]);
+ close(pipefd[1]);
+ }
+ else {
CLOG_WARN(LOG, "error creating pipe: %s", std::strerror(errno));
- return nullptr;
}
- zwp_primary_selection_offer_v1_receive(data_offer->id, mime_receive, pipefd[1]);
- close(pipefd[1]);
-
- data_offer->in_use.store(false);
if (mutex) {
mutex->unlock();
}
/* WARNING: `data_offer` may be freed from now on. */
- const char *buf = read_file_as_buffer(pipefd[0], r_len);
- close(pipefd[0]);
+ char *buf = nullptr;
+ if (pipefd_ok) {
+ buf = read_file_as_buffer(pipefd[0], nil_terminate, r_len);
+ close(pipefd[0]);
+ }
return buf;
}
@@ -1657,15 +1822,22 @@ static void data_source_handle_send(void *data,
const int32_t fd)
{
GWL_Seat *seat = static_cast<GWL_Seat *>(data);
- std::lock_guard lock{seat->data_source_mutex};
CLOG_INFO(LOG, 2, "send");
- const char *const buffer = seat->data_source->buffer_out.data;
- if (UNLIKELY(write(fd, buffer, seat->data_source->buffer_out.data_size) < 0)) {
- CLOG_WARN(LOG, "error writing to clipboard: %s", std::strerror(errno));
- }
- close(fd);
+ auto write_file_fn = [](GWL_Seat *seat, const int fd) {
+ if (UNLIKELY(write(fd,
+ seat->data_source->buffer_out.data,
+ seat->data_source->buffer_out.data_size) < 0)) {
+ CLOG_WARN(LOG, "error writing to clipboard: %s", std::strerror(errno));
+ }
+ close(fd);
+ seat->data_source_mutex.unlock();
+ };
+
+ seat->data_source_mutex.lock();
+ std::thread write_thread(write_file_fn, seat, fd);
+ write_thread.detach();
}
static void data_source_handle_cancelled(void *data, struct wl_data_source *wl_data_source)
@@ -1816,7 +1988,7 @@ static void data_device_handle_enter(void *data,
seat->data_offer_dnd = static_cast<GWL_DataOffer *>(wl_data_offer_get_user_data(id));
GWL_DataOffer *data_offer = seat->data_offer_dnd;
- data_offer->in_use.store(true);
+ data_offer->dnd.in_use = true;
data_offer->dnd.xy[0] = x;
data_offer->dnd.xy[1] = y;
@@ -1825,11 +1997,15 @@ static void data_device_handle_enter(void *data,
WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE,
WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY);
- for (const std::string &type : mime_preference_order) {
- wl_data_offer_accept(id, serial, type.c_str());
+ for (size_t i = 0; i < ARRAY_SIZE(ghost_wl_mime_preference_order); i++) {
+ const char *type = ghost_wl_mime_preference_order[i];
+ wl_data_offer_accept(id, serial, type);
}
- seat->wl_surface_focus_dnd = wl_surface;
+ seat->wl_surface_window_focus_dnd = wl_surface;
+
+ seat->system->seat_active_set(seat);
+
dnd_events(seat, GHOST_kEventDraggingEntered);
}
@@ -1841,9 +2017,9 @@ static void data_device_handle_leave(void *data, struct wl_data_device * /*wl_da
CLOG_INFO(LOG, 2, "leave");
dnd_events(seat, GHOST_kEventDraggingExited);
- seat->wl_surface_focus_dnd = nullptr;
+ seat->wl_surface_window_focus_dnd = nullptr;
- if (seat->data_offer_dnd && !seat->data_offer_dnd->in_use.load()) {
+ if (seat->data_offer_dnd && !seat->data_offer_dnd->dnd.in_use) {
wl_data_offer_destroy(seat->data_offer_dnd->id);
delete seat->data_offer_dnd;
seat->data_offer_dnd = nullptr;
@@ -1874,27 +2050,35 @@ static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_dat
GWL_DataOffer *data_offer = seat->data_offer_dnd;
- const std::string mime_receive = *std::find_first_of(mime_preference_order.begin(),
- mime_preference_order.end(),
- data_offer->types.begin(),
- data_offer->types.end());
+ /* Use a blank string for `mime_receive` to prevent crashes, although could also be `nullptr`.
+ * Failure to set this to a known type just means the file won't have any special handling.
+ * GHOST still generates a dropped file event.
+ * NOTE: this string can be compared with `mime_text_plain`, `mime_text_uri` etc...
+ * as the this always points to the same values. */
+ const char *mime_receive = "";
+ for (size_t i = 0; i < ARRAY_SIZE(ghost_wl_mime_preference_order); i++) {
+ const char *type = ghost_wl_mime_preference_order[i];
+ if (data_offer->types.count(type)) {
+ mime_receive = type;
+ break;
+ }
+ }
- CLOG_INFO(LOG, 2, "drop mime_recieve=%s", mime_receive.c_str());
+ CLOG_INFO(LOG, 2, "drop mime_recieve=%s", mime_receive);
auto read_uris_fn = [](GWL_Seat *const seat,
GWL_DataOffer *data_offer,
- wl_surface *wl_surface,
- const std::string mime_receive) {
+ wl_surface *wl_surface_window,
+ const char *mime_receive) {
const wl_fixed_t xy[2] = {UNPACK2(data_offer->dnd.xy)};
size_t data_buf_len = 0;
const char *data_buf = read_buffer_from_data_offer(
- data_offer, mime_receive.c_str(), nullptr, &data_buf_len);
+ data_offer, mime_receive, nullptr, false, &data_buf_len);
std::string data = data_buf ? std::string(data_buf, data_buf_len) : "";
free(const_cast<char *>(data_buf));
- CLOG_INFO(
- LOG, 2, "drop_read_uris mime_receive=%s, data=%s", mime_receive.c_str(), data.c_str());
+ CLOG_INFO(LOG, 2, "drop_read_uris mime_receive=%s, data=%s", mime_receive, data.c_str());
wl_data_offer_finish(data_offer->id);
wl_data_offer_destroy(data_offer->id);
@@ -1907,13 +2091,13 @@ static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_dat
GHOST_SystemWayland *const system = seat->system;
- if (mime_receive == mime_text_uri) {
+ if (mime_receive == ghost_wl_mime_text_uri) {
static constexpr const char *file_proto = "file://";
/* NOTE: some applications CRLF (`\r\n`) GTK3 for e.g. & others don't `pcmanfm-qt`.
* So support both, once `\n` is found, strip the preceding `\r` if found. */
static constexpr const char *lf = "\n";
- GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface);
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_window);
std::vector<std::string> uris;
size_t pos = 0;
@@ -1952,7 +2136,7 @@ static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_dat
wl_fixed_to_int(scale * xy[1]),
flist));
}
- else if (ELEM(mime_receive, mime_text_plain, mime_text_utf8)) {
+ else if (ELEM(mime_receive, ghost_wl_mime_text_plain, ghost_wl_mime_text_utf8)) {
/* TODO: enable use of internal functions 'txt_insert_buf' and
* 'text_update_edited' to behave like dropped text was pasted. */
CLOG_INFO(LOG, 2, "drop_read_uris_fn (text_plain, text_utf8), unhandled!");
@@ -1960,10 +2144,10 @@ static void data_device_handle_drop(void *data, struct wl_data_device * /*wl_dat
wl_display_roundtrip(system->wl_display());
};
- /* Pass in `seat->wl_surface_focus_dnd` instead of accessing it from `seat` since the leave
- * callback (#data_device_handle_leave) will clear the value once this function starts. */
+ /* Pass in `seat->wl_surface_window_focus_dnd` instead of accessing it from `seat` since the
+ * leave callback (#data_device_handle_leave) will clear the value once this function starts. */
std::thread read_thread(
- read_uris_fn, seat, data_offer, seat->wl_surface_focus_dnd, mime_receive);
+ read_uris_fn, seat, data_offer, seat->wl_surface_window_focus_dnd, mime_receive);
read_thread.detach();
}
@@ -1993,34 +2177,6 @@ static void data_device_handle_selection(void *data,
/* Get new data offer. */
data_offer = static_cast<GWL_DataOffer *>(wl_data_offer_get_user_data(id));
seat->data_offer_copy_paste = data_offer;
-
- auto read_selection_fn = [](GWL_Seat *seat) {
- GHOST_SystemWayland *const system = seat->system;
- seat->data_offer_copy_paste_mutex.lock();
-
- GWL_DataOffer *data_offer = seat->data_offer_copy_paste;
- std::string mime_receive;
- for (const std::string type : {mime_text_utf8, mime_text_plain}) {
- if (data_offer->types.count(type)) {
- mime_receive = type;
- break;
- }
- }
-
- size_t data_len = 0;
- const char *data = read_buffer_from_data_offer(
- data_offer, mime_receive.c_str(), &seat->data_offer_copy_paste_mutex, &data_len);
-
- {
- std::mutex &clipboard_mutex = system->clipboard_mutex();
- std::lock_guard lock{clipboard_mutex};
- GWL_SimpleBuffer *buf = system->clipboard_data(false);
- gwl_simple_buffer_set_and_take_ownership(buf, data, data_len);
- }
- };
-
- std::thread read_thread(read_selection_fn, seat);
- read_thread.detach();
}
static const struct wl_data_device_listener data_device_listener = {
@@ -2074,7 +2230,7 @@ static CLG_LogRef LOG_WL_CURSOR_SURFACE = {"ghost.wl.handle.cursor_surface"};
static bool update_cursor_scale(GWL_Cursor &cursor,
wl_shm *shm,
GWL_SeatStatePointer *seat_state_pointer,
- wl_surface *wl_cursor_surface)
+ wl_surface *wl_surface_cursor)
{
int scale = 0;
for (const GWL_Output *output : seat_state_pointer->outputs) {
@@ -2086,7 +2242,7 @@ static bool update_cursor_scale(GWL_Cursor &cursor,
if (scale > 0 && seat_state_pointer->theme_scale != scale) {
seat_state_pointer->theme_scale = scale;
if (!cursor.is_custom) {
- wl_surface_set_buffer_scale(wl_cursor_surface, scale);
+ wl_surface_set_buffer_scale(wl_surface_cursor, scale);
}
wl_cursor_theme_destroy(cursor.wl_theme);
cursor.wl_theme = wl_cursor_theme_load(
@@ -2179,7 +2335,9 @@ static void pointer_handle_enter(void *data,
seat->pointer_scroll.discrete_xy[1] = 0;
seat->pointer_scroll.axis_source = WL_POINTER_AXIS_SOURCE_WHEEL;
- seat->pointer.wl_surface = wl_surface;
+ seat->pointer.wl_surface_window = wl_surface;
+
+ seat->system->seat_active_set(seat);
win->setCursorShape(win->getCursorShape());
@@ -2198,7 +2356,7 @@ static void pointer_handle_leave(void *data,
struct wl_surface *wl_surface)
{
/* First clear the `pointer.wl_surface`, since the window won't exist when closing the window. */
- static_cast<GWL_Seat *>(data)->pointer.wl_surface = nullptr;
+ static_cast<GWL_Seat *>(data)->pointer.wl_surface_window = nullptr;
if (wl_surface && ghost_wl_surface_own(wl_surface)) {
CLOG_INFO(LOG, 2, "leave");
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface);
@@ -2219,7 +2377,7 @@ static void pointer_handle_motion(void *data,
seat->pointer.xy[0] = surface_x;
seat->pointer.xy[1] = surface_y;
- if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) {
+ if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) {
CLOG_INFO(LOG, 2, "motion");
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
const wl_fixed_t scale = win->scale();
@@ -2283,7 +2441,7 @@ static void pointer_handle_button(void *data,
seat->data_source_serial = serial;
seat->pointer.buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED);
- if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) {
+ if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) {
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
seat->system->pushEvent(new GHOST_EventButton(
seat->system->getMilliSeconds(), etype, win, ebutton, GHOST_TABLET_DATA_NONE));
@@ -2334,7 +2492,7 @@ static void pointer_handle_frame(void *data, struct wl_pointer * /*wl_pointer*/)
/* Discrete X axis currently unsupported. */
if (seat->pointer_scroll.discrete_xy[1]) {
- if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) {
+ if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) {
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
const int32_t discrete = seat->pointer_scroll.discrete_xy[1];
seat->system->pushEvent(new GHOST_EventWheel(
@@ -2345,7 +2503,7 @@ static void pointer_handle_frame(void *data, struct wl_pointer * /*wl_pointer*/)
}
if (seat->pointer_scroll.smooth_xy[0] || seat->pointer_scroll.smooth_xy[1]) {
- if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) {
+ if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) {
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
const wl_fixed_t scale = win->scale();
seat->system->pushEvent(new GHOST_EventTrackpad(
@@ -2355,10 +2513,11 @@ static void pointer_handle_frame(void *data, struct wl_pointer * /*wl_pointer*/)
wl_fixed_to_int(scale * seat->pointer.xy[0]),
wl_fixed_to_int(scale * seat->pointer.xy[1]),
/* NOTE: scaling the delta doesn't seem necessary.
- * NOTE: inverting delta gives correct results, see: QTBUG-85767. */
+ * NOTE: inverting delta gives correct results, see: QTBUG-85767.
+ * NOTE: the preference to invert scrolling (in GNOME at least)
+ * has already been applied so there is no need to read this preference. */
-wl_fixed_to_int(seat->pointer_scroll.smooth_xy[0]),
-wl_fixed_to_int(seat->pointer_scroll.smooth_xy[1]),
- /* TODO: investigate a way to request this configuration from the system. */
false));
}
@@ -2475,9 +2634,21 @@ static void gesture_pinch_handle_begin(void *data,
seat->pointer_gesture_pinch = GWL_SeatStatePointerGesture_Pinch{};
GHOST_WindowWayland *win = nullptr;
- if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) {
+ if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) {
win = ghost_wl_surface_user_data(wl_surface_focus);
}
+ /* NOTE(@campbellbarton): Blender's use of track-pad coordinates is inconsistent and needs work.
+ * This isn't specific to WAYLAND, in practice they tend to work well enough in most cases.
+ * Some operators scale by the UI scale, some don't.
+ * Even this window scale is not correct because it doesn't account for:
+ * 1) Fractional window scale.
+ * 2) Blender's UI scale preference (which GHOST doesn't know about).
+ *
+ * If support for this were all that was needed it could be handled in GHOST,
+ * however as the operators are not even using coordinates compatible with each other,
+ * it would be better to resolve this by passing rotation & zoom levels directly,
+ * instead of attempting to handle them as cursor coordinates.
+ */
const wl_fixed_t win_scale = win ? win->scale() : 1;
/* NOTE(@campbellbarton): Scale factors match Blender's operators & default preferences.
@@ -2519,7 +2690,7 @@ static void gesture_pinch_handle_update(void *data,
GHOST_WindowWayland *win = nullptr;
- if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) {
+ if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) {
win = ghost_wl_surface_user_data(wl_surface_focus);
}
@@ -2641,8 +2812,9 @@ static const struct zwp_pointer_gesture_swipe_v1_listener gesture_swipe_listener
/* -------------------------------------------------------------------- */
/** \name Listener (Touch Seat), #wl_touch_listener
*
- * TODO(@campbellbarton): Only setup the callbacks for now as I don't have
- * hardware that generates touch events.
+ * NOTE(@campbellbarton): It's not clear if this interface is used by popular compositors.
+ * It looks like GNOME/KDE only support `zwp_pointer_gestures_v1_interface`.
+ * If this isn't used anywhere, it could be removed.
* \{ */
static CLG_LogRef LOG_WL_TOUCH = {"ghost.wl.handle.touch"};
@@ -2806,11 +2978,13 @@ static void tablet_tool_handle_proximity_in(void *data,
GWL_Seat *seat = tablet_tool->seat;
seat->cursor_source_serial = serial;
- seat->tablet.wl_surface = wl_surface;
+ seat->tablet.wl_surface_window = wl_surface;
seat->tablet.serial = serial;
seat->data_source_serial = serial;
+ seat->system->seat_active_set(seat);
+
/* Update #GHOST_TabletData. */
GHOST_TabletData &td = tablet_tool->data;
/* Reset, to avoid using stale tilt/pressure. */
@@ -2819,7 +2993,7 @@ static void tablet_tool_handle_proximity_in(void *data,
/* In case pressure isn't supported. */
td.Pressure = 1.0f;
- GHOST_WindowWayland *win = ghost_wl_surface_user_data(seat->tablet.wl_surface);
+ GHOST_WindowWayland *win = ghost_wl_surface_user_data(seat->tablet.wl_surface_window);
win->activate();
@@ -2849,7 +3023,7 @@ static void tablet_tool_handle_down(void *data,
seat->data_source_serial = serial;
seat->tablet.buttons.set(ebutton, true);
- if (wl_surface *wl_surface_focus = seat->tablet.wl_surface) {
+ if (wl_surface *wl_surface_focus = seat->tablet.wl_surface_window) {
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
seat->system->pushEvent(new GHOST_EventButton(
seat->system->getMilliSeconds(), etype, win, ebutton, tablet_tool->data));
@@ -2867,7 +3041,7 @@ static void tablet_tool_handle_up(void *data, struct zwp_tablet_tool_v2 * /*zwp_
seat->tablet.buttons.set(ebutton, false);
- if (wl_surface *wl_surface_focus = seat->tablet.wl_surface) {
+ if (wl_surface *wl_surface_focus = seat->tablet.wl_surface_window) {
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
seat->system->pushEvent(new GHOST_EventButton(
seat->system->getMilliSeconds(), etype, win, ebutton, tablet_tool->data));
@@ -2952,7 +3126,7 @@ static void tablet_tool_handle_wheel(void *data,
GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(data);
GWL_Seat *seat = tablet_tool->seat;
- if (wl_surface *wl_surface_focus = seat->tablet.wl_surface) {
+ if (wl_surface *wl_surface_focus = seat->tablet.wl_surface_window) {
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
seat->system->pushEvent(new GHOST_EventWheel(seat->system->getMilliSeconds(), win, clicks));
}
@@ -2994,7 +3168,7 @@ static void tablet_tool_handle_button(void *data,
seat->data_source_serial = serial;
seat->tablet.buttons.set(ebutton, state == WL_POINTER_BUTTON_STATE_PRESSED);
- if (wl_surface *wl_surface_focus = seat->tablet.wl_surface) {
+ if (wl_surface *wl_surface_focus = seat->tablet.wl_surface_window) {
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
seat->system->pushEvent(new GHOST_EventButton(
seat->system->getMilliSeconds(), etype, win, ebutton, tablet_tool->data));
@@ -3010,7 +3184,7 @@ static void tablet_tool_handle_frame(void *data,
GWL_Seat *seat = tablet_tool->seat;
/* No need to check the surfaces origin, it's already known to be owned by GHOST. */
- if (wl_surface *wl_surface_focus = seat->tablet.wl_surface) {
+ if (wl_surface *wl_surface_focus = seat->tablet.wl_surface_window) {
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
const wl_fixed_t scale = win->scale();
seat->system->pushEvent(new GHOST_EventCursor(seat->system->getMilliSeconds(),
@@ -3025,7 +3199,7 @@ static void tablet_tool_handle_frame(void *data,
}
if (tablet_tool->proximity == false) {
- seat->tablet.wl_surface = nullptr;
+ seat->tablet.wl_surface_window = nullptr;
}
}
@@ -3153,9 +3327,23 @@ static void keyboard_handle_keymap(void *data,
xkb_state_unref(seat->xkb_state_empty);
seat->xkb_state_empty = xkb_state_new(keymap);
+ for (int i = 0; i < MOD_INDEX_NUM; i++) {
+ const GWL_ModifierInfo &mod_info = g_modifier_info_table[i];
+ seat->xkb_keymap_mod_index[i] = xkb_keymap_mod_get_index(keymap, mod_info.xkb_id);
+ }
+
+ xkb_state_unref(seat->xkb_state_empty_with_shift);
+ seat->xkb_state_empty_with_shift = nullptr;
+ {
+ const xkb_mod_index_t mod_shift = seat->xkb_keymap_mod_index[MOD_INDEX_SHIFT];
+ if (mod_shift != XKB_MOD_INVALID) {
+ seat->xkb_state_empty_with_shift = xkb_state_new(keymap);
+ xkb_state_update_mask(seat->xkb_state_empty_with_shift, (1 << mod_shift), 0, 0, 0, 0, 0);
+ }
+ }
+
xkb_state_unref(seat->xkb_state_empty_with_numlock);
seat->xkb_state_empty_with_numlock = nullptr;
-
{
const xkb_mod_index_t mod2 = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_NUM);
const xkb_mod_index_t num = xkb_keymap_mod_get_index(keymap, "NumLock");
@@ -3166,10 +3354,21 @@ static void keyboard_handle_keymap(void *data,
}
}
- for (int i = 0; i < MOD_INDEX_NUM; i++) {
- const GWL_ModifierInfo &mod_info = g_modifier_info_table[i];
- seat->xkb_keymap_mod_index[i] = xkb_keymap_mod_get_index(keymap, mod_info.xkb_id);
+#ifdef USE_NON_LATIN_KB_WORKAROUND
+ seat->xkb_use_non_latin_workaround = false;
+ if (seat->xkb_state_empty_with_shift) {
+ seat->xkb_use_non_latin_workaround = true;
+ for (xkb_keycode_t key_code = KEY_1 + EVDEV_OFFSET; key_code <= KEY_0 + EVDEV_OFFSET;
+ key_code++) {
+ const xkb_keysym_t sym_test = xkb_state_key_get_one_sym(seat->xkb_state_empty_with_shift,
+ key_code);
+ if (!(sym_test >= XKB_KEY_0 && sym_test <= XKB_KEY_9)) {
+ seat->xkb_use_non_latin_workaround = false;
+ break;
+ }
+ }
}
+#endif
keyboard_depressed_state_reset(seat);
@@ -3195,7 +3394,9 @@ static void keyboard_handle_enter(void *data,
GWL_Seat *seat = static_cast<GWL_Seat *>(data);
seat->keyboard.serial = serial;
- seat->keyboard.wl_surface = wl_surface;
+ seat->keyboard.wl_surface_window = wl_surface;
+
+ seat->system->seat_active_set(seat);
/* If there are any keys held when activating the window,
* modifiers will be compared against the seat state,
@@ -3238,7 +3439,7 @@ static void keyboard_handle_leave(void *data,
CLOG_INFO(LOG, 2, "leave");
GWL_Seat *seat = static_cast<GWL_Seat *>(data);
- seat->keyboard.wl_surface = nullptr;
+ seat->keyboard.wl_surface_window = nullptr;
/* Losing focus must stop repeating text. */
if (seat->key_repeat.timer) {
@@ -3258,6 +3459,8 @@ static void keyboard_handle_leave(void *data,
static xkb_keysym_t xkb_state_key_get_one_sym_without_modifiers(
struct xkb_state *xkb_state_empty,
struct xkb_state *xkb_state_empty_with_numlock,
+ struct xkb_state *xkb_state_empty_with_shift,
+ const bool xkb_use_non_latin_workaround,
const xkb_keycode_t key)
{
/* Use an empty keyboard state to access key symbol without modifiers. */
@@ -3271,12 +3474,31 @@ static xkb_keysym_t xkb_state_key_get_one_sym_without_modifiers(
/* Accounts for key-pad keys typically swapped for numbers when number-lock is enabled:
* `Home Left Up Right Down Prior Page_Up Next Page_Dow End Begin Insert Delete`. */
- if (xkb_state_empty_with_numlock && (sym >= XKB_KEY_KP_Home && sym <= XKB_KEY_KP_Delete)) {
- const xkb_keysym_t sym_test = xkb_state_key_get_one_sym(xkb_state_empty_with_numlock, key);
- if (sym_test != XKB_KEY_NoSymbol) {
- sym = sym_test;
+ if (sym >= XKB_KEY_KP_Home && sym <= XKB_KEY_KP_Delete) {
+ if (xkb_state_empty_with_numlock) {
+ const xkb_keysym_t sym_test = xkb_state_key_get_one_sym(xkb_state_empty_with_numlock, key);
+ if (sym_test != XKB_KEY_NoSymbol) {
+ sym = sym_test;
+ }
}
}
+ else {
+#ifdef USE_NON_LATIN_KB_WORKAROUND
+ if (key >= (KEY_1 + EVDEV_OFFSET) && key <= (KEY_0 + EVDEV_OFFSET)) {
+ if (xkb_state_empty_with_shift && xkb_use_non_latin_workaround) {
+ const xkb_keysym_t sym_test = xkb_state_key_get_one_sym(xkb_state_empty_with_shift, key);
+ if (sym_test != XKB_KEY_NoSymbol) {
+ /* Should never happen as enabling `xkb_use_non_latin_workaround` checks this. */
+ GHOST_ASSERT(sym_test >= XKB_KEY_0 && sym_test <= XKB_KEY_9, "Unexpected key");
+ sym = sym_test;
+ }
+ }
+ }
+#else
+ (void)xkb_state_empty_with_shift;
+ (void)xkb_use_non_latin_workaround;
+#endif
+ }
return sym;
}
@@ -3318,7 +3540,15 @@ static void keyboard_handle_key(void *data,
const xkb_keycode_t key_code = key + EVDEV_OFFSET;
const xkb_keysym_t sym = xkb_state_key_get_one_sym_without_modifiers(
- seat->xkb_state_empty, seat->xkb_state_empty_with_numlock, key_code);
+ seat->xkb_state_empty,
+ seat->xkb_state_empty_with_numlock,
+ seat->xkb_state_empty_with_shift,
+#ifdef USE_NON_LATIN_KB_WORKAROUND
+ seat->xkb_use_non_latin_workaround,
+#else
+ false,
+#endif
+ key_code);
if (sym == XKB_KEY_NoSymbol) {
CLOG_INFO(LOG, 2, "key (code=%d, state=%u, no symbol, skipped)", int(key_code), state);
return;
@@ -3399,7 +3629,7 @@ static void keyboard_handle_key(void *data,
keyboard_depressed_state_key_event(seat, gkey, etype);
- if (wl_surface *wl_surface_focus = seat->keyboard.wl_surface) {
+ if (wl_surface *wl_surface_focus = seat->keyboard.wl_surface_window) {
GHOST_IWindow *win = ghost_wl_surface_user_data(wl_surface_focus);
seat->system->pushEvent(
new GHOST_EventKey(seat->system->getMilliSeconds(), etype, win, gkey, false, utf8_buf));
@@ -3423,7 +3653,7 @@ static void keyboard_handle_key(void *data,
task->getUserData());
GWL_Seat *seat = payload->seat;
- if (wl_surface *wl_surface_focus = seat->keyboard.wl_surface) {
+ if (wl_surface *wl_surface_focus = seat->keyboard.wl_surface_window) {
GHOST_IWindow *win = ghost_wl_surface_user_data(wl_surface_focus);
GHOST_SystemWayland *system = seat->system;
/* Calculate this value every time in case modifier keys are pressed. */
@@ -3572,33 +3802,6 @@ static void primary_selection_device_handle_selection(
GWL_PrimarySelection_DataOffer *data_offer = static_cast<GWL_PrimarySelection_DataOffer *>(
zwp_primary_selection_offer_v1_get_user_data(id));
primary->data_offer = data_offer;
-
- auto read_selection_fn = [](GWL_PrimarySelection *primary) {
- GHOST_SystemWayland *system = static_cast<GHOST_SystemWayland *>(GHOST_ISystem::getSystem());
- primary->data_offer_mutex.lock();
-
- GWL_PrimarySelection_DataOffer *data_offer = primary->data_offer;
- std::string mime_receive;
- for (const std::string type : {mime_text_utf8, mime_text_plain}) {
- if (data_offer->types.count(type)) {
- mime_receive = type;
- break;
- }
- }
- size_t data_len = 0;
- const char *data = read_buffer_from_primary_selection_offer(
- data_offer, mime_receive.c_str(), &primary->data_offer_mutex, &data_len);
-
- {
- std::mutex &clipboard_mutex = system->clipboard_mutex();
- std::lock_guard lock{clipboard_mutex};
- GWL_SimpleBuffer *buf = system->clipboard_data(true);
- gwl_simple_buffer_set_and_take_ownership(buf, data, data_len);
- }
- };
-
- std::thread read_thread(read_selection_fn, primary);
- read_thread.detach();
}
static const struct zwp_primary_selection_device_v1_listener primary_selection_device_listener = {
@@ -3626,14 +3829,19 @@ static void primary_selection_source_send(void *data,
GWL_PrimarySelection *primary = static_cast<GWL_PrimarySelection *>(data);
- std::lock_guard lock{primary->data_source_mutex};
- GWL_PrimarySelection_DataSource *data_source = primary->data_source;
+ auto write_file_fn = [](GWL_PrimarySelection *primary, const int fd) {
+ if (UNLIKELY(write(fd,
+ primary->data_source->buffer_out.data,
+ primary->data_source->buffer_out.data_size) < 0)) {
+ CLOG_WARN(LOG, "error writing to primary clipboard: %s", std::strerror(errno));
+ }
+ close(fd);
+ primary->data_source_mutex.unlock();
+ };
- const char *const buffer = data_source->buffer_out.data;
- if (UNLIKELY(write(fd, buffer, data_source->buffer_out.data_size) < 0)) {
- CLOG_WARN(LOG, "error writing to primary clipboard: %s", std::strerror(errno));
- }
- close(fd);
+ primary->data_source_mutex.lock();
+ std::thread write_thread(write_file_fn, primary, fd);
+ write_thread.detach();
}
static void primary_selection_source_cancelled(void *data,
@@ -3670,7 +3878,7 @@ static void gwl_seat_capability_pointer_enable(GWL_Seat *seat)
return;
}
seat->wl_pointer = wl_seat_get_pointer(seat->wl_seat);
- seat->cursor.wl_surface = wl_compositor_create_surface(seat->system->wl_compositor());
+ seat->cursor.wl_surface_cursor = wl_compositor_create_surface(seat->system->wl_compositor());
seat->cursor.visible = true;
seat->cursor.wl_buffer = nullptr;
if (!get_cursor_settings(seat->cursor.theme_name, seat->cursor.theme_size)) {
@@ -3679,8 +3887,8 @@ static void gwl_seat_capability_pointer_enable(GWL_Seat *seat)
}
wl_pointer_add_listener(seat->wl_pointer, &pointer_listener, seat);
- wl_surface_add_listener(seat->cursor.wl_surface, &cursor_surface_listener, seat);
- ghost_wl_surface_tag_cursor_pointer(seat->cursor.wl_surface);
+ wl_surface_add_listener(seat->cursor.wl_surface_cursor, &cursor_surface_listener, seat);
+ ghost_wl_surface_tag_cursor_pointer(seat->cursor.wl_surface_cursor);
zwp_pointer_gestures_v1 *pointer_gestures = seat->system->wp_pointer_gestures();
if (pointer_gestures) {
@@ -3751,9 +3959,9 @@ static void gwl_seat_capability_pointer_disable(GWL_Seat *seat)
#endif
}
- if (seat->cursor.wl_surface) {
- wl_surface_destroy(seat->cursor.wl_surface);
- seat->cursor.wl_surface = nullptr;
+ if (seat->cursor.wl_surface_cursor) {
+ wl_surface_destroy(seat->cursor.wl_surface_cursor);
+ seat->cursor.wl_surface_cursor = nullptr;
}
if (seat->cursor.wl_theme) {
wl_cursor_theme_destroy(seat->cursor.wl_theme);
@@ -3805,7 +4013,8 @@ static void gwl_seat_capability_touch_disable(GWL_Seat *seat)
}
static void seat_handle_capabilities(void *data,
- struct wl_seat *wl_seat,
+ /* Only used in an assert. */
+ [[maybe_unused]] struct wl_seat *wl_seat,
const uint32_t capabilities)
{
CLOG_INFO(LOG,
@@ -3838,22 +4047,6 @@ static void seat_handle_capabilities(void *data,
else {
gwl_seat_capability_touch_disable(seat);
}
-
- /* TODO(@campbellbarton): this could be moved out elsewhere. */
- if (seat->system) {
- zwp_primary_selection_device_manager_v1 *primary_selection_device_manager =
- seat->system->wp_primary_selection_manager();
- if (primary_selection_device_manager) {
- if (seat->wp_primary_selection_device == nullptr) {
- seat->wp_primary_selection_device = zwp_primary_selection_device_manager_v1_get_device(
- primary_selection_device_manager, seat->wl_seat);
-
- zwp_primary_selection_device_v1_add_listener(seat->wp_primary_selection_device,
- &primary_selection_device_listener,
- &seat->primary_selection);
- }
- }
- }
}
static void seat_handle_name(void *data, struct wl_seat * /*wl_seat*/, const char *name)
@@ -4156,9 +4349,8 @@ static void gwl_registry_compositor_add(GWL_Display *display,
const GWL_RegisteryAdd_Params *params)
{
display->wl_compositor = static_cast<wl_compositor *>(
- wl_registry_bind(params->wl_registry, params->name, &wl_compositor_interface, 3));
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ wl_registry_bind(display->wl_registry, params->name, &wl_compositor_interface, 3));
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_compositor_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4176,11 +4368,10 @@ static void gwl_registry_xdg_wm_base_add(GWL_Display *display,
{
GWL_XDG_Decor_System &decor = *display->xdg_decor;
decor.shell = static_cast<xdg_wm_base *>(
- wl_registry_bind(params->wl_registry, params->name, &xdg_wm_base_interface, 1));
+ wl_registry_bind(display->wl_registry, params->name, &xdg_wm_base_interface, 1));
xdg_wm_base_add_listener(decor.shell, &shell_listener, nullptr);
decor.shell_name = params->name;
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_xdg_wm_base_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4201,10 +4392,9 @@ static void gwl_registry_xdg_decoration_manager_add(GWL_Display *display,
{
GWL_XDG_Decor_System &decor = *display->xdg_decor;
decor.manager = static_cast<zxdg_decoration_manager_v1 *>(wl_registry_bind(
- params->wl_registry, params->name, &zxdg_decoration_manager_v1_interface, 1));
+ display->wl_registry, params->name, &zxdg_decoration_manager_v1_interface, 1));
decor.manager_name = params->name;
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_xdg_decoration_manager_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4224,14 +4414,8 @@ static void gwl_registry_xdg_output_manager_add(GWL_Display *display,
const GWL_RegisteryAdd_Params *params)
{
display->xdg_output_manager = static_cast<zxdg_output_manager_v1 *>(
- wl_registry_bind(params->wl_registry, params->name, &zxdg_output_manager_v1_interface, 2));
- for (GWL_Output *output : display->outputs) {
- output->xdg_output = zxdg_output_manager_v1_get_xdg_output(display->xdg_output_manager,
- output->wl_output);
- zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output);
- }
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ wl_registry_bind(display->wl_registry, params->name, &zxdg_output_manager_v1_interface, 2));
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_xdg_output_manager_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4240,10 +4424,6 @@ static void gwl_registry_xdg_output_manager_remove(GWL_Display *display,
struct zxdg_output_manager_v1 **value_p = &display->xdg_output_manager;
zxdg_output_manager_v1_destroy(*value_p);
*value_p = nullptr;
-
- for (GWL_Output *output : display->outputs) {
- output->xdg_output = nullptr;
- }
}
/* #GWL_Display.wl_output */
@@ -4253,26 +4433,35 @@ static void gwl_registry_wl_output_add(GWL_Display *display, const GWL_Registery
GWL_Output *output = new GWL_Output;
output->system = display->system;
output->wl_output = static_cast<wl_output *>(
- wl_registry_bind(params->wl_registry, params->name, &wl_output_interface, 2));
+ wl_registry_bind(display->wl_registry, params->name, &wl_output_interface, 2));
ghost_wl_output_tag(output->wl_output);
wl_output_set_user_data(output->wl_output, output);
display->outputs.push_back(output);
wl_output_add_listener(output->wl_output, &output_listener, output);
-
+ gwl_registry_entry_add(display, params, static_cast<void *>(output));
+}
+static void gwl_registry_wl_output_update(GWL_Display *display,
+ const GWL_RegisteryUpdate_Params *params)
+{
+ GWL_Output *output = static_cast<GWL_Output *>(params->user_data);
if (display->xdg_output_manager) {
- output->xdg_output = zxdg_output_manager_v1_get_xdg_output(display->xdg_output_manager,
- output->wl_output);
- zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output);
+ if (output->xdg_output == nullptr) {
+ output->xdg_output = zxdg_output_manager_v1_get_xdg_output(display->xdg_output_manager,
+ output->wl_output);
+ zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output);
+ }
+ }
+ else {
+ output->xdg_output = nullptr;
}
-
- gwl_registry_entry_add(
- display, params->interface_slot, params->name, static_cast<void *>(output));
}
static void gwl_registry_wl_output_remove(GWL_Display *display,
void *user_data,
const bool /*on_exit*/)
{
+ /* While windows & cursors hold references to outputs, there is no need to manually remove
+ * these references as the compositor will remove references via #wl_surface_listener.leave. */
GWL_Output *output = static_cast<GWL_Output *>(user_data);
wl_output_destroy(output->wl_output);
std::vector<GWL_Output *>::iterator iter = std::find(
@@ -4295,11 +4484,52 @@ static void gwl_registry_wl_seat_add(GWL_Display *display, const GWL_RegisteryAd
seat->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
seat->data_source = new GWL_DataSource;
seat->wl_seat = static_cast<wl_seat *>(
- wl_registry_bind(params->wl_registry, params->name, &wl_seat_interface, 5));
+ wl_registry_bind(display->wl_registry, params->name, &wl_seat_interface, 5));
display->seats.push_back(seat);
wl_seat_add_listener(seat->wl_seat, &seat_listener, seat);
+ gwl_registry_entry_add(display, params, static_cast<void *>(seat));
+}
+static void gwl_registry_wl_seat_update(GWL_Display *display,
+ const GWL_RegisteryUpdate_Params *params)
+{
+ GWL_Seat *seat = static_cast<GWL_Seat *>(params->user_data);
+
+ /* Register data device per seat for IPC between WAYLAND clients. */
+ if (display->wl_data_device_manager) {
+ if (seat->wl_data_device == nullptr) {
+ seat->wl_data_device = wl_data_device_manager_get_data_device(
+ display->wl_data_device_manager, seat->wl_seat);
+ wl_data_device_add_listener(seat->wl_data_device, &data_device_listener, seat);
+ }
+ }
+ else {
+ seat->wl_data_device = nullptr;
+ }
+
+ if (display->wp_tablet_manager) {
+ if (seat->wp_tablet_seat == nullptr) {
+ seat->wp_tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(display->wp_tablet_manager,
+ seat->wl_seat);
+ zwp_tablet_seat_v2_add_listener(seat->wp_tablet_seat, &tablet_seat_listener, seat);
+ }
+ }
+ else {
+ seat->wp_tablet_seat = nullptr;
+ }
- gwl_registry_entry_add(display, params->interface_slot, params->name, static_cast<void *>(seat));
+ if (display->wp_primary_selection_device_manager) {
+ if (seat->wp_primary_selection_device == nullptr) {
+ seat->wp_primary_selection_device = zwp_primary_selection_device_manager_v1_get_device(
+ display->wp_primary_selection_device_manager, seat->wl_seat);
+
+ zwp_primary_selection_device_v1_add_listener(seat->wp_primary_selection_device,
+ &primary_selection_device_listener,
+ &seat->primary_selection);
+ }
+ }
+ else {
+ seat->wp_primary_selection_device = nullptr;
+ }
}
static void gwl_registry_wl_seat_remove(GWL_Display *display, void *user_data, const bool on_exit)
{
@@ -4370,6 +4600,7 @@ static void gwl_registry_wl_seat_remove(GWL_Display *display, void *user_data, c
/* Un-referencing checks for NULL case. */
xkb_state_unref(seat->xkb_state);
xkb_state_unref(seat->xkb_state_empty);
+ xkb_state_unref(seat->xkb_state_empty_with_shift);
xkb_state_unref(seat->xkb_state_empty_with_numlock);
xkb_context_unref(seat->xkb_context);
@@ -4384,6 +4615,9 @@ static void gwl_registry_wl_seat_remove(GWL_Display *display, void *user_data, c
GHOST_ASSERT(index != -1, "invalid internal state");
if (!on_exit) {
+ if (display->seats_active_index >= index) {
+ display->seats_active_index -= 1;
+ }
display->seats.erase(display->seats.begin() + index);
}
delete seat;
@@ -4394,9 +4628,8 @@ static void gwl_registry_wl_seat_remove(GWL_Display *display, void *user_data, c
static void gwl_registry_wl_shm_add(GWL_Display *display, const GWL_RegisteryAdd_Params *params)
{
display->wl_shm = static_cast<wl_shm *>(
- wl_registry_bind(params->wl_registry, params->name, &wl_shm_interface, 1));
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ wl_registry_bind(display->wl_registry, params->name, &wl_shm_interface, 1));
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_wl_shm_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4413,9 +4646,8 @@ static void gwl_registry_wl_data_device_manager_add(GWL_Display *display,
const GWL_RegisteryAdd_Params *params)
{
display->wl_data_device_manager = static_cast<wl_data_device_manager *>(
- wl_registry_bind(params->wl_registry, params->name, &wl_data_device_manager_interface, 3));
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ wl_registry_bind(display->wl_registry, params->name, &wl_data_device_manager_interface, 3));
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_wl_data_device_manager_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4432,9 +4664,8 @@ static void gwl_registry_wp_tablet_manager_add(GWL_Display *display,
const GWL_RegisteryAdd_Params *params)
{
display->wp_tablet_manager = static_cast<zwp_tablet_manager_v2 *>(
- wl_registry_bind(params->wl_registry, params->name, &zwp_tablet_manager_v2_interface, 1));
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ wl_registry_bind(display->wl_registry, params->name, &zwp_tablet_manager_v2_interface, 1));
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_wp_tablet_manager_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4452,9 +4683,8 @@ static void gwl_registry_wp_relative_pointer_manager_add(GWL_Display *display,
{
display->wp_relative_pointer_manager = static_cast<zwp_relative_pointer_manager_v1 *>(
wl_registry_bind(
- params->wl_registry, params->name, &zwp_relative_pointer_manager_v1_interface, 1));
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ display->wl_registry, params->name, &zwp_relative_pointer_manager_v1_interface, 1));
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_wp_relative_pointer_manager_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4471,9 +4701,8 @@ static void gwl_registry_wp_pointer_constraints_add(GWL_Display *display,
const GWL_RegisteryAdd_Params *params)
{
display->wp_pointer_constraints = static_cast<zwp_pointer_constraints_v1 *>(wl_registry_bind(
- params->wl_registry, params->name, &zwp_pointer_constraints_v1_interface, 1));
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ display->wl_registry, params->name, &zwp_pointer_constraints_v1_interface, 1));
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_wp_pointer_constraints_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4490,9 +4719,8 @@ static void gwl_registry_wp_pointer_gestures_add(GWL_Display *display,
const GWL_RegisteryAdd_Params *params)
{
display->wp_pointer_gestures = static_cast<zwp_pointer_gestures_v1 *>(
- wl_registry_bind(params->wl_registry, params->name, &zwp_pointer_gestures_v1_interface, 3));
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ wl_registry_bind(display->wl_registry, params->name, &zwp_pointer_gestures_v1_interface, 3));
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_wp_pointer_gestures_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4510,12 +4738,11 @@ static void gwl_registry_wp_primary_selection_device_manager_add(
{
display->wp_primary_selection_device_manager =
static_cast<zwp_primary_selection_device_manager_v1 *>(
- wl_registry_bind(params->wl_registry,
+ wl_registry_bind(display->wl_registry,
params->name,
&zwp_primary_selection_device_manager_v1_interface,
1));
-
- gwl_registry_entry_add(display, params->interface_slot, params->name, nullptr);
+ gwl_registry_entry_add(display, params, nullptr);
}
static void gwl_registry_wp_primary_selection_device_manager_remove(GWL_Display *display,
void * /*user_data*/,
@@ -4528,76 +4755,100 @@ static void gwl_registry_wp_primary_selection_device_manager_remove(GWL_Display
}
/**
- * Map interfaces to to initialization functions.
+ * Map interfaces to initialization functions.
+ *
+ * \note This list also defines the order interfaces are removed.
+ * On exit interface removal runs from last to first to avoid potential bugs
+ * caused by undefined order of removal.
*
- * \note This list also defines the order interfaces are freed: from last to first,
- * so the most fundamental objects such as the compositor are freed last.
+ * In general fundamental, low level objects such as the compositor and shared memory
+ * should be declared earlier and other interfaces that may use them should be declared later.
*/
static const GWL_RegistryHandler gwl_registry_handlers[] = {
+ /* Low level interfaces. */
{
&wl_compositor_interface.name,
gwl_registry_compositor_add,
+ nullptr,
gwl_registry_compositor_remove,
},
{
+ &wl_shm_interface.name,
+ gwl_registry_wl_shm_add,
+ nullptr,
+ gwl_registry_wl_shm_remove,
+ },
+ {
&xdg_wm_base_interface.name,
gwl_registry_xdg_wm_base_add,
+ nullptr,
gwl_registry_xdg_wm_base_remove,
},
+ /* Managers. */
{
&zxdg_decoration_manager_v1_interface.name,
gwl_registry_xdg_decoration_manager_add,
+ nullptr,
gwl_registry_xdg_decoration_manager_remove,
},
{
&zxdg_output_manager_v1_interface.name,
gwl_registry_xdg_output_manager_add,
+ nullptr,
gwl_registry_xdg_output_manager_remove,
},
{
- &wl_output_interface.name,
- gwl_registry_wl_output_add,
- gwl_registry_wl_output_remove,
- },
- {
- &wl_seat_interface.name,
- gwl_registry_wl_seat_add,
- gwl_registry_wl_seat_remove,
- },
- {
- &wl_shm_interface.name,
- gwl_registry_wl_shm_add,
- gwl_registry_wl_shm_remove,
- },
- {
&wl_data_device_manager_interface.name,
gwl_registry_wl_data_device_manager_add,
+ nullptr,
gwl_registry_wl_data_device_manager_remove,
},
{
+ &zwp_primary_selection_device_manager_v1_interface.name,
+ gwl_registry_wp_primary_selection_device_manager_add,
+ nullptr,
+ gwl_registry_wp_primary_selection_device_manager_remove,
+ },
+ {
&zwp_tablet_manager_v2_interface.name,
gwl_registry_wp_tablet_manager_add,
+ nullptr,
gwl_registry_wp_tablet_manager_remove,
},
{
&zwp_relative_pointer_manager_v1_interface.name,
gwl_registry_wp_relative_pointer_manager_add,
+ nullptr,
gwl_registry_wp_relative_pointer_manager_remove,
},
+ /* Higher level interfaces. */
{
&zwp_pointer_constraints_v1_interface.name,
gwl_registry_wp_pointer_constraints_add,
+ nullptr,
gwl_registry_wp_pointer_constraints_remove,
},
{
&zwp_pointer_gestures_v1_interface.name,
gwl_registry_wp_pointer_gestures_add,
+ nullptr,
gwl_registry_wp_pointer_gestures_remove,
},
+ /* Display outputs. */
{
- &zwp_primary_selection_device_manager_v1_interface.name,
- gwl_registry_wp_primary_selection_device_manager_add,
- gwl_registry_wp_primary_selection_device_manager_remove,
+ &wl_output_interface.name,
+ gwl_registry_wl_output_add,
+ gwl_registry_wl_output_update,
+ gwl_registry_wl_output_remove,
+ },
+ /* Seats.
+ * Keep the seat near the end to ensure other types are created first.
+ * as the seat creates data based on other interfaces. */
+ {
+ &wl_seat_interface.name,
+ gwl_registry_wl_seat_add,
+ gwl_registry_wl_seat_update,
+ gwl_registry_wl_seat_remove,
},
{nullptr, nullptr, nullptr},
};
@@ -4611,6 +4862,17 @@ static int gwl_registry_handler_interface_slot_max()
return ARRAY_SIZE(gwl_registry_handlers) - 1;
}
+static int gwl_registry_handler_interface_slot_from_string(const char *interface)
+{
+ for (const GWL_RegistryHandler *handler = gwl_registry_handlers; handler->interface_p != nullptr;
+ handler++) {
+ if (STREQ(interface, *handler->interface_p)) {
+ return int(handler - gwl_registry_handlers);
+ }
+ }
+ return -1;
+}
+
static const GWL_RegistryHandler *gwl_registry_handler_from_interface_slot(int interface_slot)
{
GHOST_ASSERT(uint32_t(interface_slot) < uint32_t(gwl_registry_handler_interface_slot_max()),
@@ -4619,40 +4881,35 @@ static const GWL_RegistryHandler *gwl_registry_handler_from_interface_slot(int i
}
static void global_handle_add(void *data,
- struct wl_registry *wl_registry,
+ [[maybe_unused]] struct wl_registry *wl_registry,
const uint32_t name,
const char *interface,
const uint32_t version)
{
/* Log last since it's useful to know if the interface was handled or not. */
-
GWL_Display *display = static_cast<GWL_Display *>(data);
- /* The interface name that is ensured not to be freed. */
- GWL_RegisteryAdd_Params params = {
- .wl_registry = wl_registry,
- .name = name,
- .version = version,
- .interface_slot = 0,
- };
+ GHOST_ASSERT(display->wl_registry == wl_registry, "Registry argument must match!");
- bool found = false, added = false;
- for (const GWL_RegistryHandler *handler = gwl_registry_handlers; handler->interface_p != nullptr;
- handler++) {
- if (!STREQ(interface, *handler->interface_p)) {
- continue;
- }
+ const int interface_slot = gwl_registry_handler_interface_slot_from_string(interface);
+ bool added = false;
+
+ if (interface_slot != -1) {
+ const GWL_RegistryHandler *handler = &gwl_registry_handlers[interface_slot];
const GWL_RegistryEntry *registry_entry_prev = display->registry_entry;
- params.interface_slot = int(handler - gwl_registry_handlers);
+
+ /* The interface name that is ensured not to be freed. */
+ GWL_RegisteryAdd_Params params = {
+ .name = name,
+ .interface_slot = interface_slot,
+ .version = version,
+ };
handler->add_fn(display, &params);
added = display->registry_entry != registry_entry_prev;
- found = true;
- break;
}
-
- /* Not found. */
- if (!found) {
+ else {
+ /* Not found. */
#ifdef USE_GNOME_NEEDS_LIBDECOR_HACK
if (STRPREFIX(interface, "gtk_shell")) { /* `gtk_shell1` at time of writing. */
/* Only require `libdecor` when built with X11 support,
@@ -4665,10 +4922,18 @@ static void global_handle_add(void *data,
CLOG_INFO(LOG,
2,
"add %s(interface=%s, version=%u, name=%u)",
- found ? (added ? "" : "(found but not added)") : "(skipped), ",
+ (interface_slot != -1) ? (added ? "" : "(found but not added)") : "(skipped), ",
interface,
version,
name);
+
+ /* Initialization avoids excessive calls by calling update after all have been initialized. */
+ if (added) {
+ if (display->registry_skip_update_all == false) {
+ /* See doc-string for rationale on updating all on add/removal. */
+ gwl_registry_entry_update_all(display, interface_slot);
+ }
+ }
}
/**
@@ -4681,18 +4946,27 @@ static void global_handle_add(void *data,
* using the bind request, the client should now destroy that object.
*/
static void global_handle_remove(void *data,
- struct wl_registry * /*wl_registry*/,
+ [[maybe_unused]] struct wl_registry *wl_registry,
const uint32_t name)
{
GWL_Display *display = static_cast<GWL_Display *>(data);
+ GHOST_ASSERT(display->wl_registry == wl_registry, "Registry argument must match!");
+
int interface_slot = 0;
- bool found = gwl_registry_entry_remove_by_name(display, name, &interface_slot);
+ const bool removed = gwl_registry_entry_remove_by_name(display, name, &interface_slot);
+
CLOG_INFO(LOG,
2,
- "remove (name=%u, interface=%s), %s",
+ "remove (name=%u, interface=%s)",
name,
- *gwl_registry_handlers[interface_slot].interface_p,
- found ? "(known)" : "(unknown)");
+ removed ? *gwl_registry_handlers[interface_slot].interface_p : "(unknown)");
+
+ if (removed) {
+ if (display->registry_skip_update_all == false) {
+ /* See doc-string for rationale on updating all on add/removal. */
+ gwl_registry_entry_update_all(display, interface_slot);
+ }
+ }
}
static const struct wl_registry_listener registry_listener = {
@@ -4727,13 +5001,21 @@ GHOST_SystemWayland::GHOST_SystemWayland(bool background)
display_->xdg_decor = new GWL_XDG_Decor_System;
/* Register interfaces. */
- struct wl_registry *registry = wl_display_get_registry(display_->wl_display);
- wl_registry_add_listener(registry, &registry_listener, display_);
- /* Call callback for registry listener. */
- wl_display_roundtrip(display_->wl_display);
- /* Call callbacks for registered listeners. */
- wl_display_roundtrip(display_->wl_display);
- wl_registry_destroy(registry);
+ {
+ display_->registry_skip_update_all = true;
+ struct wl_registry *registry = wl_display_get_registry(display_->wl_display);
+ display_->wl_registry = registry;
+ wl_registry_add_listener(registry, &registry_listener, display_);
+ /* First round-trip to receive all registry objects. */
+ wl_display_roundtrip(display_->wl_display);
+ /* Second round-trip to receive all output events. */
+ wl_display_roundtrip(display_->wl_display);
+
+ /* Account for dependencies between interfaces. */
+ gwl_registry_entry_update_all(display_, -1);
+
+ display_->registry_skip_update_all = false;
+ }
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
/* Ignore windowing requirements when running in background mode,
@@ -4785,23 +5067,6 @@ GHOST_SystemWayland::GHOST_SystemWayland(bool background)
throw std::runtime_error("Wayland: unable to access xdg_shell!");
}
}
-
- /* Register data device per seat for IPC between Wayland clients. */
- if (display_->wl_data_device_manager) {
- for (GWL_Seat *seat : display_->seats) {
- seat->wl_data_device = wl_data_device_manager_get_data_device(
- display_->wl_data_device_manager, seat->wl_seat);
- wl_data_device_add_listener(seat->wl_data_device, &data_device_listener, seat);
- }
- }
-
- if (display_->wp_tablet_manager) {
- for (GWL_Seat *seat : display_->seats) {
- seat->wp_tablet_seat = zwp_tablet_manager_v2_get_tablet_seat(display_->wp_tablet_manager,
- seat->wl_seat);
- zwp_tablet_seat_v2_add_listener(seat->wp_tablet_seat, &tablet_seat_listener, seat);
- }
- }
}
GHOST_SystemWayland::~GHOST_SystemWayland()
@@ -4861,12 +5126,11 @@ bool GHOST_SystemWayland::setConsoleWindowState(GHOST_TConsoleWindowState /*acti
GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) const
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
- GWL_Seat *seat = display_->seats[0];
-
const xkb_mod_mask_t state = xkb_state_serialize_mods(seat->xkb_state, XKB_STATE_MODS_DEPRESSED);
bool show_warning = true;
@@ -4923,10 +5187,10 @@ GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) co
GHOST_TSuccess GHOST_SystemWayland::getButtons(GHOST_Buttons &buttons) const
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
- GWL_Seat *seat = display_->seats[0];
GWL_SeatStatePointer *seat_state_pointer = gwl_seat_state_pointer_active(seat);
if (!seat_state_pointer) {
return GHOST_kFailure;
@@ -4936,13 +5200,131 @@ GHOST_TSuccess GHOST_SystemWayland::getButtons(GHOST_Buttons &buttons) const
return GHOST_kSuccess;
}
-char *GHOST_SystemWayland::getClipboard(bool selection) const
+/**
+ * Return a mime type which is supported by GHOST and exists in `types`
+ * (defined by the data offer).
+ */
+static const char *system_clipboard_text_mime_type(
+ const std::unordered_set<std::string> &data_offer_types)
{
- const GWL_SimpleBuffer *buf = clipboard_data(selection);
- if (buf->data == nullptr) {
+ const char *ghost_supported_types[] = {ghost_wl_mime_text_utf8, ghost_wl_mime_text_plain};
+ for (size_t i = 0; i < ARRAY_SIZE(ghost_supported_types); i++) {
+ if (data_offer_types.count(ghost_supported_types[i])) {
+ return ghost_supported_types[i];
+ }
+ }
+ return nullptr;
+}
+
+static char *system_clipboard_get_primary_selection(GWL_Display *display)
+{
+ GWL_Seat *seat = gwl_display_seat_active_get(display);
+ if (UNLIKELY(!seat)) {
return nullptr;
}
- return gwl_simple_buffer_as_string(buf);
+ GWL_PrimarySelection *primary = &seat->primary_selection;
+ std::mutex &mutex = primary->data_offer_mutex;
+
+ mutex.lock();
+ bool mutex_locked = true;
+ char *data = nullptr;
+
+ GWL_PrimarySelection_DataOffer *data_offer = primary->data_offer;
+ if (data_offer != nullptr) {
+ const char *mime_receive = system_clipboard_text_mime_type(data_offer->types);
+ if (mime_receive) {
+ /* Receive the clipboard in a thread, performing round-trips while waiting.
+ * This is needed so pasting contents from our own `primary->data_source` doesn't hang. */
+ struct ThreadResult {
+ char *data = nullptr;
+ std::atomic<bool> done = false;
+ } thread_result;
+ auto read_clipboard_fn = [](GWL_PrimarySelection_DataOffer *data_offer,
+ const char *mime_receive,
+ std::mutex *mutex,
+ struct ThreadResult *thread_result) {
+ size_t data_len = 0;
+ thread_result->data = read_buffer_from_primary_selection_offer(
+ data_offer, mime_receive, mutex, true, &data_len);
+ thread_result->done = true;
+ };
+ std::thread read_thread(read_clipboard_fn, data_offer, mime_receive, &mutex, &thread_result);
+ read_thread.detach();
+
+ while (!thread_result.done) {
+ wl_display_roundtrip(display->wl_display);
+ }
+ data = thread_result.data;
+
+ /* Reading the data offer unlocks the mutex. */
+ mutex_locked = false;
+ }
+ }
+ if (mutex_locked) {
+ mutex.unlock();
+ }
+ return data;
+}
+
+static char *system_clipboard_get(GWL_Display *display)
+{
+ GWL_Seat *seat = gwl_display_seat_active_get(display);
+ if (UNLIKELY(!seat)) {
+ return nullptr;
+ }
+ std::mutex &mutex = seat->data_offer_copy_paste_mutex;
+
+ mutex.lock();
+ bool mutex_locked = true;
+ char *data = nullptr;
+
+ GWL_DataOffer *data_offer = seat->data_offer_copy_paste;
+ if (data_offer != nullptr) {
+ const char *mime_receive = system_clipboard_text_mime_type(data_offer->types);
+ if (mime_receive) {
+ /* Receive the clipboard in a thread, performing round-trips while waiting.
+ * This is needed so pasting contents from our own `seat->data_source` doesn't hang. */
+ struct ThreadResult {
+ char *data = nullptr;
+ std::atomic<bool> done = false;
+ } thread_result;
+ auto read_clipboard_fn = [](GWL_DataOffer *data_offer,
+ const char *mime_receive,
+ std::mutex *mutex,
+ struct ThreadResult *thread_result) {
+ size_t data_len = 0;
+ thread_result->data = read_buffer_from_data_offer(
+ data_offer, mime_receive, mutex, true, &data_len);
+ thread_result->done = true;
+ };
+ std::thread read_thread(read_clipboard_fn, data_offer, mime_receive, &mutex, &thread_result);
+ read_thread.detach();
+
+ while (!thread_result.done) {
+ wl_display_roundtrip(display->wl_display);
+ }
+ data = thread_result.data;
+
+ /* Reading the data offer unlocks the mutex. */
+ mutex_locked = false;
+ }
+ }
+ if (mutex_locked) {
+ mutex.unlock();
+ }
+ return data;
+}
+
+char *GHOST_SystemWayland::getClipboard(bool selection) const
+{
+ char *data = nullptr;
+ if (selection) {
+ data = system_clipboard_get_primary_selection(display_);
+ }
+ else {
+ data = system_clipboard_get(display_);
+ }
+ return data;
}
static void system_clipboard_put_primary_selection(GWL_Display *display, const char *buffer)
@@ -4950,7 +5332,10 @@ static void system_clipboard_put_primary_selection(GWL_Display *display, const c
if (!display->wp_primary_selection_device_manager) {
return;
}
- GWL_Seat *seat = display->seats[0];
+ GWL_Seat *seat = gwl_display_seat_active_get(display);
+ if (UNLIKELY(!seat)) {
+ return;
+ }
GWL_PrimarySelection *primary = &seat->primary_selection;
std::lock_guard lock{primary->data_source_mutex};
@@ -4969,8 +5354,8 @@ static void system_clipboard_put_primary_selection(GWL_Display *display, const c
zwp_primary_selection_source_v1_add_listener(
data_source->wp_source, &primary_selection_source_listener, primary);
- for (const std::string &type : mime_send) {
- zwp_primary_selection_source_v1_offer(data_source->wp_source, type.c_str());
+ for (size_t i = 0; i < ARRAY_SIZE(ghost_wl_mime_send); i++) {
+ zwp_primary_selection_source_v1_offer(data_source->wp_source, ghost_wl_mime_send[i]);
}
if (seat->wp_primary_selection_device) {
@@ -4981,8 +5366,13 @@ static void system_clipboard_put_primary_selection(GWL_Display *display, const c
static void system_clipboard_put(GWL_Display *display, const char *buffer)
{
- GWL_Seat *seat = display->seats[0];
-
+ if (!display->wl_data_device_manager) {
+ return;
+ }
+ GWL_Seat *seat = gwl_display_seat_active_get(display);
+ if (UNLIKELY(!seat)) {
+ return;
+ }
std::lock_guard lock{seat->data_source_mutex};
GWL_DataSource *data_source = seat->data_source;
@@ -4995,8 +5385,8 @@ static void system_clipboard_put(GWL_Display *display, const char *buffer)
wl_data_source_add_listener(data_source->wl_source, &data_source_listener, seat);
- for (const std::string &type : mime_send) {
- wl_data_source_offer(data_source->wl_source, type.c_str());
+ for (size_t i = 0; i < ARRAY_SIZE(ghost_wl_mime_send); i++) {
+ wl_data_source_offer(data_source->wl_source, ghost_wl_mime_send[i]);
}
if (seat->wl_data_device) {
@@ -5007,10 +5397,6 @@ static void system_clipboard_put(GWL_Display *display, const char *buffer)
void GHOST_SystemWayland::putClipboard(const char *buffer, bool selection) const
{
- if (UNLIKELY(!display_->wl_data_device_manager || display_->seats.empty())) {
- return;
- }
-
if (selection) {
system_clipboard_put_primary_selection(display_, buffer);
}
@@ -5063,12 +5449,12 @@ GHOST_TSuccess GHOST_SystemWayland::getCursorPositionClientRelative(const GHOST_
int32_t &x,
int32_t &y) const
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
- GWL_Seat *seat = display_->seats[0];
GWL_SeatStatePointer *seat_state_pointer = gwl_seat_state_pointer_active(seat);
- if (!seat_state_pointer || !seat_state_pointer->wl_surface) {
+ if (!seat_state_pointer || !seat_state_pointer->wl_surface_window) {
return GHOST_kFailure;
}
const GHOST_WindowWayland *win = static_cast<const GHOST_WindowWayland *>(window);
@@ -5079,26 +5465,26 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorPositionClientRelative(GHOST_IWindo
const int32_t x,
const int32_t y)
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
- GWL_Seat *seat = display_->seats[0];
GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(window);
return setCursorPositionClientRelative_impl(seat, win, x, y);
}
GHOST_TSuccess GHOST_SystemWayland::getCursorPosition(int32_t &x, int32_t &y) const
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
- GWL_Seat *seat = display_->seats[0];
GWL_SeatStatePointer *seat_state_pointer = gwl_seat_state_pointer_active(seat);
if (!seat_state_pointer) {
return GHOST_kFailure;
}
- if (wl_surface *wl_surface_focus = seat_state_pointer->wl_surface) {
+ if (wl_surface *wl_surface_focus = seat_state_pointer->wl_surface_window) {
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
return getCursorPositionClientRelative_impl(seat_state_pointer, win, x, y);
}
@@ -5107,14 +5493,14 @@ GHOST_TSuccess GHOST_SystemWayland::getCursorPosition(int32_t &x, int32_t &y) co
GHOST_TSuccess GHOST_SystemWayland::setCursorPosition(const int32_t x, const int32_t y)
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
- GWL_Seat *seat = display_->seats[0];
/* Intentionally different from `getCursorPosition` which supports both tablet & pointer.
* In the case of setting the cursor location, tablets don't support this. */
- if (wl_surface *wl_surface_focus = seat->pointer.wl_surface) {
+ if (wl_surface *wl_surface_focus = seat->pointer.wl_surface_window) {
GHOST_WindowWayland *win = ghost_wl_surface_user_data(wl_surface_focus);
return setCursorPositionClientRelative_impl(seat, win, x, y);
}
@@ -5288,7 +5674,7 @@ static void cursor_buffer_show(const GWL_Seat *seat)
const int32_t hotspot_y = int32_t(cursor->wl_image.hotspot_y) / scale;
if (seat->wl_pointer) {
wl_pointer_set_cursor(
- seat->wl_pointer, seat->pointer.serial, cursor->wl_surface, hotspot_x, hotspot_y);
+ seat->wl_pointer, seat->pointer.serial, cursor->wl_surface_cursor, hotspot_x, hotspot_y);
}
}
@@ -5372,10 +5758,10 @@ static void cursor_buffer_set(const GWL_Seat *seat, wl_buffer *buffer)
wl_image, cursor->is_custom ? cursor->custom_scale : seat->pointer.theme_scale);
const int32_t hotspot_x = int32_t(wl_image->hotspot_x) / scale;
const int32_t hotspot_y = int32_t(wl_image->hotspot_y) / scale;
- cursor_buffer_set_surface_impl(seat, buffer, cursor->wl_surface, scale);
+ cursor_buffer_set_surface_impl(seat, buffer, cursor->wl_surface_cursor, scale);
wl_pointer_set_cursor(seat->wl_pointer,
seat->pointer.serial,
- visible ? cursor->wl_surface : nullptr,
+ visible ? cursor->wl_surface_cursor : nullptr,
hotspot_x,
hotspot_y);
}
@@ -5461,15 +5847,15 @@ static bool cursor_is_software(const GHOST_TGrabCursorMode mode, const bool use_
GHOST_TSuccess GHOST_SystemWayland::setCursorShape(const GHOST_TStandardCursor shape)
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
- auto cursor_find = cursors.find(shape);
- const char *cursor_name = (cursor_find == cursors.end()) ?
- cursors.at(GHOST_kStandardCursorDefault) :
+ auto cursor_find = ghost_wl_cursors.find(shape);
+ const char *cursor_name = (cursor_find == ghost_wl_cursors.end()) ?
+ ghost_wl_cursors.at(GHOST_kStandardCursorDefault) :
(*cursor_find).second;
- GWL_Seat *seat = display_->seats[0];
GWL_Cursor *cursor = &seat->cursor;
if (!cursor->wl_theme) {
@@ -5503,8 +5889,8 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(const GHOST_TStandardCursor s
GHOST_TSuccess GHOST_SystemWayland::hasCursorShape(const GHOST_TStandardCursor cursorShape)
{
- auto cursor_find = cursors.find(cursorShape);
- if (cursor_find == cursors.end()) {
+ auto cursor_find = ghost_wl_cursors.find(cursorShape);
+ if (cursor_find == ghost_wl_cursors.end()) {
return GHOST_kFailure;
}
const char *value = (*cursor_find).second;
@@ -5522,12 +5908,12 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap,
const int hotY,
const bool /*canInvertColor*/)
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
- GWL_Cursor *cursor = &display_->seats[0]->cursor;
-
+ GWL_Cursor *cursor = &seat->cursor;
if (cursor->custom_data) {
munmap(cursor->custom_data, cursor->custom_data_size);
cursor->custom_data = nullptr;
@@ -5585,14 +5971,19 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap,
cursor->wl_image.hotspot_x = uint32_t(hotX);
cursor->wl_image.hotspot_y = uint32_t(hotY);
- cursor_buffer_set(display_->seats[0], buffer);
+ cursor_buffer_set(seat, buffer);
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_SystemWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitmap)
{
- GWL_Cursor *cursor = &display_->seats[0]->cursor;
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
+ return GHOST_kFailure;
+ }
+
+ GWL_Cursor *cursor = &seat->cursor;
if (cursor->custom_data == nullptr) {
return GHOST_kFailure;
}
@@ -5613,11 +6004,11 @@ GHOST_TSuccess GHOST_SystemWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitma
GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(const bool visible)
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
- GWL_Seat *seat = display_->seats[0];
cursor_visible_set(seat, visible, seat->cursor.is_hardware, CURSOR_VISIBLE_ALWAYS_SET);
return GHOST_kSuccess;
}
@@ -5637,12 +6028,12 @@ bool GHOST_SystemWayland::supportsWindowPosition()
bool GHOST_SystemWayland::getCursorGrabUseSoftwareDisplay(const GHOST_TGrabCursorMode mode)
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return false;
}
#ifdef USE_GNOME_CONFINE_HACK
- GWL_Seat *seat = display_->seats[0];
const bool use_software_confine = seat->use_pointer_software_confine;
#else
const bool use_software_confine = false;
@@ -5830,6 +6221,11 @@ GHOST_WindowWayland *ghost_wl_surface_user_data(struct wl_surface *wl_surface)
* Functionality only used for the WAYLAND implementation.
* \{ */
+void GHOST_SystemWayland::seat_active_set(const struct GWL_Seat *seat)
+{
+ gwl_display_seat_active_set(display_, seat);
+}
+
void GHOST_SystemWayland::window_surface_unref(const wl_surface *wl_surface)
{
#define SURFACE_CLEAR_PTR(surface_test) \
@@ -5840,10 +6236,10 @@ void GHOST_SystemWayland::window_surface_unref(const wl_surface *wl_surface)
/* Only clear window surfaces (not cursors, off-screen surfaces etc). */
for (GWL_Seat *seat : display_->seats) {
- SURFACE_CLEAR_PTR(seat->pointer.wl_surface);
- SURFACE_CLEAR_PTR(seat->tablet.wl_surface);
- SURFACE_CLEAR_PTR(seat->keyboard.wl_surface);
- SURFACE_CLEAR_PTR(seat->wl_surface_focus_dnd);
+ SURFACE_CLEAR_PTR(seat->pointer.wl_surface_window);
+ SURFACE_CLEAR_PTR(seat->tablet.wl_surface_window);
+ SURFACE_CLEAR_PTR(seat->keyboard.wl_surface_window);
+ SURFACE_CLEAR_PTR(seat->wl_surface_window_focus_dnd);
}
#undef SURFACE_CLEAR_PTR
}
@@ -5861,7 +6257,8 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
return GHOST_kFailure;
}
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
/* No change, success. */
@@ -5869,8 +6266,6 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
return GHOST_kSuccess;
}
- GWL_Seat *seat = display_->seats[0];
-
#ifdef USE_GNOME_CONFINE_HACK
const bool was_software_confine = seat->use_pointer_software_confine;
const bool use_software_confine = setCursorGrab_use_software_confine(mode, wl_surface);
@@ -6031,16 +6426,6 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
return GHOST_kSuccess;
}
-struct GWL_SimpleBuffer *GHOST_SystemWayland::clipboard_data(bool selection) const
-{
- return selection ? &display_->clipboard_primary : &display_->clipboard;
-}
-
-struct std::mutex &GHOST_SystemWayland::clipboard_mutex() const
-{
- return display_->clipboard_mutex;
-}
-
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
bool GHOST_SystemWayland::use_libdecor_runtime()
{
diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h
index 7c5459fc461..a8e8d8ddc45 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.h
+++ b/intern/ghost/intern/GHOST_SystemWayland.h
@@ -178,6 +178,9 @@ class GHOST_SystemWayland : public GHOST_System {
/* WAYLAND utility functions. */
+ /** Set this seat to be active. */
+ void seat_active_set(const struct GWL_Seat *seat);
+
/** Clear all references to this surface to prevent accessing NULL pointers. */
void window_surface_unref(const wl_surface *wl_surface);
@@ -189,9 +192,6 @@ class GHOST_SystemWayland : public GHOST_System {
wl_surface *wl_surface,
int scale);
- struct GWL_SimpleBuffer *clipboard_data(bool selection) const;
- struct std::mutex &clipboard_mutex() const;
-
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
static bool use_libdecor_runtime();
#endif
diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h
index 1c0991bba30..396691fa161 100644
--- a/intern/ghost/intern/GHOST_Window.h
+++ b/intern/ghost/intern/GHOST_Window.h
@@ -74,7 +74,7 @@ class GHOST_Window : public GHOST_IWindow {
*/
virtual bool getValid() const override
{
- return m_context != NULL;
+ return m_context != nullptr;
}
/**
@@ -283,8 +283,9 @@ class GHOST_Window : public GHOST_IWindow {
float getNativePixelSize(void) override
{
- if (m_nativePixelSize > 0.0f)
+ if (m_nativePixelSize > 0.0f) {
return m_nativePixelSize;
+ }
return 1.0f;
}
@@ -298,7 +299,8 @@ class GHOST_Window : public GHOST_IWindow {
}
#ifdef WITH_INPUT_IME
- virtual void beginIME(int32_t x, int32_t y, int32_t w, int32_t h, bool completed) override
+ virtual void beginIME(
+ int32_t /*x*/, int32_t /*y*/, int32_t /*w*/, int32_t /*h*/, bool /*completed*/) override
{
/* do nothing temporarily if not in windows */
}
diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp
index 6ee1fb8b27f..ad94a02b514 100644
--- a/intern/ghost/intern/GHOST_WindowWayland.cpp
+++ b/intern/ghost/intern/GHOST_WindowWayland.cpp
@@ -90,7 +90,10 @@ struct GWL_Window {
/** The scale value written to #wl_surface_set_buffer_scale. */
int scale = 0;
- /** The fractional scale used to calculate the DPI. */
+ /**
+ * The fractional scale used to calculate the DPI.
+ * (always set, even when scaling is rounded to whole units).
+ */
wl_fixed_t scale_fractional = 0;
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h
index fdd77fb9eef..5ae33343949 100644
--- a/intern/guardedalloc/MEM_guardedalloc.h
+++ b/intern/guardedalloc/MEM_guardedalloc.h
@@ -271,7 +271,7 @@ void MEM_use_guarded_allocator(void);
template<typename T, typename... Args>
inline T *MEM_new(const char *allocation_name, Args &&...args)
{
- void *buffer = MEM_mallocN(sizeof(T), allocation_name);
+ void *buffer = MEM_mallocN_aligned(sizeof(T), alignof(T), allocation_name);
return new (buffer) T(std::forward<Args>(args)...);
}
diff --git a/intern/guardedalloc/intern/leak_detector.cc b/intern/guardedalloc/intern/leak_detector.cc
index 288d78fd206..5b565b15920 100644
--- a/intern/guardedalloc/intern/leak_detector.cc
+++ b/intern/guardedalloc/intern/leak_detector.cc
@@ -41,7 +41,7 @@ class MemLeakPrinter {
if (fail_on_memleak) {
/* There are many other ways to change the exit code to failure here:
- * - Make the destructor noexcept(false) and throw an exception.
+ * - Make the destructor `noexcept(false)` and throw an exception.
* - Call exit(EXIT_FAILURE).
* - Call terminate().
*/
diff --git a/intern/wayland_dynload/intern/wayland_dynload_client.c b/intern/wayland_dynload/intern/wayland_dynload_client.c
index 68ba5374aba..617a8878199 100644
--- a/intern/wayland_dynload/intern/wayland_dynload_client.c
+++ b/intern/wayland_dynload/intern/wayland_dynload_client.c
@@ -44,7 +44,8 @@ bool wayland_dynload_client_init(const bool verbose)
#define WAYLAND_DYNLOAD_IFACE(symbol) \
{ \
const void *symbol_val; \
- if (!(symbol_val = dynamic_library_find_with_error(lib, #symbol, paths[path_found]))) { \
+ if (!(symbol_val = dynamic_library_find_with_error( \
+ lib, #symbol, paths[path_found], verbose))) { \
return false; \
} \
memcpy(&symbol, symbol_val, sizeof(symbol)); \
@@ -54,7 +55,7 @@ bool wayland_dynload_client_init(const bool verbose)
#define WAYLAND_DYNLOAD_FN(symbol) \
if (!(wayland_dynload_client.symbol = dynamic_library_find_with_error( \
- lib, #symbol, paths[path_found]))) { \
+ lib, #symbol, paths[path_found], verbose))) { \
return false; \
}
#include "wayland_dynload_client.h"
diff --git a/intern/wayland_dynload/intern/wayland_dynload_cursor.c b/intern/wayland_dynload/intern/wayland_dynload_cursor.c
index 3d0526c7ba6..cc62a43bc01 100644
--- a/intern/wayland_dynload/intern/wayland_dynload_cursor.c
+++ b/intern/wayland_dynload/intern/wayland_dynload_cursor.c
@@ -36,7 +36,7 @@ bool wayland_dynload_cursor_init(const bool verbose)
#define WAYLAND_DYNLOAD_FN(symbol) \
if (!(wayland_dynload_cursor.symbol = dynamic_library_find_with_error( \
- lib, #symbol, paths[path_index]))) { \
+ lib, #symbol, paths[path_index], verbose))) { \
return false; \
}
#include "wayland_dynload_cursor.h"
diff --git a/intern/wayland_dynload/intern/wayland_dynload_egl.c b/intern/wayland_dynload/intern/wayland_dynload_egl.c
index cfc195c0408..d8e4dfe0dad 100644
--- a/intern/wayland_dynload/intern/wayland_dynload_egl.c
+++ b/intern/wayland_dynload/intern/wayland_dynload_egl.c
@@ -36,7 +36,7 @@ bool wayland_dynload_egl_init(const bool verbose)
#define WAYLAND_DYNLOAD_FN(symbol) \
if (!(wayland_dynload_egl.symbol = dynamic_library_find_with_error( \
- lib, #symbol, paths[path_found]))) { \
+ lib, #symbol, paths[path_found], verbose))) { \
return false; \
}
#include "wayland_dynload_egl.h"
diff --git a/intern/wayland_dynload/intern/wayland_dynload_libdecor.c b/intern/wayland_dynload/intern/wayland_dynload_libdecor.c
index d8bdd27bb27..dafd1badfda 100644
--- a/intern/wayland_dynload/intern/wayland_dynload_libdecor.c
+++ b/intern/wayland_dynload/intern/wayland_dynload_libdecor.c
@@ -36,7 +36,7 @@ bool wayland_dynload_libdecor_init(const bool verbose)
#define WAYLAND_DYNLOAD_FN(symbol) \
if (!(wayland_dynload_libdecor.symbol = dynamic_library_find_with_error( \
- lib, #symbol, paths[path_index]))) { \
+ lib, #symbol, paths[path_index], verbose))) { \
return false; \
}
#include "wayland_dynload_libdecor.h"
diff --git a/intern/wayland_dynload/intern/wayland_dynload_utils.c b/intern/wayland_dynload/intern/wayland_dynload_utils.c
index 743dac14eec..666de20c5d3 100644
--- a/intern/wayland_dynload/intern/wayland_dynload_utils.c
+++ b/intern/wayland_dynload/intern/wayland_dynload_utils.c
@@ -30,11 +30,16 @@ DynamicLibrary dynamic_library_open_array_with_error(const char **paths,
return lib;
}
-void *dynamic_library_find_with_error(DynamicLibrary lib, const char *symbol, const char *path_lib)
+void *dynamic_library_find_with_error(DynamicLibrary lib,
+ const char *symbol,
+ const char *path_lib,
+ const bool verbose)
{
void *symbol_var = dynamic_library_find(lib, symbol);
if (symbol_var == NULL) {
- fprintf(stderr, "Unable to find '%s' in '%s'.\n", symbol, path_lib);
+ if (verbose) {
+ fprintf(stderr, "Unable to find '%s' in '%s'.\n", symbol, path_lib);
+ }
}
return symbol_var;
}
diff --git a/intern/wayland_dynload/intern/wayland_dynload_utils.h b/intern/wayland_dynload/intern/wayland_dynload_utils.h
index 785f32521e4..1814879615b 100644
--- a/intern/wayland_dynload/intern/wayland_dynload_utils.h
+++ b/intern/wayland_dynload/intern/wayland_dynload_utils.h
@@ -26,4 +26,5 @@ DynamicLibrary dynamic_library_open_array_with_error(const char **paths,
/** Find a symbol, printing an error when the symbol isn't found. */
void *dynamic_library_find_with_error(DynamicLibrary lib,
const char *symbol,
- const char *path_lib);
+ const char *path_lib,
+ bool verbose);