summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorBastien Nocera <hadess@hadess.net>2022-02-23 18:38:56 +0100
committerBastien Nocera <hadess@hadess.net>2022-02-24 21:41:59 +0100
commit80daa7ad3846d41faf40b8ad6960bc58cb56315c (patch)
treeb56f8ae89fe503298ea1fbf98d5cf024f925b83f /lib
parent91aed3168ba5bc97881778539381313dda91b0db (diff)
downloadgnome-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.c81
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);