seat: Fix dangling focused_client in pointer 19/278119/1
authorSeunghun Lee <shiin.lee@samsung.com>
Mon, 11 Jul 2022 03:16:18 +0000 (12:16 +0900)
committerSooChan Lim <sc1.lim@samsung.com>
Mon, 18 Jul 2022 05:09:08 +0000 (14:09 +0900)
This patch handles destroy signal of focused_client of pointer, and
also contains a bit of refactoring.

Change-Id: I091f9b5d580ba6a36e51360d6757dfb434b03eab

src/seat/seat_pointer.c
src/seat/seat_private.h

index 2616756..dd9abcf 100644 (file)
@@ -10,11 +10,23 @@ static const struct wl_pointer_interface pointer_impl;
 
 static void seat_pointer_warp(struct ds_seat *seat, double sx, double sy);
 static void
+seat_client_send_pointer_enter_raw(struct ds_seat_client *seat_client,
+        struct ds_surface *surface, double sx, double sy);
+static void
 seat_client_send_pointer_leave_raw(struct ds_seat_client *seat_client,
         struct ds_surface *surface);
 static void
+seat_pointer_handle_client_destroy(struct wl_listener *listener, void *data);
+static void
 seat_pointer_handle_surface_destroy(struct wl_listener *listener,
         void *data);
+static void seat_pointer_clear_focus(struct ds_seat_pointer *pointer);
+static void seat_pointer_set_focus_surface(struct ds_seat_pointer *pointer,
+        struct ds_surface *surface, double sx, double sy);
+static void seat_pointer_unset_focus_surface(struct ds_seat_pointer *pointer);
+static void seat_pointer_emit_focus_change(struct ds_seat_pointer *pointer,
+        struct ds_surface *old_surface, struct ds_surface *new_surface,
+        double sx, double sy);
 static void pointer_handle_resource_destroy(struct wl_resource *resource);
 static void pointer_send_frame(struct wl_resource *resource);
 
@@ -142,69 +154,31 @@ ds_seat_pointer_enter(struct ds_seat *seat, struct ds_surface *surface,
         double sx, double sy)
 {
     struct ds_seat_pointer *pointer = &seat->pointer;
-    struct ds_seat_client *seat_client = NULL, *focused_client;
-    struct ds_surface *focused_surface;
-    struct wl_client *wl_client;
-    struct wl_resource *resource;
-    uint32_t serial;
+    struct ds_surface *focused_surface = pointer->focused_surface;
 
-    if (pointer->focused_surface == surface) {
+    if (focused_surface == surface) {
         // this surface already got an enter notify
         return;
     }
 
-    focused_client = pointer->focused_client;
-    focused_surface = pointer->focused_surface;
-
-    if (focused_client != NULL && focused_surface != NULL)
-        seat_client_send_pointer_leave_raw(focused_client, focused_surface);
+    seat_pointer_unset_focus_surface(pointer);
 
     if (surface) {
-        wl_client =
-            wl_resource_get_client(ds_surface_get_wl_resource(surface));
-        seat_client = seat_client_for_wl_client(seat, wl_client);
-    }
-
-    if (seat_client) {
-        serial = wl_display_next_serial(seat->display);
-        wl_resource_for_each(resource, &seat_client->pointers) {
-            wl_pointer_send_enter(resource, serial,
-                    ds_surface_get_wl_resource(surface),
-                    wl_fixed_from_double(sx), wl_fixed_from_double(sy));
-            pointer_send_frame(resource);
-        }
-    }
+        seat_pointer_set_focus_surface(pointer, surface, sx, sy);
 
-    wl_list_remove(&pointer->surface_destroy.link);
-    wl_list_init(&pointer->surface_destroy.link);
-
-    if (surface) {
-        pointer->surface_destroy.notify =
-            seat_pointer_handle_surface_destroy;
-        ds_surface_add_destroy_listener(surface, &pointer->surface_destroy);
-    }
-
-    pointer->focused_client = seat_client;
-    pointer->focused_surface = surface;
-    if (surface)
         seat_pointer_warp(seat, sx, sy);
-    else
+    }
+    else {
         seat_pointer_warp(seat, NAN, NAN);
+    }
 
-    struct ds_event_seat_pointer_focus_change event = {
-        .seat = seat,
-        .new_surface = surface,
-        .old_surface = focused_surface,
-        .sx = sx,
-        .sy = sy,
-    };
-    wl_signal_emit(&pointer->events.focus_change, &event);
+    seat_pointer_emit_focus_change(pointer, focused_surface, surface, sx, sy);
 }
 
 void
 ds_seat_pointer_clear_focus(struct ds_seat *seat)
 {
-    ds_seat_pointer_enter(seat, NULL, 0, 0);
+    seat_pointer_clear_focus(&seat->pointer);
 }
 
 void
@@ -326,6 +300,10 @@ seat_pointer_init(struct ds_seat *seat)
     pointer->grab = grab;
     pointer->seat = seat;
 
