diff --git a/.gitignore b/.gitignore index fa6bb83..cd652d4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /gnome-control-center-3.28.1.tar.xz /gnome-control-center-3.28.2.tar.xz +/gnome-control-center-3.29.90.tar.xz diff --git a/0001-shell-Don-t-set-per-panel-icon.patch b/0001-shell-Don-t-set-per-panel-icon.patch deleted file mode 100644 index ff593da..0000000 --- a/0001-shell-Don-t-set-per-panel-icon.patch +++ /dev/null @@ -1,47 +0,0 @@ -From ec695fae92ef7470ef05211160e431f5c3486299 Mon Sep 17 00:00:00 2001 -From: Christian Kellner -Date: Tue, 10 Apr 2018 09:43:22 +0200 -Subject: [PATCH 1/4] shell: Don't set per-panel icon - -The control center app is considered one single application with -a single icon to represent it. Therefore get rid of per-panel -icons. ---- - shell/cc-window.c | 7 +------ - 1 file changed, 1 insertion(+), 6 deletions(-) - -diff --git a/shell/cc-window.c b/shell/cc-window.c -index 557819e0c76c..33f1ddcad511 100644 ---- a/shell/cc-window.c -+++ b/shell/cc-window.c -@@ -118,7 +118,6 @@ activate_panel (CcWindow *self, - GIcon *gicon) - { - GtkWidget *box, *title_widget; -- const gchar *icon_name; - - if (!id) - return FALSE; -@@ -144,12 +143,8 @@ activate_panel (CcWindow *self, - gtk_stack_set_visible_child_name (GTK_STACK (self->stack), id); - - /* set the title of the window */ -- icon_name = get_icon_name_from_g_icon (gicon); -- - gtk_window_set_role (GTK_WINDOW (self), id); - gtk_header_bar_set_title (GTK_HEADER_BAR (self->panel_headerbar), name); -- gtk_window_set_default_icon_name (icon_name); -- gtk_window_set_icon_name (GTK_WINDOW (self), icon_name); - - title_widget = cc_panel_get_title_widget (CC_PANEL (self->current_panel)); - gtk_header_bar_set_custom_title (GTK_HEADER_BAR (self->panel_headerbar), title_widget); -@@ -778,4 +773,4 @@ cc_window_set_search_item (CcWindow *center, - gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (center->search_bar), TRUE); - gtk_entry_set_text (GTK_ENTRY (center->search_entry), search); - gtk_editable_set_position (GTK_EDITABLE (center->search_entry), -1); --} -\ No newline at end of file -+} --- -2.17.0 - diff --git a/0002-shell-Icon-name-helper-returns-symbolic-name.patch b/0002-shell-Icon-name-helper-returns-symbolic-name.patch deleted file mode 100644 index d9aa722..0000000 --- a/0002-shell-Icon-name-helper-returns-symbolic-name.patch +++ /dev/null @@ -1,78 +0,0 @@ -From b24a8e9aa82b64de970d8137181bf8a03b6f724a Mon Sep 17 00:00:00 2001 -From: Christian Kellner -Date: Tue, 10 Apr 2018 09:47:48 +0200 -Subject: [PATCH 2/4] shell: Icon name helper returns symbolic name - -The helper function to get the icon name from a GIcon directly -returns the symbolic icon now. This makes it in turn possible -to also directly check if the theme has the icon with the symbolic -name instead of checking of for the full colored one and then -deriving the symbolic name from that. The latter (old) practice -will fail if there is a symbolic icon in the theme that has no -full color icon (like e.g. thunderbolt). ---- - shell/cc-window.c | 19 ++++++++++--------- - 1 file changed, 10 insertions(+), 9 deletions(-) - -diff --git a/shell/cc-window.c b/shell/cc-window.c -index 33f1ddcad511..3af9cf0bd9fc 100644 ---- a/shell/cc-window.c -+++ b/shell/cc-window.c -@@ -88,8 +88,8 @@ enum - }; - - /* Auxiliary methods */ --static const gchar * --get_icon_name_from_g_icon (GIcon *gicon) -+static gchar * -+get_symbolic_icon_name_from_g_icon (GIcon *gicon) - { - const gchar * const *names; - GtkIconTheme *icon_theme; -@@ -103,8 +103,11 @@ get_icon_name_from_g_icon (GIcon *gicon) - - for (i = 0; names[i] != NULL; i++) - { -- if (gtk_icon_theme_has_icon (icon_theme, names[i])) -- return names[i]; -+ g_autofree gchar *name = NULL; -+ name = g_strdup_printf ("%s-symbolic", names[i]); -+ -+ if (gtk_icon_theme_has_icon (icon_theme, name)) -+ return g_steal_pointer (&name); - } - - return NULL; -@@ -248,9 +251,8 @@ setup_model (CcWindow *shell) - g_autofree gchar *name = NULL; - g_autofree gchar *description = NULL; - g_autofree gchar *id = NULL; -- g_autofree gchar *symbolic_icon = NULL; -+ g_autofree gchar *icon_name = NULL; - g_autofree GStrv keywords = NULL; -- const gchar *icon_name; - - gtk_tree_model_get (model, &iter, - COL_CATEGORY, &category, -@@ -261,8 +263,7 @@ setup_model (CcWindow *shell) - COL_KEYWORDS, &keywords, - -1); - -- icon_name = get_icon_name_from_g_icon (icon); -- symbolic_icon = g_strdup_printf ("%s-symbolic", icon_name); -+ icon_name = get_symbolic_icon_name_from_g_icon (icon); - - cc_panel_list_add_panel (CC_PANEL_LIST (shell->panel_list), - category, -@@ -270,7 +271,7 @@ setup_model (CcWindow *shell) - name, - description, - keywords, -- symbolic_icon); -+ icon_name); - - valid = gtk_tree_model_iter_next (model, &iter); - } --- -2.17.0 - diff --git a/0003-thunderbolt-new-panel-for-device-management.patch b/0003-thunderbolt-new-panel-for-device-management.patch deleted file mode 100644 index 7aea82c..0000000 --- a/0003-thunderbolt-new-panel-for-device-management.patch +++ /dev/null @@ -1,6388 +0,0 @@ -From 3d9ad5e5657059e054f011d65e3f81b3723b41a5 Mon Sep 17 00:00:00 2001 -From: Christian Kellner -Date: Mon, 26 Mar 2018 16:18:30 +0200 -Subject: [PATCH 3/4] thunderbolt: new panel for device management - -Thunderbolt devices need to be approved before they can be used. -This is done via the boltd system daemon and gnome-shell. The new -panel enables the user to manage thunderbolt devices, i.e.: - - - forget devices that have previously been authorized - - authorize currently unauthorize devices - -Additionally authorization of devices an be temporarily disabled -to ensure no evil device will gain access to the computers -resources. - -File starting with "bolt-" are copied from bolt's source tree -and currently correspond to the bolt upstream commit with the id -f22b1cd6104bdc2b33a95d9896b50f29a141b8d8 -They can be updated from bolt via the update-from-bolt.sh script. ---- - meson.build | 3 + - panels/meson.build | 1 + - panels/thunderbolt/bolt-client.c | 697 +++++++++++++ - panels/thunderbolt/bolt-client.h | 107 ++ - panels/thunderbolt/bolt-device.c | 604 +++++++++++ - panels/thunderbolt/bolt-device.h | 87 ++ - panels/thunderbolt/bolt-enums.c | 395 ++++++++ - panels/thunderbolt/bolt-enums.h | 249 +++++ - panels/thunderbolt/bolt-error.c | 99 ++ - panels/thunderbolt/bolt-error.h | 55 + - panels/thunderbolt/bolt-names.h | 50 + - panels/thunderbolt/bolt-proxy.c | 514 ++++++++++ - panels/thunderbolt/bolt-proxy.h | 97 ++ - panels/thunderbolt/bolt-str.c | 117 +++ - panels/thunderbolt/bolt-str.h | 43 + - panels/thunderbolt/bolt-time.c | 44 + - panels/thunderbolt/bolt-time.h | 32 + - panels/thunderbolt/cc-bolt-device-dialog.c | 476 +++++++++ - panels/thunderbolt/cc-bolt-device-dialog.h | 45 + - panels/thunderbolt/cc-bolt-device-dialog.ui | 359 +++++++ - panels/thunderbolt/cc-bolt-device-entry.c | 218 ++++ - panels/thunderbolt/cc-bolt-device-entry.h | 34 + - panels/thunderbolt/cc-bolt-device-entry.ui | 49 + - panels/thunderbolt/cc-bolt-panel.c | 958 ++++++++++++++++++ - panels/thunderbolt/cc-bolt-panel.ui | 594 +++++++++++ - .../gnome-thunderbolt-panel.desktop.in.in | 17 + - panels/thunderbolt/meson.build | 74 ++ - panels/thunderbolt/thunderbolt.gresource.xml | 9 + - panels/thunderbolt/update-from-bolt.sh | 50 + - shell/cc-panel-list.c | 1 + - shell/cc-panel-loader.c | 6 + - 31 files changed, 6084 insertions(+) - create mode 100644 panels/thunderbolt/bolt-client.c - create mode 100644 panels/thunderbolt/bolt-client.h - create mode 100644 panels/thunderbolt/bolt-device.c - create mode 100644 panels/thunderbolt/bolt-device.h - create mode 100644 panels/thunderbolt/bolt-enums.c - create mode 100644 panels/thunderbolt/bolt-enums.h - create mode 100644 panels/thunderbolt/bolt-error.c - create mode 100644 panels/thunderbolt/bolt-error.h - create mode 100644 panels/thunderbolt/bolt-names.h - create mode 100644 panels/thunderbolt/bolt-proxy.c - create mode 100644 panels/thunderbolt/bolt-proxy.h - create mode 100644 panels/thunderbolt/bolt-str.c - create mode 100644 panels/thunderbolt/bolt-str.h - create mode 100644 panels/thunderbolt/bolt-time.c - create mode 100644 panels/thunderbolt/bolt-time.h - create mode 100644 panels/thunderbolt/cc-bolt-device-dialog.c - create mode 100644 panels/thunderbolt/cc-bolt-device-dialog.h - create mode 100644 panels/thunderbolt/cc-bolt-device-dialog.ui - create mode 100644 panels/thunderbolt/cc-bolt-device-entry.c - create mode 100644 panels/thunderbolt/cc-bolt-device-entry.h - create mode 100644 panels/thunderbolt/cc-bolt-device-entry.ui - create mode 100644 panels/thunderbolt/cc-bolt-panel.c - create mode 100644 panels/thunderbolt/cc-bolt-panel.ui - create mode 100644 panels/thunderbolt/gnome-thunderbolt-panel.desktop.in.in - create mode 100644 panels/thunderbolt/meson.build - create mode 100644 panels/thunderbolt/thunderbolt.gresource.xml - create mode 100755 panels/thunderbolt/update-from-bolt.sh - -diff --git a/meson.build b/meson.build -index 90ee21cb0f39..ab0e91af627a 100644 ---- a/meson.build -+++ b/meson.build -@@ -203,6 +203,7 @@ if host_is_linux_not_s390 - description: 'Define to 1 if libwacom provides definition for 3D styli') - else - message('Bluetooth and Wacom panels will not be built (no USB support on this platform)') -+ message('Thunderbolt panel will not be built (not supported on this platform)') - endif - config_h.set('BUILD_BLUETOOTH', host_is_linux_not_s390, - description: 'Define to 1 to build the Bluetooth panel') -@@ -212,6 +213,8 @@ config_h.set('BUILD_WACOM', host_is_linux_not_s390, - description: 'Define to 1 to build the Wacom panel') - config_h.set('HAVE_WACOM', host_is_linux_not_s390, - description: 'Define to 1 if Wacom is supportted') -+config_h.set('BUILD_THUNDERBOLT', host_is_linux_not_s390, -+ description: 'Define to 1 to build the Thunderbolt panel') - - # Check for info panel - gnome_session_libexecdir = get_option('gnome_session_libexecdir') -diff --git a/panels/meson.build b/panels/meson.build -index d671c4775736..37a343642218 100644 ---- a/panels/meson.build -+++ b/panels/meson.build -@@ -28,6 +28,7 @@ endif - if host_is_linux_not_s390 - panels += [ - 'bluetooth', -+ 'thunderbolt', - 'wacom' - ] - endif -diff --git a/panels/thunderbolt/bolt-client.c b/panels/thunderbolt/bolt-client.c -new file mode 100644 -index 000000000000..0ebc360b18ff ---- /dev/null -+++ b/panels/thunderbolt/bolt-client.c -@@ -0,0 +1,697 @@ -+/* -+ * Copyright © 2017 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library. If not, see . -+ * -+ * Authors: -+ * Christian J. Kellner -+ */ -+ -+#include "bolt-client.h" -+ -+#include "bolt-device.h" -+#include "bolt-error.h" -+#include "bolt-names.h" -+ -+#include -+ -+static void handle_dbus_device_added (GObject *self, -+ GDBusProxy *bus_proxy, -+ GVariant *params); -+static void handle_dbus_device_removed (GObject *self, -+ GDBusProxy *bus_proxy, -+ GVariant *params); -+ -+struct _BoltClient -+{ -+ BoltProxy parent; -+}; -+ -+enum { -+ PROP_0, -+ -+ /* D-Bus Props */ -+ PROP_VERSION, -+ PROP_PROBING, -+ PROP_SECURITY, -+ PROP_AUTHMODE, -+ -+ PROP_LAST -+}; -+ -+static GParamSpec *props[PROP_LAST] = {NULL, }; -+ -+enum { -+ SIGNAL_DEVICE_ADDED, -+ SIGNAL_DEVICE_REMOVED, -+ SIGNAL_LAST -+}; -+ -+static guint signals[SIGNAL_LAST] = {0}; -+ -+ -+G_DEFINE_TYPE (BoltClient, -+ bolt_client, -+ BOLT_TYPE_PROXY); -+ -+ -+static void -+bolt_client_get_property (GObject *object, -+ guint prop_id, -+ GValue *value, -+ GParamSpec *pspec) -+{ -+ if (bolt_proxy_get_dbus_property (object, pspec, value)) -+ return; -+ -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -+} -+ -+static const BoltProxySignal * -+bolt_client_get_dbus_signals (guint *n) -+{ -+ static BoltProxySignal dbus_signals[] = { -+ {"DeviceAdded", handle_dbus_device_added}, -+ {"DeviceRemoved", handle_dbus_device_removed}, -+ }; -+ -+ *n = G_N_ELEMENTS (dbus_signals); -+ -+ return dbus_signals; -+} -+ -+ -+static void -+bolt_client_class_init (BoltClientClass *klass) -+{ -+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass); -+ BoltProxyClass *proxy_class = BOLT_PROXY_CLASS (klass); -+ -+ gobject_class->get_property = bolt_client_get_property; -+ -+ proxy_class->get_dbus_signals = bolt_client_get_dbus_signals; -+ -+ props[PROP_VERSION] -+ = g_param_spec_uint ("version", -+ "Version", NULL, -+ 0, G_MAXUINT, 0, -+ G_PARAM_READABLE | -+ G_PARAM_STATIC_NAME); -+ -+ props[PROP_PROBING] -+ = g_param_spec_boolean ("probing", -+ "Probing", NULL, -+ FALSE, -+ G_PARAM_READABLE | -+ G_PARAM_STATIC_NAME); -+ -+ props[PROP_SECURITY] -+ = g_param_spec_enum ("security-level", -+ "SecurityLevel", NULL, -+ BOLT_TYPE_SECURITY, -+ BOLT_SECURITY_UNKNOWN, -+ G_PARAM_READABLE | -+ G_PARAM_STATIC_NAME); -+ -+ props[PROP_AUTHMODE] = -+ g_param_spec_flags ("auth-mode", "AuthMode", NULL, -+ BOLT_TYPE_AUTH_MODE, -+ BOLT_AUTH_ENABLED, -+ G_PARAM_READABLE | -+ G_PARAM_STATIC_STRINGS); -+ -+ g_object_class_install_properties (gobject_class, -+ PROP_LAST, -+ props); -+ -+ /* signals */ -+ signals[SIGNAL_DEVICE_ADDED] = -+ g_signal_new ("device-added", -+ G_TYPE_FROM_CLASS (gobject_class), -+ G_SIGNAL_RUN_LAST, -+ 0, -+ NULL, NULL, -+ NULL, -+ G_TYPE_NONE, -+ 1, G_TYPE_STRING); -+ -+ signals[SIGNAL_DEVICE_REMOVED] = -+ g_signal_new ("device-removed", -+ G_TYPE_FROM_CLASS (gobject_class), -+ G_SIGNAL_RUN_LAST, -+ 0, -+ NULL, NULL, -+ NULL, -+ G_TYPE_NONE, -+ 1, G_TYPE_STRING); -+} -+ -+ -+static void -+bolt_client_init (BoltClient *cli) -+{ -+} -+ -+/* dbus signals */ -+ -+static void -+handle_dbus_device_added (GObject *self, GDBusProxy *bus_proxy, GVariant *params) -+{ -+ BoltClient *cli = BOLT_CLIENT (self); -+ const char *opath = NULL; -+ -+ g_variant_get_child (params, 0, "&o", &opath); -+ g_signal_emit (cli, signals[SIGNAL_DEVICE_ADDED], 0, opath); -+} -+ -+static void -+handle_dbus_device_removed (GObject *self, GDBusProxy *bus_proxy, GVariant *params) -+{ -+ BoltClient *cli = BOLT_CLIENT (self); -+ const char *opath = NULL; -+ -+ g_variant_get_child (params, 0, "&o", &opath); -+ g_signal_emit (cli, signals[SIGNAL_DEVICE_REMOVED], 0, opath); -+} -+ -+/* public methods */ -+ -+BoltClient * -+bolt_client_new (GError **error) -+{ -+ BoltClient *cli; -+ GDBusConnection *bus; -+ -+ bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); -+ if (bus == NULL) -+ { -+ g_prefix_error (error, "Error connecting to D-Bus: "); -+ return FALSE; -+ } -+ -+ cli = g_initable_new (BOLT_TYPE_CLIENT, -+ NULL, error, -+ "g-flags", G_DBUS_PROXY_FLAGS_NONE, -+ "g-connection", bus, -+ "g-name", BOLT_DBUS_NAME, -+ "g-object-path", BOLT_DBUS_PATH, -+ "g-interface-name", BOLT_DBUS_INTERFACE, -+ NULL); -+ -+ g_object_unref (bus); -+ -+ return cli; -+} -+ -+static void -+got_the_client (GObject *source, -+ GAsyncResult *res, -+ gpointer user_data) -+{ -+ g_autoptr(GError) error = NULL; -+ GTask *task = user_data; -+ GObject *obj; -+ -+ obj = g_async_initable_new_finish (G_ASYNC_INITABLE (source), res, &error); -+ -+ if (obj == NULL) -+ { -+ g_task_return_error (task, error); -+ return; -+ } -+ -+ g_task_return_pointer (task, obj, g_object_unref); -+ g_object_unref (task); -+} -+ -+static void -+got_the_bus (GObject *source, -+ GAsyncResult *res, -+ gpointer user_data) -+{ -+ g_autoptr(GError) error = NULL; -+ GTask *task = user_data; -+ GCancellable *cancellable; -+ GDBusConnection *bus; -+ -+ bus = g_bus_get_finish (res, &error); -+ if (bus == NULL) -+ { -+ g_prefix_error (&error, "could not connect to D-Bus: "); -+ g_task_return_error (task, error); -+ return; -+ } -+ -+ cancellable = g_task_get_cancellable (task); -+ g_async_initable_new_async (BOLT_TYPE_CLIENT, -+ G_PRIORITY_DEFAULT, -+ cancellable, -+ got_the_client, task, -+ "g-flags", G_DBUS_PROXY_FLAGS_NONE, -+ "g-connection", bus, -+ "g-name", BOLT_DBUS_NAME, -+ "g-object-path", BOLT_DBUS_PATH, -+ "g-interface-name", BOLT_DBUS_INTERFACE, -+ NULL); -+ g_object_unref (bus); -+} -+ -+void -+bolt_client_new_async (GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ GTask *task; -+ -+ task = g_task_new (NULL, cancellable, callback, user_data); -+ g_bus_get (G_BUS_TYPE_SYSTEM, cancellable, got_the_bus, task); -+} -+ -+BoltClient * -+bolt_client_new_finish (GAsyncResult *res, -+ GError **error) -+{ -+ g_return_val_if_fail (G_IS_TASK (res), NULL); -+ -+ return g_task_propagate_pointer (G_TASK (res), error); -+} -+ -+GPtrArray * -+bolt_client_list_devices (BoltClient *client, -+ GCancellable *cancel, -+ GError **error) -+{ -+ g_autoptr(GVariant) val = NULL; -+ g_autoptr(GPtrArray) devices = NULL; -+ g_autoptr(GVariantIter) iter = NULL; -+ GDBusConnection *bus = NULL; -+ const char *d; -+ -+ g_return_val_if_fail (BOLT_IS_CLIENT (client), NULL); -+ -+ val = g_dbus_proxy_call_sync (G_DBUS_PROXY (client), -+ "ListDevices", -+ NULL, -+ G_DBUS_CALL_FLAGS_NONE, -+ -1, -+ cancel, -+ error); -+ if (val == NULL) -+ return NULL; -+ -+ bus = g_dbus_proxy_get_connection (G_DBUS_PROXY (client)); -+ -+ devices = g_ptr_array_new_with_free_func (g_object_unref); -+ -+ g_variant_get (val, "(ao)", &iter); -+ while (g_variant_iter_loop (iter, "&o", &d, NULL)) -+ { -+ BoltDevice *dev; -+ -+ dev = bolt_device_new_for_object_path (bus, d, cancel, error); -+ if (dev == NULL) -+ return NULL; -+ -+ g_ptr_array_add (devices, dev); -+ } -+ -+ return g_steal_pointer (&devices); -+} -+ -+BoltDevice * -+bolt_client_get_device (BoltClient *client, -+ const char *uid, -+ GCancellable *cancel, -+ GError **error) -+{ -+ g_autoptr(GVariant) val = NULL; -+ g_autoptr(GError) err = NULL; -+ BoltDevice *dev = NULL; -+ GDBusConnection *bus = NULL; -+ const char *opath = NULL; -+ -+ g_return_val_if_fail (BOLT_IS_CLIENT (client), NULL); -+ -+ val = g_dbus_proxy_call_sync (G_DBUS_PROXY (client), -+ "DeviceByUid", -+ g_variant_new ("(s)", uid), -+ G_DBUS_CALL_FLAGS_NONE, -+ -1, -+ cancel, -+ &err); -+ -+ if (val == NULL) -+ { -+ bolt_error_propagate_stripped (error, &err); -+ return NULL; -+ } -+ -+ bus = g_dbus_proxy_get_connection (G_DBUS_PROXY (client)); -+ g_variant_get (val, "(&o)", &opath); -+ -+ if (opath == NULL) -+ return NULL; -+ -+ dev = bolt_device_new_for_object_path (bus, opath, cancel, error); -+ return dev; -+} -+ -+BoltDevice * -+bolt_client_enroll_device (BoltClient *client, -+ const char *uid, -+ BoltPolicy policy, -+ BoltAuthCtrl flags, -+ GError **error) -+{ -+ g_autoptr(GVariant) val = NULL; -+ g_autoptr(GError) err = NULL; -+ g_autofree char *fstr = NULL; -+ BoltDevice *dev = NULL; -+ GDBusConnection *bus = NULL; -+ GVariant *params = NULL; -+ const char *opath = NULL; -+ const char *pstr; -+ -+ g_return_val_if_fail (BOLT_IS_CLIENT (client), NULL); -+ -+ pstr = bolt_enum_to_string (BOLT_TYPE_POLICY, policy, error); -+ if (pstr == NULL) -+ return NULL; -+ -+ fstr = bolt_flags_to_string (BOLT_TYPE_AUTH_CTRL, flags, error); -+ if (fstr == NULL) -+ return NULL; -+ -+ params = g_variant_new ("(sss)", uid, pstr, fstr); -+ val = g_dbus_proxy_call_sync (G_DBUS_PROXY (client), -+ "EnrollDevice", -+ params, -+ G_DBUS_CALL_FLAGS_NONE, -+ -1, -+ NULL, -+ &err); -+ -+ if (val == NULL) -+ { -+ bolt_error_propagate_stripped (error, &err); -+ return NULL; -+ } -+ -+ bus = g_dbus_proxy_get_connection (G_DBUS_PROXY (client)); -+ g_variant_get (val, "(&o)", &opath); -+ -+ if (opath == NULL) -+ return NULL; -+ -+ dev = bolt_device_new_for_object_path (bus, opath, NULL, error); -+ return dev; -+} -+ -+void -+bolt_client_enroll_device_async (BoltClient *client, -+ const char *uid, -+ BoltPolicy policy, -+ BoltAuthCtrl flags, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ g_autofree char *fstr = NULL; -+ GError *err = NULL; -+ GVariant *params; -+ const char *pstr; -+ -+ g_return_if_fail (BOLT_IS_CLIENT (client)); -+ g_return_if_fail (uid != NULL); -+ -+ pstr = bolt_enum_to_string (BOLT_TYPE_POLICY, policy, &err); -+ if (pstr == NULL) -+ { -+ g_task_report_error (client, callback, user_data, NULL, err); -+ return; -+ } -+ -+ fstr = bolt_flags_to_string (BOLT_TYPE_AUTH_CTRL, flags, &err); -+ if (fstr == NULL) -+ { -+ g_task_report_error (client, callback, user_data, NULL, err); -+ return; -+ } -+ -+ params = g_variant_new ("(sss)", uid, pstr, fstr); -+ g_dbus_proxy_call (G_DBUS_PROXY (client), -+ "EnrollDevice", -+ params, -+ G_DBUS_CALL_FLAGS_NONE, -+ -1, -+ cancellable, -+ callback, -+ user_data); -+} -+ -+gboolean -+bolt_client_enroll_device_finish (BoltClient *client, -+ GAsyncResult *res, -+ char **path, -+ GError **error) -+{ -+ GVariant *val = NULL; -+ -+ g_autoptr(GError) err = NULL; -+ -+ g_return_val_if_fail (BOLT_IS_CLIENT (client), FALSE); -+ -+ val = g_dbus_proxy_call_finish (G_DBUS_PROXY (client), res, &err); -+ if (val == NULL) -+ { -+ bolt_error_propagate_stripped (error, &err); -+ return FALSE; -+ } -+ -+ if (path != NULL) -+ g_variant_get (val, "(o)", path); -+ -+ return TRUE; -+} -+ -+gboolean -+bolt_client_forget_device (BoltClient *client, -+ const char *uid, -+ GError **error) -+{ -+ g_autoptr(GVariant) val = NULL; -+ g_autoptr(GError) err = NULL; -+ -+ g_return_val_if_fail (BOLT_IS_CLIENT (client), FALSE); -+ -+ val = g_dbus_proxy_call_sync (G_DBUS_PROXY (client), -+ "ForgetDevice", -+ g_variant_new ("(s)", uid), -+ G_DBUS_CALL_FLAGS_NONE, -+ -1, -+ NULL, -+ &err); -+ -+ if (val == NULL) -+ { -+ bolt_error_propagate_stripped (error, &err); -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+void -+bolt_client_forget_device_async (BoltClient *client, -+ const char *uid, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ g_return_if_fail (BOLT_IS_CLIENT (client)); -+ -+ g_dbus_proxy_call (G_DBUS_PROXY (client), -+ "ForgetDevice", -+ g_variant_new ("(s)", uid), -+ G_DBUS_CALL_FLAGS_NONE, -+ -1, -+ cancellable, -+ callback, -+ user_data); -+} -+ -+gboolean -+bolt_client_forget_device_finish (BoltClient *client, -+ GAsyncResult *res, -+ GError **error) -+{ -+ g_autoptr(GVariant) val = NULL; -+ g_autoptr(GError) err = NULL; -+ -+ g_return_val_if_fail (BOLT_IS_CLIENT (client), FALSE); -+ -+ val = g_dbus_proxy_call_finish (G_DBUS_PROXY (client), res, &err); -+ if (val == NULL) -+ { -+ bolt_error_propagate_stripped (error, &err); -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+/* getter */ -+guint -+bolt_client_get_version (BoltClient *client) -+{ -+ const char *key; -+ guint val = 0; -+ gboolean ok; -+ -+ g_return_val_if_fail (BOLT_IS_CLIENT (client), val); -+ -+ key = g_param_spec_get_name (props[PROP_VERSION]); -+ ok = bolt_proxy_get_property_uint32 (BOLT_PROXY (client), key, &val); -+ -+ if (!ok) -+ g_warning ("failed to get property '%s'", key); -+ -+ return val; -+} -+ -+gboolean -+bolt_client_is_probing (BoltClient *client) -+{ -+ const char *key; -+ gboolean val = FALSE; -+ gboolean ok; -+ -+ g_return_val_if_fail (BOLT_IS_CLIENT (client), val); -+ -+ key = g_param_spec_get_name (props[PROP_PROBING]); -+ ok = bolt_proxy_get_property_bool (BOLT_PROXY (client), key, &val); -+ -+ if (!ok) -+ g_warning ("failed to get enum property '%s'", key); -+ -+ return val; -+} -+ -+BoltSecurity -+bolt_client_get_security (BoltClient *client) -+{ -+ const char *key; -+ gboolean ok; -+ gint val = BOLT_SECURITY_UNKNOWN; -+ -+ g_return_val_if_fail (BOLT_IS_CLIENT (client), val); -+ -+ key = g_param_spec_get_name (props[PROP_SECURITY]); -+ ok = bolt_proxy_get_property_enum (BOLT_PROXY (client), key, &val); -+ -+ if (!ok) -+ g_warning ("failed to get enum property '%s'", key); -+ -+ return val; -+} -+ -+BoltAuthMode -+bolt_client_get_authmode (BoltClient *client) -+{ -+ const char *key; -+ gboolean ok; -+ guint val = BOLT_AUTH_DISABLED; -+ -+ g_return_val_if_fail (BOLT_IS_CLIENT (client), val); -+ -+ key = g_param_spec_get_name (props[PROP_AUTHMODE]); -+ ok = bolt_proxy_get_property_flags (BOLT_PROXY (client), key, &val); -+ -+ if (!ok) -+ g_warning ("failed to get enum property '%s'", key); -+ -+ return val; -+} -+ -+void -+bolt_client_set_authmode_async (BoltClient *client, -+ BoltAuthMode mode, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ g_autofree char *str = NULL; -+ GError *err = NULL; -+ GParamSpec *pspec; -+ GParamSpecFlags *flags_pspec; -+ GFlagsClass *flags_class; -+ -+ pspec = props[PROP_AUTHMODE]; -+ flags_pspec = G_PARAM_SPEC_FLAGS (pspec); -+ flags_class = flags_pspec->flags_class; -+ str = bolt_flags_class_to_string (flags_class, mode, &err); -+ -+ if (str == NULL) -+ { -+ g_task_report_error (client, callback, user_data, NULL, err); -+ return; -+ } -+ -+ bolt_proxy_set_property_async (BOLT_PROXY (client), -+ g_param_spec_get_nick (pspec), -+ g_variant_new ("s", str), -+ cancellable, -+ callback, -+ user_data); -+} -+ -+gboolean -+bolt_client_set_authmode_finish (BoltClient *client, -+ GAsyncResult *res, -+ GError **error) -+{ -+ return bolt_proxy_set_property_finish (res, error); -+} -+ -+/* utility functions */ -+static gint -+device_sort_by_syspath (gconstpointer ap, -+ gconstpointer bp, -+ gpointer data) -+{ -+ BoltDevice *a = BOLT_DEVICE (*((BoltDevice **) ap)); -+ BoltDevice *b = BOLT_DEVICE (*((BoltDevice **) bp)); -+ gint sort_order = GPOINTER_TO_INT (data); -+ const char *pa; -+ const char *pb; -+ -+ pa = bolt_device_get_syspath (a); -+ pb = bolt_device_get_syspath (b); -+ -+ return sort_order * g_strcmp0 (pa, pb); -+} -+ -+void -+bolt_devices_sort_by_syspath (GPtrArray *devices, -+ gboolean reverse) -+{ -+ gpointer sort_order = GINT_TO_POINTER (reverse ? -1 : 1); -+ -+ if (devices == NULL) -+ return; -+ -+ g_ptr_array_sort_with_data (devices, -+ device_sort_by_syspath, -+ sort_order); -+} -diff --git a/panels/thunderbolt/bolt-client.h b/panels/thunderbolt/bolt-client.h -new file mode 100644 -index 000000000000..85382301182b ---- /dev/null -+++ b/panels/thunderbolt/bolt-client.h -@@ -0,0 +1,107 @@ -+/* -+ * Copyright © 2017 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library. If not, see . -+ * -+ * Authors: -+ * Christian J. Kellner -+ */ -+ -+#pragma once -+ -+#include "bolt-enums.h" -+#include "bolt-device.h" -+#include "bolt-proxy.h" -+ -+G_BEGIN_DECLS -+ -+#define BOLT_TYPE_CLIENT bolt_client_get_type () -+G_DECLARE_FINAL_TYPE (BoltClient, bolt_client, BOLT, CLIENT, BoltProxy); -+ -+BoltClient * bolt_client_new (GError **error); -+ -+void bolt_client_new_async (GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data); -+BoltClient * bolt_client_new_finish (GAsyncResult *res, -+ GError **error); -+ -+GPtrArray * bolt_client_list_devices (BoltClient *client, -+ GCancellable *cancellable, -+ GError **error); -+ -+BoltDevice * bolt_client_get_device (BoltClient *client, -+ const char *uid, -+ GCancellable *cancellable, -+ GError **error); -+ -+BoltDevice * bolt_client_enroll_device (BoltClient *client, -+ const char *uid, -+ BoltPolicy policy, -+ BoltAuthCtrl flags, -+ GError **error); -+ -+void bolt_client_enroll_device_async (BoltClient *client, -+ const char *uid, -+ BoltPolicy policy, -+ BoltAuthCtrl flags, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data); -+ -+gboolean bolt_client_enroll_device_finish (BoltClient *client, -+ GAsyncResult *res, -+ char **path, -+ GError **error); -+ -+gboolean bolt_client_forget_device (BoltClient *client, -+ const char *uid, -+ GError **error); -+ -+void bolt_client_forget_device_async (BoltClient *client, -+ const char *uid, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data); -+ -+gboolean bolt_client_forget_device_finish (BoltClient *client, -+ GAsyncResult *res, -+ GError **error); -+ -+/* getter */ -+guint bolt_client_get_version (BoltClient *client); -+ -+gboolean bolt_client_is_probing (BoltClient *client); -+ -+BoltSecurity bolt_client_get_security (BoltClient *client); -+ -+BoltAuthMode bolt_client_get_authmode (BoltClient *client); -+ -+/* setter */ -+ -+void bolt_client_set_authmode_async (BoltClient *client, -+ BoltAuthMode mode, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data); -+ -+gboolean bolt_client_set_authmode_finish (BoltClient *client, -+ GAsyncResult *res, -+ GError **error); -+ -+/* utility functions */ -+void bolt_devices_sort_by_syspath (GPtrArray *devices, -+ gboolean reverse); -+ -+G_END_DECLS -diff --git a/panels/thunderbolt/bolt-device.c b/panels/thunderbolt/bolt-device.c -new file mode 100644 -index 000000000000..b316950d3b81 ---- /dev/null -+++ b/panels/thunderbolt/bolt-device.c -@@ -0,0 +1,604 @@ -+/* -+ * Copyright © 2017 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library. If not, see . -+ * -+ * Authors: -+ * Christian J. Kellner -+ */ -+ -+#include "config.h" -+ -+#include "bolt-device.h" -+ -+#include "bolt-enums.h" -+#include "bolt-error.h" -+#include "bolt-names.h" -+ -+#include -+ -+struct _BoltDevice -+{ -+ BoltProxy parent; -+}; -+ -+enum { -+ PROP_0, -+ -+ /* D-Bus Props */ -+ PROP_UID, -+ PROP_NAME, -+ PROP_VENDOR, -+ PROP_TYPE, -+ PROP_STATUS, -+ PROP_AUTHFLAGS, -+ PROP_PARENT, -+ PROP_SYSPATH, -+ PROP_CONNTIME, -+ PROP_AUTHTIME, -+ -+ PROP_STORED, -+ PROP_POLICY, -+ PROP_KEY, -+ PROP_STORETIME, -+ PROP_LABEL, -+ -+ PROP_LAST -+}; -+ -+static GParamSpec *props[PROP_LAST] = {NULL, }; -+ -+G_DEFINE_TYPE (BoltDevice, -+ bolt_device, -+ BOLT_TYPE_PROXY); -+ -+static void -+bolt_device_get_property (GObject *object, -+ guint prop_id, -+ GValue *value, -+ GParamSpec *pspec) -+{ -+ if (bolt_proxy_get_dbus_property (object, pspec, value)) -+ return; -+} -+ -+ -+ -+static void -+bolt_device_class_init (BoltDeviceClass *klass) -+{ -+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass); -+ -+ gobject_class->get_property = bolt_device_get_property; -+ -+ props[PROP_UID] = -+ g_param_spec_string ("uid", -+ "Uid", NULL, -+ "unknown", -+ G_PARAM_READABLE | -+ G_PARAM_STATIC_NICK); -+ -+ props[PROP_NAME] = -+ g_param_spec_string ("name", -+ "Name", NULL, -+ "unknown", -+ G_PARAM_READABLE | -+ G_PARAM_STATIC_NICK); -+ -+ props[PROP_VENDOR] = -+ g_param_spec_string ("vendor", -+ "Vendor", NULL, -+ "unknown", -+ G_PARAM_READABLE | -+ G_PARAM_STATIC_NICK); -+ -+ props[PROP_TYPE] = -+ g_param_spec_enum ("type", -+ "Type", NULL, -+ BOLT_TYPE_DEVICE_TYPE, -+ BOLT_DEVICE_PERIPHERAL, -+ G_PARAM_READABLE | -+ G_PARAM_STATIC_NICK); -+ -+ props[PROP_STATUS] = -+ g_param_spec_enum ("status", -+ "Status", NULL, -+ BOLT_TYPE_STATUS, -+ BOLT_STATUS_DISCONNECTED, -+ G_PARAM_READABLE | -+ G_PARAM_STATIC_NICK); -+ -+ props[PROP_AUTHFLAGS] = -+ g_param_spec_flags ("authflags", -+ "AuthFlags", NULL, -+ BOLT_TYPE_AUTH_FLAGS, -+ BOLT_AUTH_NONE, -+ G_PARAM_READABLE | -+ G_PARAM_STATIC_STRINGS); -+ -+ props[PROP_PARENT] = -+ g_param_spec_string ("parent", -+ "Parent", NULL, -+ "unknown", -+ G_PARAM_READABLE | -+ G_PARAM_STATIC_NICK); -+ -+ props[PROP_SYSPATH] = -+ g_param_spec_string ("syspath", -+ "SysfsPath", NULL, -+ "unknown", -+ G_PARAM_READABLE | -+ G_PARAM_STATIC_NICK); -+ -+ props[PROP_CONNTIME] = -+ g_param_spec_uint64 ("conntime", -+ "ConnectTime", NULL, -+ 0, G_MAXUINT64, 0, -+ G_PARAM_READABLE | -+ G_PARAM_STATIC_STRINGS); -+ -+ props[PROP_AUTHTIME] = -+ g_param_spec_uint64 ("authtime", -+ "AuthorizeTime", NULL, -+ 0, G_MAXUINT64, 0, -+ G_PARAM_READABLE | -+ G_PARAM_STATIC_STRINGS); -+ -+ props[PROP_STORED] = -+ g_param_spec_boolean ("stored", -+ "Stored", NULL, -+ FALSE, -+ G_PARAM_READABLE | -+ G_PARAM_STATIC_NICK); -+ -+ props[PROP_POLICY] = -+ g_param_spec_enum ("policy", -+ "Policy", NULL, -+ BOLT_TYPE_POLICY, -+ BOLT_POLICY_DEFAULT, -+ G_PARAM_READABLE | -+ G_PARAM_STATIC_NICK); -+ -+ props[PROP_KEY] = -+ g_param_spec_enum ("key", -+ "Key", NULL, -+ BOLT_TYPE_KEY_STATE, -+ BOLT_KEY_MISSING, -+ G_PARAM_READABLE | -+ G_PARAM_STATIC_NICK); -+ -+ props[PROP_STORETIME] = -+ g_param_spec_uint64 ("storetime", -+ "StoreTime", NULL, -+ 0, G_MAXUINT64, 0, -+ G_PARAM_READABLE | -+ G_PARAM_STATIC_STRINGS); -+ -+ props[PROP_LABEL] = -+ g_param_spec_string ("label", -+ "Label", NULL, -+ NULL, -+ G_PARAM_READABLE | -+ G_PARAM_STATIC_STRINGS); -+ -+ g_object_class_install_properties (gobject_class, -+ PROP_LAST, -+ props); -+ -+} -+ -+static void -+bolt_device_init (BoltDevice *mgr) -+{ -+} -+ -+/* public methods */ -+ -+BoltDevice * -+bolt_device_new_for_object_path (GDBusConnection *bus, -+ const char *path, -+ GCancellable *cancel, -+ GError **error) -+{ -+ BoltDevice *dev; -+ -+ dev = g_initable_new (BOLT_TYPE_DEVICE, -+ cancel, error, -+ "g-flags", G_DBUS_PROXY_FLAGS_NONE, -+ "g-connection", bus, -+ "g-name", BOLT_DBUS_NAME, -+ "g-object-path", path, -+ "g-interface-name", BOLT_DBUS_DEVICE_INTERFACE, -+ NULL); -+ -+ return dev; -+} -+ -+gboolean -+bolt_device_authorize (BoltDevice *dev, -+ BoltAuthCtrl flags, -+ GCancellable *cancel, -+ GError **error) -+{ -+ g_autoptr(GError) err = NULL; -+ g_autofree char *fstr = NULL; -+ -+ g_return_val_if_fail (BOLT_IS_DEVICE (dev), FALSE); -+ -+ fstr = bolt_flags_to_string (BOLT_TYPE_AUTH_CTRL, flags, error); -+ if (fstr == NULL) -+ return FALSE; -+ -+ g_dbus_proxy_call_sync (G_DBUS_PROXY (dev), -+ "Authorize", -+ g_variant_new ("(s)", fstr), -+ G_DBUS_CALL_FLAGS_NONE, -+ -1, -+ cancel, -+ &err); -+ -+ if (err != NULL) -+ return bolt_error_propagate_stripped (error, &err); -+ -+ return TRUE; -+} -+ -+void -+bolt_device_authorize_async (BoltDevice *dev, -+ BoltAuthCtrl flags, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ GError *err = NULL; -+ g_autofree char *fstr = NULL; -+ -+ g_return_if_fail (BOLT_IS_DEVICE (dev)); -+ -+ fstr = bolt_flags_to_string (BOLT_TYPE_AUTH_CTRL, flags, &err); -+ if (fstr == NULL) -+ { -+ g_task_report_error (dev, callback, user_data, NULL, err); -+ return; -+ } -+ -+ g_dbus_proxy_call (G_DBUS_PROXY (dev), -+ "Authorize", -+ g_variant_new ("(s)", fstr), -+ G_DBUS_CALL_FLAGS_NONE, -+ -1, -+ cancellable, -+ callback, -+ user_data); -+} -+ -+gboolean -+bolt_device_authorize_finish (BoltDevice *dev, -+ GAsyncResult *res, -+ GError **error) -+{ -+ g_autoptr(GError) err = NULL; -+ g_autoptr(GVariant) val = NULL; -+ -+ g_return_val_if_fail (BOLT_IS_DEVICE (dev), FALSE); -+ -+ val = g_dbus_proxy_call_finish (G_DBUS_PROXY (dev), res, &err); -+ if (val == NULL) -+ { -+ bolt_error_propagate_stripped (error, &err); -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+const char * -+bolt_device_get_uid (BoltDevice *dev) -+{ -+ const char *key; -+ const char *str; -+ -+ g_return_val_if_fail (BOLT_IS_DEVICE (dev), NULL); -+ -+ key = g_param_spec_get_name (props[PROP_UID]); -+ str = bolt_proxy_get_property_string (BOLT_PROXY (dev), key); -+ -+ return str; -+} -+ -+const char * -+bolt_device_get_name (BoltDevice *dev) -+{ -+ const char *key; -+ const char *str; -+ -+ g_return_val_if_fail (BOLT_IS_DEVICE (dev), NULL); -+ -+ key = g_param_spec_get_name (props[PROP_NAME]); -+ str = bolt_proxy_get_property_string (BOLT_PROXY (dev), key); -+ -+ return str; -+} -+ -+const char * -+bolt_device_get_vendor (BoltDevice *dev) -+{ -+ const char *key; -+ const char *str; -+ -+ g_return_val_if_fail (BOLT_IS_DEVICE (dev), NULL); -+ -+ key = g_param_spec_get_name (props[PROP_VENDOR]); -+ str = bolt_proxy_get_property_string (BOLT_PROXY (dev), key); -+ -+ return str; -+} -+ -+BoltDeviceType -+bolt_device_get_device_type (BoltDevice *dev) -+{ -+ const char *key; -+ gboolean ok; -+ gint val = BOLT_DEVICE_PERIPHERAL; -+ -+ g_return_val_if_fail (BOLT_IS_DEVICE (dev), val); -+ -+ key = g_param_spec_get_name (props[PROP_TYPE]); -+ ok = bolt_proxy_get_property_enum (BOLT_PROXY (dev), key, &val); -+ -+ if (!ok) -+ g_warning ("failed to get enum property '%s'", key); -+ -+ return val; -+} -+ -+BoltStatus -+bolt_device_get_status (BoltDevice *dev) -+{ -+ const char *key; -+ gboolean ok; -+ gint val = BOLT_STATUS_UNKNOWN; -+ -+ g_return_val_if_fail (BOLT_IS_DEVICE (dev), val); -+ -+ key = g_param_spec_get_name (props[PROP_STATUS]); -+ ok = bolt_proxy_get_property_enum (BOLT_PROXY (dev), key, &val); -+ -+ if (!ok) -+ g_warning ("failed to get enum property '%s'", key); -+ -+ return val; -+} -+ -+BoltAuthFlags -+bolt_device_get_authflags (BoltDevice *dev) -+{ -+ const char *key; -+ gboolean ok; -+ guint val = BOLT_AUTH_NONE; -+ -+ g_return_val_if_fail (BOLT_IS_DEVICE (dev), val); -+ -+ key = g_param_spec_get_name (props[PROP_AUTHFLAGS]); -+ ok = bolt_proxy_get_property_flags (BOLT_PROXY (dev), key, &val); -+ -+ if (!ok) -+ g_warning ("failed to get enum property '%s'", key); -+ -+ return val; -+} -+ -+const char * -+bolt_device_get_parent (BoltDevice *dev) -+{ -+ const char *key; -+ const char *str; -+ -+ g_return_val_if_fail (BOLT_IS_DEVICE (dev), NULL); -+ -+ key = g_param_spec_get_name (props[PROP_PARENT]); -+ str = bolt_proxy_get_property_string (BOLT_PROXY (dev), key); -+ -+ return str; -+} -+ -+const char * -+bolt_device_get_syspath (BoltDevice *dev) -+{ -+ const char *key; -+ const char *str; -+ -+ g_return_val_if_fail (BOLT_IS_DEVICE (dev), NULL); -+ -+ key = g_param_spec_get_name (props[PROP_SYSPATH]); -+ str = bolt_proxy_get_property_string (BOLT_PROXY (dev), key); -+ -+ return str; -+} -+ -+guint64 -+bolt_device_get_conntime (BoltDevice *dev) -+{ -+ const char *key; -+ guint64 val = 0; -+ gboolean ok; -+ -+ g_return_val_if_fail (BOLT_IS_DEVICE (dev), val); -+ -+ key = g_param_spec_get_name (props[PROP_CONNTIME]); -+ ok = bolt_proxy_get_property_uint64 (BOLT_PROXY (dev), key, &val); -+ -+ if (!ok) -+ g_warning ("failed to get enum property '%s'", key); -+ -+ return val; -+} -+ -+guint64 -+bolt_device_get_authtime (BoltDevice *dev) -+{ -+ const char *key; -+ guint64 val = 0; -+ gboolean ok; -+ -+ g_return_val_if_fail (BOLT_IS_DEVICE (dev), val); -+ -+ key = g_param_spec_get_name (props[PROP_AUTHTIME]); -+ ok = bolt_proxy_get_property_uint64 (BOLT_PROXY (dev), key, &val); -+ -+ if (!ok) -+ g_warning ("failed to get enum property '%s'", key); -+ -+ return val; -+} -+ -+gboolean -+bolt_device_is_stored (BoltDevice *dev) -+{ -+ const char *key; -+ gboolean val = FALSE; -+ gboolean ok; -+ -+ g_return_val_if_fail (BOLT_IS_DEVICE (dev), val); -+ -+ key = g_param_spec_get_name (props[PROP_STORED]); -+ ok = bolt_proxy_get_property_bool (BOLT_PROXY (dev), key, &val); -+ -+ if (!ok) -+ g_warning ("failed to get enum property '%s'", key); -+ -+ return val; -+} -+ -+BoltPolicy -+bolt_device_get_policy (BoltDevice *dev) -+{ -+ const char *key; -+ gboolean ok; -+ gint val = BOLT_POLICY_DEFAULT; -+ -+ g_return_val_if_fail (BOLT_IS_DEVICE (dev), val); -+ -+ key = g_param_spec_get_name (props[PROP_POLICY]); -+ ok = bolt_proxy_get_property_enum (BOLT_PROXY (dev), key, &val); -+ -+ if (!ok) -+ g_warning ("failed to get enum property '%s'", key); -+ -+ return val; -+} -+ -+BoltKeyState -+bolt_device_get_keystate (BoltDevice *dev) -+{ -+ const char *key; -+ gboolean ok; -+ gint val = BOLT_KEY_MISSING; -+ -+ g_return_val_if_fail (BOLT_IS_DEVICE (dev), val); -+ -+ key = g_param_spec_get_name (props[PROP_KEY]); -+ ok = bolt_proxy_get_property_enum (BOLT_PROXY (dev), key, &val); -+ -+ if (!ok) -+ g_warning ("failed to get enum property '%s'", key); -+ -+ return val; -+} -+ -+guint64 -+bolt_device_get_storetime (BoltDevice *dev) -+{ -+ const char *key; -+ guint64 val = 0; -+ gboolean ok; -+ -+ g_return_val_if_fail (BOLT_IS_DEVICE (dev), val); -+ -+ key = g_param_spec_get_name (props[PROP_STORETIME]); -+ ok = bolt_proxy_get_property_uint64 (BOLT_PROXY (dev), key, &val); -+ -+ if (!ok) -+ g_warning ("failed to get enum property '%s'", key); -+ -+ return val; -+} -+ -+const char * -+bolt_device_get_label (BoltDevice *dev) -+{ -+ const char *key; -+ const char *str; -+ -+ g_return_val_if_fail (BOLT_IS_DEVICE (dev), NULL); -+ -+ key = g_param_spec_get_name (props[PROP_LABEL]); -+ str = bolt_proxy_get_property_string (BOLT_PROXY (dev), key); -+ -+ return str; -+} -+ -+char * -+bolt_device_get_display_name (BoltDevice *dev) -+{ -+ const char *label; -+ const char *name; -+ const char *vendor; -+ -+ label = bolt_device_get_label (dev); -+ if (label != NULL) -+ return g_strdup (label); -+ -+ name = bolt_device_get_name (dev); -+ vendor = bolt_device_get_vendor (dev); -+ -+ return g_strdup_printf ("%s %s", vendor, name); -+} -+ -+guint64 -+bolt_device_get_timestamp (BoltDevice *dev) -+{ -+ BoltStatus status; -+ guint64 timestamp = 0; -+ -+ status = bolt_device_get_status (dev); -+ -+ switch (status) -+ { -+ case BOLT_STATUS_AUTHORIZING: -+ case BOLT_STATUS_AUTH_ERROR: -+ case BOLT_STATUS_CONNECTING: -+ case BOLT_STATUS_CONNECTED: -+ timestamp = bolt_device_get_conntime (dev); -+ break; -+ -+ case BOLT_STATUS_DISCONNECTED: -+ /* implicit: device is stored */ -+ timestamp = bolt_device_get_storetime (dev); -+ break; -+ -+ case BOLT_STATUS_AUTHORIZED: -+ case BOLT_STATUS_AUTHORIZED_DPONLY: -+ case BOLT_STATUS_AUTHORIZED_NEWKEY: -+ case BOLT_STATUS_AUTHORIZED_SECURE: -+ timestamp = bolt_device_get_authtime (dev); -+ break; -+ -+ case BOLT_STATUS_UNKNOWN: -+ timestamp = 0; -+ break; -+ } -+ -+ return timestamp; -+} -diff --git a/panels/thunderbolt/bolt-device.h b/panels/thunderbolt/bolt-device.h -new file mode 100644 -index 000000000000..ffd09f9a8ad7 ---- /dev/null -+++ b/panels/thunderbolt/bolt-device.h -@@ -0,0 +1,87 @@ -+/* -+ * Copyright © 2017 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library. If not, see . -+ * -+ * Authors: -+ * Christian J. Kellner -+ */ -+ -+#pragma once -+ -+#include "bolt-enums.h" -+#include "bolt-proxy.h" -+ -+G_BEGIN_DECLS -+ -+#define BOLT_TYPE_DEVICE bolt_device_get_type () -+G_DECLARE_FINAL_TYPE (BoltDevice, bolt_device, BOLT, DEVICE, BoltProxy); -+ -+BoltDevice * bolt_device_new_for_object_path (GDBusConnection *bus, -+ const char *path, -+ GCancellable *cancellable, -+ GError **error); -+ -+gboolean bolt_device_authorize (BoltDevice *dev, -+ BoltAuthCtrl flags, -+ GCancellable *cancellable, -+ GError **error); -+ -+void bolt_device_authorize_async (BoltDevice *dev, -+ BoltAuthCtrl flags, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data); -+ -+gboolean bolt_device_authorize_finish (BoltDevice *dev, -+ GAsyncResult *res, -+ GError **error); -+ -+/* getter */ -+const char * bolt_device_get_uid (BoltDevice *dev); -+ -+const char * bolt_device_get_name (BoltDevice *dev); -+ -+const char * bolt_device_get_vendor (BoltDevice *dev); -+ -+BoltDeviceType bolt_device_get_device_type (BoltDevice *dev); -+ -+BoltStatus bolt_device_get_status (BoltDevice *dev); -+ -+BoltAuthFlags bolt_device_get_authflags (BoltDevice *dev); -+ -+const char * bolt_device_get_parent (BoltDevice *dev); -+ -+const char * bolt_device_get_syspath (BoltDevice *dev); -+ -+guint64 bolt_device_get_conntime (BoltDevice *dev); -+ -+guint64 bolt_device_get_authtime (BoltDevice *dev); -+ -+gboolean bolt_device_is_stored (BoltDevice *dev); -+ -+BoltPolicy bolt_device_get_policy (BoltDevice *dev); -+ -+BoltKeyState bolt_device_get_keystate (BoltDevice *dev); -+ -+guint64 bolt_device_get_storetime (BoltDevice *dev); -+ -+const char * bolt_device_get_label (BoltDevice *dev); -+ -+/* derived getter */ -+char * bolt_device_get_display_name (BoltDevice *dev); -+ -+guint64 bolt_device_get_timestamp (BoltDevice *dev); -+ -+G_END_DECLS -diff --git a/panels/thunderbolt/bolt-enums.c b/panels/thunderbolt/bolt-enums.c -new file mode 100644 -index 000000000000..de77737f8088 ---- /dev/null -+++ b/panels/thunderbolt/bolt-enums.c -@@ -0,0 +1,395 @@ -+/* -+ * Copyright © 2017 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library. If not, see . -+ * -+ * Authors: -+ * Christian J. Kellner -+ */ -+ -+#include "config.h" -+ -+#include "bolt-enums.h" -+#include "bolt-error.h" -+ -+#include -+ -+G_DEFINE_AUTOPTR_CLEANUP_FUNC (GEnumClass, g_type_class_unref); -+G_DEFINE_AUTOPTR_CLEANUP_FUNC (GFlagsClass, g_type_class_unref); -+ -+gboolean -+bolt_enum_class_validate (GEnumClass *enum_class, -+ gint value, -+ GError **error) -+{ -+ const char *name; -+ gboolean oob; -+ -+ if (enum_class == NULL) -+ { -+ name = g_type_name_from_class ((GTypeClass *) enum_class); -+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, -+ "could not determine enum class for '%s'", -+ name); -+ -+ return FALSE; -+ } -+ -+ oob = value < enum_class->minimum || value > enum_class->maximum; -+ -+ if (oob) -+ { -+ name = g_type_name_from_class ((GTypeClass *) enum_class); -+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, -+ "enum value '%d' is out of bounds for '%s'", -+ value, name); -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+gboolean -+bolt_enum_validate (GType enum_type, -+ gint value, -+ GError **error) -+{ -+ g_autoptr(GEnumClass) klass = g_type_class_ref (enum_type); -+ return bolt_enum_class_validate (klass, value, error); -+} -+ -+const char * -+bolt_enum_to_string (GType enum_type, -+ gint value, -+ GError **error) -+{ -+ g_autoptr(GEnumClass) klass = NULL; -+ GEnumValue *ev; -+ -+ klass = g_type_class_ref (enum_type); -+ -+ if (!bolt_enum_class_validate (klass, value, error)) -+ return NULL; -+ -+ ev = g_enum_get_value (klass, value); -+ return ev->value_nick; -+} -+ -+gint -+bolt_enum_from_string (GType enum_type, -+ const char *string, -+ GError **error) -+{ -+ g_autoptr(GEnumClass) klass = NULL; -+ const char *name; -+ GEnumValue *ev; -+ -+ klass = g_type_class_ref (enum_type); -+ -+ if (klass == NULL) -+ { -+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, -+ "could not determine enum class"); -+ return -1; -+ } -+ -+ if (string == NULL) -+ { -+ name = g_type_name_from_class ((GTypeClass *) klass); -+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, -+ "empty string passed for enum class for '%s'", -+ name); -+ return -1; -+ } -+ -+ ev = g_enum_get_value_by_nick (klass, string); -+ -+ if (ev == NULL) -+ { -+ name = g_type_name (enum_type); -+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, -+ "invalid string '%s' for enum '%s'", string, name); -+ return -1; -+ } -+ -+ return ev->value; -+} -+ -+char * -+bolt_flags_class_to_string (GFlagsClass *flags_class, -+ guint value, -+ GError **error) -+{ -+ g_autoptr(GString) str = NULL; -+ const char *name; -+ GFlagsValue *fv; -+ -+ if (flags_class == NULL) -+ { -+ name = g_type_name_from_class ((GTypeClass *) flags_class); -+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, -+ "could not determine flags class for '%s'", -+ name); -+ -+ return FALSE; -+ } -+ -+ fv = g_flags_get_first_value (flags_class, value); -+ if (fv == NULL) -+ { -+ if (value == 0) -+ return g_strdup (""); -+ -+ name = g_type_name_from_class ((GTypeClass *) flags_class); -+ -+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, -+ "invalid value '%u' for flags '%s'", value, name); -+ return NULL; -+ } -+ -+ value &= ~fv->value; -+ str = g_string_new (fv->value_nick); -+ -+ while (value != 0 && -+ (fv = g_flags_get_first_value (flags_class, value)) != NULL) -+ { -+ g_string_append (str, " | "); -+ g_string_append (str, fv->value_nick); -+ -+ value &= ~fv->value; -+ } -+ -+ if (value != 0) -+ { -+ name = g_type_name_from_class ((GTypeClass *) flags_class); -+ -+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, -+ "unhandled value '%u' for flags '%s'", value, name); -+ return NULL; -+ } -+ -+ return g_string_free (g_steal_pointer (&str), FALSE); -+} -+ -+gboolean -+bolt_flags_class_from_string (GFlagsClass *flags_class, -+ const char *string, -+ guint *flags_out, -+ GError **error) -+{ -+ g_auto(GStrv) vals = NULL; -+ const char *name; -+ guint flags = 0; -+ -+ if (flags_class == NULL) -+ { -+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, -+ "could not determine flags class"); -+ -+ return FALSE; -+ } -+ -+ if (string == NULL) -+ { -+ name = g_type_name_from_class ((GTypeClass *) flags_class); -+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, -+ "empty string passed for flags class for '%s'", -+ name); -+ return FALSE; -+ } -+ -+ vals = g_strsplit (string, "|", -1); -+ -+ for (guint i = 0; vals[i]; i++) -+ { -+ GFlagsValue *fv; -+ char *nick; -+ -+ nick = g_strstrip (vals[i]); -+ fv = g_flags_get_value_by_nick (flags_class, nick); -+ -+ if (fv == NULL) -+ { -+ name = g_type_name_from_class ((GTypeClass *) flags_class); -+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, -+ "invalid flag '%s' for flags '%s'", string, name); -+ -+ return FALSE; -+ } -+ -+ flags |= fv->value; -+ } -+ -+ if (flags_out != NULL) -+ *flags_out = flags; -+ -+ return TRUE; -+} -+ -+char * -+bolt_flags_to_string (GType flags_type, -+ guint value, -+ GError **error) -+{ -+ g_autoptr(GFlagsClass) klass = NULL; -+ -+ klass = g_type_class_ref (flags_type); -+ return bolt_flags_class_to_string (klass, value, error); -+} -+ -+gboolean -+bolt_flags_from_string (GType flags_type, -+ const char *string, -+ guint *flags_out, -+ GError **error) -+{ -+ g_autoptr(GFlagsClass) klass = NULL; -+ -+ klass = g_type_class_ref (flags_type); -+ return bolt_flags_class_from_string (klass, string, flags_out, error); -+} -+ -+gboolean -+bolt_flags_update (guint from, -+ guint *to, -+ guint mask) -+{ -+ guint val; -+ gboolean chg; -+ -+ g_return_val_if_fail (to != NULL, FALSE); -+ -+ val = *to & ~mask; /* clear all bits in mask */ -+ val = val | (from & mask); /* set all bits in from and mask */ -+ chg = *to != val; -+ *to = val; -+ -+ return chg; -+} -+ -+const char * -+bolt_status_to_string (BoltStatus status) -+{ -+ return bolt_enum_to_string (BOLT_TYPE_STATUS, status, NULL); -+} -+ -+gboolean -+bolt_status_is_authorized (BoltStatus status) -+{ -+ return status == BOLT_STATUS_AUTHORIZED || -+ status == BOLT_STATUS_AUTHORIZED_SECURE || -+ status == BOLT_STATUS_AUTHORIZED_NEWKEY; -+} -+ -+gboolean -+bolt_status_is_pending (BoltStatus status) -+{ -+ return status == BOLT_STATUS_AUTH_ERROR || -+ status == BOLT_STATUS_CONNECTED; -+} -+ -+gboolean -+bolt_status_validate (BoltStatus status) -+{ -+ return bolt_enum_validate (BOLT_TYPE_STATUS, status, NULL); -+} -+ -+gboolean -+bolt_status_is_connected (BoltStatus status) -+{ -+ return status > BOLT_STATUS_DISCONNECTED; -+} -+ -+BoltSecurity -+bolt_security_from_string (const char *str) -+{ -+ return bolt_enum_from_string (BOLT_TYPE_SECURITY, str, NULL); -+} -+ -+const char * -+bolt_security_to_string (BoltSecurity security) -+{ -+ return bolt_enum_to_string (BOLT_TYPE_SECURITY, security, NULL); -+} -+ -+gboolean -+bolt_security_validate (BoltSecurity security) -+{ -+ return bolt_enum_validate (BOLT_TYPE_SECURITY, security, NULL); -+} -+ -+gboolean -+bolt_security_allows_pcie (BoltSecurity security) -+{ -+ gboolean pcie = FALSE; -+ -+ switch (security) -+ { -+ case BOLT_SECURITY_NONE: -+ case BOLT_SECURITY_USER: -+ case BOLT_SECURITY_SECURE: -+ pcie = TRUE; -+ break; -+ -+ case BOLT_SECURITY_DPONLY: -+ case BOLT_SECURITY_USBONLY: -+ case BOLT_SECURITY_UNKNOWN: -+ pcie = FALSE; -+ break; -+ } -+ -+ return pcie; -+} -+ -+BoltPolicy -+bolt_policy_from_string (const char *str) -+{ -+ return bolt_enum_from_string (BOLT_TYPE_POLICY, str, NULL); -+} -+ -+const char * -+bolt_policy_to_string (BoltPolicy policy) -+{ -+ return bolt_enum_to_string (BOLT_TYPE_POLICY, policy, NULL); -+} -+ -+gboolean -+bolt_policy_validate (BoltPolicy policy) -+{ -+ return bolt_enum_validate (BOLT_TYPE_POLICY, policy, NULL); -+} -+ -+BoltDeviceType -+bolt_device_type_from_string (const char *str) -+{ -+ return bolt_enum_from_string (BOLT_TYPE_DEVICE_TYPE, str, NULL); -+} -+ -+const char * -+bolt_device_type_to_string (BoltDeviceType type) -+{ -+ return bolt_enum_to_string (BOLT_TYPE_DEVICE_TYPE, type, NULL); -+} -+ -+gboolean -+bolt_device_type_validate (BoltDeviceType type) -+{ -+ return bolt_enum_validate (BOLT_TYPE_DEVICE_TYPE, type, NULL); -+} -+ -+gboolean -+bolt_device_type_is_host (BoltDeviceType type) -+{ -+ return type == BOLT_DEVICE_HOST; -+} -diff --git a/panels/thunderbolt/bolt-enums.h b/panels/thunderbolt/bolt-enums.h -new file mode 100644 -index 000000000000..6e2953fa2fd2 ---- /dev/null -+++ b/panels/thunderbolt/bolt-enums.h -@@ -0,0 +1,249 @@ -+/* -+ * Copyright © 2017 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library. If not, see . -+ * -+ * Authors: -+ * Christian J. Kellner -+ */ -+ -+#pragma once -+ -+#include "bolt-names.h" -+#include "bolt-enum-types.h" -+ -+ -+gboolean bolt_enum_validate (GType enum_type, -+ gint value, -+ GError **error); -+ -+gboolean bolt_enum_class_validate (GEnumClass *enum_class, -+ gint value, -+ GError **error); -+ -+const char * bolt_enum_to_string (GType enum_type, -+ gint value, -+ GError **error); -+ -+gint bolt_enum_from_string (GType enum_type, -+ const char *string, -+ GError **error); -+ -+ -+char * bolt_flags_class_to_string (GFlagsClass *flags_class, -+ guint value, -+ GError **error); -+ -+gboolean bolt_flags_class_from_string (GFlagsClass *flags_class, -+ const char *string, -+ guint *flags_out, -+ GError **error); -+ -+char * bolt_flags_to_string (GType flags_type, -+ guint value, -+ GError **error); -+ -+gboolean bolt_flags_from_string (GType flags_type, -+ const char *string, -+ guint *flags_out, -+ GError **error); -+ -+gboolean bolt_flags_update (guint from, -+ guint *to, -+ guint mask); -+ -+#define bolt_flag_isset(flags_, flag_) (!!(flags_ & flag_)) -+#define bolt_flag_isclear(flags_, flag_) (!(flags_ & flag_)) -+ -+/** -+ * BoltStatus: -+ * @BOLT_STATUS_UNKNOWN: Device is in an unknown state (should normally not happen). -+ * @BOLT_STATUS_DISCONNECTED: Device is not connected. -+ * @BOLT_STATUS_CONNECTING: Device is currently being connected. -+ * @BOLT_STATUS_CONNECTED: Device is connected, but not authorized. -+ * @BOLT_STATUS_AUTHORIZING: Device is currently authorizing. -+ * @BOLT_STATUS_AUTH_ERROR: Failed to authorize a device via a key. -+ * @BOLT_STATUS_AUTHORIZED: Device connected and authorized. -+ * @BOLT_STATUS_AUTHORIZED_SECURE: Device connected and securely authorized via a key (deprecated). -+ * @BOLT_STATUS_AUTHORIZED_NEWKEY: Device connected and authorized via a new key (deprecated). -+ * @BOLT_STATUS_AUTHORIZED_DPONLY: Device authorized but with thunderbolt disabled (deprecated). -+ * -+ * The current status of the device. -+ */ -+typedef enum { -+ -+ BOLT_STATUS_UNKNOWN = -1, -+ BOLT_STATUS_DISCONNECTED = 0, -+ BOLT_STATUS_CONNECTING, -+ BOLT_STATUS_CONNECTED, -+ BOLT_STATUS_AUTHORIZING, -+ BOLT_STATUS_AUTH_ERROR, -+ BOLT_STATUS_AUTHORIZED, -+ -+ /* deprecated, do not use */ -+ BOLT_STATUS_AUTHORIZED_SECURE, -+ BOLT_STATUS_AUTHORIZED_NEWKEY, -+ BOLT_STATUS_AUTHORIZED_DPONLY -+ -+} BoltStatus; -+ -+const char * bolt_status_to_string (BoltStatus status); -+gboolean bolt_status_is_authorized (BoltStatus status); -+gboolean bolt_status_is_connected (BoltStatus status); -+gboolean bolt_status_is_pending (BoltStatus status); -+gboolean bolt_status_validate (BoltStatus status); -+ -+/** -+ * BoltAuthFlags: -+ * @BOLT_AUTH_NONE: No specific authorization. -+ * @BOLT_AUTH_NOPCIE: PCIe tunnels are *not* authorized. -+ * @BOLT_AUTH_SECURE: Device is securely authorized. -+ * @BOLT_AUTH_NOKEY: Device does *not* support key verification. -+ * @BOLT_AUTH_BOOT: Device was already authorized during pre-boot. -+ * -+ * More specific information about device authorization. -+ */ -+typedef enum { /*< flags >*/ -+ -+ BOLT_AUTH_NONE = 0, -+ BOLT_AUTH_NOPCIE = 1 << 0, -+ BOLT_AUTH_SECURE = 1 << 1, -+ BOLT_AUTH_NOKEY = 1 << 2, -+ BOLT_AUTH_BOOT = 1 << 3, -+ -+} BoltAuthFlags; -+ -+/** -+ * BoltKeyState: -+ * @BOLT_KEY_UNKNOWN: unknown key state -+ * @BOLT_KEY_MISSING: no key -+ * @BOLT_KEY_HAVE: key exists -+ * @BOLT_KEY_NEW: key is new -+ * -+ * The state of the key. -+ */ -+ -+typedef enum { -+ -+ BOLT_KEY_UNKNOWN = -1, -+ BOLT_KEY_MISSING = 0, -+ BOLT_KEY_HAVE = 1, -+ BOLT_KEY_NEW = 2 -+ -+} BoltKeyState; -+ -+/** -+ * BoltSecurity: -+ * @BOLT_SECURITY_UNKNOWN : Unknown security. -+ * @BOLT_SECURITY_NONE : No security, all devices are automatically connected. -+ * @BOLT_SECURITY_DPONLY : Display Port only devices only. -+ * @BOLT_SECURITY_USER : User needs to authorize devices. -+ * @BOLT_SECURITY_SECURE : User needs to authorize devices. Authorization can -+ * be done via key exchange to verify the device identity. -+ * @BOLT_SECURITY_USBONLY : Only create a PCIe tunnel to the USB controller in a -+ * connected thunderbolt dock, allowing no downstream PCIe tunnels. -+ * -+ * The security level of the thunderbolt domain. -+ */ -+typedef enum { -+ -+ BOLT_SECURITY_UNKNOWN = -1, -+ BOLT_SECURITY_NONE = 0, -+ BOLT_SECURITY_DPONLY = 1, -+ BOLT_SECURITY_USER = '1', -+ BOLT_SECURITY_SECURE = '2', -+ BOLT_SECURITY_USBONLY = 4, -+ -+} BoltSecurity; -+ -+ -+BoltSecurity bolt_security_from_string (const char *str); -+const char * bolt_security_to_string (BoltSecurity security); -+gboolean bolt_security_validate (BoltSecurity security); -+gboolean bolt_security_allows_pcie (BoltSecurity security); -+ -+/** -+ * BoltPolicy: -+ * @BOLT_POLICY_UNKNOWN: Unknown policy. -+ * @BOLT_POLICY_DEFAULT: Default policy. -+ * @BOLT_POLICY_MANUAL: Manual authorization of the device. -+ * @BOLT_POLICY_AUTO: Connect the device automatically, -+ * with the best possible security level supported -+ * by the domain controller. -+ * -+ * What do to for connected devices. -+ */ -+typedef enum { -+ -+ BOLT_POLICY_UNKNOWN = -1, -+ BOLT_POLICY_DEFAULT = 0, -+ BOLT_POLICY_MANUAL = 1, -+ BOLT_POLICY_AUTO = 2, -+ -+} BoltPolicy; -+ -+ -+BoltPolicy bolt_policy_from_string (const char *str); -+const char * bolt_policy_to_string (BoltPolicy policy); -+gboolean bolt_policy_validate (BoltPolicy policy); -+ -+/** -+ * BoltAuthCtrl: -+ * @BOLT_AUTHCTRL_NONE: No authorization flags. -+ * -+ * Control authorization. -+ */ -+typedef enum { /*< flags >*/ -+ -+ BOLT_AUTHCTRL_NONE = 0 -+ -+} BoltAuthCtrl; -+ -+/** -+ * BoltDeviceType: -+ * @BOLT_DEVICE_UNKNOWN_TYPE: Unknown device type -+ * @BOLT_DEVICE_HOST: The device representing the host -+ * @BOLT_DEVICE_PERIPHERAL: A generic thunderbolt peripheral -+ * -+ * The type of the device. -+ */ -+typedef enum { -+ -+ BOLT_DEVICE_UNKNOWN_TYPE = -1, -+ BOLT_DEVICE_HOST = 0, -+ BOLT_DEVICE_PERIPHERAL -+ -+} BoltDeviceType; -+ -+BoltDeviceType bolt_device_type_from_string (const char *str); -+const char * bolt_device_type_to_string (BoltDeviceType type); -+gboolean bolt_device_type_validate (BoltDeviceType type); -+gboolean bolt_device_type_is_host (BoltDeviceType type); -+ -+/** -+ * BoltAuthMode: -+ * @BOLT_AUTH_DISABLED: Authorization is disabled -+ * @BOLT_AUTH_ENABLED: Authorization is enabled. -+ * -+ * Control authorization. -+ */ -+typedef enum { /*< flags >*/ -+ -+ BOLT_AUTH_DISABLED = 0, -+ BOLT_AUTH_ENABLED = 1 -+ -+} BoltAuthMode; -+ -+#define bolt_auth_mode_is_enabled(auth) ((auth & BOLT_AUTH_ENABLED) != 0) -+#define bolt_auth_mode_is_disabled(auth) (!bolt_auth_mode_is_enabled (auth)) -diff --git a/panels/thunderbolt/bolt-error.c b/panels/thunderbolt/bolt-error.c -new file mode 100644 -index 000000000000..37d844e4a14d ---- /dev/null -+++ b/panels/thunderbolt/bolt-error.c -@@ -0,0 +1,99 @@ -+/* -+ * Copyright © 2017 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library. If not, see . -+ * -+ * Authors: -+ * Christian J. Kellner -+ */ -+ -+#include "config.h" -+ -+#include "bolt-error.h" -+ -+#include "bolt-names.h" -+ -+#include -+ -+/** -+ * SECTION:bolt-error -+ * @Title: Error codes -+ * -+ */ -+ -+static const GDBusErrorEntry bolt_error_entries[] = { -+ {BOLT_ERROR_FAILED, BOLT_DBUS_NAME ".Error.Failed"}, -+ {BOLT_ERROR_UDEV, BOLT_DBUS_NAME ".Error.UDev"}, -+}; -+ -+ -+GQuark -+bolt_error_quark (void) -+{ -+ static volatile gsize quark_volatile = 0; -+ -+ g_dbus_error_register_error_domain ("bolt-error-quark", -+ &quark_volatile, -+ bolt_error_entries, -+ G_N_ELEMENTS (bolt_error_entries)); -+ return (GQuark) quark_volatile; -+} -+ -+gboolean -+bolt_err_notfound (const GError *error) -+{ -+ return g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) || -+ g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT) || -+ g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND) || -+ g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND); -+} -+ -+gboolean -+bolt_err_exists (const GError *error) -+{ -+ return g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS) || -+ g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_EXIST); -+} -+ -+gboolean -+bolt_err_inval (const GError *error) -+{ -+ return g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE); -+} -+ -+gboolean -+bolt_err_cancelled (const GError *error) -+{ -+ return g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); -+} -+ -+gboolean -+bolt_error_propagate_stripped (GError **dest, -+ GError **source) -+{ -+ GError *src; -+ -+ g_return_val_if_fail (source != NULL, FALSE); -+ -+ src = *source; -+ -+ if (src == NULL) -+ return TRUE; -+ -+ if (g_dbus_error_is_remote_error (src)) -+ g_dbus_error_strip_remote_error (src); -+ -+ g_propagate_error (dest, g_steal_pointer (source)); -+ return FALSE; -+} -diff --git a/panels/thunderbolt/bolt-error.h b/panels/thunderbolt/bolt-error.h -new file mode 100644 -index 000000000000..39b3eee98917 ---- /dev/null -+++ b/panels/thunderbolt/bolt-error.h -@@ -0,0 +1,55 @@ -+/* -+ * Copyright © 2017 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library. If not, see . -+ * -+ * Authors: -+ * Christian J. Kellner -+ */ -+ -+#pragma once -+ -+#include -+ -+G_BEGIN_DECLS -+ -+/** -+ * BoltError: -+ * @BOLT_ERROR_FAILED: Generic error code -+ * @BOLT_ERROR_UDEV: UDev error -+ * -+ * Error codes used inside Bolt. -+ */ -+enum { -+ BOLT_ERROR_FAILED = 0, -+ BOLT_ERROR_UDEV, -+ BOLT_ERROR_NOKEY, -+ BOLT_ERROR_BADKEY, -+ BOLT_ERROR_CFG, -+} BoltError; -+ -+ -+GQuark bolt_error_quark (void); -+#define BOLT_ERROR (bolt_error_quark ()) -+ -+/* helper function to check for certain error types */ -+gboolean bolt_err_notfound (const GError *error); -+gboolean bolt_err_exists (const GError *error); -+gboolean bolt_err_inval (const GError *error); -+gboolean bolt_err_cancelled (const GError *error); -+ -+gboolean bolt_error_propagate_stripped (GError **dest, -+ GError **source); -+ -+G_END_DECLS -diff --git a/panels/thunderbolt/bolt-names.h b/panels/thunderbolt/bolt-names.h -new file mode 100644 -index 000000000000..2c0a97b24b49 ---- /dev/null -+++ b/panels/thunderbolt/bolt-names.h -@@ -0,0 +1,50 @@ -+/* -+ * Copyright © 2018 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library. If not, see . -+ * -+ * Authors: -+ * Christian J. Kellner -+ */ -+ -+#pragma once -+ -+/* D-Bus API revision (here for the lack of a better place) */ -+#define BOLT_DBUS_API_VERSION 1U -+ -+/* logging */ -+ -+#define BOLT_LOG_DEVICE_UID "BOLT_DEVICE_UID" -+#define BOLT_LOG_DEVICE_NAME "BOLT_DEVICE_NAME" -+#define BOLT_LOG_DEVICE_STATE "BOLT_DEVICE_STATE" -+ -+#define BOLT_LOG_ERROR_DOMAIN "ERROR_DOMAIN" -+#define BOLT_LOG_ERROR_CODE "ERROR_CODE" -+#define BOLT_LOG_ERROR_MESSAGE "ERROR_MESSAGE" -+ -+#define BOLT_LOG_TOPIC "BOLT_TOPIC" -+#define BOLT_LOG_VERSION "BOLT_VERSION" -+#define BOLT_LOG_CONTEXT "BOLT_LOG_CONTEXT" -+ -+/* logging - message ids */ -+#define BOLT_LOG_MSG_ID_STARTUP "dd11929c788e48bdbb6276fb5f26b08a" -+ -+ -+/* dbus */ -+ -+#define BOLT_DBUS_NAME "org.freedesktop.bolt" -+#define BOLT_DBUS_PATH "/org/freedesktop/bolt" -+#define BOLT_DBUS_INTERFACE "org.freedesktop.bolt1.Manager" -+ -+#define BOLT_DBUS_DEVICE_INTERFACE "org.freedesktop.bolt1.Device" -diff --git a/panels/thunderbolt/bolt-proxy.c b/panels/thunderbolt/bolt-proxy.c -new file mode 100644 -index 000000000000..e044c871f747 ---- /dev/null -+++ b/panels/thunderbolt/bolt-proxy.c -@@ -0,0 +1,514 @@ -+/* -+ * Copyright © 2017 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library. If not, see . -+ * -+ * Authors: -+ * Christian J. Kellner -+ */ -+ -+#include "bolt-proxy.h" -+ -+#include "bolt-enums.h" -+#include "bolt-error.h" -+#include "bolt-names.h" -+#include "bolt-str.h" -+ -+static void bolt_proxy_handle_props_changed (GDBusProxy *proxy, -+ GVariant *changed_properties, -+ GStrv invalidated_properties, -+ gpointer user_data); -+ -+static void bolt_proxy_handle_dbus_signal (GDBusProxy *proxy, -+ const gchar *sender_name, -+ const gchar *signal_name, -+ GVariant *params, -+ gpointer user_data); -+ -+G_DEFINE_TYPE (BoltProxy, bolt_proxy, G_TYPE_DBUS_PROXY); -+ -+ -+static void -+bolt_proxy_constructed (GObject *object) -+{ -+ G_OBJECT_CLASS (bolt_proxy_parent_class)->constructed (object); -+ -+ g_signal_connect (object, "g-properties-changed", -+ G_CALLBACK (bolt_proxy_handle_props_changed), object); -+ -+ g_signal_connect (object, "g-signal", -+ G_CALLBACK (bolt_proxy_handle_dbus_signal), object); -+} -+ -+static const BoltProxySignal * -+bolt_proxy_get_dbus_signals (guint *n) -+{ -+ *n = 0; -+ return NULL; -+} -+ -+static void -+bolt_proxy_class_init (BoltProxyClass *klass) -+{ -+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass); -+ -+ gobject_class->constructed = bolt_proxy_constructed; -+ -+ klass->get_dbus_signals = bolt_proxy_get_dbus_signals; -+ -+} -+ -+static void -+bolt_proxy_init (BoltProxy *object) -+{ -+} -+ -+static void -+bolt_proxy_handle_props_changed (GDBusProxy *proxy, -+ GVariant *changed_properties, -+ GStrv invalidated_properties, -+ gpointer user_data) -+{ -+ g_autoptr(GVariantIter) iter = NULL; -+ gboolean handled; -+ GParamSpec **pp; -+ const char *key; -+ guint n; -+ -+ pp = g_object_class_list_properties (G_OBJECT_GET_CLASS (proxy), &n); -+ -+ g_variant_get (changed_properties, "a{sv}", &iter); -+ while (g_variant_iter_next (iter, "{&sv}", &key, NULL)) -+ { -+ handled = FALSE; -+ for (guint i = 0; !handled && i < n; i++) -+ { -+ GParamSpec *pspec = pp[i]; -+ const char *nick; -+ const char *name; -+ -+ nick = g_param_spec_get_nick (pspec); -+ name = g_param_spec_get_name (pspec); -+ -+ handled = bolt_streq (nick, key); -+ -+ if (handled) -+ g_object_notify (G_OBJECT (user_data), name); -+ } -+ } -+ -+ g_free (pp); -+} -+ -+static void -+bolt_proxy_handle_dbus_signal (GDBusProxy *proxy, -+ const gchar *sender_name, -+ const gchar *signal_name, -+ GVariant *params, -+ gpointer user_data) -+{ -+ const BoltProxySignal *ps; -+ guint n; -+ -+ if (signal_name == NULL) -+ return; -+ -+ ps = BOLT_PROXY_GET_CLASS (proxy)->get_dbus_signals (&n); -+ -+ for (guint i = 0; i < n; i++) -+ { -+ const BoltProxySignal *sig = &ps[i]; -+ -+ if (g_str_equal (sig->theirs, signal_name)) -+ { -+ sig->handle (G_OBJECT (proxy), proxy, params); -+ break; -+ } -+ } -+ -+} -+ -+/* public methods */ -+ -+gboolean -+bolt_proxy_get_dbus_property (GObject *proxy, -+ GParamSpec *spec, -+ GValue *value) -+{ -+ g_autoptr(GVariant) val = NULL; -+ const GVariantType *vt; -+ gboolean handled = FALSE; -+ const char *nick; -+ -+ nick = g_param_spec_get_nick (spec); -+ val = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), nick); -+ -+ if (val == NULL) -+ return FALSE; -+ -+ vt = g_variant_get_type (val); -+ -+ if (g_variant_type_equal (vt, G_VARIANT_TYPE_STRING) && -+ G_IS_PARAM_SPEC_ENUM (spec)) -+ { -+ GParamSpecEnum *enum_spec = G_PARAM_SPEC_ENUM (spec); -+ GEnumValue *ev; -+ const char *str; -+ -+ str = g_variant_get_string (val, NULL); -+ ev = g_enum_get_value_by_nick (enum_spec->enum_class, str); -+ -+ handled = ev != NULL; -+ -+ if (handled) -+ g_value_set_enum (value, ev->value); -+ else -+ g_value_set_enum (value, enum_spec->default_value); -+ } -+ else if (g_variant_type_equal (vt, G_VARIANT_TYPE_STRING) && -+ G_IS_PARAM_SPEC_FLAGS (spec)) -+ { -+ GParamSpecFlags *flags_spec = G_PARAM_SPEC_FLAGS (spec); -+ GFlagsClass *flags_class = flags_spec->flags_class; -+ const char *str; -+ guint v; -+ -+ str = g_variant_get_string (val, NULL); -+ handled = bolt_flags_class_from_string (flags_class, str, &v, NULL); -+ -+ if (handled) -+ g_value_set_flags (value, v); -+ else -+ g_value_set_flags (value, flags_spec->default_value); -+ } -+ else -+ { -+ g_dbus_gvariant_to_gvalue (val, value); -+ } -+ -+ return handled; -+} -+ -+gboolean -+bolt_proxy_has_name_owner (BoltProxy *proxy) -+{ -+ const char *name_owner; -+ -+ g_return_val_if_fail (proxy != NULL, FALSE); -+ g_return_val_if_fail (BOLT_IS_PROXY (proxy), FALSE); -+ -+ name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (proxy)); -+ -+ return name_owner != NULL; -+} -+ -+static GParamSpec * -+find_property (BoltProxy *proxy, -+ const char *name, -+ GError **error) -+{ -+ GParamSpec *res = NULL; -+ GParamSpec **pp; -+ guint n; -+ -+ pp = g_object_class_list_properties (G_OBJECT_GET_CLASS (proxy), &n); -+ -+ for (guint i = 0; i < n; i++) -+ { -+ GParamSpec *pspec = pp[i]; -+ -+ if (bolt_streq (pspec->name, name)) -+ { -+ res = pspec; -+ break; -+ } -+ } -+ -+ if (pp == NULL) -+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_PROPERTY, -+ "could not find property '%s'", name); -+ -+ g_free (pp); -+ return res; -+} -+ -+static GVariant * -+bolt_proxy_get_cached_property (BoltProxy *proxy, -+ const char *name) -+{ -+ const char *bus_name = NULL; -+ GParamSpec *pspec; -+ GVariant *var; -+ -+ g_return_val_if_fail (BOLT_IS_PROXY (proxy), NULL); -+ pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (proxy), name); -+ -+ if (pspec == NULL) -+ return NULL; -+ -+ bus_name = g_param_spec_get_nick (pspec); -+ var = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), bus_name); -+ -+ return var; -+} -+ -+gboolean -+bolt_proxy_get_property_bool (BoltProxy *proxy, -+ const char *name, -+ gboolean *value) -+{ -+ g_autoptr(GVariant) var = NULL; -+ -+ var = bolt_proxy_get_cached_property (proxy, name); -+ -+ if (var == NULL) -+ return FALSE; -+ else if (value) -+ *value = g_variant_get_boolean (var); -+ -+ return TRUE; -+} -+ -+gboolean -+bolt_proxy_get_property_enum (BoltProxy *proxy, -+ const char *name, -+ gint *value) -+{ -+ g_autoptr(GVariant) var = NULL; -+ const char *str = NULL; -+ const char *bus_name = NULL; -+ GParamSpec *pspec; -+ GEnumValue *ev; -+ -+ g_return_val_if_fail (BOLT_IS_PROXY (proxy), FALSE); -+ -+ pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (proxy), name); -+ -+ if (pspec == NULL) -+ return FALSE; -+ -+ bus_name = g_param_spec_get_nick (pspec); -+ var = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), bus_name); -+ if (var == NULL) -+ return FALSE; -+ -+ str = g_variant_get_string (var, NULL); -+ -+ if (str == NULL) -+ return FALSE; -+ -+ ev = g_enum_get_value_by_nick (G_PARAM_SPEC_ENUM (pspec)->enum_class, str); -+ -+ if (ev == NULL) -+ return FALSE; -+ -+ if (value) -+ *value = ev->value; -+ -+ return TRUE; -+} -+ -+gboolean -+bolt_proxy_get_property_flags (BoltProxy *proxy, -+ const char *name, -+ guint *value) -+{ -+ g_autoptr(GVariant) var = NULL; -+ const char *str = NULL; -+ const char *bus_name = NULL; -+ GFlagsClass *flags_class; -+ GParamSpec *pspec; -+ guint v; -+ gboolean ok; -+ -+ g_return_val_if_fail (BOLT_IS_PROXY (proxy), FALSE); -+ -+ pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (proxy), name); -+ -+ if (pspec == NULL || !G_IS_PARAM_SPEC_FLAGS (pspec)) -+ return FALSE; -+ -+ bus_name = g_param_spec_get_nick (pspec); -+ var = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), bus_name); -+ if (var == NULL) -+ return FALSE; -+ -+ str = g_variant_get_string (var, NULL); -+ -+ if (str == NULL) -+ return FALSE; -+ -+ flags_class = G_PARAM_SPEC_FLAGS (pspec)->flags_class; -+ ok = bolt_flags_class_from_string (flags_class, str, &v, NULL); -+ -+ if (ok && value) -+ *value = v; -+ -+ return ok; -+} -+ -+gboolean -+bolt_proxy_get_property_uint32 (BoltProxy *proxy, -+ const char *name, -+ guint *value) -+{ -+ g_autoptr(GVariant) var = NULL; -+ -+ var = bolt_proxy_get_cached_property (proxy, name); -+ -+ if (var == NULL) -+ return FALSE; -+ else if (value) -+ *value = g_variant_get_uint32 (var); -+ -+ return TRUE; -+} -+ -+gboolean -+bolt_proxy_get_property_int64 (BoltProxy *proxy, -+ const char *name, -+ gint64 *value) -+{ -+ g_autoptr(GVariant) var = NULL; -+ -+ var = bolt_proxy_get_cached_property (proxy, name); -+ -+ if (var == NULL) -+ return FALSE; -+ else if (value) -+ *value = g_variant_get_int64 (var); -+ -+ return TRUE; -+} -+ -+gboolean -+bolt_proxy_get_property_uint64 (BoltProxy *proxy, -+ const char *name, -+ guint64 *value) -+{ -+ g_autoptr(GVariant) var = NULL; -+ -+ var = bolt_proxy_get_cached_property (proxy, name); -+ -+ if (var == NULL) -+ return FALSE; -+ else if (value) -+ *value = g_variant_get_uint64 (var); -+ -+ return TRUE; -+} -+ -+const char * -+bolt_proxy_get_property_string (BoltProxy *proxy, -+ const char *name) -+{ -+ g_autoptr(GVariant) var = NULL; -+ const char *val = NULL; -+ -+ var = bolt_proxy_get_cached_property (proxy, name); -+ -+ if (var != NULL) -+ val = g_variant_get_string (var, NULL); -+ -+ if (val && *val == '\0') -+ val = NULL; -+ -+ return val; -+} -+ -+gboolean -+bolt_proxy_set_property (BoltProxy *proxy, -+ const char *name, -+ GVariant *value, -+ GCancellable *cancellable, -+ GError **error) -+{ -+ GParamSpec *pp; -+ const char *iface; -+ gboolean ok = FALSE; -+ GVariant *res; -+ -+ pp = find_property (proxy, name, NULL); -+ if (pp != NULL) -+ name = g_param_spec_get_nick (pp); -+ -+ iface = g_dbus_proxy_get_interface_name (G_DBUS_PROXY (proxy)); -+ -+ res = g_dbus_proxy_call_sync (G_DBUS_PROXY (proxy), -+ "org.freedesktop.DBus.Properties.Set", -+ g_variant_new ("(ssv)", -+ iface, -+ name, -+ value), -+ G_DBUS_CALL_FLAGS_NONE, -+ -1, -+ cancellable, -+ error); -+ -+ if (res) -+ { -+ g_variant_unref (res); -+ ok = TRUE; -+ } -+ -+ return ok; -+} -+ -+void -+bolt_proxy_set_property_async (BoltProxy *proxy, -+ const char *name, -+ GVariant *value, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data) -+{ -+ GParamSpec *pp; -+ const char *iface; -+ -+ pp = find_property (proxy, name, NULL); -+ -+ if (pp != NULL) -+ name = g_param_spec_get_nick (pp); -+ -+ iface = g_dbus_proxy_get_interface_name (G_DBUS_PROXY (proxy)); -+ -+ g_dbus_proxy_call (G_DBUS_PROXY (proxy), -+ "org.freedesktop.DBus.Properties.Set", -+ g_variant_new ("(ssv)", -+ iface, -+ name, -+ value), -+ G_DBUS_CALL_FLAGS_NONE, -+ -1, -+ cancellable, -+ callback, -+ user_data); -+} -+ -+gboolean -+bolt_proxy_set_property_finish (GAsyncResult *res, -+ GError **error) -+{ -+ BoltProxy *proxy; -+ GVariant *val = NULL; -+ -+ proxy = (BoltProxy *) g_async_result_get_source_object (res); -+ val = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), res, error); -+ -+ if (val == NULL) -+ return FALSE; -+ -+ g_variant_unref (val); -+ return TRUE; -+} -diff --git a/panels/thunderbolt/bolt-proxy.h b/panels/thunderbolt/bolt-proxy.h -new file mode 100644 -index 000000000000..c05eb8c8850f ---- /dev/null -+++ b/panels/thunderbolt/bolt-proxy.h -@@ -0,0 +1,97 @@ -+/* -+ * Copyright © 2017 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library. If not, see . -+ * -+ * Authors: -+ * Christian J. Kellner -+ */ -+ -+#pragma once -+ -+#include -+ -+G_BEGIN_DECLS -+ -+typedef struct BoltProxySignal -+{ -+ -+ const char *theirs; -+ void (*handle)(GObject *self, -+ GDBusProxy *bus_proxy, -+ GVariant *params); -+ -+} BoltProxySignal; -+ -+#define BOLT_TYPE_PROXY (bolt_proxy_get_type ()) -+G_DECLARE_DERIVABLE_TYPE (BoltProxy, bolt_proxy, BOLT, PROXY, GDBusProxy) -+ -+struct _BoltProxyClass -+{ -+ GDBusProxyClass parent; -+ -+ /* virtuals */ -+ const BoltProxySignal * (*get_dbus_signals) (guint *n); -+}; -+ -+gboolean bolt_proxy_get_dbus_property (GObject *proxy, -+ GParamSpec *spec, -+ GValue *value); -+ -+gboolean bolt_proxy_has_name_owner (BoltProxy *proxy); -+ -+gboolean bolt_proxy_get_property_bool (BoltProxy *proxy, -+ const char *name, -+ gboolean *value); -+ -+gboolean bolt_proxy_get_property_enum (BoltProxy *proxy, -+ const char *name, -+ gint *value); -+ -+gboolean bolt_proxy_get_property_flags (BoltProxy *proxy, -+ const char *name, -+ guint *value); -+ -+gboolean bolt_proxy_get_property_uint32 (BoltProxy *proxy, -+ const char *name, -+ guint *value); -+ -+gboolean bolt_proxy_get_property_int64 (BoltProxy *proxy, -+ const char *name, -+ gint64 *value); -+ -+gboolean bolt_proxy_get_property_uint64 (BoltProxy *proxy, -+ const char *name, -+ guint64 *value); -+ -+const char * bolt_proxy_get_property_string (BoltProxy *proxy, -+ const char *name); -+ -+gboolean bolt_proxy_set_property (BoltProxy *proxy, -+ const char *name, -+ GVariant *value, -+ GCancellable *cancellable, -+ GError **error); -+ -+void bolt_proxy_set_property_async (BoltProxy *proxy, -+ const char *name, -+ GVariant *value, -+ GCancellable *cancellable, -+ GAsyncReadyCallback callback, -+ gpointer user_data); -+ -+gboolean bolt_proxy_set_property_finish (GAsyncResult *res, -+ GError **error); -+ -+G_END_DECLS -diff --git a/panels/thunderbolt/bolt-str.c b/panels/thunderbolt/bolt-str.c -new file mode 100644 -index 000000000000..fe0580d4863a ---- /dev/null -+++ b/panels/thunderbolt/bolt-str.c -@@ -0,0 +1,117 @@ -+/* -+ * Copyright © 2017 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library. If not, see . -+ * -+ * Authors: -+ * Christian J. Kellner -+ */ -+ -+#include "config.h" -+ -+#include "bolt-str.h" -+ -+#include -+ -+typedef void (* zero_fn_t) (void *s, -+ size_t n); -+void -+bolt_erase_n (void *data, gsize n) -+{ -+#if !HAVE_FN_EXPLICIT_BZERO -+ #warning no explicit bzero, using fallback -+ static volatile zero_fn_t explicit_bzero = bzero; -+#endif -+ -+ explicit_bzero (data, n); -+} -+ -+void -+bolt_str_erase (char *str) -+{ -+ if (str == NULL) -+ return; -+ -+ bolt_erase_n (str, strlen (str)); -+} -+ -+void -+bolt_str_erase_clear (char **str) -+{ -+ g_return_if_fail (str != NULL); -+ if (*str == NULL) -+ return; -+ -+ bolt_str_erase (*str); -+ g_free (*str); -+ *str = NULL; -+} -+ -+GStrv -+bolt_strv_from_ptr_array (GPtrArray **array) -+{ -+ GPtrArray *a; -+ -+ if (array == NULL || *array == NULL) -+ return NULL; -+ -+ a = *array; -+ -+ if (a->len == 0 || a->pdata[a->len - 1] != NULL) -+ g_ptr_array_add (a, NULL); -+ -+ *array = NULL; -+ return (GStrv) g_ptr_array_free (a, FALSE); -+} -+ -+char * -+bolt_strdup_validate (const char *string) -+{ -+ g_autofree char *str = NULL; -+ gboolean ok; -+ gsize l; -+ -+ if (string == NULL) -+ return NULL; -+ -+ str = g_strdup (string); -+ str = g_strstrip (str); -+ -+ l = strlen (str); -+ if (l == 0) -+ return NULL; -+ -+ ok = g_utf8_validate (str, l, NULL); -+ -+ if (!ok) -+ return NULL; -+ -+ return g_steal_pointer (&str); -+} -+ -+char * -+bolt_strstrip (char *string) -+{ -+ char *str; -+ -+ if (string == NULL) -+ return NULL; -+ -+ str = g_strstrip (string); -+ -+ if (strlen (str) == 0) -+ g_clear_pointer (&str, g_free); -+ -+ return str; -+} -diff --git a/panels/thunderbolt/bolt-str.h b/panels/thunderbolt/bolt-str.h -new file mode 100644 -index 000000000000..ecf95a7ed885 ---- /dev/null -+++ b/panels/thunderbolt/bolt-str.h -@@ -0,0 +1,43 @@ -+/* -+ * Copyright © 2017 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library. If not, see . -+ * -+ * Authors: -+ * Christian J. Kellner -+ */ -+ -+#pragma once -+ -+#include -+#include -+ -+G_BEGIN_DECLS -+ -+void bolt_erase_n (void *data, -+ gsize n); -+void bolt_str_erase (char *str); -+void bolt_str_erase_clear (char **str); -+ -+#define bolt_streq(s1, s2) (g_strcmp0 (s1, s2) == 0) -+ -+GStrv bolt_strv_from_ptr_array (GPtrArray **array); -+ -+#define bolt_yesno(val) val ? "yes" : "no" -+ -+char *bolt_strdup_validate (const char *string); -+ -+char *bolt_strstrip (char *string); -+ -+G_END_DECLS -diff --git a/panels/thunderbolt/bolt-time.c b/panels/thunderbolt/bolt-time.c -new file mode 100644 -index 000000000000..606aed69a444 ---- /dev/null -+++ b/panels/thunderbolt/bolt-time.c -@@ -0,0 +1,44 @@ -+/* -+ * Copyright © 2018 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library. If not, see . -+ * -+ * Authors: -+ * Christian J. Kellner -+ */ -+ -+#include "config.h" -+ -+#include "bolt-time.h" -+ -+char * -+bolt_epoch_format (guint64 seconds, const char *format) -+{ -+ g_autoptr(GDateTime) dt = NULL; -+ -+ dt = g_date_time_new_from_unix_utc ((gint64) seconds); -+ -+ if (dt == NULL) -+ return NULL; -+ -+ return g_date_time_format (dt, format); -+} -+ -+guint64 -+bolt_now_in_seconds (void) -+{ -+ gint64 now = g_get_real_time (); -+ -+ return (guint64) now / G_USEC_PER_SEC; -+} -diff --git a/panels/thunderbolt/bolt-time.h b/panels/thunderbolt/bolt-time.h -new file mode 100644 -index 000000000000..fc3ed9741940 ---- /dev/null -+++ b/panels/thunderbolt/bolt-time.h -@@ -0,0 +1,32 @@ -+/* -+ * Copyright © 2018 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * This library is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with this library. If not, see . -+ * -+ * Authors: -+ * Christian J. Kellner -+ */ -+ -+#pragma once -+ -+#include -+ -+G_BEGIN_DECLS -+ -+char * bolt_epoch_format (guint64 seconds, -+ const char *format); -+ -+guint64 bolt_now_in_seconds (void); -+ -+G_END_DECLS -diff --git a/panels/thunderbolt/cc-bolt-device-dialog.c b/panels/thunderbolt/cc-bolt-device-dialog.c -new file mode 100644 -index 000000000000..11469d46cb0b ---- /dev/null -+++ b/panels/thunderbolt/cc-bolt-device-dialog.c -@@ -0,0 +1,476 @@ -+/* Copyright (C) 2018 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ * -+ * Authors: Christian J. Kellner -+ * -+ */ -+ -+#include -+ -+#include -+ -+#include "bolt-device.h" -+#include "bolt-error.h" -+#include "bolt-time.h" -+ -+#include "cc-thunderbolt-resources.h" -+ -+#include "cc-bolt-device-dialog.h" -+ -+struct _CcBoltDeviceDialog -+{ -+ GtkDialog parent; -+ -+ BoltClient *client; -+ BoltDevice *device; -+ GCancellable *cancel; -+ -+ /* main ui */ -+ GtkHeaderBar *header_bar; -+ -+ /* notifications */ -+ GtkLabel *notify_label; -+ GtkRevealer *notify_revealer; -+ -+ /* device details */ -+ GtkLabel *name_label; -+ GtkLabel *status_label; -+ GtkLabel *uuid_label; -+ -+ GtkLabel *time_title; -+ GtkLabel *time_label; -+ -+ /* actions */ -+ GtkWidget *button_box; -+ GtkSpinner *spinner; -+ GtkButton *connect_button; -+ GtkButton *forget_button; -+}; -+ -+static void on_notify_button_clicked_cb (GtkButton *button, -+ CcBoltDeviceDialog *panel); -+ -+static void on_forget_button_clicked_cb (CcBoltDeviceDialog *dialog); -+static void on_connect_button_clicked_cb (CcBoltDeviceDialog *dialog); -+ -+G_DEFINE_TYPE (CcBoltDeviceDialog, cc_bolt_device_dialog, GTK_TYPE_DIALOG); -+ -+#define RESOURCE_UI "/org/gnome/control-center/thunderbolt/cc-bolt-device-dialog.ui" -+ -+static const char * -+status_to_string_for_ui (BoltDevice *dev) -+{ -+ BoltStatus status; -+ BoltAuthFlags aflags; -+ gboolean nopcie; -+ -+ status = bolt_device_get_status (dev); -+ aflags = bolt_device_get_authflags(dev); -+ nopcie = bolt_flag_isset (aflags, BOLT_AUTH_NOPCIE); -+ -+ switch (status) -+ { -+ case BOLT_STATUS_DISCONNECTED: -+ return C_("Thunderbolt Device Status", "Disconnected"); -+ -+ case BOLT_STATUS_CONNECTING: -+ return C_("Thunderbolt Device Status", "Connecting"); -+ -+ case BOLT_STATUS_CONNECTED: -+ return C_("Thunderbolt Device Status", "Connected"); -+ -+ case BOLT_STATUS_AUTH_ERROR: -+ return C_("Thunderbolt Device Status", "Authorization Error"); -+ -+ case BOLT_STATUS_AUTHORIZING: -+ return C_("Thunderbolt Device Status", "Authorizing"); -+ -+ case BOLT_STATUS_AUTHORIZED: -+ case BOLT_STATUS_AUTHORIZED_NEWKEY: -+ case BOLT_STATUS_AUTHORIZED_SECURE: -+ case BOLT_STATUS_AUTHORIZED_DPONLY: -+ if (nopcie) -+ return C_("Thunderbolt Device Status", "Reduced Functionality"); -+ else -+ return C_("Thunderbolt Device Status", "Connected & Authorized"); -+ -+ case BOLT_STATUS_UNKNOWN: -+ break; /* use default return value, i.e. Unknown */ -+ } -+ -+ return C_("Thunderbolt Device Status", "Unknown"); -+} -+ -+static void -+dialog_update_from_device (CcBoltDeviceDialog *dialog) -+{ -+ g_autofree char *generated = NULL; -+ g_autofree char *timestr = NULL; -+ const char *label; -+ const char *uuid; -+ const char *status_brief; -+ BoltStatus status; -+ gboolean stored; -+ BoltDevice *dev; -+ guint timestamp; -+ -+ if (gtk_widget_in_destruction (GTK_WIDGET (dialog))) -+ return; -+ -+ dev = dialog->device; -+ -+ uuid = bolt_device_get_uid (dev); -+ label = bolt_device_get_label (dev); -+ -+ stored = bolt_device_is_stored (dev); -+ status = bolt_device_get_status (dev); -+ -+ if (label == NULL) -+ { -+ const char *name = bolt_device_get_name (dev); -+ const char *vendor = bolt_device_get_vendor (dev); -+ -+ generated = g_strdup_printf ("%s %s", name, vendor); -+ label = generated; -+ } -+ -+ gtk_label_set_label (dialog->name_label, label); -+ gtk_header_bar_set_title (dialog->header_bar, label); -+ -+ status_brief = status_to_string_for_ui (dev); -+ gtk_label_set_label (dialog->status_label, status_brief); -+ gtk_widget_set_visible (GTK_WIDGET (dialog->forget_button), stored); -+ -+ /* while we are having an ongoing operation we are setting the buttons -+ * to be in-sensitive. In that case, if the button was visible -+ * before it will be hidden when the operation is finished by the -+ * dialog_operation_done() function */ -+ if (gtk_widget_is_sensitive (GTK_WIDGET (dialog->connect_button))) -+ gtk_widget_set_visible (GTK_WIDGET (dialog->connect_button), -+ status == BOLT_STATUS_CONNECTED); -+ -+ gtk_label_set_label (dialog->uuid_label, uuid); -+ -+ if (bolt_status_is_authorized (status)) -+ { -+ /* Translators: The time point the device was authorized. */ -+ gtk_label_set_label (dialog->time_title, _("Authorized at:")); -+ timestamp = bolt_device_get_authtime (dev); -+ } -+ else if (bolt_status_is_connected (status)) -+ { -+ /* Translators: The time point the device was connected. */ -+ gtk_label_set_label (dialog->time_title, _("Connected at:")); -+ timestamp = bolt_device_get_conntime (dev); -+ } -+ else -+ { -+ /* Translators: The time point the device was enrolled, -+ * i.e. authorized and stored in the device database. */ -+ gtk_label_set_label (dialog->time_title, _("Enrolled at:")); -+ timestamp = bolt_device_get_storetime (dev); -+ } -+ -+ timestr = bolt_epoch_format (timestamp, "%c"); -+ gtk_label_set_label (dialog->time_label, timestr); -+ -+} -+ -+static void -+on_device_notify_cb (GObject *gobject, -+ GParamSpec *pspec, -+ gpointer user_data) -+{ -+ CcBoltDeviceDialog *dialog = CC_BOLT_DEVICE_DIALOG (user_data); -+ -+ dialog_update_from_device (dialog); -+} -+ -+static void -+dialog_operation_start (CcBoltDeviceDialog *dialog) -+{ -+ gtk_widget_set_sensitive (GTK_WIDGET (dialog->connect_button), FALSE); -+ gtk_widget_set_sensitive (GTK_WIDGET (dialog->forget_button), FALSE); -+ gtk_spinner_start (dialog->spinner); -+} -+ -+static void -+dialog_operation_done (CcBoltDeviceDialog *dialog, -+ GtkWidget *sender, -+ GError *error) -+{ -+ GtkWidget *cb = GTK_WIDGET (dialog->connect_button); -+ GtkWidget *fb = GTK_WIDGET (dialog->forget_button); -+ -+ /* don' do anything if we are being destroyed */ -+ if (gtk_widget_in_destruction (GTK_WIDGET (dialog))) -+ return; -+ -+ /* also don't do anything if the op was canceled */ -+ if (error != NULL && bolt_err_cancelled (error)) -+ return; -+ -+ gtk_spinner_stop (dialog->spinner); -+ -+ if (error != NULL) -+ { -+ gtk_label_set_label (dialog->notify_label, error->message); -+ gtk_revealer_set_reveal_child (dialog->notify_revealer, TRUE); -+ -+ /* set the *other* button to sensitive */ -+ gtk_widget_set_sensitive (cb, cb != sender); -+ gtk_widget_set_sensitive (fb, fb != sender); -+ } -+ else -+ { -+ gtk_widget_set_visible (sender, FALSE); -+ gtk_widget_set_sensitive (cb, TRUE); -+ gtk_widget_set_sensitive (fb, TRUE); -+ } -+} -+ -+static void -+dialog_authorize_done (CcBoltDeviceDialog *dialog, -+ gboolean ok, -+ GError *error) -+{ -+ if (!ok) -+ g_prefix_error (&error, _("Failed to authorize device: ")); -+ -+ dialog_operation_done (dialog, GTK_WIDGET (dialog->connect_button), error); -+} -+ -+static void -+on_device_authorized (GObject *source, -+ GAsyncResult *res, -+ gpointer user_data) -+{ -+ g_autoptr(GError) err = NULL; -+ CcBoltDeviceDialog *dialog = CC_BOLT_DEVICE_DIALOG (user_data); -+ gboolean ok; -+ -+ ok = bolt_device_authorize_finish (BOLT_DEVICE (source), res, &err); -+ dialog_authorize_done (dialog, ok, err); -+} -+ -+static void -+on_device_enrolled (GObject *source_object, -+ GAsyncResult *res, -+ gpointer user_data) -+{ -+ g_autoptr(GError) err = NULL; -+ CcBoltDeviceDialog *dialog = CC_BOLT_DEVICE_DIALOG (user_data); -+ gboolean ok; -+ -+ ok = bolt_client_enroll_device_finish (dialog->client, res, NULL, &err); -+ dialog_authorize_done (dialog, ok, err); -+} -+ -+static void -+on_connect_button_clicked_cb (CcBoltDeviceDialog *dialog) -+{ -+ BoltDevice *device = dialog->device; -+ gboolean stored; -+ -+ g_return_if_fail (device != NULL); -+ -+ dialog_operation_start (dialog); -+ -+ stored = bolt_device_is_stored (device); -+ if (stored) -+ { -+ bolt_device_authorize_async (device, -+ BOLT_AUTHCTRL_NONE, -+ dialog->cancel, -+ on_device_authorized, -+ dialog); -+ } -+ else -+ { -+ const char *uid = bolt_device_get_uid (device); -+ -+ bolt_client_enroll_device_async (dialog->client, -+ uid, -+ BOLT_POLICY_DEFAULT, -+ BOLT_AUTHCTRL_NONE, -+ dialog->cancel, -+ on_device_enrolled, -+ dialog); -+ } -+ -+} -+ -+static void -+on_forget_device_done (GObject *source_object, -+ GAsyncResult *res, -+ gpointer user_data) -+{ -+ g_autoptr(GError) err = NULL; -+ CcBoltDeviceDialog *dialog = CC_BOLT_DEVICE_DIALOG (user_data); -+ gboolean ok; -+ -+ ok = bolt_client_forget_device_finish (dialog->client, res, &err); -+ -+ if (!ok) -+ g_prefix_error (&err, _("Failed to forget device: ")); -+ -+ dialog_operation_done (dialog, GTK_WIDGET (dialog->forget_button), err); -+} -+ -+static void -+on_forget_button_clicked_cb (CcBoltDeviceDialog *dialog) -+{ -+ const char *uid = NULL; -+ -+ g_return_if_fail (dialog->device != NULL); -+ -+ uid = bolt_device_get_uid (dialog->device); -+ dialog_operation_start (dialog); -+ -+ bolt_client_forget_device_async (dialog->client, -+ uid, -+ dialog->cancel, -+ on_forget_device_done, -+ dialog); -+} -+ -+static void -+on_notify_button_clicked_cb (GtkButton *button, -+ CcBoltDeviceDialog *dialog) -+{ -+ gtk_revealer_set_reveal_child (dialog->notify_revealer, FALSE); -+} -+ -+ -+static void -+cc_bolt_device_dialog_finalize (GObject *object) -+{ -+ CcBoltDeviceDialog *dialog = CC_BOLT_DEVICE_DIALOG (object); -+ -+ g_clear_object (&dialog->device); -+ g_cancellable_cancel (dialog->cancel); -+ g_clear_object (&dialog->cancel); -+ g_clear_object (&dialog->client); -+ -+ G_OBJECT_CLASS (cc_bolt_device_dialog_parent_class)->finalize (object); -+} -+ -+static void -+cc_bolt_device_dialog_class_init (CcBoltDeviceDialogClass *klass) -+{ -+ GObjectClass *object_class = G_OBJECT_CLASS (klass); -+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); -+ -+ object_class->finalize = cc_bolt_device_dialog_finalize; -+ -+ gtk_widget_class_set_template_from_resource (widget_class, RESOURCE_UI); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltDeviceDialog, header_bar); -+ -+ gtk_widget_class_bind_template_child (widget_class, CcBoltDeviceDialog, notify_label); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltDeviceDialog, notify_revealer); -+ -+ gtk_widget_class_bind_template_child (widget_class, CcBoltDeviceDialog, name_label); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltDeviceDialog, status_label); -+ -+ gtk_widget_class_bind_template_child (widget_class, CcBoltDeviceDialog, uuid_label); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltDeviceDialog, time_title); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltDeviceDialog, time_label); -+ -+ gtk_widget_class_bind_template_child (widget_class, CcBoltDeviceDialog, button_box); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltDeviceDialog, spinner); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltDeviceDialog, connect_button); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltDeviceDialog, forget_button); -+ -+ gtk_widget_class_bind_template_callback (widget_class, on_notify_button_clicked_cb); -+ gtk_widget_class_bind_template_callback (widget_class, on_connect_button_clicked_cb); -+ gtk_widget_class_bind_template_callback (widget_class, on_forget_button_clicked_cb); -+} -+ -+static void -+cc_bolt_device_dialog_init (CcBoltDeviceDialog *dialog) -+{ -+ g_resources_register (cc_thunderbolt_get_resource ()); -+ gtk_widget_init_template (GTK_WIDGET (dialog)); -+} -+ -+/* public functions */ -+CcBoltDeviceDialog * -+cc_bolt_device_dialog_new (void) -+{ -+ CcBoltDeviceDialog *dialog; -+ -+ dialog = g_object_new (CC_TYPE_BOLT_DEVICE_DIALOG, -+ "use-header-bar", TRUE, -+ NULL); -+ return dialog; -+} -+ -+void -+cc_bolt_device_dialog_set_client (CcBoltDeviceDialog *dialog, -+ BoltClient *client) -+{ -+ g_clear_object (&dialog->client); -+ dialog->client = g_object_ref (client); -+} -+ -+void -+cc_bolt_device_dialog_set_device (CcBoltDeviceDialog *dialog, -+ BoltDevice *device) -+{ -+ if (device == dialog->device) -+ return; -+ -+ if (dialog->device) -+ { -+ g_cancellable_cancel (dialog->cancel); -+ g_clear_object (&dialog->cancel); -+ dialog->cancel = g_cancellable_new (); -+ -+ g_signal_handlers_disconnect_by_func (dialog->device, -+ G_CALLBACK (on_device_notify_cb), -+ dialog); -+ g_clear_object (&dialog->device); -+ } -+ -+ if (device == NULL) -+ return; -+ -+ dialog->device = g_object_ref (device); -+ g_signal_connect_object (dialog->device, -+ "notify", -+ G_CALLBACK (on_device_notify_cb), -+ dialog, -+ 0); -+ -+ /* reset the sensitivity of the buttons, because -+ * dialog_update_from_device, because it can't know */ -+ gtk_widget_set_sensitive (GTK_WIDGET (dialog->connect_button), TRUE); -+ gtk_widget_set_sensitive (GTK_WIDGET (dialog->forget_button), TRUE); -+ -+ dialog_update_from_device (dialog); -+} -+ -+BoltDevice * -+cc_bolt_device_dialog_peek_device (CcBoltDeviceDialog *dialog) -+{ -+ return dialog->device; -+} -+ -+gboolean -+cc_bolt_device_dialog_device_equal (CcBoltDeviceDialog *dialog, -+ BoltDevice *device) -+{ -+ return dialog->device != NULL && device == dialog->device; -+} -diff --git a/panels/thunderbolt/cc-bolt-device-dialog.h b/panels/thunderbolt/cc-bolt-device-dialog.h -new file mode 100644 -index 000000000000..d2c44c8589a8 ---- /dev/null -+++ b/panels/thunderbolt/cc-bolt-device-dialog.h -@@ -0,0 +1,45 @@ -+/* Copyright (C) 2018 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ * -+ * Authors: Christian J. Kellner -+ * -+ */ -+ -+#pragma once -+ -+#include -+ -+#include "bolt-client.h" -+#include "bolt-device.h" -+ -+G_BEGIN_DECLS -+ -+#define CC_TYPE_BOLT_DEVICE_DIALOG cc_bolt_device_dialog_get_type () -+G_DECLARE_FINAL_TYPE (CcBoltDeviceDialog, cc_bolt_device_dialog, CC, BOLT_DEVICE_DIALOG, GtkDialog); -+ -+ -+CcBoltDeviceDialog * cc_bolt_device_dialog_new (void); -+ -+void cc_bolt_device_dialog_set_client (CcBoltDeviceDialog *dialog, -+ BoltClient *client); -+ -+void cc_bolt_device_dialog_set_device (CcBoltDeviceDialog *dialog, -+ BoltDevice *device); -+BoltDevice * cc_bolt_device_dialog_peek_device (CcBoltDeviceDialog *dialog); -+ -+gboolean cc_bolt_device_dialog_device_equal (CcBoltDeviceDialog *dialog, -+ BoltDevice *device); -+ -+G_END_DECLS -diff --git a/panels/thunderbolt/cc-bolt-device-dialog.ui b/panels/thunderbolt/cc-bolt-device-dialog.ui -new file mode 100644 -index 000000000000..cd19796db20d ---- /dev/null -+++ b/panels/thunderbolt/cc-bolt-device-dialog.ui -@@ -0,0 +1,359 @@ -+ -+ -+ -+ -+ -+ -diff --git a/panels/thunderbolt/cc-bolt-device-entry.c b/panels/thunderbolt/cc-bolt-device-entry.c -new file mode 100644 -index 000000000000..1e6d6e75a228 ---- /dev/null -+++ b/panels/thunderbolt/cc-bolt-device-entry.c -@@ -0,0 +1,218 @@ -+/* Copyright (C) 2018 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ * -+ * Authors: Christian J. Kellner -+ * -+ */ -+ -+#include -+ -+#include "bolt-str.h" -+ -+#include "cc-bolt-device-entry.h" -+ -+#include "cc-thunderbolt-resources.h" -+ -+#include -+ -+struct _CcBoltDeviceEntry -+{ -+ GtkListBoxRow parent; -+ -+ BoltDevice *device; -+ -+ /* main ui */ -+ GtkLabel *name_label; -+ GtkLabel *status_label; -+}; -+ -+static const char * device_status_to_brief_for_ui (BoltDevice *dev); -+ -+enum -+{ -+ SIGNAL_STATUS_CHANGED, -+ SIGNAL_LAST -+}; -+ -+static guint signals[SIGNAL_LAST] = {0}; -+ -+G_DEFINE_TYPE (CcBoltDeviceEntry, cc_bolt_device_entry, GTK_TYPE_LIST_BOX_ROW); -+ -+#define RESOURCE_UI "/org/gnome/control-center/thunderbolt/cc-bolt-device-entry.ui" -+ -+static void -+entry_set_name (CcBoltDeviceEntry *entry) -+{ -+ g_autofree char *name = NULL; -+ BoltDevice *dev = entry->device; -+ -+ g_return_if_fail (dev != NULL); -+ -+ name = bolt_device_get_display_name (dev); -+ -+ gtk_label_set_label (entry->name_label, name); -+} -+ -+static void -+entry_update_status (CcBoltDeviceEntry *entry) -+{ -+ const char *brief; -+ BoltStatus status; -+ -+ status = bolt_device_get_status (entry->device); -+ brief = device_status_to_brief_for_ui (entry->device); -+ -+ gtk_label_set_label (entry->status_label, brief); -+ -+ g_signal_emit (entry, -+ signals[SIGNAL_STATUS_CHANGED], -+ 0, -+ status); -+} -+ -+static void -+on_device_notify_cb (GObject *gobject, -+ GParamSpec *pspec, -+ gpointer user_data) -+{ -+ CcBoltDeviceEntry *entry = CC_BOLT_DEVICE_ENTRY (user_data); -+ const char *what; -+ -+ what = g_param_spec_get_name (pspec); -+ -+ if (bolt_streq (what, "status")) -+ entry_update_status (entry); -+ else if (bolt_streq (what, "label") || -+ bolt_streq (what, "name") || -+ bolt_streq (what, "vendor")) -+ entry_set_name (entry); -+} -+ -+/* device helpers */ -+ -+static const char * -+device_status_to_brief_for_ui (BoltDevice *dev) -+{ -+ BoltStatus status; -+ BoltAuthFlags aflags; -+ gboolean nopcie; -+ -+ status = bolt_device_get_status (dev); -+ aflags = bolt_device_get_authflags(dev); -+ nopcie = bolt_flag_isset (aflags, BOLT_AUTH_NOPCIE); -+ -+ switch (status) -+ { -+ case BOLT_STATUS_DISCONNECTED: -+ return C_("Thunderbolt Device Status", "Disconnected"); -+ -+ case BOLT_STATUS_CONNECTING: -+ return C_("Thunderbolt Device Status", "Connecting"); -+ -+ case BOLT_STATUS_CONNECTED: -+ case BOLT_STATUS_AUTHORIZED_DPONLY: -+ return C_("Thunderbolt Device Status", "Connected"); -+ -+ case BOLT_STATUS_AUTH_ERROR: -+ return C_("Thunderbolt Device Status", "Error"); -+ -+ case BOLT_STATUS_AUTHORIZING: -+ return C_("Thunderbolt Device Status", "Authorizing"); -+ -+ case BOLT_STATUS_AUTHORIZED: -+ case BOLT_STATUS_AUTHORIZED_NEWKEY: -+ case BOLT_STATUS_AUTHORIZED_SECURE: -+ if (nopcie) -+ return C_("Thunderbolt Device Status", "Connected"); -+ else -+ return C_("Thunderbolt Device Status", "Authorized"); -+ -+ case BOLT_STATUS_UNKNOWN: -+ break; /* use function default */ -+ } -+ -+ return C_("Thunderbolt Device Status", "Unknown"); -+} -+ -+static void -+cc_bolt_device_entry_finalize (GObject *object) -+{ -+ CcBoltDeviceEntry *entry = CC_BOLT_DEVICE_ENTRY (object); -+ -+ g_clear_object (&entry->device); -+ -+ G_OBJECT_CLASS (cc_bolt_device_entry_parent_class)->finalize (object); -+} -+ -+static void -+cc_bolt_device_entry_class_init (CcBoltDeviceEntryClass *klass) -+{ -+ GObjectClass *object_class = G_OBJECT_CLASS (klass); -+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); -+ -+ object_class->finalize = cc_bolt_device_entry_finalize; -+ -+ gtk_widget_class_set_template_from_resource (widget_class, RESOURCE_UI); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltDeviceEntry, name_label); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltDeviceEntry, status_label); -+ -+ signals[SIGNAL_STATUS_CHANGED] = -+ g_signal_new ("status-changed", -+ G_TYPE_FROM_CLASS (object_class), -+ G_SIGNAL_RUN_LAST, -+ 0, -+ NULL, NULL, -+ NULL, -+ G_TYPE_NONE, -+ 1, BOLT_TYPE_STATUS); -+} -+ -+static void -+cc_bolt_device_entry_init (CcBoltDeviceEntry *entry) -+{ -+ g_resources_register (cc_thunderbolt_get_resource ()); -+ gtk_widget_init_template (GTK_WIDGET (entry)); -+} -+ -+/* public function */ -+ -+CcBoltDeviceEntry * -+cc_bolt_device_entry_new (BoltDevice *device) -+{ -+ CcBoltDeviceEntry *entry; -+ -+ entry = g_object_new (CC_TYPE_BOLT_DEVICE_ENTRY, NULL); -+ entry->device = g_object_ref (device); -+ -+ entry_set_name (entry); -+ entry_update_status (entry); -+ -+ g_signal_connect_object (entry->device, -+ "notify", -+ G_CALLBACK (on_device_notify_cb), -+ entry, -+ 0); -+ -+ return entry; -+} -+ -+BoltDevice * -+cc_bolt_device_entry_get_device (CcBoltDeviceEntry *entry) -+{ -+ g_return_val_if_fail (entry != NULL, NULL); -+ g_return_val_if_fail (CC_IS_BOLT_DEVICE_ENTRY (entry), NULL); -+ -+ return entry->device; -+} -diff --git a/panels/thunderbolt/cc-bolt-device-entry.h b/panels/thunderbolt/cc-bolt-device-entry.h -new file mode 100644 -index 000000000000..f93cee5f825b ---- /dev/null -+++ b/panels/thunderbolt/cc-bolt-device-entry.h -@@ -0,0 +1,34 @@ -+/* Copyright (C) 2018 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ * -+ * Authors: Christian J. Kellner -+ * -+ */ -+ -+#pragma once -+ -+#include -+#include "bolt-device.h" -+ -+G_BEGIN_DECLS -+ -+#define CC_TYPE_BOLT_DEVICE_ENTRY cc_bolt_device_entry_get_type () -+G_DECLARE_FINAL_TYPE (CcBoltDeviceEntry, cc_bolt_device_entry, CC, BOLT_DEVICE_ENTRY, GtkListBoxRow); -+ -+ -+CcBoltDeviceEntry * cc_bolt_device_entry_new (BoltDevice *device); -+BoltDevice * cc_bolt_device_entry_get_device (CcBoltDeviceEntry *entry); -+ -+G_END_DECLS -diff --git a/panels/thunderbolt/cc-bolt-device-entry.ui b/panels/thunderbolt/cc-bolt-device-entry.ui -new file mode 100644 -index 000000000000..37f865333d71 ---- /dev/null -+++ b/panels/thunderbolt/cc-bolt-device-entry.ui -@@ -0,0 +1,49 @@ -+ -+ -+ -+ -+ -+ -diff --git a/panels/thunderbolt/cc-bolt-panel.c b/panels/thunderbolt/cc-bolt-panel.c -new file mode 100644 -index 000000000000..e67e3625eb2c ---- /dev/null -+++ b/panels/thunderbolt/cc-bolt-panel.c -@@ -0,0 +1,958 @@ -+/* Copyright (C) 2018 Red Hat, Inc -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, see . -+ * -+ * Authors: Christian J. Kellner -+ * -+ */ -+ -+#include -+ -+#include -+#include -+ -+#include -+#include -+ -+#include "cc-bolt-device-dialog.h" -+#include "cc-bolt-device-entry.h" -+ -+#include "bolt-client.h" -+#include "bolt-str.h" -+ -+#include "cc-thunderbolt-resources.h" -+ -+#define CC_TYPE_BOLT_PANEL cc_bolt_panel_get_type () -+G_DECLARE_FINAL_TYPE (CcBoltPanel, cc_bolt_panel, CC, BOLT_PANEL, CcPanel); -+ -+struct _CcBoltPanel -+{ -+ CcPanel parent; -+ -+ BoltClient *client; -+ GCancellable *cancel; -+ -+ /* headerbar menu */ -+ GtkBox *headerbar_box; -+ GtkLockButton *lock_button; -+ -+ /* main ui */ -+ GtkStack *container; -+ -+ /* empty state */ -+ GtkLabel *notb_caption; -+ GtkLabel *notb_details; -+ -+ /* notifications */ -+ GtkLabel *notification_label; -+ GtkRevealer *notification_revealer; -+ -+ /* authmode */ -+ GtkSwitch *authmode_switch; -+ GtkSpinner *authmode_spinner; -+ GtkStack *authmode_mode; -+ -+ /* device list */ -+ GHashTable *devices; -+ -+ GtkStack *devices_stack; -+ GtkBox *devices_box; -+ GtkBox *pending_box; -+ -+ GtkListBox *devices_list; -+ GtkListBox *pending_list; -+ -+ /* device details dialog */ -+ CcBoltDeviceDialog *device_dialog; -+ -+ /* polkit integration */ -+ GPermission *permission; -+}; -+ -+/* initialization */ -+static void bolt_client_ready (GObject *source, -+ GAsyncResult *res, -+ gpointer user_data); -+ -+/* panel functions */ -+static void cc_bolt_panel_set_no_thunderbolt (CcBoltPanel *panel, -+ const char *custom_msg); -+ -+static void cc_bolt_panel_name_owner_changed (CcBoltPanel *panel); -+ -+static CcBoltDeviceEntry * cc_bolt_panel_add_device (CcBoltPanel *panel, -+ BoltDevice *dev); -+ -+static void cc_bolt_panel_del_device_entry (CcBoltPanel *panel, -+ CcBoltDeviceEntry *entry); -+ -+static void cc_bolt_panel_authmode_sync (CcBoltPanel *panel); -+ -+static void cc_panel_list_box_migrate (CcBoltPanel *panel, -+ GtkListBox *from, -+ GtkListBox *to, -+ CcBoltDeviceEntry *entry); -+ -+/* bolt client signals */ -+static void on_bolt_name_owner_changed_cb (GObject *object, -+ GParamSpec *pspec, -+ gpointer user_data); -+ -+static void on_bolt_device_added_cb (BoltClient *cli, -+ const char *path, -+ CcBoltPanel *panel); -+ -+static void on_bolt_device_removed_cb (BoltClient *cli, -+ const char *opath, -+ CcBoltPanel *panel); -+ -+static void on_bolt_notify_authmode_cb (GObject *gobject, -+ GParamSpec *pspec, -+ gpointer user_data); -+ -+/* panel signals */ -+static gboolean on_authmode_state_set_cb (CcBoltPanel *panel, -+ gboolean state, -+ GtkSwitch *toggle); -+ -+static void on_device_entry_row_activated_cb (CcBoltPanel *panel, -+ GtkListBoxRow *row); -+ -+static gboolean on_device_dialog_delete_event_cb (GtkWidget *widget, -+ GdkEvent *event, -+ CcBoltPanel *panel); -+ -+static void on_device_entry_status_changed_cb (CcBoltDeviceEntry *entry, -+ BoltStatus new_status, -+ CcBoltPanel *panel); -+ -+static void on_notification_button_clicked_cb (GtkButton *button, -+ CcBoltPanel *panel); -+ -+ -+/* polkit */ -+static void on_permission_ready (GObject *source_object, -+ GAsyncResult *res, -+ gpointer user_data); -+ -+static void on_permission_notify_cb (GPermission *permission, -+ GParamSpec *pspec, -+ CcBoltPanel *panel); -+ -+/* device related helpers helpers */ -+static gint device_entries_sort_by_recency (GtkListBoxRow *a_row, -+ GtkListBoxRow *b_row, -+ gpointer user_data); -+ -+static gint device_entries_sort_by_syspath (GtkListBoxRow *a_row, -+ GtkListBoxRow *b_row, -+ gpointer user_data); -+ -+#define RESOURCE_PANEL_UI "/org/gnome/control-center/thunderbolt/cc-bolt-panel.ui" -+ -+CC_PANEL_REGISTER (CcBoltPanel, cc_bolt_panel); -+ -+static void -+bolt_client_ready (GObject *source, -+ GAsyncResult *res, -+ gpointer user_data) -+{ -+ g_autoptr(GError) err = NULL; -+ g_autoptr(CcBoltPanel) panel = NULL; -+ BoltClient *client; -+ -+ panel = CC_BOLT_PANEL (user_data); -+ client = bolt_client_new_finish (res, &err); -+ -+ if (client == NULL) -+ { -+ const char *text; -+ -+ /* operation got cancelled because the panel got destroyed */ -+ if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED) || -+ g_error_matches (err, G_IO_ERROR, G_IO_ERROR_FAILED_HANDLED)) -+ return; -+ -+ g_warning ("Could not create client: %s", err->message); -+ text = _("The thunderbolt subsystem (boltd) is not installed or " -+ "not setup properly."); -+ -+ gtk_label_set_label (panel->notb_details, text); -+ gtk_stack_set_visible_child_name (panel->container, "no-thunderbolt"); -+ -+ return; -+ } -+ -+ g_signal_connect_object (client, "notify::g-name-owner", -+ G_CALLBACK (on_bolt_name_owner_changed_cb), -+ panel, 0); -+ -+ g_signal_connect_object (client, "device-added", -+ G_CALLBACK (on_bolt_device_added_cb), -+ panel, 0); -+ -+ g_signal_connect_object (client, "device-removed", -+ G_CALLBACK (on_bolt_device_removed_cb), -+ panel, 0); -+ -+ g_signal_connect_object (client, "notify::auth-mode", -+ G_CALLBACK (on_bolt_notify_authmode_cb), -+ panel, 0); -+ -+ panel->client = client; -+ -+ cc_bolt_device_dialog_set_client (panel->device_dialog, client); -+ -+ cc_bolt_panel_authmode_sync (panel); -+ -+ g_object_bind_property (panel->authmode_switch, "active", -+ panel->devices_box, "sensitive", -+ G_BINDING_SYNC_CREATE); -+ -+ g_object_bind_property (panel->authmode_switch, "active", -+ panel->pending_box, "sensitive", -+ G_BINDING_SYNC_CREATE); -+ -+ gtk_stack_set_visible_child_name (panel->devices_stack, "no-devices"); -+ cc_bolt_panel_name_owner_changed (panel); -+} -+ -+static gboolean -+devices_table_transfer_entry (GHashTable *from, -+ GHashTable *to, -+ gconstpointer key) -+{ -+ gpointer k, v; -+ gboolean found; -+ -+ found = g_hash_table_lookup_extended (from, key, &k, &v); -+ -+ if (found) -+ { -+ g_hash_table_steal (from, key); -+ g_hash_table_insert (to, k, v); -+ } -+ -+ return found; -+} -+ -+static void -+devices_table_clear_entries (GHashTable *table, -+ CcBoltPanel *panel) -+{ -+ GHashTableIter iter; -+ gpointer key, value; -+ -+ g_hash_table_iter_init (&iter, table); -+ while (g_hash_table_iter_next (&iter, &key, &value)) -+ { -+ CcBoltDeviceEntry *entry = value; -+ -+ cc_bolt_panel_del_device_entry (panel, entry); -+ g_hash_table_iter_remove (&iter); -+ } -+} -+ -+static void -+devices_table_synchronize (CcBoltPanel *panel) -+{ -+ g_autoptr(GError) err = NULL; -+ g_autoptr(GPtrArray) devices = NULL; -+ g_autoptr(GHashTable) old = NULL; -+ -+ devices = bolt_client_list_devices (panel->client, panel->cancel, &err); -+ -+ if (devices == NULL) -+ { -+ g_warning ("Could not list devices: %s", err->message); -+ devices = g_ptr_array_new_with_free_func (g_object_unref); -+ } -+ -+ old = panel->devices; -+ panel->devices = g_hash_table_new (g_str_hash, g_str_equal); -+ -+ for (guint i = 0; i < devices->len; i++) -+ { -+ BoltDevice *dev = g_ptr_array_index (devices, i); -+ const char *path; -+ gboolean found; -+ -+ path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (dev)); -+ found = devices_table_transfer_entry (old, panel->devices, path); -+ -+ if (found) -+ continue; -+ -+ cc_bolt_panel_add_device (panel, dev); -+ } -+ -+ devices_table_clear_entries (old, panel); -+ gtk_stack_set_visible_child_name (panel->container, "devices-listing"); -+} -+ -+static gboolean -+list_box_sync_visible (GtkListBox *lstbox) -+{ -+ g_autoptr(GList) children = NULL; -+ gboolean show; -+ -+ children = gtk_container_get_children (GTK_CONTAINER (lstbox)); -+ show = g_list_length (children) > 0; -+ -+ gtk_widget_set_visible (GTK_WIDGET (lstbox), show); -+ -+ return show; -+} -+ -+static GtkWidget * -+cc_bolt_panel_box_for_listbox (CcBoltPanel *panel, -+ GtkListBox *lstbox) -+{ -+ if ((gpointer) lstbox == panel->devices_list) -+ return GTK_WIDGET (panel->devices_box); -+ else if ((gpointer) lstbox == panel->pending_list) -+ return GTK_WIDGET (panel->pending_box); -+ -+ g_return_val_if_reached (NULL); -+} -+ -+static CcBoltDeviceEntry * -+cc_bolt_panel_add_device (CcBoltPanel *panel, -+ BoltDevice *dev) -+{ -+ CcBoltDeviceEntry *entry; -+ BoltDeviceType type; -+ BoltStatus status; -+ const char *path; -+ -+ type = bolt_device_get_device_type (dev); -+ -+ if (type != BOLT_DEVICE_PERIPHERAL) -+ return FALSE; -+ -+ entry = cc_bolt_device_entry_new (dev); -+ path = g_dbus_proxy_get_object_path (G_DBUS_PROXY (dev)); -+ -+ /* add to the list box */ -+ gtk_widget_show_all (GTK_WIDGET (entry)); -+ -+ status = bolt_device_get_status (dev); -+ -+ if (bolt_status_is_pending (status)) -+ { -+ gtk_container_add (GTK_CONTAINER (panel->pending_list), GTK_WIDGET (entry)); -+ gtk_widget_show_all (GTK_WIDGET (panel->pending_list)); -+ gtk_widget_show_all (GTK_WIDGET (panel->pending_box)); -+ } -+ else -+ { -+ gtk_container_add (GTK_CONTAINER (panel->devices_list), GTK_WIDGET (entry)); -+ gtk_widget_show_all (GTK_WIDGET (panel->devices_list)); -+ gtk_widget_show_all (GTK_WIDGET (panel->devices_box)); -+ } -+ -+ g_signal_connect_object (entry, "status-changed", -+ G_CALLBACK (on_device_entry_status_changed_cb), -+ panel, 0); -+ -+ gtk_stack_set_visible_child_name (panel->devices_stack, "have-devices"); -+ g_hash_table_insert (panel->devices, (gpointer) path, entry); -+ return entry; -+} -+ -+static void -+cc_bolt_panel_del_device_entry (CcBoltPanel *panel, -+ CcBoltDeviceEntry *entry) -+{ -+ BoltDevice *dev; -+ GtkWidget *box; -+ GtkWidget *p; -+ gboolean show; -+ -+ dev = cc_bolt_device_entry_get_device (entry); -+ if (cc_bolt_device_dialog_device_equal (panel->device_dialog, dev)) -+ { -+ gtk_widget_hide (GTK_WIDGET (panel->device_dialog)); -+ cc_bolt_device_dialog_set_device (panel->device_dialog, NULL); -+ } -+ -+ p = gtk_widget_get_parent (GTK_WIDGET (entry)); -+ gtk_widget_destroy (GTK_WIDGET (entry)); -+ -+ box = cc_bolt_panel_box_for_listbox (panel, GTK_LIST_BOX (p)); -+ show = list_box_sync_visible (GTK_LIST_BOX (p)); -+ gtk_widget_set_visible (box, show); -+ -+ if (!gtk_widget_is_visible (GTK_WIDGET (panel->pending_list)) && -+ !gtk_widget_is_visible (GTK_WIDGET (panel->devices_list))) -+ gtk_stack_set_visible_child_name (panel->devices_stack, "no-devices"); -+} -+ -+static void -+cc_bolt_panel_authmode_sync (CcBoltPanel *panel) -+{ -+ BoltClient *client = panel->client; -+ BoltAuthMode mode; -+ gboolean enabled; -+ const char *name; -+ -+ mode = bolt_client_get_authmode (client); -+ -+ enabled = (mode & BOLT_AUTH_ENABLED) != 0; -+ -+ g_signal_handlers_block_by_func (panel->authmode_switch, -+ on_authmode_state_set_cb, -+ panel); -+ -+ gtk_switch_set_state (panel->authmode_switch, enabled); -+ -+ g_signal_handlers_unblock_by_func (panel->authmode_switch, -+ on_authmode_state_set_cb, -+ panel); -+ -+ name = enabled ? "enabled" : "disabled"; -+ gtk_stack_set_visible_child_name (panel->authmode_mode, name); -+} -+ -+static void -+cc_panel_list_box_migrate (CcBoltPanel *panel, -+ GtkListBox *from, -+ GtkListBox *to, -+ CcBoltDeviceEntry *entry) -+{ -+ GtkWidget *from_box; -+ GtkWidget *to_box; -+ gboolean show; -+ GtkWidget *target; -+ -+ target = GTK_WIDGET (entry); -+ -+ gtk_container_remove (GTK_CONTAINER (from), target); -+ gtk_container_add (GTK_CONTAINER (to), target); -+ gtk_widget_show_all (GTK_WIDGET (to)); -+ -+ from_box = cc_bolt_panel_box_for_listbox (panel, from); -+ to_box = cc_bolt_panel_box_for_listbox (panel, to); -+ -+ show = list_box_sync_visible (from); -+ gtk_widget_set_visible (from_box, show); -+ gtk_widget_set_visible (to_box, TRUE); -+} -+ -+/* bolt client signals */ -+static void -+cc_bolt_panel_set_no_thunderbolt (CcBoltPanel *panel, -+ const char *msg) -+{ -+ if (msg == NULL) -+ msg = _("Thunderbolt could not be detected.\n" -+ "Either the system lacks Thunderbolt support, " -+ "it has been disabled in the BIOS or is set to " -+ "an unsupported security level in the BIOS."); -+ -+ gtk_label_set_label (panel->notb_details, msg); -+ gtk_stack_set_visible_child_name (panel->container, "no-thunderbolt"); -+} -+ -+static void -+cc_bolt_panel_name_owner_changed (CcBoltPanel *panel) -+{ -+ BoltClient *client = panel->client; -+ BoltSecurity sl; -+ gboolean notb = TRUE; -+ const char *text = NULL; -+ const char *name_owner; -+ -+ name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (panel->client)); -+ -+ if (name_owner == NULL) -+ { -+ cc_bolt_panel_set_no_thunderbolt (panel, NULL); -+ devices_table_clear_entries (panel->devices, panel); -+ gtk_widget_hide (GTK_WIDGET (panel->headerbar_box)); -+ return; -+ } -+ -+ gtk_stack_set_visible_child_name (panel->container, "loading"); -+ -+ sl = bolt_client_get_security (client); -+ -+ switch (sl) -+ { -+ case BOLT_SECURITY_NONE: -+ case BOLT_SECURITY_SECURE: -+ case BOLT_SECURITY_USER: -+ /* we fetch the device list and show them here */ -+ notb = FALSE; -+ break; -+ -+ case BOLT_SECURITY_DPONLY: -+ case BOLT_SECURITY_USBONLY: -+ text = _("Thunderbolt support has been disabled in the BIOS."); -+ break; -+ -+ case BOLT_SECURITY_UNKNOWN: -+ text = NULL; -+ break; -+ } -+ -+ if (notb) -+ { -+ /* security level is unknown or un-handled */ -+ cc_bolt_panel_set_no_thunderbolt (panel, text); -+ return; -+ } -+ -+ if (panel->permission) -+ gtk_widget_show (GTK_WIDGET (panel->headerbar_box)); -+ else -+ polkit_permission_new ("org.freedesktop.bolt.manage", -+ NULL, -+ panel->cancel, -+ on_permission_ready, -+ g_object_ref (panel)); -+ -+ devices_table_synchronize (panel); -+} -+ -+/* bolt client signals */ -+static void -+on_bolt_name_owner_changed_cb (GObject *object, -+ GParamSpec *pspec, -+ gpointer user_data) -+{ -+ CcBoltPanel *panel = CC_BOLT_PANEL (user_data); -+ -+ cc_bolt_panel_name_owner_changed (panel); -+} -+ -+static void -+on_bolt_device_added_cb (BoltClient *cli, -+ const char *path, -+ CcBoltPanel *panel) -+{ -+ g_autoptr(GError) err = NULL; -+ GDBusConnection *bus; -+ BoltDevice *dev; -+ gboolean found; -+ -+ found = g_hash_table_contains (panel->devices, path); -+ -+ if (found) -+ return; -+ -+ bus = g_dbus_proxy_get_connection (G_DBUS_PROXY (panel->client)); -+ dev = bolt_device_new_for_object_path (bus, path, panel->cancel, &err); -+ -+ if (dev == NULL) -+ { -+ g_warning ("Could not create proxy for %s", path); -+ return; -+ } -+ -+ cc_bolt_panel_add_device (panel, dev); -+} -+ -+static void -+on_bolt_device_removed_cb (BoltClient *cli, -+ const char *path, -+ CcBoltPanel *panel) -+{ -+ CcBoltDeviceEntry *entry; -+ -+ entry = g_hash_table_lookup (panel->devices, path); -+ -+ if (entry == NULL) -+ return; -+ -+ cc_bolt_panel_del_device_entry (panel, entry); -+ g_hash_table_remove (panel->devices, path); -+} -+ -+static void -+on_bolt_notify_authmode_cb (GObject *gobject, -+ GParamSpec *pspec, -+ gpointer user_data) -+{ -+ CcBoltPanel *panel = CC_BOLT_PANEL (user_data); -+ -+ cc_bolt_panel_authmode_sync (panel); -+} -+ -+/* panel signals */ -+ -+static void -+on_authmode_ready (GObject *source_object, -+ GAsyncResult *res, -+ gpointer user_data) -+{ -+ g_autoptr(GError) error = NULL; -+ CcBoltPanel *panel = CC_BOLT_PANEL (user_data); -+ gboolean ok; -+ -+ ok = bolt_client_set_authmode_finish (BOLT_CLIENT (source_object), res, &error); -+ if (!ok) -+ { -+ g_autofree char *text; -+ -+ g_warning ("Could not set authmode: %s", error->message); -+ -+ text = g_strdup_printf (_("Error switching direct mode: %s"), error->message); -+ gtk_label_set_markup (panel->notification_label, text); -+ gtk_revealer_set_reveal_child (panel->notification_revealer, TRUE); -+ -+ /* make sure we are reflecting the correct state */ -+ cc_bolt_panel_authmode_sync (panel); -+ } -+ -+ gtk_spinner_stop (panel->authmode_spinner); -+ gtk_widget_set_sensitive (GTK_WIDGET (panel->authmode_switch), TRUE); -+} -+ -+static gboolean -+on_authmode_state_set_cb (CcBoltPanel *panel, -+ gboolean enable, -+ GtkSwitch *toggle) -+{ -+ BoltClient *client = panel->client; -+ BoltAuthMode mode; -+ -+ gtk_widget_set_sensitive (GTK_WIDGET (panel->authmode_switch), FALSE); -+ gtk_spinner_start (panel->authmode_spinner); -+ -+ mode = bolt_client_get_authmode (client); -+ -+ if (enable) -+ mode = mode | BOLT_AUTH_ENABLED; -+ else -+ mode = mode & ~BOLT_AUTH_ENABLED; -+ -+ bolt_client_set_authmode_async (client, mode, NULL, on_authmode_ready, panel); -+ -+ return TRUE; -+} -+ -+static void -+on_device_entry_row_activated_cb (CcBoltPanel *panel, -+ GtkListBoxRow *row) -+{ -+ CcBoltDeviceEntry *entry; -+ BoltDevice *device; -+ -+ if (!CC_IS_BOLT_DEVICE_ENTRY (row)) -+ return; -+ -+ entry = CC_BOLT_DEVICE_ENTRY (row); -+ device = cc_bolt_device_entry_get_device (entry); -+ -+ cc_bolt_device_dialog_set_device (panel->device_dialog, device); -+ gtk_window_resize (GTK_WINDOW (panel->device_dialog), 1, 1); -+ gtk_widget_show (GTK_WIDGET (panel->device_dialog)); -+} -+ -+static gboolean -+on_device_dialog_delete_event_cb (GtkWidget *widget, -+ GdkEvent *event, -+ CcBoltPanel *panel) -+{ -+ CcBoltDeviceDialog *dialog; -+ -+ dialog = CC_BOLT_DEVICE_DIALOG (widget); -+ -+ cc_bolt_device_dialog_set_device (dialog, NULL); -+ gtk_widget_hide (widget); -+ -+ return TRUE; -+} -+ -+static void -+on_device_entry_status_changed_cb (CcBoltDeviceEntry *entry, -+ BoltStatus new_status, -+ CcBoltPanel *panel) -+{ -+ GtkListBox *from = NULL; -+ GtkListBox *to = NULL; -+ GtkWidget *p; -+ gboolean is_pending; -+ gboolean parent_pending; -+ -+ /* if we are doing some active work, then lets not change -+ * the list the entry is in; otherwise we might just hop -+ * from one box to the other and back again. -+ */ -+ if (new_status == BOLT_STATUS_CONNECTING || -+ new_status == BOLT_STATUS_AUTHORIZING) -+ return; -+ -+ is_pending = bolt_status_is_pending (new_status); -+ -+ p = gtk_widget_get_parent (GTK_WIDGET (entry)); -+ parent_pending = (gpointer) p == panel->pending_list; -+ -+ /* */ -+ if (is_pending && !parent_pending) -+ { -+ from = panel->devices_list; -+ to = panel->pending_list; -+ } -+ else if (!is_pending && parent_pending) -+ { -+ from = panel->pending_list; -+ to = panel->devices_list; -+ } -+ -+ if (from && to) -+ cc_panel_list_box_migrate (panel, from, to, entry); -+} -+ -+ -+static void -+on_notification_button_clicked_cb (GtkButton *button, -+ CcBoltPanel *panel) -+{ -+ gtk_revealer_set_reveal_child (panel->notification_revealer, FALSE); -+} -+ -+/* polkit */ -+ -+static void -+on_permission_ready (GObject *source_object, -+ GAsyncResult *res, -+ gpointer user_data) -+{ -+ g_autoptr(GError) err = NULL; -+ g_autoptr(CcBoltPanel) panel = user_data; -+ GPermission *permission; -+ gboolean is_allowed; -+ const char *name; -+ -+ permission = polkit_permission_new_finish (res, &err); -+ panel->permission = permission; -+ -+ if (panel->permission == NULL) -+ { -+ g_warning ("Could not get polkit permissions: %s", err->message); -+ return; -+ } -+ -+ g_signal_connect_object (permission, -+ "notify", -+ G_CALLBACK (on_permission_notify_cb), -+ panel, -+ G_CONNECT_AFTER); -+ -+ is_allowed = g_permission_get_allowed (permission); -+ gtk_widget_set_sensitive (GTK_WIDGET (panel->authmode_switch), is_allowed); -+ gtk_lock_button_set_permission (panel->lock_button, permission); -+ -+ name = gtk_stack_get_visible_child_name (panel->container); -+ -+ gtk_widget_set_visible (GTK_WIDGET (panel->headerbar_box), -+ bolt_streq (name, "devices-listing")); -+} -+ -+static void -+on_permission_notify_cb (GPermission *permission, -+ GParamSpec *pspec, -+ CcBoltPanel *panel) -+{ -+ gboolean is_allowed = g_permission_get_allowed (permission); -+ -+ gtk_widget_set_sensitive (GTK_WIDGET (panel->authmode_switch), is_allowed); -+} -+ -+static gint -+device_entries_sort_by_recency (GtkListBoxRow *a_row, -+ GtkListBoxRow *b_row, -+ gpointer user_data) -+{ -+ CcBoltDeviceEntry *a_entry = CC_BOLT_DEVICE_ENTRY (a_row); -+ CcBoltDeviceEntry *b_entry = CC_BOLT_DEVICE_ENTRY (b_row); -+ BoltDevice *a = cc_bolt_device_entry_get_device (a_entry); -+ BoltDevice *b = cc_bolt_device_entry_get_device (b_entry); -+ BoltStatus status; -+ gint64 a_ts, b_ts; -+ gint64 score; -+ -+ a_ts = (gint64) bolt_device_get_timestamp (a); -+ b_ts = (gint64) bolt_device_get_timestamp (b); -+ -+ score = b_ts - a_ts; -+ -+ if (score != 0) -+ return score; -+ -+ status = bolt_device_get_status (a); -+ -+ if (bolt_status_is_connected (status)) -+ { -+ const char *a_path; -+ const char *b_path; -+ -+ a_path = bolt_device_get_syspath (a); -+ b_path = bolt_device_get_syspath (b); -+ -+ return g_strcmp0 (a_path, b_path); -+ } -+ else -+ { -+ const char *a_name; -+ const char *b_name; -+ -+ a_name = bolt_device_get_name (a); -+ b_name = bolt_device_get_name (b); -+ -+ return g_strcmp0 (a_name, b_name); -+ } -+ -+ return 0; -+} -+ -+static gint -+device_entries_sort_by_syspath (GtkListBoxRow *a_row, -+ GtkListBoxRow *b_row, -+ gpointer user_data) -+{ -+ CcBoltDeviceEntry *a_entry = CC_BOLT_DEVICE_ENTRY (a_row); -+ CcBoltDeviceEntry *b_entry = CC_BOLT_DEVICE_ENTRY (b_row); -+ BoltDevice *a = cc_bolt_device_entry_get_device (a_entry); -+ BoltDevice *b = cc_bolt_device_entry_get_device (b_entry); -+ -+ const char *a_path; -+ const char *b_path; -+ -+ a_path = bolt_device_get_syspath (a); -+ b_path = bolt_device_get_syspath (b); -+ -+ return g_strcmp0 (a_path, b_path); -+} -+ -+static void -+cc_bolt_panel_finalize (GObject *object) -+{ -+ CcBoltPanel *panel = CC_BOLT_PANEL (object); -+ -+ g_clear_object (&panel->client); -+ g_clear_pointer (&panel->devices, g_hash_table_unref); -+ g_clear_object (&panel->permission); -+ -+ G_OBJECT_CLASS (cc_bolt_panel_parent_class)->finalize (object); -+} -+ -+static void -+cc_bolt_panel_dispose (GObject *object) -+{ -+ CcBoltPanel *panel = CC_BOLT_PANEL (object); -+ -+ /* cancel any ongoing operation */ -+ g_cancellable_cancel (panel->cancel); -+ -+ /* Must be destroyed in dispose, not finalize. */ -+ g_clear_pointer (&panel->device_dialog, gtk_widget_destroy); -+ -+ G_OBJECT_CLASS (cc_bolt_panel_parent_class)->dispose (object); -+} -+ -+static void -+cc_bolt_panel_constructed (GObject *object) -+{ -+ CcBoltPanel *panel = CC_BOLT_PANEL (object); -+ GtkWindow *parent; -+ CcShell *shell; -+ -+ parent = GTK_WINDOW (cc_shell_get_toplevel (cc_panel_get_shell (CC_PANEL (panel)))); -+ gtk_window_set_transient_for (GTK_WINDOW (panel->device_dialog), parent); -+ -+ G_OBJECT_CLASS (cc_bolt_panel_parent_class)->constructed (object); -+ -+ shell = cc_panel_get_shell (CC_PANEL (panel)); -+ cc_shell_embed_widget_in_header (shell, GTK_WIDGET (panel->headerbar_box)); -+} -+ -+static void -+cc_bolt_panel_class_init (CcBoltPanelClass *klass) -+{ -+ GObjectClass *object_class = G_OBJECT_CLASS (klass); -+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); -+ -+ object_class->constructed = cc_bolt_panel_constructed; -+ object_class->dispose = cc_bolt_panel_dispose; -+ object_class->finalize = cc_bolt_panel_finalize; -+ -+ gtk_widget_class_set_template_from_resource (widget_class, RESOURCE_PANEL_UI); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltPanel, headerbar_box); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltPanel, lock_button); -+ -+ gtk_widget_class_bind_template_child (widget_class, CcBoltPanel, container); -+ -+ gtk_widget_class_bind_template_child (widget_class, CcBoltPanel, notb_caption); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltPanel, notb_details); -+ -+ gtk_widget_class_bind_template_child (widget_class, CcBoltPanel, notification_label); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltPanel, notification_revealer); -+ -+ gtk_widget_class_bind_template_child (widget_class, CcBoltPanel, authmode_mode); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltPanel, authmode_switch); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltPanel, authmode_spinner); -+ -+ gtk_widget_class_bind_template_child (widget_class, CcBoltPanel, devices_stack); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltPanel, devices_box); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltPanel, pending_box); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltPanel, devices_list); -+ gtk_widget_class_bind_template_child (widget_class, CcBoltPanel, pending_list); -+ -+ gtk_widget_class_bind_template_callback (widget_class, on_notification_button_clicked_cb); -+ gtk_widget_class_bind_template_callback (widget_class, on_authmode_state_set_cb); -+ gtk_widget_class_bind_template_callback (widget_class, on_device_entry_row_activated_cb); -+} -+ -+static void -+cc_bolt_panel_init (CcBoltPanel *panel) -+{ -+ g_resources_register (cc_thunderbolt_get_resource ()); -+ gtk_widget_init_template (GTK_WIDGET (panel)); -+ -+ gtk_stack_set_visible_child_name (panel->container, "loading"); -+ -+ gtk_list_box_set_header_func (panel->devices_list, -+ cc_list_box_update_header_func, -+ NULL, NULL); -+ -+ gtk_list_box_set_header_func (panel->pending_list, -+ cc_list_box_update_header_func, -+ NULL, NULL); -+ -+ gtk_list_box_set_sort_func (panel->devices_list, -+ device_entries_sort_by_recency, -+ panel, -+ NULL); -+ -+ gtk_list_box_set_sort_func (panel->pending_list, -+ device_entries_sort_by_syspath, -+ panel, -+ NULL); -+ -+ panel->devices = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); -+ -+ panel->device_dialog = cc_bolt_device_dialog_new (); -+ g_signal_connect_object (panel->device_dialog, "delete-event", -+ G_CALLBACK (on_device_dialog_delete_event_cb), -+ panel, 0); -+ -+ panel->cancel = g_cancellable_new (); -+ bolt_client_new_async (panel->cancel, -+ bolt_client_ready, -+ g_object_ref (panel)); -+ -+} -diff --git a/panels/thunderbolt/cc-bolt-panel.ui b/panels/thunderbolt/cc-bolt-panel.ui -new file mode 100644 -index 000000000000..5ec6748600b9 ---- /dev/null -+++ b/panels/thunderbolt/cc-bolt-panel.ui -@@ -0,0 +1,594 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ False -+ False -+ 6 -+ end -+ -+ -+ True -+ -+ -+ -+ -+ -diff --git a/panels/thunderbolt/gnome-thunderbolt-panel.desktop.in.in b/panels/thunderbolt/gnome-thunderbolt-panel.desktop.in.in -new file mode 100644 -index 000000000000..db2477e45a74 ---- /dev/null -+++ b/panels/thunderbolt/gnome-thunderbolt-panel.desktop.in.in -@@ -0,0 +1,17 @@ -+[Desktop Entry] -+Name=Thunderbolt -+Comment=Manage Thunderbolt devices -+Exec=gnome-control-center thunderbolt -+Icon=thunderbolt -+Terminal=false -+Type=Application -+NoDisplay=true -+StartupNotify=true -+Categories=GNOME;GTK;Settings;X-GNOME-Settings-Panel;HardwareSettings;X-GNOME-DevicesSettings;X-GNOME-ConnectivitySettings; -+OnlyShowIn=GNOME;Unity; -+X-GNOME-Bugzilla-Bugzilla=GNOME -+X-GNOME-Bugzilla-Product=gnome-control-center -+X-GNOME-Bugzilla-Component=thunderbolt -+X-GNOME-Bugzilla-Version=@VERSION@ -+# Translators: those are keywords for the thunderbolt control-center panel. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! -+Keywords=Thunderbolt; -diff --git a/panels/thunderbolt/meson.build b/panels/thunderbolt/meson.build -new file mode 100644 -index 000000000000..e855661574fc ---- /dev/null -+++ b/panels/thunderbolt/meson.build -@@ -0,0 +1,74 @@ -+panels_list += cappletname -+ -+desktop = 'gnome-@0@-panel.desktop'.format(cappletname) -+desktop_in = configure_file( -+ input: desktop + '.in.in', -+ output: desktop + '.in', -+ configuration: desktop_conf -+) -+ -+i18n.merge_file( -+ desktop, -+ type: 'desktop', -+ input: desktop_in, -+ output: desktop, -+ po_dir: po_dir, -+ install: true, -+ install_dir: control_center_desktopdir -+) -+ -+sources = files( -+ 'bolt-client.c', -+ 'bolt-device.c', -+ 'bolt-enums.c', -+ 'bolt-error.c', -+ 'bolt-proxy.c', -+ 'bolt-str.c', -+ 'bolt-time.c', -+ 'cc-bolt-panel.c', -+ 'cc-bolt-device-dialog.c', -+ 'cc-bolt-device-entry.c', -+) -+ -+enum_headers = [ -+ 'bolt-enums.h', -+ 'bolt-error.h' -+] -+ -+sources += gnome.mkenums_simple( -+ 'bolt-enum-types', -+ sources: enum_headers) -+ -+resource_data = files( -+ 'cc-bolt-device-dialog.ui', -+ 'cc-bolt-device-entry.ui', -+ 'cc-bolt-panel.ui' -+) -+ -+sources += gnome.compile_resources( -+ 'cc-' + cappletname + '-resources', -+ cappletname + '.gresource.xml', -+ source_dir: '.', -+ c_name: 'cc_' + cappletname, -+ dependencies: resource_data, -+ export: true -+) -+ -+deps = common_deps + [ -+ gnome_desktop_dep, -+ polkit_gobject_dep, -+ m_dep, -+] -+ -+cflags += [ -+ '-DGNOMELOCALEDIR="@0@"'.format(control_center_localedir), -+ '-DBINDIR="@0@"'.format(control_center_bindir) -+] -+ -+panels_libs += static_library( -+ cappletname, -+ sources: sources, -+ include_directories: top_inc, -+ dependencies: deps, -+ c_args: cflags -+) -diff --git a/panels/thunderbolt/thunderbolt.gresource.xml b/panels/thunderbolt/thunderbolt.gresource.xml -new file mode 100644 -index 000000000000..8953d6243275 ---- /dev/null -+++ b/panels/thunderbolt/thunderbolt.gresource.xml -@@ -0,0 +1,9 @@ -+ -+ -+ -+ cc-bolt-device-dialog.ui -+ cc-bolt-device-entry.ui -+ cc-bolt-panel.ui -+ -+ -+ -diff --git a/panels/thunderbolt/update-from-bolt.sh b/panels/thunderbolt/update-from-bolt.sh -new file mode 100755 -index 000000000000..8b22f0831781 ---- /dev/null -+++ b/panels/thunderbolt/update-from-bolt.sh -@@ -0,0 +1,50 @@ -+#!/bin/bash -+ -+if [ $# -ne 1 ]; then -+ echo "$0: usage: " -+ exit 1 -+fi -+ -+boltsrc="$1" -+ -+function die() { -+ echo $* -+ exit 1 -+} -+ -+function copyone() { -+ dst=$1 -+ src="$boltsrc/$dst" -+ -+ search=(common cli) -+ for base in ${search[*]} -+ do -+ path="$boltsrc/$base/$dst" -+ if [ -f $path ]; then -+ src=$path -+ break; -+ fi -+ done -+ -+ if [ ! -f $src ]; then -+ echo -e "$dst \t[ skipped ] $src (ENOENT)" -+ elif cmp -s $src $dst; then -+ echo -e "$dst \t[ unchanged ]" -+ else -+ cp $src $dst || die "$dst [failed] source: $src" -+ echo -e "$dst \t[ updated ] $src" -+ git add $dst -+ fi -+} -+ -+names=(client device enums error names proxy str time) -+ -+for fn in ${names[*]} -+do -+ header="bolt-$fn.h" -+ source="bolt-$fn.c" -+ -+ copyone $header -+ copyone $source -+done -+ -diff --git a/shell/cc-panel-list.c b/shell/cc-panel-list.c -index 0fd093cf9758..99d8a91144ad 100644 ---- a/shell/cc-panel-list.c -+++ b/shell/cc-panel-list.c -@@ -276,6 +276,7 @@ static const gchar * const panel_order[] = { - "wifi", - "mobile-broadband", - "bluetooth", -+ "thunderbolt", - "background", - "notifications", - "search", -diff --git a/shell/cc-panel-loader.c b/shell/cc-panel-loader.c -index 675833c129d7..9b8aca5c6f9b 100644 ---- a/shell/cc-panel-loader.c -+++ b/shell/cc-panel-loader.c -@@ -54,6 +54,9 @@ extern GType cc_region_panel_get_type (void); - extern GType cc_search_panel_get_type (void); - extern GType cc_sharing_panel_get_type (void); - extern GType cc_sound_panel_get_type (void); -+#ifdef BUILD_THUNDERBOLT -+extern GType cc_bolt_panel_get_type (void); -+#endif /* BUILD_THUNDERBOLT */ - extern GType cc_ua_panel_get_type (void); - extern GType cc_user_panel_get_type (void); - #ifdef BUILD_WACOM -@@ -99,6 +102,9 @@ static struct { - PANEL_TYPE("search", cc_search_panel_get_type ), - PANEL_TYPE("sharing", cc_sharing_panel_get_type ), - PANEL_TYPE("sound", cc_sound_panel_get_type ), -+#ifdef BUILD_THUNDERBOLT -+ PANEL_TYPE("thunderbolt", cc_bolt_panel_get_type ), -+#endif - PANEL_TYPE("universal-access", cc_ua_panel_get_type ), - PANEL_TYPE("user-accounts", cc_user_panel_get_type ), - #ifdef BUILD_WACOM --- -2.17.0 - diff --git a/0004-thunderbolt-move-to-the-Devices-page.patch b/0004-thunderbolt-move-to-the-Devices-page.patch deleted file mode 100644 index 23659fa..0000000 --- a/0004-thunderbolt-move-to-the-Devices-page.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 2d1da22e17f703e27ff1b3177e35a54aa0c3aecc Mon Sep 17 00:00:00 2001 -From: Christian Kellner -Date: Fri, 13 Apr 2018 16:03:21 +0200 -Subject: [PATCH 4/4] thunderbolt: move to the 'Devices' page - -The 'Devices' page is a fitting place for the thunderbolt, being -an IO technology. It is expected that people that need to go to -that page will be sent there via a gnome-shell notification, so -there is no need for it to be on the main page. -Ok'ed by the design team (jimmac). ---- - panels/thunderbolt/gnome-thunderbolt-panel.desktop.in.in | 2 +- - shell/cc-panel-list.c | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/panels/thunderbolt/gnome-thunderbolt-panel.desktop.in.in b/panels/thunderbolt/gnome-thunderbolt-panel.desktop.in.in -index db2477e45a74..abd317341bfd 100644 ---- a/panels/thunderbolt/gnome-thunderbolt-panel.desktop.in.in -+++ b/panels/thunderbolt/gnome-thunderbolt-panel.desktop.in.in -@@ -7,7 +7,7 @@ Terminal=false - Type=Application - NoDisplay=true - StartupNotify=true --Categories=GNOME;GTK;Settings;X-GNOME-Settings-Panel;HardwareSettings;X-GNOME-DevicesSettings;X-GNOME-ConnectivitySettings; -+Categories=GNOME;GTK;Settings;X-GNOME-Settings-Panel;HardwareSettings;X-GNOME-DevicesSettings; - OnlyShowIn=GNOME;Unity; - X-GNOME-Bugzilla-Bugzilla=GNOME - X-GNOME-Bugzilla-Product=gnome-control-center -diff --git a/shell/cc-panel-list.c b/shell/cc-panel-list.c -index 99d8a91144ad..f5b83509d646 100644 ---- a/shell/cc-panel-list.c -+++ b/shell/cc-panel-list.c -@@ -276,7 +276,6 @@ static const gchar * const panel_order[] = { - "wifi", - "mobile-broadband", - "bluetooth", -- "thunderbolt", - "background", - "notifications", - "search", -@@ -295,6 +294,7 @@ static const gchar * const panel_order[] = { - "mouse", - "printers", - "removable-media", -+ "thunderbolt", - "wacom", - "color", - --- -2.17.0 - diff --git a/gnome-control-center.spec b/gnome-control-center.spec index f7933e8..b8697c4 100644 --- a/gnome-control-center.spec +++ b/gnome-control-center.spec @@ -9,22 +9,16 @@ %define gnome_bluetooth_version 3.18.2 Name: gnome-control-center -Version: 3.28.2 -Release: 2%{?dist} +Version: 3.29.90 +Release: 1%{?dist} Summary: Utilities to configure the GNOME desktop License: GPLv2+ and CC-BY-SA URL: http://www.gnome.org -Source0: https://download.gnome.org/sources/gnome-control-center/3.28/gnome-control-center-%{version}.tar.xz +Source0: https://download.gnome.org/sources/gnome-control-center/3.29/gnome-control-center-%{version}.tar.xz # https://bugzilla.gnome.org/show_bug.cgi?id=695691 Patch0: distro-logo.patch -# thunderbolt panel backported to 3.28.x -# https://gitlab.gnome.org/gicmo/gnome-control-center/commits/thunderbolt_3_28_1 -Patch1: 0001-shell-Don-t-set-per-panel-icon.patch -Patch2: 0002-shell-Icon-name-helper-returns-symbolic-name.patch -Patch3: 0003-thunderbolt-new-panel-for-device-management.patch -Patch4: 0004-thunderbolt-move-to-the-Devices-page.patch BuildRequires: chrpath BuildRequires: cups-devel @@ -163,7 +157,7 @@ chrpath --delete $RPM_BUILD_ROOT%{_bindir}/gnome-control-center %files -f %{name}.lang %license COPYING -%doc AUTHORS NEWS README +%doc NEWS README.md %{_bindir}/gnome-control-center %{_datadir}/applications/*.desktop %{_datadir}/bash-completion/completions/gnome-control-center @@ -194,6 +188,9 @@ chrpath --delete $RPM_BUILD_ROOT%{_bindir}/gnome-control-center %dir %{_datadir}/gnome/wm-properties %changelog +* Sun Aug 12 2018 Kalev Lember - 3.29.90-1 +- Update to 3.29.90 + * Fri Jul 13 2018 Fedora Release Engineering - 3.28.2-2 - Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild diff --git a/sources b/sources index 102cf8b..b741566 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (gnome-control-center-3.28.2.tar.xz) = 3e1b54cf1a603ee7c47d8b0f1fb025405c8d133c9e0dbe0eaf2f287eff82109e95581c79f131d227422d682b7049ccb6e6297dba1ff2276cff5f715308195d7f +SHA512 (gnome-control-center-3.29.90.tar.xz) = 5a054562ffce72f54396f606ba24e6e54aa40f0a5c8f24a78784d39d55421e57081802a0ed5634e8941b80b656c3eb51ad682b2dac944cd75e553c1cd00ed25d