[gnome-disk-utility/new-ui] Handle LUKS volumes and show spinner in grid
- From: David Zeuthen <davidz src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-disk-utility/new-ui] Handle LUKS volumes and show spinner in grid
- Date: Sat, 24 Oct 2009 22:09:49 +0000 (UTC)
commit b671bc977f2c7fd8104e28cf1e0c7a1d849fb368
Author: David Zeuthen <davidz redhat com>
Date: Sat Oct 24 18:08:49 2009 -0400
Handle LUKS volumes and show spinner in grid
We still need to port the code for the passphrase dialogs to
sub-classes of GduDialog but that's for another day.
src/gdu-gtk/gdu-volume-grid.c | 464 +++++++++++++++++++++++++---------
src/palimpsest/gdu-section-volumes.c | 447 ++++++++++++++++++++++++++++++++
2 files changed, 797 insertions(+), 114 deletions(-)
---
diff --git a/src/gdu-gtk/gdu-volume-grid.c b/src/gdu-gtk/gdu-volume-grid.c
index cdbafa4..e1281c7 100644
--- a/src/gdu-gtk/gdu-volume-grid.c
+++ b/src/gdu-gtk/gdu-volume-grid.c
@@ -53,11 +53,14 @@ struct GridElement
GridElement *next;
/* these values are set in recompute_size() */
- gint x;
- gint y;
- gint width;
- gint height;
+ guint x;
+ guint y;
+ guint width;
+ guint height;
GridEdgeFlags edge_flags;
+
+ /* used for the job spinner */
+ guint spinner_current;
};
static void
@@ -84,6 +87,8 @@ struct GduVolumeGridPrivate
GridElement *selected;
GridElement *focused;
+
+ guint animation_timeout_id;
};
enum
@@ -105,15 +110,15 @@ G_DEFINE_TYPE (GduVolumeGrid, gdu_volume_grid, GTK_TYPE_DRAWING_AREA)
static void recompute_grid (GduVolumeGrid *grid);
static void recompute_size (GduVolumeGrid *grid,
- gint width,
- gint height);
+ guint width,
+ guint height);
static GridElement *find_element_for_presentable (GduVolumeGrid *grid,
GduPresentable *presentable);
static GridElement *find_element_for_position (GduVolumeGrid *grid,
- gint x,
- gint y);
+ guint x,
+ guint y);
static gboolean gdu_volume_grid_expose_event (GtkWidget *widget,
GdkEventExpose *event);
@@ -157,6 +162,11 @@ gdu_volume_grid_finalize (GObject *object)
grid);
g_object_unref (grid->priv->pool);
+ if (grid->priv->animation_timeout_id > 0) {
+ g_source_remove (grid->priv->animation_timeout_id);
+ grid->priv->animation_timeout_id = 0;
+ }
+
if (G_OBJECT_CLASS (gdu_volume_grid_parent_class)->finalize != NULL)
G_OBJECT_CLASS (gdu_volume_grid_parent_class)->finalize (object);
}
@@ -497,10 +507,37 @@ presentable_sort_offset (GduPresentable *a, GduPresentable *b)
return 0;
}
+static guint
+get_depth (GList *elements)
+{
+ guint depth;
+ GList *l;
+
+ depth = 0;
+ if (elements == NULL)
+ goto out;
+
+ for (l = elements; l != NULL; l = l->next) {
+ GridElement *ee = l->data;
+ guint ee_depth;
+
+ ee_depth = get_depth (ee->embedded_elements) + 1;
+ if (ee_depth > depth)
+ depth = ee_depth;
+ }
+
+ out:
+ return depth;
+}
+
static void
-recompute_size (GduVolumeGrid *grid,
- gint width,
- gint height)
+recompute_size_for_slice (GList *elements,
+ guint width,
+ guint height,
+ guint total_width,
+ guint total_height,
+ guint offset_x,
+ guint offset_y)
{
GList *l;
gint x;
@@ -508,15 +545,17 @@ recompute_size (GduVolumeGrid *grid,
x = 0;
pixels_left = width;
- for (l = grid->priv->elements; l != NULL; l = l->next) {
+ for (l = elements; l != NULL; l = l->next) {
GridElement *element = l->data;
gint element_width;
- gboolean is_first;
gboolean is_last;
+ guint element_depth;
- is_first = (l == grid->priv->elements);
is_last = (l->next == NULL);
+ element_depth = get_depth (element->embedded_elements);
+ //g_debug ("element_depth = %d (x,y)=(%d,%d) height=%d", element_depth, offset_x, offset_y, height);
+
if (is_last) {
element_width = pixels_left;
pixels_left = 0;
@@ -527,67 +566,111 @@ recompute_size (GduVolumeGrid *grid,
pixels_left -= element_width;
}
- element->x = x;
- element->y = 0;
+ element->x = x + offset_x;
+ element->y = offset_y;
element->width = element_width;
- element->height = height;
- element->edge_flags = GRID_EDGE_TOP | GRID_EDGE_BOTTOM;
- if (is_first)
+ if (element_depth > 0) {
+ element->height = height / (element_depth + 1);
+ } else {
+ element->height = height;
+ }
+
+ if (element->x == 0)
element->edge_flags |= GRID_EDGE_LEFT;
- if (is_last)
+ if (element->y == 0)
+ element->edge_flags |= GRID_EDGE_TOP;
+ if (element->x + element->width == total_width)
element->edge_flags |= GRID_EDGE_RIGHT;
+ if (element->y + element->height == total_height)
+ element->edge_flags |= GRID_EDGE_BOTTOM;
x += element_width;
- /* for now we don't recurse - we only handle embedded element for toplevel elements */
- if (element->embedded_elements != NULL) {
- gint e_x;
- gint e_width;
- gint e_pixels_left;
- GList *ll;
+ recompute_size_for_slice (element->embedded_elements,
+ element->width,
+ height - element->height,
+ total_width,
+ total_height,
+ element->x,
+ element->height + element->y);
+ }
+}
- element->height = height/3;
- element->edge_flags &= ~(GRID_EDGE_BOTTOM);
-
- e_x = element->x;
- e_width = element->width;
- e_pixels_left = e_width;
- for (ll = element->embedded_elements; ll != NULL; ll = ll->next) {
- GridElement *e_element = ll->data;
- gint e_element_width;
- gboolean e_is_first;
- gboolean e_is_last;
-
- e_is_first = (ll == element->embedded_elements);
- e_is_last = (ll->next == NULL);
-
- if (e_is_last) {
- e_element_width = e_pixels_left;
- e_pixels_left = 0;
- } else {
- e_element_width = e_element->size_ratio * e_width;
- if (e_element_width > e_pixels_left)
- element_width = e_pixels_left;
- e_pixels_left -= e_element_width;
- }
+static void
+recompute_size (GduVolumeGrid *grid,
+ guint width,
+ guint height)
+{
+ recompute_size_for_slice (grid->priv->elements,
+ width,
+ height,
+ width,
+ height,
+ 0,
+ 0);
+}
- e_element->x = e_x;
- e_element->y = element->height;
- e_element->width = e_element_width;
- e_element->height = height - e_element->y;
- e_element->edge_flags = GRID_EDGE_BOTTOM;
- if (is_first && e_is_first)
- e_element->edge_flags |= GRID_EDGE_LEFT;
- if (is_last && e_is_last)
- e_element->edge_flags |= GRID_EDGE_RIGHT;
+static void
+add_luks_holders (GduVolumeGrid *grid,
+ GridElement *element)
+{
+ GduDevice *d;
+ GduDevice *dholder;
+ GduPresentable *pholder;
+ const gchar *holder;
+ GridElement *holder_element;
+
+ d = NULL;
+ dholder = NULL;
+ pholder = NULL;
+
+ d = gdu_presentable_get_device (element->presentable);
+ if (d == NULL)
+ goto out;
- e_x += e_element_width;
+ if (g_strcmp0 (gdu_device_id_get_usage (d), "crypto") != 0)
+ goto out;
- }
- }
- }
+ holder = gdu_device_luks_get_holder (d);
+ if (holder == NULL || g_strcmp0 (holder, "/") == 0)
+ goto out;
+
+ dholder = gdu_pool_get_by_object_path (grid->priv->pool, holder);
+ if (dholder == NULL)
+ goto out;
+
+ pholder = gdu_pool_get_volume_by_device (grid->priv->pool, dholder);
+ if (pholder == NULL)
+ goto out;
+
+ holder_element = g_new0 (GridElement, 1);
+ holder_element->size_ratio = 1.0;
+ holder_element->presentable = g_object_ref (pholder);
+ holder_element->parent = element;
+
+ g_assert (element->embedded_elements == NULL);
+
+ //g_debug ("added holder %s for %s", gdu_device_get_device_file (dholder), gdu_device_get_device_file (d));
+
+ element->embedded_elements = g_list_append (element->embedded_elements,
+ holder_element);
+
+ /* recurse - because we might have more than one level of encryption - for example
+ *
+ * sda1 -> LUKS -> LUKS -> filesystem
+ */
+ add_luks_holders (grid, holder_element);
+
+ out:
+ if (d != NULL)
+ g_object_unref (d);
+ if (dholder != NULL)
+ g_object_unref (dholder);
+ if (pholder != NULL)
+ g_object_unref (pholder);
}
+
static void
recompute_grid (GduVolumeGrid *grid)
{
@@ -668,10 +751,17 @@ recompute_grid (GduVolumeGrid *grid)
element->embedded_elements = g_list_append (element->embedded_elements,
logical_element);
+
+ add_luks_holders (grid, logical_element);
+
}
g_list_foreach (enclosed_logical_partitions, (GFunc) g_object_unref, NULL);
g_list_free (enclosed_logical_partitions);
- }
+
+ }
+
+ add_luks_holders (grid, element);
+
if (ed != NULL)
g_object_unref (ed);
@@ -713,6 +803,63 @@ recompute_grid (GduVolumeGrid *grid)
}
static void
+render_spinner (cairo_t *cr,
+ guint size,
+ guint num_lines,
+ guint current,
+ gdouble x,
+ gdouble y)
+{
+ guint n;
+ gdouble radius;
+ gdouble cx;
+ gdouble cy;
+ gdouble half;
+
+ cx = x + size/2.0;
+ cy = y + size/2.0;
+ radius = size/2.0;
+ half = num_lines / 2;
+
+ current = current % num_lines;
+
+ for (n = 0; n < num_lines; n++) {
+ gdouble inset;
+ gdouble t;
+
+ inset = 0.7 * radius;
+
+ /* transparency is a function of time and intial value */
+ t = (gdouble) ((n + num_lines - current) % num_lines) / num_lines;
+
+ cairo_set_source_rgba (cr, 0, 0, 0, t);
+ cairo_set_line_width (cr, 2.0);
+ cairo_move_to (cr,
+ cx + (radius - inset) * cos (n * M_PI / half),
+ cy + (radius - inset) * sin (n * M_PI / half));
+ cairo_line_to (cr,
+ cx + radius * cos (n * M_PI / half),
+ cy + radius * sin (n * M_PI / half));
+ cairo_stroke (cr);
+ }
+}
+
+static void
+render_pixbuf (cairo_t *cr,
+ gdouble x,
+ gdouble y,
+ GdkPixbuf *pixbuf)
+{
+ gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y);
+ cairo_rectangle (cr,
+ x,
+ y,
+ gdk_pixbuf_get_width (pixbuf),
+ gdk_pixbuf_get_height (pixbuf));
+ cairo_fill (cr);
+}
+
+static void
round_rect (cairo_t *cr,
gdouble x, gdouble y,
gdouble w, gdouble h,
@@ -786,7 +933,8 @@ round_rect (cairo_t *cr,
}
}
-static void
+/* returns true if an animation timeout is needed */
+static gboolean
render_element (GduVolumeGrid *grid,
cairo_t *cr,
GridElement *element,
@@ -794,6 +942,7 @@ render_element (GduVolumeGrid *grid,
gboolean is_focused,
gboolean is_grid_focused)
{
+ gboolean need_animation_timeout;
gdouble fill_red;
gdouble fill_green;
gdouble fill_blue;
@@ -831,6 +980,8 @@ render_element (GduVolumeGrid *grid,
gdouble text_selected_not_focused_green;
gdouble text_selected_not_focused_blue;
+ need_animation_timeout = FALSE;
+
fill_red = 1;
fill_green = 1;
fill_blue = 1;
@@ -1000,16 +1151,29 @@ render_element (GduVolumeGrid *grid,
ceil (element->y + element->height / 2 - 2 - te.height/2 - te.y_bearing));
cairo_show_text (cr, text);
- } else { /* render descriptive text for the presentable */
+ } else { /* render descriptive text + icons for the presentable */
gchar *s;
gchar *s1;
cairo_text_extents_t te;
cairo_text_extents_t te1;
GduDevice *d;
gdouble text_height;
+ gboolean render_padlock_closed;
+ gboolean render_padlock_open;
+ gboolean render_job_in_progress;
+ GPtrArray *pixbufs_to_render;
+ guint icon_offset;
+ guint n;
+
+ render_padlock_closed = FALSE;
+ render_padlock_open = FALSE;
+ render_job_in_progress = FALSE;
d = gdu_presentable_get_device (element->presentable);
+ if (d != NULL && gdu_device_job_in_progress (d))
+ render_job_in_progress = TRUE;
+
s = NULL;
s1 = NULL;
if (d != NULL && g_strcmp0 (gdu_device_id_get_usage (d), "filesystem") == 0) {
@@ -1039,6 +1203,11 @@ render_element (GduVolumeGrid *grid,
s1 = gdu_util_get_size_for_display (gdu_presentable_get_size (element->presentable),
FALSE,
FALSE);
+ if (g_strcmp0 (gdu_device_luks_get_holder (d), "/") == 0) {
+ render_padlock_closed = TRUE;
+ } else {
+ render_padlock_open = TRUE;
+ }
} else if (!gdu_presentable_is_allocated (element->presentable)) {
s = g_strdup (_("Free"));
s1 = gdu_util_get_size_for_display (gdu_presentable_get_size (element->presentable),
@@ -1092,42 +1261,87 @@ render_element (GduVolumeGrid *grid,
g_free (s);
g_free (s1);
+ /* OK, done with the text - now render spinner and icons */
+ icon_offset = 0;
+
+ if (render_job_in_progress) {
+ render_spinner (cr,
+ 16,
+ 12,
+ element->spinner_current,
+ ceil (element->x + element->width - 16 - icon_offset - 4),
+ ceil (element->y + element->height - 16 - 4));
+
+ icon_offset += 16 + 2; /* padding */
+
+ element->spinner_current += 1;
+
+ need_animation_timeout = TRUE;
+ }
+
+ /* icons */
+ pixbufs_to_render = g_ptr_array_new_with_free_func (g_object_unref);
+ if (render_padlock_open)
+ g_ptr_array_add (pixbufs_to_render,
+ gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+ "gdu-encrypted-unlock",
+ 16, 0, NULL));
+ if (render_padlock_closed)
+ g_ptr_array_add (pixbufs_to_render,
+ gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+ "gdu-encrypted-lock",
+ 16, 0, NULL));
+ for (n = 0; n < pixbufs_to_render->len; n++) {
+ GdkPixbuf *pixbuf = GDK_PIXBUF (pixbufs_to_render->pdata[n]);
+ guint icon_width;
+ guint icon_height;
+
+ icon_width = gdk_pixbuf_get_width (pixbuf);
+ icon_height = gdk_pixbuf_get_height (pixbuf);
+
+ render_pixbuf (cr,
+ ceil (element->x + element->width - icon_width - icon_offset - 4),
+ ceil (element->y + element->height - icon_height - 4),
+ pixbuf);
+
+ icon_offset += icon_width + 2; /* padding */
+ }
+ g_ptr_array_free (pixbufs_to_render, TRUE);
+
+
if (d != NULL)
g_object_unref (d);
}
cairo_restore (cr);
+
+ return need_animation_timeout;
}
static gboolean
-gdu_volume_grid_expose_event (GtkWidget *widget,
- GdkEventExpose *event)
+on_animation_timeout (gpointer data)
{
- GduVolumeGrid *grid = GDU_VOLUME_GRID (widget);
- GList *l;
- cairo_t *cr;
- gdouble width;
- gdouble height;
+ GduVolumeGrid *grid = GDU_VOLUME_GRID (data);
- width = widget->allocation.width;
- height = widget->allocation.height;
+ gtk_widget_queue_draw (GTK_WIDGET (grid));
- recompute_size (grid,
- width - 1,
- height -1);
+ return TRUE; /* keep timeout around */
+}
- cr = gdk_cairo_create (widget->window);
- cairo_rectangle (cr,
- event->area.x, event->area.y,
- event->area.width, event->area.height);
- cairo_clip (cr);
+static gboolean
+render_slice (GduVolumeGrid *grid,
+ cairo_t *cr,
+ GList *elements)
+{
+ GList *l;
+ gboolean need_animation_timeout;
- for (l = grid->priv->elements; l != NULL; l = l->next) {
+ need_animation_timeout = FALSE;
+ for (l = elements; l != NULL; l = l->next) {
GridElement *element = l->data;
gboolean is_selected;
gboolean is_focused;
gboolean is_grid_focused;
- GList *ll;
is_selected = FALSE;
is_focused = FALSE;
@@ -1141,39 +1355,61 @@ gdu_volume_grid_expose_event (GtkWidget *widget,
is_focused = TRUE;
}
- render_element (grid,
- cr,
- element,
- is_selected,
- is_focused,
- is_grid_focused);
+ need_animation_timeout |= render_element (grid,
+ cr,
+ element,
+ is_selected,
+ is_focused,
+ is_grid_focused);
- for (ll = element->embedded_elements; ll != NULL; ll = ll->next) {
- GridElement *element = ll->data;
+ need_animation_timeout |= render_slice (grid,
+ cr,
+ element->embedded_elements);
+ }
- is_selected = FALSE;
- is_focused = FALSE;
- is_grid_focused = GTK_WIDGET_HAS_FOCUS (grid);
+ return need_animation_timeout;
+}
- if (element == grid->priv->selected)
- is_selected = TRUE;
+static gboolean
+gdu_volume_grid_expose_event (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ GduVolumeGrid *grid = GDU_VOLUME_GRID (widget);
+ cairo_t *cr;
+ gdouble width;
+ gdouble height;
+ gboolean need_animation_timeout;
- if (element == grid->priv->focused) {
- if (grid->priv->focused != grid->priv->selected && is_grid_focused)
- is_focused = TRUE;
- }
+ width = widget->allocation.width;
+ height = widget->allocation.height;
- render_element (grid,
- cr,
- element,
- is_selected,
- is_focused,
- is_grid_focused);
- }
- }
+ recompute_size (grid,
+ width - 1,
+ height -1);
+
+ cr = gdk_cairo_create (widget->window);
+ cairo_rectangle (cr,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ cairo_clip (cr);
+
+ need_animation_timeout = render_slice (grid, cr, grid->priv->elements);
cairo_destroy (cr);
+ if (need_animation_timeout) {
+ if (grid->priv->animation_timeout_id == 0) {
+ grid->priv->animation_timeout_id = g_timeout_add (80,
+ on_animation_timeout,
+ grid);
+ }
+ } else {
+ if (grid->priv->animation_timeout_id > 0) {
+ g_source_remove (grid->priv->animation_timeout_id);
+ grid->priv->animation_timeout_id = 0;
+ }
+ }
+
return FALSE;
}
@@ -1212,8 +1448,8 @@ find_element_for_presentable (GduVolumeGrid *grid,
static GridElement *
do_find_element_for_position (GList *elements,
- gint x,
- gint y)
+ guint x,
+ guint y)
{
GList *l;
GridElement *ret;
@@ -1243,8 +1479,8 @@ do_find_element_for_position (GList *elements,
static GridElement *
find_element_for_position (GduVolumeGrid *grid,
- gint x,
- gint y)
+ guint x,
+ guint y)
{
return do_find_element_for_position (grid->priv->elements, x, y);
}
diff --git a/src/palimpsest/gdu-section-volumes.c b/src/palimpsest/gdu-section-volumes.c
index 7ef4971..9c9935c 100644
--- a/src/palimpsest/gdu-section-volumes.c
+++ b/src/palimpsest/gdu-section-volumes.c
@@ -56,6 +56,10 @@ struct _GduSectionVolumesPrivate
GduButtonElement *partition_edit_button;
GduButtonElement *partition_delete_button;
GduButtonElement *partition_create_button;
+ GduButtonElement *luks_lock_button;
+ GduButtonElement *luks_unlock_button;
+ GduButtonElement *luks_forget_passphrase_button;
+ GduButtonElement *luks_change_passphrase_button;
};
G_DEFINE_TYPE (GduSectionVolumes, gdu_section_volumes, GDU_TYPE_SECTION)
@@ -457,6 +461,383 @@ on_partition_edit_button_clicked (GduButtonElement *button_element,
/* ---------------------------------------------------------------------------------------------------- */
static void
+on_luks_forget_passphrase_button_clicked (GduButtonElement *button_element,
+ gpointer user_data)
+{
+ GduSectionVolumes *section = GDU_SECTION_VOLUMES (user_data);
+ GtkWidget *dialog;
+ GduPresentable *v;
+ GduDevice *d;
+ gint response;
+
+ v = NULL;
+
+ v = gdu_volume_grid_get_selected (GDU_VOLUME_GRID (section->priv->grid));
+ if (v == NULL)
+ goto out;
+
+ d = gdu_presentable_get_device (v);
+ if (d == NULL)
+ goto out;
+
+ dialog = gdu_confirmation_dialog_new (GTK_WINDOW (gdu_shell_get_toplevel (gdu_section_get_shell (GDU_SECTION (section)))),
+ v,
+ _("Are you sure you want to forget the passphrase?"),
+ _("_Forget"));
+ gtk_widget_show_all (dialog);
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+ if (response == GTK_RESPONSE_OK) {
+ gdu_util_delete_secret (d);
+ }
+ gtk_widget_destroy (dialog);
+
+ gdu_section_update (GDU_SECTION (section));
+
+ out:
+ if (d != NULL)
+ g_object_unref (d);
+ if (v != NULL)
+ g_object_unref (v);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+luks_lock_op_callback (GduDevice *device,
+ GError *error,
+ gpointer user_data)
+{
+ GduShell *shell = GDU_SHELL (user_data);
+
+ if (error != NULL) {
+ GtkWidget *dialog;
+ dialog = gdu_error_dialog_for_volume (GTK_WINDOW (gdu_shell_get_toplevel (shell)),
+ device,
+ _("Error locking LUKS volume"),
+ error);
+ gtk_widget_show_all (dialog);
+ gtk_window_present (GTK_WINDOW (dialog));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ g_error_free (error);
+ }
+ g_object_unref (shell);
+}
+
+static void
+on_luks_lock_button_clicked (GduButtonElement *button_element,
+ gpointer user_data)
+{
+ GduSectionVolumes *section = GDU_SECTION_VOLUMES (user_data);
+ GduPresentable *v;
+ GduDevice *d;
+
+ v = NULL;
+
+ v = gdu_volume_grid_get_selected (GDU_VOLUME_GRID (section->priv->grid));
+ if (v == NULL)
+ goto out;
+
+ d = gdu_presentable_get_device (v);
+ if (d == NULL)
+ goto out;
+
+ gdu_device_op_luks_lock (d,
+ luks_lock_op_callback,
+ g_object_ref (gdu_section_get_shell (GDU_SECTION (section))));
+
+ out:
+ if (d != NULL)
+ g_object_unref (d);
+ if (v != NULL)
+ g_object_unref (v);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void unlock_action_do (GduSectionVolumes *section,
+ GduPresentable *presentable,
+ gboolean bypass_keyring,
+ gboolean indicate_wrong_passphrase);
+
+typedef struct {
+ GduSectionVolumes *section;
+ GduPresentable *presentable;
+ gboolean asked_user;
+} UnlockData;
+
+static UnlockData *
+unlock_data_new (GduSectionVolumes *section,
+ GduPresentable *presentable,
+ gboolean asked_user)
+{
+ UnlockData *data;
+ data = g_new0 (UnlockData, 1);
+ data->section = g_object_ref (section);
+ data->presentable = g_object_ref (presentable);
+ data->asked_user = asked_user;
+ return data;
+}
+
+static void
+unlock_data_free (UnlockData *data)
+{
+ g_object_unref (data->section);
+ g_object_unref (data->presentable);
+ g_free (data);
+}
+
+static gboolean
+unlock_retry (gpointer user_data)
+{
+ UnlockData *data = user_data;
+ GduDevice *device;
+ gboolean indicate_wrong_passphrase;
+
+ device = gdu_presentable_get_device (data->presentable);
+ if (device != NULL) {
+ indicate_wrong_passphrase = FALSE;
+
+ if (!data->asked_user) {
+ /* if we attempted to unlock the device without asking the user
+ * then the password must have come from the keyring.. hence,
+ * since we failed, the password in the keyring is bad. Remove
+ * it.
+ */
+ g_warning ("removing bad password from keyring");
+ gdu_util_delete_secret (device);
+ } else {
+ /* we did ask the user on the last try and that passphrase
+ * didn't work.. make sure the new dialog tells him that
+ */
+ indicate_wrong_passphrase = TRUE;
+ }
+
+ unlock_action_do (data->section, data->presentable, TRUE, indicate_wrong_passphrase);
+ g_object_unref (device);
+ }
+ unlock_data_free (data);
+ return FALSE;
+}
+
+static void
+unlock_op_cb (GduDevice *device,
+ char *object_path_of_cleartext_device,
+ GError *error,
+ gpointer user_data)
+{
+ UnlockData *data = user_data;
+ GduShell *shell;
+
+ shell = gdu_section_get_shell (GDU_SECTION (data->section));
+
+ if (error != NULL && error->code == GDU_ERROR_INHIBITED) {
+ GtkWidget *dialog;
+
+ dialog = gdu_error_dialog_for_volume (GTK_WINDOW (gdu_shell_get_toplevel (shell)),
+ device,
+ _("Error unlocking LUKS volume"),
+ error);
+ gtk_widget_show_all (dialog);
+ gtk_window_present (GTK_WINDOW (dialog));
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ g_error_free (error);
+ } else if (error != NULL) {
+ /* retry */
+ g_idle_add (unlock_retry, data);
+ g_error_free (error);
+ } else {
+ unlock_data_free (data);
+ g_free (object_path_of_cleartext_device);
+ }
+}
+
+static void
+unlock_action_do (GduSectionVolumes *section,
+ GduPresentable *presentable,
+ gboolean bypass_keyring,
+ gboolean indicate_wrong_passphrase)
+{
+ gchar *secret;
+ gboolean asked_user;
+ GduDevice *device;
+
+ device = gdu_presentable_get_device (presentable);
+ if (device != NULL) {
+ GduShell *shell;
+
+ shell = gdu_section_get_shell (GDU_SECTION (section));
+
+ secret = gdu_util_dialog_ask_for_secret (GTK_WIDGET (gdu_shell_get_toplevel (shell)),
+ presentable,
+ bypass_keyring,
+ indicate_wrong_passphrase,
+ &asked_user);
+ if (secret != NULL) {
+ gdu_device_op_luks_unlock (device,
+ secret,
+ unlock_op_cb,
+ unlock_data_new (section,
+ presentable,
+ asked_user));
+ /* scrub the password */
+ memset (secret, '\0', strlen (secret));
+ g_free (secret);
+ }
+
+ g_object_unref (device);
+ }
+}
+
+
+static void
+on_luks_unlock_button_clicked (GduButtonElement *button_element,
+ gpointer user_data)
+{
+ GduSectionVolumes *section = GDU_SECTION_VOLUMES (user_data);
+ GduPresentable *v;
+
+ v = NULL;
+
+ v = gdu_volume_grid_get_selected (GDU_VOLUME_GRID (section->priv->grid));
+ if (v == NULL)
+ goto out;
+
+ unlock_action_do (section, v, FALSE, FALSE);
+
+ out:
+ if (v != NULL)
+ g_object_unref (v);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct {
+ char *old_secret;
+ char *new_secret;
+ gboolean save_in_keyring;
+ gboolean save_in_keyring_session;
+ GduPresentable *presentable;
+ GduSectionVolumes *section;
+} ChangePassphraseData;
+
+static void
+change_passphrase_data_free (ChangePassphraseData *data)
+{
+ /* scrub the secrets */
+ if (data->old_secret != NULL) {
+ memset (data->old_secret, '\0', strlen (data->old_secret));
+ g_free (data->old_secret);
+ }
+ if (data->new_secret != NULL) {
+ memset (data->new_secret, '\0', strlen (data->new_secret));
+ g_free (data->new_secret);
+ }
+ if (data->presentable != NULL)
+ g_object_unref (data->presentable);
+ if (data->section != NULL)
+ g_object_unref (data->section);
+ g_free (data);
+}
+
+static void change_passphrase_do (GduSectionVolumes *section,
+ GduPresentable *presentable,
+ gboolean bypass_keyring,
+ gboolean indicate_wrong_passphrase);
+
+static void
+change_passphrase_completed (GduDevice *device,
+ GError *error,
+ gpointer user_data)
+{
+ ChangePassphraseData *data = user_data;
+
+ if (error == NULL) {
+ /* It worked! Now update the keyring */
+
+ if (data->save_in_keyring || data->save_in_keyring_session)
+ gdu_util_save_secret (device, data->new_secret, data->save_in_keyring_session);
+ else
+ gdu_util_delete_secret (device);
+
+ change_passphrase_data_free (data);
+ } else {
+ /* It didn't work. Because the given passphrase was wrong. Try again,
+ * this time forcibly bypassing the keyring and telling the user
+ * the given passphrase was wrong.
+ */
+ change_passphrase_do (data->section, data->presentable, TRUE, TRUE);
+ change_passphrase_data_free (data);
+ }
+}
+
+static void
+change_passphrase_do (GduSectionVolumes *section,
+ GduPresentable *presentable,
+ gboolean bypass_keyring,
+ gboolean indicate_wrong_passphrase)
+{
+ GduDevice *device;
+ ChangePassphraseData *data;
+
+ device = gdu_presentable_get_device (presentable);
+ if (device == NULL) {
+ goto out;
+ }
+
+ data = g_new0 (ChangePassphraseData, 1);
+ data->presentable = g_object_ref (presentable);
+ data->section = g_object_ref (section);
+
+ if (!gdu_util_dialog_change_secret (gdu_shell_get_toplevel (gdu_section_get_shell (GDU_SECTION (section))),
+ presentable,
+ &data->old_secret,
+ &data->new_secret,
+ &data->save_in_keyring,
+ &data->save_in_keyring_session,
+ bypass_keyring,
+ indicate_wrong_passphrase)) {
+ change_passphrase_data_free (data);
+ goto out;
+ }
+
+ gdu_device_op_luks_change_passphrase (device,
+ data->old_secret,
+ data->new_secret,
+ change_passphrase_completed,
+ data);
+
+out:
+ if (device != NULL) {
+ g_object_unref (device);
+ }
+}
+
+static void
+on_luks_change_passphrase_button_clicked (GduButtonElement *button_element,
+ gpointer user_data)
+{
+ GduSectionVolumes *section = GDU_SECTION_VOLUMES (user_data);
+ GduPresentable *v;
+
+ v = NULL;
+
+ v = gdu_volume_grid_get_selected (GDU_VOLUME_GRID (section->priv->grid));
+ if (v == NULL)
+ goto out;
+
+ change_passphrase_do (section, v, FALSE, FALSE);
+
+ out:
+ if (v != NULL)
+ g_object_unref (v);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
gdu_section_volumes_update (GduSection *_section)
{
GduSectionVolumes *section = GDU_SECTION_VOLUMES (_section);
@@ -472,6 +853,10 @@ gdu_section_volumes_update (GduSection *_section)
gboolean show_partition_edit_button;
gboolean show_partition_delete_button;
gboolean show_partition_create_button;
+ gboolean show_luks_lock_button;
+ gboolean show_luks_unlock_button;
+ gboolean show_luks_forget_passphrase_button;
+ gboolean show_luks_change_passphrase_button;
v = NULL;
d = NULL;
@@ -483,6 +868,10 @@ gdu_section_volumes_update (GduSection *_section)
show_partition_edit_button = FALSE;
show_partition_delete_button = FALSE;
show_partition_create_button = FALSE;
+ show_luks_lock_button = FALSE;
+ show_luks_unlock_button = FALSE;
+ show_luks_forget_passphrase_button = FALSE;
+ show_luks_change_passphrase_button = FALSE;
v = gdu_volume_grid_get_selected (GDU_VOLUME_GRID (section->priv->grid));
@@ -692,6 +1081,19 @@ gdu_section_volumes_update (GduSection *_section)
show_fs_check_button = TRUE;
+ } else if (g_strcmp0 (usage, "crypto") == 0) {
+
+ if (g_strcmp0 (gdu_device_luks_get_holder (d), "/") == 0) {
+ show_luks_unlock_button = TRUE;
+ gdu_details_element_set_text (section->priv->usage_element, _("Encrypted Volume (Locked)"));
+ } else {
+ show_luks_lock_button = TRUE;
+ gdu_details_element_set_text (section->priv->usage_element, _("Encrypted Volume (Unlocked)"));
+ }
+ if (gdu_util_have_secret (d))
+ show_luks_forget_passphrase_button = TRUE;
+ show_luks_change_passphrase_button = TRUE;
+
} else if (g_strcmp0 (usage, "") == 0 &&
d != NULL && gdu_device_is_partition (d) &&
g_strcmp0 (gdu_device_partition_get_scheme (d), "mbr") == 0 &&
@@ -720,6 +1122,10 @@ gdu_section_volumes_update (GduSection *_section)
gdu_button_element_set_visible (section->priv->partition_edit_button, show_partition_edit_button);
gdu_button_element_set_visible (section->priv->partition_delete_button, show_partition_delete_button);
gdu_button_element_set_visible (section->priv->partition_create_button, show_partition_create_button);
+ gdu_button_element_set_visible (section->priv->luks_lock_button, show_luks_lock_button);
+ gdu_button_element_set_visible (section->priv->luks_unlock_button, show_luks_unlock_button);
+ gdu_button_element_set_visible (section->priv->luks_forget_passphrase_button, show_luks_forget_passphrase_button);
+ gdu_button_element_set_visible (section->priv->luks_change_passphrase_button, show_luks_change_passphrase_button);
out:
if (d != NULL)
@@ -873,6 +1279,47 @@ gdu_section_volumes_constructed (GObject *object)
g_ptr_array_add (button_elements, button_element);
section->priv->partition_create_button = button_element;
+ button_element = gdu_button_element_new ("gdu-encrypted-lock",
+ _("_Lock Volume"),
+ _("Make encrypted data unavailable"));
+ g_signal_connect (button_element,
+ "clicked",
+ G_CALLBACK (on_luks_lock_button_clicked),
+ section);
+ g_ptr_array_add (button_elements, button_element);
+ section->priv->luks_lock_button = button_element;
+
+ button_element = gdu_button_element_new ("gdu-encrypted-unlock",
+ _("_Unlock Volume"),
+ _("Make encrypted data available"));
+ g_signal_connect (button_element,
+ "clicked",
+ G_CALLBACK (on_luks_unlock_button_clicked),
+ section);
+ g_ptr_array_add (button_elements, button_element);
+ section->priv->luks_unlock_button = button_element;
+
+ button_element = gdu_button_element_new (GTK_STOCK_CLEAR,
+ _("Forge_t Passphrase"),
+ _("Delete passphrase from keyring"));
+ g_signal_connect (button_element,
+ "clicked",
+ G_CALLBACK (on_luks_forget_passphrase_button_clicked),
+ section);
+ g_ptr_array_add (button_elements, button_element);
+ section->priv->luks_forget_passphrase_button = button_element;
+
+ /* TODO: not a great choice for the icon but _EDIT would conflict with "Edit Partition */
+ button_element = gdu_button_element_new (GTK_STOCK_FIND_AND_REPLACE,
+ _("Change _Passphrase"),
+ _("Change passphrase"));
+ g_signal_connect (button_element,
+ "clicked",
+ G_CALLBACK (on_luks_change_passphrase_button_clicked),
+ section);
+ g_ptr_array_add (button_elements, button_element);
+ section->priv->luks_change_passphrase_button = button_element;
+
gdu_button_table_set_elements (GDU_BUTTON_TABLE (section->priv->button_table), button_elements);
g_ptr_array_unref (button_elements);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]