summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Watson <mattdangerw@gmail.com>2014-01-13 15:39:25 -0800
committerMatt Watson <mattdangerw@gmail.com>2014-01-22 13:43:04 -0800
commit011fffcedfa2845179355052f69a2f0ceabd5852 (patch)
tree67a302e246e04459bd7b64031ad41579da8607b1
parent63dae1af95255ec96b17e829e6e15545595347ce (diff)
Added EosCustomContainer C class for gjs containers
forall cannot be overridden in gjs. There's an upstream bug here https://bugzilla.gnome.org/show_bug.cgi?id=701567 but that does not look like it will be fixed soon. So for now added a small c class that take care of GtkContainers add, remove and forall methods. This makes it possible to write generic containers in gjs. See docs for an example [endlessm/eos-sdk#481]
-rw-r--r--docs/reference/endless/endless-docs.xml1
-rw-r--r--docs/reference/endless/endless-sections.txt15
-rw-r--r--endless/Makefile.am2
-rw-r--r--endless/endless.h1
-rw-r--r--endless/eoscustomcontainer.c114
-rw-r--r--endless/eoscustomcontainer.h67
-rw-r--r--test/endless/Makefile.am.inc1
-rw-r--r--test/endless/run-tests.c1
-rw-r--r--test/endless/run-tests.h1
-rw-r--r--test/endless/test-custom-container.c83
-rw-r--r--test/smoke-tests/custom-container.js44
11 files changed, 330 insertions, 0 deletions
diff --git a/docs/reference/endless/endless-docs.xml b/docs/reference/endless/endless-docs.xml
index c602ed2..f946d1f 100644
--- a/docs/reference/endless/endless-docs.xml
+++ b/docs/reference/endless/endless-docs.xml
@@ -23,6 +23,7 @@
<xi:include href="xml/splash-page-manager.xml"/>
<xi:include href="xml/action-button.xml"/>
<xi:include href="xml/flexy-grid.xml"/>
+ <xi:include href="xml/custom-container.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 4e4887a..963629f 100644
--- a/docs/reference/endless/endless-sections.txt
+++ b/docs/reference/endless/endless-sections.txt
@@ -192,3 +192,18 @@ eos_flexy_grid_get_type
eos_flexy_grid_cell_get_type
eos_flexy_shape_get_type
</SECTION>
+
+<SECTION>
+<FILE>custom-container</FILE>
+EosCustomContainer
+eos_custom_container_new
+<SUBSECTION Standard>
+EOS_CUSTOM_CONTAINER
+EOS_CUSTOM_CONTAINER_CLASS
+EOS_CUSTOM_CONTAINER_GET_CLASS
+EOS_IS_CUSTOM_CONTAINER
+EOS_IS_CUSTOM_CONTAINER_CLASS
+EOS_TYPE_CUSTOM_CONTAINER
+EosCustomContainerClass
+eos_custom_container_get_type
+</SECTION>
diff --git a/endless/Makefile.am b/endless/Makefile.am
index 3a5b95c..74d8b3c 100644
--- a/endless/Makefile.am
+++ b/endless/Makefile.am
@@ -28,6 +28,7 @@ endless_private_installed_headers = \
endless/eosversion.h \
endless/eosactionbutton.h \
endless/eosapplication.h \
+ endless/eoscustomcontainer.h \
endless/eosenums.h \
endless/eosmacros.h \
endless/eospagemanager.h \
@@ -39,6 +40,7 @@ endless_private_installed_headers = \
endless_library_sources = \
endless/eosapplication.c \
+ endless/eoscustomcontainer.c \
endless/eoshello.c \
endless/eosinit.c endless/eosinit-private.h \
endless/eospagemanager.c endless/eospagemanager-private.h \
diff --git a/endless/endless.h b/endless/endless.h
index 9efbe6e..f3f2061 100644
--- a/endless/endless.h
+++ b/endless/endless.h
@@ -18,6 +18,7 @@ G_BEGIN_DECLS
#include "eospagemanager.h"
#include "eossplashpagemanager.h"
#include "eoswindow.h"
+#include "eoscustomcontainer.h"
#undef _EOS_SDK_INSIDE_ENDLESS_H
diff --git a/endless/eoscustomcontainer.c b/endless/eoscustomcontainer.c
new file mode 100644
index 0000000..a68745b
--- /dev/null
+++ b/endless/eoscustomcontainer.c
@@ -0,0 +1,114 @@
+/* Copyright 2014 Endless Mobile, Inc. */
+
+#include "config.h"
+#include "eoscustomcontainer.h"
+
+#include <gtk/gtk.h>
+
+/**
+ * SECTION:custom-container
+ * @short_description: For gjs container implementations
+ * @title: Custom Container
+ *
+ * This container allows for implementing a custom size allocate routine in
+ * gjs. This container implements the bare minimum of virtual functions from
+ * GtkContainer, add, remove and forall. Add and remove simply append to and
+ * remove from an internal list, and forall iterates over that list. Forall
+ * cannot be implemented in gjs, it's not supported by gobject-introspection,
+ * so this is needed for custom gjs containers. This class will not
+ * size_allocate any children or ever queue_resize, so that is up to
+ * subclasses in gjs.
+ *
+ * Here's an example gjs program which allocates a GtkFrame the top right
+ * quarter of it's allocation.
+ * |[
+ * const TestContainer = Lang.Class({
+ * Name: 'TestContainer',
+ * Extends: Endless.CustomContainer,
+ *
+ * _init: function() {
+ * this.parent();
+ *
+ * this._frame = new Gtk.Frame();
+ * this.add(this._frame);
+ * },
+ *
+ * vfunc_size_allocate: function (alloc) {
+ * this.parent(alloc);
+ * alloc.width = alloc.width / 2;
+ * alloc.height = alloc.height / 2;
+ * this._frame.size_allocate(alloc);
+ * }
+ * });
+ * ]|
+ */
+
+typedef struct {
+ GList *children;
+} EosCustomContainerPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (EosCustomContainer, eos_custom_container, GTK_TYPE_CONTAINER)
+
+static void
+eos_custom_container_add (GtkContainer *container,
+ GtkWidget *child)
+{
+ EosCustomContainer *self = EOS_CUSTOM_CONTAINER (container);
+ EosCustomContainerPrivate *priv = eos_custom_container_get_instance_private (self);
+
+ priv->children = g_list_prepend (priv->children, child);
+ gtk_widget_set_parent (child, GTK_WIDGET (container));
+}
+
+static void
+eos_custom_container_remove (GtkContainer *container,
+ GtkWidget *child)
+{
+ EosCustomContainer *self = EOS_CUSTOM_CONTAINER (container);
+ EosCustomContainerPrivate *priv = eos_custom_container_get_instance_private (self);
+
+ priv->children = g_list_remove (priv->children, child);
+ gtk_widget_unparent (child);
+}
+
+static void
+eos_custom_container_forall (GtkContainer *container,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer callback_data)
+{
+ EosCustomContainer *self = EOS_CUSTOM_CONTAINER (container);
+ EosCustomContainerPrivate *priv = eos_custom_container_get_instance_private (self);
+
+ g_list_foreach (priv->children, (GFunc)callback, callback_data);
+}
+
+static void
+eos_custom_container_class_init (EosCustomContainerClass *klass)
+{
+ GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+ container_class->add = eos_custom_container_add;
+ container_class->remove = eos_custom_container_remove;
+ container_class->forall = eos_custom_container_forall;
+}
+
+static void
+eos_custom_container_init (EosCustomContainer *self)
+{
+ GtkWidget *widget = GTK_WIDGET (self);
+ gtk_widget_set_has_window (widget, FALSE);
+}
+
+/**
+ * eos_custom_container_new:
+ *
+ * Creates a new custom container.
+ *
+ * Returns: the custom container.
+ */
+GtkWidget *
+eos_custom_container_new (void)
+{
+ return g_object_new (EOS_TYPE_CUSTOM_CONTAINER, NULL);
+}
diff --git a/endless/eoscustomcontainer.h b/endless/eoscustomcontainer.h
new file mode 100644
index 0000000..743bc59
--- /dev/null
+++ b/endless/eoscustomcontainer.h
@@ -0,0 +1,67 @@
+/* Copyright 2014 Endless Mobile, Inc. */
+
+#ifndef EOS_CUSTOM_CONTAINER_H
+#define EOS_CUSTOM_CONTAINER_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_CUSTOM_CONTAINER eos_custom_container_get_type()
+
+#define EOS_CUSTOM_CONTAINER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ EOS_TYPE_CUSTOM_CONTAINER, EosCustomContainer))
+
+#define EOS_CUSTOM_CONTAINER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ EOS_TYPE_CUSTOM_CONTAINER, EosCustomContainerClass))
+
+#define EOS_IS_CUSTOM_CONTAINER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ EOS_TYPE_CUSTOM_CONTAINER))
+
+#define EOS_IS_CUSTOM_CONTAINER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ EOS_TYPE_CUSTOM_CONTAINER))
+
+#define EOS_CUSTOM_CONTAINER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ EOS_TYPE_CUSTOM_CONTAINER, EosCustomContainerClass))
+
+typedef struct _EosCustomContainer EosCustomContainer;
+typedef struct _EosCustomContainerClass EosCustomContainerClass;
+
+/**
+ * EosCustomContainer:
+ *
+ * This structure contains no public members.
+ */
+struct _EosCustomContainer
+{
+ GtkContainer parent;
+};
+
+struct _EosCustomContainerClass
+{
+ GtkContainerClass parent_class;
+
+ /* For further expansion */
+ gpointer _padding[8];
+};
+
+EOS_SDK_ALL_API_VERSIONS
+GType eos_custom_container_get_type (void) G_GNUC_CONST;
+
+EOS_SDK_ALL_API_VERSIONS
+GtkWidget *eos_custom_container_new (void);
+
+G_END_DECLS
+
+#endif /* EOS_CUSTOM_CONTAINER_H */
diff --git a/test/endless/Makefile.am.inc b/test/endless/Makefile.am.inc
index 2835934..8b78baf 100644
--- a/test/endless/Makefile.am.inc
+++ b/test/endless/Makefile.am.inc
@@ -12,6 +12,7 @@ test_endless_run_tests_SOURCES = \
$(ENDLESS_TESTS_DIRECTORY)/endless/test-action-menu.c \
$(ENDLESS_TESTS_DIRECTORY)/endless/test-action-button.c \
$(ENDLESS_TESTS_DIRECTORY)/endless/test-flexy-grid.c \
+ $(ENDLESS_TESTS_DIRECTORY)/endless/test-custom-container.c \
$(NULL)
test_endless_run_tests_CPPFLAGS = $(TEST_FLAGS)
test_endless_run_tests_LDADD = $(TEST_LIBS)
diff --git a/test/endless/run-tests.c b/test/endless/run-tests.c
index db9c289..4bc4006 100644
--- a/test/endless/run-tests.c
+++ b/test/endless/run-tests.c
@@ -111,6 +111,7 @@ main (int argc,
add_action_menu_tests ();
add_action_button_tests ();
add_flexy_grid_test ();
+ add_custom_container_tests ();
return g_test_run ();
}
diff --git a/test/endless/run-tests.h b/test/endless/run-tests.h
index 8947a5a..cb52ab7 100644
--- a/test/endless/run-tests.h
+++ b/test/endless/run-tests.h
@@ -41,5 +41,6 @@ void add_splash_page_manager_tests (void);
void add_action_menu_tests (void);
void add_action_button_tests (void);
void add_flexy_grid_test (void);
+void add_custom_container_tests (void);
#endif /* RUN_TESTS_H */
diff --git a/test/endless/test-custom-container.c b/test/endless/test-custom-container.c
new file mode 100644
index 0000000..42cf99f
--- /dev/null
+++ b/test/endless/test-custom-container.c
@@ -0,0 +1,83 @@
+/* Copyright 2014 Endless Mobile, Inc. */
+
+#include <gtk/gtk.h>
+#include <endless/endless.h>
+
+#include "run-tests.h"
+
+typedef struct
+{
+ GtkContainer *container;
+ GtkWidget *child1;
+ GtkWidget *child2;
+ GtkWidget *child3;
+} CustomContainerFixture;
+
+#define ADD_CUSTOM_CONTAINER_TEST(path, test_func) \
+ g_test_add ((path), CustomContainerFixture, NULL, \
+ custom_container_fixture_setup, \
+ (test_func), \
+ custom_container_fixture_teardown)
+
+
+static void
+custom_container_fixture_setup (CustomContainerFixture *fixture,
+ gconstpointer unused G_GNUC_UNUSED)
+{
+ // We acquire the widget ref so they don't automatically get destroyed after
+ // being removed from the container.
+ fixture->child1 = g_object_ref_sink (gtk_label_new ("1"));
+ fixture->child2 = g_object_ref_sink (gtk_label_new ("2"));
+ fixture->child3 = g_object_ref_sink (gtk_label_new ("3"));
+ fixture->container = GTK_CONTAINER (eos_custom_container_new ());
+}
+
+static void
+custom_container_fixture_teardown (CustomContainerFixture *fixture,
+ gconstpointer unused G_GNUC_UNUSED)
+{
+ gtk_widget_destroy (fixture->child1);
+ gtk_widget_destroy (fixture->child2);
+ gtk_widget_destroy (fixture->child3);
+ gtk_widget_destroy ((GtkWidget *) fixture->container);
+ g_object_unref (fixture->child1);
+ g_object_unref (fixture->child2);
+ g_object_unref (fixture->child3);
+}
+
+static void
+test_custom_container_add (CustomContainerFixture *fixture,
+ gconstpointer unused G_GNUC_UNUSED)
+{
+ gtk_container_add (fixture->container, fixture->child1);
+ gtk_container_add (fixture->container, fixture->child2);
+ gtk_container_add (fixture->container, fixture->child3);
+
+ g_assert (gtk_widget_get_parent (fixture->child1) == GTK_WIDGET (fixture->container));
+ GList *children = gtk_container_get_children (fixture->container);
+ g_assert (g_list_length (children) == 3);
+ g_assert (g_list_find (children, fixture->child1) != NULL);
+ g_assert (g_list_find (children, fixture->child2) != NULL);
+ g_assert (g_list_find (children, fixture->child3) != NULL);
+}
+
+static void
+test_custom_container_remove (CustomContainerFixture *fixture,
+ gconstpointer unused G_GNUC_UNUSED)
+{
+ gtk_container_add (fixture->container, fixture->child1);
+ gtk_container_add (fixture->container, fixture->child2);
+ gtk_container_add (fixture->container, fixture->child3);
+ gtk_container_remove (fixture->container, fixture->child2);
+
+ g_assert (gtk_widget_get_parent (fixture->child2) != GTK_WIDGET (fixture->container));
+ GList *children = gtk_container_get_children (fixture->container);
+ g_assert (g_list_find (children, fixture->child2) == NULL);
+}
+
+void
+add_custom_container_tests (void)
+{
+ ADD_CUSTOM_CONTAINER_TEST ("/custom-container/add", test_custom_container_add);
+ ADD_CUSTOM_CONTAINER_TEST ("/custom-container/remove", test_custom_container_remove);
+}
diff --git a/test/smoke-tests/custom-container.js b/test/smoke-tests/custom-container.js
new file mode 100644
index 0000000..679e0be
--- /dev/null
+++ b/test/smoke-tests/custom-container.js
@@ -0,0 +1,44 @@
+// Copyright 2014 Endless Mobile, Inc.
+
+const Lang = imports.lang;
+const Endless = imports.gi.Endless;
+const Gtk = imports.gi.Gtk;
+const GObject = imports.gi.GObject;
+
+const TEST_APPLICATION_ID = 'com.endlessm.example.test';
+
+const TestContainer = Lang.Class({
+ Name: 'TestContainer',
+ Extends: Endless.CustomContainer,
+
+ _init: function() {
+ this.parent();
+
+ this._frame = new Gtk.Frame();
+ this.add(this._frame);
+ },
+
+ vfunc_size_allocate: function (alloc) {
+ this.parent(alloc);
+ alloc.width = alloc.width / 2;
+ alloc.height = alloc.height / 2;
+ this._frame.size_allocate(alloc);
+ }
+});
+
+const TestApplication = new Lang.Class ({
+ Name: 'TestApplication',
+ Extends: Gtk.Application,
+
+ vfunc_startup: function() {
+ this.parent();
+ let window = new Gtk.Window();
+ window.add(new TestContainer());
+ window.show_all();
+ this.add_window(window);
+ }
+});
+
+let app = new TestApplication({ application_id: TEST_APPLICATION_ID,
+ flags: 0 });
+app.run(ARGV);