From 6310b35bac3bbe5db903e2bb962219fdca7fe992 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Mon, 22 Aug 2011 11:05:34 +0200 Subject: [PATCH] gcr: Fix up GcrDisplayView bugs and look * Separators between items. * Clicking details doesn't remove items when more than one is displayed. * Better spacing. --- gcr/gcr-certificate-renderer.c | 7 +- gcr/gcr-display-view.c | 193 +++++++++++++++++++++++++++++++++-------- gcr/gcr-display-view.h | 5 +- gcr/gcr-key-renderer.c | 9 +- 4 files changed, 172 insertions(+), 42 deletions(-) diff --git a/gcr/gcr-certificate-renderer.c b/gcr/gcr-certificate-renderer.c index 558f5ce..5f53cb6 100644 --- a/gcr/gcr-certificate-renderer.c +++ b/gcr/gcr-certificate-renderer.c @@ -589,12 +589,14 @@ gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer) return; } - _gcr_display_view_clear (view, renderer); + _gcr_display_view_begin (view, renderer); cert = GCR_CERTIFICATE (self); data = gcr_certificate_get_der_data (cert, &n_data); - if (!data) + if (!data) { + _gcr_display_view_end (view, renderer); return; + } icon = gcr_certificate_get_icon (cert); _gcr_display_view_set_icon (view, GCR_RENDERER (self), icon); @@ -724,6 +726,7 @@ gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer) } egg_asn1x_destroy (asn); + _gcr_display_view_end (view, renderer); } static void diff --git a/gcr/gcr-display-view.c b/gcr/gcr-display-view.c index 8dd702a..b6cec63 100644 --- a/gcr/gcr-display-view.c +++ b/gcr/gcr-display-view.c @@ -64,6 +64,8 @@ struct _GcrDisplayViewPrivate { GtkTextTag *heading_tag; GtkTextTag *monospace_tag; GcrDisplayItem *current_item; + gint text_height; + GdkCursor *cursor; gboolean have_measurements; gint minimal_width; @@ -135,6 +137,23 @@ ensure_measurements (GcrDisplayView *self) } static void +ensure_text_height (GcrDisplayView *self) +{ + PangoRectangle extents; + PangoLayout *layout; + + if (self->pv->text_height > 0) + return; + + layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), "Wp"); + pango_layout_get_extents (layout, NULL, &extents); + pango_extents_to_pixels (&extents, NULL); + g_object_unref (layout); + + self->pv->text_height = extents.height; +} + +static void recalculate_and_resize (GcrDisplayView *self) { self->pv->have_measurements = FALSE; @@ -158,7 +177,6 @@ create_tag_table (GcrDisplayView *self) "name", "title", "scale", PANGO_SCALE_LARGE, "right-margin", (ICON_MARGIN * 2) + width, - "pixels-above-lines", 9, "pixels-below-lines", 6, "weight", PANGO_WEIGHT_BOLD, NULL); @@ -221,7 +239,10 @@ style_display_item (GtkWidget *widget, GcrDisplayItem *item) gtk_style_context_restore (style); - gtk_widget_override_background_color (item->details_widget, GTK_STATE_NORMAL, &color); + color.red = 255; + color.green = 0; + color.blue = 0; + gtk_widget_override_background_color (item->details_widget, GTK_STATE_FLAG_NORMAL, &color); } static GcrDisplayItem* @@ -255,13 +276,20 @@ create_display_item (GcrDisplayView *self, GcrRenderer *renderer) item->details_tag = g_object_new (GTK_TYPE_TEXT_TAG, NULL); gtk_text_tag_table_add (tags, item->details_tag); - /* The mark that determines the beginning of this item, with left gravity. */ + /* + * Add two zero width spaces that delimit this from later items. The + * item will live between the two zero width spaces. + */ gtk_text_buffer_get_end_iter (self->pv->buffer, &iter); + gtk_text_buffer_insert (self->pv->buffer, &iter, "\n\n", -1); + if (!gtk_text_iter_backward_char (&iter)) + g_assert_not_reached (); + + /* The mark that determines the beginning of this item, with left gravity. */ item->beginning = gtk_text_buffer_create_mark (self->pv->buffer, NULL, &iter, TRUE); g_object_ref (item->beginning); /* The mark that determines the end of this item, with right gravity. */ - gtk_text_buffer_get_end_iter (self->pv->buffer, &iter); item->ending = gtk_text_buffer_create_mark (self->pv->buffer, NULL, &iter, FALSE); g_object_ref (item->ending); @@ -280,6 +308,7 @@ create_display_item (GcrDisplayView *self, GcrRenderer *renderer) gtk_widget_show_all (alignment); item->details_widget = gtk_event_box_new (); + gtk_event_box_set_visible_window (GTK_EVENT_BOX (item->details_widget), FALSE); gtk_container_add (GTK_CONTAINER (item->details_widget), alignment); g_signal_connect (item->details_widget, "realize", G_CALLBACK (on_expander_realize), NULL); g_object_ref (item->details_widget); @@ -370,45 +399,103 @@ on_renderer_data_changed (GcrRenderer *renderer, GcrViewer *self) } static void -paint_widget_icons (GcrDisplayView *self, cairo_t *cr) +paint_item_icon (GcrDisplayView *self, + GcrDisplayItem *item, + GdkRectangle *visible, + cairo_t *cr) { - GHashTableIter hit; - GtkTextView *view; - GdkRectangle visible; - GdkRectangle location; - GcrDisplayItem *item; - gpointer value; GtkTextIter iter; + GdkRectangle location; + GtkTextView *view; + + if (item->pixbuf == NULL) + return; view = GTK_TEXT_VIEW (self); - gtk_text_view_get_visible_rect (view, &visible); + gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->beginning); + gtk_text_view_get_iter_location (view, &iter, &location); - g_hash_table_iter_init (&hit, self->pv->items); - while (g_hash_table_iter_next (&hit, NULL, &value)) { + location.height = gdk_pixbuf_get_height (item->pixbuf); + location.width = gdk_pixbuf_get_width (item->pixbuf); + location.x = visible->width - location.width - ICON_MARGIN; - item = value; - if (item->pixbuf == NULL) - continue; + if (!gdk_rectangle_intersect (visible, &location, NULL)) + return; - gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->beginning); - gtk_text_view_get_iter_location (view, &iter, &location); + gtk_text_view_buffer_to_window_coords (view, GTK_TEXT_WINDOW_TEXT, + location.x, location.y, + &location.x, &location.y); - location.height = gdk_pixbuf_get_height (item->pixbuf); - location.width = gdk_pixbuf_get_width (item->pixbuf); - location.x = visible.width - location.width - ICON_MARGIN; + cairo_save (cr); + gdk_cairo_set_source_pixbuf (cr, item->pixbuf, location.x, location.y); + cairo_rectangle (cr, location.x, location.y, location.width, location.height); + cairo_fill (cr); + cairo_restore (cr); +} - if (!gdk_rectangle_intersect (&visible, &location, NULL)) - continue; +static void +paint_item_border (GcrDisplayView *self, + GcrDisplayItem *item, + GtkStyleContext *context, + GdkRectangle *visible, + gint index, + cairo_t *cr) +{ + GdkRGBA color; + GtkTextView *view; + GtkTextIter iter; + GdkRectangle location; - gtk_text_view_buffer_to_window_coords (view, GTK_TEXT_WINDOW_TEXT, - location.x, location.y, - &location.x, &location.y); + if (index == 0) + return; - cairo_save (cr); - gdk_cairo_set_source_pixbuf (cr, item->pixbuf, location.x, location.y); - cairo_rectangle (cr, location.x, location.y, location.width, location.height); - cairo_fill (cr); - cairo_restore (cr); + ensure_text_height (self); + + gtk_style_context_get_background_color (context, + GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED, + &color); + + view = GTK_TEXT_VIEW (self); + gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->beginning); + gtk_text_view_get_iter_location (view, &iter, &location); + + location.height = 2; + location.width = visible->width - (NORMAL_MARGIN * 2); + location.x = NORMAL_MARGIN; + location.y -= self->pv->text_height / 2; + + if (!gdk_rectangle_intersect (visible, &location, NULL)) + return; + + gtk_text_view_buffer_to_window_coords (view, GTK_TEXT_WINDOW_TEXT, + location.x, location.y, + &location.x, &location.y); + + cairo_save (cr); + cairo_set_source_rgb (cr, color.red, color.green, color.blue); + cairo_set_line_width (cr, 0.5); + cairo_move_to (cr, location.x, location.y); + cairo_line_to (cr, location.x + location.width, location.y); + cairo_stroke (cr); + cairo_restore (cr); +} + +static void +paint_extras (GcrDisplayView *self, cairo_t *cr) +{ + GdkRectangle visible; + GcrDisplayItem *item; + GtkStyleContext *context; + guint i; + + gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (self), &visible); + context = gtk_widget_get_style_context (GTK_WIDGET (self)); + + for (i = 0; i < self->pv->renderers->len; i++) { + item = g_hash_table_lookup (self->pv->items, self->pv->renderers->pdata[i]); + g_assert (item != NULL); + paint_item_icon (self, item, &visible, cr); + paint_item_border (self, item, context, &visible, i, cr); } } @@ -510,6 +597,8 @@ _gcr_display_view_finalize (GObject *obj) g_object_unref (self->pv->title_tag); self->pv->title_tag = NULL; + g_clear_object (&self->pv->cursor); + G_OBJECT_CLASS (_gcr_display_view_parent_class)->finalize (obj); } @@ -518,6 +607,7 @@ _gcr_display_view_realize (GtkWidget *widget) { GcrDisplayView *self = GCR_DISPLAY_VIEW (widget); GHashTableIter iter; + GdkDisplay *display; gpointer value; if (GTK_WIDGET_CLASS (_gcr_display_view_parent_class)->realize) @@ -527,6 +617,14 @@ _gcr_display_view_realize (GtkWidget *widget) g_hash_table_iter_init (&iter, self->pv->items); while (g_hash_table_iter_next (&iter, NULL, &value)) style_display_item (widget, value); + + if (!self->pv->cursor) { + display = gtk_widget_get_display (GTK_WIDGET (self)); + self->pv->cursor = gdk_cursor_new_for_display (display, GDK_ARROW); + } + + gdk_window_set_cursor (gtk_text_view_get_window (GTK_TEXT_VIEW (self), GTK_TEXT_WINDOW_WIDGET), + self->pv->cursor); } static gboolean @@ -567,7 +665,7 @@ _gcr_display_view_draw (GtkWidget *widget, cairo_t *cr) window = gtk_text_view_get_window (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_TEXT); if (gtk_cairo_should_draw_window (cr, window)) - paint_widget_icons (GCR_DISPLAY_VIEW (widget), cr); + paint_extras (GCR_DISPLAY_VIEW (widget), cr); return handled; } @@ -700,7 +798,8 @@ _gcr_display_view_new (void) } void -_gcr_display_view_clear (GcrDisplayView *self, GcrRenderer *renderer) +_gcr_display_view_begin (GcrDisplayView *self, + GcrRenderer *renderer) { GtkTextIter start, iter; GcrDisplayItem *item; @@ -715,15 +814,32 @@ _gcr_display_view_clear (GcrDisplayView *self, GcrRenderer *renderer) gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->ending); gtk_text_buffer_delete (self->pv->buffer, &start, &iter); - g_return_if_fail (!gtk_text_mark_get_deleted (item->beginning)); - g_return_if_fail (!gtk_text_mark_get_deleted (item->ending)); - item->extra_tag = NULL; item->field_width = 0; item->details = FALSE; } void +_gcr_display_view_end (GcrDisplayView *self, + GcrRenderer *renderer) +{ + GtkTextIter start, iter; + GcrDisplayItem *item; + + g_return_if_fail (GCR_IS_DISPLAY_VIEW (self)); + item = lookup_display_item (self, renderer); + g_return_if_fail (item); + + gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &start, item->beginning); + gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->ending); + +#if 0 + if (gtk_text_iter_compare (&start, &iter) != 0) + gtk_text_buffer_insert (self->pv->buffer, &iter, "\n", 1); +#endif +} + +void _gcr_display_view_start_details (GcrDisplayView *self, GcrRenderer *renderer) { GtkTextChildAnchor *anchor; @@ -809,6 +925,9 @@ _gcr_display_view_append_value (GcrDisplayView *self, GcrRenderer *renderer, con pango_extents_to_pixels (&extents, NULL); g_object_unref (layout); + /* An estimate of the text height */ + self->pv->text_height = extents.height; + /* Make the tab wide enough to accomodate */ if (extents.width > item->field_width) { item->field_width = extents.width + COLUMN_MARGIN; diff --git a/gcr/gcr-display-view.h b/gcr/gcr-display-view.h index 5f0f2ee..f697e59 100644 --- a/gcr/gcr-display-view.h +++ b/gcr/gcr-display-view.h @@ -55,7 +55,10 @@ GType _gcr_display_view_get_type (void); GcrDisplayView* _gcr_display_view_new (void); -void _gcr_display_view_clear (GcrDisplayView *self, +void _gcr_display_view_begin (GcrDisplayView *self, + GcrRenderer *renderer); + +void _gcr_display_view_end (GcrDisplayView *self, GcrRenderer *renderer); void _gcr_display_view_append_value (GcrDisplayView *self, diff --git a/gcr/gcr-key-renderer.c b/gcr/gcr-key-renderer.c index 1b7677d..242d842 100644 --- a/gcr/gcr-key-renderer.c +++ b/gcr/gcr-key-renderer.c @@ -258,14 +258,17 @@ gcr_key_renderer_real_render (GcrRenderer *renderer, GcrViewer *viewer) return; } - _gcr_display_view_clear (view, renderer); + _gcr_display_view_begin (view, renderer); - if (!self->pv->attributes) + if (!self->pv->attributes) { + _gcr_display_view_end (view, renderer); return; + } if (!gck_attributes_find_ulong (self->pv->attributes, CKA_CLASS, &klass) || !gck_attributes_find_ulong (self->pv->attributes, CKA_KEY_TYPE, &key_type)) { g_warning ("private key does not have the CKA_CLASS and CKA_KEY_TYPE attributes"); + _gcr_display_view_end (view, renderer); return; } @@ -334,6 +337,8 @@ gcr_key_renderer_real_render (GcrRenderer *renderer, GcrViewer *viewer) _gcr_display_view_append_hex (view, renderer, _("SHA256"), fingerprint, n_fingerprint); g_free (fingerprint); } + + _gcr_display_view_end (view, renderer); } static void -- 2.7.4