6389 lines
192 KiB
Diff
6389 lines
192 KiB
Diff
From 3d9ad5e5657059e054f011d65e3f81b3723b41a5 Mon Sep 17 00:00:00 2001
|
|
From: Christian Kellner <christian@kellner.me>
|
|
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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors:
|
|
+ * Christian J. Kellner <christian@kellner.me>
|
|
+ */
|
|
+
|
|
+#include "bolt-client.h"
|
|
+
|
|
+#include "bolt-device.h"
|
|
+#include "bolt-error.h"
|
|
+#include "bolt-names.h"
|
|
+
|
|
+#include <gio/gio.h>
|
|
+
|
|
+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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors:
|
|
+ * Christian J. Kellner <christian@kellner.me>
|
|
+ */
|
|
+
|
|
+#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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors:
|
|
+ * Christian J. Kellner <christian@kellner.me>
|
|
+ */
|
|
+
|
|
+#include "config.h"
|
|
+
|
|
+#include "bolt-device.h"
|
|
+
|
|
+#include "bolt-enums.h"
|
|
+#include "bolt-error.h"
|
|
+#include "bolt-names.h"
|
|
+
|
|
+#include <gio/gio.h>
|
|
+
|
|
+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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors:
|
|
+ * Christian J. Kellner <christian@kellner.me>
|
|
+ */
|
|
+
|
|
+#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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors:
|
|
+ * Christian J. Kellner <christian@kellner.me>
|
|
+ */
|
|
+
|
|
+#include "config.h"
|
|
+
|
|
+#include "bolt-enums.h"
|
|
+#include "bolt-error.h"
|
|
+
|
|
+#include <gio/gio.h>
|
|
+
|
|
+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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors:
|
|
+ * Christian J. Kellner <christian@kellner.me>
|
|
+ */
|
|
+
|
|
+#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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors:
|
|
+ * Christian J. Kellner <christian@kellner.me>
|
|
+ */
|
|
+
|
|
+#include "config.h"
|
|
+
|
|
+#include "bolt-error.h"
|
|
+
|
|
+#include "bolt-names.h"
|
|
+
|
|
+#include <gio/gio.h>
|
|
+
|
|
+/**
|
|
+ * 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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors:
|
|
+ * Christian J. Kellner <christian@kellner.me>
|
|
+ */
|
|
+
|
|
+#pragma once
|
|
+
|
|
+#include <glib.h>
|
|
+
|
|
+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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors:
|
|
+ * Christian J. Kellner <christian@kellner.me>
|
|
+ */
|
|
+
|
|
+#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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors:
|
|
+ * Christian J. Kellner <christian@kellner.me>
|
|
+ */
|
|
+
|
|
+#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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors:
|
|
+ * Christian J. Kellner <christian@kellner.me>
|
|
+ */
|
|
+
|
|
+#pragma once
|
|
+
|
|
+#include <gio/gio.h>
|
|
+
|
|
+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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors:
|
|
+ * Christian J. Kellner <christian@kellner.me>
|
|
+ */
|
|
+
|
|
+#include "config.h"
|
|
+
|
|
+#include "bolt-str.h"
|
|
+
|
|
+#include <string.h>
|
|
+
|
|
+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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors:
|
|
+ * Christian J. Kellner <christian@kellner.me>
|
|
+ */
|
|
+
|
|
+#pragma once
|
|
+
|
|
+#include <glib.h>
|
|
+#include <string.h>
|
|
+
|
|
+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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors:
|
|
+ * Christian J. Kellner <christian@kellner.me>
|
|
+ */
|
|
+
|
|
+#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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors:
|
|
+ * Christian J. Kellner <christian@kellner.me>
|
|
+ */
|
|
+
|
|
+#pragma once
|
|
+
|
|
+#include <glib.h>
|
|
+
|
|
+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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors: Christian J. Kellner <ckellner@redhat.com>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <config.h>
|
|
+
|
|
+#include <glib/gi18n.h>
|
|
+
|
|
+#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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors: Christian J. Kellner <ckellner@redhat.com>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#pragma once
|
|
+
|
|
+#include <gtk/gtk.h>
|
|
+
|
|
+#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 @@
|
|
+<?xml version="1.0" encoding="UTF-8"?>
|
|
+<!-- Generated with glade 3.20.0 -->
|
|
+<interface>
|
|
+ <requires lib="gtk+" version="3.20"/>
|
|
+ <template class="CcBoltDeviceDialog" parent="GtkDialog">
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="type_hint">dialog</property>
|
|
+ <property name="use_header_bar">1</property>
|
|
+ <property name="resizable">False</property>
|
|
+ <property name="modal">True</property>
|
|
+
|
|
+ <child internal-child="headerbar">
|
|
+ <object class="GtkHeaderBar" id="header_bar">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="show_close_button">True</property>
|
|
+ <property name="title">Device Identifier</property>
|
|
+ <property name="subtitle"></property>
|
|
+ <property name="has-subtitle">False</property>
|
|
+ </object>
|
|
+ </child>
|
|
+
|
|
+ <child internal-child="vbox">
|
|
+ <object class="GtkBox">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="orientation">vertical</property>
|
|
+ <property name="margin-bottom">24</property>
|
|
+ <property name="border-width">0</property>
|
|
+ <child>
|
|
+ <object class="GtkOverlay">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <child type="overlay">
|
|
+ <object class="GtkRevealer" id="notify_revealer">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="halign">center</property>
|
|
+ <property name="valign">start</property>
|
|
+ <property name="transition_type">slide-down</property>
|
|
+ <child>
|
|
+ <object class="GtkFrame">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <child>
|
|
+ <object class="GtkBox">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="spacing">12</property>
|
|
+ <child>
|
|
+ <object class="GtkLabel" id="notify_label">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="use_markup">True</property>
|
|
+ <property name="wrap">True</property>
|
|
+ </object>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkButton">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <property name="relief">none</property>
|
|
+ <signal name="clicked"
|
|
+ handler="on_notify_button_clicked_cb"
|
|
+ object="CcBoltDeviceDialog"
|
|
+ swapped="no" />
|
|
+ <child>
|
|
+ <object class="GtkImage">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="icon-name">window-close-symbolic</property>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ <style>
|
|
+ <class name="app-notification" />
|
|
+ </style>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkBox">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="expand">True</property>
|
|
+ <property name="orientation">vertical</property>
|
|
+
|
|
+ <child>
|
|
+ <object class="GtkGrid">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="margin-left">72</property>
|
|
+ <property name="margin-right">72</property>
|
|
+ <property name="margin-top">24</property>
|
|
+ <property name="margin-bottom">0</property>
|
|
+ <property name="row_spacing">12</property>
|
|
+ <property name="column_spacing">24</property>
|
|
+ <child>
|
|
+ <object class="GtkLabel" id="name_title_label">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="halign">end</property>
|
|
+ <property name="hexpand">False</property>
|
|
+ <property name="vexpand">False</property>
|
|
+ <property name="label" translatable="yes">Name:</property>
|
|
+ <property name="justify">right</property>
|
|
+ <property name="xalign">1</property>
|
|
+ <property name="mnemonic_widget">name_label</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="left_attach">0</property>
|
|
+ <property name="top_attach">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkLabel" id="name_label">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="hexpand">True</property>
|
|
+ <property name="label">Device identifier</property>
|
|
+ <property name="use_markup">True</property>
|
|
+ <property name="ellipsize">end</property>
|
|
+ <property name="xalign">0</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="left_attach">1</property>
|
|
+ <property name="top_attach">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkLabel" id="status_title_label">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="halign">end</property>
|
|
+ <property name="hexpand">False</property>
|
|
+ <property name="vexpand">False</property>
|
|
+ <property name="label" translatable="yes">Status:</property>
|
|
+ <property name="justify">right</property>
|
|
+ <property name="xalign">1</property>
|
|
+ <property name="mnemonic_widget">status_label</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="left_attach">0</property>
|
|
+ <property name="top_attach">1</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkLabel" id="status_label">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="valign">center</property>
|
|
+ <property name="hexpand">True</property>
|
|
+ <property name="label">Status</property>
|
|
+ <property name="ellipsize">end</property>
|
|
+ <property name="xalign">0</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="left_attach">1</property>
|
|
+ <property name="top_attach">1</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+
|
|
+ <child>
|
|
+ <object class="GtkLabel" id="uuid_title_label">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="halign">end</property>
|
|
+ <property name="hexpand">False</property>
|
|
+ <property name="vexpand">False</property>
|
|
+ <property name="label" translatable="yes">UUID:</property>
|
|
+ <property name="justify">right</property>
|
|
+ <property name="xalign">1</property>
|
|
+ <property name="mnemonic_widget">uuid_label</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="left_attach">0</property>
|
|
+ <property name="top_attach">2</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkLabel" id="uuid_label">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="valign">center</property>
|
|
+ <property name="hexpand">True</property>
|
|
+ <property name="label">Status</property>
|
|
+ <property name="ellipsize">end</property>
|
|
+ <property name="xalign">0</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="left_attach">1</property>
|
|
+ <property name="top_attach">2</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+
|
|
+ <child>
|
|
+ <object class="GtkLabel" id="time_title">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="halign">end</property>
|
|
+ <property name="hexpand">False</property>
|
|
+ <property name="vexpand">False</property>
|
|
+ <property name="label">Timestamp:</property>
|
|
+ <property name="justify">right</property>
|
|
+ <property name="xalign">1</property>
|
|
+ <property name="mnemonic_widget">time_label</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="left_attach">0</property>
|
|
+ <property name="top_attach">3</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkLabel" id="time_label">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="valign">center</property>
|
|
+ <property name="hexpand">True</property>
|
|
+ <property name="label">Status</property>
|
|
+ <property name="ellipsize">end</property>
|
|
+ <property name="xalign">0</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="left_attach">1</property>
|
|
+ <property name="top_attach">3</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">True</property>
|
|
+ <property name="fill">True</property>
|
|
+ <property name="padding">1</property>
|
|
+ <property name="position">1</property>
|
|
+ </packing>
|
|
+ <object class="GtkSizeGroup" id="device_titles_sizegroup">
|
|
+ <widgets>
|
|
+ <widget name="name_title_label"/>
|
|
+ <widget name="status_title_label"/>
|
|
+ <widget name="uuid_title_label"/>
|
|
+ <widget name="time_title"/>
|
|
+ </widgets>
|
|
+ </object>
|
|
+ <object class="GtkSizeGroup" id="device_labels_sizegroup">
|
|
+ <widgets>
|
|
+ <widget name="name_label"/>
|
|
+ <widget name="status_label"/>
|
|
+ <widget name="uuid_label"/>
|
|
+ <widget name="time_label"/>
|
|
+ </widgets>
|
|
+ </object>
|
|
+ </child>
|
|
+ <!-- end of grid -->
|
|
+ <child>
|
|
+ <object class="GtkBox" id="button_box">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="orientation">horizontal</property>
|
|
+ <property name="spacing">12</property>
|
|
+ <property name="margin-left">72</property>
|
|
+ <property name="margin-right">72</property>
|
|
+ <property name="margin-top">36</property>
|
|
+ <property name="margin-bottom">0</property>
|
|
+ <property name="halign">fill</property>
|
|
+ <child>
|
|
+ <object class="GtkSpinner" id="spinner">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="halign">center</property>
|
|
+ <property name="valign">center</property>
|
|
+ <property name="active">False</property>
|
|
+ </object>
|
|
+ </child>
|
|
+
|
|
+ <child>
|
|
+ <object class="GtkButton" id="connect_button">
|
|
+ <property name="label" translatable="yes">Authorize and Connect</property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="no_show_all">True</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <property name="receives_default">True</property>
|
|
+ <property name="halign">fill</property>
|
|
+
|
|
+ <signal name="clicked"
|
|
+ handler="on_connect_button_clicked_cb"
|
|
+ object="CcBoltDeviceDialog"
|
|
+ swapped="yes" />
|
|
+ <style>
|
|
+ <class name="suggested-action"/>
|
|
+ </style>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">True</property>
|
|
+ <property name="fill">True</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+
|
|
+ <child>
|
|
+ <object class="GtkButton" id="forget_button">
|
|
+ <property name="label" translatable="yes">Forget Device</property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="no_show_all">True</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <property name="receives_default">False</property>
|
|
+ <property name="halign">fill</property>
|
|
+ <signal name="clicked"
|
|
+ handler="on_forget_button_clicked_cb"
|
|
+ object="CcBoltDeviceDialog"
|
|
+ swapped="yes" />
|
|
+ <style>
|
|
+ <class name="destructive-action"/>
|
|
+ </style>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">True</property>
|
|
+ <property name="fill">True</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkBox" id="spinner_box">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+
|
|
+ <packing>
|
|
+ <property name="expand">True</property>
|
|
+ <property name="fill">True</property>
|
|
+ <property name="position">2</property>
|
|
+ </packing>
|
|
+
|
|
+ <object class="GtkSizeGroup" id="actions_sizegroup">
|
|
+ <widgets>
|
|
+ <widget name="forget_button"/>
|
|
+ <widget name="connect_button"/>
|
|
+ </widgets>
|
|
+ </object>
|
|
+
|
|
+ <object class="GtkSizeGroup" id="spinner_sizegroup">
|
|
+ <widgets>
|
|
+ <widget name="spinner"/>
|
|
+ <widget name="spinner_box"/>
|
|
+ </widgets>
|
|
+ </object>
|
|
+
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ </template>
|
|
+</interface>
|
|
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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors: Christian J. Kellner <ckellner@redhat.com>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <config.h>
|
|
+
|
|
+#include "bolt-str.h"
|
|
+
|
|
+#include "cc-bolt-device-entry.h"
|
|
+
|
|
+#include "cc-thunderbolt-resources.h"
|
|
+
|
|
+#include <glib/gi18n.h>
|
|
+
|
|
+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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors: Christian J. Kellner <ckellner@redhat.com>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#pragma once
|
|
+
|
|
+#include <gtk/gtk.h>
|
|
+#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 @@
|
|
+<?xml version="1.0" encoding="UTF-8"?>
|
|
+<interface>
|
|
+ <requires lib="gtk+" version="3.20"/>
|
|
+
|
|
+ <template class="CcBoltDeviceEntry" parent="GtkListBoxRow">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can-focus">False</property>
|
|
+ <property name="activatable">True</property>
|
|
+ <child>
|
|
+ <object class="GtkGrid">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="border-width">12</property>
|
|
+ <property name="margin_left">6</property>
|
|
+ <property name="margin_right">6</property>
|
|
+ <property name="column-spacing">12</property>
|
|
+ <property name="row-spacing">2</property>
|
|
+ <child>
|
|
+ <object class="GtkLabel" id="name_label">
|
|
+ <property name="ellipsize">end</property>
|
|
+ <property name="use-markup">True</property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="hexpand">True</property>
|
|
+ <property name="label">Device Name</property>
|
|
+ <property name="xalign">0.0</property>
|
|
+ <property name="valign">center</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="left-attach">0</property>
|
|
+ <property name="top-attach">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkLabel" id="status_label">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="hexpand">False</property>
|
|
+ <property name="label">Status</property>
|
|
+ <property name="halign">end</property>
|
|
+ <property name="valign">center</property>
|
|
+ <property name="xalign">1.0</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="left-attach">1</property>
|
|
+ <property name="top-attach">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ </template>
|
|
+</interface>
|
|
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 <http://www.gnu.org/licenses/>.
|
|
+ *
|
|
+ * Authors: Christian J. Kellner <ckellner@redhat.com>
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <config.h>
|
|
+
|
|
+#include <shell/cc-panel.h>
|
|
+#include <shell/list-box-helper.h>
|
|
+
|
|
+#include <glib/gi18n.h>
|
|
+#include <polkit/polkit.h>
|
|
+
|
|
+#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 @@
|
|
+<?xml version="1.0" encoding="UTF-8"?>
|
|
+<interface>
|
|
+ <requires lib="gtk+" version="3.20"/>
|
|
+
|
|
+ <template class="CcBoltPanel" parent="CcPanel">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can-focus">False</property>
|
|
+
|
|
+ <child>
|
|
+ <object class="GtkOverlay">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <child type="overlay">
|
|
+ <object class="GtkRevealer" id="notification_revealer">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="halign">center</property>
|
|
+ <property name="valign">start</property>
|
|
+ <property name="transition_type">slide-down</property>
|
|
+ <child>
|
|
+ <object class="GtkFrame">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <child>
|
|
+ <object class="GtkBox">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="spacing">12</property>
|
|
+ <child>
|
|
+ <object class="GtkLabel" id="notification_label">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="use_markup">True</property>
|
|
+ <property name="wrap">True</property>
|
|
+ </object>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkButton">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <property name="relief">none</property>
|
|
+ <signal name="clicked"
|
|
+ handler="on_notification_button_clicked_cb"
|
|
+ object="CcBoltPanel"
|
|
+ swapped="no" />
|
|
+ <child>
|
|
+ <object class="GtkImage">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="icon-name">window-close-symbolic</property>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ <style>
|
|
+ <class name="app-notification" />
|
|
+ </style>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+
|
|
+ <child>
|
|
+ <object class="GtkStack" id="container">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can-focus">False</property>
|
|
+ <property name="homogeneous">False</property>
|
|
+ <property name="transition_type">crossfade</property>
|
|
+
|
|
+ <!-- Spinner for when we are creating -->
|
|
+ <child>
|
|
+ <object class="GtkBox">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="expand">True</property>
|
|
+ <property name="halign">center</property>
|
|
+ <property name="valign">center</property>
|
|
+ <property name="orientation">vertical</property>
|
|
+ <property name="spacing">10</property>
|
|
+ <property name="margin">18</property>
|
|
+ <child type="center">
|
|
+ <object class="GtkSpinner" id="loading-spinner">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="active">True</property>
|
|
+ <property name="expand">True</property>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="name">loading</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+
|
|
+ <!-- No tunderbolt -->
|
|
+
|
|
+ <child>
|
|
+ <object class="GtkBox">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="expand">True</property>
|
|
+ <property name="halign">center</property>
|
|
+ <property name="valign">center</property>
|
|
+ <property name="orientation">vertical</property>
|
|
+ <property name="spacing">10</property>
|
|
+ <property name="margin">18</property>
|
|
+ <child type="center" >
|
|
+ <object class="GtkGrid">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="margin_start">12</property>
|
|
+ <property name="margin_end">6</property>
|
|
+ <property name="margin_top">12</property>
|
|
+ <property name="margin_bottom">12</property>
|
|
+ <property name="row_spacing">12</property>
|
|
+ <property name="column_spacing">24</property>
|
|
+
|
|
+ <child>
|
|
+ <object class="GtkImage">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="icon_name">thunderbolt-symbolic</property>
|
|
+ <property name="pixel_size">96</property>
|
|
+ <property name="yalign">0</property>
|
|
+ <style>
|
|
+ <class name="dim-label" />
|
|
+ </style>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="left_attach">0</property>
|
|
+ <property name="top_attach">0</property>
|
|
+ <property name="height">2</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+
|
|
+ <child>
|
|
+ <object class="GtkLabel" id="notb_caption">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="wrap">True</property>
|
|
+ <property name="xalign">0</property>
|
|
+ <property name="label" translatable="yes">No Thunderbolt support</property>
|
|
+ <attributes>
|
|
+ <attribute name="scale" value="1.2" />
|
|
+ </attributes>
|
|
+ <style>
|
|
+ <class name="dim-label" />
|
|
+ </style>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="left_attach">1</property>
|
|
+ <property name="top_attach">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+
|
|
+ <child>
|
|
+ <object class="GtkLabel" id="notb_details">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="hexpand">True</property>
|
|
+ <property name="max-width-chars">40</property>
|
|
+ <property name="use_markup">True</property>
|
|
+ <property name="xalign">0</property>
|
|
+ <property name="yalign">0</property>
|
|
+ <property name="wrap">True</property>
|
|
+ <property name="label" translatable="no">Could not connect to the thunderbolt subsystem.</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="left_attach">1</property>
|
|
+ <property name="top_attach">1</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+
|
|
+ </object>
|
|
+ </child>
|
|
+
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="name">no-thunderbolt</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+
|
|
+ <!-- Normal operation mode (show list of devices) -->
|
|
+ <child>
|
|
+ <object class="GtkScrolledWindow">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="hscrollbar-policy">never</property>
|
|
+
|
|
+ <child>
|
|
+ <object class="GtkViewport">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="shadow-type">none</property>
|
|
+
|
|
+ <child>
|
|
+ <object class="GtkBox">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="orientation">horizontal</property>
|
|
+ <property name="valign">start</property>
|
|
+
|
|
+ <!-- Stub box -->
|
|
+ <child>
|
|
+ <object class="GtkBox">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="hexpand">True</property>
|
|
+ </object>
|
|
+ </child>
|
|
+
|
|
+ <!-- center/content box -->
|
|
+ <child>
|
|
+ <object class="GtkBox">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="hexpand">True</property>
|
|
+ <property name="spacing">32</property>
|
|
+ <property name="margin_top">32</property>
|
|
+ <property name="margin_bottom">32</property>
|
|
+ <property name="margin_left">18</property>
|
|
+ <property name="margin_right">18</property>
|
|
+ <property name="orientation">vertical</property>
|
|
+
|
|
+ <!-- Auth Mode -->
|
|
+ <child>
|
|
+ <object class="GtkBox" id="authmode_box">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="orientation">horizontal</property>
|
|
+ <property name="spacing">12</property>
|
|
+ <child>
|
|
+ <object class="GtkBox">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="orientation">vertical</property>
|
|
+ <property name="spacing">6</property>
|
|
+ <child>
|
|
+ <object class="GtkLabel">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="hexpand">False</property>
|
|
+ <property name="halign">start</property>
|
|
+ <property name="xalign">0.0</property>
|
|
+ <property name="label" translatable="yes">Direct Access</property>
|
|
+ <property name="mnemonic_widget">authmode_switch</property>
|
|
+ <attributes>
|
|
+ <attribute name="weight" value="bold" />
|
|
+ </attributes>
|
|
+ </object>
|
|
+ </child>
|
|
+
|
|
+ <child>
|
|
+ <object class="GtkStack" id="authmode_mode">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can-focus">False</property>
|
|
+ <property name="transition-type">crossfade</property>
|
|
+ <property name="homogeneous">True</property>
|
|
+
|
|
+ <child>
|
|
+ <object class="GtkLabel">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="halign">start</property>
|
|
+ <property name="margin_left">0</property>
|
|
+ <property name="hexpand">False</property>
|
|
+ <property name="vexpand">False</property>
|
|
+ <property name="label" translatable="yes" >Allow direct access to devices such as docks and external GPUs.</property>
|
|
+ <property name="use_markup">True</property>
|
|
+ <property name="wrap">True</property>
|
|
+ <property name="xalign">0.0</property>
|
|
+ <property name="yalign">0.0</property>
|
|
+ <property name="max-width-chars">45</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="name">enabled</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+
|
|
+ <child>
|
|
+ <object class="GtkLabel">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="halign">start</property>
|
|
+ <property name="margin_left">0</property>
|
|
+ <property name="hexpand">False</property>
|
|
+ <property name="vexpand">False</property>
|
|
+ <property name="label" translatable="yes" >Only USB and Display Port devices can attach.</property>
|
|
+ <property name="use_markup">True</property>
|
|
+ <property name="wrap">True</property>
|
|
+ <property name="xalign">0.0</property>
|
|
+ <property name="yalign">0.0</property>
|
|
+ <property name="max-width-chars">45</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="name">disabled</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">True</property>
|
|
+ <property name="fill">True</property>
|
|
+ <property name="position">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkBox">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="orientation">horizontal</property>
|
|
+ <property name="spacing">6</property>
|
|
+ <property name="halign">center</property>
|
|
+ <property name="valign">start</property>
|
|
+
|
|
+ <child>
|
|
+ <object class="GtkSpinner" id="authmode_spinner">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="active">False</property>
|
|
+ </object>
|
|
+ </child>
|
|
+
|
|
+ <child>
|
|
+ <object class="GtkSwitch" id="authmode_switch">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <property name="halign">end</property>
|
|
+ <property name="valign">start</property>
|
|
+ <property name="active">True</property>
|
|
+ <signal name="state-set"
|
|
+ handler="on_authmode_state_set_cb"
|
|
+ object="CcBoltPanel"
|
|
+ swapped="yes" />
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">1</property>
|
|
+ <property name="pack-type">end</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+
|
|
+ <!-- Stack: devices/no-devices -->
|
|
+ <child>
|
|
+ <object class="GtkStack" id="devices_stack">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="transition-type">crossfade</property>
|
|
+
|
|
+ <child>
|
|
+ <object class="GtkBox">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="orientation">vertical</property>
|
|
+ <property name="spacing">32</property>
|
|
+
|
|
+ <!-- Pending Device List -->
|
|
+ <child>
|
|
+ <object class="GtkBox" id="pending_box">
|
|
+ <property name="visible">False</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="orientation">vertical</property>
|
|
+ <property name="spacing">12</property>
|
|
+
|
|
+ <!-- Pending Device List: Header -->
|
|
+ <child>
|
|
+ <object class="GtkBox" id="pending_header">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="hexpand">True</property>
|
|
+ <property name="halign">start</property>
|
|
+ <property name="spacing">6</property>
|
|
+ <child>
|
|
+ <object class="GtkImage">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="icon_name">dialog-warning-symbolic</property>
|
|
+ <property name="icon_size">1</property>
|
|
+ <property name="margin_left">0</property>
|
|
+ <property name="xalign">0.0</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkLabel">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="label" translatable="yes">Pending Devices</property>
|
|
+ <property name="xalign">0.0</property>
|
|
+ <attributes>
|
|
+ <attribute name="weight" value="bold"/>
|
|
+ </attributes>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">1</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkSpinner" id="pending_spinner">
|
|
+ <property name="hexpand">True</property>
|
|
+ <property name="visible">True</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">2</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+
|
|
+ <!-- Pending List: Devices -->
|
|
+ <child>
|
|
+ <object class="GtkFrame">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="valign">start</property>
|
|
+ <property name="vexpand">False</property>
|
|
+ <style>
|
|
+ <class name="view" />
|
|
+ </style>
|
|
+ <child>
|
|
+ <object class="GtkListBox" id="pending_list">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="selection-mode">none</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <signal name="row-activated"
|
|
+ handler="on_device_entry_row_activated_cb"
|
|
+ object="CcBoltPanel"
|
|
+ swapped="yes" />
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+
|
|
+ <!-- Device List -->
|
|
+ <child>
|
|
+ <object class="GtkBox" id="devices_box">
|
|
+ <property name="visible">False</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="orientation">vertical</property>
|
|
+ <property name="spacing">12</property>
|
|
+
|
|
+ <!-- Device List: Header -->
|
|
+ <child>
|
|
+ <object class="GtkBox" id="devices_header">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="hexpand">True</property>
|
|
+ <property name="halign">start</property>
|
|
+ <property name="spacing">6</property>
|
|
+ <child>
|
|
+ <object class="GtkLabel">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="label" translatable="yes">Devices</property>
|
|
+ <property name="xalign">0.0</property>
|
|
+ <attributes>
|
|
+ <attribute name="weight" value="bold"/>
|
|
+ </attributes>
|
|
+ </object>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkSpinner" id="probing_spinner">
|
|
+ <property name="hexpand">True</property>
|
|
+ <property name="visible">True</property>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+
|
|
+ <!-- Device List: Devices -->
|
|
+ <child>
|
|
+ <object class="GtkFrame">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="valign">start</property>
|
|
+ <property name="vexpand">False</property>
|
|
+ <style>
|
|
+ <class name="view" />
|
|
+ </style>
|
|
+ <child>
|
|
+ <object class="GtkListBox" id="devices_list">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="selection-mode">none</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <signal name="row-activated"
|
|
+ handler="on_device_entry_row_activated_cb"
|
|
+ object="CcBoltPanel"
|
|
+ swapped="yes" />
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+
|
|
+ </object>
|
|
+ </child>
|
|
+
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="name">have-devices</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+
|
|
+ <!-- No Devices -->
|
|
+ <child>
|
|
+ <object class="GtkBox">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="hexpand">True</property>
|
|
+ <property name="halign">start</property>
|
|
+ <property name="orientation">vertical</property>
|
|
+ <property name="spacing">6</property>
|
|
+ <child>
|
|
+ <object class="GtkLabel">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="label" translatable="yes">Devices</property>
|
|
+ <property name="xalign">0.0</property>
|
|
+ <attributes>
|
|
+ <attribute name="weight" value="bold"/>
|
|
+ </attributes>
|
|
+ </object>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkLabel">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="label" translatable="yes">No devices attached</property>
|
|
+ <property name="xalign">0.0</property>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="name">no-devices</property>
|
|
+ </packing>
|
|
+ </child> <!-- End of: No Devices -->
|
|
+
|
|
+ </object>
|
|
+ </child> <!-- End of Stack: devices/no-devices -->
|
|
+
|
|
+ </object>
|
|
+ </child> <!-- End of enter/content box -->
|
|
+
|
|
+
|
|
+ <!-- Stub box -->
|
|
+ <child>
|
|
+ <object class="GtkBox">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="hexpand">True</property>
|
|
+ </object>
|
|
+ </child>
|
|
+
|
|
+ <!-- End of content -->
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="name">devices-listing</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+
|
|
+ <!-- End of 'container' -->
|
|
+ </object>
|
|
+ </child>
|
|
+
|
|
+ <!-- End of overlay -->
|
|
+ </object>
|
|
+ </child>
|
|
+ </template>
|
|
+
|
|
+ <!-- Headerbar entries -->
|
|
+ <object class="GtkBox" id="headerbar_box">
|
|
+ <property name="visible">False</property>
|
|
+ <property name="can_focus">False</property>
|
|
+ <property name="spacing">6</property>
|
|
+ <property name="halign">end</property>
|
|
+ <child>
|
|
+ <object class="GtkLockButton" id="lock_button">
|
|
+ <property name="visible">True</property>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+
|
|
+</interface>
|
|
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 @@
|
|
+<?xml version="1.0" encoding="UTF-8"?>
|
|
+<gresources>
|
|
+ <gresource prefix="/org/gnome/control-center/thunderbolt">
|
|
+ <file preprocess="xml-stripblanks">cc-bolt-device-dialog.ui</file>
|
|
+ <file preprocess="xml-stripblanks">cc-bolt-device-entry.ui</file>
|
|
+ <file preprocess="xml-stripblanks">cc-bolt-panel.ui</file>
|
|
+ </gresource>
|
|
+</gresources>
|
|
+
|
|
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: <BOLT-SOURCE>"
|
|
+ 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
|
|
|