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




commit 80daa7ad3846d41faf40b8ad6960bc58cb56315c
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 | 81 ++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 66 insertions(+), 15 deletions(-)
---
diff --git a/lib/bluetooth-client.c b/lib/bluetooth-client.c
index bd138c02..8a81d850 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 {
@@ -87,6 +89,8 @@ static guint signals[LAST_SIGNAL] = { 0 };
 
 G_DEFINE_TYPE(BluetoothClient, bluetooth_client, G_TYPE_OBJECT)
 
+#define DEVICE_REMOVAL_TIMEOUT_MSECS 50
+
 static void up_client_coldplug (BluetoothClient *client);
 
 static BluetoothDevice *
@@ -343,26 +347,60 @@ 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;
+               gboolean found = FALSE;
 
-               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;
+               g_debug ("Removing '%s' from queue of removed devices", path);
+
+               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);
+                               found = TRUE;
+                               break;
+                       }
                }
+               if (!found)
+                       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));
+       g_clear_handle_id (&client->removed_devices_queue_id, g_source_remove);
+       client->removed_devices_queue_id = g_timeout_add (DEVICE_REMOVAL_TIMEOUT_MSECS,
+                                                         (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, path);
 }
 
 static void
@@ -655,6 +693,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,9 +718,18 @@ 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);
+               client->removed_devices_queue = NULL;
+       }
+
        default_adapter_changed (manager,
                                 new_default_adapter,
-                                new_default_adapter ? NEW_DEFAULT : REMOVAL,
+                                change_type,
                                 client);
 
 out:
@@ -1209,6 +1257,9 @@ 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_list_free_full (client->removed_devices_queue, g_free);
+       client->removed_devices_queue = NULL;
        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]