summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorP. F. Chimento <philip.chimento@gmail.com>2013-05-03 18:33:05 +0200
committerP. F. Chimento <philip.chimento@gmail.com>2013-05-13 16:41:15 +0200
commit5e9dcb466c5506a8ea4b52e1eb452df6d806c823 (patch)
treec896145fc89115c6ffc37484f460a0e5330f7964
parent55be2cb2bd90e55832af798c05e699c99fc3d38f (diff)
Implement EosPageManager
Minimum functionality for EosPageManager. Currently uses a GtkNotebook internally until we decide what to do regarding GtkStack. (Philip; map/unmap Matt, Patrick)
-rw-r--r--docs/reference/endless/Makefile.am3
-rw-r--r--docs/reference/endless/endless-docs.xml1
-rw-r--r--docs/reference/endless/endless-sections.txt24
-rw-r--r--endless/Makefile.am2
-rw-r--r--endless/endless.h1
-rw-r--r--endless/eospagemanager.c795
-rw-r--r--endless/eospagemanager.h97
-rw-r--r--test/Makefile.am1
-rw-r--r--test/run-tests.c1
-rw-r--r--test/run-tests.h1
-rw-r--r--test/smoke-tests/app-window.js42
-rw-r--r--test/test-page-manager.c333
12 files changed, 1297 insertions, 4 deletions
diff --git a/docs/reference/endless/Makefile.am b/docs/reference/endless/Makefile.am
index 01b7069..ec57db9 100644
--- a/docs/reference/endless/Makefile.am
+++ b/docs/reference/endless/Makefile.am
@@ -16,7 +16,8 @@ DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml
DOC_SOURCE_DIR=$(top_srcdir)/endless
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
-SCANGOBJ_OPTIONS=
+SCANGOBJ_OPTIONS= \
+ --query-child-properties=gtk_container_class_list_child_properties
# Extra options to supply to gtkdoc-scan.
# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
diff --git a/docs/reference/endless/endless-docs.xml b/docs/reference/endless/endless-docs.xml
index 13866ca..38d4ae3 100644
--- a/docs/reference/endless/endless-docs.xml
+++ b/docs/reference/endless/endless-docs.xml
@@ -19,6 +19,7 @@
<title>Open Endless SDK reference (C API)</title>
<xi:include href="xml/application.xml"/>
<xi:include href="xml/window.xml"/>
+ <xi:include href="xml/page-manager.xml"/>
<!--<xi:include href="xml/hello.xml"/>-->
</chapter>
diff --git a/docs/reference/endless/endless-sections.txt b/docs/reference/endless/endless-sections.txt
index 8978d4d..4024e77 100644
--- a/docs/reference/endless/endless-sections.txt
+++ b/docs/reference/endless/endless-sections.txt
@@ -38,3 +38,27 @@ eos_window_get_type
<SUBSECTION Private>
EosWindowPrivate
</SECTION>
+
+<SECTION>
+<FILE>page-manager</FILE>
+EosPageManager
+eos_page_manager_new
+eos_page_manager_get_visible_page
+eos_page_manager_set_visible_page
+eos_page_manager_get_visible_page_name
+eos_page_manager_set_visible_page_name
+eos_page_manager_get_page_name
+eos_page_manager_set_page_name
+eos_page_manager_remove_page_by_name
+<SUBSECTION Standard>
+EOS_IS_PAGE_MANAGER
+EOS_IS_PAGE_MANAGER_CLASS
+EOS_PAGE_MANAGER
+EOS_PAGE_MANAGER_CLASS
+EOS_PAGE_MANAGER_GET_CLASS
+EOS_TYPE_PAGE_MANAGER
+EosPageManagerClass
+eos_page_manager_get_type
+<SUBSECTION Private>
+EosPageManagerPrivate
+</SECTION> \ No newline at end of file
diff --git a/endless/Makefile.am b/endless/Makefile.am
index 4ccd55d..a313905 100644
--- a/endless/Makefile.am
+++ b/endless/Makefile.am
@@ -7,6 +7,7 @@ endless_private_installed_headers = \
endless/eosapplication.h \
endless/eosenums.h \
endless/eosmacros.h \
+ endless/eospagemanager.h \
endless/eostypes.h \
endless/eoswindow.h
@@ -14,6 +15,7 @@ endless_library_sources = \
endless/eosapplication.c \
endless/eoshello.c \
endless/eosinit.c endless/eosinit-private.h \
+ endless/eospagemanager.c \
endless/eostopbar.c endless/eostopbar-private.h \
endless/eoswindow.c
diff --git a/endless/endless.h b/endless/endless.h
index 6bf4f29..9f5706c 100644
--- a/endless/endless.h
+++ b/endless/endless.h
@@ -13,6 +13,7 @@ G_BEGIN_DECLS
/* Pull in other header files */
#include "eostypes.h"
#include "eosapplication.h"
+#include "eospagemanager.h"
#include "eoswindow.h"
#undef _EOS_SDK_INSIDE_ENDLESS_H
diff --git a/endless/eospagemanager.c b/endless/eospagemanager.c
new file mode 100644
index 0000000..4d847b0
--- /dev/null
+++ b/endless/eospagemanager.c
@@ -0,0 +1,795 @@
+/* Copyright 2013 Endless Mobile, Inc. */
+
+#include "config.h"
+#include "eospagemanager.h"
+
+#include <gtk/gtk.h>
+
+#include <string.h>
+
+/**
+ * SECTION:page-manager
+ * @short_description: Controlling the flow of your application
+ * @title: Page Manager
+ *
+ * Your users experience your application as a series of
+ * <emphasis>pages</emphasis> &mdash; screens that present a small amount
+ * of information or show one feature before moving on to the next page
+ * or a previous page.
+ *
+ * The <emphasis>page manager</emphasis> controls how these pages relate to
+ * each other.
+ * There are several different page managers available, each representing a
+ * different user interaction.
+ * The default page manager, described in this section of the manual, lets you
+ * add any number of pages and switch between them however you like, but there
+ * are also other, more specialized ones:
+ * for example, the #EosSplashScreenPageManager displays a splash screen and
+ * later turns control over to a different page or page manager when you signal
+ * it to;
+ * and the #EosTabbedPageManager creates a tabbed interface in your window, much
+ * like the one in your browser.
+ *
+ * Each window has a page manager; one is created by default when you create
+ * the window, but you can replace it by a different one.
+ * You can also nest page managers, one inside the other, in order to create
+ * more complex application flows.
+ *
+ * A page can be any widget, most likely a container widget with other widgets
+ * inside it.
+ * To add a page to a page manager, call
+ * |[
+ * gtk_container_add (GTK_CONTAINER (page_manager), page);
+ * ]|
+ * If the added page is the only page, then the page manager will display it
+ * immediately.
+ * If the page manager was already displaying another page, then adding a new
+ * page will not change which page is displayed.
+ *
+ * To get information about how to display the pages, for example the background
+ * image to use, the page manager reads the page's <emphasis>child
+ * properties</emphasis>.
+ * These are like regular properties, but instead of modifying the page, they
+ * modify the relationship between the page and the page manager that contains
+ * it.
+ * Most pages have at least a name and a background image as child properties.
+ * You can add a page with child properties as follows:
+ * |[
+ * gtk_container_add_with_properties (GTK_CONTAINER (page_manager), page,
+ * "name", "front-page",
+ * "background", "image.jpg",
+ * NULL);
+ * ]|
+ * In Javascript, this has been simplified to use JSON:
+ * |[
+ * page_manager.add(page, {
+ * name: 'front-page',
+ * background: 'image.jpg'
+ * });
+ * ]|
+ * To remove a page, use gtk_container_remove() or
+ * eos_page_manager_remove_page_by_name().
+ * If the removed page was the only page, then the page manager will display
+ * nothing.
+ * If that page was currently displaying but was not the only page, then the
+ * page manager will display another page; which page is undefined.
+ *
+ * <warning>
+ * <para>Removing pages with gtk_container_remove() is currently broken due to
+ * a bug in GTK. Use eos_page_manager_remove_page_by_name() for the time
+ * being.</para>
+ * </warning>
+ *
+ * In general, it is convenient to refer to a page by its name when dealing with
+ * the page manager, so you should make a point of giving all your pages names.
+ */
+
+G_DEFINE_TYPE (EosPageManager, eos_page_manager, GTK_TYPE_CONTAINER)
+
+#define PAGE_MANAGER_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), EOS_TYPE_PAGE_MANAGER, EosPageManagerPrivate))
+
+typedef struct _EosPageManagerPageInfo EosPageManagerPageInfo;
+struct _EosPageManagerPageInfo
+{
+ GtkWidget *page;
+ gchar *name;
+};
+
+struct _EosPageManagerPrivate
+{
+ GtkWidget *stack;
+ GList *page_info; /* GList<EosPageManagerPageInfo> */
+ EosPageManagerPageInfo *visible_page_info;
+};
+
+enum
+{
+ PROP_0,
+ PROP_VISIBLE_PAGE,
+ PROP_VISIBLE_PAGE_NAME,
+ NPROPS
+};
+
+enum
+{
+ CHILD_PROP_0,
+ CHILD_PROP_NAME,
+ NCHILDPROPS
+};
+
+static GParamSpec *eos_page_manager_props[NPROPS] = { NULL, };
+static GParamSpec *eos_page_manager_child_props[NCHILDPROPS] = { NULL, };
+
+static void
+page_info_free (EosPageManagerPageInfo *info)
+{
+ g_free (info->name);
+ g_slice_free (EosPageManagerPageInfo, info);
+}
+
+/* Helper function for find_page_info_by_widget() */
+static gint
+page_info_widget_compare (const EosPageManagerPageInfo *info,
+ const GtkWidget *page)
+{
+ return (info->page != page); /* not orderable */
+}
+
+/*
+ * find_page_info_by_widget:
+ * @self: the page manager
+ * @page: the page to look for
+ *
+ * Searches for the page info corresponding to the child @page.
+ *
+ * Returns: the #EosPageManagerPageInfo for @page, or %NULL if @page is not a
+ * child of @self.
+ */
+static EosPageManagerPageInfo *
+find_page_info_by_widget (EosPageManager *self,
+ GtkWidget *page)
+{
+ GList *result = g_list_find_custom (self->priv->page_info, page,
+ (GCompareFunc)page_info_widget_compare);
+ if (result == NULL)
+ return NULL;
+ return result->data;
+}
+
+/* Helper function for find_page_info_by_name() */
+static gint
+page_info_name_compare (const EosPageManagerPageInfo *info,
+ const gchar *name)
+{
+ /* g_strcmp0() handles NULL */
+ return g_strcmp0(info->name, name);
+}
+
+/*
+ * find_page_info_by_name:
+ * @self: the page manager
+ * @name: the name to look for
+ *
+ * Searches for the page info corresponding to the child with name @name.
+ *
+ * Returns: the #EosPageManagerPageInfo for @name, or %NULL if @name is not the
+ * name of a child of @self.
+ */
+static EosPageManagerPageInfo *
+find_page_info_by_name (EosPageManager *self,
+ const gchar *name)
+{
+ GList *result = g_list_find_custom (self->priv->page_info, name,
+ (GCompareFunc)page_info_name_compare);
+ if (result == NULL)
+ return NULL;
+ return result->data;
+}
+
+/* Convenience function, since this warning occurs at several places */
+static void
+warn_page_widget_not_found (EosPageManager *self,
+ GtkWidget *page)
+{
+ g_critical ("Page at %p (type %s) is not a child of EosPageManager %p",
+ page,
+ g_type_name (G_OBJECT_TYPE (page)),
+ self);
+}
+
+/* Convenience function, since this warning occurs at several places */
+static void
+warn_page_name_not_found (EosPageManager *self,
+ const gchar *name)
+{
+ g_critical ("EosPageManager %p has no page named %s",
+ self,
+ name);
+}
+
+static void
+set_visible_page_from_info (EosPageManager *self,
+ EosPageManagerPageInfo *info)
+{
+ /* FIXME when porting to GtkStack */
+ GtkNotebook *stack_notebook = GTK_NOTEBOOK (self->priv->stack);
+ int page_pos = gtk_notebook_page_num (stack_notebook, info->page);
+ /* Invariant: if info is not NULL, then page must be in stack */
+ g_assert (page_pos != -1);
+ gtk_notebook_set_current_page (stack_notebook, page_pos);
+
+ self->priv->visible_page_info = info;
+
+ GObject *self_object = G_OBJECT (self);
+ g_object_notify(self_object, "visible-page");
+ g_object_notify(self_object, "visible-page-name");
+}
+
+static void
+eos_page_manager_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EosPageManager *self = EOS_PAGE_MANAGER (object);
+
+ switch (property_id)
+ {
+ case PROP_VISIBLE_PAGE:
+ g_value_set_object (value, eos_page_manager_get_visible_page (self));
+ break;
+
+ case PROP_VISIBLE_PAGE_NAME:
+ g_value_set_string (value, eos_page_manager_get_visible_page_name (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+eos_page_manager_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EosPageManager *self = EOS_PAGE_MANAGER (object);
+
+ switch (property_id)
+ {
+ case PROP_VISIBLE_PAGE:
+ eos_page_manager_set_visible_page (self, g_value_get_object (value));
+ break;
+
+ case PROP_VISIBLE_PAGE_NAME:
+ eos_page_manager_set_visible_page_name (self, g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+eos_page_manager_finalize (GObject *object)
+{
+ EosPageManager *self = EOS_PAGE_MANAGER (object);
+
+ g_list_foreach (self->priv->page_info, (GFunc)page_info_free, NULL);
+
+ G_OBJECT_CLASS (eos_page_manager_parent_class)->finalize (object);
+}
+
+static GtkSizeRequestMode
+eos_page_manager_get_request_mode (GtkWidget *widget)
+{
+ EosPageManager *self = EOS_PAGE_MANAGER (widget);
+
+ return gtk_widget_get_request_mode (self->priv->stack);
+}
+
+static void
+eos_page_manager_get_preferred_height (GtkWidget *widget,
+ gint *minimum,
+ gint *natural)
+{
+ EosPageManager *self = EOS_PAGE_MANAGER (widget);
+
+ gtk_widget_get_preferred_height (self->priv->stack, minimum, natural);
+}
+
+static void
+eos_page_manager_get_preferred_width_for_height (GtkWidget *widget,
+ gint height,
+ gint *minimum,
+ gint *natural)
+{
+ EosPageManager *self = EOS_PAGE_MANAGER (widget);
+
+ gtk_widget_get_preferred_height_for_width (self->priv->stack, height,
+ minimum, natural);
+}
+
+static void
+eos_page_manager_get_preferred_width (GtkWidget *widget,
+ gint *minimum,
+ gint *natural)
+{
+ EosPageManager *self = EOS_PAGE_MANAGER (widget);
+
+ gtk_widget_get_preferred_width (self->priv->stack, minimum, natural);
+}
+
+static void
+eos_page_manager_get_preferred_height_for_width (GtkWidget *widget,
+ gint width,
+ gint *minimum,
+ gint *natural)
+{
+ EosPageManager *self = EOS_PAGE_MANAGER (widget);
+
+ gtk_widget_get_preferred_height_for_width (self->priv->stack, width,
+ minimum, natural);
+}
+
+static void
+eos_page_manager_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ EosPageManager *self = EOS_PAGE_MANAGER (widget);
+
+ gtk_widget_set_allocation (widget, allocation);
+ gtk_widget_size_allocate (self->priv->stack, allocation);
+}
+
+static void
+eos_page_manager_show_all (GtkWidget *widget)
+{
+ EosPageManager *self = EOS_PAGE_MANAGER (widget);
+
+ GTK_WIDGET_CLASS (eos_page_manager_parent_class)->show (widget);
+ if (self->priv->stack != NULL)
+ gtk_widget_show_all (self->priv->stack);
+}
+
+static void
+eos_page_manager_map (GtkWidget *widget)
+{
+ EosPageManager *self = EOS_PAGE_MANAGER (widget);
+
+ if (self->priv->stack != NULL && gtk_widget_get_visible (self->priv->stack))
+ gtk_widget_map (self->priv->stack);
+ GTK_WIDGET_CLASS (eos_page_manager_parent_class)->map (widget);
+}
+
+static void
+eos_page_manager_unmap (GtkWidget *widget)
+{
+ EosPageManager *self = EOS_PAGE_MANAGER (widget);
+
+ if (self->priv->stack != NULL)
+ gtk_widget_unmap (self->priv->stack);
+ GTK_WIDGET_CLASS (eos_page_manager_parent_class)->unmap (widget);
+}
+
+static gboolean
+eos_page_manager_draw (GtkWidget *widget,
+ cairo_t *cr)
+{
+ EosPageManager *self = EOS_PAGE_MANAGER (widget);
+
+ if (self->priv->stack != NULL)
+ gtk_widget_draw (self->priv->stack, cr);
+
+ return FALSE;
+}
+
+static void
+eos_page_manager_add (GtkContainer *container,
+ GtkWidget *new_page)
+{
+ EosPageManager *self = EOS_PAGE_MANAGER (container);
+
+ gtk_container_add (GTK_CONTAINER (self->priv->stack), new_page);
+ EosPageManagerPageInfo *info = g_slice_new0 (EosPageManagerPageInfo);
+ info->page = new_page;
+ self->priv->page_info = g_list_prepend (self->priv->page_info, info);
+
+ /* If there were no pages yet, then this one must become the visible one */
+ if (self->priv->visible_page_info == NULL)
+ self->priv->visible_page_info = info;
+}
+
+static void
+eos_page_manager_remove (GtkContainer *container,
+ GtkWidget *page)
+{
+ EosPageManager *self = EOS_PAGE_MANAGER (container);
+
+ gtk_container_remove (GTK_CONTAINER (self->priv->stack), page);
+ EosPageManagerPageInfo *info = find_page_info_by_widget (self, page);
+ if (info == NULL)
+ {
+ warn_page_widget_not_found (self, page);
+ return;
+ }
+ self->priv->page_info = g_list_remove (self->priv->page_info, info);
+
+ /* If this was the only page */
+ if (self->priv->visible_page_info == info)
+ self->priv->visible_page_info = NULL;
+
+ page_info_free (info);
+}
+
+static void
+eos_page_manager_forall (GtkContainer *container,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer callback_data)
+{
+ EosPageManager *self = EOS_PAGE_MANAGER (container);
+
+ if (self->priv->stack == NULL)
+ return;
+
+ GtkContainerClass *stack_class = GTK_CONTAINER_GET_CLASS (self->priv->stack);
+ stack_class->forall (GTK_CONTAINER (self->priv->stack),
+ include_internals,
+ callback,
+ callback_data);
+ if (include_internals)
+ callback (self->priv->stack, callback_data);
+}
+
+static void
+eos_page_manager_get_child_property (GtkContainer *container,
+ GtkWidget *child,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EosPageManager *self = EOS_PAGE_MANAGER (container);
+
+ switch (property_id)
+ {
+ case CHILD_PROP_NAME:
+ g_value_set_string (value, eos_page_manager_get_page_name (self, child));
+ break;
+
+ default:
+ GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container,
+ property_id, pspec);
+ }
+}
+
+static void
+eos_page_manager_set_child_property (GtkContainer *container,
+ GtkWidget *child,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EosPageManager *self = EOS_PAGE_MANAGER (container);
+
+ switch (property_id)
+ {
+ case CHILD_PROP_NAME:
+ eos_page_manager_set_page_name (self, child, g_value_get_string (value));
+ break;
+
+ default:
+ GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container,
+ property_id, pspec);
+ }
+}
+
+static void
+eos_page_manager_class_init (EosPageManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (EosPageManagerPrivate));
+
+ object_class->get_property = eos_page_manager_get_property;
+ object_class->set_property = eos_page_manager_set_property;
+ object_class->finalize = eos_page_manager_finalize;
+
+ /* Pass all size requesting and allocation on to the stack */
+ widget_class->get_request_mode = eos_page_manager_get_request_mode;
+ widget_class->get_preferred_height = eos_page_manager_get_preferred_height;
+ widget_class->get_preferred_height_for_width =
+ eos_page_manager_get_preferred_height_for_width;
+ widget_class->get_preferred_width = eos_page_manager_get_preferred_width;
+ widget_class->get_preferred_width_for_height =
+ eos_page_manager_get_preferred_width_for_height;
+ widget_class->size_allocate = eos_page_manager_size_allocate;
+ widget_class->show_all = eos_page_manager_show_all;
+ widget_class->map = eos_page_manager_map;
+ widget_class->unmap = eos_page_manager_unmap;
+ widget_class->draw = eos_page_manager_draw;
+
+ container_class->add = eos_page_manager_add;
+ container_class->remove = eos_page_manager_remove;
+ container_class->forall = eos_page_manager_forall;
+ container_class->get_child_property = eos_page_manager_get_child_property;
+ container_class->set_child_property = eos_page_manager_set_child_property;
+
+ /**
+ * EosPageManager:visible-page:
+ *
+ * A reference to the page widget that is currently being displayed by the
+ * page manager.
+ * If the page manager has no pages, then this is %NULL.
+ */
+ eos_page_manager_props[PROP_VISIBLE_PAGE] =
+ g_param_spec_object ("visible-page", "Visible page",
+ "Page widget currently displaying in the page manager",
+ GTK_TYPE_WIDGET,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ /**
+ * EosPageManager:visible-page-name:
+ *
+ * The name of the page that is currently being displayed by the page manager.
+ * If the page manager has no pages, then this is %NULL.
+ * However, if there is a page currently being displayed but it has no name,
+ * then this is the empty string (<code>""</code>).
+ */
+ eos_page_manager_props[PROP_VISIBLE_PAGE_NAME] =
+ g_param_spec_string ("visible-page-name", "Visible page name",
+ "Name of page currently displaying in the page "
+ "manager",
+ "",
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, NPROPS,
+ eos_page_manager_props);
+
+ /**
+ * EosPageManager:name:
+ *
+ * The name of this page. Make sure to choose a unique name.
+ */
+ eos_page_manager_child_props[CHILD_PROP_NAME] =
+ g_param_spec_string ("name", "Name", "Unique ID for the page",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ gtk_container_class_install_child_property (container_class, CHILD_PROP_NAME,
+ eos_page_manager_child_props[CHILD_PROP_NAME]);
+}
+
+static void
+eos_page_manager_init (EosPageManager *self)
+{
+ GtkWidget *self_widget = GTK_WIDGET (self);
+ self->priv = PAGE_MANAGER_PRIVATE (self);
+
+ gtk_widget_set_has_window (self_widget, FALSE);
+
+ /* TODO replace with GtkStack */
+ self->priv->stack = gtk_notebook_new ();
+ g_object_set (self->priv->stack,
+ "show-tabs", FALSE,
+ "show-border", FALSE,
+ NULL);
+ gtk_widget_set_parent (self->priv->stack, self_widget);
+}
+
+/* Public API */
+
+/**
+ * eos_page_manager_new:
+ *
+ * Creates a new default page manager.
+ *
+ * Returns: the new page manager.
+ */
+GtkWidget *
+eos_page_manager_new (void)
+{
+ return g_object_new (EOS_TYPE_PAGE_MANAGER, NULL);
+}
+
+/**
+ * eos_page_manager_get_visible_page:
+ * @self: the page manager
+ *
+ * Gets the page widget that @self is currently displaying.
+ * See #EosPageManager:visible-page for more information.
+ *
+ * Returns: (transfer none): the page #GtkWidget, or %NULL if @self does not
+ * have any pages.
+ */
+GtkWidget *
+eos_page_manager_get_visible_page (EosPageManager *self)
+{
+ g_return_val_if_fail (EOS_IS_PAGE_MANAGER (self), NULL);
+
+ if(self->priv->visible_page_info == NULL)
+ return NULL;
+
+ return self->priv->visible_page_info->page;
+}
+
+/**
+ * eos_page_manager_set_visible_page:
+ * @self: the page manager
+ * @page: the page to switch to
+ *
+ * Switches the page manager @self to display @page.
+ * The @page widget must previously have been added to the page manager.
+ * See #EosPageManager:visible-page for more information.
+ */
+void
+eos_page_manager_set_visible_page (EosPageManager *self,
+ GtkWidget *page)
+{
+ g_return_if_fail (EOS_IS_PAGE_MANAGER (self));
+
+ EosPageManagerPageInfo *info = find_page_info_by_widget (self, page);
+ if (info == NULL)
+ {
+ warn_page_widget_not_found (self, page);
+ return;
+ }
+
+ set_visible_page_from_info (self, info);
+}
+
+/**
+ * eos_page_manager_get_visible_page_name:
+ * @self: the page manager
+ *
+ * Gets the name of the page widget that @self is currently displaying.
+ * See #EosPageManager:visible-page for more information.
+ *
+ * Returns: the name of the page, or %NULL if @self does not have any pages,
+ * or the empty string if the page does not have a name.
+ */
+const gchar *
+eos_page_manager_get_visible_page_name (EosPageManager *self)
+{
+ g_return_val_if_fail (EOS_IS_PAGE_MANAGER (self), NULL);
+
+ if(self->priv->visible_page_info == NULL)
+ return NULL;
+
+ return self->priv->visible_page_info->name;
+}
+
+/**
+ * eos_page_manager_set_visible_page_name:
+ * @self: the page manager
+ * @page_name: the name of the page to switch to
+ *
+ * Switches the page manager @self to display the page called @page_name.
+ * This page must previously have been added to the page manager.
+ * See #EosPageManager:visible-page for more information.
+ */
+void
+eos_page_manager_set_visible_page_name (EosPageManager *self,
+ const gchar *page_name)
+{
+ g_return_if_fail (EOS_IS_PAGE_MANAGER (self));
+
+ EosPageManagerPageInfo *info = find_page_info_by_name (self, page_name);
+ if (info == NULL)
+ {
+ warn_page_name_not_found (self, page_name);
+ return;
+ }
+
+ set_visible_page_from_info (self, info);
+}
+
+/**
+ * eos_page_manager_get_page_name:
+ * @self: the page manager
+ * @page: the page to be queried
+ *
+ * Gets the name of @page, which must previously have been added to the
+ * page manager.
+ * See #EosPageManager:name for more information.
+ *
+ * Returns: the name of @page, or the empty string if @page does not have a
+ * name.
+ */
+const gchar *
+eos_page_manager_get_page_name (EosPageManager *self,
+ GtkWidget *page)
+{
+ g_return_val_if_fail (EOS_IS_PAGE_MANAGER (self), NULL);
+ g_return_val_if_fail (GTK_IS_WIDGET (page), NULL);
+
+ EosPageManagerPageInfo *info = find_page_info_by_widget (self, page);
+ if (info == NULL)
+ {
+ warn_page_widget_not_found (self, page);
+ return NULL;
+ }
+
+ if (info->name == NULL)
+ return "";
+
+ return info->name;
+}
+
+/**
+ * eos_page_manager_set_page_name:
+ * @self: the page manager
+ * @page: the page to be renamed
+ * @name: the new name for @page
+ *
+ * Changes the name of @page, which must previously have been added to the
+ * page manager.
+ * See #EosPageManager:name for more information.
+ */
+void
+eos_page_manager_set_page_name (EosPageManager *self,
+ GtkWidget *page,
+ const gchar *name)
+{
+ g_return_if_fail (EOS_IS_PAGE_MANAGER (self));
+ g_return_if_fail (GTK_IS_WIDGET (page));
+
+ /* Two pages with the same name are not allowed */
+ EosPageManagerPageInfo *info = find_page_info_by_name (self, name);
+ if (info != NULL && info->page != page)
+ {
+ g_critical ("Not setting page name to \"%s\", because page manager "
+ "already contains a page by that name",
+ name);
+ return;
+ }
+
+ info = find_page_info_by_widget (self, page);
+ if (info == NULL)
+ {
+ warn_page_widget_not_found (self, page);
+ return;
+ }
+
+ if (g_strcmp0(info->name, name) == 0)
+ return;
+
+ g_free (info->name);
+ info->name = g_strdup (name);
+
+ gtk_container_child_notify (GTK_CONTAINER (self), page, "name");
+}
+
+/**
+ * eos_page_manager_remove_page_by_name:
+ * @self: the page manager
+ * @name: the name of the page to remove
+ *
+ * Removes the page called @name from the page manager.
+ * If that page was the only page, then the page manager will display nothing.
+ * If that page was currently displaying but was not the only page, then the
+ * page manager will display another page; which page is undefined.
+ *
+ * To remove a page without looking it up by name, use gtk_container_remove().
+ */
+void
+eos_page_manager_remove_page_by_name (EosPageManager *self,
+ const gchar *name)
+{
+ g_return_if_fail (EOS_IS_PAGE_MANAGER (self));
+
+ EosPageManagerPageInfo *info = find_page_info_by_name (self, name);
+ if (info == NULL)
+ {
+ warn_page_name_not_found (self, name);
+ return;
+ }
+
+ /* FIXME: Can't use gtk_container_remove() directly because that asserts
+ gtk_widget_get_parent(child) == self || GTK_IS_ASSISTANT(self)
+ See https://bugzilla.gnome.org/show_bug.cgi?id=699756 [endlessm/eos-sdk#67] */
+ g_signal_emit_by_name (self, "remove", info->page);
+} \ No newline at end of file
diff --git a/endless/eospagemanager.h b/endless/eospagemanager.h
new file mode 100644
index 0000000..7f006ec
--- /dev/null
+++ b/endless/eospagemanager.h
@@ -0,0 +1,97 @@
+/* Copyright 2013 Endless Mobile, Inc. */
+
+#ifndef EOS_PAGE_MANAGER_H
+#define EOS_PAGE_MANAGER_H
+
+#if !(defined(_EOS_SDK_INSIDE_ENDLESS_H) || defined(COMPILING_EOS_SDK))
+#error "Please do not include this header file directly."
+#endif
+
+#include "eostypes.h"
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define EOS_TYPE_PAGE_MANAGER eos_page_manager_get_type()
+
+#define EOS_PAGE_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ EOS_TYPE_PAGE_MANAGER, EosPageManager))
+
+#define EOS_PAGE_MANAGER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ EOS_TYPE_PAGE_MANAGER, EosPageManagerClass))
+
+#define EOS_IS_PAGE_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ EOS_TYPE_PAGE_MANAGER))
+
+#define EOS_IS_PAGE_MANAGER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ EOS_TYPE_PAGE_MANAGER))
+
+#define EOS_PAGE_MANAGER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ EOS_TYPE_PAGE_MANAGER, EosPageManagerClass))
+
+typedef struct _EosPageManager EosPageManager;
+typedef struct _EosPageManagerClass EosPageManagerClass;
+typedef struct _EosPageManagerPrivate EosPageManagerPrivate;
+
+/**
+ * EosPageManager:
+ *
+ * This structure contains no public members.
+ */
+struct _EosPageManager
+{
+ GtkContainer parent;
+
+ EosPageManagerPrivate *priv;
+};
+
+struct _EosPageManagerClass
+{
+ GtkContainerClass parent_class;
+
+ /* For further expansion */
+ gpointer _padding[8];
+};
+
+EOS_SDK_ALL_API_VERSIONS
+GType eos_page_manager_get_type (void) G_GNUC_CONST;
+
+EOS_SDK_ALL_API_VERSIONS
+GtkWidget *eos_page_manager_new (void);
+
+EOS_SDK_ALL_API_VERSIONS
+GtkWidget *eos_page_manager_get_visible_page (EosPageManager *self);
+
+EOS_SDK_ALL_API_VERSIONS
+void eos_page_manager_set_visible_page (EosPageManager *self,
+ GtkWidget *page);
+
+EOS_SDK_ALL_API_VERSIONS
+const gchar *eos_page_manager_get_visible_page_name (EosPageManager *self);
+
+EOS_SDK_ALL_API_VERSIONS
+void eos_page_manager_set_visible_page_name (EosPageManager *self,
+ const gchar *page_name);
+
+EOS_SDK_ALL_API_VERSIONS
+const gchar *eos_page_manager_get_page_name (EosPageManager *self,
+ GtkWidget *page);
+
+EOS_SDK_ALL_API_VERSIONS
+void eos_page_manager_set_page_name (EosPageManager *self,
+ GtkWidget *page,
+ const gchar *name);
+
+EOS_SDK_ALL_API_VERSIONS
+void eos_page_manager_remove_page_by_name (EosPageManager *self,
+ const gchar *name);
+
+G_END_DECLS
+
+#endif /* EOS_PAGE_MANAGER_H */
diff --git a/test/Makefile.am b/test/Makefile.am
index 39f4155..9435a9b 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -12,6 +12,7 @@ test_run_tests_SOURCES = \
test/test-init.c \
test/test-hello.c \
test/test-application.c \
+ test/test-page-manager.c \
test/test-window.c
test_run_tests_CPPFLAGS = $(TEST_FLAGS)
test_run_tests_LDADD = $(TEST_LIBS)
diff --git a/test/run-tests.c b/test/run-tests.c
index aa6acbf..aaecef8 100644
--- a/test/run-tests.c
+++ b/test/run-tests.c
@@ -42,6 +42,7 @@ main (int argc,
add_hello_tests ();
add_application_tests ();
add_window_tests ();
+ add_page_manager_tests ();
return g_test_run ();
}
diff --git a/test/run-tests.h b/test/run-tests.h
index 8d18015..77319a3 100644
--- a/test/run-tests.h
+++ b/test/run-tests.h
@@ -28,5 +28,6 @@ void add_init_tests (void);
void add_hello_tests (void);
void add_application_tests (void);
void add_window_tests (void);
+void add_page_manager_tests (void);
#endif /* RUN_TESTS_H */
diff --git a/test/smoke-tests/app-window.js b/test/smoke-tests/app-window.js
index 8f989ea..32b1736 100644
--- a/test/smoke-tests/app-window.js
+++ b/test/smoke-tests/app-window.js
@@ -6,6 +6,15 @@ const Gtk = imports.gi.Gtk;
const TEST_APPLICATION_ID = 'com.endlessm.example.test';
+/* Override Endless.PageManager.add() */
+Endless.PageManager.prototype.add_real = Endless.PageManager.prototype.add
+Endless.PageManager.prototype.add = function(child, props) {
+ this.add_real(child);
+ for(let prop_id in props) {
+ this.child_set_property(child, prop_id, props[prop_id]);
+ }
+}
+
const TestApplication = new Lang.Class ({
Name: 'TestApplication',
Extends: Endless.Application,
@@ -13,14 +22,41 @@ const TestApplication = new Lang.Class ({
vfunc_startup: function() {
this.parent();
- this._button = new Gtk.Button({label: 'Close me'});
- this._button.connect('clicked', Lang.bind(this, this._onButtonClicked));
+ // First page
+ this._page0 = new Gtk.Grid({ orientation: Gtk.Orientation.VERTICAL });
+ let a1 = new Gtk.Button({ label: 'Go to page1' });
+ a1.connect('clicked', Lang.bind(this, function () {
+ this._pm.visible_page = this._page1;
+ }));
+ this._page0.add(a1);
+ let a2 = new Gtk.Button({ label: 'Go to page named "page1"' });
+ a2.connect('clicked', Lang.bind(this, function () {
+ this._pm.visible_page_name = "page1";
+ }));
+ this._page0.add(a2);
+
+ // Second page
+ this._page1 = new Gtk.Grid({ orientation: Gtk.Orientation.HORIZONTAL });
+ let b1 = new Gtk.Button({ label: 'Go to page0' });
+ b1.connect('clicked', Lang.bind(this, function () {
+ this._pm.visible_page = this._page0;
+ }));
+ this._page1.add(b1);
+ let b2 = new Gtk.Button({ label: 'Go to page named "page0"' });
+ b2.connect('clicked', Lang.bind(this, function () {
+ this._pm.visible_page_name = "page0";
+ }));
+ this._page1.add(b2);
+
+ this._pm = new Endless.PageManager();
+ this._pm.add(this._page0, { name: "page0" });
+ this._pm.add(this._page1, { name: "page1" });
this._window = new Endless.Window({
application: this,
border_width: 16
});
- this._window.add(this._button);
+ this._window.add(this._pm);
this._window.show_all();
},
diff --git a/test/test-page-manager.c b/test/test-page-manager.c
new file mode 100644
index 0000000..00ce0ad
--- /dev/null
+++ b/test/test-page-manager.c
@@ -0,0 +1,333 @@
+#include <gtk/gtk.h>
+#include <endless/endless.h>
+
+#include "run-tests.h"
+
+#define PAGE1_NAME "page1"
+#define PAGE2_NAME "page2"
+#define PAGE3_NAME "page3"
+#define EXPECTED_PAGE_NAME PAGE2_NAME
+#define EXPECTED_CHANGED_PAGE_NAME "changed-name"
+#define DUPLICATE_PAGE_NAME "duplicate-name"
+#define EXPECTED_DUPLICATE_PAGE_NAME_ERRMSG "*Not setting page name to \"" \
+ DUPLICATE_PAGE_NAME "\", because page manager already contains a page by " \
+ "that name*"
+#define ADD_PAGE_MANAGER_TEST(path, test_func) \
+ g_test_add ((path), PageManagerFixture, NULL, \
+ pm_fixture_setup, (test_func), pm_fixture_teardown)
+#define ADD_EMPTY_PAGE_MANAGER_TEST(path, test_func) \
+ g_test_add ((path), PageManagerFixture, NULL, \
+ empty_pm_fixture_setup, (test_func), pm_fixture_teardown);
+
+typedef struct
+{
+ GtkWidget *pm;
+ GtkWidget *page1;
+ GtkWidget *page2;
+ GtkWidget *page3;
+} PageManagerFixture;
+
+static void
+pm_fixture_setup (PageManagerFixture *fixture,
+ gconstpointer unused)
+{
+ fixture->pm = eos_page_manager_new ();
+ fixture->page1 = gtk_label_new ("1");
+ fixture->page2 = gtk_label_new ("2");
+ fixture->page3 = gtk_label_new ("3");
+ gtk_container_add_with_properties (GTK_CONTAINER (fixture->pm),
+ fixture->page1,
+ "name", PAGE1_NAME,
+ NULL);
+ gtk_container_add_with_properties (GTK_CONTAINER (fixture->pm),
+ fixture->page2,
+ "name", PAGE2_NAME,
+ NULL);
+ gtk_container_add_with_properties (GTK_CONTAINER (fixture->pm),
+ fixture->page3,
+ "name", PAGE3_NAME,
+ NULL);
+}
+
+static void
+empty_pm_fixture_setup (PageManagerFixture *fixture,
+ gconstpointer unused)
+{
+ fixture->pm = eos_page_manager_new ();
+}
+
+static void
+pm_fixture_teardown (PageManagerFixture *fixture,
+ gconstpointer unused)
+{
+ gtk_widget_destroy (fixture->pm);
+}
+
+static void
+test_pm_get_set_visible_page (PageManagerFixture *fixture,
+ gconstpointer unused)
+{
+ GtkWidget *visible_page;
+ visible_page = eos_page_manager_get_visible_page (EOS_PAGE_MANAGER (fixture->pm));
+ g_assert (visible_page != fixture->page2);
+ eos_page_manager_set_visible_page (EOS_PAGE_MANAGER (fixture->pm),
+ fixture->page2);
+ visible_page = eos_page_manager_get_visible_page (EOS_PAGE_MANAGER (fixture->pm));
+ g_assert (visible_page == fixture->page2);
+}
+
+static void
+test_pm_prop_visible_page (PageManagerFixture *fixture,
+ gconstpointer unused)
+{
+ GtkWidget *visible_page;
+ g_object_get (fixture->pm, "visible-page", &visible_page, NULL);
+ g_assert (visible_page != fixture->page2);
+ g_object_set (fixture->pm, "visible-page", fixture->page2, NULL);
+ g_object_get (fixture->pm, "visible-page", &visible_page, NULL);
+ g_assert (visible_page == fixture->page2);
+}
+
+static void
+test_pm_get_set_visible_page_name (PageManagerFixture *fixture,
+ gconstpointer unused)
+{
+ const gchar *name;
+ name = eos_page_manager_get_visible_page_name (EOS_PAGE_MANAGER (fixture->pm));
+ g_assert_cmpstr (name, !=, EXPECTED_PAGE_NAME);
+ eos_page_manager_set_visible_page_name (EOS_PAGE_MANAGER (fixture->pm),
+ EXPECTED_PAGE_NAME);
+ name = eos_page_manager_get_visible_page_name (EOS_PAGE_MANAGER (fixture->pm));
+ g_assert_cmpstr (name, ==, EXPECTED_PAGE_NAME);
+}
+
+static void
+test_pm_prop_visible_page_name (PageManagerFixture *fixture,
+ gconstpointer unused)
+{
+ gchar *name;
+ g_object_get (fixture->pm, "visible-page-name", &name, NULL);
+ g_assert_cmpstr (name, !=, EXPECTED_PAGE_NAME);
+ g_free (name);
+ g_object_set (fixture->pm, "visible-page-name", EXPECTED_PAGE_NAME, NULL);
+ g_object_get (fixture->pm, "visible-page-name", &name, NULL);
+ g_assert_cmpstr (name, ==, EXPECTED_PAGE_NAME);
+ g_free (name);
+}
+
+static void
+test_pm_get_set_page_name (PageManagerFixture *fixture,
+ gconstpointer unused)
+{
+ const gchar *name;
+ name = eos_page_manager_get_page_name (EOS_PAGE_MANAGER (fixture->pm),
+ fixture->page1);
+ g_assert_cmpstr (name, ==, PAGE1_NAME);
+ name = eos_page_manager_get_page_name (EOS_PAGE_MANAGER (fixture->pm),
+ fixture->page2);
+ g_assert_cmpstr (name, ==, PAGE2_NAME);
+ name = eos_page_manager_get_page_name (EOS_PAGE_MANAGER (fixture->pm),
+ fixture->page3);
+ g_assert_cmpstr (name, ==, PAGE3_NAME);
+ eos_page_manager_set_page_name (EOS_PAGE_MANAGER (fixture->pm),
+ fixture->page2,
+ EXPECTED_CHANGED_PAGE_NAME);
+ name = eos_page_manager_get_page_name (EOS_PAGE_MANAGER (fixture->pm),
+ fixture->page2);
+ g_assert_cmpstr (name, ==, EXPECTED_CHANGED_PAGE_NAME);
+}
+
+static void
+test_pm_child_prop_name (PageManagerFixture *fixture,
+ gconstpointer unused)
+{
+ gchar *name;
+ gtk_container_child_get (GTK_CONTAINER (fixture->pm), fixture->page1,
+ "name", &name,
+ NULL);
+ g_assert_cmpstr (name, ==, PAGE1_NAME);
+ g_free (name);
+ gtk_container_child_get (GTK_CONTAINER (fixture->pm), fixture->page2,
+ "name", &name,
+ NULL);
+ g_assert_cmpstr (name, ==, PAGE2_NAME);
+ g_free (name);
+ gtk_container_child_get (GTK_CONTAINER (fixture->pm), fixture->page3,
+ "name", &name,
+ NULL);
+ g_assert_cmpstr (name, ==, PAGE3_NAME);
+ g_free (name);
+ gtk_container_child_set (GTK_CONTAINER (fixture->pm), fixture->page2,
+ "name", EXPECTED_CHANGED_PAGE_NAME,
+ NULL);
+ gtk_container_child_get (GTK_CONTAINER (fixture->pm), fixture->page2,
+ "name", &name,
+ NULL);
+ g_assert_cmpstr (name, ==, EXPECTED_CHANGED_PAGE_NAME);
+ g_free (name);
+}
+
+static void
+test_pm_page_no_name (PageManagerFixture *fixture,
+ gconstpointer unused)
+{
+ const gchar *name_get;
+ gchar *name_prop;
+ GtkWidget *new_page = gtk_label_new("new");
+ gtk_container_add (GTK_CONTAINER (fixture->pm), new_page);
+ name_get = eos_page_manager_get_page_name (EOS_PAGE_MANAGER (fixture->pm), new_page);
+ g_assert_cmpstr (name_get, ==, "");
+ gtk_container_child_get (GTK_CONTAINER (fixture->pm), new_page,
+ "name", &name_prop,
+ NULL);
+ g_assert_cmpstr (name_prop, ==, "");
+ g_free (name_prop);
+}
+
+static void
+test_pm_remove_page_behavior (PageManagerFixture *fixture,
+ gconstpointer unused)
+{
+ GtkWidget *visible_page;
+ visible_page = eos_page_manager_get_visible_page (EOS_PAGE_MANAGER (fixture->pm));
+ g_assert (visible_page == fixture->page1);
+ gtk_container_remove (GTK_CONTAINER (fixture->pm), fixture->page3);
+ visible_page = eos_page_manager_get_visible_page (EOS_PAGE_MANAGER (fixture->pm));
+ g_assert (visible_page == fixture->page1);
+ gtk_container_remove (GTK_CONTAINER (fixture->pm), fixture->page2);
+ visible_page = eos_page_manager_get_visible_page (EOS_PAGE_MANAGER (fixture->pm));
+ g_assert (visible_page == fixture->page1);
+ gtk_container_remove (GTK_CONTAINER (fixture->pm), fixture->page1);
+ visible_page = eos_page_manager_get_visible_page (EOS_PAGE_MANAGER (fixture->pm));
+ g_assert (visible_page == NULL);
+}
+
+static void
+test_pm_remove_page_undefined_behavior (PageManagerFixture *fixture,
+ gconstpointer unused)
+{
+ GtkWidget *visible_page;
+ visible_page = eos_page_manager_get_visible_page (EOS_PAGE_MANAGER (fixture->pm));
+ g_assert (visible_page == fixture->page1);
+ gtk_container_remove (GTK_CONTAINER (fixture->pm), fixture->page1);
+ visible_page = eos_page_manager_get_visible_page (EOS_PAGE_MANAGER (fixture->pm));
+ g_assert (visible_page != fixture->page1);
+}
+
+static void
+test_pm_remove_page_by_name (PageManagerFixture *fixture,
+ gconstpointer unused)
+{
+ GList *pages = gtk_container_get_children (GTK_CONTAINER (fixture->pm));
+ guint length = g_list_length (pages);
+ g_list_free (pages);
+
+ eos_page_manager_remove_page_by_name (EOS_PAGE_MANAGER (fixture->pm),
+ PAGE2_NAME);
+ pages = gtk_container_get_children (GTK_CONTAINER (fixture->pm));
+ g_assert_cmpuint (g_list_length (pages), ==, length - 1);
+ g_assert (g_list_find (pages, fixture->page1) != NULL);
+ g_assert (g_list_find (pages, fixture->page2) == NULL);
+ g_assert (g_list_find (pages, fixture->page3) != NULL);
+ g_list_free (pages);
+}
+
+static void
+test_pm_duplicate_page_name (PageManagerFixture *fixture,
+ gconstpointer unused)
+{
+ eos_page_manager_set_page_name (EOS_PAGE_MANAGER (fixture->pm),
+ fixture->page1,
+ DUPLICATE_PAGE_NAME);
+ /* Should not complain */
+ eos_page_manager_set_page_name (EOS_PAGE_MANAGER (fixture->pm),
+ fixture->page1,
+ DUPLICATE_PAGE_NAME);
+
+ g_test_expect_message (TEST_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+ EXPECTED_DUPLICATE_PAGE_NAME_ERRMSG);
+ eos_page_manager_set_page_name (EOS_PAGE_MANAGER (fixture->pm),
+ fixture->page2,
+ DUPLICATE_PAGE_NAME);
+ g_test_assert_expected_messages ();
+
+ const gchar *name = eos_page_manager_get_page_name (EOS_PAGE_MANAGER (fixture->pm),
+ fixture->page2);
+ g_assert_cmpstr (name, !=, DUPLICATE_PAGE_NAME);
+}
+
+static void
+test_empty_pm_visible_page (PageManagerFixture *fixture,
+ gconstpointer unused)
+{
+ GtkWidget *visible_page_get, *visible_page_prop;
+ visible_page_get = eos_page_manager_get_visible_page (EOS_PAGE_MANAGER (fixture->pm));
+ g_assert (visible_page_get == NULL);
+ g_object_get (fixture->pm, "visible-page", &visible_page_prop, NULL);
+ g_assert (visible_page_prop == NULL);
+}
+
+static void
+test_empty_pm_visible_page_name (PageManagerFixture *fixture,
+ gconstpointer unused)
+{
+ const gchar *name_get;
+ gchar *name_prop;
+ name_get = eos_page_manager_get_visible_page_name (EOS_PAGE_MANAGER (fixture->pm));
+ g_assert (name_get == NULL);
+ g_object_get (fixture->pm, "visible-page-name", &name_prop, NULL);
+ g_assert (name_prop == NULL);
+}
+
+static void
+test_empty_pm_add_page_behavior (PageManagerFixture *fixture,
+ gconstpointer unused)
+{
+ GtkWidget *visible_page;
+ GtkWidget *page1 = gtk_label_new ("page1");
+ GtkWidget *page2 = gtk_label_new ("page2");
+ gtk_container_add (GTK_CONTAINER (fixture->pm), page1);
+ visible_page = eos_page_manager_get_visible_page (EOS_PAGE_MANAGER (fixture->pm));
+ g_assert (visible_page == page1);
+ gtk_container_add (GTK_CONTAINER (fixture->pm), page2);
+ visible_page = eos_page_manager_get_visible_page (EOS_PAGE_MANAGER (fixture->pm));
+ g_assert (visible_page == page1); /* Not page2! */
+}
+
+void
+add_page_manager_tests (void)
+{
+ ADD_PAGE_MANAGER_TEST ("/page-manager/get-set-visible-page",
+ test_pm_get_set_visible_page);
+ ADD_PAGE_MANAGER_TEST ("/page-manager/prop-visible-page",
+ test_pm_prop_visible_page);
+ ADD_PAGE_MANAGER_TEST ("/page-manager/get-set-visible-page-name",
+ test_pm_get_set_visible_page_name);
+ ADD_PAGE_MANAGER_TEST ("/page-manager/prop-visible-page-name",
+ test_pm_prop_visible_page_name);
+ ADD_PAGE_MANAGER_TEST ("/page-manager/get-set-page-name",
+ test_pm_get_set_page_name);
+ ADD_PAGE_MANAGER_TEST ("/page-manager/child-prop-name",
+ test_pm_child_prop_name);
+ ADD_PAGE_MANAGER_TEST ("/page-manager/page-no-name", test_pm_page_no_name);
+ ADD_PAGE_MANAGER_TEST ("/page-manager/remove-page-by-name",
+ test_pm_remove_page_by_name);
+ ADD_PAGE_MANAGER_TEST ("/page-manager/duplicate-page-name",
+ test_pm_duplicate_page_name);
+ ADD_EMPTY_PAGE_MANAGER_TEST ("/page-manager/empty-visible-page",
+ test_empty_pm_visible_page);
+ ADD_EMPTY_PAGE_MANAGER_TEST ("/page-manager/empty-visible-page-name",
+ test_empty_pm_visible_page_name);
+ ADD_EMPTY_PAGE_MANAGER_TEST ("/page-manager/add-page-behavior",
+ test_empty_pm_add_page_behavior);
+
+ /* Disabled until https://bugzilla.gnome.org/show_bug.cgi?id=699756 is fixed
+ [endlessm/eos-sdk#67] */
+ if (FALSE)
+ {
+ ADD_PAGE_MANAGER_TEST ("/page-manager/remove-page-behavior",
+ test_pm_remove_page_behavior);
+ ADD_PAGE_MANAGER_TEST ("/page-manager/remove-page-undefined-behavior",
+ test_pm_remove_page_undefined_behavior);
+ }
+}