tornavis/intern/ghost/intern/GHOST_WindowWayland.hh

205 lines
6.8 KiB
C++

/* SPDX-FileCopyrightText: 2020-2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup GHOST
*
* Declaration of GHOST_WindowWayland class.
*/
#pragma once
#include "GHOST_Window.hh"
#include <vector>
#include <wayland-util.h> /* For #wl_fixed_t */
/**
* Define to workaround for a bug/limitation in WAYLAND, see: #100855 & upstream report:
* https://gitlab.freedesktop.org/wayland/wayland/-/issues/159
*
* Consume events from WAYLAND in a thread, this is needed because overflowing the event queue
* causes a fatal error (more than `sizeof(wl_buffer.data)` at the time of writing).
*
* Solve this using a thread that handles events, locking must be performed as follows:
*
* - Lock #GWL_Display.server_mutex to prevent #wl_display_dispatch / #wl_display_roundtrip
* running from multiple threads at once.
*
* Even though WAYLAND functions that communicate with `wl_display_*` have their own locks,
* GHOST functions that communicate with WAYLAND must use this lock to be thread safe.
*
* Without this reading/writing values such as changing the cursor or setting the window size
* could conflict with WAYLAND callbacks running in a separate thread.
* So the `server_mutex` ensures either GHOST or WAYLAND is manipulating this data,
* having two WAYLAND callbacks accessing the data at once isn't a problem.
*
* \warning Some operations such as #ContextEGL creation/deletion & swap-buffers may call
* #wl_display_dispatch indirectly, so it's important to take care to lock the `server_mutex`,
* before accessing these functions too.
*
* \warning An unfortunate side-effect of this is care needs to be taken not to call public
* GHOST functions from each other in situations that would otherwise be supported.
* As both using a `server_mutex` results in a dead-lock. In some cases this means the
* implementation and the public function may need to be split.
*
* - Lock #GWL_Display.timer_mutex when WAYLAND callbacks manipulate timers.
*
* - Lock #GWL_Display.events_pending_mutex before manipulating #GWL_Display.events_pending.
*
* - Lock #GWL_Window.frame_pending_mutex before changing window size & frame settings,
* this is flushed in #GHOST_WindowWayland::pending_actions_handle.
*
* \note Keep this define as it can be useful to disable threading when troubleshooting
* issues with events.
*/
#define USE_EVENT_BACKGROUND_THREAD
class GHOST_SystemWayland;
struct GWL_Output;
struct GWL_Window;
class GHOST_WindowWayland : public GHOST_Window {
public:
GHOST_TSuccess hasCursorShape(GHOST_TStandardCursor cursorShape) 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);
~GHOST_WindowWayland() override;
/* Ghost API */
#ifdef USE_EVENT_BACKGROUND_THREAD
GHOST_TSuccess swapBuffers() override; /* Only for assertion. */
#endif
uint16_t getDPIHint() override;
GHOST_TSuccess setWindowCursorGrab(GHOST_TGrabCursorMode mode) override;
GHOST_TSuccess setWindowCursorShape(GHOST_TStandardCursor shape) override;
GHOST_TSuccess setWindowCustomCursorShape(uint8_t *bitmap,
uint8_t *mask,
int sizex,
int sizey,
int hotX,
int hotY,
bool canInvertColor) override;
bool getCursorGrabUseSoftwareDisplay() override;
GHOST_TSuccess getCursorBitmap(GHOST_CursorBitmapRef *bitmap) override;
void setTitle(const char *title) override;
std::string getTitle() const override;
void getWindowBounds(GHOST_Rect &bounds) const override;
void getClientBounds(GHOST_Rect &bounds) const override;
GHOST_TSuccess setClientWidth(uint32_t width) override;
GHOST_TSuccess setClientHeight(uint32_t height) override;
GHOST_TSuccess setClientSize(uint32_t width, uint32_t height) override;
void screenToClient(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const override;
void clientToScreen(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const override;
GHOST_TSuccess setWindowCursorVisibility(bool visible) override;
GHOST_TSuccess setState(GHOST_TWindowState state) override;
GHOST_TWindowState getState() const override;
GHOST_TSuccess invalidate() override;
GHOST_TSuccess setOrder(GHOST_TWindowOrder order) override;
GHOST_TSuccess beginFullScreen() const override;
GHOST_TSuccess endFullScreen() const override;
bool isDialog() const override;
#ifdef WITH_INPUT_IME
void beginIME(int32_t x, int32_t y, int32_t w, int32_t h, bool completed) override;
void endIME() override;
#endif /* WITH_INPUT_IME */
/* WAYLAND direct-data access. */
int scale_get() const;
const struct GWL_WindowScaleParams &scale_params_get() const;
struct wl_surface *wl_surface_get() const;
const std::vector<GWL_Output *> &outputs_get();
wl_fixed_t wl_fixed_from_window(wl_fixed_t value) const;
wl_fixed_t wl_fixed_to_window(wl_fixed_t value) const;
/* WAYLAND window-level functions. */
/**
* Set the window as active and send an #GHOST_kEventWindowActivate event.
*
* \note The current active state is *not* checked, the caller is responsible for
* not activating windows which are already active.
*/
GHOST_TSuccess activate();
/**
* De-activate the window and send a #GHOST_kEventWindowDeactivate event.
*
* \note The current active state is *not* checked, the caller is responsible for
* not de-activating windows that aren't active.
*/
GHOST_TSuccess deactivate();
GHOST_TSuccess close();
GHOST_TSuccess notify_size();
GHOST_TSuccess notify_decor_redraw();
/* WAYLAND utility functions. */
bool outputs_enter(GWL_Output *output);
bool outputs_leave(GWL_Output *output);
/**
* Return true when the windows scale or DPI changes.
*/
bool outputs_changed_update_scale();
void outputs_changed_update_scale_tag();
#ifdef USE_EVENT_BACKGROUND_THREAD
void pending_actions_handle();
#endif
private:
GHOST_SystemWayland *system_;
struct GWL_Window *window_;
bool is_debug_context_;
/**
* \param type: The type of rendering context create.
* \return Indication of success.
*/
GHOST_Context *newDrawingContext(GHOST_TDrawingContextType type) override;
};