+    pointer->client_destroy.notify = seat_pointer_handle_client_destroy;
+    wl_list_init(&pointer->client_destroy.link);
+
+    pointer->surface_destroy.notify = seat_pointer_handle_surface_destroy;
     wl_list_init(&pointer->surface_destroy.link);
 
     wl_signal_init(&pointer->events.focus_change);
@@ -338,7 +316,12 @@ seat_pointer_finish(struct ds_seat *seat)
 {
     struct ds_seat_pointer *pointer = &seat->pointer;
 
-    wl_list_remove(&pointer->surface_destroy.link);
+    if (pointer->focused_client)
+        wl_list_remove(&pointer->client_destroy.link);
+
+    if (pointer->focused_surface)
+        wl_list_remove(&pointer->surface_destroy.link);
+
     free(pointer->default_grab);
 }
 
@@ -385,6 +368,22 @@ seat_pointer_warp(struct ds_seat *seat, double sx, double sy)
 }
 
 static void
+seat_client_send_pointer_enter_raw(struct ds_seat_client *seat_client,
+        struct ds_surface *surface, double sx, double sy)
+{
+    struct wl_resource *resource;
+    uint32_t serial;
+
+    serial = wl_display_next_serial(seat_client->seat->display);
+    wl_resource_for_each(resource, &seat_client->pointers) {
+        wl_pointer_send_enter(resource, serial,
+                ds_surface_get_wl_resource(surface),
+                wl_fixed_from_double(sx), wl_fixed_from_double(sy));
+        pointer_send_frame(resource);
+    }
+}
+
+static void
 seat_client_send_pointer_leave_raw(struct ds_seat_client *seat_client,
         struct ds_surface *surface)
 {
@@ -400,14 +399,92 @@ seat_client_send_pointer_leave_raw(struct ds_seat_client *seat_client,
 }
 
 static void
+seat_pointer_handle_client_destroy(struct wl_listener *listener, void *data)
+{
+    struct ds_seat_pointer *pointer;
+
+    pointer = wl_container_of(listener, pointer, client_destroy);
+
+    wl_list_remove(&pointer->client_destroy.link);
+    pointer->focused_client = NULL;
+}
+
+static void
 seat_pointer_handle_surface_destroy(struct wl_listener *listener, void *data)
 {
     struct ds_seat_pointer *pointer;
 
     pointer = wl_container_of(listener, pointer, surface_destroy);
-    wl_list_remove(&pointer->surface_destroy.link);
-    wl_list_init(&pointer->surface_destroy.link);
-    ds_seat_pointer_clear_focus(pointer->seat);
+
+    seat_pointer_clear_focus(pointer);
+}
+
+static void
+seat_pointer_clear_focus(struct ds_seat_pointer *pointer)
+{
+    struct ds_surface *focused_surface = pointer->focused_surface;
+
+    seat_pointer_unset_focus_surface(pointer);
+
+    seat_pointer_warp(pointer->seat, NAN, NAN);
+
+    if (focused_surface)
+        seat_pointer_emit_focus_change(pointer, focused_surface, NULL, 0, 0);
+}
+
+static void
+seat_pointer_set_focus_surface(struct ds_seat_pointer *pointer,
+        struct ds_surface *surface, double sx, double sy)
+{
+    struct ds_seat *seat = pointer->seat;
+    struct ds_seat_client *seat_client;
+
+    seat_client = seat_client_from_surface(seat, surface);
+    if (seat_client) {
+        seat_client_send_pointer_enter_raw(seat_client, surface, sx, sy);
+
+        wl_signal_add(&seat_client->events.destroy, &pointer->client_destroy);
+
+        pointer->focused_client = seat_client;
+    }
+
+    ds_surface_add_destroy_listener(surface, &pointer->surface_destroy);
+
+    pointer->focused_surface = surface;
+}
+
+static void
+seat_pointer_unset_focus_surface(struct ds_seat_pointer *pointer)
+{
+    struct ds_seat_client *focused_client = pointer->focused_client;
+    struct ds_surface *focused_surface = pointer->focused_surface;
+
+    if (focused_client)
+        wl_list_remove(&pointer->client_destroy.link);
+
+    if (focused_surface)
+        wl_list_remove(&pointer->surface_destroy.link);
+
+    if (focused_client != NULL && focused_surface != NULL)
+        seat_client_send_pointer_leave_raw(focused_client, focused_surface);
+
+    pointer->focused_client = NULL;
+    pointer->focused_surface = NULL;
+}
+
+static void
+seat_pointer_emit_focus_change(struct ds_seat_pointer *pointer,
+        struct ds_surface *old_surface, struct ds_surface *new_surface,
+        double sx, double sy)
+{
+    struct ds_event_seat_pointer_focus_change event = {
+        .seat = pointer->seat,
+        .new_surface = new_surface,
+        .old_surface = old_surface,
+        .sx = sx,
+        .sy = sy,
+    };
+    wl_signal_emit(&pointer->events.focus_change, &event);
 }
 
 static void
index 0a5cf84..0211a72 100644 (file)
@@ -47,6 +47,7 @@ struct ds_seat_pointer
     uint32_t grab_serial;
     uint32_t grab_time;
 
+    struct wl_listener client_destroy;
     struct wl_listener surface_destroy;
 
     struct {