diff options
author | Bastien Nocera <hadess@hadess.net> | 2022-02-23 18:38:56 +0100 |
---|---|---|
committer | Bastien Nocera <hadess@hadess.net> | 2022-02-24 21:41:59 +0100 |
commit | 80daa7ad3846d41faf40b8ad6960bc58cb56315c (patch) | |
tree | b56f8ae89fe503298ea1fbf98d5cf024f925b83f /lib | |
parent | 91aed3168ba5bc97881778539381313dda91b0db (diff) | |
download | gnome-bluetooth-80daa7ad3846d41faf40b8ad6960bc58cb56315c.tar.gz |
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
Diffstat (limited to 'lib')
-rw-r--r-- | lib/bluetooth-client.c | 81 |
1 files 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); |