[gnome-software] Break out the update dialog as a separate object



commit 99fb74b1c04a467865a98ca75c546f9039b3af55
Author: Kalev Lember <kalevlember gmail com>
Date:   Sat Mar 1 22:29:22 2014 +0100

    Break out the update dialog as a separate object
    
    At the same time, move to a separate GtkBuilder template.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=725579

 po/POTFILES.in                   |    2 +
 src/Makefile.am                  |    3 +
 src/gnome-software.gresource.xml |    1 +
 src/gnome-software.ui            |  209 ---------------------------
 src/gs-shell-updates.c           |  244 ++------------------------------
 src/gs-update-dialog.c           |  288 ++++++++++++++++++++++++++++++++++++++
 src/gs-update-dialog.h           |   59 ++++++++
 src/gs-update-dialog.ui          |  212 ++++++++++++++++++++++++++++
 8 files changed, 576 insertions(+), 442 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 3b67194..9c5e3d8 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -24,6 +24,8 @@ src/gs-shell-installed.c
 src/gs-shell-overview.c
 src/gs-shell-search.c
 src/gs-shell-updates.c
+src/gs-update-dialog.c
+[type: gettext/glade]src/gs-update-dialog.ui
 src/gs-update-monitor.c
 [type: gettext/glade]src/gs-star-widget.ui
 src/gs-utils.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 4dda90c..258d59d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -34,6 +34,7 @@ UI_FILES =                                            \
        gnome-software.ui                               \
        gs-history-dialog.ui                    \
        gs-star-widget.ui                               \
+       gs-update-dialog.ui                             \
        screenshot-image.ui                             \
        popular-tile.ui
 
@@ -130,6 +131,8 @@ gnome_software_SOURCES =                            \
        gs-shell-updates.h                              \
        gs-shell-search.c                               \
        gs-shell-search.h                               \
+       gs-update-dialog.c                              \
+       gs-update-dialog.h                              \
        gs-update-monitor.c                             \
        gs-update-monitor.h                             \
        gs-proxy-settings.c                             \
diff --git a/src/gnome-software.gresource.xml b/src/gnome-software.gresource.xml
index 23dd7a2..06f8f97 100644
--- a/src/gnome-software.gresource.xml
+++ b/src/gnome-software.gresource.xml
@@ -12,6 +12,7 @@
   <file preprocess="xml-stripblanks">screenshot-image.ui</file>
   <file preprocess="xml-stripblanks">gs-history-dialog.ui</file>
   <file preprocess="xml-stripblanks">gs-star-widget.ui</file>
+  <file preprocess="xml-stripblanks">gs-update-dialog.ui</file>
   <file preprocess="xml-stripblanks">org.freedesktop.PackageKit.xml</file>
   <file>gtk-style.css</file>
   <file>gtk-style-hc.css</file>
diff --git a/src/gnome-software.ui b/src/gnome-software.ui
index 419bb01..1d58367 100644
--- a/src/gnome-software.ui
+++ b/src/gnome-software.ui
@@ -2037,215 +2037,6 @@
       </object>
     </child>
   </object>
