summaryrefslogtreecommitdiffstats
path: root/widgets/src
diff options
context:
space:
mode:
Diffstat (limited to 'widgets/src')
-rw-r--r--widgets/src/BaseWindow.c318
-rw-r--r--widgets/src/BaseWindow.h71
-rw-r--r--widgets/src/DiskOverview.c347
-rw-r--r--widgets/src/DiskOverview.h70
-rw-r--r--widgets/src/HubWindow.c146
-rw-r--r--widgets/src/HubWindow.h70
-rw-r--r--widgets/src/Makefile.am69
-rw-r--r--widgets/src/SpokeSelector.c251
-rw-r--r--widgets/src/SpokeSelector.h69
-rw-r--r--widgets/src/SpokeWindow.c123
-rw-r--r--widgets/src/SpokeWindow.h73
-rw-r--r--widgets/src/StandaloneWindow.c194
-rw-r--r--widgets/src/StandaloneWindow.h78
-rw-r--r--widgets/src/glade-adaptor.c76
-rw-r--r--widgets/src/intl.h34
15 files changed, 1989 insertions, 0 deletions
diff --git a/widgets/src/BaseWindow.c b/widgets/src/BaseWindow.c
new file mode 100644
index 000000000..b050836d6
--- /dev/null
+++ b/widgets/src/BaseWindow.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Chris Lumens <clumens@redhat.com>
+ */
+
+#include <string.h>
+
+#include "BaseWindow.h"
+#include "intl.h"
+
+/**
+ * SECTION: BaseWindow
+ * @title: AnacondaBaseWindow
+ * @short_description: Top-level, non-resizeable window
+ *
+ * A #AnacondaBaseWindow is a top-level, non-resizeable window that contains
+ * other widgets and serves as the base class from which all other specialized
+ * Anaconda windows are derived. It is undecorated.
+ *
+ * The window consists of two areas:
+ *
+ * - A navigation area in the top of the screen, consisting of some basic
+ * information about what is being displayed and what is being installed.
+ *
+ * - An action area in the majority of the screen. This area is where
+ * subclasses should add their particular widgets.
+ *
+ * <refsect2 id="AnacondaBaseWindow-BUILDER-UI"><title>AnacondaBaseWindow as GtkBuildable</title>
+ * <para>
+ * The AnacondaBaseWindow implementation of the #GtkBuildable interface exposes
+ * the @action_area as an internal child with the name "action_area".
+ * </para>
+ * <example>
+ * <title>A <structname>AnacondaBaseWindow</structname> UI definition fragment.</title>
+ * <programlisting><![CDATA[
+ * <object class="AnacondaBaseWindow" id="window1">
+ * <child internal-child="action_area">
+ * <object class="GtkVBox" id="vbox1">
+ * <child>
+ * <object class="GtkLabel" id="label1">
+ * <property name="label" translatable="yes">THIS IS ONE LABEL</property>
+ * </object>
+ * </child>
+ * <child>
+ * <object class="GtkLabel" id="label2">
+ * <property name="label" translatable="yes">THIS IS ANOTHER LABEL</property>
+ * </object>
+ * </child>
+ * </object>
+ * </child>
+ * </object>
+ * ]]></programlisting>
+ * </example>
+ * </refsect2>
+ */
+
+enum {
+ PROP_DISTRIBUTION = 1,
+ PROP_WINDOW_NAME
+};
+
+#define DEFAULT_DISTRIBUTION "DISTRIBUTION INSTALLATION"
+#define DEFAULT_WINDOW_NAME "SPOKE NAME"
+
+struct _AnacondaBaseWindowPrivate {
+ gboolean is_beta;
+ GtkWidget *action_area;
+ GtkWidget *nav_area;
+ GtkWidget *name_label, *distro_label, *beta_label;
+};
+
+static void anaconda_base_window_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+static void anaconda_base_window_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void anaconda_base_window_buildable_init(GtkBuildableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE(AnacondaBaseWindow, anaconda_base_window, GTK_TYPE_WINDOW,
+ G_IMPLEMENT_INTERFACE(GTK_TYPE_BUILDABLE, anaconda_base_window_buildable_init))
+
+static void anaconda_base_window_class_init(AnacondaBaseWindowClass *klass) {
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ object_class->set_property = anaconda_base_window_set_property;
+ object_class->get_property = anaconda_base_window_get_property;
+
+ /**
+ * AnacondaBaseWindow:distribution:
+ *
+ * The :distribution string is displayed in the upper right corner of all
+ * windows throughout installation.
+ *
+ * Since: 1.0
+ */
+ g_object_class_install_property(object_class,
+ PROP_DISTRIBUTION,
+ g_param_spec_string("distribution",
+ P_("Distribution"),
+ P_("The distribution being installed"),
+ DEFAULT_DISTRIBUTION,
+ G_PARAM_READWRITE));
+
+ /**
+ * AnacondaBaseWindow:window-name:
+ *
+ * The name of the currently displayed window, displayed in the upper
+ * left corner of all windows with a title throughout installation.
+ *
+ * Since: 1.0
+ */
+ g_object_class_install_property(object_class,
+ PROP_WINDOW_NAME,
+ g_param_spec_string("window-name",
+ P_("Window Name"),
+ P_("The name of this spoke"),
+ DEFAULT_WINDOW_NAME,
+ G_PARAM_READWRITE));
+
+ g_type_class_add_private(object_class, sizeof(AnacondaBaseWindowPrivate));
+}
+
+/**
+ * anaconda_base_window_new:
+ *
+ * Creates a new #AnacondaBaseWindow, which is a toplevel, non-resizeable
+ * window that contains other widgets. This is the base class for all other
+ * Anaconda windows and creates the window style that all windows will share.
+ *
+ * Returns: A new #AnacondaBaseWindow.
+ */
+GtkWidget *anaconda_base_window_new() {
+ return g_object_new(ANACONDA_TYPE_BASE_WINDOW, NULL);
+}
+
+static void anaconda_base_window_init(AnacondaBaseWindow *win) {
+ char *markup;
+
+ win->priv = G_TYPE_INSTANCE_GET_PRIVATE(win,
+ ANACONDA_TYPE_BASE_WINDOW,
+ AnacondaBaseWindowPrivate);
+
+ win->priv->is_beta = FALSE;
+
+ /* Set properties on the parent (Gtk.Window) class. */
+ gtk_window_set_decorated(GTK_WINDOW(win), FALSE);
+ gtk_window_maximize(GTK_WINDOW(win));
+ gtk_container_set_border_width(GTK_CONTAINER(win), 6);
+
+ win->priv->action_area = gtk_vbox_new(FALSE, 6);
+
+ /* Create the navigation area. */
+ win->priv->nav_area = gtk_grid_new();
+ gtk_grid_set_row_homogeneous(GTK_GRID(win->priv->nav_area), FALSE);
+ gtk_grid_set_column_homogeneous(GTK_GRID(win->priv->nav_area), FALSE);
+
+ /* Create the name label. */
+ win->priv->name_label = gtk_label_new(NULL);
+ markup = g_markup_printf_escaped("<span weight='bold'>%s</span>", _(DEFAULT_WINDOW_NAME));
+ gtk_label_set_markup(GTK_LABEL(win->priv->name_label), markup);
+ g_free(markup);
+ gtk_misc_set_alignment(GTK_MISC(win->priv->name_label), 0, 0);
+ gtk_widget_set_hexpand(GTK_WIDGET(win->priv->name_label), TRUE);
+
+ /* Create the distribution label. */
+ win->priv->distro_label = gtk_label_new(_(DEFAULT_DISTRIBUTION));
+ gtk_misc_set_alignment(GTK_MISC(win->priv->distro_label), 0, 0);
+
+ /* Create the betanag label. */
+ win->priv->beta_label = gtk_label_new(NULL);
+ markup = g_markup_printf_escaped("<span foreground='red'>%s</span>", _("PRE-RELEASE / TESTING"));
+ gtk_label_set_markup(GTK_LABEL(win->priv->beta_label), markup);
+ g_free(markup);
+ gtk_misc_set_alignment(GTK_MISC(win->priv->beta_label), 0, 0);
+ gtk_widget_set_no_show_all(GTK_WIDGET(win->priv->beta_label), TRUE);
+
+ /* Add everything to the nav area. */
+ gtk_grid_attach(GTK_GRID(win->priv->nav_area), win->priv->name_label, 0, 0, 1, 1);
+ gtk_grid_attach(GTK_GRID(win->priv->nav_area), win->priv->distro_label, 1, 0, 1, 1);
+ gtk_grid_attach(GTK_GRID(win->priv->nav_area), win->priv->beta_label, 1, 1, 1, 1);
+
+ /* Put the grid into the action_area, and the action_area into the window. */
+ gtk_box_pack_start(GTK_BOX(win->priv->action_area), GTK_WIDGET(win->priv->nav_area), FALSE, FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(win), GTK_WIDGET(win->priv->action_area));
+}
+
+static void anaconda_base_window_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) {
+ AnacondaBaseWindow *widget = ANACONDA_BASE_WINDOW(object);
+ AnacondaBaseWindowPrivate *priv = widget->priv;
+
+ switch(prop_id) {
+ case PROP_DISTRIBUTION:
+ g_value_set_string(value, gtk_label_get_text(GTK_LABEL(priv->distro_label)));
+ break;
+
+ case PROP_WINDOW_NAME:
+ g_value_set_string(value, gtk_label_get_text(GTK_LABEL(priv->name_label)));
+ break;
+ }
+}
+
+static void anaconda_base_window_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) {
+ AnacondaBaseWindow *widget = ANACONDA_BASE_WINDOW(object);
+ AnacondaBaseWindowPrivate *priv = widget->priv;
+
+ switch(prop_id) {
+ case PROP_DISTRIBUTION: {
+ gtk_label_set_text(GTK_LABEL(priv->distro_label), g_value_get_string(value));
+ break;
+ }
+
+ case PROP_WINDOW_NAME: {
+ char *markup = g_markup_printf_escaped("<span weight='bold'>%s</span>", g_value_get_string(value));
+ gtk_label_set_markup(GTK_LABEL(priv->name_label), markup);
+ g_free(markup);
+ break;
+ }
+ }
+}
+
+/**
+ * anaconda_base_window_get_beta:
+ * @win: a #AnacondaBaseWindow
+ *
+ * Returns whether or not this window is set to display the betanag warning.
+ *
+ * Returns: Whether @win is set to display the betanag warning
+ *
+ * Since: 1.0
+ */
+gboolean anaconda_base_window_get_beta(AnacondaBaseWindow *win) {
+ return win->priv->is_beta;
+}
+
+/**
+ * anaconda_base_window_set_beta:
+ * @win: a #AnacondaBaseWindow
+ * @is_beta: %TRUE to display the betanag warning
+ *
+ * Sets up the window to display the betanag warning in red along the top of
+ * the screen.
+ *
+ * Since: 1.0
+ */
+void anaconda_base_window_set_beta(AnacondaBaseWindow *win, gboolean is_beta) {
+ win->priv->is_beta = is_beta;
+
+ if (is_beta)
+ gtk_widget_show(win->priv->beta_label);
+ else
+ gtk_widget_hide(win->priv->beta_label);
+}
+
+/**
+ * anaconda_base_window_get_action_area:
+ * @win: a #AnacondaBaseWindow
+ *
+ * Returns the action area of @win.
+ *
+ * Returns: (transfer none): The action area
+ *
+ * Since: 1.0
+ */
+GtkWidget *anaconda_base_window_get_action_area(AnacondaBaseWindow *win) {
+ return win->priv->action_area;
+}
+
+/**
+ * anaconda_base_window_get_nav_area:
+ * @win: a #AnacondaBaseWindow
+ *
+ * Returns the navigation area of @win.
+ *
+ * Returns: (transfer none): The navigation area
+ *
+ * Since: 1.0
+ */
+GtkWidget *anaconda_base_window_get_nav_area(AnacondaBaseWindow *win) {
+ return win->priv->nav_area;
+}
+
+static GtkBuildableIface *parent_buildable_iface;
+
+static void
+anaconda_base_window_buildable_add_child (GtkBuildable *window,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type) {
+ gtk_container_add(GTK_CONTAINER(anaconda_base_window_get_action_area(ANACONDA_BASE_WINDOW(window))),
+ GTK_WIDGET(child));
+}
+
+static GObject *
+anaconda_base_window_buildable_get_internal_child (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *childname) {
+ if (strcmp (childname, "action_area") == 0)
+ return G_OBJECT(anaconda_base_window_get_action_area(ANACONDA_BASE_WINDOW(buildable)));
+
+ return parent_buildable_iface->get_internal_child (buildable, builder, childname);
+}
+
+static void anaconda_base_window_buildable_init (GtkBuildableIface *iface) {
+ parent_buildable_iface = g_type_interface_peek_parent (iface);
+ iface->add_child = anaconda_base_window_buildable_add_child;
+ iface->get_internal_child = anaconda_base_window_buildable_get_internal_child;
+}
diff --git a/widgets/src/BaseWindow.h b/widgets/src/BaseWindow.h
new file mode 100644
index 000000000..088980400
--- /dev/null
+++ b/widgets/src/BaseWindow.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Chris Lumens <clumens@redhat.com>
+ */
+
+#ifndef _BASE_WINDOW_H
+#define _BASE_WINDOW_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define ANACONDA_TYPE_BASE_WINDOW (anaconda_base_window_get_type())
+#define ANACONDA_BASE_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ANACONDA_TYPE_BASE_WINDOW, AnacondaBaseWindow))
+#define ANACONDA_IS_BASE_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ANACONDA_TYPE_BASE_WINDOW))
+#define ANACONDA_BASE_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ANACONDA_TYPE_BASE_WINDOW, AnacondaBaseWindowClass))
+#define ANACONDA_IS_BASE_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ANACONDA_TYPE_BASE_WINDOW))
+#define ANACONDA_BASE_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ANACONDA_TYPE_BASE_WINDOW, AnacondaBaseWindowClass))
+
+typedef struct _AnacondaBaseWindow AnacondaBaseWindow;
+typedef struct _AnacondaBaseWindowClass AnacondaBaseWindowClass;
+typedef struct _AnacondaBaseWindowPrivate AnacondaBaseWindowPrivate;
+
+/**
+ * AnacondaBaseWindow:
+ *
+ * The AnacondaBaseWindow struct contains only private fields and should not
+ * be directly accessed.
+ */
+struct _AnacondaBaseWindow {
+ GtkWindow parent;
+
+ /*< private >*/
+ AnacondaBaseWindowPrivate *priv;
+};
+
+/**
+ * AnacondaBaseWindowClass:
+ * @parent_class: The object class structure needs to be the first element in
+ * the widget class structure in order for the class mechanism
+ * to work correctly. This allows a AnacondaBaseWindowClass
+ * pointer to be cast to a #GtkWindow pointer.
+ */
+struct _AnacondaBaseWindowClass {
+ GtkWindowClass parent_class;
+};
+
+GType anaconda_base_window_get_type (void);
+GtkWidget *anaconda_base_window_new ();
+gboolean anaconda_base_window_get_beta (AnacondaBaseWindow *win);
+void anaconda_base_window_set_beta (AnacondaBaseWindow *win, gboolean is_beta);
+GtkWidget *anaconda_base_window_get_action_area(AnacondaBaseWindow *win);
+GtkWidget *anaconda_base_window_get_nav_area(AnacondaBaseWindow *win);
+
+G_END_DECLS
+
+#endif
diff --git a/widgets/src/DiskOverview.c b/widgets/src/DiskOverview.c
new file mode 100644
index 000000000..c8a90aba3
--- /dev/null
+++ b/widgets/src/DiskOverview.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Chris Lumens <clumens@redhat.com>
+ */
+
+#include <string.h>
+
+#include "DiskOverview.h"
+#include "intl.h"
+
+/**
+ * SECTION: DiskOverview
+ * @title: AnacondaDiskOverview
+ * @short_description: A widget that displays basic information about a disk
+ *
+ * A #AnacondaDiskOverview is a potentially selectable widget that displays a
+ * disk device's size, kind, and a prominant icon based on the kind of device.
+ * This widget can come in different sizes, depending on where it needs to be
+ * used.
+ *
+ * As a #AnacondaDiskOverview is a subclass of a #GtkEventBox, any signals
+ * may be caught. The #GtkWidget::button-press-event signal is already
+ * handled internally to change the background color, but may also be handled
+ * by user code in order to take some action based on the disk clicked upon.
+ */
+enum {
+ PROP_DESCRIPTION = 1,
+ PROP_KIND,
+ PROP_CAPACITY,
+ PROP_OS,
+ PROP_POPUP_INFO
+};
+
+/* Defaults for each property. */
+#define DEFAULT_DESCRIPTION "New Device"
+#define DEFAULT_KIND "drive-harddisk"
+#define DEFAULT_CAPACITY "0 MB"
+#define DEFAULT_OS ""
+#define DEFAULT_POPUP_INFO ""
+
+struct _AnacondaDiskOverviewPrivate {
+ GtkWidget *vbox;
+ GtkWidget *kind;
+ GtkWidget *description_label;
+ GtkWidget *capacity_label;
+ GtkWidget *os_label;
+ GtkWidget *tooltip;
+
+ gboolean selected;
+};
+
+G_DEFINE_TYPE(AnacondaDiskOverview, anaconda_disk_overview, GTK_TYPE_EVENT_BOX)
+
+gboolean anaconda_disk_overview_clicked(AnacondaDiskOverview *widget, GdkEvent *event);
+static void anaconda_disk_overview_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+static void anaconda_disk_overview_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+
+static void anaconda_disk_overview_class_init(AnacondaDiskOverviewClass *klass) {
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ object_class->set_property = anaconda_disk_overview_set_property;
+ object_class->get_property = anaconda_disk_overview_get_property;
+
+ /**
+ * AnacondaDiskOverview:kind:
+ *
+ * The :kind string specifies what type of disk device this is, used to
+ * figure out what icon to be displayed. This should be something like
+ * "drive-harddisk", "drive-removable-media", etc.
+ *
+ * Since: 1.0
+ */
+ g_object_class_install_property(object_class,
+ PROP_KIND,
+ g_param_spec_string("kind",
+ P_("kind"),
+ P_("Drive kind icon"),
+ DEFAULT_KIND,
+ G_PARAM_READWRITE));
+
+ /**
+ * AnacondaDiskOverview:description:
+ *
+ * The :description string is a very basic description of the device
+ * and is displayed in bold letters under the icon.
+ *
+ * Since: 1.0
+ */
+ g_object_class_install_property(object_class,
+ PROP_DESCRIPTION,
+ g_param_spec_string("description",
+ P_("Description"),
+ P_("The drive description"),
+ DEFAULT_DESCRIPTION,
+ G_PARAM_READWRITE));
+
+ /**
+ * AnacondaDiskOverview:capacity:
+ *
+ * The :capacity string is the total size of the disk, plus units.
+ *
+ * Since: 1.0
+ */
+ g_object_class_install_property(object_class,
+ PROP_CAPACITY,
+ g_param_spec_string("capacity",
+ P_("Capacity"),
+ P_("The drive size (including units)"),
+ DEFAULT_CAPACITY,
+ G_PARAM_READWRITE));
+
+ /**
+ * AnacondaDiskOverview:os:
+ *
+ * The :os string describes any operating system found on this device.
+ *
+ * Since: 1.0
+ */
+ g_object_class_install_property(object_class,
+ PROP_OS,
+ g_param_spec_string("os",
+ P_("Operating System"),
+ P_("Installed OS on this drive"),
+ DEFAULT_OS,
+ G_PARAM_READWRITE));
+
+ /**
+ * AnacondaDiskOverview:popup-info:
+ *
+ * The :popup-info string is text that should appear in a tooltip when the
+ * #AnacondaDiskOverview is hovered over. For normal disk devices, this
+ * could be available space information. For more complex devics, this
+ * could be WWID, LUN, and so forth.
+ *
+ * Since: 1.0
+ */
+ g_object_class_install_property(object_class,
+ PROP_POPUP_INFO,
+ g_param_spec_string("popup-info",
+ P_("Detailed Disk Information"),
+ P_("Tooltip information for this drive"),
+ DEFAULT_POPUP_INFO,
+ G_PARAM_READWRITE));
+
+ g_type_class_add_private(object_class, sizeof(AnacondaDiskOverviewPrivate));
+}
+
+/**
+ * anaconda_disk_overview_new:
+ *
+ * Creates a new #AnacondaDiskOverview, which is a potentially selectable
+ * widget that displays basic information about a single storage device, be
+ * that a regular disk or a more complicated network device.
+ *
+ * Returns: A new #AnacondaDiskOverview.
+ */
+GtkWidget *anaconda_disk_overview_new() {
+ return g_object_new(ANACONDA_TYPE_DISK_OVERVIEW, NULL);
+}
+
+/* Initialize the widgets in a newly allocated DiskOverview. */
+static void anaconda_disk_overview_init(AnacondaDiskOverview *widget) {
+ char *markup;
+
+ widget->priv = G_TYPE_INSTANCE_GET_PRIVATE(widget,
+ ANACONDA_TYPE_DISK_OVERVIEW,
+ AnacondaDiskOverviewPrivate);
+
+ /* Set some properties. */
+ widget->priv->selected = FALSE;
+
+ /* Create the vbox. */
+ widget->priv->vbox = gtk_vbox_new(FALSE, 6);
+
+ /* Create the capacity label. */
+ widget->priv->capacity_label = gtk_label_new(NULL);
+ markup = g_markup_printf_escaped("<span size='large'>%s</span>", DEFAULT_CAPACITY);
+ gtk_label_set_markup(GTK_LABEL(widget->priv->capacity_label), markup);
+ g_free(markup);
+
+ /* Create the spoke's icon. */
+ widget->priv->kind = gtk_image_new_from_icon_name(DEFAULT_KIND, GTK_ICON_SIZE_DIALOG);
+ gtk_image_set_pixel_size(GTK_IMAGE(widget->priv->kind), 200);
+
+ /* Create the description label. */
+ widget->priv->description_label = gtk_label_new(NULL);
+ markup = g_markup_printf_escaped("<span weight='bold' size='large'>%s</span>", _(DEFAULT_DESCRIPTION));
+ gtk_label_set_markup(GTK_LABEL(widget->priv->description_label), markup);
+ g_free(markup);
+
+ /* Create the OS label. By default there is no operating system, so just
+ * create a new label here so we have a place for later, should an OS be
+ * specified.
+ */
+ widget->priv->os_label = gtk_label_new(NULL);
+
+ /* Add everything to the vbox, add the vbox to the widget. */
+ gtk_container_add(GTK_CONTAINER(widget->priv->vbox), widget->priv->capacity_label);
+ gtk_container_add(GTK_CONTAINER(widget->priv->vbox), widget->priv->kind);
+ gtk_container_add(GTK_CONTAINER(widget->priv->vbox), widget->priv->description_label);
+ gtk_container_add(GTK_CONTAINER(widget->priv->vbox), widget->priv->os_label);
+
+ gtk_container_add(GTK_CONTAINER(widget), widget->priv->vbox);
+
+ /* We need to handle button-press-event in order to change the background color. */
+ g_signal_connect(widget, "button-press-event", G_CALLBACK(anaconda_disk_overview_clicked), NULL);
+}
+
+gboolean anaconda_disk_overview_clicked(AnacondaDiskOverview *widget, GdkEvent *event) {
+ GtkStateFlags new_state;
+
+ /* This toggles whether the DiskOverview widget is selected or not. If it's selected,
+ * we then let GTK in on that secret and it'll render the background in whatever color
+ * the theme CSS says.
+ */
+ new_state = gtk_widget_get_state_flags(GTK_WIDGET(widget)) & ~GTK_STATE_FLAG_SELECTED;
+ widget->priv->selected = !widget->priv->selected;
+ if (widget->priv->selected)
+ new_state |= GTK_STATE_FLAG_SELECTED;
+
+ gtk_widget_set_state_flags(GTK_WIDGET(widget), new_state, TRUE);
+
+ return FALSE;
+}
+
+static void anaconda_disk_overview_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) {
+ AnacondaDiskOverview *widget = ANACONDA_DISK_OVERVIEW(object);
+ AnacondaDiskOverviewPrivate *priv = widget->priv;
+
+ switch(prop_id) {
+ case PROP_DESCRIPTION:
+ g_value_set_string (value, gtk_label_get_text(GTK_LABEL(priv->description_label)));
+ break;
+
+ case PROP_KIND:
+ g_value_set_object (value, (GObject *)priv->kind);
+ break;
+
+ case PROP_CAPACITY:
+ g_value_set_string (value, gtk_label_get_text(GTK_LABEL(priv->capacity_label)));
+ break;
+
+ case PROP_OS:
+ g_value_set_string (value, gtk_label_get_text(GTK_LABEL(priv->os_label)));
+ break;
+
+ case PROP_POPUP_INFO:
+ g_value_set_string (value, gtk_widget_get_tooltip_text(GTK_WIDGET(widget)));
+ break;
+ }
+}
+
+static void anaconda_disk_overview_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) {
+ AnacondaDiskOverview *widget = ANACONDA_DISK_OVERVIEW(object);
+ AnacondaDiskOverviewPrivate *priv = widget->priv;
+
+ switch(prop_id) {
+ case PROP_DESCRIPTION: {
+ char *markup = g_markup_printf_escaped("<span weight='bold' size='large'>%s</span>", g_value_get_string(value));
+ gtk_label_set_markup(GTK_LABEL(priv->description_label), markup);
+ g_free(markup);
+ break;
+ }
+
+ case PROP_KIND:
+ gtk_image_set_from_icon_name(GTK_IMAGE(priv->kind), g_value_get_string(value), GTK_ICON_SIZE_DIALOG);
+ gtk_image_set_pixel_size(GTK_IMAGE(priv->kind), 200);
+ break;
+
+ case PROP_CAPACITY: {
+ char *markup = g_markup_printf_escaped("<span size='large'>%s</span>", DEFAULT_CAPACITY);
+ gtk_label_set_markup(GTK_LABEL(priv->capacity_label), markup);
+ g_free(markup);
+ break;
+ }
+
+ case PROP_OS: {
+ /* If no OS is given, set the label to blank. This will prevent
+ * seeing a strange brown blob with no text in the middle of
+ * nowhere.
+ */
+ if (!strcmp(g_value_get_string(value), ""))
+ gtk_label_set_text(GTK_LABEL(priv->os_label), NULL);
+ else {
+ char *markup = g_markup_printf_escaped("<span foreground='white' background='brown'>%s</span>", g_value_get_string(value));
+ gtk_label_set_markup(GTK_LABEL(priv->os_label), markup);
+ g_free(markup);
+ break;
+ }
+ }
+
+ case PROP_POPUP_INFO: {
+ if (!strcmp(g_value_get_string(value), ""))
+ gtk_widget_set_has_tooltip(GTK_WIDGET(widget), FALSE);
+ else {
+ gtk_widget_set_tooltip_text(GTK_WIDGET(widget), g_value_get_string(value));
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * anaconda_disk_overview_get_selected:
+ * @widget: a #AnacondaDiskOverview
+ *
+ * Returns whether or not this disk has been selected by the user.
+ *
+ * Returns: Whether @widget has been selected.
+ *
+ * Since: 1.0
+ */
+gboolean anaconda_disk_overview_get_selected(AnacondaDiskOverview *widget) {
+ return widget->priv->selected;
+}
+
+/**
+ * anaconda_disk_overview_set_selected:
+ * @widget: a #AnacondaDiskOverview
+ * @is_selected: %TRUE if this disk is selected.
+ *
+ * Specifies whether the disk shown by this overview has been selected by
+ * the user for inclusion in installation. If so, a special background will
+ * be set as a visual indicator.
+ *
+ * Since: 1.0
+ */
+void anaconda_disk_overview_set_selected(AnacondaDiskOverview *widget, gboolean is_selected) {
+ gboolean result;
+
+ widget->priv->selected = is_selected;
+ g_signal_emit_by_name(widget, "button-press-event", &result);
+}
diff --git a/widgets/src/DiskOverview.h b/widgets/src/DiskOverview.h
new file mode 100644
index 000000000..fd78e1790
--- /dev/null
+++ b/widgets/src/DiskOverview.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Chris Lumens <clumens@redhat.com>
+ */
+
+#ifndef _DISK_OVERVIEW_H
+#define _DISK_OVERVIEW_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define ANACONDA_TYPE_DISK_OVERVIEW (anaconda_disk_overview_get_type())
+#define ANACONDA_DISK_OVERVIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ANACONDA_TYPE_DISK_OVERVIEW, AnacondaDiskOverview))
+#define ANACONDA_IS_DISK_OVERVIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj)), ANACONDA_TYPE_DISK_OVERVIEW)
+#define ANACONDA_DISK_OVERVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ANACONDA_TYPE_DISK_OVERVIEW, AnacondaDiskOverviewClass))
+#define ANACONDA_IS_DISK_OVERVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ANACONDA_TYPE_DISK_OVERVIEW))
+#define ANACONDA_DISK_OVERVIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ANACONDA_TYPE_DISK_OVERVIEW, AnacondaDiskOverviewClass))
+
+typedef struct _AnacondaDiskOverview AnacondaDiskOverview;
+typedef struct _AnacondaDiskOverviewClass AnacondaDiskOverviewClass;
+typedef struct _AnacondaDiskOverviewPrivate AnacondaDiskOverviewPrivate;
+
+/**
+ * AnacondaDiskOverview:
+ *
+ * The AnacondaDiskOverview struct contains only private fields and should not
+ * be directly accessed.
+ */
+struct _AnacondaDiskOverview {
+ GtkEventBox parent;
+
+ /*< private >*/
+ AnacondaDiskOverviewPrivate *priv;
+};
+
+/**
+ * AnacondaDiskOverviewClass:
+ * @parent_class: The object class structure needs to be the first element in
+ * the widget class structure in order for the class mechanism
+ * to work correctly. This allows a AnacondaDiskOverviewClass
+ * pointer to be cast to a #GtkEventBox pointer.
+ */
+struct _AnacondaDiskOverviewClass {
+ GtkEventBoxClass parent_class;
+};
+
+GType anaconda_disk_overview_get_type (void);
+GtkWidget *anaconda_disk_overview_new ();
+
+gboolean anaconda_disk_overview_get_selected(AnacondaDiskOverview *widget);
+void anaconda_disk_overview_set_selected(AnacondaDiskOverview *widget, gboolean is_selected);
+
+G_END_DECLS
+
+#endif
diff --git a/widgets/src/HubWindow.c b/widgets/src/HubWindow.c
new file mode 100644
index 000000000..9707bb3fc
--- /dev/null
+++ b/widgets/src/HubWindow.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Chris Lumens <clumens@redhat.com>
+ */
+
+#include "BaseWindow.h"
+#include "HubWindow.h"
+#include "intl.h"
+
+/**
+ * SECTION: HubWindow
+ * @title: AnacondaHubWindow
+ * @short_description: Window for displaying a Hub
+ *
+ * A #AnacondaHubWindow is a top-level window that displays a hub on the
+ * entire screen. A Hub allows selection of multiple configuration spokes
+ * from a single interface, as well as a place to display current configuration
+ * selections.
+ *
+ * The window consists of three areas:
+ *
+ * - A navigation area in the top of the screen, inherited from #AnacondaBaseWindow.
+ *
+ * - A selection area in the middle of the screen, taking up a majority of the space.
+ * This is where spokes will be displayed and the user can decide what to do.
+ *
+ * - An action area on the bottom of the screen. This area is different for
+ * different kinds of hubs. It may have buttons, or it may have progress
+ * information.
+ *
+ * <refsect2 id="AnacondaHubWindow-BUILDER-UI"><title>AnacondaHubWindow as GtkBuildable</title>
+ * <para>
+ * The AnacondaHubWindow implementation of the #GtkBuildable interface exposes
+ * the @action_area and @scrolled_window as internal children with the names
+ * "action_area" and "scrolled_window". action_area, in this case, is largely
+ * there to give a box to contain both the scrolled_window and a #GtkButtonBox.
+ * </para>
+ * <example>
+ * <title>A <structname>AnacondaHubWindow</structname> UI definition fragment.</title>
+ * <programlisting><![CDATA[
+ * <object class="AnacondaHubWindow" id="hub1">
+ * <child internal-child="action_area">
+ * <object class="GtkVBox" id="vbox1">
+ * <child internal-child="scrolled_window">
+ * <object class="GtkScrolledWindow" id="window1">
+ * <child>...</child>
+ * </object>
+ * </child>
+ * <child>
+ * <object class="GtkHButtonBox" id="buttonbox1">
+ * <child>...</child>
+ * </object>
+ * </child>
+ * </object>
+ * </child>
+ * </object>
+ * ]]></programlisting>
+ * </example>
+ * </refsect2>
+ */
+
+struct _AnacondaHubWindowPrivate {
+ GtkWidget *scrolled_window;
+};
+
+static void anaconda_hub_window_buildable_init(GtkBuildableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE(AnacondaHubWindow, anaconda_hub_window, ANACONDA_TYPE_BASE_WINDOW,
+ G_IMPLEMENT_INTERFACE(GTK_TYPE_BUILDABLE, anaconda_hub_window_buildable_init))
+
+static void anaconda_hub_window_class_init(AnacondaHubWindowClass *klass) {
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ g_type_class_add_private(object_class, sizeof(AnacondaHubWindowPrivate));
+}
+
+/**
+ * anaconda_hub_window_new:
+ *
+ * Creates a new #AnacondaHubWindow, which is a window designed for displaying
+ * multiple spokes in one location.
+ *
+ * Returns: A new #AnacondaHubWindow.
+ */
+GtkWidget *anaconda_hub_window_new() {
+ return g_object_new(ANACONDA_TYPE_HUB_WINDOW, NULL);
+}
+
+static void anaconda_hub_window_init(AnacondaHubWindow *win) {
+ GtkWidget *action_area = anaconda_base_window_get_action_area(ANACONDA_BASE_WINDOW(win));
+
+ win->priv = G_TYPE_INSTANCE_GET_PRIVATE(win,
+ ANACONDA_TYPE_HUB_WINDOW,
+ AnacondaHubWindowPrivate);
+
+ win->priv->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(win->priv->scrolled_window),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+
+ gtk_box_pack_start(GTK_BOX(action_area), win->priv->scrolled_window, TRUE, TRUE, 0);
+}
+
+/**
+ * anaconda_hub_window_get_spoke_area:
+ * @win: a #AnacondaHubWindow
+ *
+ * Returns the scrolled window of @win where spokes may be displayed
+ *
+ * Returns: (transfer none): The spoke area
+ *
+ * Since: 1.0
+ */
+GtkWidget *anaconda_hub_window_get_spoke_area(AnacondaHubWindow *win) {
+ return win->priv->scrolled_window;
+}
+
+static GtkBuildableIface *parent_buildable_iface;
+
+static GObject *
+anaconda_hub_window_buildable_get_internal_child (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ const gchar *childname) {
+ if (strcmp (childname, "scrolled_window") == 0)
+ return G_OBJECT(anaconda_hub_window_get_spoke_area(ANACONDA_HUB_WINDOW(buildable)));
+
+ return parent_buildable_iface->get_internal_child (buildable, builder, childname);
+}
+
+static void anaconda_hub_window_buildable_init (GtkBuildableIface *iface) {
+ parent_buildable_iface = g_type_interface_peek_parent (iface);
+ iface->get_internal_child = anaconda_hub_window_buildable_get_internal_child;
+}
diff --git a/widgets/src/HubWindow.h b/widgets/src/HubWindow.h
new file mode 100644
index 000000000..8040eb8fc
--- /dev/null
+++ b/widgets/src/HubWindow.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Chris Lumens <clumens@redhat.com>
+ */
+
+#ifndef _HUB_WINDOW_H
+#define _HUB_WINDOW_H
+
+#include <gtk/gtk.h>
+
+#include "BaseWindow.h"
+
+G_BEGIN_DECLS
+
+#define ANACONDA_TYPE_HUB_WINDOW (anaconda_hub_window_get_type())
+#define ANACONDA_HUB_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ANACONDA_TYPE_HUB_WINDOW, AnacondaHubWindow))
+#define ANACONDA_IS_HUB_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ANACONDA_TYPE_HUB_WINDOW))
+#define ANACONDA_HUB_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ANACONDA_TYPE_HUB_WINDOW, AnacondaHubWindowClass))
+#define ANACONDA_IS_HUB_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ANACONDA_TYPE_HUB_WINDOW))
+#define ANACONDA_HUB_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ANACONDA_TYPE_HUB_WINDOW, AnacondaHubWindowClass))
+
+typedef struct _AnacondaHubWindow AnacondaHubWindow;
+typedef struct _AnacondaHubWindowClass AnacondaHubWindowClass;
+typedef struct _AnacondaHubWindowPrivate AnacondaHubWindowPrivate;
+
+/**
+ * AnacondaHubWindow:
+ *
+ * The AnacondaHubWindow struct contains only private fields and should not
+ * be directly accessed.
+ */
+struct _AnacondaHubWindow {
+ AnacondaBaseWindow parent;
+
+ /*< private >*/
+ AnacondaHubWindowPrivate *priv;
+};
+
+/**
+ * AnacondaHubWindowClass:
+ * @parent_class: The object class structure needs to be the first element in
+ * the widget class structure in order for the class mechanism
+ * to work correctly. This allows an AnacondaHubWindowClass
+ * pointer to be cast to an #AnacondaBaseWindow pointer.
+ */
+struct _AnacondaHubWindowClass {
+ AnacondaBaseWindowClass parent_class;
+};
+
+GType anaconda_hub_window_get_type (void);
+GtkWidget *anaconda_hub_window_new ();
+GtkWidget *anaconda_hub_window_get_spoke_area (AnacondaHubWindow *win);
+
+G_END_DECLS
+
+#endif
diff --git a/widgets/src/Makefile.am b/widgets/src/Makefile.am
new file mode 100644
index 000000000..067da353b
--- /dev/null
+++ b/widgets/src/Makefile.am
@@ -0,0 +1,69 @@
+# Makefile.am for anaconda widgets
+#
+# Copyright (C) 2011 Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions of
+# the GNU General Public License v.2, or (at your option) any later version.
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY expressed or implied, including the implied warranties 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. Any Red Hat trademarks that are incorporated in the
+# source code or documentation are not subject to the GNU General Public
+# License and may only be used or replicated with the express permission of
+# Red Hat, Inc.
+#
+# Red Hat Author(s): Chris Lumens <clumens@redhat.com>
+#
+
+-include $(INTROSPECTION_MAKEFILE)
+
+ACLOCAL_AMFLAGS = -I m4
+
+DISTCHECK_CONFIGURE_FLAGS = --enable-introspection --enable-gtk-doc
+
+SOURCES = BaseWindow.c \
+ DiskOverview.c \
+ HubWindow.c \
+ SpokeSelector.c \
+ SpokeWindow.c \
+ StandaloneWindow.c
+
+HDRS = BaseWindow.h \
+ DiskOverview.h \
+ HubWindow.h \
+ SpokeSelector.h \
+ SpokeWindow.h \
+ StandaloneWindow.h
+
+noinst_HEADERS = gettext.h intl.h
+
+lib_LTLIBRARIES = libAnacondaWidgets.la
+libAnacondaWidgets_la_CFLAGS = $(GTK_CFLAGS) $(GLADEUI_CFLAGS) -Wall -g
+libAnacondaWidgets_la_LIBADD = $(GTK_LIBS) $(GLADEUI_LIBS)
+libAnacondaWidgets_la_LDFLAGS = $(LTLIBINTL)
+libAnacondaWidgets_la_SOURCES = $(SOURCES) $(HDRS) \
+ glade-adaptor.c
+
+lib_includedir=$(includedir)/AnacondaWidgets
+lib_include_HEADERS = $(HDRS)
+
+if HAVE_INTROSPECTION
+AnacondaWidgets-1.0.gir: libAnacondaWidgets.la
+
+AnacondaWidgets_1_0_gir_FILES = $(SOURCES) $(HDRS)
+AnacondaWidgets_1_0_gir_LIBS = libAnacondaWidgets.la
+AnacondaWidgets_1_0_gir_SCANNERFLAGS = --warn-all --identifier-prefix=Anaconda --symbol-prefix=anaconda
+AnacondaWidgets_1_0_gir_INCLUDES = Gtk-3.0
+
+INTROSPECTION_GIRS = AnacondaWidgets-1.0.gir
+
+typelibdir = $(libdir)/girepository-1.0
+typelib_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
+
+CLEANFILES = AnacondaWidgets-1.0.gir $(typelib_DATA)
+MAINTAINERCLEANFILES = Makefile.in
+endif
diff --git a/widgets/src/SpokeSelector.c b/widgets/src/SpokeSelector.c
new file mode 100644
index 000000000..7f0279405
--- /dev/null
+++ b/widgets/src/SpokeSelector.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Chris Lumens <clumens@redhat.com>
+ */
+
+#include "SpokeSelector.h"
+#include "intl.h"
+
+/**
+ * SECTION: SpokeSelector
+ * @title: AnacondaSpokeSelector
+ * @short_description: A graphical way to enter a configuration spoke
+ *
+ * A #AnacondaSpokeSelector is a widget that is associated with a Spoke and
+ * is packed into a grid on a Hub. A Spoke allows the user to configure one
+ * piece of system, and the associated selector both displays the current
+ * configuration and allows for a place to click to do further configuration.
+ *
+ * Some Spokes can have their initial configuration guessed, while others
+ * (specifically storage) requires the user to do something. For those that
+ * the user has not entered, the selector may be set as incomplete. See
+ * #anaconda_spoke_selector_get_incomplete and #anaconda_spoke_selector_set_incomplete.
+ *
+ * As a #AnacondaSpokeSelector is a subclass of a #GtkEventBox, any signals
+ * may be caught. However ::button-press-event is the most important one and
+ * should be how control is transferred to a Spoke.
+ */
+
+enum {
+ PROP_ICON = 1,
+ PROP_STATUS,
+ PROP_TITLE,
+};
+
+#define DEFAULT_ICON "gtk-missing-image"
+#define DEFAULT_STATUS "None"
+#define DEFAULT_TITLE "New Selector"
+
+struct _AnacondaSpokeSelectorPrivate {
+ gboolean is_incomplete;
+ GtkWidget *grid;
+ GtkWidget *icon;
+ GtkWidget *title_label;
+ GtkWidget *status_label;
+};
+
+G_DEFINE_TYPE(AnacondaSpokeSelector, anaconda_spoke_selector, GTK_TYPE_EVENT_BOX)
+
+static void anaconda_spoke_selector_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+static void anaconda_spoke_selector_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+
+static void anaconda_spoke_selector_class_init(AnacondaSpokeSelectorClass *klass) {
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ object_class->set_property = anaconda_spoke_selector_set_property;
+ object_class->get_property = anaconda_spoke_selector_get_property;
+
+ /**
+ * AnacondaSpokeSelector:icon:
+ *
+ * The :icon string is the standard icon name for an icon to display
+ * beside this spoke's :title. It is strongly suggested that one of the
+ * "-symbolic" icons be used, as that is consistent with the style we
+ * are going for.
+ *
+ * Since: 1.0
+ */
+ g_object_class_install_property(object_class,
+ PROP_ICON,
+ g_param_spec_string("icon",
+ P_("Icon"),
+ P_("Icon to appear next to the title"),
+ DEFAULT_ICON,
+ G_PARAM_READWRITE));
+
+ /**
+ * AnacondaSpokeSelector:status:
+ *
+ * The :status string is text displayed underneath the spoke's :title and
+ * also beside the :icon. This text very briefly describes what has been
+ * selected on the spoke associated with this selector. For instance, it
+ * might be set up to "English" for a language-related spoke.
+ *
+ * Since: 1.0
+ */
+ g_object_class_install_property(object_class,
+ PROP_STATUS,
+ g_param_spec_string("status",
+ P_("Status"),
+ P_("Status display"),
+ DEFAULT_STATUS,
+ G_PARAM_READWRITE));
+
+ /**
+ * AnacondaSpokeSelector:title:
+ *
+ * The :title of this selector, which will be displayed large and bold
+ * beside the :icon.
+ *
+ * Since: 1.0
+ */
+ g_object_class_install_property(object_class,
+ PROP_TITLE,
+ g_param_spec_string("title",
+ P_("Title"),
+ P_("The title of the spoke selector"),
+ DEFAULT_TITLE,
+ G_PARAM_READWRITE));
+
+ g_type_class_add_private(object_class, sizeof(AnacondaSpokeSelectorPrivate));
+}
+
+/**
+ * anaconda_spoke_selector_new:
+ *
+ * Creates a new #AnacondaSpokeSelector, which is a selectable display for a
+ * single spoke of an Anaconda hub. Many spokes may be put together into a
+ * grid, displaying everything that a user needs to do in one place.
+ *
+ * Returns: A new #AnacondaSpokeSelector.
+ */
+GtkWidget *anaconda_spoke_selector_new() {
+ return g_object_new(ANACONDA_TYPE_SPOKE_SELECTOR, NULL);
+}
+
+static void anaconda_spoke_selector_init(AnacondaSpokeSelector *spoke) {
+ char *markup;
+
+ spoke->priv = G_TYPE_INSTANCE_GET_PRIVATE(spoke,
+ ANACONDA_TYPE_SPOKE_SELECTOR,
+ AnacondaSpokeSelectorPrivate);
+
+ /* Set property defaults. */
+ spoke->priv->is_incomplete = FALSE;
+
+ /* Create the grid. */
+ spoke->priv->grid = gtk_grid_new();
+ gtk_grid_set_column_spacing(GTK_GRID(spoke->priv->grid), 6);
+
+ /* Create the icon. */
+ spoke->priv->icon = gtk_image_new_from_stock(DEFAULT_ICON, GTK_ICON_SIZE_DIALOG);
+
+ /* Create the title label. */
+ spoke->priv->title_label = gtk_label_new(NULL);
+ markup = g_markup_printf_escaped("<span weight='bold'>%s</span>", _(DEFAULT_TITLE));
+ gtk_label_set_markup(GTK_LABEL(spoke->priv->title_label), markup);
+ gtk_misc_set_alignment(GTK_MISC(spoke->priv->title_label), 0, 0);
+ g_free(markup);
+
+ /* Create the status label. */
+ spoke->priv->status_label = gtk_label_new(NULL);
+ markup = g_markup_printf_escaped("<span style='italic'>%s</span>", _(DEFAULT_STATUS));
+ gtk_label_set_markup(GTK_LABEL(spoke->priv->status_label), markup);
+ gtk_misc_set_alignment(GTK_MISC(spoke->priv->status_label), 0, 0);
+ g_free(markup);
+
+ /* Add everything to the grid, add the grid to the widget. */
+ gtk_grid_attach(GTK_GRID(spoke->priv->grid), spoke->priv->icon, 0, 0, 1, 2);
+ gtk_grid_attach(GTK_GRID(spoke->priv->grid), spoke->priv->title_label, 1, 0, 1, 1);
+ gtk_grid_attach(GTK_GRID(spoke->priv->grid), spoke->priv->status_label, 1, 1, 1, 1);
+
+ gtk_container_add(GTK_CONTAINER(spoke), spoke->priv->grid);
+}
+
+static void anaconda_spoke_selector_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) {
+ AnacondaSpokeSelector *widget = ANACONDA_SPOKE_SELECTOR(object);
+ AnacondaSpokeSelectorPrivate *priv = widget->priv;
+
+ switch(prop_id) {
+ case PROP_ICON:
+ g_value_set_object (value, (GObject *)priv->icon);
+ break;
+
+ case PROP_STATUS:
+ g_value_set_string (value, gtk_label_get_text(GTK_LABEL(priv->status_label)));
+ break;
+
+ case PROP_TITLE:
+ g_value_set_string (value, gtk_label_get_text(GTK_LABEL(priv->title_label)));
+ break;
+ }
+}
+
+static void anaconda_spoke_selector_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) {
+ AnacondaSpokeSelector *widget = ANACONDA_SPOKE_SELECTOR(object);
+ AnacondaSpokeSelectorPrivate *priv = widget->priv;
+
+ switch(prop_id) {
+ case PROP_ICON:
+ gtk_image_set_from_icon_name(GTK_IMAGE(priv->icon), g_value_get_string(value), GTK_ICON_SIZE_DIALOG);
+ break;
+
+ case PROP_STATUS: {
+ char *markup = g_markup_printf_escaped("<span style='italic'>%s</span>", g_value_get_string(value));
+ gtk_label_set_markup(GTK_LABEL(priv->status_label), markup);
+ g_free(markup);
+ break;
+ }
+
+ case PROP_TITLE: {
+ char *markup = g_markup_printf_escaped("<span weight='bold'>%s</span>", g_value_get_string(value));
+ gtk_label_set_markup(GTK_LABEL(priv->title_label), markup);
+ g_free(markup);
+ break;
+ }
+ }
+}
+
+/**
+ * anaconda_spoke_selector_get_incomplete:
+ * @spoke: a #AnacondaSpokeSelector
+ *
+ * Returns whether or not this spoke has been completed.
+ *
+ * Returns: Whether @spoke has been completed by the user.
+ *
+ * Since: 1.0
+ */
+gboolean anaconda_spoke_selector_get_incomplete(AnacondaSpokeSelector *spoke) {
+ return spoke->priv->is_incomplete;
+}
+
+/**
+ * anaconda_spoke_selector_set_incomplete:
+ * @spoke: a #AnacondaSpokeSelector
+ * @is_incomplete: %TRUE if this spoke still needs to be visited.
+ *
+ * Specifies whether this spoke must still be visited by the user. If so, this
+ * means anaconda doesn't have enough information to continue and the user must
+ * take some action. A warning icon will be displayed alongside the spoke's
+ * icon, and the continue button will be disabled.
+ *
+ * Since: 1.0
+ */
+void anaconda_spoke_selector_set_incomplete(AnacondaSpokeSelector *spoke, gboolean is_incomplete) {
+ spoke->priv->is_incomplete = is_incomplete;
+}
diff --git a/widgets/src/SpokeSelector.h b/widgets/src/SpokeSelector.h
new file mode 100644
index 000000000..4a2111d25
--- /dev/null
+++ b/widgets/src/SpokeSelector.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Chris Lumens <clumens@redhat.com>
+ */
+
+#ifndef _SPOKE_SELECTOR_H
+#define _SPOKE_SELECTOR_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define ANACONDA_TYPE_SPOKE_SELECTOR (anaconda_spoke_selector_get_type())
+#define ANACONDA_SPOKE_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ANACONDA_TYPE_SPOKE_SELECTOR, AnacondaSpokeSelector))
+#define ANACONDA_IS_SPOKE_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj)), ANACONDA_TYPE_SPOKE_SELECTOR)
+#define ANACONDA_SPOKE_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ANACONDA_TYPE_SPOKE_SELECTOR, AnacondaSpokeSelectorClass))
+#define ANACONDA_IS_SPOKE_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ANACONDA_TYPE_SPOKE_SELECTOR))
+#define ANACONDA_SPOKE_SELECTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ANACONDA_TYPE_SPOKE_SELECTOR, AnacondaSpokeSelectorClass))
+
+typedef struct _AnacondaSpokeSelector AnacondaSpokeSelector;
+typedef struct _AnacondaSpokeSelectorClass AnacondaSpokeSelectorClass;
+typedef struct _AnacondaSpokeSelectorPrivate AnacondaSpokeSelectorPrivate;
+
+/**
+ * AnacondaSpokeSelector:
+ *
+ * The AnacondaSpokeSelector struct contains only private fields and should
+ * not be directly accessed.
+ */
+struct _AnacondaSpokeSelector {
+ GtkEventBox parent;
+
+ /*< private >*/
+ AnacondaSpokeSelectorPrivate *priv;
+};
+
+/**
+ * AnacondaSpokeSelectorClass:
+ * @parent_class: The object class structure needs to be the first element in
+ * the widget class structure in order for the class mechanism
+ * to work correctly. This allows an AnacondaSpokeSelectorClass
+ * pointer to be cast to a #GtkEventBox pointer.
+ */
+struct _AnacondaSpokeSelectorClass {
+ GtkEventBoxClass parent_class;
+};
+
+GType anaconda_spoke_selector_get_type (void);
+GtkWidget *anaconda_spoke_selector_new ();
+gboolean anaconda_spoke_selector_get_incomplete (AnacondaSpokeSelector *spoke);
+void anaconda_spoke_selector_set_incomplete (AnacondaSpokeSelector *spoke, gboolean is_incomplete);
+
+G_END_DECLS
+
+#endif
diff --git a/widgets/src/SpokeWindow.c b/widgets/src/SpokeWindow.c
new file mode 100644
index 000000000..6b6adb29a
--- /dev/null
+++ b/widgets/src/SpokeWindow.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Chris Lumens <clumens@redhat.com>
+ */
+
+#include "BaseWindow.h"
+#include "SpokeWindow.h"
+#include "intl.h"
+
+/**
+ * SECTION: SpokeWindow
+ * @title: AnacondaSpokeWindow
+ * @short_description: Window for displaying single spokes
+ *
+ * A #AnacondaSpokeWindow is a top-level window that displays a single spoke
+ * on the entire screen. Examples include the keyboard and language
+ * configuration screens off the first hub.
+ *
+ * The iwndow consists of two areas:
+ *
+ * - A navigation area in the top of the screen, inherited from #AnacondaBaseWindow
+ * and augmented with a back button.
+ *
+ * - An action area in the rest of the screen, taking up a majority of the
+ * space. This is where widgets will be added and the user will do things.
+ */
+
+enum {
+ SIGNAL_BACK_CLICKED,
+ LAST_SIGNAL
+};
+
+static guint window_signals[LAST_SIGNAL] = { 0 };
+
+struct _AnacondaSpokeWindowPrivate {
+ GtkWidget *back_button;
+};
+
+static void anaconda_spoke_window_back_clicked(GtkButton *button,
+ AnacondaSpokeWindow *win);
+
+G_DEFINE_TYPE(AnacondaSpokeWindow, anaconda_spoke_window, ANACONDA_TYPE_BASE_WINDOW)
+
+static void anaconda_spoke_window_class_init(AnacondaSpokeWindowClass *klass) {
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ klass->back_clicked = NULL;
+
+ /**
+ * AnacondaSpokeWindow::back-clicked:
+ * @window: the window that received the signal
+ *
+ * Emitted when the back button has been activated (pressed and released).
+ *
+ * Since: 1.0
+ */
+ window_signals[SIGNAL_BACK_CLICKED] = g_signal_new("back-clicked",
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET(AnacondaSpokeWindowClass, back_clicked),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ g_type_class_add_private(object_class, sizeof(AnacondaSpokeWindowPrivate));
+}
+
+/**
+ * anaconda_spoke_window_new:
+ *
+ * Creates a new #AnacondaSpokeWindow, which is a window designed for
+ * displaying a single spoke, such as the keyboard or network configuration
+ * screens.
+ *
+ * Returns: A new #AnacondaSpokeWindow.
+ */
+GtkWidget *anaconda_spoke_window_new() {
+ return g_object_new(ANACONDA_TYPE_SPOKE_WINDOW, NULL);
+}
+
+static void anaconda_spoke_window_init(AnacondaSpokeWindow *win) {
+ GtkWidget *nav_area;
+
+ win->priv = G_TYPE_INSTANCE_GET_PRIVATE(win,
+ ANACONDA_TYPE_SPOKE_WINDOW,
+ AnacondaSpokeWindowPrivate);
+
+ /* Set some default properties. */
+ gtk_window_set_modal(GTK_WINDOW(win), TRUE);
+
+ /* Create the buttons. */
+ win->priv->back_button = gtk_button_new_with_mnemonic(_("_Back to install summary"));
+ gtk_widget_set_halign(GTK_WIDGET(win->priv->back_button), GTK_ALIGN_START);
+
+ /* Hook up some signals for that button. The signal handlers here will
+ * just raise our own custom signals for the whole window.
+ */
+ g_signal_connect(win->priv->back_button, "clicked",
+ G_CALLBACK(anaconda_spoke_window_back_clicked), win);
+
+ /* And then put the back button into the navigation area. */
+ nav_area = anaconda_base_window_get_nav_area(ANACONDA_BASE_WINDOW(win));
+ gtk_grid_attach(GTK_GRID(nav_area), win->priv->back_button, 0, 1, 1, 1);
+}
+
+static void anaconda_spoke_window_back_clicked(GtkButton *button,
+ AnacondaSpokeWindow *win) {
+ g_signal_emit(win, window_signals[SIGNAL_BACK_CLICKED], 0);
+}
diff --git a/widgets/src/SpokeWindow.h b/widgets/src/SpokeWindow.h
new file mode 100644
index 000000000..b6e1739d3
--- /dev/null
+++ b/widgets/src/SpokeWindow.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Chris Lumens <clumens@redhat.com>
+ */
+
+#ifndef _SPOKE_WINDOW_H
+#define _SPOKE_WINDOW_H
+
+#include <gtk/gtk.h>
+
+#include "BaseWindow.h"
+
+G_BEGIN_DECLS
+
+#define ANACONDA_TYPE_SPOKE_WINDOW (anaconda_spoke_window_get_type())
+#define ANACONDA_SPOKE_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ANACONDA_TYPE_SPOKE_WINDOW, AnacondaSpokeWindow))
+#define ANACONDA_IS_SPOKE_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ANACONDA_TYPE_SPOKE_WINDOW))
+#define ANACONDA_SPOKE_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ANACONDA_TYPE_SPOKE_WINDOW, AnacondaSpokeWindowClass))
+#define ANACONDA_IS_SPOKE_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ANACONDA_TYPE_SPOKE_WINDOW))
+#define ANACONDA_SPOKE_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ANACONDA_TYPE_SPOKE_WINDOW, AnacondaSpokeWindowClass))
+
+typedef struct _AnacondaSpokeWindow AnacondaSpokeWindow;
+typedef struct _AnacondaSpokeWindowClass AnacondaSpokeWindowClass;
+typedef struct _AnacondaSpokeWindowPrivate AnacondaSpokeWindowPrivate;
+
+/**
+ * AnacondaSpokeWindow:
+ *
+ * The AnacondaSpokeWindow struct contains only private fields and should not
+ * be directly accessed.
+ */
+struct _AnacondaSpokeWindow {
+ AnacondaBaseWindow parent;
+
+ /*< private >*/
+ AnacondaSpokeWindowPrivate *priv;
+};
+
+/**
+ * AnacondaSpokeWindowClass:
+ * @parent_class: The object class structure needs to be the first element in
+ * the widget class structure in order for the class mechanism
+ * to work correctly. This allows an AnacondaSpokeWindowClass
+ * pointer to be cast to an #AnacondaBaseWindow pointer.
+ * @back_clicked: Function pointer called when the #AnacondaSpokeWindow::back-clicked
+ * signal is emitted.
+ */
+struct _AnacondaSpokeWindowClass {
+ AnacondaBaseWindowClass parent_class;
+
+ void (* back_clicked) (AnacondaSpokeWindow *window);
+};
+
+GType anaconda_spoke_window_get_type (void);
+GtkWidget *anaconda_spoke_window_new ();
+
+G_END_DECLS
+
+#endif
diff --git a/widgets/src/StandaloneWindow.c b/widgets/src/StandaloneWindow.c
new file mode 100644
index 000000000..6ba4031f0
--- /dev/null
+++ b/widgets/src/StandaloneWindow.c
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Chris Lumens <clumens@redhat.com>
+ */
+
+#include "BaseWindow.h"
+#include "StandaloneWindow.h"
+#include "intl.h"
+
+/**
+ * SECTION: StandaloneWindow
+ * @title: AnacondaStandaloneWindow
+ * @short_description: Window for displaying standalone spokes
+ *
+ * A #AnacondaStandaloneWindow is a top-level window that displays a standalone
+ * spoke. A standalone spoke is like a normal spoke, but is not entered via a
+ * hub. Instead, it is displayed by itself. Examples include the welcome and
+ * network configuration screens at the beginning of installation.
+ *
+ * The window consist of three areas:
+ *
+ * - A navigation area in the top of the screen, inherited from #AnacondaBaseWindow.
+ *
+ * - A button box at the bottom of the screen, with Quit and Continue buttons.
+ * The Continue button may not be enabled until required information is
+ * entered by the user.
+ *
+ * - An action area in the middle of the screen, taking up a majority of the
+ * space. This is where widgets will be added and the user will do things.
+ */
+
+enum {
+ SIGNAL_QUIT_CLICKED,
+ SIGNAL_CONTINUE_CLICKED,
+ LAST_SIGNAL
+};
+
+static guint window_signals[LAST_SIGNAL] = { 0 };
+
+struct _AnacondaStandaloneWindowPrivate {
+ GtkWidget *button_box;
+ GtkWidget *continue_button, *quit_button;
+};
+
+static void anaconda_standalone_window_quit_clicked(GtkButton *button,
+ AnacondaStandaloneWindow *win);
+static void anaconda_standalone_window_continue_clicked(GtkButton *button,
+ AnacondaStandaloneWindow *win);
+
+G_DEFINE_TYPE(AnacondaStandaloneWindow, anaconda_standalone_window, ANACONDA_TYPE_BASE_WINDOW)
+
+static void anaconda_standalone_window_class_init(AnacondaStandaloneWindowClass *klass) {
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ klass->quit_clicked = NULL;
+ klass->continue_clicked = NULL;
+
+ /**
+ * AnacondaStandaloneWindow::quit-clicked:
+ * @window: the window that received the signal
+ *
+ * Emitted when the quit button has been activated (pressed and released).
+ *
+ * Since: 1.0
+ */
+ window_signals[SIGNAL_QUIT_CLICKED] = g_signal_new("quit-clicked",
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET(AnacondaStandaloneWindowClass, quit_clicked),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ /**
+ * AnacondaStandaloneWindow::continue-clicked:
+ * @window: the window that received the signal
+ *
+ * Emitted when the continue button has been activated (pressed and released).
+ *
+ * Since: 1.0
+ */
+ window_signals[SIGNAL_CONTINUE_CLICKED] = g_signal_new("continue-clicked",
+ G_TYPE_FROM_CLASS(object_class),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET(AnacondaStandaloneWindowClass, continue_clicked),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ g_type_class_add_private(object_class, sizeof(AnacondaStandaloneWindowPrivate));
+}
+
+/**
+ * anaconda_standalone_window_new:
+ *
+ * Creates a new #AnacondaStandaloneWindow, which is a window designed for
+ * displaying a standalone spoke, such as the welcome screen or network
+ * configuration.
+ *
+ * Returns: A new #AnacondaStandaloneWindow.
+ */
+GtkWidget *anaconda_standalone_window_new() {
+ return g_object_new(ANACONDA_TYPE_STANDALONE_WINDOW, NULL);
+}
+
+static void anaconda_standalone_window_init(AnacondaStandaloneWindow *win) {
+ /* This is the section of the parent AnacondaBaseWindow class where we
+ * put buttons, dialogs, etc. We need a reference to it here to pac
+ * things into.
+ */
+ GtkWidget *action_area = anaconda_base_window_get_action_area(ANACONDA_BASE_WINDOW(win));
+
+ win->priv = G_TYPE_INSTANCE_GET_PRIVATE(win,
+ ANACONDA_TYPE_STANDALONE_WINDOW,
+ AnacondaStandaloneWindowPrivate);
+
+ /* Create the buttons. */
+ win->priv->quit_button = gtk_button_new_with_mnemonic(_("_QUIT"));
+ win->priv->continue_button = gtk_button_new_with_mnemonic(_("_CONTINUE"));
+
+ /* Hook up some signals for those buttons. The signal handlers here will
+ * just raise our own custom signals for the whole window.
+ */
+ g_signal_connect(win->priv->quit_button, "clicked",
+ G_CALLBACK(anaconda_standalone_window_quit_clicked), win);
+ g_signal_connect(win->priv->continue_button, "clicked",
+ G_CALLBACK(anaconda_standalone_window_continue_clicked), win);
+
+ /* Create the button box and pack the buttons into it. */
+ win->priv->button_box = gtk_hbutton_box_new();
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(win->priv->button_box), GTK_BUTTONBOX_EDGE);
+ gtk_container_add(GTK_CONTAINER(win->priv->button_box), win->priv->quit_button);
+ gtk_container_add(GTK_CONTAINER(win->priv->button_box), win->priv->continue_button);
+
+ /* Pack the button box into the action_area. */
+ gtk_box_pack_end(GTK_BOX(action_area), win->priv->button_box, FALSE, TRUE, 0);
+}
+
+static void anaconda_standalone_window_quit_clicked(GtkButton *button,
+ AnacondaStandaloneWindow *win) {
+ g_signal_emit(win, window_signals[SIGNAL_QUIT_CLICKED], 0);
+}
+
+static void anaconda_standalone_window_continue_clicked(GtkButton *button,
+ AnacondaStandaloneWindow *win) {
+ g_signal_emit(win, window_signals[SIGNAL_CONTINUE_CLICKED], 0);
+}
+
+/**
+ * anaconda_standalone_window_get_may_continue:
+ * @win: a #AnacondaStandaloneWindow
+ *
+ * Returns whether or not the continue button is sensitive (thus, whether the
+ * user may continue forward from this window).
+ *
+ * Returns: Whether the continue button on @win is sensitive.
+ *
+ * Since: 1.0
+ */
+gboolean anaconda_standalone_window_get_may_continue(AnacondaStandaloneWindow *win) {
+ return gtk_widget_get_sensitive(win->priv->continue_button);
+}
+
+/**
+ * anaconda_standalone_window_set_may_continue:
+ * @win: a #AnacondaStandaloneWindow
+ * @may_continue: %TRUE if this window's continue button should be sensitive.
+ *
+ * Specifies whether the user may continue forward from this window. If so,
+ * the continue button will be made sensitive. Windows default to continuable
+ * so you must set it as false if you want. The reason the user may not be
+ * able to continue is if there is required information the user must enter
+ * when no reasonable default may be given.
+ *
+ * Since: 1.0
+ */
+void anaconda_standalone_window_set_may_continue(AnacondaStandaloneWindow *win,
+ gboolean may_continue) {
+ gtk_widget_set_sensitive(win->priv->continue_button, may_continue);
+}
diff --git a/widgets/src/StandaloneWindow.h b/widgets/src/StandaloneWindow.h
new file mode 100644
index 000000000..b1ba02938
--- /dev/null
+++ b/widgets/src/StandaloneWindow.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Chris Lumens <clumens@redhat.com>
+ */
+
+#ifndef _STANDALONE_WINDOW_H
+#define _STANDALONE_WINDOW_H
+
+#include <gtk/gtk.h>
+
+#include "BaseWindow.h"
+
+G_BEGIN_DECLS
+
+#define ANACONDA_TYPE_STANDALONE_WINDOW (anaconda_standalone_window_get_type())
+#define ANACONDA_STANDALONE_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ANACONDA_TYPE_STANDALONE_WINDOW, AnacondaStandaloneWindow))
+#define ANACONDA_IS_STANDALONE_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ANACONDA_TYPE_STANDALONE_WINDOW))
+#define ANACONDA_STANDALONE_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ANACONDA_TYPE_STANDALONE_WINDOW, AnacondaStandaloneWindowClass))
+#define ANACONDA_IS_STANDALONE_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ANACONDA_TYPE_STANDALONE_WINDOW))
+#define ANACONDA_STANDALONE_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ANACONDA_TYPE_STANDALONE_WINDOW, AnacondaStandaloneWindowClass))
+
+typedef struct _AnacondaStandaloneWindow AnacondaStandaloneWindow;
+typedef struct _AnacondaStandaloneWindowClass AnacondaStandaloneWindowClass;
+typedef struct _AnacondaStandaloneWindowPrivate AnacondaStandaloneWindowPrivate;
+
+/**
+ * AnacondaStandaloneWindow:
+ *
+ * The AnacondaStandaloneWindow struct contains only private fields and should not
+ * be directly accessed.
+ */
+struct _AnacondaStandaloneWindow {
+ AnacondaBaseWindow parent;
+
+ /*< private >*/
+ AnacondaStandaloneWindowPrivate *priv;
+};
+
+/**
+ * AnacondaStandaloneWindowClass:
+ * @parent_class: The object class structure needs to be the first element in
+ * the widget class structure in order for the class mechanism
+ * to work correctly. This allows an AnacondaStandaloneWindowClass
+ * pointer to be cast to an #AnacondaBaseWindow pointer.
+ * @quit_clicked: Function pointer called when the #AnacondaStandaloneWindow::quit-clicked
+ * signal is emitted.
+ * @continue_clicked: Function pointer called when the #AnacondaStandaloneWindow::continue-clicked
+ * signal is emitted.
+ */
+struct _AnacondaStandaloneWindowClass {
+ AnacondaBaseWindowClass parent_class;
+
+ void (* quit_clicked) (AnacondaStandaloneWindow *window);
+ void (* continue_clicked) (AnacondaStandaloneWindow *window);
+};
+
+GType anaconda_standalone_window_get_type (void);
+GtkWidget *anaconda_standalone_window_new ();
+gboolean anaconda_standalone_window_get_may_continue (AnacondaStandaloneWindow *win);
+void anaconda_standalone_window_set_may_continue (AnacondaStandaloneWindow *win, gboolean may_continue);
+
+G_END_DECLS
+
+#endif
diff --git a/widgets/src/glade-adaptor.c b/widgets/src/glade-adaptor.c
new file mode 100644
index 000000000..866d7950c
--- /dev/null
+++ b/widgets/src/glade-adaptor.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Chris Lumens <clumens@redhat.com>
+ */
+
+/* This file contains code called by glade when it creates, reads, writes, or
+ * otherwise manipulates anaconda-specific widgets. Each function in this file
+ * that glade should call must be referenced in a glade-widget-class stanza of
+ * glade/AnacondaWidgets.xml.
+ *
+ * This file relies on a lot of halfway documented magic. Good luck.
+ */
+#include <gladeui/glade-project.h>
+#include <gladeui/glade-widget.h>
+#include <gladeui/glade-widget-adaptor.h>
+
+#include <gtk/gtk.h>
+
+#include "BaseWindow.h"
+#include "SpokeWindow.h"
+
+void anaconda_standalone_window_post_create(GladeWidgetAdaptor *adaptor,
+ GObject *object, GladeCreateReason reason) {
+ GladeWidget *widget, *actionarea_widget;
+ AnacondaBaseWindow *window;
+
+ if (reason != GLADE_CREATE_USER)
+ return;
+
+ g_return_if_fail(ANACONDA_IS_BASE_WINDOW(object));
+
+ widget = glade_widget_get_from_gobject(GTK_WIDGET(object));
+ if (!widget)
+ return;
+
+ window = ANACONDA_BASE_WINDOW(object);
+ actionarea_widget = glade_widget_get_from_gobject(anaconda_base_window_get_action_area(window));
+
+ if (ANACONDA_IS_SPOKE_WINDOW(object))
+ glade_widget_property_set(actionarea_widget, "size", 2);
+ else
+ glade_widget_property_set(actionarea_widget, "size", 3);
+}
+
+void anaconda_standalone_window_write_widget(GladeWidgetAdaptor *adaptor,
+ GladeWidget *widget,
+ GladeXmlContext *context, GladeXmlNode *node) {
+ GladeProperty *startup_id_prop;
+
+ if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET))
+ return;
+
+ /* Set a bogus startup-id in the output XML file. This doesn't really seem
+ * like it should be necessary, but glade will crash if I don't.
+ */
+ startup_id_prop = glade_widget_get_property(widget, "startup-id");
+ glade_property_set(startup_id_prop, "filler");
+ glade_property_write(startup_id_prop, context, node);
+
+ /* Chain up and write the parent's properties */
+ GWA_GET_CLASS (GTK_TYPE_WINDOW)->write_widget (adaptor, widget, context, node);
+}
diff --git a/widgets/src/intl.h b/widgets/src/intl.h
new file mode 100644
index 000000000..30bca59dc
--- /dev/null
+++ b/widgets/src/intl.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Chris Lumens <clumens@redhat.com>
+ */
+
+#ifndef _INTL_H
+#define _INTL_H
+
+#include "../config.h"
+#include "gettext.h"
+
+#define _(x) gettext(x)
+
+#ifdef ENABLE_NLS
+#define P_(String) g_dgettext(GETTEXT_PACKAGE "-properties",String)
+#else
+#define P_(String) (String)
+#endif
+
+#endif