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
path: root/source
diff options
context:
space:
mode:
authorCampbell Barton <campbell@blender.org>2022-06-08 06:01:31 +0300
committerCampbell Barton <campbell@blender.org>2022-06-08 06:16:14 +0300
commita1d2efd190038c7615bd3bb459dc86c8b3a8ecdc (patch)
tree2f709a3566c84d45ccd352104573626a445cdb41 /source
parentb3e0101a35b2885212aa199335564dca98dc50cd (diff)
GHOST/Wayland: draw a software-cursor when wrapping cursor motion
As Wayland doesn't support moving the cursor, draw a cross-hair cursor at the location used by Blender. Without this, the cursor was locked at the location where grab started, making some actions unusable since the cursor location was invisible. Resolves T77311.
Diffstat (limited to 'source')
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c124
1 files changed, 124 insertions, 0 deletions
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