-  <object class="GtkDialog" id="dialog_update">
-    <property name="can_focus">False</property>
-    <property name="modal">True</property>
-    <property name="use-header-bar">1</property>
-    <property name="default_width">600</property>
-    <property name="default_height">600</property>
-    <property name="destroy_with_parent">True</property>
-    <property name="type_hint">dialog</property>
-    <property name="transient_for">window_software</property>
-    <child internal-child="headerbar">
-      <object class="GtkHeaderBar">
-        <child>
-          <object class="GtkButton" id="button_update_back">
-            <property name="visible">True</property>
-            <property name="can_focus">True</property>
-            <property name="receives_default">True</property>
-            <child internal-child="accessible">
-              <object class="AtkObject" id="button_update_back_accessible">
-                <property name="accessible-name" translatable="yes">Go back</property>
-              </object>
-            </child>
-            <style>
-              <class name="image-button"/>
-            </style>
-            <child>
-              <object class="GtkImage" id="image_update_back">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="icon_name">go-previous-symbolic</property>
-                <property name="icon_size">1</property>
-              </object>
-            </child>
-          </object>
-          <packing>
-            <property name="pack-type">start</property>
-          </packing>
-        </child>
-      </object>
-    </child>
-    <child internal-child="vbox">
-      <object class="GtkBox" id="dialog-vbox1">
-        <property name="can_focus">False</property>
-        <property name="margin_start">6</property>
-        <property name="margin_end">6</property>
-        <property name="margin_top">6</property>
-        <property name="margin_bottom">6</property>
-        <property name="orientation">vertical</property>
-        <property name="spacing">2</property>
-        <child>
-          <object class="GtkBox" id="box7">
-            <property name="visible">True</property>
-            <property name="can_focus">False</property>
-            <property name="margin_bottom">3</property>
-            <property name="border_width">3</property>
-            <property name="orientation">vertical</property>
-            <property name="spacing">9</property>
-            <child>
-              <object class="GtkBox" id="box_update_header">
-                <property name="visible">True</property>
-                <property name="can_focus">False</property>
-                <property name="spacing">9</property>
-                <child>
-                  <object class="GtkImage" id="image_update_icon">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="pixel_size">96</property>
-                    <property name="icon_name">accessories-calculator</property>
-                    <property name="icon_size">0</property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-                <child>
-                  <object class="GtkBox" id="box9">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="orientation">vertical</property>
-                    <property name="spacing">3</property>
-                    <child>
-                      <object class="GtkLabel" id="label_update_name">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="label">Inkscape</property>
-                        <property name="angle">0.41999998688697815</property>
-                        <attributes>
-                          <attribute name="weight" value="bold"/>
-                          <attribute name="scale" value="1.3999999999999999"/>
-                        </attributes>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel" id="label_update_summary">
-                        <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="xalign">0</property>
-                        <property name="label">Vector based drawing program</property>
-                        <property name="selectable">True</property>
-                      </object>
-                      <packing>
-                        <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">1</property>
-                      </packing>
-                    </child>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">1</property>
-                  </packing>
-                </child>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkScrolledWindow" id="scrolledwindow_update_details">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="vexpand">True</property>
-                <property name="hscrollbar_policy">never</property>
-                <property name="vscrollbar_policy">automatic</property>
-                <property name="shadow_type">none</property>
-                <property name="kinetic_scrolling">False</property>
-                <child>
-                  <object class="GtkLabel" id="label_update_details">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="xalign">0</property>
-                    <property name="yalign">0</property>
-                    <property name="margin">6</property>
-                    <property name="label">New in kmod 14-1
-* Moo
-* bar</property>
-                    <property name="wrap">True</property>
-                    <property name="selectable">True</property>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">True</property>
-                <property name="position">1</property>
-              </packing>
-            </child>
-            <child>
-              <object class="GtkScrolledWindow" id="scrolledwindow_update">
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="vexpand">True</property>
-                <property name="hscrollbar_policy">never</property>
-                <property name="vscrollbar_policy">automatic</property>
-                <property name="shadow_type">none</property>
-                <property name="kinetic_scrolling">False</property>
-                <child>
-                  <object class="GtkFrame" id="box_update_frame">
-                    <property name="visible">True</property>
-                    <property name="shadow_type">in</property>
-                    <property name="halign">fill</property>
-                    <property name="valign">start</property>
-                    <style>
-                      <class name="view"/>
-                    </style>
-                    <child>
-                      <object class="GtkListBox" id="list_box_update">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="selection_mode">none</property>
-                      </object>
-                    </child>
-                  </object>
-                </child>
-              </object>
-              <packing>
-                <property name="expand">True</property>
-                <property name="fill">True</property>
-                <property name="position">2</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">1</property>
-          </packing>
-        </child>
-      </object>
-    </child>
-  </object>
-  <object class="GtkSizeGroup" id="sizegroup_update_details">
-    <property name="ignore-hidden">False</property>
-    <property name="mode">horizontal</property>
-    <widgets>
-      <widget name="scrolledwindow_update"/>
-      <widget name="scrolledwindow_update_details"/>
-    </widgets>
-  </object>
   <object class="GtkSizeGroup" id="sizegroup_details_buttons">
     <widgets>
       <widget name="button_details_website"/>
diff --git a/src/gs-shell-updates.c b/src/gs-shell-updates.c
index a10447d..2c596ae 100644
--- a/src/gs-shell-updates.c
+++ b/src/gs-shell-updates.c
@@ -30,6 +30,7 @@
 #include "gs-app.h"
 #include "gs-app-widget.h"
 #include "gs-markdown.h"
+#include "gs-update-dialog.h"
 
 /* this isn't ideal, as PK should be abstracted away in a plugin, but
  * GNetworkMonitor doesn't provide us with a connection type */
@@ -59,7 +60,7 @@ struct GsShellUpdatesPrivate
        GtkListBox              *list_box_updates;
        gboolean                 cache_valid;
        GsShell                 *shell;
-       GsApp                   *app;
+       GtkWidget               *update_dialog;
        PkControl               *control;
        GsShellUpdatesState      state;
        gboolean                 has_agreed_to_mobile_data;
@@ -428,150 +429,18 @@ gs_shell_updates_refresh (GsShellUpdates *shell_updates,
                                            shell_updates);
 }
 
