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
diff options
context:
space:
mode:
Diffstat (limited to 'intern/ghost/intern/GHOST_WindowWayland.cpp')
-rw-r--r--intern/ghost/intern/GHOST_WindowWayland.cpp549
1 files changed, 325 insertions, 224 deletions
diff --git a/intern/ghost/intern/GHOST_WindowWayland.cpp b/intern/ghost/intern/GHOST_WindowWayland.cpp
index 5f3cb3e3f3a..9d62c69edef 100644
--- a/intern/ghost/intern/GHOST_WindowWayland.cpp
+++ b/intern/ghost/intern/GHOST_WindowWayland.cpp
@@ -31,15 +31,54 @@
# include <libdecor.h>
#endif
+/* Generated by `wayland-scanner`. */
+#include <xdg-decoration-unstable-v1-client-protocol.h>
+#include <xdg-shell-client-protocol.h>
+
/* Logging, use `ghost.wl.*` prefix. */
#include "CLG_log.h"
static constexpr size_t base_dpi = 96;
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+/* Access `use_libdecor` in #GHOST_SystemWayland. */
+# define use_libdecor GHOST_SystemWayland::use_libdecor_runtime()
+#endif
+
static GHOST_WindowManager *window_manager = nullptr;
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+struct WGL_LibDecor_Window {
+ struct libdecor_frame *frame = nullptr;
+ bool configured = false;
+};
+
+static void gwl_libdecor_window_destroy(WGL_LibDecor_Window *decor)
+{
+ libdecor_frame_unref(decor->frame);
+ delete decor;
+}
+#endif /* WITH_GHOST_WAYLAND_LIBDECOR */
+
+struct WGL_XDG_Decor_Window {
+ struct xdg_surface *surface = nullptr;
+ struct zxdg_toplevel_decoration_v1 *toplevel_decor = nullptr;
+ struct xdg_toplevel *toplevel = nullptr;
+ enum zxdg_toplevel_decoration_v1_mode mode = (enum zxdg_toplevel_decoration_v1_mode)0;
+};
+
+static void gwl_xdg_decor_window_destroy(WGL_XDG_Decor_Window *decor)
+{
+ if (decor->toplevel_decor) {
+ zxdg_toplevel_decoration_v1_destroy(decor->toplevel_decor);
+ }
+ xdg_toplevel_destroy(decor->toplevel);
+ xdg_surface_destroy(decor->surface);
+ delete decor;
+}
+
struct GWL_Window {
- GHOST_WindowWayland *w = nullptr;
+ GHOST_WindowWayland *ghost_window = nullptr;
struct wl_surface *wl_surface = nullptr;
/**
* Outputs on which the window is currently shown on.
@@ -52,23 +91,15 @@ struct GWL_Window {
/** The scale value written to #wl_surface_set_buffer_scale. */
int scale = 0;
/**
- * The DPI, either:
- * - `scale * base_dpi`
- * - `wl_fixed_to_int(scale_fractional * base_dpi)`
- * When fractional scaling is available.
+ * The fractional scale used to calculate the DPI.
+ * (always set, even when scaling is rounded to whole units).
*/
- uint32_t dpi = 0;
+ wl_fixed_t scale_fractional = 0;
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- struct libdecor_frame *decor_frame = nullptr;
- bool decor_configured = false;
-#else
- struct xdg_surface *xdg_surface = nullptr;
- struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration = nullptr;
- struct xdg_toplevel *xdg_toplevel = nullptr;
-
- enum zxdg_toplevel_decoration_v1_mode decoration_mode = (enum zxdg_toplevel_decoration_v1_mode)0;
+ WGL_LibDecor_Window *libdecor = nullptr;
#endif
+ WGL_XDG_Decor_Window *xdg_decor = nullptr;
wl_egl_window *egl_window = nullptr;
bool is_maximised = false;
@@ -114,7 +145,7 @@ static int output_scale_cmp(const GWL_Output *output_a, const GWL_Output *output
static int outputs_max_scale_or_default(const std::vector<GWL_Output *> &outputs,
const int32_t scale_default,
- uint32_t *r_dpi)
+ wl_fixed_t *r_scale_fractional)
{
const GWL_Output *output_max = nullptr;
for (const GWL_Output *reg_output : outputs) {
@@ -124,18 +155,16 @@ static int outputs_max_scale_or_default(const std::vector<GWL_Output *> &outputs
}
if (output_max) {
- if (r_dpi) {
- *r_dpi = output_max->has_scale_fractional ?
- /* Fractional DPI. */
- wl_fixed_to_int(output_max->scale_fractional * base_dpi) :
- /* Simple non-fractional DPI. */
- (output_max->scale * base_dpi);
+ if (r_scale_fractional) {
+ *r_scale_fractional = output_max->has_scale_fractional ?
+ output_max->scale_fractional :
+ wl_fixed_from_int(output_max->scale);
}
return output_max->scale;
}
- if (r_dpi) {
- *r_dpi = scale_default * base_dpi;
+ if (r_scale_fractional) {
+ *r_scale_fractional = wl_fixed_from_int(scale_default);
}
return scale_default;
}
@@ -146,10 +175,8 @@ static int outputs_max_scale_or_default(const std::vector<GWL_Output *> &outputs
/** \name Listener (XDG Top Level), #xdg_toplevel_listener
* \{ */
-#ifndef WITH_GHOST_WAYLAND_LIBDECOR
-
static CLG_LogRef LOG_WL_XDG_TOPLEVEL = {"ghost.wl.handle.xdg_toplevel"};
-# define LOG (&LOG_WL_XDG_TOPLEVEL)
+#define LOG (&LOG_WL_XDG_TOPLEVEL)
static void xdg_toplevel_handle_configure(void *data,
xdg_toplevel * /*xdg_toplevel*/,
@@ -189,17 +216,15 @@ static void xdg_toplevel_handle_configure(void *data,
static void xdg_toplevel_handle_close(void *data, xdg_toplevel * /*xdg_toplevel*/)
{
CLOG_INFO(LOG, 2, "close");
- static_cast<GWL_Window *>(data)->w->close();
+ static_cast<GWL_Window *>(data)->ghost_window->close();
}
-static const xdg_toplevel_listener toplevel_listener = {
+static const xdg_toplevel_listener xdg_toplevel_listener = {
xdg_toplevel_handle_configure,
xdg_toplevel_handle_close,
};
-# undef LOG
-
-#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
+#undef LOG
/** \} */
@@ -234,7 +259,7 @@ static void frame_handle_configure(struct libdecor_frame *frame,
win->size[1] = win->scale * size_next[1];
wl_egl_window_resize(win->egl_window, UNPACK2(win->size), 0, 0);
- win->w->notify_size();
+ win->ghost_window->notify_size();
if (!libdecor_configuration_get_window_state(configuration, &window_state)) {
window_state = LIBDECOR_WINDOW_STATE_NONE;
@@ -244,20 +269,20 @@ static void frame_handle_configure(struct libdecor_frame *frame,
win->is_fullscreen = window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN;
win->is_active = window_state & LIBDECOR_WINDOW_STATE_ACTIVE;
- win->is_active ? win->w->activate() : win->w->deactivate();
+ win->is_active ? win->ghost_window->activate() : win->ghost_window->deactivate();
state = libdecor_state_new(UNPACK2(size_next));
libdecor_frame_commit(frame, state, configuration);
libdecor_state_free(state);
- win->decor_configured = true;
+ win->libdecor->configured = true;
}
static void frame_handle_close(struct libdecor_frame * /*frame*/, void *data)
{
CLOG_INFO(LOG, 2, "close");
- static_cast<GWL_Window *>(data)->w->close();
+ static_cast<GWL_Window *>(data)->ghost_window->close();
}
static void frame_handle_commit(struct libdecor_frame * /*frame*/, void *data)
@@ -265,8 +290,8 @@ static void frame_handle_commit(struct libdecor_frame * /*frame*/, void *data)
CLOG_INFO(LOG, 2, "commit");
/* We have to swap twice to keep any pop-up menus alive. */
- static_cast<GWL_Window *>(data)->w->swapBuffers();
- static_cast<GWL_Window *>(data)->w->swapBuffers();
+ static_cast<GWL_Window *>(data)->ghost_window->swapBuffers();
+ static_cast<GWL_Window *>(data)->ghost_window->swapBuffers();
}
static struct libdecor_frame_interface libdecor_frame_iface = {
@@ -285,10 +310,8 @@ static struct libdecor_frame_interface libdecor_frame_iface = {
/** \name Listener (XDG Decoration Listener), #zxdg_toplevel_decoration_v1_listener
* \{ */
-#ifndef WITH_GHOST_WAYLAND_LIBDECOR
-
static CLG_LogRef LOG_WL_XDG_TOPLEVEL_DECORATION = {"ghost.wl.handle.xdg_toplevel_decoration"};
-# define LOG (&LOG_WL_XDG_TOPLEVEL_DECORATION)
+#define LOG (&LOG_WL_XDG_TOPLEVEL_DECORATION)
static void xdg_toplevel_decoration_handle_configure(
void *data,
@@ -296,16 +319,14 @@ static void xdg_toplevel_decoration_handle_configure(
const uint32_t mode)
{
CLOG_INFO(LOG, 2, "configure (mode=%u)", mode);
- static_cast<GWL_Window *>(data)->decoration_mode = (zxdg_toplevel_decoration_v1_mode)mode;
+ static_cast<GWL_Window *>(data)->xdg_decor->mode = (zxdg_toplevel_decoration_v1_mode)mode;
}
-static const zxdg_toplevel_decoration_v1_listener toplevel_decoration_v1_listener = {
+static const zxdg_toplevel_decoration_v1_listener xdg_toplevel_decoration_v1_listener = {
xdg_toplevel_decoration_handle_configure,
};
-# undef LOG
-
-#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
+#undef LOG
/** \} */
@@ -313,10 +334,8 @@ static const zxdg_toplevel_decoration_v1_listener toplevel_decoration_v1_listene
/** \name Listener (XDG Surface Handle Configure), #xdg_surface_listener
* \{ */
-#ifndef WITH_GHOST_WAYLAND_LIBDECOR
-
static CLG_LogRef LOG_WL_XDG_SURFACE = {"ghost.wl.handle.xdg_surface"};
-# define LOG (&LOG_WL_XDG_SURFACE)
+#define LOG (&LOG_WL_XDG_SURFACE)
static void xdg_surface_handle_configure(void *data,
xdg_surface *xdg_surface,
@@ -324,7 +343,7 @@ static void xdg_surface_handle_configure(void *data,
{
GWL_Window *win = static_cast<GWL_Window *>(data);
- if (win->xdg_surface != xdg_surface) {
+ if (win->xdg_decor->surface != xdg_surface) {
CLOG_INFO(LOG, 2, "configure (skipped)");
return;
}
@@ -337,14 +356,14 @@ static void xdg_surface_handle_configure(void *data,
wl_egl_window_resize(win->egl_window, UNPACK2(win->size), 0, 0);
win->size_pending[0] = 0;
win->size_pending[1] = 0;
- win->w->notify_size();
+ win->ghost_window->notify_size();
}
if (win->is_active) {
- win->w->activate();
+ win->ghost_window->activate();
}
else {
- win->w->deactivate();
+ win->ghost_window->deactivate();
}
xdg_surface_ack_configure(xdg_surface, serial);
@@ -354,9 +373,7 @@ static const xdg_surface_listener xdg_surface_listener = {
xdg_surface_handle_configure,
};
-# undef LOG
-
-#endif /* !WITH_GHOST_WAYLAND_LIBDECOR. */
+#undef LOG
/** \} */
@@ -401,7 +418,7 @@ static void surface_handle_leave(void *data,
}
}
-static struct wl_surface_listener wl_surface_listener = {
+static const struct wl_surface_listener wl_surface_listener = {
surface_handle_enter,
surface_handle_leave,
};
@@ -418,7 +435,7 @@ static struct wl_surface_listener wl_surface_listener = {
GHOST_TSuccess GHOST_WindowWayland::hasCursorShape(GHOST_TStandardCursor cursorShape)
{
- return m_system->hasCursorShape(cursorShape);
+ return system_->hasCursorShape(cursorShape);
}
GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
@@ -434,20 +451,20 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
const bool stereoVisual,
const bool exclusive)
: GHOST_Window(width, height, state, stereoVisual, exclusive),
- m_system(system),
- w(new GWL_Window)
+ system_(system),
+ window_(new GWL_Window)
{
/* Globally store pointer to window manager. */
if (!window_manager) {
- window_manager = m_system->getWindowManager();
+ window_manager = system_->getWindowManager();
}
- w->w = this;
+ window_->ghost_window = this;
- w->size[0] = int32_t(width);
- w->size[1] = int32_t(height);
+ window_->size[0] = int32_t(width);
+ window_->size[1] = int32_t(height);
- w->is_dialog = is_dialog;
+ window_->is_dialog = is_dialog;
/* NOTE(@campbellbarton): The scale set here to avoid flickering on startup.
* When all monitors use the same scale (which is quite common) there aren't any problems.
@@ -458,75 +475,100 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
*
* Using the maximum scale is best as it results in the window first being smaller,
* avoiding a large window flashing before it's made smaller. */
- w->scale = outputs_max_scale_or_default(this->m_system->outputs(), 1, &w->dpi);
+ window_->scale = outputs_max_scale_or_default(system_->outputs(), 1, &window_->scale_fractional);
/* Window surfaces. */
- w->wl_surface = wl_compositor_create_surface(m_system->compositor());
- ghost_wl_surface_tag(w->wl_surface);
+ window_->wl_surface = wl_compositor_create_surface(system_->wl_compositor());
+ ghost_wl_surface_tag(window_->wl_surface);
- wl_surface_set_buffer_scale(w->wl_surface, w->scale);
+ wl_surface_set_buffer_scale(window_->wl_surface, window_->scale);
- wl_surface_add_listener(w->wl_surface, &wl_surface_listener, this);
+ wl_surface_add_listener(window_->wl_surface, &wl_surface_listener, window_);
- w->egl_window = wl_egl_window_create(w->wl_surface, int(w->size[0]), int(w->size[1]));
+ window_->egl_window = wl_egl_window_create(
+ window_->wl_surface, int(window_->size[0]), int(window_->size[1]));
/* NOTE: The limit is in points (not pixels) so Hi-DPI will limit to larger number of pixels.
* This has the advantage that the size limit is the same when moving the window between monitors
* with different scales set. If it was important to limit in pixels it could be re-calculated
- * when the `w->scale` changed. */
+ * when the `window_->scale` changed. */
const int32_t size_min[2] = {320, 240};
-#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- /* create window decorations */
- w->decor_frame = libdecor_decorate(
- m_system->decor_context(), w->wl_surface, &libdecor_frame_iface, w);
- libdecor_frame_map(w->decor_frame);
-
- libdecor_frame_set_min_content_size(w->decor_frame, UNPACK2(size_min));
-
- if (parentWindow) {
- libdecor_frame_set_parent(
- w->decor_frame, dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->decor_frame);
- }
-#else
- w->xdg_surface = xdg_wm_base_get_xdg_surface(m_system->xdg_shell(), w->wl_surface);
- w->xdg_toplevel = xdg_surface_get_toplevel(w->xdg_surface);
-
- xdg_toplevel_set_min_size(w->xdg_toplevel, UNPACK2(size_min));
+ /* This value is expected to match the base name of the `.desktop` file. see T101805.
+ *
+ * NOTE: the XDG desktop-entry-spec defines that this should follow the "reverse DNS" convention.
+ * For e.g. `org.blender.Blender` - however the `.desktop` file distributed with Blender is
+ * simply called `blender.desktop`, so the it's important to follow that name.
+ * Other distributions such as SNAP & FLATPAK may need to change this value T101779.
+ * Currently there isn't a way to configure this, we may want to support that. */
+ const char *xdg_app_id = "blender";
- if (m_system->xdg_decoration_manager()) {
- w->xdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
- m_system->xdg_decoration_manager(), w->xdg_toplevel);
- zxdg_toplevel_decoration_v1_add_listener(
- w->xdg_toplevel_decoration, &toplevel_decoration_v1_listener, w);
- zxdg_toplevel_decoration_v1_set_mode(w->xdg_toplevel_decoration,
- ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ if (use_libdecor) {
+ window_->libdecor = new WGL_LibDecor_Window;
+ WGL_LibDecor_Window &decor = *window_->libdecor;
+
+ /* create window decorations */
+ decor.frame = libdecor_decorate(
+ system_->libdecor_context(), window_->wl_surface, &libdecor_frame_iface, window_);
+ libdecor_frame_map(window_->libdecor->frame);
+
+ libdecor_frame_set_min_content_size(decor.frame, UNPACK2(size_min));
+ libdecor_frame_set_app_id(decor.frame, xdg_app_id);
+
+ if (parentWindow) {
+ WGL_LibDecor_Window &decor_parent =
+ *dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->window_->libdecor;
+ libdecor_frame_set_parent(decor.frame, decor_parent.frame);
+ }
}
+ else
+#endif
+ {
+ window_->xdg_decor = new WGL_XDG_Decor_Window;
+ WGL_XDG_Decor_Window &decor = *window_->xdg_decor;
+ decor.surface = xdg_wm_base_get_xdg_surface(system_->xdg_decor_shell(), window_->wl_surface);
+ decor.toplevel = xdg_surface_get_toplevel(decor.surface);
+
+ xdg_toplevel_set_min_size(decor.toplevel, UNPACK2(size_min));
+ xdg_toplevel_set_app_id(decor.toplevel, xdg_app_id);
+
+ if (system_->xdg_decor_manager()) {
+ decor.toplevel_decor = zxdg_decoration_manager_v1_get_toplevel_decoration(
+ system_->xdg_decor_manager(), decor.toplevel);
+ zxdg_toplevel_decoration_v1_add_listener(
+ decor.toplevel_decor, &xdg_toplevel_decoration_v1_listener, window_);
+ zxdg_toplevel_decoration_v1_set_mode(decor.toplevel_decor,
+ ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
+ }
- xdg_surface_add_listener(w->xdg_surface, &xdg_surface_listener, w);
- xdg_toplevel_add_listener(w->xdg_toplevel, &toplevel_listener, w);
+ xdg_surface_add_listener(decor.surface, &xdg_surface_listener, window_);
+ xdg_toplevel_add_listener(decor.toplevel, &xdg_toplevel_listener, window_);
- if (parentWindow && is_dialog) {
- xdg_toplevel_set_parent(
- w->xdg_toplevel, dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->w->xdg_toplevel);
+ if (parentWindow && is_dialog) {
+ WGL_XDG_Decor_Window &decor_parent =
+ *dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->window_->xdg_decor;
+ xdg_toplevel_set_parent(decor.toplevel, decor_parent.toplevel);
+ }
}
-#endif /* !WITH_GHOST_WAYLAND_LIBDECOR */
-
setTitle(title);
- wl_surface_set_user_data(w->wl_surface, this);
+ wl_surface_set_user_data(window_->wl_surface, this);
/* Call top-level callbacks. */
- wl_surface_commit(w->wl_surface);
- wl_display_roundtrip(m_system->display());
+ wl_surface_commit(window_->wl_surface);
+ wl_display_roundtrip(system_->wl_display());
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- /* It's important not to return until the window is configured or
- * calls to `setState` from Blender will crash `libdecor`. */
- while (!w->decor_configured) {
- if (libdecor_dispatch(m_system->decor_context(), 0) < 0) {
- break;
+ if (use_libdecor) {
+ WGL_LibDecor_Window &decor = *window_->libdecor;
+ /* It's important not to return until the window is configured or
+ * calls to `setState` from Blender will crash `libdecor`. */
+ while (!decor.configured) {
+ if (libdecor_dispatch(system_->libdecor_context(), 0) < 0) {
+ break;
+ }
}
}
#endif
@@ -535,9 +577,13 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
setOpaque();
#endif
-#ifndef WITH_GHOST_WAYLAND_LIBDECOR /* Causes a glitch with `libdecor` for some reason. */
- setState(state);
+ /* Causes a glitch with `libdecor` for some reason. */
+#ifdef WITH_GHOST_WAYLAND_LIBDECOR
+ if (use_libdecor == false)
#endif
+ {
+ setState(state);
+ }
/* EGL context. */
if (setDrawingContextType(type) == GHOST_kFailure) {
@@ -558,13 +604,13 @@ GHOST_TSuccess GHOST_WindowWayland::setWindowCursorGrab(GHOST_TGrabCursorMode mo
}
bounds = &bounds_buf;
}
- if (m_system->window_cursor_grab_set(mode,
- m_cursorGrab,
- m_cursorGrabInitPos,
- bounds,
- m_cursorGrabAxis,
- w->wl_surface,
- w->scale)) {
+ if (system_->window_cursor_grab_set(mode,
+ m_cursorGrab,
+ m_cursorGrabInitPos,
+ bounds,
+ m_cursorGrabAxis,
+ window_->wl_surface,
+ window_->scale)) {
return GHOST_kSuccess;
}
return GHOST_kFailure;
@@ -572,43 +618,47 @@ GHOST_TSuccess GHOST_WindowWayland::setWindowCursorGrab(GHOST_TGrabCursorMode mo
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorShape(GHOST_TStandardCursor shape)
{
- const GHOST_TSuccess ok = m_system->setCursorShape(shape);
+ const GHOST_TSuccess ok = system_->setCursorShape(shape);
m_cursorShape = (ok == GHOST_kSuccess) ? shape : GHOST_kStandardCursorDefault;
return ok;
}
bool GHOST_WindowWayland::getCursorGrabUseSoftwareDisplay()
{
- return m_system->getCursorGrabUseSoftwareDisplay(m_cursorGrab);
+ return system_->getCursorGrabUseSoftwareDisplay(m_cursorGrab);
}
GHOST_TSuccess GHOST_WindowWayland::setWindowCustomCursorShape(
uint8_t *bitmap, uint8_t *mask, int sizex, int sizey, int hotX, int hotY, bool canInvertColor)
{
- return m_system->setCustomCursorShape(bitmap, mask, sizex, sizey, hotX, hotY, canInvertColor);
+ return system_->setCustomCursorShape(bitmap, mask, sizex, sizey, hotX, hotY, canInvertColor);
}
GHOST_TSuccess GHOST_WindowWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitmap)
{
- return m_system->getCursorBitmap(bitmap);
+ return system_->getCursorBitmap(bitmap);
}
void GHOST_WindowWayland::setTitle(const char *title)
{
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- libdecor_frame_set_app_id(w->decor_frame, title);
- libdecor_frame_set_title(w->decor_frame, title);
-#else
- xdg_toplevel_set_title(w->xdg_toplevel, title);
- xdg_toplevel_set_app_id(w->xdg_toplevel, title);
+ if (use_libdecor) {
+ WGL_LibDecor_Window &decor = *window_->libdecor;
+ libdecor_frame_set_title(decor.frame, title);
+ }
+ else
#endif
+ {
+ WGL_XDG_Decor_Window &decor = *window_->xdg_decor;
+ xdg_toplevel_set_title(decor.toplevel, title);
+ }
- this->title = title;
+ title_ = title;
}
std::string GHOST_WindowWayland::getTitle() const
{
- return this->title.empty() ? "untitled" : this->title;
+ return title_.empty() ? "untitled" : title_;
}
void GHOST_WindowWayland::getWindowBounds(GHOST_Rect &bounds) const
@@ -618,29 +668,29 @@ void GHOST_WindowWayland::getWindowBounds(GHOST_Rect &bounds) const
void GHOST_WindowWayland::getClientBounds(GHOST_Rect &bounds) const
{
- bounds.set(0, 0, UNPACK2(w->size));
+ bounds.set(0, 0, UNPACK2(window_->size));
}
GHOST_TSuccess GHOST_WindowWayland::setClientWidth(const uint32_t width)
{
- return setClientSize(width, uint32_t(w->size[1]));
+ return setClientSize(width, uint32_t(window_->size[1]));
}
GHOST_TSuccess GHOST_WindowWayland::setClientHeight(const uint32_t height)
{
- return setClientSize(uint32_t(w->size[0]), height);
+ return setClientSize(uint32_t(window_->size[0]), height);
}
GHOST_TSuccess GHOST_WindowWayland::setClientSize(const uint32_t width, const uint32_t height)
{
- wl_egl_window_resize(w->egl_window, int(width), int(height), 0, 0);
+ wl_egl_window_resize(window_->egl_window, int(width), int(height), 0, 0);
/* Override any pending size that may be set. */
- w->size_pending[0] = 0;
- w->size_pending[1] = 0;
+ window_->size_pending[0] = 0;
+ window_->size_pending[1] = 0;
- w->size[0] = width;
- w->size[1] = height;
+ window_->size[0] = width;
+ window_->size[1] = height;
notify_size();
@@ -669,40 +719,42 @@ GHOST_WindowWayland::~GHOST_WindowWayland()
{
releaseNativeHandles();
- wl_egl_window_destroy(w->egl_window);
+ wl_egl_window_destroy(window_->egl_window);
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- libdecor_frame_unref(w->decor_frame);
-#else
- if (w->xdg_toplevel_decoration) {
- zxdg_toplevel_decoration_v1_destroy(w->xdg_toplevel_decoration);
+ if (use_libdecor) {
+ gwl_libdecor_window_destroy(window_->libdecor);
}
- xdg_toplevel_destroy(w->xdg_toplevel);
- xdg_surface_destroy(w->xdg_surface);
+ else
#endif
+ {
+ gwl_xdg_decor_window_destroy(window_->xdg_decor);
+ }
/* Clear any pointers to this window. This is needed because there are no guarantees
* that flushing the display will the "leave" handlers before handling events. */
- m_system->window_surface_unref(w->wl_surface);
+ system_->window_surface_unref(window_->wl_surface);
- wl_surface_destroy(w->wl_surface);
+ wl_surface_destroy(window_->wl_surface);
/* NOTE(@campbellbarton): Flushing will often run the appropriate handlers event
* (#wl_surface_listener.leave in particular) to avoid attempted access to the freed surfaces.
* This is not fool-proof though, hence the call to #window_surface_unref, see: T99078. */
- wl_display_flush(m_system->display());
+ wl_display_flush(system_->wl_display());
- delete w;
+ delete window_;
}
uint16_t GHOST_WindowWayland::getDPIHint()
{
- return w->dpi;
+ /* Using the physical DPI will cause wrong scaling of the UI
+ * use a multiplier for the default DPI as a workaround. */
+ return wl_fixed_to_int(window_->scale_fractional * base_dpi);
}
GHOST_TSuccess GHOST_WindowWayland::setWindowCursorVisibility(bool visible)
{
- return m_system->setCursorVisibility(visible);
+ return system_->setCursorVisibility(visible);
}
GHOST_TSuccess GHOST_WindowWayland::setState(GHOST_TWindowState state)
@@ -711,57 +763,84 @@ GHOST_TSuccess GHOST_WindowWayland::setState(GHOST_TWindowState state)
case GHOST_kWindowStateNormal:
/* Unset states. */
switch (getState()) {
- case GHOST_kWindowStateMaximized:
+ case GHOST_kWindowStateMaximized: {
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- libdecor_frame_unset_maximized(w->decor_frame);
-#else
- xdg_toplevel_unset_maximized(w->xdg_toplevel);
+ if (use_libdecor) {
+ libdecor_frame_unset_maximized(window_->libdecor->frame);
+ }
+ else
#endif
+ {
+ xdg_toplevel_unset_maximized(window_->xdg_decor->toplevel);
+ }
break;
- case GHOST_kWindowStateFullScreen:
+ }
+ case GHOST_kWindowStateFullScreen: {
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- libdecor_frame_unset_fullscreen(w->decor_frame);
-#else
- xdg_toplevel_unset_fullscreen(w->xdg_toplevel);
+ if (use_libdecor) {
+ libdecor_frame_unset_fullscreen(window_->libdecor->frame);
+ }
+ else
#endif
+ {
+ xdg_toplevel_unset_fullscreen(window_->xdg_decor->toplevel);
+ }
break;
- default:
+ }
+ default: {
break;
+ }
}
break;
- case GHOST_kWindowStateMaximized:
+ case GHOST_kWindowStateMaximized: {
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- libdecor_frame_set_maximized(w->decor_frame);
-#else
- xdg_toplevel_set_maximized(w->xdg_toplevel);
+ if (use_libdecor) {
+ libdecor_frame_set_maximized(window_->libdecor->frame);
+ }
+ else
#endif
+ {
+ xdg_toplevel_set_maximized(window_->xdg_decor->toplevel);
+ }
break;
- case GHOST_kWindowStateMinimized:
+ }
+ case GHOST_kWindowStateMinimized: {
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- libdecor_frame_set_minimized(w->decor_frame);
-#else
- xdg_toplevel_set_minimized(w->xdg_toplevel);
+ if (use_libdecor) {
+ libdecor_frame_set_minimized(window_->libdecor->frame);
+ }
+ else
#endif
+ {
+ xdg_toplevel_set_minimized(window_->xdg_decor->toplevel);
+ }
break;
- case GHOST_kWindowStateFullScreen:
+ }
+ case GHOST_kWindowStateFullScreen: {
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- libdecor_frame_set_fullscreen(w->decor_frame, nullptr);
-#else
- xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr);
+ if (use_libdecor) {
+ libdecor_frame_set_fullscreen(window_->libdecor->frame, nullptr);
+ }
+ else
#endif
+ {
+ xdg_toplevel_set_fullscreen(window_->xdg_decor->toplevel, nullptr);
+ }
break;
- case GHOST_kWindowStateEmbedded:
+ }
+ case GHOST_kWindowStateEmbedded: {
return GHOST_kFailure;
+ }
}
return GHOST_kSuccess;
}
GHOST_TWindowState GHOST_WindowWayland::getState() const
{
- if (w->is_fullscreen) {
+ if (window_->is_fullscreen) {
return GHOST_kWindowStateFullScreen;
}
- if (w->is_maximised) {
+ if (window_->is_maximised) {
return GHOST_kWindowStateMaximized;
}
return GHOST_kWindowStateNormal;
@@ -780,26 +859,35 @@ GHOST_TSuccess GHOST_WindowWayland::setOrder(GHOST_TWindowOrder /*order*/)
GHOST_TSuccess GHOST_WindowWayland::beginFullScreen() const
{
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- libdecor_frame_set_fullscreen(w->decor_frame, nullptr);
-#else
- xdg_toplevel_set_fullscreen(w->xdg_toplevel, nullptr);
+ if (use_libdecor) {
+ libdecor_frame_set_fullscreen(window_->libdecor->frame, nullptr);
+ }
+ else
#endif
+ {
+ xdg_toplevel_set_fullscreen(window_->xdg_decor->toplevel, nullptr);
+ }
+
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_WindowWayland::endFullScreen() const
{
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
- libdecor_frame_unset_fullscreen(w->decor_frame);
-#else
- xdg_toplevel_unset_fullscreen(w->xdg_toplevel);
+ if (use_libdecor) {
+ libdecor_frame_unset_fullscreen(window_->libdecor->frame);
+ }
+ else
#endif
+ {
+ xdg_toplevel_unset_fullscreen(window_->xdg_decor->toplevel);
+ }
return GHOST_kSuccess;
}
bool GHOST_WindowWayland::isDialog() const
{
- return w->is_dialog;
+ return window_->is_dialog;
}
#ifdef GHOST_OPENGL_ALPHA
@@ -808,9 +896,9 @@ void GHOST_WindowWayland::setOpaque() const
struct wl_region *region;
/* Make the window opaque. */
- region = wl_compositor_create_region(m_system->compositor());
- wl_region_add(region, 0, 0, UNPACK2(w->size));
- wl_surface_set_opaque_region(w->surface, region);
+ region = wl_compositor_create_region(system_->compositor());
+ wl_region_add(region, 0, 0, UNPACK2(window_->size));
+ wl_surface_set_opaque_region(window_->surface, region);
wl_region_destroy(region);
}
#endif
@@ -828,10 +916,10 @@ GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType
break;
case GHOST_kDrawingContextTypeOpenGL:
for (int minor = 6; minor >= 0; --minor) {
- context = new GHOST_ContextEGL(this->m_system,
+ context = new GHOST_ContextEGL(system_,
m_wantStereoVisual,
- EGLNativeWindowType(w->egl_window),
- EGLNativeDisplayType(m_system->display()),
+ EGLNativeWindowType(window_->egl_window),
+ EGLNativeDisplayType(system_->wl_display()),
EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
4,
minor,
@@ -844,10 +932,10 @@ GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType
}
delete context;
}
- context = new GHOST_ContextEGL(this->m_system,
+ context = new GHOST_ContextEGL(system_,
m_wantStereoVisual,
- EGLNativeWindowType(w->egl_window),
- EGLNativeDisplayType(m_system->display()),
+ EGLNativeWindowType(window_->egl_window),
+ EGLNativeDisplayType(system_->wl_display()),
EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT,
3,
3,
@@ -856,7 +944,12 @@ GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType
EGL_OPENGL_API);
}
- return (context->initializeDrawingContext() == GHOST_kSuccess) ? context : nullptr;
+ if (context->initializeDrawingContext()) {
+ return context;
+ }
+
+ delete context;
+ return nullptr;
}
/** \} */
@@ -867,24 +960,24 @@ GHOST_Context *GHOST_WindowWayland::newDrawingContext(GHOST_TDrawingContextType
* Expose some members via methods.
* \{ */
-uint16_t GHOST_WindowWayland::dpi() const
+int GHOST_WindowWayland::scale() const
{
- return w->dpi;
+ return window_->scale;
}
-int GHOST_WindowWayland::scale() const
+wl_fixed_t GHOST_WindowWayland::scale_fractional() const
{
- return w->scale;
+ return window_->scale_fractional;
}
wl_surface *GHOST_WindowWayland::wl_surface() const
{
- return w->wl_surface;
+ return window_->wl_surface;
}
const std::vector<GWL_Output *> &GHOST_WindowWayland::outputs()
{
- return w->outputs;
+ return window_->outputs;
}
/** \} */
@@ -897,24 +990,24 @@ const std::vector<GWL_Output *> &GHOST_WindowWayland::outputs()
GHOST_TSuccess GHOST_WindowWayland::close()
{
- return m_system->pushEvent(
- new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowClose, this));
+ return system_->pushEvent(
+ new GHOST_Event(system_->getMilliSeconds(), GHOST_kEventWindowClose, this));
}
GHOST_TSuccess GHOST_WindowWayland::activate()
{
- if (m_system->getWindowManager()->setActiveWindow(this) == GHOST_kFailure) {
+ if (system_->getWindowManager()->setActiveWindow(this) == GHOST_kFailure) {
return GHOST_kFailure;
}
- return m_system->pushEvent(
- new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowActivate, this));
+ return system_->pushEvent(
+ new GHOST_Event(system_->getMilliSeconds(), GHOST_kEventWindowActivate, this));
}
GHOST_TSuccess GHOST_WindowWayland::deactivate()
{
- m_system->getWindowManager()->setWindowInactive(this);
- return m_system->pushEvent(
- new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowDeactivate, this));
+ system_->getWindowManager()->setWindowInactive(this);
+ return system_->pushEvent(
+ new GHOST_Event(system_->getMilliSeconds(), GHOST_kEventWindowDeactivate, this));
}
GHOST_TSuccess GHOST_WindowWayland::notify_size()
@@ -923,8 +1016,8 @@ GHOST_TSuccess GHOST_WindowWayland::notify_size()
setOpaque();
#endif
- return m_system->pushEvent(
- new GHOST_Event(m_system->getMilliSeconds(), GHOST_kEventWindowSize, this));
+ return system_->pushEvent(
+ new GHOST_Event(system_->getMilliSeconds(), GHOST_kEventWindowSize, this));
}
/** \} */
@@ -940,31 +1033,39 @@ GHOST_TSuccess GHOST_WindowWayland::notify_size()
*/
bool GHOST_WindowWayland::outputs_changed_update_scale()
{
- uint32_t dpi_next;
- const int scale_next = outputs_max_scale_or_default(this->outputs(), 0, &dpi_next);
+ wl_fixed_t scale_fractional_next = 0;
+ const int scale_next = outputs_max_scale_or_default(outputs(), 0, &scale_fractional_next);
if (UNLIKELY(scale_next == 0)) {
return false;
}
- GWL_Window *win = this->w;
- const uint32_t dpi_curr = win->dpi;
- const int scale_curr = win->scale;
+ const wl_fixed_t scale_fractional_curr = window_->scale_fractional;
+ const int scale_curr = window_->scale;
bool changed = false;
if (scale_next != scale_curr) {
- /* Unlikely but possible there is a pending size change is set. */
- win->size_pending[0] = (win->size_pending[0] / scale_curr) * scale_next;
- win->size_pending[1] = (win->size_pending[1] / scale_curr) * scale_next;
+ window_->scale = scale_next;
+ wl_surface_set_buffer_scale(window_->wl_surface, scale_next);
+
+ /* It's important to resize the window immediately, to avoid the window changing size
+ * and flickering in a constant feedback loop (in some bases). */
+ if ((window_->size_pending[0] != 0) && (window_->size_pending[1] != 0)) {
+ /* Unlikely but possible there is a pending size change is set. */
+ window_->size[0] = window_->size_pending[0];
+ window_->size[1] = window_->size_pending[1];
+ window_->size_pending[0] = 0;
+ window_->size_pending[1] = 0;
+ }
+ window_->size[0] = (window_->size[0] / scale_curr) * scale_next;
+ window_->size[1] = (window_->size[1] / scale_curr) * scale_next;
+ wl_egl_window_resize(window_->egl_window, UNPACK2(window_->size), 0, 0);
+ window_->ghost_window->notify_size();
- win->scale = scale_next;
- wl_surface_set_buffer_scale(w->wl_surface, scale_next);
changed = true;
}
- if (dpi_next != dpi_curr) {
- /* Using the real DPI will cause wrong scaling of the UI
- * use a multiplier for the default DPI as workaround. */
- win->dpi = dpi_next;
+ if (scale_fractional_next != scale_fractional_curr) {
+ window_->scale_fractional = scale_fractional_next;
changed = true;
/* As this is a low-level function, we might want adding this event to be optional,
@@ -979,7 +1080,7 @@ bool GHOST_WindowWayland::outputs_changed_update_scale()
bool GHOST_WindowWayland::outputs_enter(GWL_Output *output)
{
- std::vector<GWL_Output *> &outputs = w->outputs;
+ std::vector<GWL_Output *> &outputs = window_->outputs;
auto it = std::find(outputs.begin(), outputs.end(), output);
if (it != outputs.end()) {
return false;
@@ -990,7 +1091,7 @@ bool GHOST_WindowWayland::outputs_enter(GWL_Output *output)
bool GHOST_WindowWayland::outputs_leave(GWL_Output *output)
{
- std::vector<GWL_Output *> &outputs = w->outputs;
+ std::vector<GWL_Output *> &outputs = window_->outputs;
auto it = std::find(outputs.begin(), outputs.end(), output);
if (it == outputs.end()) {
return false;