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;
309 const uint8_t *bitmap,
313 bool can_invert_color)
317 const size_t bitmap_size =
sizeof(uint8_t) * ((
size[0] + 7) / 8) *
size[1];
320 ccs.
bitmap =
static_cast<uint8_t *
>(malloc(bitmap_size));
321 memcpy(ccs.
bitmap, bitmap, bitmap_size);
324 ccs.
mask =
static_cast<uint8_t *
>(malloc(bitmap_size));
325 memcpy(ccs.
mask,
mask, bitmap_size);
353#ifdef USE_EVENT_BACKGROUND_THREAD
376#ifdef USE_EVENT_BACKGROUND_THREAD
413# define PENDING_NUM (PENDING_WINDOW_CURSOR_SHAPE_REFRESH + 1)
467#ifdef WITH_OPENGL_BACKEND
468 wl_egl_window *egl_window =
nullptr;
470#ifdef WITH_VULKAN_BACKEND
487#ifdef WITH_GHOST_WAYLAND_LIBDECOR
488 GWL_LibDecor_Window *libdecor =
nullptr;
499#ifdef USE_EVENT_BACKGROUND_THREAD
522#ifdef USE_EVENT_BACKGROUND_THREAD
533#ifdef WITH_OPENGL_BACKEND
541#ifdef WITH_VULKAN_BACKEND
543 win->
backend.vulkan_window_info->size[0] =
size[0];
544 win->
backend.vulkan_window_info->size[1] =
size[1];
551#ifdef WITH_GHOST_WAYLAND_LIBDECOR
553 GWL_LibDecor_Window &decor = *win->libdecor;
560 xdg_toplevel_set_title(decor.
toplevel, title);
577#ifdef WITH_GHOST_WAYLAND_LIBDECOR
581static bool gwl_window_state_set_for_libdecor(libdecor_frame *frame,
588 switch (state_current) {
630 switch (state_current) {
632 xdg_toplevel_unset_maximized(toplevel);
636 xdg_toplevel_unset_fullscreen(toplevel);
645 xdg_toplevel_set_maximized(toplevel);
649 xdg_toplevel_set_minimized(toplevel);
653 xdg_toplevel_set_fullscreen(toplevel,
nullptr);
664#ifdef WITH_GHOST_WAYLAND_LIBDECOR
666 result = gwl_window_state_set_for_libdecor(win->libdecor->
frame,
state, state_current);
722 bool *r_surface_needs_commit,
723 bool *r_surface_needs_buffer_scale)
729 if (viewporter ==
nullptr) {
741 if (r_surface_needs_buffer_scale) {
742 *r_surface_needs_buffer_scale =
true;
748 if (r_surface_needs_commit) {
749 *r_surface_needs_commit =
true;
760 bool *r_surface_needs_commit,
761 bool *r_surface_needs_buffer_scale)
774 if (r_surface_needs_buffer_scale) {
775 *r_surface_needs_buffer_scale =
true;
781 if (r_surface_needs_commit) {
782 *r_surface_needs_commit =
true;
800 wp_viewport_set_destination(
823 if (
UNLIKELY(activation_manager ==
nullptr)) {
833 xdg_activation_token_v1_add_listener(
852 if (ghost_window_active) {
870 GWL_Window *win,
bool *r_surface_needs_commit,
bool *r_surface_needs_buffer_scale)
883 if (r_surface_needs_buffer_scale) {
884 *r_surface_needs_buffer_scale =
true;
889 if (r_surface_needs_commit) {
890 *r_surface_needs_commit =
true;
900 bool *r_surface_needs_commit,
901 bool *r_surface_needs_buffer_scale)
909 win, r_surface_needs_commit, r_surface_needs_buffer_scale);
913 bool *r_surface_needs_commit,
914 bool *r_surface_needs_resize_for_backend,
915 bool *r_surface_needs_buffer_scale)
928 win, r_surface_needs_commit, r_surface_needs_buffer_scale);
934 if (r_surface_needs_resize_for_backend) {
935 *r_surface_needs_resize_for_backend =
true;
949#ifdef USE_EVENT_BACKGROUND_THREAD
998#ifdef USE_EVENT_BACKGROUND_THREAD
1000 "Only from main thread!");
1005 bool surface_needs_commit =
false;
1006 bool surface_needs_resize_for_backend =
false;
1007 bool surface_needs_buffer_scale =
false;
1014 &surface_needs_commit,
1015 &surface_needs_resize_for_backend,
1016 &surface_needs_buffer_scale);
1022 win, &surface_needs_commit, &surface_needs_buffer_scale);
1027 surface_needs_buffer_scale =
true;
1031 if (surface_needs_resize_for_backend) {
1035 if (surface_needs_buffer_scale) {
1039#ifdef WITH_GHOST_WAYLAND_LIBDECOR
1041 GWL_LibDecor_Window &decor = *win->libdecor;
1042 if (decor.pending.ack_configure) {
1043 surface_needs_commit =
true;
1045 decor.pending.ack_configure =
false;
1049# ifdef USE_LIBDECOR_CONFIG_COPY_QUEUE
1050 GHOST_ASSERT(decor.pending.size[0] != 0 && decor.pending.size[1] != 0,
"Invalid size");
1051 for (libdecor_configuration *configuration : decor.pending.configuration_queue) {
1053 ghost_wl_libdecor_configuration_free(configuration);
1055 decor.pending.configuration_queue.clear();
1062 decor.pending.size[0] = 0;
1063 decor.pending.size[1] = 0;
1065 if (decor.initial_configure_seen ==
false) {
1066 decor.initial_configure_seen =
true;
1068 if (decor.initial_configure_state) {
1072 decor.initial_configure_state = std::nullopt;
1076# ifdef USE_LIBDECOR_CONFIG_COPY_WORKAROUND
1077 if (decor.pending.configuration_needs_free) {
1078 ghost_wl_libdecor_configuration_free(decor.pending.configuration);
1079 decor.pending.configuration_needs_free =
false;
1083 decor.pending.configuration =
nullptr;
1094 surface_needs_commit =
true;
1103 if (surface_needs_commit) {
1104#ifdef USE_EVENT_BACKGROUND_THREAD
1132 "GHOST internal active state does not match WAYLAND!");
1147#ifdef USE_EVENT_BACKGROUND_THREAD
1177 if (scale_fractional_a < scale_fractional_b) {
1180 if (scale_fractional_a > scale_fractional_b) {
1189 int *r_scale_fractional)
1194 output_max = reg_output;
1199 if (r_scale_fractional) {
1204 return output_max->
scale;
1206 if (r_scale_fractional) {
1209 return scale_default;
1214 int *r_scale_fractional)
1218 if (!output_uniform) {
1219 output_uniform = reg_output;
1223 output_uniform =
nullptr;
1228 if (output_uniform) {
1229 if (r_scale_fractional) {
1234 return output_uniform->
scale;
1236 if (r_scale_fractional) {
1239 return scale_default;
1250#ifdef USE_LIBDECOR_CONFIG_COPY_WORKAROUND
1252static libdecor_configuration *ghost_wl_libdecor_configuration_copy(
1253 const libdecor_configuration *configuration)
1255 size_t configuration_size = malloc_usable_size((
void *)configuration);
1256 libdecor_configuration *configuration_copy = (libdecor_configuration *)malloc(
1257 configuration_size);
1258 memcpy((
void *)configuration_copy, (
const void *)configuration, configuration_size);
1259 return configuration_copy;
1262static void ghost_wl_libdecor_configuration_free(libdecor_configuration *configuration)
1264 free((
void *)configuration);
1276#define LOG (&LOG_WL_XDG_TOPLEVEL)
1285 CLOG_INFO(
LOG, 2,
"configure (size=[%d, %d])", width, height);
1289#ifdef USE_EVENT_BACKGROUND_THREAD
1294 for (
int i = 0;
i < 2;
i++) {
1308 enum xdg_toplevel_state *
state;
1311 case XDG_TOPLEVEL_STATE_MAXIMIZED:
1314 case XDG_TOPLEVEL_STATE_FULLSCREEN:
1317 case XDG_TOPLEVEL_STATE_ACTIVATED:
1341 CLOG_INFO(
LOG, 2,
"configure_bounds (size=[%d, %d])", width, height);
1379 xdg_activation_token_v1 *xdg_activation_token_v1,
1389 xdg_activation_v1_activate(activation_manager, token, win->
wl.
surface);
1412#define LOG (&LOG_WL_FRACTIONAL_SCALE)
1415 void *
data, wp_fractional_scale_v1 * ,
uint preferred_scale)
1417#ifdef USE_EVENT_BACKGROUND_THREAD
1418 std::lock_guard lock_frame_guard{
static_cast<GWL_Window *
>(
data)->frame_pending_mutex};
1422 "preferred_scale (preferred_scale=%.6f)",
1445#ifdef WITH_GHOST_WAYLAND_LIBDECOR
1447static CLG_LogRef LOG_WL_LIBDECOR_FRAME = {
"ghost.wl.handle.libdecor_frame"};
1448# define LOG (&LOG_WL_LIBDECOR_FRAME)
1450static void libdecor_frame_handle_configure(libdecor_frame *frame,
1451 libdecor_configuration *configuration,
1456# ifdef USE_EVENT_BACKGROUND_THREAD
1457 std::lock_guard lock_frame_guard{
static_cast<GWL_Window *
>(
data)->frame_pending_mutex};
1458 const bool is_main_thread = [
data] {
1468 int size_next[2] = {0, 0};
1477 "Fractional scale has no fractional component!");
1482 win->frame.buffer_scale;
1485 configuration, frame, &size_next[0], &size_next[1]))
1487 if (fractional_scale) {
1494 frame_pending.
size[0] = ((size_next[0] *
scale) * fractional_scale) / scale_as_fractional;
1495 frame_pending.
size[1] = ((size_next[1] *
scale) * fractional_scale) / scale_as_fractional;
1498 frame_pending.
size[0] = size_next[0] *
scale;
1499 frame_pending.
size[1] = size_next[1] *
scale;
1510 const GWL_LibDecor_Window &decor = *win->libdecor;
1511 size_next[0] = decor.pending.size[0];
1512 size_next[1] = decor.pending.size[1];
1518 enum libdecor_window_state window_state;
1520 frame_pending.
is_maximised = window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED;
1521 frame_pending.
is_fullscreen = window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN;
1522 frame_pending.
is_active = window_state & LIBDECOR_WINDOW_STATE_ACTIVE;
1528 GWL_LibDecor_Window &decor = *win->libdecor;
1530# ifdef USE_LIBDECOR_CONFIG_COPY_WORKAROUND
1532 if (decor.pending.configuration_needs_free) {
1533 ghost_wl_libdecor_configuration_free(decor.pending.configuration);
1534 decor.pending.configuration_needs_free =
false;
1538 decor.pending.size[0] = size_next[0];
1539 decor.pending.size[1] = size_next[1];
1540 decor.pending.configuration = configuration;
1541 decor.pending.ack_configure =
true;
1543# ifdef USE_EVENT_BACKGROUND_THREAD
1544 if (!is_main_thread) {
1545# ifdef USE_LIBDECOR_CONFIG_COPY_WORKAROUND
1546 decor.pending.configuration = ghost_wl_libdecor_configuration_copy(configuration);
1547 decor.pending.configuration_needs_free =
true;
1551 decor.pending.configuration =
nullptr;
1556# ifdef USE_LIBDECOR_CONFIG_COPY_QUEUE
1557 if (!(size_next[0] && size_next[1])) {
1559 if (decor.pending.configuration_needs_free ==
false) {
1560 decor.pending.configuration = ghost_wl_libdecor_configuration_copy(
1561 decor.pending.configuration);
1562 decor.pending.configuration_needs_free =
true;
1565 decor.pending.configuration_queue.push_back(decor.pending.configuration);
1566 decor.pending.configuration =
nullptr;
1567 decor.pending.configuration_needs_free =
false;
1569 decor.pending.ack_configure =
false;
1577# ifdef USE_EVENT_BACKGROUND_THREAD
1578 if (!is_main_thread) {
1589static void libdecor_frame_handle_close(libdecor_frame * ,
void *
data)
1598static void libdecor_frame_handle_commit(libdecor_frame * ,
void *
data)
1611static libdecor_frame_interface libdecor_frame_iface = {
1612 libdecor_frame_handle_configure,
1613 libdecor_frame_handle_close,
1614 libdecor_frame_handle_commit,
1628#define LOG (&LOG_WL_XDG_TOPLEVEL_DECORATION)
1631 void *
data, zxdg_toplevel_decoration_v1 * ,
const uint32_t mode)
1637 win->
xdg_decor->
mode = (zxdg_toplevel_decoration_v1_mode)mode;
1653#define LOG (&LOG_WL_XDG_SURFACE)
1656 xdg_surface *xdg_surface,
1657 const uint32_t serial)
1667#ifdef USE_EVENT_BACKGROUND_THREAD
1668 std::lock_guard lock_frame_guard{
static_cast<GWL_Window *
>(
data)->frame_pending_mutex};
1673#ifdef USE_EVENT_BACKGROUND_THREAD
1675 const bool is_main_thread = system->
main_thread_id == std::this_thread::get_id();
1676 if (!is_main_thread) {
1701#define LOG (&LOG_WL_SURFACE)
1733#if defined(WL_SURFACE_PREFERRED_BUFFER_SCALE_SINCE_VERSION) && \
1734 defined(WL_SURFACE_PREFERRED_BUFFER_TRANSFORM_SINCE_VERSION)
1735static void surface_handle_preferred_buffer_scale(
void * ,
1740 CLOG_INFO(
LOG, 2,
"handle_preferred_buffer_scale (factor=%d)", factor);
1743static void surface_handle_preferred_buffer_transform(
void * ,
1756#if defined(WL_SURFACE_PREFERRED_BUFFER_SCALE_SINCE_VERSION) && \
1757 defined(WL_SURFACE_PREFERRED_BUFFER_TRANSFORM_SINCE_VERSION)
1758 surface_handle_preferred_buffer_scale,
1759 surface_handle_preferred_buffer_transform,
1777 const uint32_t width,
1778 const uint32_t height,
1782 const bool is_dialog,
1783 const bool stereoVisual,
1784 const bool exclusive,
1785 const bool is_debug,
1790 is_debug_context_(is_debug),
1791 preferred_device_(preferred_device)
1793#ifdef USE_EVENT_BACKGROUND_THREAD
1794 std::lock_guard lock_server_guard{*system->
server_mutex};
1797 window_->ghost_window =
this;
1798 window_->ghost_system = system;
1799 window_->ghost_context_type = type;
1820 int scale_fractional_from_output;
1822 system_->outputs_get(), 0, &scale_fractional_from_output);
1824 window_->frame.size[0] =
int32_t(width);
1825 window_->frame.size[1] =
int32_t(height);
1827 window_->is_dialog = is_dialog;
1830 window_->wl.surface = wl_compositor_create_surface(system_->wl_compositor_get());
1835 wp_fractional_scale_manager_v1 *fractional_scale_manager =
1837 if (fractional_scale_manager) {
1838 window_->wp.fractional_scale_handle = wp_fractional_scale_manager_v1_get_fractional_scale(
1839 fractional_scale_manager, window_->wl.surface);
1840 wp_fractional_scale_v1_add_listener(
1848 const int32_t size_min[2] = {320, 240};
1852#ifdef WITH_GHOST_WAYLAND_LIBDECOR
1854 window_->libdecor =
new GWL_LibDecor_Window;
1855 GWL_LibDecor_Window &decor = *window_->libdecor;
1859 system_->libdecor_context_get(), window_->wl.surface, &libdecor_frame_iface, window_);
1865 GWL_LibDecor_Window &decor_parent =
1875 decor.
surface = xdg_wm_base_get_xdg_surface(system_->xdg_decor_shell_get(),
1876 window_->wl.surface);
1880 xdg_toplevel_set_app_id(decor.
toplevel, xdg_app_id);
1885 if (parentWindow && is_dialog) {
1894#ifdef WITH_GHOST_WAYLAND_LIBDECOR
1902 wl_surface_set_user_data(window_->wl.surface,
this);
1908#ifdef WITH_GHOST_WAYLAND_LIBDECOR
1917 if (system_->xdg_decor_manager_get()) {
1918 decor.
toplevel_decor = zxdg_decoration_manager_v1_get_toplevel_decoration(
1919 system_->xdg_decor_manager_get(), decor.
toplevel);
1920 zxdg_toplevel_decoration_v1_add_listener(
1923 ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
1927 wl_surface_commit(window_->wl.surface);
1938 int early_buffer_scale = 0;
1939 int early_fractional_scale = 0;
1941 if (
const int test_fractional_scale =
1942 fractional_scale_manager ? (window_->frame_pending.fractional_scale_preferred ?
1943 window_->frame_pending.fractional_scale_preferred :
1944 scale_fractional_from_output) :
1948 early_fractional_scale = test_fractional_scale;
1953 early_fractional_scale = 0;
1956 else if (buffer_scale_from_output) {
1957 early_buffer_scale = buffer_scale_from_output;
1960 if (early_fractional_scale != 0) {
1963 window_->frame.fractional_scale_preferred = early_fractional_scale;
1964 window_->frame.fractional_scale = early_fractional_scale;
1965 window_->frame.buffer_scale = 1;
1967 window_->frame_pending.fractional_scale_preferred = early_fractional_scale;
1968 window_->frame_pending.fractional_scale = early_fractional_scale;
1969 window_->frame_pending.buffer_scale = 1;
1972 window_->frame_pending.is_scale_init =
true;
1975 bool surface_needs_commit_dummy =
false, surface_needs_buffer_scale_dummy =
false;
1977 window_, &surface_needs_commit_dummy, &surface_needs_buffer_scale_dummy);
1979 else if (early_buffer_scale != 0) {
1983 window_->frame.buffer_scale = early_buffer_scale;
1984 window_->frame_pending.buffer_scale = early_buffer_scale;
1987 window_->frame_pending.is_scale_init =
true;
1995 window_->frame.buffer_scale = 1;
1996 window_->frame_pending.buffer_scale = 1;
1997 GHOST_ASSERT(window_->frame_pending.is_scale_init ==
false,
1998 "An initialized scale is not expected");
2001 if (window_->frame_pending.is_scale_init) {
2004 "Fractional scale was not properly initialized");
2007 wl_surface_set_buffer_scale(window_->wl.surface, window_->frame.buffer_scale);
2011#ifdef WITH_GHOST_WAYLAND_LIBDECOR
2020 window_->frame.size[0] = std::min(window_->frame.size[0],
2022 window_->frame.size[1] = std::min(window_->frame.size[1],
2031#ifdef WITH_OPENGL_BACKEND
2032 if (type == GHOST_kDrawingContextTypeOpenGL) {
2034 window_->wl.surface,
int(window_->frame.size[0]),
int(window_->frame.size[1]));
2037#ifdef WITH_VULKAN_BACKEND
2038 if (type == GHOST_kDrawingContextTypeVulkan) {
2040 window_->backend.vulkan_window_info->
size[0] = window_->frame.size[0];
2041 window_->backend.vulkan_window_info->size[1] = window_->frame.size[1];
2045#ifdef WITH_GHOST_WAYLAND_LIBDECOR
2046# ifdef WITH_VULKAN_BACKEND
2047 const bool libdecor_wait_for_window_init = (type == GHOST_kDrawingContextTypeVulkan);
2049 const bool libdecor_wait_for_window_init =
false;
2057 GHOST_PRINT(
"Failed to create drawing context" << std::endl);
2060 window_->is_valid_setup =
true;
2063 if (window_->is_valid_setup ==
false) {
2068#ifdef WITH_GHOST_WAYLAND_LIBDECOR
2069 if (use_libdecor && libdecor_wait_for_window_init)
2085 GWL_LibDecor_Window &decor = *window_->libdecor;
2086 decor.initial_configure_state =
state;
2088 else if (use_libdecor) {
2090 wl_surface_commit(window_->wl.surface);
2091 GWL_LibDecor_Window &decor = *window_->libdecor;
2134 wl_surface_commit(window_->wl.surface);
2136 window_->is_init =
true;
2144#ifdef USE_EVENT_BACKGROUND_THREAD
2145 std::lock_guard lock_server_guard{*system_->server_mutex};
2150#ifdef WITH_OPENGL_BACKEND
2151 if (window_->ghost_context_type == GHOST_kDrawingContextTypeOpenGL) {
2155#ifdef WITH_VULKAN_BACKEND
2156 if (window_->ghost_context_type == GHOST_kDrawingContextTypeVulkan) {
2157 delete window_->backend.vulkan_window_info;
2161 if (window_->xdg.activation_token) {
2162 xdg_activation_token_v1_destroy(window_->xdg.activation_token);
2163 window_->xdg.activation_token =
nullptr;
2166 if (window_->wp.fractional_scale_handle) {
2167 wp_fractional_scale_v1_destroy(window_->wp.fractional_scale_handle);
2168 window_->wp.fractional_scale_handle =
nullptr;
2171 if (window_->wp.viewport) {
2172 wp_viewport_destroy(window_->wp.viewport);
2173 window_->wp.viewport =
nullptr;
2176#ifdef WITH_GHOST_WAYLAND_LIBDECOR
2178 gwl_libdecor_window_destroy(window_->libdecor);
2188 system_->window_surface_unref(window_->wl.surface);
2190 wl_surface_destroy(window_->wl.surface);
2202#ifdef USE_EVENT_BACKGROUND_THREAD
2205 GHOST_ASSERT(system_->main_thread_id == std::this_thread::get_id(),
"Only from main thread!");
2212 return system_->cursor_shape_check(cursorShape);
2217#ifdef USE_EVENT_BACKGROUND_THREAD
2218 std::lock_guard lock_server_guard{*system_->server_mutex};
2230 if (system_->window_cursor_grab_set(mode,
2235 window_->wl.surface,
2236 this->scale_params_get()))
2245#ifdef USE_EVENT_BACKGROUND_THREAD
2246 std::lock_guard lock_server_guard{*system_->server_mutex};
2250 system_->getWindowManager()->getActiveWindow());
2264 wl_display *display = system_->wl_display_get();
2265#ifdef USE_CURSOR_IMMEDIATE_DISPATCH
2279 ok = system_->cursor_shape_check(shape);
2289#ifdef USE_EVENT_BACKGROUND_THREAD
2290 std::lock_guard lock_server_guard{*system_->server_mutex};
2292 return system_->cursor_grab_use_software_display_get(
m_cursorGrab);
2296 uint8_t *bitmap, uint8_t *
mask,
int sizex,
int sizey,
int hotX,
int hotY,
bool canInvertColor)
2298#ifdef USE_EVENT_BACKGROUND_THREAD
2299 std::lock_guard lock_server_guard{*system_->server_mutex};
2303 system_->getWindowManager()->getActiveWindow());
2305 const int32_t hot_spot[2] = {hotX, hotY};
2308 window_->cursor_custom_shape, bitmap,
mask,
size, hot_spot, canInvertColor);
2321 wl_display *display = system_->wl_display_get();
2324#ifdef USE_CURSOR_IMMEDIATE_DISPATCH
2338#ifdef USE_EVENT_BACKGROUND_THREAD
2339 std::lock_guard lock_server_guard{*system_->server_mutex};
2341 return system_->cursor_bitmap_get(bitmap);
2351#ifdef USE_EVENT_BACKGROUND_THREAD
2352 std::lock_guard lock_server_guard{*system_->server_mutex};
2360 return window_->title.empty() ?
"untitled" : window_->title;
2376 return setClientSize(width, uint32_t(window_->frame.size[1]));
2381 return setClientSize(uint32_t(window_->frame.size[0]), height);
2386#ifdef USE_EVENT_BACKGROUND_THREAD
2387 std::lock_guard lock_server_guard{*system_->server_mutex};
2388 std::lock_guard lock_frame_guard{window_->frame_pending_mutex};
2393 frame_pending.
size[0] = width;
2394 frame_pending.
size[1] = height;
2425 if (window_->frame.fractional_scale) {
2429 return window_->frame.buffer_scale *
base_dpi;
2434#ifdef USE_EVENT_BACKGROUND_THREAD
2435 std::lock_guard lock_server_guard{*system_->server_mutex};
2437 const GHOST_TSuccess ok = system_->cursor_visibility_set(visible);
2439 wl_display *display = system_->wl_display_get();
2442#ifdef USE_CURSOR_IMMEDIATE_DISPATCH
2451#ifdef USE_EVENT_BACKGROUND_THREAD
2452 std::lock_guard lock_server_guard{*system_->server_mutex};
2459#ifdef USE_EVENT_BACKGROUND_THREAD
2460 std::lock_guard lock_server_guard{*system_->server_mutex};
2485 return window_->is_dialog;
2496#ifdef WITH_VULKAN_BACKEND
2497 case GHOST_kDrawingContextTypeVulkan: {
2499 GHOST_kVulkanPlatformWayland,
2502 window_->wl.surface,
2503 system_->wl_display_get(),
2504 window_->backend.vulkan_window_info,
2509 if (
context->initializeDrawingContext()) {
2517#ifdef WITH_OPENGL_BACKEND
2518 case GHOST_kDrawingContextTypeOpenGL: {
2519 for (
int minor = 6; minor >= 3; --minor) {
2520 GHOST_Context *
context =
new GHOST_ContextEGL(
2523 EGLNativeWindowType(window_->backend.egl_window),
2524 EGLNativeDisplayType(system_->wl_display_get()),
2525 EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
2529 (is_debug_context_ ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0),
2533 if (
context->initializeDrawingContext()) {
2548#ifdef WITH_INPUT_IME
2552 system_->ime_begin(
this,
x,
y,
w, h, completed);
2555void GHOST_WindowWayland::endIME()
2557 system_->ime_end(
this);
2572 return window_->frame.buffer_scale;
2580 scale_params->
is_fractional = (window_->frame.fractional_scale != 0);
2581 scale_params->
scale = scale_params->
is_fractional ? window_->frame.fractional_scale :
2582 window_->frame.buffer_scale;
2583 return *scale_params;
2588 if (window_->frame.fractional_scale) {
2591 return value / window_->frame.buffer_scale;
2596 if (window_->frame.fractional_scale) {
2599 return value * window_->frame.buffer_scale;
2604 return window_->wl.surface;
2609 return window_->outputs;
2622 return system_->pushEvent_maybe_pending(
2628#ifdef USE_EVENT_BACKGROUND_THREAD
2629 const bool is_main_thread = system_->main_thread_id == std::this_thread::get_id();
2635 if (window_->is_init) {
2636 if (system_->getWindowManager()->setActiveWindow(
this) ==
GHOST_kFailure) {
2643#ifdef WITH_GHOST_WAYLAND_LIBDECOR
2656#ifdef USE_EVENT_BACKGROUND_THREAD
2658 const bool is_main_thread = system_->main_thread_id == std::this_thread::get_id();
2663 if (window_->is_init) {
2664 system_->getWindowManager()->setWindowInactive(
this);
2669#ifdef WITH_GHOST_WAYLAND_LIBDECOR
2682 return system_->pushEvent_maybe_pending(
2690 return system_->pushEvent_maybe_pending(
2704#ifdef USE_EVENT_BACKGROUND_THREAD
2705 if (system_->main_thread_id != std::this_thread::get_id()) {
2715#ifdef USE_EVENT_BACKGROUND_THREAD
2727#ifdef USE_EVENT_BACKGROUND_THREAD
2728 if (system_->main_thread_id != std::this_thread::get_id()) {
2733 int fractional_scale_next = -1;
2734 int fractional_scale_from_output = 0;
2742#ifdef USE_EVENT_BACKGROUND_THREAD
2743 std::lock_guard lock_frame_guard{window_->frame_pending_mutex};
2746 if (window_->wp.fractional_scale_handle) {
2749 if (window_->frame_pending.fractional_scale_preferred != 0) {
2750 fractional_scale_next = window_->frame_pending.fractional_scale_preferred;
2755 if (fractional_scale_next == -1) {
2756 fractional_scale_next = fractional_scale_from_output;
2760 bool changed =
false;
2762 const bool is_fractional_prev = window_->frame.fractional_scale != 0;
2766 window_->frame_pending.fractional_scale = is_fractional_next ? fractional_scale_next : 0;
2767 window_->frame_pending.buffer_scale = is_fractional_next ?
2771 const int fractional_scale_prev = window_->frame.fractional_scale ?
2772 window_->frame.fractional_scale :
2777 bool do_frame_resize =
false;
2778 bool do_frame_update =
false;
2780 if (window_->frame_pending.is_scale_init ==
false) {
2781 window_->frame_pending.is_scale_init =
true;
2790#ifdef WITH_GHOST_WAYLAND_LIBDECOR
2799 int size_next[2] = {0, 0};
2800 int size_orig[2] = {0, 0};
2803 for (
size_t i = 0;
i <
ARRAY_SIZE(window_->frame_pending.size);
i++) {
2804 const int value = size_next[
i] ? window_->frame_pending.size[
i] : window_->frame.size[
i];
2805 size_orig[
i] = value;
2806 if (is_fractional_prev || is_fractional_next) {
2808 double(fractional_scale_next));
2811 size_next[
i] = value / scale_prev;
2813 if (window_->frame_pending.buffer_scale > 1) {
2818 if (size_orig[0] != size_next[0] || size_orig[1] != size_next[1]) {
2819 GWL_LibDecor_Window &decor = *window_->libdecor;
2827 do_frame_resize =
false;
2828 do_frame_update =
true;
2837 if (window_->frame_pending.buffer_scale != window_->frame.buffer_scale) {
2838 do_frame_resize =
true;
2843 if ((fractional_scale_prev != fractional_scale_next) ||
2844 (window_->frame_pending.buffer_scale != window_->frame.buffer_scale))
2846 do_frame_resize =
true;
2850 if (do_frame_resize) {
2857 for (
size_t i = 0;
i <
ARRAY_SIZE(window_->frame_pending.size);
i++) {
2858 const int value = window_->frame_pending.size[
i] ? window_->frame_pending.size[
i] :
2859 window_->frame.size[
i];
2860 if (is_fractional_prev || is_fractional_next) {
2861 window_->frame_pending.size[
i] = lroundf((value *
double(fractional_scale_next)) /
2862 double(fractional_scale_prev));
2865 window_->frame_pending.size[
i] = (value * scale_next) / scale_prev;
2867 if (window_->frame_pending.buffer_scale > 1) {
2868 gwl_round_int_by(&window_->frame_pending.size[
i], window_->frame_pending.buffer_scale);
2871 do_frame_update =
true;
2874 if (do_frame_update) {
2884 std::vector<GWL_Output *> &
outputs = window_->outputs;
2895 std::vector<GWL_Output *> &
outputs = window_->outputs;
2904#ifdef USE_EVENT_BACKGROUND_THREAD
2912 "Run from main thread!");
KDTree *BLI_kdtree_nd_ new(unsigned int nodes_len_capacity)
void BLI_kdtree_nd_ free(KDTree *tree)
#define CLOG_INFO(clg_ref, level,...)
#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)
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_round_int2_by(int value_p[2], const int round_value)
static int gwl_window_fractional_from_viewport(const GWL_WindowFrame &frame, int 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)
int gwl_window_scale_int_to(const GWL_WindowScaleParams &scale_params, int value)
static bool gwl_window_viewport_unset(GWL_Window *win, bool *r_surface_needs_commit, bool *r_surface_needs_buffer_scale)
static void gwl_window_cursor_custom_free(GWL_WindowCursorCustomShape &ccs)
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 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 GWL_WindowCursorCustomShape &ccs, GHOST_SystemWayland *system)
static bool gwl_window_state_set(GWL_Window *win, const GHOST_TWindowState state)
static GHOST_TSuccess gwl_window_cursor_shape_refresh(GHOST_TStandardCursor shape, const GWL_WindowCursorCustomShape &ccs, GHOST_SystemWayland *system)
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)
int gwl_window_scale_int_from(const GWL_WindowScaleParams &scale_params, int value)
static CLG_LogRef LOG_WL_FRACTIONAL_SCALE
static void xdg_toplevel_handle_configure_bounds(void *data, xdg_toplevel *, int32_t width, int32_t height)
static int gwl_window_fractional_to_viewport(const GWL_WindowFrame &frame, int value)
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_cursor_custom_clear(GWL_WindowCursorCustomShape &ccs)
static void gwl_window_pending_actions_handle(GWL_Window *win)
static const xdg_surface_listener xdg_surface_listener
static int gwl_window_fractional_to_viewport_round(const GWL_WindowFrame &frame, 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 void gwl_window_cursor_custom_store(GWL_WindowCursorCustomShape &ccs, const uint8_t *bitmap, const uint8_t *mask, const int32_t size[2], const int32_t hot_spot[2], bool can_invert_color)
static bool gwl_window_viewport_size_update(GWL_Window *win)
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)
static bool gwl_round_int_test(int value, const int round_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_title_set(GWL_Window *win, const char *title)
static int gwl_window_fractional_from_viewport_round(const GWL_WindowFrame &frame, int value)
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 uint8_t *bitmap, const uint8_t *mask, int sizex, int sizey, int hotX, int hotY, bool canInvertColor)
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
GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor cursorShape) override
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 swapBuffers() override
GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode) override
GHOST_TSuccess notify_size()
void outputs_changed_update_scale_tag()
GHOST_TSuccess setState(GHOST_TWindowState state) override
GHOST_TSuccess setWindowCursorVisibility(bool visible) override
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 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_WindowWayland() override
GHOST_TSuccess invalidate() override
GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape) override
void setTitle(const char *title) 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 *parentWindow, GHOST_TDrawingContextType type, const bool is_dialog, const bool stereoVisual, const bool exclusive, const bool is_debug, const GHOST_GPUDevice &preferred_device)
GHOST_TSuccess setWindowCustomCursorShape(uint8_t *bitmap, uint8_t *mask, int sizex, int sizey, int hotX, int hotY, bool canInvertColor) override
void getWindowBounds(GHOST_Rect &bounds) const override
GHOST_TSuccess getCursorBitmap(GHOST_CursorBitmapRef *bitmap) override
const std::vector< GWL_Output * > & outputs_get()
GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds) const override
GHOST_TGrabCursorMode m_cursorGrab
int32_t m_cursorGrabInitPos[2]
GHOST_TStandardCursor getCursorShape() const override
GHOST_TSuccess setDrawingContextType(GHOST_TDrawingContextType type) override
GHOST_TStandardCursor m_cursorShape
GHOST_TSuccess setSwapInterval(int interval) override
GHOST_TSuccess releaseNativeHandles()
GHOST_TAxisFlag m_cursorGrabAxis
bool getValid() const override
GHOST_TSuccess swapBuffers() override
GHOST_Window(uint32_t width, uint32_t height, GHOST_TWindowState state, const bool wantStereoVisual=false, const bool exclusive=false)
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[]
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::@134345167343032125222034242235331103322063140311 backend
struct GWL_Window::@346242015150140313046202031043322041261127307055 wp
xdg_activation_token_v1 * activation_token
std::mutex frame_pending_mutex
struct GWL_Window::@006172365347273206337304067023015006207271022251 xdg
GWL_WindowFrame frame_pending
struct GWL_Window::@170217342020275242231320302336126001265007324145 wl
GHOST_WindowWayland * ghost_window
GWL_WindowCursorCustomShape cursor_custom_shape
std::vector< GWL_Output * > outputs
GHOST_TDrawingContextType ghost_context_type
struct GWL_XDG_Decor_Window::@124026176340051024073126310177374306241061266214 pending
zxdg_toplevel_decoration_v1 * toplevel_decor
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(...)