-/**
- * gs_shell_updates_set_updates_description_ui:
- **/
-static void
-gs_shell_updates_set_updates_description_ui (GsShellUpdates *shell_updates, GsApp *app)
-{
-       GsShellUpdatesPrivate *priv = shell_updates->priv;
-       GsAppKind kind;
-       GsMarkdown *markdown;
-       GtkWidget *widget;
-       gchar *tmp;
-       gchar *update_desc;
-
-       /* set window title */
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "dialog_update"));
-       kind = gs_app_get_kind (app);
-       if (kind == GS_APP_KIND_OS_UPDATE) {
-               gtk_window_set_title (GTK_WINDOW (widget), gs_app_get_name (app));
-       } else {
-               tmp = g_strdup_printf ("%s %s",
-                                      gs_app_get_source_default (app),
-                                      gs_app_get_update_version_ui (app));
-               gtk_window_set_title (GTK_WINDOW (widget), tmp);
-               g_free (tmp);
-       }
-
-       /* get the update description */
-       if (gs_app_get_update_details (app) == NULL) {
-               /* TRANSLATORS: this is where the packager did not write a
-                * description for the update */
-               update_desc = g_strdup ("No update description");
-       } else {
-               markdown = gs_markdown_new (GS_MARKDOWN_OUTPUT_PANGO);
-               gs_markdown_set_smart_quoting (markdown, FALSE);
-               gs_markdown_set_autocode (markdown, TRUE);
-               update_desc = gs_markdown_parse (markdown, gs_app_get_update_details (app));
-               g_object_unref (markdown);
-       }
-
-       /* set update header */
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "box_update_header"));
-       gtk_widget_set_visible (widget, kind == GS_APP_KIND_NORMAL || kind == GS_APP_KIND_SYSTEM);
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "scrolledwindow_update_details"));
-       gtk_widget_set_visible (widget, kind != GS_APP_KIND_OS_UPDATE);
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "scrolledwindow_update"));
-       gtk_widget_set_visible (widget, kind == GS_APP_KIND_OS_UPDATE);
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "label_update_details"));
-       gtk_label_set_markup (GTK_LABEL (widget), update_desc);
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "image_update_icon"));
-       gtk_image_set_from_pixbuf (GTK_IMAGE (widget), gs_app_get_pixbuf (app));
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "label_update_name"));
-       gtk_label_set_label (GTK_LABEL (widget), gs_app_get_name (app));
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "label_update_summary"));
-       gtk_label_set_label (GTK_LABEL (widget), gs_app_get_summary (app));
-       g_free (update_desc);
-}
-
 static void
-gs_shell_updates_row_activated_cb (GtkListBox *list_box,
-                                  GtkListBoxRow *row,
-                                  GsShellUpdates *shell_updates)
+show_update_details (GsApp *app, GsShellUpdates *shell_updates)
 {
        GsShellUpdatesPrivate *priv = shell_updates->priv;
-       GsApp *app = NULL;
-       GtkWidget *widget;
+       GtkWidget *toplevel;
 
-       app = GS_APP (g_object_get_data (G_OBJECT (gtk_bin_get_child (GTK_BIN (row))), "app"));
-       /* setup package view */
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "scrolledwindow_update"));
-       gtk_widget_hide (widget);
-       gs_shell_updates_set_updates_description_ui (shell_updates, app);
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_update_back"));
-       gtk_widget_show (widget);
-}
+       gs_update_dialog_set_app (GS_UPDATE_DIALOG (priv->update_dialog), app);
 
