Просмотр исходного кода

wayland: Don't clear the cursor on leave events

Stop the frame callback and flag the cursor for a refresh when the pointer re-enters the surface, but don't set a null cursor, as it may have already been set after entering a surface that is part of the window decorations, resulting in an unwanted invisible cursor.
Frank Praznik 1 месяц назад
Родитель
Сommit
5e2977709b
2 измененных файлов с 40 добавлено и 22 удалено
  1. 3 0
      src/video/wayland/SDL_waylandevents_c.h
  2. 37 22
      src/video/wayland/SDL_waylandmouse.c

+ 3 - 0
src/video/wayland/SDL_waylandevents_c.h

@@ -73,7 +73,10 @@ typedef struct SDL_WaylandCursorState
 
     Uint64 last_frame_callback_time_ms;
     Uint32 current_frame_time_ms;
+
+    // 0 or greater if a buffer is attached, -1 if in the reset state.
     int current_frame;
+
     SDL_HitTestResult hit_test_result;
 } SDL_WaylandCursorState;
 

+ 37 - 22
src/video/wayland/SDL_waylandmouse.c

@@ -900,7 +900,8 @@ static void Wayland_FreeCursorData(SDL_CursorData *d)
         if (seat->pointer.current_cursor == d) {
             Wayland_CursorStateDestroyFrameCallback(&seat->pointer.cursor_state);
 
-            if (seat->pointer.cursor_state.surface) {
+            // Custom cursor buffers are about to be destroyed, so ensure they are detached.
+            if (!d->is_system_cursor && seat->pointer.cursor_state.surface) {
                 wl_surface_attach(seat->pointer.cursor_state.surface, NULL, 0, 0);
             }
 
@@ -1040,7 +1041,7 @@ static void Wayland_CursorStateSetCursor(SDL_WaylandCursorState *state, const Wa
     }
 
     if (cursor) {
-        if (cursor_data == state->current_cursor) {
+        if (cursor_data == state->current_cursor && state->current_frame >= 0) {
             // Restart the animation sequence if the cursor didn't change.
             if (cursor_data->num_frames > 1) {
                 Wayland_CursorStateResetAnimation(state, true);
@@ -1075,6 +1076,7 @@ static void Wayland_CursorStateSetCursor(SDL_WaylandCursorState *state, const Wa
                 const enum wp_cursor_shape_device_v1_shape shape = Wayland_GetSystemCursorShape(cursor_data->cursor_data.system.id);
                 wp_cursor_shape_device_v1_set_shape(state->cursor_shape, serial, shape);
                 state->current_cursor = cursor_data;
+                state->current_frame = 0;
 
                 return;
             }
@@ -1107,6 +1109,7 @@ static void Wayland_CursorStateSetCursor(SDL_WaylandCursorState *state, const Wa
 
         struct wl_buffer *buffer = Wayland_CursorStateGetFrame(state, 0);
         wl_surface_attach(state->surface, buffer, 0, 0);
+        state->current_frame = 0;
 
         if (state->scale != 1.0) {
             if (!state->viewport) {
@@ -1156,6 +1159,13 @@ static void Wayland_CursorStateSetCursor(SDL_WaylandCursorState *state, const Wa
     }
 }
 
+static void Wayland_CursorStateResetCursor(SDL_WaylandCursorState *state)
+{
+    // Stop the frame callback and set the reset status.
+    Wayland_CursorStateDestroyFrameCallback(state);
+    state->current_frame = -1;
+}
+
 static bool Wayland_ShowCursor(SDL_Cursor *cursor)
 {
     SDL_VideoDevice *vd = SDL_GetVideoDevice();
@@ -1170,7 +1180,7 @@ static bool Wayland_ShowCursor(SDL_Cursor *cursor)
         if (mouse->focus && mouse->focus->internal == seat->pointer.focus) {
             Wayland_CursorStateSetCursor(&seat->pointer.cursor_state, &obj, seat->pointer.focus, seat->pointer.enter_serial, cursor);
         } else if (!seat->pointer.focus) {
-            Wayland_CursorStateSetCursor(&seat->pointer.cursor_state, &obj, seat->pointer.focus, seat->pointer.enter_serial, NULL);
+            Wayland_CursorStateResetCursor(&seat->pointer.cursor_state);
         }
 
         SDL_WaylandPenTool *tool;
@@ -1184,7 +1194,7 @@ static bool Wayland_ShowCursor(SDL_Cursor *cursor)
             if (tool->focus && (!mouse->focus || mouse->focus->internal == tool->focus)) {
                 Wayland_CursorStateSetCursor(&tool->cursor_state, &obj, tool->focus, tool->proximity_serial, mouse->cur_cursor);
             } else if (!tool->focus) {
-                Wayland_CursorStateSetCursor(&tool->cursor_state, &obj, tool->focus, tool->proximity_serial, NULL);
+                Wayland_CursorStateResetCursor(&tool->cursor_state);
             }
         }
     }
@@ -1506,24 +1516,25 @@ void Wayland_SeatUpdatePointerCursor(SDL_WaylandSeat *seat)
         .is_pointer = true
     };
 
-    if (pointer_focus && mouse->cursor_visible) {
-        if (!seat->pointer.relative_pointer || !mouse->relative_mode_hide_cursor) {
-            const SDL_HitTestResult rc = pointer_focus->hit_test_result;
+    if (pointer_focus) {
+        if (mouse->cursor_visible) {
+            if (!seat->pointer.relative_pointer || !mouse->relative_mode_hide_cursor) {
+                const SDL_HitTestResult rc = pointer_focus->hit_test_result;
 
-            if (seat->pointer.relative_pointer || rc == SDL_HITTEST_NORMAL || rc == SDL_HITTEST_DRAGGABLE) {
-                Wayland_CursorStateSetCursor(&seat->pointer.cursor_state, &obj, pointer_focus, seat->pointer.enter_serial, mouse->cur_cursor);
+                if (seat->pointer.relative_pointer || rc == SDL_HITTEST_NORMAL || rc == SDL_HITTEST_DRAGGABLE) {
+                    Wayland_CursorStateSetCursor(&seat->pointer.cursor_state, &obj, pointer_focus, seat->pointer.enter_serial, mouse->cur_cursor);
+                } else {
+                    Wayland_CursorStateSetCursor(&seat->pointer.cursor_state, &obj, pointer_focus, seat->pointer.enter_serial, sys_cursors[rc]);
+                }
             } else {
-                Wayland_CursorStateSetCursor(&seat->pointer.cursor_state, &obj, pointer_focus, seat->pointer.enter_serial, sys_cursors[rc]);
+                // Hide the cursor in relative mode, unless requested otherwise by the hint.
+                Wayland_CursorStateSetCursor(&seat->pointer.cursor_state, &obj, pointer_focus, seat->pointer.enter_serial, NULL);
             }
         } else {
-            // Hide the cursor in relative mode, unless requested otherwise by the hint.
             Wayland_CursorStateSetCursor(&seat->pointer.cursor_state, &obj, pointer_focus, seat->pointer.enter_serial, NULL);
         }
     } else {
-        /* The spec states "The cursor actually changes only if the input device focus is one of the
-         * requesting client's surfaces", so just clear the cursor if the seat has no pointer focus.
-         */
-        Wayland_CursorStateSetCursor(&seat->pointer.cursor_state, &obj, pointer_focus, seat->pointer.enter_serial, NULL);
+        Wayland_CursorStateResetCursor(&seat->pointer.cursor_state);
     }
 }
 
@@ -1536,18 +1547,22 @@ void Wayland_TabletToolUpdateCursor(SDL_WaylandPenTool *tool)
         .is_pointer = false
     };
 
-    if (tool_focus && mouse->cursor_visible) {
-        // Relative mode is only relevant if the tool sends pointer events.
-        const bool relative = mouse->pen_mouse_events && (tool_focus->sdlwindow->flags & SDL_WINDOW_MOUSE_RELATIVE_MODE);
+    if (tool_focus) {
+        if (mouse->cursor_visible) {
+            // Relative mode is only relevant if the tool sends pointer events.
+            const bool relative = mouse->pen_mouse_events && (tool_focus->sdlwindow->flags & SDL_WINDOW_MOUSE_RELATIVE_MODE);
 
-        if (!relative || !mouse->relative_mode_hide_cursor) {
-            Wayland_CursorStateSetCursor(&tool->cursor_state, &obj, tool_focus, tool->proximity_serial, mouse->cur_cursor);
+            if (!relative || !mouse->relative_mode_hide_cursor) {
+                Wayland_CursorStateSetCursor(&tool->cursor_state, &obj, tool_focus, tool->proximity_serial, mouse->cur_cursor);
+            } else {
+                // Hide the cursor in relative mode, unless requested otherwise by the hint.
+                Wayland_CursorStateSetCursor(&tool->cursor_state, &obj, tool_focus, tool->proximity_serial, NULL);
+            }
         } else {
-            // Hide the cursor in relative mode, unless requested otherwise by the hint.
             Wayland_CursorStateSetCursor(&tool->cursor_state, &obj, tool_focus, tool->proximity_serial, NULL);
         }
     } else {
-        Wayland_CursorStateSetCursor(&tool->cursor_state, &obj, tool_focus, tool->proximity_serial, NULL);
+        Wayland_CursorStateResetCursor(&tool->cursor_state);
     }
 }