18#ifdef WITH_OPENGL_BACKEND
21#ifdef WITH_VULKAN_BACKEND
25#include <wayland-client-protocol.h>
27#ifdef WITH_OPENGL_BACKEND
28# ifdef WITH_GHOST_WAYLAND_DYNLOAD
31# include <wayland-egl.h>
36#ifdef WITH_GHOST_WAYLAND_LIBDECOR
37# ifdef WITH_GHOST_WAYLAND_DYNLOAD
44#include <fractional-scale-v1-client-protocol.h>
45#include <viewporter-client-protocol.h>
46#include <xdg-activation-v1-client-protocol.h>
47#include <xdg-decoration-unstable-v1-client-protocol.h>
48#include <xdg-shell-client-protocol.h>
75# define USE_CURSOR_IMMEDIATE_DISPATCH
90#ifdef USE_EVENT_BACKGROUND_THREAD
91# ifdef WITH_GHOST_WAYLAND_LIBDECOR
92# ifdef HAVE_MALLOC_USABLE_SIZE
93# define USE_LIBDECOR_CONFIG_COPY_WORKAROUND
103#ifdef USE_LIBDECOR_CONFIG_COPY_WORKAROUND
104# define USE_LIBDECOR_CONFIG_COPY_QUEUE
107#ifdef USE_LIBDECOR_CONFIG_COPY_WORKAROUND
108static libdecor_configuration *ghost_wl_libdecor_configuration_copy(
109 const libdecor_configuration *configuration);
110static void ghost_wl_libdecor_configuration_free(libdecor_configuration *configuration);
117#ifdef WITH_GHOST_WAYLAND_LIBDECOR
119# define use_libdecor GHOST_SystemWayland::use_libdecor_runtime()
122#ifdef WITH_GHOST_WAYLAND_LIBDECOR
123struct GWL_LibDecor_Window {
124 libdecor_frame *frame =
nullptr;
132 bool ack_configure =
false;
134 int size[2] = {0, 0};
135 libdecor_configuration *configuration =
nullptr;
137# ifdef USE_LIBDECOR_CONFIG_COPY_WORKAROUND
138 bool configuration_needs_free =
false;
141# ifdef USE_LIBDECOR_CONFIG_COPY_QUEUE
146 std::vector<libdecor_configuration *> configuration_queue;
152 bool initial_configure_seen =
false;
154 std::optional<GHOST_TWindowState> initial_configure_state = std::nullopt;
157static void gwl_libdecor_window_destroy(GWL_LibDecor_Window *decor)
159# ifdef USE_LIBDECOR_CONFIG_COPY_WORKAROUND
160 if (decor->pending.configuration_needs_free) {
161 ghost_wl_libdecor_configuration_free(decor->pending.configuration);
166# ifdef USE_LIBDECOR_CONFIG_COPY_QUEUE
167 for (libdecor_configuration *configuration : decor->pending.configuration_queue) {
168 ghost_wl_libdecor_configuration_free(configuration);
170 decor->pending.configuration_queue.clear();
182 enum zxdg_toplevel_decoration_v1_mode
mode = (
enum zxdg_toplevel_decoration_v1_mode)0;
206 xdg_toplevel_destroy(decor->
toplevel);
207 xdg_surface_destroy(decor->
surface);
217 GHOST_ASSERT(round_value > 0,
"Invalid rounding value!");
218 *value_p = (*value_p / round_value) * round_value;
223 GHOST_ASSERT(round_value > 0,
"Invalid rounding value!");
224 value_p[0] = (value_p[0] / round_value) * round_value;
225 value_p[1] = (value_p[1] / round_value) * round_value;
233 return value == ((value / round_value) * round_value);
258 return value * scale_params.
scale;
266 return value / scale_params.
scale;
291 if (*cg ==
nullptr) {
308#ifdef USE_EVENT_BACKGROUND_THREAD
331#ifdef USE_EVENT_BACKGROUND_THREAD
368# define PENDING_NUM (PENDING_WINDOW_CURSOR_SHAPE_REFRESH + 1)
422#ifdef WITH_OPENGL_BACKEND
423 wl_egl_window *egl_window =
nullptr;
425#ifdef WITH_VULKAN_BACKEND
442#ifdef WITH_GHOST_WAYLAND_LIBDECOR
443 GWL_LibDecor_Window *libdecor =
nullptr;
454#ifdef USE_EVENT_BACKGROUND_THREAD
477#ifdef USE_EVENT_BACKGROUND_THREAD
488#ifdef WITH_OPENGL_BACKEND
496#ifdef WITH_VULKAN_BACKEND
502 win->
backend.vulkan_window_info->size[0] =
size[0];
503 win->
backend.vulkan_window_info->size[1] =
size[1];
510#ifdef WITH_GHOST_WAYLAND_LIBDECOR
512 GWL_LibDecor_Window &decor = *win->libdecor;
519 xdg_toplevel_set_title(decor.
toplevel, title);
536#ifdef WITH_GHOST_WAYLAND_LIBDECOR
540static bool gwl_window_state_set_for_libdecor(libdecor_frame *frame,
547 switch (state_current) {
589 switch (state_current) {
591 xdg_toplevel_unset_maximized(toplevel);
595 xdg_toplevel_unset_fullscreen(toplevel);
604 xdg_toplevel_set_maximized(toplevel);
608 xdg_toplevel_set_minimized(toplevel);
612 xdg_toplevel_set_fullscreen(toplevel,
nullptr);
623#ifdef WITH_GHOST_WAYLAND_LIBDECOR
625 result = gwl_window_state_set_for_libdecor(win->libdecor->
frame,
state, state_current);
681 bool *r_surface_needs_commit,
682 bool *r_surface_needs_buffer_scale)
688 if (viewporter ==
nullptr) {
700 if (r_surface_needs_buffer_scale) {
701 *r_surface_needs_buffer_scale =
true;
707 if (r_surface_needs_commit) {
708 *r_surface_needs_commit =
true;
719 bool *r_surface_needs_commit,
720 bool *r_surface_needs_buffer_scale)
733 if (r_surface_needs_buffer_scale) {
734 *r_surface_needs_buffer_scale =
true;
740 if (r_surface_needs_commit) {
741 *r_surface_needs_commit =
true;
759 wp_viewport_set_destination(
782 if (
UNLIKELY(activation_manager ==
nullptr)) {
792 xdg_activation_token_v1_add_listener(
811 if (ghost_window_active) {
829 GWL_Window *win,
bool *r_surface_needs_commit,
bool *r_surface_needs_buffer_scale)
842 if (r_surface_needs_buffer_scale) {
843 *r_surface_needs_buffer_scale =
true;
848 if (r_surface_needs_commit) {
849 *r_surface_needs_commit =
true;
859 bool *r_surface_needs_commit,
860 bool *r_surface_needs_buffer_scale)
868 win, r_surface_needs_commit, r_surface_needs_buffer_scale);
872 bool *r_surface_needs_commit,
873 bool *r_surface_needs_resize_for_backend,
874 bool *r_surface_needs_buffer_scale)
887 win, r_surface_needs_commit, r_surface_needs_buffer_scale);
893 if (r_surface_needs_resize_for_backend) {
894 *r_surface_needs_resize_for_backend =
true;
908#ifdef USE_EVENT_BACKGROUND_THREAD
957#ifdef USE_EVENT_BACKGROUND_THREAD
959 "Only from main thread!");
964 bool surface_needs_commit =
false;
965 bool surface_needs_resize_for_backend =
false;
966 bool surface_needs_buffer_scale =
false;
973 &surface_needs_commit,
974 &surface_needs_resize_for_backend,
975 &surface_needs_buffer_scale);
981 win, &surface_needs_commit, &surface_needs_buffer_scale);
986 surface_needs_buffer_scale =
true;
990 if (surface_needs_resize_for_backend) {
994 if (surface_needs_buffer_scale) {
998#ifdef WITH_GHOST_WAYLAND_LIBDECOR
1000 GWL_LibDecor_Window &decor = *win->libdecor;
1001 if (decor.pending.ack_configure) {
1002 surface_needs_commit =
true;
1004 decor.pending.ack_configure =
false;
1008# ifdef USE_LIBDECOR_CONFIG_COPY_QUEUE
1009 GHOST_ASSERT(decor.pending.size[0] != 0 && decor.pending.size[1] != 0,
"Invalid size");
1010 for (libdecor_configuration *configuration : decor.pending.configuration_queue) {
1012 ghost_wl_libdecor_configuration_free(configuration);
1014 decor.pending.configuration_queue.clear();
1021 decor.pending.size[0] = 0;
1022 decor.pending.size[1] = 0;
1024 if (decor.initial_configure_seen ==
false) {
1025 decor.initial_configure_seen =
true;
1027 if (decor.initial_configure_state) {
1031 decor.initial_configure_state = std::nullopt;
1035# ifdef USE_LIBDECOR_CONFIG_COPY_WORKAROUND
1036 if (decor.pending.configuration_needs_free) {
1037 ghost_wl_libdecor_configuration_free(decor.pending.configuration);
1038 decor.pending.configuration_needs_free =
false;
1042 decor.pending.configuration =
nullptr;
1053 surface_needs_commit =
true;
1062 if (surface_needs_commit) {
1063#ifdef USE_EVENT_BACKGROUND_THREAD
1091 "GHOST internal active state does not match WAYLAND!");
1106#ifdef USE_EVENT_BACKGROUND_THREAD
1136 if (scale_fractional_a < scale_fractional_b) {
1139 if (scale_fractional_a > scale_fractional_b) {
1148 int *r_scale_fractional)
1153 output_max = reg_output;
1158 if (r_scale_fractional) {
1163 return output_max->
scale;
1165 if (r_scale_fractional) {
1168 return scale_default;
1173 int *r_scale_fractional)
1177 if (!output_uniform) {
1178 output_uniform = reg_output;
1182 output_uniform =
nullptr;
1187 if (output_uniform) {
1188 if (r_scale_fractional) {
1193 return output_uniform->
scale;
1195 if (r_scale_fractional) {
1198 return scale_default;
1209#ifdef USE_LIBDECOR_CONFIG_COPY_WORKAROUND
1211static libdecor_configuration *ghost_wl_libdecor_configuration_copy(
1212 const libdecor_configuration *configuration)
1214 size_t configuration_size = malloc_usable_size((
void *)configuration);
1215 libdecor_configuration *configuration_copy = (libdecor_configuration *)malloc(
1216 configuration_size);
1217 memcpy((
void *)configuration_copy, (
const void *)configuration, configuration_size);
1218 return configuration_copy;
1221static void ghost_wl_libdecor_configuration_free(libdecor_configuration *configuration)
1223 free((
void *)configuration);
1235#define LOG (&LOG_WL_XDG_TOPLEVEL)
1244 CLOG_DEBUG(
LOG,
"configure (size=[%d, %d])", width, height);
1248#ifdef USE_EVENT_BACKGROUND_THREAD
1253 for (
int i = 0;
i < 2;
i++) {
1267 enum xdg_toplevel_state *
state;
1270 case XDG_TOPLEVEL_STATE_MAXIMIZED:
1273 case XDG_TOPLEVEL_STATE_FULLSCREEN:
1276 case XDG_TOPLEVEL_STATE_ACTIVATED:
1300 CLOG_DEBUG(
LOG,
"configure_bounds (size=[%d, %d])", width, height);
1338 xdg_activation_token_v1 *xdg_activation_token_v1,
1348 xdg_activation_v1_activate(activation_manager, token, win->
wl.
surface);
1371#define LOG (&LOG_WL_FRACTIONAL_SCALE)
1374 void *
data, wp_fractional_scale_v1 * ,
uint preferred_scale)
1376#ifdef USE_EVENT_BACKGROUND_THREAD
1377 std::lock_guard lock_frame_guard{
static_cast<GWL_Window *
>(
data)->frame_pending_mutex};
1380 "preferred_scale (preferred_scale=%.6f)",
1403#ifdef WITH_GHOST_WAYLAND_LIBDECOR
1405static CLG_LogRef LOG_WL_LIBDECOR_FRAME = {
"ghost.wl.handle.libdecor_frame"};
1406# define LOG (&LOG_WL_LIBDECOR_FRAME)
1408static void libdecor_frame_handle_configure(libdecor_frame *frame,
1409 libdecor_configuration *configuration,
1414# ifdef USE_EVENT_BACKGROUND_THREAD
1415 std::lock_guard lock_frame_guard{
static_cast<GWL_Window *
>(
data)->frame_pending_mutex};
1416 const bool is_main_thread = [
data] {
1426 int size_next[2] = {0, 0};
1435 "Fractional scale has no fractional component!");
1440 win->frame.buffer_scale;
1443 configuration, frame, &size_next[0], &size_next[1]))
1445 if (fractional_scale) {
1452 frame_pending.
size[0] = ((size_next[0] *
scale) * fractional_scale) / scale_as_fractional;
1453 frame_pending.
size[1] = ((size_next[1] *
scale) * fractional_scale) / scale_as_fractional;
1456 frame_pending.
size[0] = size_next[0] *
scale;
1457 frame_pending.
size[1] = size_next[1] *
scale;
1468 const GWL_LibDecor_Window &decor = *win->libdecor;
1469 size_next[0] = decor.pending.size[0];
1470 size_next[1] = decor.pending.size[1];
1476 enum libdecor_window_state window_state;
1478 frame_pending.
is_maximised = window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED;
1479 frame_pending.
is_fullscreen = window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN;
1480 frame_pending.
is_active = window_state & LIBDECOR_WINDOW_STATE_ACTIVE;
1486 GWL_LibDecor_Window &decor = *win->libdecor;
1488# ifdef USE_LIBDECOR_CONFIG_COPY_WORKAROUND
1490 if (decor.pending.configuration_needs_free) {
1491 ghost_wl_libdecor_configuration_free(decor.pending.configuration);
1492 decor.pending.configuration_needs_free =
false;
1496 decor.pending.size[0] = size_next[0];
1497 decor.pending.size[1] = size_next[1];
1498 decor.pending.configuration = configuration;
1499 decor.pending.ack_configure =
true;
1501# ifdef USE_EVENT_BACKGROUND_THREAD
1502 if (!is_main_thread) {
1503# ifdef USE_LIBDECOR_CONFIG_COPY_WORKAROUND
1504 decor.pending.configuration = ghost_wl_libdecor_configuration_copy(configuration);
1505 decor.pending.configuration_needs_free =
true;
1509 decor.pending.configuration =
nullptr;
1514# ifdef USE_LIBDECOR_CONFIG_COPY_QUEUE
1515 if (!(size_next[0] && size_next[1])) {
1517 if (decor.pending.configuration_needs_free ==
false) {
1518 decor.pending.configuration = ghost_wl_libdecor_configuration_copy(
1519 decor.pending.configuration);
1520 decor.pending.configuration_needs_free =
true;
1523 decor.pending.configuration_queue.push_back(decor.pending.configuration);
1524 decor.pending.configuration =
nullptr;
1525 decor.pending.configuration_needs_free =
false;
1527 decor.pending.ack_configure =
false;
1535# ifdef USE_EVENT_BACKGROUND_THREAD
1536 if (!is_main_thread) {
1547static void libdecor_frame_handle_close(libdecor_frame * ,
void *
data)
1556static void libdecor_frame_handle_commit(libdecor_frame * ,
void *
data)
1569static libdecor_frame_interface libdecor_frame_iface = {
1570 libdecor_frame_handle_configure,
1571 libdecor_frame_handle_close,
1572 libdecor_frame_handle_commit,
1586#define LOG (&LOG_WL_XDG_TOPLEVEL_DECORATION)
1589 void *
data, zxdg_toplevel_decoration_v1 * ,
const uint32_t mode)
1595 win->
xdg_decor->
mode = (zxdg_toplevel_decoration_v1_mode)mode;
1611#define LOG (&LOG_WL_XDG_SURFACE)
1614 xdg_surface *xdg_surface,
1615 const uint32_t serial)
1625#ifdef USE_EVENT_BACKGROUND_THREAD
1626 std::lock_guard lock_frame_guard{
static_cast<GWL_Window *
>(
data)->frame_pending_mutex};
1631#ifdef USE_EVENT_BACKGROUND_THREAD
1633 const bool is_main_thread = system->
main_thread_id == std::this_thread::get_id();
1634 if (!is_main_thread) {
1659#define LOG (&LOG_WL_SURFACE)
1691#if defined(WL_SURFACE_PREFERRED_BUFFER_SCALE_SINCE_VERSION) && \
1692 defined(WL_SURFACE_PREFERRED_BUFFER_TRANSFORM_SINCE_VERSION)
1693static void surface_handle_preferred_buffer_scale(
void * ,
1698 CLOG_DEBUG(
LOG,
"handle_preferred_buffer_scale (factor=%d)", factor);
1701static void surface_handle_preferred_buffer_transform(
void * ,
1714#if defined(WL_SURFACE_PREFERRED_BUFFER_SCALE_SINCE_VERSION) && \
1715 defined(WL_SURFACE_PREFERRED_BUFFER_TRANSFORM_SINCE_VERSION)
1716 surface_handle_preferred_buffer_scale,
1717 surface_handle_preferred_buffer_transform,
1735 const uint32_t width,
1736 const uint32_t height,
1740 const bool is_dialog,
1742 const bool exclusive,
1747 preferred_device_(preferred_device)
1749#ifdef USE_EVENT_BACKGROUND_THREAD
1750 std::lock_guard lock_server_guard{*system->
server_mutex};
1753 window_->ghost_window =
this;
1754 window_->ghost_system = system;
1755 window_->ghost_context_type = type;
1776 int scale_fractional_from_output;
1778 system_->outputs_get(), 0, &scale_fractional_from_output);
1780 window_->frame.size[0] =
int32_t(width);
1781 window_->frame.size[1] =
int32_t(height);
1783 window_->is_dialog = is_dialog;
1786 window_->wl.surface = wl_compositor_create_surface(system_->wl_compositor_get());
1791 wp_fractional_scale_manager_v1 *fractional_scale_manager =
1793 if (fractional_scale_manager) {
1794 window_->wp.fractional_scale_handle = wp_fractional_scale_manager_v1_get_fractional_scale(
1795 fractional_scale_manager, window_->wl.surface);
1796 wp_fractional_scale_v1_add_listener(
1804 const int32_t size_min[2] = {320, 240};
1808#ifdef WITH_GHOST_WAYLAND_LIBDECOR
1810 window_->libdecor =
new GWL_LibDecor_Window;
1811 GWL_LibDecor_Window &decor = *window_->libdecor;
1815 system_->libdecor_context_get(), window_->wl.surface, &libdecor_frame_iface, window_);
1820 if (parent_window) {
1821 GWL_LibDecor_Window &decor_parent =
1831 decor.
surface = xdg_wm_base_get_xdg_surface(system_->xdg_decor_shell_get(),
1832 window_->wl.surface);
1836 xdg_toplevel_set_app_id(decor.
toplevel, xdg_app_id);
1841 if (parent_window && is_dialog) {
1850#ifdef WITH_GHOST_WAYLAND_LIBDECOR
1858 wl_surface_set_user_data(window_->wl.surface,
this);
1864#ifdef WITH_GHOST_WAYLAND_LIBDECOR
1873 if (system_->xdg_decor_manager_get()) {
1874 const bool use_window_frame = system_->use_window_frame_get();
1875 decor.
toplevel_decor = zxdg_decoration_manager_v1_get_toplevel_decoration(
1876 system_->xdg_decor_manager_get(), decor.
toplevel);
1877 zxdg_toplevel_decoration_v1_add_listener(
1882 ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE :
1883 ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
1887 wl_surface_commit(window_->wl.surface);
1898 int early_buffer_scale = 0;
1899 int early_fractional_scale = 0;
1901 if (
const int test_fractional_scale =
1902 fractional_scale_manager ? (window_->frame_pending.fractional_scale_preferred ?
1903 window_->frame_pending.fractional_scale_preferred :
1904 scale_fractional_from_output) :
1908 early_fractional_scale = test_fractional_scale;
1913 early_fractional_scale = 0;
1916 else if (buffer_scale_from_output) {
1917 early_buffer_scale = buffer_scale_from_output;
1920 if (early_fractional_scale != 0) {
1923 window_->frame.fractional_scale_preferred = early_fractional_scale;
1924 window_->frame.fractional_scale = early_fractional_scale;
1925 window_->frame.buffer_scale = 1;
1927 window_->frame_pending.fractional_scale_preferred = early_fractional_scale;
1928 window_->frame_pending.fractional_scale = early_fractional_scale;
1929 window_->frame_pending.buffer_scale = 1;
1932 window_->frame_pending.is_scale_init =
true;
1935 bool surface_needs_commit_dummy =
false, surface_needs_buffer_scale_dummy =
false;
1937 window_, &surface_needs_commit_dummy, &surface_needs_buffer_scale_dummy);
1939 else if (early_buffer_scale != 0) {
1943 window_->frame.buffer_scale = early_buffer_scale;
1944 window_->frame_pending.buffer_scale = early_buffer_scale;
1947 window_->frame_pending.is_scale_init =
true;
1955 window_->frame.buffer_scale = 1;
1956 window_->frame_pending.buffer_scale = 1;
1957 GHOST_ASSERT(window_->frame_pending.is_scale_init ==
false,
1958 "An initialized scale is not expected");
1961 if (window_->frame_pending.is_scale_init) {
1964 "Fractional scale was not properly initialized");
1967 wl_surface_set_buffer_scale(window_->wl.surface, window_->frame.buffer_scale);
1971#ifdef WITH_GHOST_WAYLAND_LIBDECOR
1980 window_->frame.size[0] = std::min(window_->frame.size[0],
1982 window_->frame.size[1] = std::min(window_->frame.size[1],
1991#ifdef WITH_OPENGL_BACKEND
1992 if (type == GHOST_kDrawingContextTypeOpenGL) {
1994 window_->wl.surface,
int(window_->frame.size[0]),
int(window_->frame.size[1]));
1997#ifdef WITH_VULKAN_BACKEND
1998 if (type == GHOST_kDrawingContextTypeVulkan) {
2000 window_->backend.vulkan_window_info->
size[0] = window_->frame.size[0];
2001 window_->backend.vulkan_window_info->size[1] = window_->frame.size[1];
2012#ifdef WITH_GHOST_WAYLAND_LIBDECOR
2013# ifdef WITH_VULKAN_BACKEND
2014 const bool libdecor_wait_for_window_init = (type == GHOST_kDrawingContextTypeVulkan);
2016 const bool libdecor_wait_for_window_init =
false;
2024 GHOST_PRINT(
"Failed to create drawing context" << std::endl);
2027 window_->is_valid_setup =
true;
2030 if (window_->is_valid_setup ==
false) {
2035#ifdef WITH_GHOST_WAYLAND_LIBDECOR
2036 if (use_libdecor && libdecor_wait_for_window_init)
2052 GWL_LibDecor_Window &decor = *window_->libdecor;
2053 decor.initial_configure_state =
state;
2055 else if (use_libdecor) {
2057 wl_surface_commit(window_->wl.surface);
2058 GWL_LibDecor_Window &decor = *window_->libdecor;
2101 wl_surface_commit(window_->wl.surface);
2103#ifdef WITH_OPENGL_BACKEND
2104 if (type == GHOST_kDrawingContextTypeOpenGL) {
2116 window_->is_init =
true;
2121#ifdef USE_EVENT_BACKGROUND_THREAD
2122 std::lock_guard lock_server_guard{*system_->server_mutex};
2127#ifdef WITH_OPENGL_BACKEND
2128 if (window_->ghost_context_type == GHOST_kDrawingContextTypeOpenGL) {
2132#ifdef WITH_VULKAN_BACKEND
2133 if (window_->ghost_context_type == GHOST_kDrawingContextTypeVulkan) {
2134 delete window_->backend.vulkan_window_info;
2138 if (window_->xdg.activation_token) {
2139 xdg_activation_token_v1_destroy(window_->xdg.activation_token);
2140 window_->xdg.activation_token =
nullptr;
2143 if (window_->wp.fractional_scale_handle) {
2144 wp_fractional_scale_v1_destroy(window_->wp.fractional_scale_handle);
2145 window_->wp.fractional_scale_handle =
nullptr;
2148 if (window_->wp.viewport) {
2149 wp_viewport_destroy(window_->wp.viewport);
2150 window_->wp.viewport =
nullptr;
2153#ifdef WITH_GHOST_WAYLAND_LIBDECOR
2155 gwl_libdecor_window_destroy(window_->libdecor);
2165 system_->window_surface_unref(window_->wl.surface);
2167 wl_surface_destroy(window_->wl.surface);
2174 if (window_->cursor_generator) {
2181#ifdef USE_EVENT_BACKGROUND_THREAD
2184 GHOST_ASSERT(system_->main_thread_id == std::this_thread::get_id(),
"Only from main thread!");
2191 return system_->cursor_shape_check(cursor_shape);
2196#ifdef USE_EVENT_BACKGROUND_THREAD
2197 std::lock_guard lock_server_guard{*system_->server_mutex};
2209 if (system_->window_cursor_grab_set(mode,
2214 window_->wl.surface,
2215 this->scale_params_get()))
2224#ifdef USE_EVENT_BACKGROUND_THREAD
2225 std::lock_guard lock_server_guard{*system_->server_mutex};
2229 system_->getWindowManager()->getActiveWindow());
2243 wl_display *display = system_->wl_display_get();
2244#ifdef USE_CURSOR_IMMEDIATE_DISPATCH
2258 ok = system_->cursor_shape_check(shape);
2268#ifdef USE_EVENT_BACKGROUND_THREAD
2269 std::lock_guard lock_server_guard{*system_->server_mutex};
2271 return system_->cursor_grab_use_software_display_get(
cursor_grab_);
2278#ifdef USE_EVENT_BACKGROUND_THREAD
2279 std::lock_guard lock_server_guard{*system_->server_mutex};
2282 if (window_->cursor_generator) {
2285 window_->cursor_generator = cursor_generator;
2291 wl_display *display = system_->wl_display_get();
2294#ifdef USE_CURSOR_IMMEDIATE_DISPATCH
2302 const uint8_t *
mask,
2304 const int hot_spot[2],
2305 const bool can_invert_color)
2313 (void)can_invert_color;
2320#ifdef USE_EVENT_BACKGROUND_THREAD
2321 std::lock_guard lock_server_guard{*system_->server_mutex};
2323 return system_->cursor_bitmap_get(bitmap);
2333#ifdef USE_EVENT_BACKGROUND_THREAD
2334 std::lock_guard lock_server_guard{*system_->server_mutex};
2342 return window_->title.empty() ?
"untitled" : window_->title;
2358 return setClientSize(width, uint32_t(window_->frame.size[1]));
2363 return setClientSize(uint32_t(window_->frame.size[0]), height);
2368#ifdef USE_EVENT_BACKGROUND_THREAD
2369 std::lock_guard lock_server_guard{*system_->server_mutex};
2370 std::lock_guard lock_frame_guard{window_->frame_pending_mutex};
2375 frame_pending.
size[0] = width;
2376 frame_pending.
size[1] = height;
2407 if (window_->frame.fractional_scale) {
2411 return window_->frame.buffer_scale *
base_dpi;
2416#ifdef USE_EVENT_BACKGROUND_THREAD
2417 std::lock_guard lock_server_guard{*system_->server_mutex};
2419 const GHOST_TSuccess ok = system_->cursor_visibility_set(visible);
2421 wl_display *display = system_->wl_display_get();
2424#ifdef USE_CURSOR_IMMEDIATE_DISPATCH
2433#ifdef USE_EVENT_BACKGROUND_THREAD
2434 std::lock_guard lock_server_guard{*system_->server_mutex};
2441#ifdef USE_EVENT_BACKGROUND_THREAD
2442 std::lock_guard lock_server_guard{*system_->server_mutex};
2467 return window_->is_dialog;
2478#ifdef WITH_VULKAN_BACKEND
2479 case GHOST_kDrawingContextTypeVulkan: {
2481 GHOST_kVulkanPlatformWayland,
2484 window_->wl.surface,
2485 system_->wl_display_get(),
2486 window_->backend.vulkan_window_info,
2491 if (
context->initializeDrawingContext()) {
2499#ifdef WITH_OPENGL_BACKEND
2500 case GHOST_kDrawingContextTypeOpenGL: {
2501 for (
int minor = 6; minor >= 3; --minor) {
2502 GHOST_Context *
context =
new GHOST_ContextEGL(
2505 EGLNativeWindowType(window_->backend.egl_window),
2506 EGLNativeDisplayType(system_->wl_display_get()),
2507 EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
2515 if (
context->initializeDrawingContext()) {
2530#ifdef WITH_INPUT_IME
2532void GHOST_WindowWayland::beginIME(
2535 system_->ime_begin(
this,
x,
y,
w, h, completed);
2538void GHOST_WindowWayland::endIME()
2540 system_->ime_end(
this);
2555 return window_->frame.buffer_scale;
2563 scale_params->
is_fractional = (window_->frame.fractional_scale != 0);
2564 scale_params->
scale = scale_params->
is_fractional ? window_->frame.fractional_scale :
2565 window_->frame.buffer_scale;
2566 return *scale_params;
2571 if (window_->frame.fractional_scale) {
2574 return value / window_->frame.buffer_scale;
2579 if (window_->frame.fractional_scale) {
2582 return value * window_->frame.buffer_scale;
2587 return window_->wl.surface;
2592 return window_->outputs;
2605 return system_->pushEvent_maybe_pending(
2613#ifdef USE_EVENT_BACKGROUND_THREAD
2614 const bool is_main_thread = system_->main_thread_id == std::this_thread::get_id();
2620 if (window_->is_init) {
2621 if (system_->getWindowManager()->setActiveWindow(
this) ==
GHOST_kFailure) {
2628#ifdef WITH_GHOST_WAYLAND_LIBDECOR
2643#ifdef USE_EVENT_BACKGROUND_THREAD
2644 const bool is_main_thread = system_->main_thread_id == std::this_thread::get_id();
2649 if (window_->is_init) {
2650 system_->getWindowManager()->setWindowInactive(
this);
2655#ifdef WITH_GHOST_WAYLAND_LIBDECOR
2668 return system_->pushEvent_maybe_pending(
2676 return system_->pushEvent_maybe_pending(
2690#ifdef USE_EVENT_BACKGROUND_THREAD
2691 if (system_->main_thread_id != std::this_thread::get_id()) {
2701#ifdef USE_EVENT_BACKGROUND_THREAD
2713#ifdef USE_EVENT_BACKGROUND_THREAD
2714 if (system_->main_thread_id != std::this_thread::get_id()) {
2719 int fractional_scale_next = -1;
2720 int fractional_scale_from_output = 0;
2728#ifdef USE_EVENT_BACKGROUND_THREAD
2729 std::lock_guard lock_frame_guard{window_->frame_pending_mutex};
2732 if (window_->wp.fractional_scale_handle) {
2735 if (window_->frame_pending.fractional_scale_preferred != 0) {
2736 fractional_scale_next = window_->frame_pending.fractional_scale_preferred;
2741 if (fractional_scale_next == -1) {
2742 fractional_scale_next = fractional_scale_from_output;
2746 bool changed =
false;
2748 const bool is_fractional_prev = window_->frame.fractional_scale != 0;
2752 window_->frame_pending.fractional_scale = is_fractional_next ? fractional_scale_next : 0;
2753 window_->frame_pending.buffer_scale = is_fractional_next ?
2757 const int fractional_scale_prev = window_->frame.fractional_scale ?
2758 window_->frame.fractional_scale :
2763 bool do_frame_resize =
false;
2764 bool do_frame_update =
false;
2766 if (window_->frame_pending.is_scale_init ==
false) {
2767 window_->frame_pending.is_scale_init =
true;
2776#ifdef WITH_GHOST_WAYLAND_LIBDECOR
2785 int size_next[2] = {0, 0};
2786 int size_orig[2] = {0, 0};
2789 for (
size_t i = 0;
i <
ARRAY_SIZE(window_->frame_pending.size);
i++) {
2790 const int value = size_next[
i] ? window_->frame_pending.size[
i] : window_->frame.size[
i];
2791 size_orig[
i] = value;
2792 if (is_fractional_prev || is_fractional_next) {
2794 double(fractional_scale_next));
2797 size_next[
i] = value / scale_prev;
2799 if (window_->frame_pending.buffer_scale > 1) {
2804 if (size_orig[0] != size_next[0] || size_orig[1] != size_next[1]) {
2805 GWL_LibDecor_Window &decor = *window_->libdecor;
2813 do_frame_resize =
false;
2814 do_frame_update =
true;
2823 if (window_->frame_pending.buffer_scale != window_->frame.buffer_scale) {
2824 do_frame_resize =
true;
2829 if ((fractional_scale_prev != fractional_scale_next) ||
2830 (window_->frame_pending.buffer_scale != window_->frame.buffer_scale))
2832 do_frame_resize =
true;
2836 if (do_frame_resize) {
2843 for (
size_t i = 0;
i <
ARRAY_SIZE(window_->frame_pending.size);
i++) {
2844 const int value = window_->frame_pending.size[
i] ? window_->frame_pending.size[
i] :
2845 window_->frame.size[
i];
2846 if (is_fractional_prev || is_fractional_next) {
2847 window_->frame_pending.size[
i] = lroundf((value *
double(fractional_scale_next)) /
2848 double(fractional_scale_prev));
2851 window_->frame_pending.size[
i] = (value * scale_next) / scale_prev;
2853 if (window_->frame_pending.buffer_scale > 1) {
2854 gwl_round_int_by(&window_->frame_pending.size[
i], window_->frame_pending.buffer_scale);
2857 do_frame_update =
true;
2860 if (do_frame_update) {
2870 std::vector<GWL_Output *> &
outputs = window_->outputs;
2881 std::vector<GWL_Output *> &
outputs = window_->outputs;
2890#ifdef USE_EVENT_BACKGROUND_THREAD
2898 "Run from main thread!");
KDTree *BLI_kdtree_nd_ new(unsigned int nodes_len_capacity)
void BLI_kdtree_nd_ free(KDTree *tree)
#define CLOG_DEBUG(clg_ref,...)
#define GHOST_OPENGL_EGL_CONTEXT_FLAGS
#define GHOST_OPENGL_EGL_RESET_NOTIFICATION_STRATEGY
#define GHOST_ASSERT(x, info)
GWL_Output * ghost_wl_output_user_data(wl_output *wl_output)
void ghost_wl_surface_tag(wl_surface *wl_surface)
bool ghost_wl_display_report_error_if_set(wl_display *display)
bool ghost_wl_output_own(const wl_output *wl_output)
#define FRACTIONAL_DENOMINATOR
@ GHOST_kWindowStateMinimized
@ GHOST_kWindowStateMaximized
@ GHOST_kWindowStateNormal
@ GHOST_kWindowStateFullScreen
@ GHOST_kStandardCursorCustom
@ GHOST_kStandardCursorDefault
@ GHOST_kEventWindowClose
@ GHOST_kEventWindowActivate
@ GHOST_kEventWindowUpdateDecor
@ GHOST_kEventWindowDeactivate
@ GHOST_kEventWindowDPIHintChanged
GHOST_TDrawingContextType
@ GHOST_kDrawingContextTypeNone
#define WL_ARRAY_FOR_EACH(pos, array)
static void wp_fractional_scale_handle_preferred_scale(void *data, wp_fractional_scale_v1 *, uint preferred_scale)
wl_fixed_t gwl_window_scale_wl_fixed_to(const GWL_WindowScaleParams &scale_params, wl_fixed_t value)
static bool gwl_round_int_test(const int value, const int round_value)
static GHOST_TSuccess gwl_window_cursor_shape_refresh(GHOST_TStandardCursor shape, const GHOST_CursorGenerator *cg, GHOST_SystemWayland *system)
eGWL_PendingWindowActions
@ PENDING_WINDOW_FRAME_CONFIGURE
@ PENDING_OUTPUT_SCALE_UPDATE_DEFERRED
@ PENDING_WINDOW_CURSOR_SHAPE_REFRESH
@ PENDING_WINDOW_SURFACE_COMMIT
@ PENDING_OUTPUT_SCALE_UPDATE
wl_fixed_t gwl_window_scale_wl_fixed_from(const GWL_WindowScaleParams &scale_params, wl_fixed_t value)
static void gwl_window_cursor_custom_clear(GHOST_CursorGenerator **cg)
static void gwl_round_int2_by(int value_p[2], const int round_value)
static void surface_handle_leave(void *data, wl_surface *, wl_output *wl_output)
static void gwl_window_frame_pending_fractional_scale_set_notest(GWL_Window *win, bool *r_surface_needs_commit, bool *r_surface_needs_buffer_scale)
static CLG_LogRef LOG_WL_XDG_TOPLEVEL_DECORATION
static void gwl_window_frame_update_from_pending_no_lock(GWL_Window *win)
static int gwl_window_fractional_from_viewport(const GWL_WindowFrame &frame, const int value)
static bool gwl_window_viewport_unset(GWL_Window *win, bool *r_surface_needs_commit, bool *r_surface_needs_buffer_scale)
static GHOST_TWindowState gwl_window_state_get(const GWL_Window *win)
static void xdg_toplevel_handle_configure(void *data, xdg_toplevel *, const int32_t width, const int32_t height, wl_array *states)
static CLG_LogRef LOG_WL_XDG_SURFACE
static void gwl_window_frame_pending_fractional_scale_set(GWL_Window *win, bool *r_surface_needs_commit, bool *r_surface_needs_buffer_scale)
static void xdg_surface_handle_configure(void *data, xdg_surface *xdg_surface, const uint32_t serial)
static int gwl_window_fractional_to_viewport_round(const GWL_WindowFrame &frame, const int value)
static void gwl_window_frame_update_from_pending(GWL_Window *win)
static const wp_fractional_scale_v1_listener wp_fractional_scale_listener
static CLG_LogRef LOG_WL_SURFACE
static const xdg_toplevel_listener xdg_toplevel_listener
static const zxdg_toplevel_decoration_v1_listener xdg_toplevel_decoration_v1_listener
static GHOST_TSuccess gwl_window_cursor_custom_load(const GHOST_CursorGenerator &cg, GHOST_SystemWayland *system)
int gwl_window_scale_int_to(const GWL_WindowScaleParams &scale_params, const int value)
static bool gwl_window_state_set(GWL_Window *win, const GHOST_TWindowState state)
static void gwl_window_frame_pending_size_set(GWL_Window *win, bool *r_surface_needs_commit, bool *r_surface_needs_resize_for_backend, bool *r_surface_needs_buffer_scale)
static bool gwl_window_state_set_for_xdg(xdg_toplevel *toplevel, const GHOST_TWindowState state, const GHOST_TWindowState state_current)
static int outputs_uniform_scale_or_default(const std::vector< GWL_Output * > &outputs, const int32_t scale_default, int *r_scale_fractional)
static void gwl_xdg_decor_window_destroy(GWL_XDG_Decor_Window *decor)
static CLG_LogRef LOG_WL_FRACTIONAL_SCALE
static void gwl_window_activate(GWL_Window *win)
static void gwl_window_resize_for_backend(GWL_Window *win, const int32_t size[2])
static int outputs_max_scale_or_default(const std::vector< GWL_Output * > &outputs, const int32_t scale_default, int *r_scale_fractional)
static constexpr size_t base_dpi
static void gwl_window_pending_actions_handle(GWL_Window *win)
static const xdg_surface_listener xdg_surface_listener
static int gwl_window_fractional_from_viewport_round(const GWL_WindowFrame &frame, const int value)
static int output_scale_cmp(const GWL_Output *output_a, const GWL_Output *output_b)
static void gwl_round_int_by(int *value_p, const int round_value)
static CLG_LogRef LOG_WL_XDG_TOPLEVEL
static bool gwl_window_viewport_size_update(GWL_Window *win)
static void xdg_toplevel_handle_configure_bounds(void *data, xdg_toplevel *, const int32_t width, const int32_t height)
static void xdg_activation_handle_done(void *data, xdg_activation_token_v1 *xdg_activation_token_v1, const char *token)
static const xdg_activation_token_v1_listener xdg_activation_listener
static void xdg_toplevel_handle_wm_capabilities(void *, xdg_toplevel *, wl_array *)
static void gwl_window_pending_actions_tag(GWL_Window *win, enum eGWL_PendingWindowActions type)
static void surface_handle_enter(void *data, wl_surface *, wl_output *wl_output)
int gwl_window_scale_int_from(const GWL_WindowScaleParams &scale_params, const int value)
static int gwl_window_fractional_to_viewport(const GWL_WindowFrame &frame, const int value)
static bool gwl_window_viewport_set(GWL_Window *win, bool *r_surface_needs_commit, bool *r_surface_needs_buffer_scale)
static void gwl_window_cursor_custom_free(GHOST_CursorGenerator *cg)
static void gwl_window_title_set(GWL_Window *win, const char *title)
static void xdg_toplevel_decoration_handle_configure(void *data, zxdg_toplevel_decoration_v1 *, const uint32_t mode)
static const xdg_activation_token_v1_listener * xdg_activation_listener_get()
static const wl_surface_listener wl_surface_listener
static void xdg_toplevel_handle_close(void *data, xdg_toplevel *)
BMesh const char void * data
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
static const char * xdg_app_id_get()
uint64_t getMilliSeconds() const override
std::thread::id main_thread_id
struct wl_display * wl_display_get()
struct wp_fractional_scale_manager_v1 * wp_fractional_scale_manager_get()
GHOST_TSuccess cursor_shape_set(GHOST_TStandardCursor shape)
struct wp_viewporter * wp_viewporter_get()
struct wl_seat * wl_seat_active_get_with_input_serial(uint32_t &serial)
GHOST_TSuccess cursor_shape_custom_set(const GHOST_CursorGenerator &cg)
std::atomic< bool > has_pending_actions_for_window
std::mutex * server_mutex
struct xdg_activation_v1 * xdg_activation_manager_get()
GHOST_WindowManager * getWindowManager() const
GHOST_TSuccess pushEvent(const GHOST_IEvent *event)
GHOST_IWindow * getActiveWindow() const
const struct GWL_WindowScaleParams & scale_params_get() const
GHOST_TSuccess setClientSize(uint32_t width, uint32_t height) override
bool outputs_leave(GWL_Output *output)
GHOST_TSuccess setClientWidth(uint32_t width) override
wl_fixed_t wl_fixed_to_window(wl_fixed_t value) const
GHOST_TSuccess setOrder(GHOST_TWindowOrder order) override
GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode) override
GHOST_TSuccess notify_size()
GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor cursor_shape) override
void outputs_changed_update_scale_tag()
GHOST_TSuccess setState(GHOST_TWindowState state) override
GHOST_TSuccess setWindowCursorVisibility(bool visible) override
GHOST_WindowWayland(GHOST_SystemWayland *system, const char *title, int32_t left, int32_t top, uint32_t width, uint32_t height, GHOST_TWindowState state, const GHOST_IWindow *parent_window, GHOST_TDrawingContextType type, const bool is_dialog, const GHOST_ContextParams &context_params, const bool exclusive, const GHOST_GPUDevice &preferred_device)
void pending_actions_handle()
GHOST_TWindowState getState() const override
bool getCursorGrabUseSoftwareDisplay() override
bool isDialog() const override
struct wl_surface * wl_surface_get() const
GHOST_TSuccess notify_decor_redraw()
bool getValid() const override
wl_fixed_t wl_fixed_from_window(wl_fixed_t value) const
std::string getTitle() const override
GHOST_TSuccess deactivate()
bool outputs_changed_update_scale()
void getClientBounds(GHOST_Rect &bounds) const override
GHOST_TSuccess activate()
uint16_t getDPIHint() override
void clientToScreen(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const override
GHOST_TSuccess swapBufferRelease() override
GHOST_TSuccess setClientHeight(uint32_t height) override
GHOST_TSuccess cursor_shape_refresh()
void screenToClient(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const override
bool outputs_enter(GWL_Output *output)
GHOST_TSuccess setWindowCustomCursorShape(const uint8_t *bitmap, const uint8_t *mask, const int size[2], const int hot_spot[2], bool can_invert_color) override
~GHOST_WindowWayland() override
GHOST_TSuccess invalidate() override
GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape) override
GHOST_TSuccess setWindowCustomCursorGenerator(GHOST_CursorGenerator *cursor_generator) override
void setTitle(const char *title) override
void getWindowBounds(GHOST_Rect &bounds) const override
GHOST_TSuccess getCursorBitmap(GHOST_CursorBitmapRef *bitmap) override
const std::vector< GWL_Output * > & outputs_get()
GHOST_ContextParams want_context_params_
GHOST_TSuccess swapBufferRelease() override
GHOST_TStandardCursor cursor_shape_
GHOST_TAxisFlag cursor_grab_axis_
GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds) const override
GHOST_TStandardCursor getCursorShape() const override
GHOST_TSuccess setDrawingContextType(GHOST_TDrawingContextType type) override
int32_t cursor_grab_init_pos_[2]
GHOST_TSuccess setSwapInterval(int interval) override
GHOST_TSuccess releaseNativeHandles()
bool getValid() const override
GHOST_Window(uint32_t width, uint32_t height, GHOST_TWindowState state, const GHOST_ContextParams &context_params, const bool exclusive=false)
GHOST_WindowHDRInfo hdr_info_
GHOST_TGrabCursorMode cursor_grab_
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
int context(const bContext *C, const char *member, bContextDataResult *result)
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
static blender::bke::bNodeSocketTemplate outputs[]
void(* free_fn)(struct GHOST_CursorGenerator *cursor_generator)
bool has_scale_fractional
int fractional_scale_preferred
GHOST_SystemWayland * ghost_system
std::atomic< bool > pending_actions[PENDING_NUM]
wp_fractional_scale_v1 * fractional_scale_handle
GWL_XDG_Decor_Window * xdg_decor
GWL_WindowScaleParams scale_params
struct GWL_Window::@211324370331073216033106070037277062312046022064 wp
xdg_activation_token_v1 * activation_token
std::mutex frame_pending_mutex
struct GWL_Window::@226144076170122005126305352224000061130331357311 wl
GWL_WindowFrame frame_pending
struct GWL_Window::@052270163354376334004337043250357320164157112151 backend
GHOST_WindowWayland * ghost_window
struct GWL_Window::@040024232136114172255107327327361000017072123125 xdg
GHOST_CursorGenerator * cursor_generator
std::vector< GWL_Output * > outputs
GHOST_TDrawingContextType ghost_context_type
zxdg_toplevel_decoration_v1 * toplevel_decor
struct GWL_XDG_Decor_Window::@000320341361074024320003302145125362246371366227 pending
uint32_t ack_configure_serial
enum zxdg_toplevel_decoration_v1_mode mode
bool initial_configure_seen
#define wl_display_dispatch_pending(...)
#define wl_display_dispatch(...)
#define wl_display_flush(...)
#define wl_display_roundtrip(...)
#define wl_egl_window_resize(...)
#define wl_egl_window_create(...)
#define wl_egl_window_destroy(...)
#define libdecor_frame_set_fullscreen(...)
#define libdecor_frame_map(...)
#define libdecor_state_new(...)
#define libdecor_frame_unset_fullscreen(...)
#define libdecor_configuration_get_content_size(...)
#define libdecor_state_free(...)
#define libdecor_configuration_get_window_state(...)
#define libdecor_frame_unref(...)
#define libdecor_frame_unset_maximized(...)
#define libdecor_frame_get_xdg_toplevel(...)
#define libdecor_frame_set_app_id(...)
#define libdecor_frame_set_min_content_size(...)
#define libdecor_frame_set_parent(...)
#define libdecor_frame_set_title(...)
#define libdecor_frame_set_minimized(...)
#define libdecor_frame_commit(...)
#define libdecor_decorate(...)
#define libdecor_frame_set_maximized(...)