You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6564 lines
198 KiB
6564 lines
198 KiB
From ec695fae92ef7470ef05211160e431f5c3486299 Mon Sep 17 00:00:00 2001 |
|
From: Christian Kellner <christian@kellner.me> |
|
Date: Tue, 10 Apr 2018 09:43:22 +0200 |
|
Subject: [PATCH 1/4] shell: Don't set per-panel icon |
|
|
|
The control center app is considered one single application with |
|
a single icon to represent it. Therefore get rid of per-panel |
|
icons. |
|
--- |
|
shell/cc-window.c | 7 +------ |
|
1 file changed, 1 insertion(+), 6 deletions(-) |
|
|
|
diff --git a/shell/cc-window.c b/shell/cc-window.c |
|
index 557819e0c76c..33f1ddcad511 100644 |
|
--- a/shell/cc-window.c |
|
+++ b/shell/cc-window.c |
|
@@ -118,7 +118,6 @@ activate_panel (CcWindow *self, |
|
GIcon *gicon) |
|
{ |
|
GtkWidget *box, *title_widget; |
|
- const gchar *icon_name; |
|
|
|
if (!id) |
|
return FALSE; |
|
@@ -144,12 +143,8 @@ activate_panel (CcWindow *self, |
|
gtk_stack_set_visible_child_name (GTK_STACK (self->stack), id); |
|
|
|
/* set the title of the window */ |
|
- icon_name = get_icon_name_from_g_icon (gicon); |
|
- |
|
gtk_window_set_role (GTK_WINDOW (self), id); |
|
gtk_header_bar_set_title (GTK_HEADER_BAR (self->panel_headerbar), name); |
|
- gtk_window_set_default_icon_name (icon_name); |
|
- gtk_window_set_icon_name (GTK_WINDOW (self), icon_name); |
|
|
|
title_widget = cc_panel_get_title_widget (CC_PANEL (self->current_panel)); |
|
gtk_header_bar_set_custom_title (GTK_HEADER_BAR (self->panel_headerbar), title_widget); |
|
@@ -778,4 +773,4 @@ cc_window_set_search_item (CcWindow *center, |
|
gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (center->search_bar), TRUE); |
|
gtk_entry_set_text (GTK_ENTRY (center->search_entry), search); |
|
gtk_editable_set_position (GTK_EDITABLE (center->search_entry), -1); |
|
-} |
|
\ No newline at end of file |
|
+} |
|
-- |
|
2.17.0 |
|
|
|
From b24a8e9aa82b64de970d8137181bf8a03b6f724a Mon Sep 17 00:00:00 2001 |
|
From: Christian Kellner <christian@kellner.me> |
|
Date: Tue, 10 Apr 2018 09:47:48 +0200 |
|
Subject: [PATCH 2/4] shell: Icon name helper returns symbolic name |
|
|
|
The helper function to get the icon name from a GIcon directly |
|
returns the symbolic icon now. This makes it in turn possible |
|
to also directly check if the theme has the icon with the symbolic |
|
name instead of checking of for the full colored one and then |
|
deriving the symbolic name from that. The latter (old) practice |
|
will fail if there is a symbolic icon in the theme that has no |
|
full color icon (like e.g. thunderbolt). |
|
--- |
|
shell/cc-window.c | 19 ++++++++++--------- |
|
1 file changed, 10 insertions(+), 9 deletions(-) |
|
|
|
diff --git a/shell/cc-window.c b/shell/cc-window.c |
|
index 33f1ddcad511..3af9cf0bd9fc 100644 |
|
--- a/shell/cc-window.c |
|
+++ b/shell/cc-window.c |
|
@@ -88,8 +88,8 @@ enum |
|
}; |
|
|
|
/* Auxiliary methods */ |
|
-static const gchar * |
|
-get_icon_name_from_g_icon (GIcon *gicon) |
|
+static gchar * |
|
+get_symbolic_icon_name_from_g_icon (GIcon *gicon) |
|
{ |
|
const gchar * const *names; |
|
GtkIconTheme *icon_theme; |
|
@@ -103,8 +103,11 @@ get_icon_name_from_g_icon (GIcon *gicon) |
|
|
|
for (i = 0; names[i] != NULL; i++) |
|
{ |
|
- if (gtk_icon_theme_has_icon (icon_theme, names[i])) |
|
- return names[i]; |
|
+ g_autofree gchar *name = NULL; |
|
+ name = g_strdup_printf ("%s-symbolic", names[i]); |
|
+ |
|
+ if (gtk_icon_theme_has_icon (icon_theme, name)) |
|
+ return g_steal_pointer (&name); |
|
} |
|
|
|
return NULL; |
|
@@ -248,9 +251,8 @@ setup_model (CcWindow *shell) |
|
g_autofree gchar *name = NULL; |
|
g_autofree gchar *description = NULL; |
|
g_autofree gchar *id = NULL; |
|
- g_autofree gchar *symbolic_icon = NULL; |
|
+ g_autofree gchar *icon_name = NULL; |
|
g_autofree GStrv keywords = NULL; |
|
- const gchar *icon_name; |
|
|
|
gtk_tree_model_get (model, &iter, |
|
COL_CATEGORY, &category, |
|
@@ -261,8 +263,7 @@ setup_model (CcWindow *shell) |
|
COL_KEYWORDS, &keywords, |
|
-1); |
|
|
|
- icon_name = get_icon_name_from_g_icon (icon); |
|
- symbolic_icon = g_strdup_printf ("%s-symbolic", icon_name); |
|
+ icon_name = get_symbolic_icon_name_from_g_icon (icon); |
|
|
|
cc_panel_list_add_panel (CC_PANEL_LIST (shell->panel_list), |
|
category, |
|
@@ -270,7 +271,7 @@ setup_model (CcWindow *shell) |
|
name, |
|
description, |
|
keywords, |
|
- symbolic_icon); |
|
+ icon_name); |
|
|
|
valid = gtk_tree_model_iter_next (model, &iter); |
|
} |
|
-- |
|
2.17.0 |
|
|
|
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 |
|
|
|
From 2d1da22e17f703e27ff1b3177e35a54aa0c3aecc Mon Sep 17 00:00:00 2001 |
|
From: Christian Kellner <christian@kellner.me> |
|
Date: Fri, 13 Apr 2018 16:03:21 +0200 |
|
Subject: [PATCH 4/4] thunderbolt: move to the 'Devices' page |
|
|
|
The 'Devices' page is a fitting place for the thunderbolt, being |
|
an IO technology. It is expected that people that need to go to |
|
that page will be sent there via a gnome-shell notification, so |
|
there is no need for it to be on the main page. |
|
Ok'ed by the design team (jimmac). |
|
--- |
|
panels/thunderbolt/gnome-thunderbolt-panel.desktop.in.in | 2 +- |
|
shell/cc-panel-list.c | 2 +- |
|
2 files changed, 2 insertions(+), 2 deletions(-) |
|
|
|
diff --git a/panels/thunderbolt/gnome-thunderbolt-panel.desktop.in.in b/panels/thunderbolt/gnome-thunderbolt-panel.desktop.in.in |
|
index db2477e45a74..abd317341bfd 100644 |
|
--- a/panels/thunderbolt/gnome-thunderbolt-panel.desktop.in.in |
|
+++ b/panels/thunderbolt/gnome-thunderbolt-panel.desktop.in.in |
|
@@ -7,7 +7,7 @@ Terminal=false |
|
Type=Application |
|
NoDisplay=true |
|
StartupNotify=true |
|
-Categories=GNOME;GTK;Settings;X-GNOME-Settings-Panel;HardwareSettings;X-GNOME-DevicesSettings;X-GNOME-ConnectivitySettings; |
|
+Categories=GNOME;GTK;Settings;X-GNOME-Settings-Panel;HardwareSettings;X-GNOME-DevicesSettings; |
|
OnlyShowIn=GNOME;Unity; |
|
X-GNOME-Bugzilla-Bugzilla=GNOME |
|
X-GNOME-Bugzilla-Product=gnome-control-center |
|
diff --git a/shell/cc-panel-list.c b/shell/cc-panel-list.c |
|
index 99d8a91144ad..f5b83509d646 100644 |
|
--- a/shell/cc-panel-list.c |
|
+++ b/shell/cc-panel-list.c |
|
@@ -276,7 +276,6 @@ static const gchar * const panel_order[] = { |
|
"wifi", |
|
"mobile-broadband", |
|
"bluetooth", |
|
- "thunderbolt", |
|
"background", |
|
"notifications", |
|
"search", |
|
@@ -295,6 +294,7 @@ static const gchar * const panel_order[] = { |
|
"mouse", |
|
"printers", |
|
"removable-media", |
|
+ "thunderbolt", |
|
"wacom", |
|
"color", |
|
|
|
-- |
|
2.17.0 |
|
|
|
|