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:
-rw-r--r--intern/ghost/GHOST_C-api.h9
-rw-r--r--intern/ghost/GHOST_ISystem.h5
-rw-r--r--intern/ghost/GHOST_IWindow.h4
-rw-r--r--intern/ghost/GHOST_Types.h2
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp23
-rw-r--r--intern/ghost/intern/GHOST_System.cpp5
-rw-r--r--intern/ghost/intern/GHOST_System.h3
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp10
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.h2
-rw-r--r--intern/ghost/intern/GHOST_Window.cpp23
-rw-r--r--intern/ghost/intern/GHOST_Window.h2
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c124
12 files changed, 210 insertions, 2 deletions
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index ae749eb3b8c..57714083656 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -402,6 +402,10 @@ extern GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle,
int32_t x,
int32_t y);
+GHOST_TSuccess GHOST_GetCursorGrabState(GHOST_WindowHandle windowhandle,
+ GHOST_TAxisFlag *r_wrap_axis,
+ int r_bounds[4]);
+
/**
* Grabs the cursor for a modal operation, to keep receiving
* events when the mouse is outside the window. X11 only, others
@@ -897,6 +901,11 @@ extern int setConsoleWindowState(GHOST_TConsoleWindowState action);
extern int GHOST_UseNativePixels(void);
/**
+ * Warp the cursor, if supported.
+ */
+extern int GHOST_SupportsCursorWarp(void);
+
+/**
* Focus window after opening, or put them in the background.
*/
extern void GHOST_UseWindowFocus(int use_focus);
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index bb91abbadec..8a4412403f7 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -305,6 +305,11 @@ class GHOST_ISystem {
virtual bool useNativePixel(void) = 0;
/**
+ * Return true when warping the cursor is supported.
+ */
+ virtual bool supportsCursorWarp() = 0;
+
+ /**
* Focus window after opening, or put them in the background.
*/
virtual void useWindowFocus(const bool use_focus) = 0;
diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h
index 183e97a4b55..681ad9c5b07 100644
--- a/intern/ghost/GHOST_IWindow.h
+++ b/intern/ghost/GHOST_IWindow.h
@@ -254,6 +254,10 @@ class GHOST_IWindow {
*/
virtual GHOST_TSuccess setCursorShape(GHOST_TStandardCursor cursorShape) = 0;
+ virtual GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds) = 0;
+
+ virtual GHOST_TSuccess getCursorGrabState(GHOST_TAxisFlag &axis_flag, GHOST_Rect &bounds) = 0;
+
/**
* Test if the standard cursor shape is supported by current platform.
* \return Indication of success.
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index e2ed9830e4e..841c0c33ee1 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -403,6 +403,8 @@ typedef enum {
GHOST_kGrabHide,
} GHOST_TGrabCursorMode;
+#define GHOST_GRAB_NEEDS_SOFTWARE_CURSOR_FOR_WARP(grab) ((grab) == GHOST_kGrabWrap)
+
typedef enum {
/** Axis that cursor grab will wrap. */
GHOST_kGrabAxisNone = 0,
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 9374d087408..f4c978a88d4 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -376,6 +376,23 @@ GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle,
mode, wrap_axis, bounds ? &bounds_rect : nullptr, mouse_ungrab_xy ? mouse_xy : nullptr);
}
+GHOST_TSuccess GHOST_GetCursorGrabState(GHOST_WindowHandle windowhandle,
+ GHOST_TAxisFlag *r_axis_flag,
+ int r_bounds[4])
+{
+ GHOST_IWindow *window = (GHOST_IWindow *)windowhandle;
+ GHOST_Rect bounds_rect;
+ if (!window->getCursorGrabState(*r_axis_flag, bounds_rect)) {
+ return GHOST_kFailure;
+ }
+
+ r_bounds[0] = bounds_rect.m_l;
+ r_bounds[1] = bounds_rect.m_t;
+ r_bounds[2] = bounds_rect.m_r;
+ r_bounds[3] = bounds_rect.m_b;
+ return GHOST_kSuccess;
+}
+
GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle,
GHOST_TModifierKeyMask mask,
int *isDown)
@@ -815,6 +832,12 @@ int GHOST_UseNativePixels(void)
return system->useNativePixel();
}
+int GHOST_SupportsCursorWarp(void)
+{
+ GHOST_ISystem *system = GHOST_ISystem::getSystem();
+ return system->supportsCursorWarp();
+}
+
void GHOST_UseWindowFocus(int use_focus)
{
GHOST_ISystem *system = GHOST_ISystem::getSystem();
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index 1ddf884bbc5..2aad4f2ea29 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -390,6 +390,11 @@ void GHOST_System::useWindowFocus(const bool use_focus)
m_windowFocus = use_focus;
}
+bool GHOST_System::supportsCursorWarp()
+{
+ return true;
+}
+
void GHOST_System::initDebug(GHOST_Debug debug)
{
m_is_debug_enabled = debug.flags & GHOST_kDebugDefault;
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h
index 4a3cded1fbd..9f2fba1a2c6 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -151,10 +151,13 @@ class GHOST_System : public GHOST_ISystem {
bool useNativePixel(void);
bool m_nativePixel;
+ bool supportsCursorWarp(void);
+
/**
* Focus window after opening, or put them in the background.
*/
void useWindowFocus(const bool use_focus);
+
bool m_windowFocus;
/**
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index f6eabb60b05..7e471d5c7d4 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -1920,6 +1920,11 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(bool visible)
return GHOST_kSuccess;
}
+bool GHOST_SystemWayland::supportsCursorWarp()
+{
+ return false;
+}
+
GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mode,
const GHOST_TGrabCursorMode mode_current,
@@ -1948,8 +1953,9 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorGrab(const GHOST_TGrabCursorMode mo
const bool was_lock = MODE_NEEDS_LOCK(mode_current);
const bool use_lock = MODE_NEEDS_LOCK(mode);
- const bool was_hide = MODE_NEEDS_HIDE(mode_current);
- const bool use_hide = MODE_NEEDS_HIDE(mode);
+ /* Check for wrap as #supportsCursorWarp isn't supproted. */
+ const bool was_hide = MODE_NEEDS_HIDE(mode_current) || (mode_current == GHOST_kGrabWrap);
+ const bool use_hide = MODE_NEEDS_HIDE(mode) || (mode == GHOST_kGrabWrap);
const bool was_confine = MODE_NEEDS_CONFINE(mode_current);
const bool use_confine = MODE_NEEDS_CONFINE(mode);
diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h
index eeb65eb4fc3..5b3e4f8ed75 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.h
+++ b/intern/ghost/intern/GHOST_SystemWayland.h
@@ -103,6 +103,8 @@ class GHOST_SystemWayland : public GHOST_System {
GHOST_TSuccess setCursorVisibility(bool visible);
+ bool supportsCursorWarp();
+
GHOST_TSuccess setCursorGrab(const GHOST_TGrabCursorMode mode,
const GHOST_TGrabCursorMode mode_current,
wl_surface *surface);
diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp
index 954f0bc244d..12963abf128 100644
--- a/intern/ghost/intern/GHOST_Window.cpp
+++ b/intern/ghost/intern/GHOST_Window.cpp
@@ -155,10 +155,33 @@ GHOST_TSuccess GHOST_Window::setCursorGrab(GHOST_TGrabCursorMode mode,
GHOST_TSuccess GHOST_Window::getCursorGrabBounds(GHOST_Rect &bounds)
{
+ if (m_cursorGrab != GHOST_kGrabWrap) {
+ return GHOST_kFailure;
+ }
bounds = m_cursorGrabBounds;
return (bounds.m_l == -1 && bounds.m_r == -1) ? GHOST_kFailure : GHOST_kSuccess;
}
+GHOST_TSuccess GHOST_Window::getCursorGrabState(GHOST_TAxisFlag &wrap_axis, GHOST_Rect &bounds)
+{
+ if (m_cursorGrab == GHOST_kGrabDisable) {
+ return GHOST_kFailure;
+ }
+
+ if (m_cursorGrab == GHOST_kGrabWrap) {
+ bounds = m_cursorGrabBounds;
+ wrap_axis = m_cursorGrabAxis;
+ }
+ else {
+ bounds.m_l = -1;
+ bounds.m_r = -1;
+ bounds.m_t = -1;
+ bounds.m_b = -1;
+ wrap_axis = GHOST_kGrabAxisNone;
+ }
+ return GHOST_kSuccess;
+}
+
GHOST_TSuccess GHOST_Window::setCursorShape(GHOST_TStandardCursor cursorShape)
{
if (setWindowCursorShape(cursorShape)) {
diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h
index 794e834d5c7..b0042a33a00 100644
--- a/intern/ghost/intern/GHOST_Window.h
+++ b/intern/ghost/intern/GHOST_Window.h
@@ -152,6 +152,8 @@ class GHOST_Window : public GHOST_IWindow {
*/
GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds);
+ GHOST_TSuccess getCursorGrabState(GHOST_TAxisFlag &axis_flag, GHOST_Rect &bounds);
+
/**
* Sets the progress bar value displayed in the window/application icon
* \param progress: The progress percentage (0.0 to 1.0).
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index d2ade7b0376..810cc9001fe 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -119,6 +119,113 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Draw Software Cursor
+ *
+ * Draw the cursor instead of relying on the graphical environment.
+ * Needed when setting the cursor position (warping) isn't supported (GHOST/WAYLAND).
+ * \{ */
+
+/**
+ * Track the state of the last drawn cursor.
+ */
+static struct {
+ int8_t enabled;
+ int winid;
+ int xy[2];
+} g_software_cursor = {
+ .enabled = -1,
+ .winid = -1,
+};
+
+static bool wm_software_cursor_needed(void)
+{
+ if (UNLIKELY(g_software_cursor.enabled == -1)) {
+ g_software_cursor.enabled = !GHOST_SupportsCursorWarp();
+ }
+ return g_software_cursor.enabled;
+}
+
+static bool wm_software_cursor_needed_for_window(const wmWindow *win)
+{
+ BLI_assert(wm_software_cursor_needed());
+ return (win->grabcursor == GHOST_kGrabWrap) && GHOST_GetCursorVisibility(win->ghostwin);
+}
+
+static bool wm_software_cursor_motion_test(const wmWindow *win)
+{
+ return (g_software_cursor.winid != win->winid) ||
+ (g_software_cursor.xy[0] != win->eventstate->xy[0]) ||
+ (g_software_cursor.xy[1] != win->eventstate->xy[1]);
+}
+
+static void wm_software_cursor_motion_update(const wmWindow *win)
+{
+
+ g_software_cursor.winid = win->winid;
+ g_software_cursor.xy[0] = win->eventstate->xy[0];
+ g_software_cursor.xy[1] = win->eventstate->xy[1];
+}
+
+static void wm_software_cursor_motion_clear(void)
+{
+ g_software_cursor.winid = -1;
+ g_software_cursor.xy[0] = -1;
+ g_software_cursor.xy[1] = -1;
+}
+
+static void wm_software_cursor_draw(wmWindow *win)
+{
+ int x = win->eventstate->xy[0];
+ int y = win->eventstate->xy[1];
+
+ int bounds[4];
+ GHOST_TAxisFlag wrap_axis = 0;
+ if (GHOST_GetCursorGrabState(win->ghostwin, &wrap_axis, bounds) != GHOST_kFailure) {
+ if (wrap_axis & GHOST_kAxisX) {
+ const int min = bounds[0];
+ const int max = bounds[2];
+ if (min != max) {
+ x = mod_i(x - min, max - min) + min;
+ }
+ }
+ if (wrap_axis & GHOST_kGrabAxisY) {
+ const int height = WM_window_pixels_y(win);
+ const int min = height - bounds[1];
+ const int max = height - bounds[3];
+ if (min != max) {
+ y = mod_i(y - max, min - max) + max;
+ }
+ }
+ }
+
+ /* Draw a primitive cross-hair cursor.
+ * NOTE: the `win->cursor` could be used for drawing although it's complicated as some cursors
+ * are set by the operating-system, where the pixel information isn't easily available. */
+ const float unit = max_ff(U.dpi_fac, 1.0f);
+ uint pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4f(1, 1, 1, 1);
+ {
+ const int ofs_line = (8 * unit);
+ const int ofs_size = (2 * unit);
+ immRecti(pos, x - ofs_line, y - ofs_size, x + ofs_line, y + ofs_size);
+ immRecti(pos, x - ofs_size, y - ofs_line, x + ofs_size, y + ofs_line);
+ }
+ immUniformColor4f(0, 0, 0, 1);
+ {
+ const int ofs_line = (7 * unit);
+ const int ofs_size = (1 * unit);
+ immRecti(pos, x - ofs_line, y - ofs_size, x + ofs_line, y + ofs_size);
+ immRecti(pos, x - ofs_size, y - ofs_line, x + ofs_size, y + ofs_line);
+ }
+ immUnbindProgram();
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Post Draw Region on display handlers
* \{ */
@@ -862,6 +969,7 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
/* always draw, not only when screen tagged */
if (win->gesture.first) {
wm_gesture_draw(win);
+ wmWindowViewport(win);
}
/* Needs pixel coords in screen. */
@@ -870,6 +978,16 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
wmWindowViewport(win);
}
+ if (wm_software_cursor_needed()) {
+ if (wm_software_cursor_needed_for_window(win)) {
+ wm_software_cursor_draw(win);
+ wm_software_cursor_motion_update(win);
+ }
+ else {
+ wm_software_cursor_motion_clear();
+ }
+ }
+
GPU_debug_group_end();
}
@@ -1020,6 +1138,12 @@ static bool wm_draw_update_test_window(Main *bmain, bContext *C, wmWindow *win)
return true;
}
+ if (wm_software_cursor_needed()) {
+ if (wm_software_cursor_needed_for_window(win) && wm_software_cursor_motion_test(win)) {
+ return true;
+ }
+ }
+
#ifndef WITH_XR_OPENXR
UNUSED_VARS(wm);
#endif