[gnome-software/wip/rancell/permissions: 41/41] Add a basic permissions system
- From: Robert Ancell <rancell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software/wip/rancell/permissions: 41/41] Add a basic permissions system
- Date: Thu, 22 Jun 2017 03:39:36 +0000 (UTC)
commit 68334d1f4bde4b8446945a718b39ce0f7abfea9b
Author: Robert Ancell <robert ancell canonical com>
Date: Fri May 26 16:30:56 2017 +1200
Add a basic permissions system
lib/gs-app.c | 47 ++++++++
lib/gs-app.h | 4 +
lib/gs-permission.c | 252 +++++++++++++++++++++++++++++++++++++++++
lib/gs-permission.h | 57 +++++++++
lib/meson.build | 2 +
plugins/snap/gs-plugin-snap.c | 50 ++++++++
src/gs-details-page.c | 40 +++++++
src/gs-details-page.ui | 55 ++++++++-
src/gtk-style-hc.css | 5 +
src/gtk-style.css | 5 +
10 files changed, 512 insertions(+), 5 deletions(-)
---
diff --git a/lib/gs-app.c b/lib/gs-app.c
index 8ed7e7e..7a9fa3e 100644
--- a/lib/gs-app.c
+++ b/lib/gs-app.c
@@ -87,6 +87,7 @@ struct _GsApp
gchar **menu_path;
gchar *origin;
gchar *origin_hostname;
+ GPtrArray *permissions;
gchar *update_version;
gchar *update_version_ui;
gchar *update_details;
@@ -423,6 +424,16 @@ gs_app_to_string (GsApp *app)
gs_app_kv_lpad (str, "icon-filename",
as_icon_get_filename (icon));
}
+ for (i = 0; i < app->permissions->len; i++) {
+ GsPermission *permission;
+ g_autofree gchar *key = NULL;
+
+ permission = g_ptr_array_index (app->permissions, i);
+ key = g_strdup_printf ("permission-%02u", i);
+ gs_app_kv_printf (str, key, "[%s] %s",
+ gs_permission_get_label (permission),
+ gs_permission_get_enabled (permission) ? "true" : "false");
+ }
if (app->match_value != 0)
gs_app_kv_printf (str, "match-value", "%05x", app->match_value);
if (app->priority != 0)
@@ -2274,6 +2285,40 @@ gs_app_set_origin_hostname (GsApp *app, const gchar *origin_hostname)
}
/**
+ * gs_app_add_permission:
+ * @app: a #GsApp
+ * @permission: a #GsPermission
+ *
+ * Adds a permission to the applicaton.
+ *
+ * Since: 3.26
+ **/
+void
+gs_app_add_permission (GsApp *app, GsPermission *permission)
+{
+ g_return_if_fail (GS_IS_APP (app));
+ g_return_if_fail (GS_IS_PERMISSION (permission));
+ g_ptr_array_add (app->permissions, g_object_ref (permission));
+}
+
+/**
+ * gs_app_get_permissions:
+ * @app: a #GsApp
+ *
+ * Gets the list of permissions.
+ *
+ * Returns: (element-type GsPermission) (transfer none): a list
+ *
+ * Since: 3.26
+ **/
+GPtrArray *
+gs_app_get_permissions (GsApp *app)
+{
+ g_return_val_if_fail (GS_IS_APP (app), NULL);
+ return app->permissions;
+}
+
+/**
* gs_app_add_screenshot:
* @app: a #GsApp
* @screenshot: a #AsScreenshot
@@ -3651,6 +3696,7 @@ gs_app_dispose (GObject *object)
g_clear_pointer (&app->reviews, g_ptr_array_unref);
g_clear_pointer (&app->provides, g_ptr_array_unref);
g_clear_pointer (&app->icons, g_ptr_array_unref);
+ g_clear_pointer (&app->permissions, g_ptr_array_unref);
G_OBJECT_CLASS (gs_app_parent_class)->dispose (object);
}
@@ -3819,6 +3865,7 @@ gs_app_init (GsApp *app)
app->reviews = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
app->provides = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
app->icons = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+ app->permissions = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
app->metadata = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
diff --git a/lib/gs-app.h b/lib/gs-app.h
index 45165f8..3da0b85 100644
--- a/lib/gs-app.h
+++ b/lib/gs-app.h
@@ -28,6 +28,7 @@
#include <appstream-glib.h>
#include "gs-price.h"
+#include "gs-permission.h"
G_BEGIN_DECLS
@@ -183,6 +184,9 @@ void gs_app_set_origin (GsApp *app,
const gchar *gs_app_get_origin_hostname (GsApp *app);
void gs_app_set_origin_hostname (GsApp *app,
const gchar *origin_hostname);
+GPtrArray *gs_app_get_permissions (GsApp *app);
+void gs_app_add_permission (GsApp *app,
+ GsPermission *permission);
GPtrArray *gs_app_get_screenshots (GsApp *app);
void gs_app_add_screenshot (GsApp *app,
AsScreenshot *screenshot);
diff --git a/lib/gs-permission.c b/lib/gs-permission.c
new file mode 100644
index 0000000..397d783
--- /dev/null
+++ b/lib/gs-permission.c
@@ -0,0 +1,252 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2017 Canonical Ltd.
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include "gs-permission.h"
+
+struct _GsPermission
+{
+ GObject parent_instance;
+
+ gchar *label;
+ gboolean enabled;
+ GHashTable *metadata; /* utf8: utf8 */
+};
+
+G_DEFINE_TYPE (GsPermission, gs_permission, G_TYPE_OBJECT)
+
+/**
+ * gs_permission_get_metadata_item:
+ * @auth: a #GsPermission
+ * @key: a string
+ *
+ * Gets some metadata from a permission object.
+ * It is left for the the plugin to use this method as required, but a
+ * typical use would be to retrieve an ID for this permission.
+ *
+ * Returns: A string value, or %NULL for not found
+ */
+const gchar *
+gs_permission_get_metadata_item (GsPermission *auth, const gchar *key)
+{
+ g_return_val_if_fail (GS_IS_PERMISSION (auth), NULL);
+ g_return_val_if_fail (key != NULL, NULL);
+ return g_hash_table_lookup (auth->metadata, key);
+}
+
+/**
+ * gs_permission_add_metadata:
+ * @auth: a #GsPermission
+ * @key: a string
+ * @value: a string
+ *
+ * Adds metadata to the permission object.
+ * It is left for the the plugin to use this method as required, but a
+ * typical use would be to store an ID for this permission.
+ */
+void
+gs_permission_add_metadata (GsPermission *auth, const gchar *key, const gchar *value)
+{
+ g_return_if_fail (GS_IS_PERMISSION (auth));
+ g_hash_table_insert (auth->metadata, g_strdup (key), g_strdup (value));
+}
+
+/**
+ * gs_permission_get_label:
+ * @permission: a #GsPermission
+ *
+ * Get the label for this permission.
+ *
+ * Returns: a label string.
+ */
+const gchar *
+gs_permission_get_label (GsPermission *permission)
+{
+ g_return_val_if_fail (GS_IS_PERMISSION (permission), NULL);
+ return permission->label;
+}
+
+/**
+ * gs_permission_get_enabled:
+ * @permission: a #GsPermission
+ *
+ * Get if this permission is enabled.
+ *
+ * Returns: %TRUE if enabled
+ */
+gboolean
+gs_permission_get_enabled (GsPermission *permission)
+{
+ g_return_val_if_fail (GS_IS_PERMISSION (permission), 0);
+ return permission->enabled;
+}
+
+/**
+ * gs_permission_set_enabled:
+ * @permission: a #GsPermission
+ * @enabled: %TRUE if this permission is enabled.
+ *
+ * Set if this permission is enabled.
+ */
+void
+gs_permission_set_enabled (GsPermission *permission, gboolean enabled)
+{
+ g_return_if_fail (GS_IS_PERMISSION (permission));
+ permission->enabled = enabled;
+}
+
+static void
+gs_permission_finalize (GObject *object)
+{
+ GsPermission *permission = GS_PERMISSION (object);
+
+ g_free (permission->label);
+ g_hash_table_unref (permission->metadata);
+
+ G_OBJECT_CLASS (gs_permission_parent_class)->finalize (object);
+}
+
+static void
+gs_permission_class_init (GsPermissionClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = gs_permission_finalize;
+}
+
+static void
+gs_permission_init (GsPermission *permission)
+{
+ permission->metadata = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_free);
+}
+
+static GsPermission *
+gs_permission_new (const gchar *label, gboolean enabled)
+{
+ GsPermission *permission;
+ permission = g_object_new (GS_TYPE_PERMISSION, NULL);
+ permission->label = g_strdup (label);
+ permission->enabled = enabled;
+ return GS_PERMISSION (permission);
+}
+
+/**
+ * gs_permission_new_camera:
+ * @enabled: %TRUE if camera access is enabled.
+ *
+ * Creates a new permission object for camera access.
+ *
+ * Return value: a new #GsPermission object.
+ **/
+GsPermission *
+gs_permission_new_camera (gboolean enabled)
+{
+ return gs_permission_new (_("Can acquire photos / video from cameras"), enabled);
+}
+
+/**
+ * gs_permission_new_bluetooth:
+ * @enabled: %TRUE if Bluetooth access is enabled.
+ *
+ * Creates a new permission object for Bluetooth access.
+ *
+ * Return value: a new #GsPermission object.
+ **/
+GsPermission *
+gs_permission_new_bluetooth (gboolean enabled)
+{
+ return gs_permission_new (_("Can access Bluetooth devices"), enabled);
+}
+
+/**
+ * gs_permission_new_network:
+ * @enabled: %TRUE if network access is enabled.
+ *
+ * Creates a new permission object for network access.
+ *
+ * Return value: a new #GsPermission object.
+ **/
+GsPermission *
+gs_permission_new_network (gboolean enabled)
+{
+ return gs_permission_new (_("Can access the network"), enabled);
+}
+
+/**
+ * gs_permission_new_media:
+ * @enabled: %TRUE if removable media is enabled.
+ *
+ * Creates a new permission object for removable media.
+ *
+ * Return value: a new #GsPermission object.
+ **/
+GsPermission *
+gs_permission_new_media (gboolean enabled)
+{
+ return gs_permission_new (_("Can access removable media (USB drives etc)"), enabled);
+}
+
+/**
+ * gs_permission_new_optical_drive:
+ * @enabled: %TRUE if optical drive access is enabled.
+ *
+ * Creates a new permission object for optical drive access.
+ *
+ * Return value: a new #GsPermission object.
+ **/
+GsPermission *
+gs_permission_new_optical_drive (gboolean enabled)
+{
+ return gs_permission_new (_("Can access optical drives (CD, DVD etc)"), enabled);
+}
+
+/**
+ * gs_permission_new_printing:
+ * @enabled: %TRUE if printing access is enabled.
+ *
+ * Creates a new permission object for printing access.
+ *
+ * Return value: a new #GsPermission object.
+ **/
+GsPermission *
+gs_permission_new_printing (gboolean enabled)
+{
+ return gs_permission_new (_("Can print documents"), enabled);
+}
+
+/**
+ * gs_permission_new_shutdown:
+ * @enabled: %TRUE if shutdown / restart is allowed.
+ *
+ * Creates a new permission object for shutdown / restart of this machine.
+ *
+ * Return value: a new #GsPermission object.
+ **/
+GsPermission *
+gs_permission_new_shutdown (gboolean enabled)
+{
+ return gs_permission_new (_("Can shutdown / restart this computer"), enabled);
+}
+
+/* vim: set noexpandtab: */
diff --git a/lib/gs-permission.h b/lib/gs-permission.h
new file mode 100644
index 0000000..c952ac3
--- /dev/null
+++ b/lib/gs-permission.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2017 Canonical Ltd.
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GS_PERMISSION_H
+#define __GS_PERMISSION_H
+
+#include <glib-object.h>
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_PERMISSION (gs_permission_get_type ())
+
+G_DECLARE_FINAL_TYPE (GsPermission, gs_permission, GS, PERMISSION, GObject)
+
+GsPermission *gs_permission_new_bluetooth (gboolean enabled);
+GsPermission *gs_permission_new_camera (gboolean enabled);
+GsPermission *gs_permission_new_network (gboolean enabled);
+GsPermission *gs_permission_new_media (gboolean enabled);
+GsPermission *gs_permission_new_optical_drive (gboolean enabled);
+GsPermission *gs_permission_new_printing (gboolean enabled);
+GsPermission *gs_permission_new_shutdown (gboolean enabled);
+
+const gchar *gs_permission_get_metadata_item (GsPermission *permission,
+ const gchar *key);
+void gs_permission_add_metadata (GsPermission *permission,
+ const gchar *key,
+ const gchar *value);
+
+const gchar *gs_permission_get_label (GsPermission *permission);
+gboolean gs_permission_get_enabled (GsPermission *permission);
+void gs_permission_set_enabled (GsPermission *permission,
+ gboolean enabled);
+
+G_END_DECLS
+
+#endif /* __GS_PERMISSION_H */
+
+/* vim: set noexpandtab: */
diff --git a/lib/meson.build b/lib/meson.build
index 7d910ec..b9034b1 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -43,6 +43,7 @@ install_headers([
'gs-auth.h',
'gs-category.h',
'gs-os-release.h',
+ 'gs-permission.h',
'gs-plugin.h',
'gs-plugin-event.h',
'gs-plugin-types.h',
@@ -62,6 +63,7 @@ libgnomesoftware = static_library(
'gs-category.c',
'gs-debug.c',
'gs-os-release.c',
+ 'gs-permission.c',
'gs-plugin.c',
'gs-plugin-event.c',
'gs-plugin-job.c',
diff --git a/plugins/snap/gs-plugin-snap.c b/plugins/snap/gs-plugin-snap.c
index b268a13..737783e 100644
--- a/plugins/snap/gs-plugin-snap.c
+++ b/plugins/snap/gs-plugin-snap.c
@@ -513,6 +513,56 @@ gs_plugin_refine_app (GsPlugin *plugin,
return FALSE;
}
+ if (gs_app_get_permissions (app)->len == 0) {
+ g_autoptr(GPtrArray) plugs = NULL;
+ g_autoptr(GPtrArray) slots = NULL;
+ guint i;
+
+ if (!snapd_client_get_interfaces_sync (client, &plugs, &slots, cancellable, error))
+ return FALSE;
+ for (i = 0; i < plugs->len; i++) {
+ SnapdPlug *plug = plugs->pdata[i];
+ const gchar *name;
+ gboolean is_connected;
+ g_autoptr(GsPermission) permission = NULL;
+
+ /* skip if not relating to this snap */
+ if (g_strcmp0 (snapd_plug_get_snap (plug), gs_app_get_name (app)) != 0)
+ continue;
+
+ /* map interfaces to known permissions */
+ name = snapd_plug_get_name (plug);
+ is_connected = snapd_plug_get_connections (plug)->len > 0;
+ if (g_strcmp0 (name, "camera") == 0)
+ permission = gs_permission_new_camera (is_connected);
+ else if (g_strcmp0 (name, "removable-media") == 0)
+ permission = gs_permission_new_media (is_connected);
+ else if (g_strcmp0 (name, "optical-drive") == 0)
+ permission = gs_permission_new_optical_drive (is_connected);
+ else if (g_strcmp0 (name, "network") == 0)
+ permission = gs_permission_new_network (is_connected);
+ else if (g_strcmp0 (name, "cups-control") == 0)
+ permission = gs_permission_new_printing (is_connected);
+ else if (g_strcmp0 (name, "bluetooth-control") == 0)
+ permission = gs_permission_new_bluetooth (is_connected);
+ else if (g_strcmp0 (name, "shutdown") == 0)
+ permission = gs_permission_new_shutdown (is_connected);
+ else if (g_strcmp0 (name, "home") == 0 ||
+ g_strcmp0 (name, "opengl") == 0 ||
+ g_strcmp0 (name, "pulseaudio") == 0 ||
+ g_strcmp0 (name, "unity7") == 0 ||
+ g_strcmp0 (name, "x11") == 0) {
+ g_debug ("Ignoring common plug %s:%s", snapd_plug_get_snap (plug), name);
+ continue;
+ } else {
+ g_warning ("Ignoring unknown plug %s:%s", snapd_plug_get_snap (plug), name);
+ continue;
+ }
+
+ gs_app_add_permission (app, permission);
+ }
+ }
+
return TRUE;
}
diff --git a/src/gs-details-page.c b/src/gs-details-page.c
index eb76079..dfd75dc 100644
--- a/src/gs-details-page.c
+++ b/src/gs-details-page.c
@@ -76,6 +76,7 @@ struct _GsDetailsPage
GtkWidget *box_details_screenshot_main;
GtkWidget *box_details_screenshot_thumbnails;
GtkWidget *box_details_license_list;
+ GtkWidget *box_permissions;
GtkWidget *button_details_launch;
GtkWidget *button_details_add_shortcut;
GtkWidget *button_details_remove_shortcut;
@@ -121,6 +122,7 @@ struct _GsDetailsPage
GtkWidget *spinner_remove;
GtkWidget *stack_details;
GtkWidget *grid_details_kudo;
+ GtkWidget *grid_permissions;
GtkWidget *image_details_kudo_docs;
GtkWidget *image_details_kudo_sandboxed;
GtkWidget *image_details_kudo_integration;
@@ -521,6 +523,40 @@ gs_details_page_notify_state_changed_cb (GsApp *app,
}
static void
+gs_details_page_refresh_permissions (GsDetailsPage *self)
+{
+ GPtrArray *permissions;
+ guint i;
+
+ /* nothing to show */
+ if (self->app == NULL)
+ return;
+
+ /* show or hide the entire permissions section */
+ permissions = gs_app_get_permissions (self->app);
+ gtk_widget_set_visible (self->box_permissions, permissions->len > 0);
+
+ gtk_container_foreach (GTK_CONTAINER (self->grid_permissions),
+ (GtkCallback) gtk_widget_destroy, NULL);
+ for (i = 0; i < permissions->len; i++) {
+ GsPermission *permission = g_ptr_array_index (permissions, i);
+ GtkWidget *sw, *label;
+
+ sw = gtk_switch_new ();
+ gtk_widget_set_visible (sw, TRUE);
+ gtk_switch_set_active (GTK_SWITCH (sw), gs_permission_get_enabled (permission));
+ gtk_grid_attach (GTK_GRID (self->grid_permissions), sw, 0, i, 1, 1);
+
+ label = gtk_label_new (gs_permission_get_label (permission));
+ g_object_set (label,
+ "xalign", 0.0,
+ NULL);
+ gtk_widget_set_visible (label, TRUE);
+ gtk_grid_attach (GTK_GRID (self->grid_permissions), label, 1, i, 1, 1);
+ }
+}
+
+static void
gs_details_page_screenshot_selected_cb (GtkListBox *list,
GtkListBoxRow *row,
GsDetailsPage *self)
@@ -1458,6 +1494,7 @@ gs_details_page_app_refine_cb (GObject *source,
app_dump = gs_app_to_string (self->app);
g_debug ("%s", app_dump);
+ gs_details_page_refresh_permissions (self);
gs_details_page_refresh_screenshots (self);
gs_details_page_refresh_addons (self);
gs_details_page_refresh_reviews (self);
@@ -1507,6 +1544,7 @@ set_app (GsDetailsPage *self, GsApp *app)
/* change widgets */
gs_page_switch_to (GS_PAGE (self), TRUE);
+ gs_details_page_refresh_permissions (self);
gs_details_page_refresh_screenshots (self);
gs_details_page_refresh_addons (self);
gs_details_page_refresh_reviews (self);
@@ -2245,6 +2283,7 @@ gs_details_page_class_init (GsDetailsPageClass *klass)
gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, box_details_screenshot_main);
gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, box_details_screenshot_thumbnails);
gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, box_details_license_list);
+ gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, box_permissions);
gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, button_details_launch);
gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, button_details_add_shortcut);
gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, button_details_remove_shortcut);
@@ -2288,6 +2327,7 @@ gs_details_page_class_init (GsDetailsPageClass *klass)
gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, spinner_remove);
gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, stack_details);
gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, grid_details_kudo);
+ gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, grid_permissions);
gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, image_details_kudo_docs);
gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, image_details_kudo_sandboxed);
gtk_widget_class_bind_template_child (widget_class, GsDetailsPage, image_details_kudo_integration);
diff --git a/src/gs-details-page.ui b/src/gs-details-page.ui
index cacd1a0..888ca7f 100644
--- a/src/gs-details-page.ui
+++ b/src/gs-details-page.ui
@@ -571,7 +571,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">0</property>
+ <property name="position">1</property>
</packing>
</child>
</object>
@@ -582,6 +582,51 @@
</packing>
</child>
<child>
+ <object class="GtkBox" id="box_permissions">
+ <property name="visible">False</property>
+ <property name="orientation">vertical</property>
+ <property name="margin_bottom">26</property>
+ <property name="spacing">30</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="valign">start</property>
+ <property name="hexpand">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Permissions</property>
+ <style>
+ <class name="application-permissions-title"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid" id="grid_permissions">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">9</property>
+ <property name="column_spacing">24</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">11</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkLabel" id="application_details_details_title">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -597,7 +642,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">11</property>
+ <property name="position">12</property>
</packing>
</child>
<child>
@@ -1135,7 +1180,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">12</property>
+ <property name="position">13</property>
</packing>
</child>
<child>
@@ -1198,7 +1243,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">13</property>
+ <property name="position">14</property>
</packing>
</child>
<child>
@@ -1263,7 +1308,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">14</property>
+ <property name="position">15</property>
</packing>
</child>
</object>
diff --git a/src/gtk-style-hc.css b/src/gtk-style-hc.css
index 5dd475c..fb8cfdc 100644
--- a/src/gtk-style-hc.css
+++ b/src/gtk-style-hc.css
@@ -96,6 +96,11 @@
text-shadow: none;
}
+.application-permissions-title {
+ font-weight: bold;
+ font-size: 125%;
+}
+
.application-details-title {
font-weight: bold;
font-size: 125%;
diff --git a/src/gtk-style.css b/src/gtk-style.css
index c259469..534d56f 100644
--- a/src/gtk-style.css
+++ b/src/gtk-style.css
@@ -219,6 +219,11 @@
text-shadow: none;
}
+.application-permissions-title {
+ font-weight: bold;
+ font-size: 125%;
+}
+
.application-details-title {
font-weight: bold;
font-size: 125%;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]