-static void
-show_update_details (GsApp *app, GsShellUpdates *shell_updates)
-{
-       GsShellUpdatesPrivate *priv = shell_updates->priv;
-       GsApp *app_related;
-       GsAppKind kind;
-       GtkWidget *widget;
-       const gchar *sort;
-
-       kind = gs_app_get_kind (app);
-
-       /* set update header */
-       gs_shell_updates_set_updates_description_ui (shell_updates, app);
-
-       /* only OS updates can go back, and only on selection */
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_update_back"));
-       gtk_widget_hide (widget);
-
-       /* set update description */
-       if (kind == GS_APP_KIND_OS_UPDATE) {
-               GPtrArray *related;
-               GtkListBox *list_box;
-               guint i;
-               GtkWidget *row, *label;
-
-               list_box = GTK_LIST_BOX (gtk_builder_get_object (priv->builder, "list_box_update"));
-               gs_container_remove_all (GTK_CONTAINER (list_box));
-               related = gs_app_get_related (app);
-               for (i = 0; i < related->len; i++) {
-                       app_related = g_ptr_array_index (related, i);
-                       row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
-                       g_object_set_data_full (G_OBJECT (row),
-                                               "app",
-                                               g_object_ref (app_related),
-                                               g_object_unref);
-                       sort = gs_app_get_source_default (app_related);
-                       g_object_set_data_full (G_OBJECT (row),
-                                               "sort",
-                                               g_strdup (sort),
-                                               g_free);
-                       label = gtk_label_new (gs_app_get_source_default (app_related));
-                       g_object_set (label,
-                                     "margin-left", 20,
-                                     "margin-right", 20,
-                                     "margin-top", 6,
-                                     "margin-bottom", 6,
-                                     "xalign", 0.0,
-                                     NULL);
-                       gtk_widget_set_halign (label, GTK_ALIGN_START);
-                       gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
-                       gtk_box_pack_start (GTK_BOX (row), label, TRUE, TRUE, 0);
-                       label = gtk_label_new (gs_app_get_update_version_ui (app_related));
-                       g_object_set (label,
-                                     "margin-left", 20,
-                                     "margin-right", 20,
-                                     "margin-top", 6,
-                                     "margin-bottom", 6,
-                                     "xalign", 1.0,
-                                     NULL);
-                       gtk_widget_set_halign (label, GTK_ALIGN_END);
-                       gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
-                       gtk_box_pack_start (GTK_BOX (row), label, FALSE, FALSE, 0);
-                       gtk_widget_show_all (row);
-                       gtk_list_box_insert (list_box,row, -1);
-               }
-       }
+       toplevel = GTK_WIDGET (gtk_builder_get_object (priv->builder, "window_software"));
+       gtk_window_set_transient_for (GTK_WINDOW (priv->update_dialog), GTK_WINDOW (toplevel));
 
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "dialog_update"));
-       gtk_window_present (GTK_WINDOW (widget));
+       gtk_window_present (GTK_WINDOW (priv->update_dialog));
 }
 
 /**
@@ -582,17 +451,13 @@ gs_shell_updates_activated_cb (GtkListBox *list_box,
                               GtkListBoxRow *row,
                               GsShellUpdates *shell_updates)
 {
-       GsShellUpdatesPrivate *priv = shell_updates->priv;
        GsAppWidget *app_widget;
        GsApp *app;
 
        app_widget = GS_APP_WIDGET (gtk_bin_get_child (GTK_BIN (row)));
        app = gs_app_widget_get_app (app_widget);
 
-       g_clear_object (&priv->app);
-       priv->app = g_object_ref (app);
-
-       show_update_details (priv->app, shell_updates);
+       show_update_details (app, shell_updates);
 }
 
 /**
@@ -869,28 +734,6 @@ gs_shell_updates_button_refresh_cb (GtkWidget *widget,
 }
 
 /**
- * gs_shell_updates_button_back_cb:
- **/
-static void
-gs_shell_updates_button_back_cb (GtkWidget *widget, GsShellUpdates *shell_updates)
-{
-       GsShellUpdatesPrivate *priv = shell_updates->priv;
-
-       /* return to the list view */
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_update_back"));
-       gtk_widget_hide (widget);
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "box_update_header"));
-       gtk_widget_hide (widget);
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "scrolledwindow_update_details"));
-       gtk_widget_hide (widget);
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "scrolledwindow_update"));
-       gtk_widget_show (widget);
-
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "dialog_update"));
-       gtk_window_set_title (GTK_WINDOW (widget), gs_app_get_name (priv->app));
-}
-
-/**
  * gs_shell_updates_changed_cb:
  */
 static void
@@ -919,31 +762,6 @@ gs_shell_updates_button_update_all_cb (GtkButton      *button,
        gs_reboot (gs_offline_updates_cancel);
 }
 
-static void
-scrollbar_mapped_cb (GtkWidget *sb, GtkScrolledWindow *swin)
-{
-        GtkWidget *frame;
-
-        frame = gtk_bin_get_child (GTK_BIN (gtk_bin_get_child (GTK_BIN (swin))));
-
-       if (gtk_widget_get_mapped (GTK_WIDGET (sb))) {
-               gtk_scrolled_window_set_shadow_type (swin, GTK_SHADOW_IN);
-               if (GTK_IS_FRAME (frame))
-                       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
-       } else {
-               if (GTK_IS_FRAME (frame))
-                       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
-               gtk_scrolled_window_set_shadow_type (swin, GTK_SHADOW_NONE);
-       }
-}
-
-static void
-dialog_update_hide_cb (GtkWidget *dialog, GsShellUpdates *shell_updates)
-{
-       g_clear_object (&shell_updates->priv->app);
-}
-
-
 /**
  * gs_shell_installed_sort_func:
  **/
@@ -1009,21 +827,6 @@ gs_shell_updates_sort_func (GtkListBoxRow *a,
 }
 
 /**
- * gs_shell_updates_os_updates_sort_func:
- **/
-static gint
-gs_shell_updates_os_updates_sort_func (GtkListBoxRow *a,
-                                      GtkListBoxRow *b,
-                                      gpointer user_data)
-{
-       GObject *o1 = G_OBJECT (gtk_bin_get_child (GTK_BIN (a)));
-       GObject *o2 = G_OBJECT (gtk_bin_get_child (GTK_BIN (b)));
-       const gchar *key1 = g_object_get_data (o1, "sort");
-       const gchar *key2 = g_object_get_data (o2, "sort");
-       return g_strcmp0 (key1, key2);
-}
-
-/**
  * gs_shell_updates_get_properties_cb:
  **/
 static void
@@ -1054,7 +857,6 @@ gs_shell_updates_setup (GsShellUpdates *shell_updates,
 {
        GsShellUpdatesPrivate *priv = shell_updates->priv;
        GtkWidget *widget;
-       GtkWidget *sw;
 
        g_return_if_fail (GS_IS_SHELL_UPDATES (shell_updates));
 
@@ -1082,13 +884,6 @@ gs_shell_updates_setup (GsShellUpdates *shell_updates,
                                    gs_shell_updates_sort_func,
                                    shell_updates, NULL);
 
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "list_box_update"));
-       g_signal_connect (GTK_LIST_BOX (widget), "row-activated",
-                         G_CALLBACK (gs_shell_updates_row_activated_cb), shell_updates);
-       gtk_list_box_set_sort_func (GTK_LIST_BOX (widget),
-                                   gs_shell_updates_os_updates_sort_func,
-                                   shell_updates, NULL);
-
        widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_update_all"));
        g_signal_connect (widget, "clicked", G_CALLBACK (gs_shell_updates_button_update_all_cb), 
shell_updates);
 
