[gnome-bluetooth/wip/hadess/fix-shell-menu: 4/5] lib: Merge device removal with adapter removal




commit a675f0902bc4c2b468fe60773c386ca204a8ba95
Author: Bastien Nocera <hadess hadess net>
Date:   Wed Feb 23 18:38:56 2022 +0100

    lib: Merge device removal with adapter removal
    
    When an adapter is removed while bluetoothd is still running (eg. not
    crashing as we also want to handle), suppress the emission of
    device-removed so that front-ends don't think that every device is
    removed.
    
    We implement this by queue device-removed signals until the next
    mainloop iteration instead of sending it straight away.
    
    Closes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/1426
    Closes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/5058

 lib/bluetooth-client.c | 69 ++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 55 insertions(+), 14 deletions(-)
---
diff --git a/lib/bluetooth-client.c b/lib/bluetooth-client.c
index bd138c02..64773333 100644
--- a/lib/bluetooth-client.c
+++ b/lib/bluetooth-client.c
@@ -65,6 +65,8 @@ struct _BluetoothClient {
        gboolean discovery_started;
        UpClient *up_client;
        gboolean bluez_devices_coldplugged;
+       GList *removed_devices_queue;
+       guint removed_devices_queue_id;
 };
 
 enum {
@@ -343,26 +345,55 @@ device_added (GDBusObjectManager   *manager,
        g_signal_emit (G_OBJECT (client), signals[DEVICE_ADDED], 0, device_obj);
 }
 
-static void
-device_removed (const char      *path,
-               BluetoothClient *client)
+static gboolean
+unqueue_device_removal (BluetoothClient *client)
 {
-       guint i, n_items;
+       GList *l;
 
-       g_debug ("Removing device '%s'", path);
+       if (!client->removed_devices_queue)
+               return G_SOURCE_REMOVE;
 
-       n_items = g_list_model_get_n_items (G_LIST_MODEL (client->list_store));
-       for (i = 0; i < n_items; i++) {
-               g_autoptr(BluetoothDevice) device = NULL;
+       for (l = client->removed_devices_queue; l != NULL; l = l->next) {
+               char *path = l->data;
+               guint i, n_items;
 
-               device = g_list_model_get_item (G_LIST_MODEL (client->list_store), i);
-               if (g_str_equal (path, bluetooth_device_get_object_path (device))) {
-                       g_signal_emit (G_OBJECT (client), signals[DEVICE_REMOVED], 0, path);
-                       g_list_store_remove (client->list_store, i);
-                       return;
+               n_items = g_list_model_get_n_items (G_LIST_MODEL (client->list_store));
+               for (i = 0; i < n_items; i++) {
+                       g_autoptr(BluetoothDevice) device = NULL;
+
+                       device = g_list_model_get_item (G_LIST_MODEL (client->list_store), i);
+                       if (g_str_equal (path, bluetooth_device_get_object_path (device))) {
+                               g_signal_emit (G_OBJECT (client), signals[DEVICE_REMOVED], 0, path);
+                               g_list_store_remove (client->list_store, i);
+                               g_free (path);
+                               continue;
+                       }
                }
+               g_debug ("Device %s was not known, so not removed", path);
+               g_free (path);
        }
-       g_debug ("Device %s was not known, so not removed", path);
+       g_clear_pointer (&client->removed_devices_queue, g_list_free);
+
+       client->removed_devices_queue_id = 0;
+       return G_SOURCE_REMOVE;
+}
+
+static void
+queue_device_removal (BluetoothClient *client,
+                     const char      *path)
+{
+       client->removed_devices_queue = g_list_prepend (client->removed_devices_queue,
+                                                       g_strdup (path));
+       client->removed_devices_queue_id = g_idle_add ((GSourceFunc) unqueue_device_removal, client);
+}
+
+static void
+device_removed (const char      *path,
+               BluetoothClient *client)
+{
+
+       g_debug ("Device '%s' was removed", path);
+       queue_device_removal (client, g_strdup (path));
 }
 
 static void
@@ -655,6 +686,7 @@ adapter_removed (GDBusObjectManager   *manager,
        g_autoptr(GDBusProxy) new_default_adapter = NULL;
        GList *object_list, *l;
        gboolean was_default = FALSE;
+       DefaultAdapterChangeType change_type;
 
        if (g_strcmp0 (path, g_dbus_proxy_get_object_path (G_DBUS_PROXY (client->default_adapter))) == 0)
                was_default = TRUE;
@@ -679,6 +711,14 @@ adapter_removed (GDBusObjectManager   *manager,
        }
        g_list_free_full (object_list, g_object_unref);
 
+       /* Removal? */
+       change_type = new_default_adapter ? NEW_DEFAULT : REMOVAL;
+       if (change_type == REMOVAL) {
+               /* Clear out the removed_devices queue */
+               g_clear_handle_id (&client->removed_devices_queue_id, g_source_remove);
+               g_list_free_full (client->removed_devices_queue, g_free);
+       }
+
        default_adapter_changed (manager,
                                 new_default_adapter,
                                 new_default_adapter ? NEW_DEFAULT : REMOVAL,
@@ -1209,6 +1249,7 @@ static void bluetooth_client_finalize(GObject *object)
                g_cancellable_cancel (client->cancellable);
                g_clear_object (&client->cancellable);
        }
+       g_clear_handle_id (&client->removed_devices_queue_id, g_source_remove);
        g_clear_object (&client->manager);
        g_object_unref (client->list_store);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]