@@ -1105,25 +900,9 @@ gs_shell_updates_setup (GsShellUpdates *shell_updates,
        g_signal_connect (widget, "clicked",
                          G_CALLBACK (gs_shell_updates_button_network_settings_cb),
                          shell_updates);
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "dialog_update"));
-       g_signal_connect (widget, "delete-event",
+       priv->update_dialog = gs_update_dialog_new ();
+       g_signal_connect (priv->update_dialog, "delete-event",
                          G_CALLBACK (gtk_widget_hide_on_delete), shell_updates);
-       g_signal_connect (widget, "hide",
-                         G_CALLBACK (dialog_update_hide_cb), shell_updates);
-
-       widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_update_back"));
-       g_signal_connect (widget, "clicked",
-                         G_CALLBACK (gs_shell_updates_button_back_cb),
-                         shell_updates);
-       sw = GTK_WIDGET (gtk_builder_get_object (priv->builder, "scrolledwindow_update_details"));
-       widget = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (sw));
-       g_signal_connect (widget, "map", G_CALLBACK (scrollbar_mapped_cb), sw);
-       g_signal_connect (widget, "unmap", G_CALLBACK (scrollbar_mapped_cb), sw);
-
-       sw = GTK_WIDGET (gtk_builder_get_object (priv->builder, "scrolledwindow_update"));
-       widget = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (sw));
-       g_signal_connect (widget, "map", G_CALLBACK (scrollbar_mapped_cb), sw);
-       g_signal_connect (widget, "unmap", G_CALLBACK (scrollbar_mapped_cb), sw);
 
        g_signal_connect (priv->control, "notify::network-state",
                          G_CALLBACK (gs_shell_updates_notify_network_state_cb),
@@ -1175,7 +954,6 @@ gs_shell_updates_finalize (GObject *object)
        g_object_unref (priv->plugin_loader);
        g_object_unref (priv->cancellable);
        g_object_unref (priv->control);
-       g_clear_object (&priv->app);
 
        G_OBJECT_CLASS (gs_shell_updates_parent_class)->finalize (object);
 }
diff --git a/src/gs-update-dialog.c b/src/gs-update-dialog.c
new file mode 100644
index 0000000..9d9bee2
--- /dev/null
+++ b/src/gs-update-dialog.c
@@ -0,0 +1,288 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013-2014 Richard Hughes <richard hughsie com>
+ *
+ * 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 <gtk/gtk.h>
+
+#include "gs-update-dialog.h"
+#include "gs-markdown.h"
+#include "gs-utils.h"
+
+struct _GsUpdateDialogPrivate
+{
+       GsApp           *app;
+       GtkWidget       *box_header;
+       GtkWidget       *button_back;
+       GtkWidget       *image_icon;
+       GtkWidget       *label_details;
+       GtkWidget       *label_name;
+       GtkWidget       *label_summary;
+       GtkWidget       *list_box;
+       GtkWidget       *scrolledwindow;
+       GtkWidget       *scrolledwindow_details;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GsUpdateDialog, gs_update_dialog, GTK_TYPE_DIALOG)
+
+static void
+set_updates_description_ui (GsUpdateDialog *dialog, GsApp *app)
+{
+       GsUpdateDialogPrivate *priv = gs_update_dialog_get_instance_private (dialog);
+       GsAppKind kind;
+       GsMarkdown *markdown;
+       gchar *tmp;
+       gchar *update_desc;
+
+       /* set window title */
+       kind = gs_app_get_kind (app);
+       if (kind == GS_APP_KIND_OS_UPDATE) {
+               gtk_window_set_title (GTK_WINDOW (dialog), gs_app_get_name (app));
+       } else {
+               tmp = g_strdup_printf ("%s %s",
+                                      gs_app_get_source_default (app),
+                                      gs_app_get_update_version_ui (app));
+               gtk_window_set_title (GTK_WINDOW (dialog), tmp);
+               g_free (tmp);
+       }
+
+       /* get the update description */
+       if (gs_app_get_update_details (app) == NULL) {
+               /* TRANSLATORS: this is where the packager did not write a
+                * description for the update */
+               update_desc = g_strdup ("No update description");
+       } else {
+               markdown = gs_markdown_new (GS_MARKDOWN_OUTPUT_PANGO);
+               gs_markdown_set_smart_quoting (markdown, FALSE);
+               gs_markdown_set_autocode (markdown, TRUE);
+               update_desc = gs_markdown_parse (markdown, gs_app_get_update_details (app));
+               g_object_unref (markdown);
+       }
+
+       /* set update header */
+       gtk_widget_set_visible (priv->box_header, kind == GS_APP_KIND_NORMAL || kind == GS_APP_KIND_SYSTEM);
+       gtk_widget_set_visible (priv->scrolledwindow_details, kind != GS_APP_KIND_OS_UPDATE);
+       gtk_widget_set_visible (priv->scrolledwindow, kind == GS_APP_KIND_OS_UPDATE);
+       gtk_label_set_markup (GTK_LABEL (priv->label_details), update_desc);
+       gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image_icon), gs_app_get_pixbuf (app));
+       gtk_label_set_label (GTK_LABEL (priv->label_name), gs_app_get_name (app));
+       gtk_label_set_label (GTK_LABEL (priv->label_summary), gs_app_get_summary (app));
+       g_free (update_desc);
+}
+
+static void
+row_activated_cb (GtkListBox *list_box,
+                  GtkListBoxRow *row,
+                  GsUpdateDialog *dialog)
+{
+       GsUpdateDialogPrivate *priv = gs_update_dialog_get_instance_private (dialog);
+       GsApp *app = NULL;
+
+       app = GS_APP (g_object_get_data (G_OBJECT (gtk_bin_get_child (GTK_BIN (row))), "app"));
+       /* setup package view */
+       gtk_widget_hide (priv->scrolledwindow);
+       set_updates_description_ui (dialog, app);
+       gtk_widget_show (priv->button_back);
+}
+
+void
+gs_update_dialog_set_app (GsUpdateDialog *dialog, GsApp *app)
+{
+       GsUpdateDialogPrivate *priv = gs_update_dialog_get_instance_private (dialog);
+       GsApp *app_related;
+       GsAppKind kind;
+       const gchar *sort;
+
+       g_clear_object (&priv->app);
+       priv->app = g_object_ref (app);
+
+       kind = gs_app_get_kind (app);
+
+       /* set update header */
+       set_updates_description_ui (dialog, app);
+
+       /* only OS updates can go back, and only on selection */
+       gtk_widget_hide (priv->button_back);
+
+       /* set update description */
+       if (kind == GS_APP_KIND_OS_UPDATE) {
+               GPtrArray *related;
+               GtkListBox *list_box;
+               guint i;
+               GtkWidget *row, *label;
+
+               list_box = GTK_LIST_BOX (priv->list_box);
+               gs_container_remove_all (GTK_CONTAINER (list_box));
+               related = gs_app_get_related (app);
+               for (i = 0; i < related->len; i++) {
+                       app_related = g_ptr_array_index (related, i);
+                       row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+                       g_object_set_data_full (G_OBJECT (row),
+                                               "app",
+                                               g_object_ref (app_related),
+                                               g_object_unref);
+                       sort = gs_app_get_source_default (app_related);
+                       g_object_set_data_full (G_OBJECT (row),
+                                               "sort",
+                                               g_strdup (sort),
+                                               g_free);
+                       label = gtk_label_new (gs_app_get_source_default (app_related));
+                       g_object_set (label,
+                                     "margin-left", 20,
+                                     "margin-right", 20,
+                                     "margin-top", 6,
+                                     "margin-bottom", 6,
+                                     "xalign", 0.0,
+                                     NULL);
+                       gtk_widget_set_halign (label, GTK_ALIGN_START);
+                       gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
+                       gtk_box_pack_start (GTK_BOX (row), label, TRUE, TRUE, 0);
+                       label = gtk_label_new (gs_app_get_update_version_ui (app_related));
+                       g_object_set (label,
+                                     "margin-left", 20,
+                                     "margin-right", 20,
+                                     "margin-top", 6,
+                                     "margin-bottom", 6,
+                                     "xalign", 1.0,
+                                     NULL);
+                       gtk_widget_set_halign (label, GTK_ALIGN_END);
+                       gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
+                       gtk_box_pack_start (GTK_BOX (row), label, FALSE, FALSE, 0);
+                       gtk_widget_show_all (row);
+                       gtk_list_box_insert (list_box,row, -1);
+               }
+       }
+}
+
+static gint
+os_updates_sort_func (GtkListBoxRow *a,
+                      GtkListBoxRow *b,
+                      gpointer user_data)
+{
+       GObject *o1 = G_OBJECT (gtk_bin_get_child (GTK_BIN (a)));
+       GObject *o2 = G_OBJECT (gtk_bin_get_child (GTK_BIN (b)));
+       const gchar *key1 = g_object_get_data (o1, "sort");
+       const gchar *key2 = g_object_get_data (o2, "sort");
+       return g_strcmp0 (key1, key2);
+}
+
+
+static void
+button_back_cb (GtkWidget *widget, GsUpdateDialog *dialog)
+{
+       GsUpdateDialogPrivate *priv = gs_update_dialog_get_instance_private (dialog);
+
+       /* return to the list view */
+       gtk_widget_hide (priv->button_back);
+       gtk_widget_hide (priv->box_header);
+       gtk_widget_hide (priv->scrolledwindow_details);
+       gtk_widget_show (priv->scrolledwindow);
+
+       gtk_window_set_title (GTK_WINDOW (dialog), gs_app_get_name (priv->app));
+}
+
+static void
+scrollbar_mapped_cb (GtkWidget *sb, GtkScrolledWindow *swin)
+{
+       GtkWidget *frame;
+
+       frame = gtk_bin_get_child (GTK_BIN (gtk_bin_get_child (GTK_BIN (swin))));
+
+       if (gtk_widget_get_mapped (GTK_WIDGET (sb))) {
+               gtk_scrolled_window_set_shadow_type (swin, GTK_SHADOW_IN);
+               if (GTK_IS_FRAME (frame))
+                       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
+       } else {
+               if (GTK_IS_FRAME (frame))
+                       gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+               gtk_scrolled_window_set_shadow_type (swin, GTK_SHADOW_NONE);
+       }
+}
+
+static void
+gs_update_dialog_finalize (GObject *object)
+{
+       GsUpdateDialog *dialog = GS_UPDATE_DIALOG (object);
+       GsUpdateDialogPrivate *priv = gs_update_dialog_get_instance_private (dialog);
+
+       g_clear_object (&priv->app);
+
+       G_OBJECT_CLASS (gs_update_dialog_parent_class)->finalize (object);
+}
+
+static void
+gs_update_dialog_init (GsUpdateDialog *dialog)
+{
+       GsUpdateDialogPrivate *priv = gs_update_dialog_get_instance_private (dialog);
+       GtkWidget *scrollbar;
+
+       gtk_widget_init_template (GTK_WIDGET (dialog));
+
+       g_signal_connect (GTK_LIST_BOX (priv->list_box), "row-activated",
+                         G_CALLBACK (row_activated_cb), dialog);
+       gtk_list_box_set_sort_func (GTK_LIST_BOX (priv->list_box),
+                                   os_updates_sort_func,
+                                   dialog, NULL);
+
+       g_signal_connect (priv->button_back, "clicked",
+                         G_CALLBACK (button_back_cb),
+                         dialog);
+
+       scrollbar = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (priv->scrolledwindow_details));
+       g_signal_connect (scrollbar, "map", G_CALLBACK (scrollbar_mapped_cb), priv->scrolledwindow_details);
+       g_signal_connect (scrollbar, "unmap", G_CALLBACK (scrollbar_mapped_cb), priv->scrolledwindow_details);
+
+       scrollbar = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (priv->scrolledwindow));
+       g_signal_connect (scrollbar, "map", G_CALLBACK (scrollbar_mapped_cb), priv->scrolledwindow);
+       g_signal_connect (scrollbar, "unmap", G_CALLBACK (scrollbar_mapped_cb), priv->scrolledwindow);
+}
+
+static void
+gs_update_dialog_class_init (GsUpdateDialogClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+       object_class->finalize = gs_update_dialog_finalize;
+
+       gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/software/gs-update-dialog.ui");
+
+       gtk_widget_class_bind_template_child_private (widget_class, GsUpdateDialog, box_header);
+       gtk_widget_class_bind_template_child_private (widget_class, GsUpdateDialog, button_back);
+       gtk_widget_class_bind_template_child_private (widget_class, GsUpdateDialog, image_icon);
+       gtk_widget_class_bind_template_child_private (widget_class, GsUpdateDialog, label_details);
+       gtk_widget_class_bind_template_child_private (widget_class, GsUpdateDialog, label_name);
+       gtk_widget_class_bind_template_child_private (widget_class, GsUpdateDialog, label_summary);
+       gtk_widget_class_bind_template_child_private (widget_class, GsUpdateDialog, list_box);
+       gtk_widget_class_bind_template_child_private (widget_class, GsUpdateDialog, scrolledwindow);
+       gtk_widget_class_bind_template_child_private (widget_class, GsUpdateDialog, scrolledwindow_details);
+}
+
+GtkWidget *
+gs_update_dialog_new (void)
+{
+       return GTK_WIDGET (g_object_new (GS_TYPE_UPDATE_DIALOG,
+                                        "use-header-bar", TRUE,
+                                        NULL));
+}
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-update-dialog.h b/src/gs-update-dialog.h
new file mode 100644
index 0000000..0a64c80
--- /dev/null
+++ b/src/gs-update-dialog.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ *
+ * 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_UPDATE_DIALOG_H
+#define GS_UPDATE_DIALOG_H
+
+#include <gtk/gtk.h>
+
+#include "gs-app.h"
+
+#define GS_TYPE_UPDATE_DIALOG          (gs_update_dialog_get_type())
+#define GS_UPDATE_DIALOG(obj)          (G_TYPE_CHECK_INSTANCE_CAST((obj), GS_TYPE_UPDATE_DIALOG, 
GsUpdateDialog))
+#define GS_UPDATE_DIALOG_CLASS(cls)    (G_TYPE_CHECK_CLASS_CAST((cls), GS_TYPE_UPDATE_DIALOG, 
GsUpdateDialogClass))
+#define GS_IS_UPDATE_DIALOG(obj)       (G_TYPE_CHECK_INSTANCE_TYPE((obj), GS_TYPE_UPDATE_DIALOG))
+#define GS_IS_UPDATE_DIALOG_CLASS(cls) (G_TYPE_CHECK_CLASS_TYPE((cls), GS_TYPE_UPDATE_DIALOG))
+#define GS_UPDATE_DIALOG_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS((obj), GS_TYPE_UPDATE_DIALOG, 
GsUpdateDialogClass))
+
+G_BEGIN_DECLS
+
+typedef struct _GsUpdateDialog         GsUpdateDialog;
+typedef struct _GsUpdateDialogClass    GsUpdateDialogClass;
+typedef struct _GsUpdateDialogPrivate  GsUpdateDialogPrivate;
+
+struct _GsUpdateDialog
+{
+       GtkDialog        parent;
+};
+
+struct _GsUpdateDialogClass
+{
+       GtkDialogClass   parent_class;
+};
+
+GType           gs_update_dialog_get_type      (void);
+GtkWidget      *gs_update_dialog_new           (void);
+void            gs_update_dialog_set_app       (GsUpdateDialog         *dialog,
+                                                GsApp                  *app);
+
+#endif /* GS_UPDATE_DIALOG_H */
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-update-dialog.ui b/src/gs-update-dialog.ui
new file mode 100644
index 0000000..8628ec3
--- /dev/null
+++ b/src/gs-update-dialog.ui
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.10"/>
+  <template class="GsUpdateDialog" parent="GtkDialog">
+    <property name="can_focus">False</property>
+    <property name="modal">True</property>
+    <property name="default_width">600</property>
+    <property name="default_height">600</property>
+    <property name="destroy_with_parent">True</property>
+    <property name="type_hint">dialog</property>
+    <property name="use_header_bar">1</property>
+    <child internal-child="headerbar">
+      <object class="GtkHeaderBar">
+        <child>
+          <object class="GtkButton" id="button_back">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <child internal-child="accessible">
+              <object class="AtkObject" id="button_back_accessible">
+                <property name="accessible-name" translatable="yes">Go back</property>
+              </object>
+            </child>
+            <style>
+              <class name="image-button"/>
+            </style>
+            <child>
+              <object class="GtkImage" id="image_update_back">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="icon_name">go-previous-symbolic</property>
+                <property name="icon_size">1</property>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="pack-type">start</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="dialog-vbox1">
+        <property name="can_focus">False</property>
+        <property name="margin_start">6</property>
+        <property name="margin_end">6</property>
+        <property name="margin_top">6</property>
+        <property name="margin_bottom">6</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkBox" id="box7">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_bottom">3</property>
+            <property name="border_width">3</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">9</property>
+            <child>
+              <object class="GtkBox" id="box_header">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="spacing">9</property>
+                <child>
+                  <object class="GtkImage" id="image_icon">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="pixel_size">96</property>
+                    <property name="icon_name">accessories-calculator</property>
+                    <property name="icon_size">0</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkBox" id="box9">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="orientation">vertical</property>
+                    <property name="spacing">3</property>
+                    <child>
+                      <object class="GtkLabel" id="label_name">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">0</property>
+                        <property name="label">Inkscape</property>
+                        <property name="angle">0.41999998688697815</property>
+                        <attributes>
+                          <attribute name="weight" value="bold"/>
+                          <attribute name="scale" value="1.3999999999999999"/>
+                        </attributes>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label_summary">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">0</property>
+                        <property name="label">Vector based drawing program</property>
+                        <property name="selectable">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">True</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkScrolledWindow" id="scrolledwindow_details">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="vexpand">True</property>
+                <property name="hscrollbar_policy">never</property>
+                <property name="vscrollbar_policy">automatic</property>
+                <property name="shadow_type">none</property>
+                <property name="kinetic_scrolling">False</property>
+                <child>
+                  <object class="GtkLabel" id="label_details">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="yalign">0</property>
+                    <property name="margin">6</property>
+                    <property name="label">New in kmod 14-1
+* Moo
+* bar</property>
+                    <property name="wrap">True</property>
+                    <property name="selectable">True</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkScrolledWindow" id="scrolledwindow">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="vexpand">True</property>
+                <property name="hscrollbar_policy">never</property>
+                <property name="vscrollbar_policy">automatic</property>
+                <property name="shadow_type">none</property>
+                <property name="kinetic_scrolling">False</property>
+                <child>
+                  <object class="GtkFrame" id="box_update_frame">
+                    <property name="visible">True</property>
+                    <property name="shadow_type">in</property>
+                    <property name="halign">fill</property>
+                    <property name="valign">start</property>
+                    <style>
+                      <class name="view"/>
+                    </style>
+                    <child>
+                      <object class="GtkListBox" id="list_box">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="selection_mode">none</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </template>
+  <object class="GtkSizeGroup" id="sizegroup_update_details">
+    <property name="ignore-hidden">False</property>
+    <property name="mode">horizontal</property>
+    <widgets>
+      <widget name="scrolledwindow"/>
+      <widget name="scrolledwindow_details"/>
+    </widgets>
+  </object>
+</interface>



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]