summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorP. F. Chimento <philip.chimento@gmail.com>2013-04-15 18:04:27 +0200
committerP. F. Chimento <philip.chimento@gmail.com>2013-04-24 14:48:15 +0200
commit096c63f7ed002b99a995c35a407483a0bfa161c5 (patch)
treecf324aae1bce4f5cb9edf42e68bc9c7cb4da0964
parent7fc4090461ad888612491814e5a44aaf7e52d7ff (diff)
Application class
Add an EosApplication class. Functionality: - present main application window when activated - warn if more than one application window is added Also add a stub EosWindow class that overrides GtkWindow's "application" property to be a construct-only property. [#4]
-rw-r--r--configure.ac4
-rw-r--r--docs/reference/endless/endless-docs.xml4
-rw-r--r--docs/reference/endless/endless-sections.txt34
-rw-r--r--endless/Makefile.am8
-rw-r--r--endless/application.c165
-rw-r--r--endless/application.h70
-rw-r--r--endless/endless.h2
-rw-r--r--endless/types.h2
-rw-r--r--endless/window.c121
-rw-r--r--endless/window.h71
-rw-r--r--test/Makefile.am4
-rw-r--r--test/run-tests.c4
-rw-r--r--test/run-tests.h6
-rw-r--r--test/smoke-tests/app-window.js21
-rw-r--r--test/test-application.c48
-rw-r--r--test/test-window.c24
16 files changed, 580 insertions, 8 deletions
diff --git a/configure.ac b/configure.ac
index 08f32f1..42f4098 100644
--- a/configure.ac
+++ b/configure.ac
@@ -69,10 +69,10 @@ AC_SUBST(EOS_SDK_LT_VERSION_INFO)
# Required versions of libraries
# Update these whenever you use a function that requires a certain API version
-GLIB_REQUIREMENT="glib-2.0 >= 2.20"
+GLIB_REQUIREMENT="glib-2.0 >= 2.36"
GOBJECT_REQUIREMENT="gobject-2.0"
GIO_REQUIREMENT="gio-2.0"
-GTK_REQUIREMENT="gtk+-3.0 >= 3.0"
+GTK_REQUIREMENT="gtk+-3.0 >= 3.4"
# These go into the pkg-config file as Requires: and Requires.private:
# (Generally, use Requires.private: instead of Requires:)
EOS_REQUIRED_MODULES=
diff --git a/docs/reference/endless/endless-docs.xml b/docs/reference/endless/endless-docs.xml
index d4004aa..13866ca 100644
--- a/docs/reference/endless/endless-docs.xml
+++ b/docs/reference/endless/endless-docs.xml
@@ -17,7 +17,9 @@
<chapter>
<title>Open Endless SDK reference (C API)</title>
- <xi:include href="xml/hello.xml"/>
+ <xi:include href="xml/application.xml"/>
+ <xi:include href="xml/window.xml"/>
+ <!--<xi:include href="xml/hello.xml"/>-->
</chapter>
<chapter id="object-tree">
diff --git a/docs/reference/endless/endless-sections.txt b/docs/reference/endless/endless-sections.txt
index 4782fbb..8978d4d 100644
--- a/docs/reference/endless/endless-sections.txt
+++ b/docs/reference/endless/endless-sections.txt
@@ -4,3 +4,37 @@ eos_hello_sample_function
<SUBSECTION Private>
EOS_SDK_ALL_API_VERSIONS
</SECTION>
+
+<SECTION>
+<FILE>application</FILE>
+EosApplication
+eos_application_new
+<SUBSECTION Standard>
+EosApplicationClass
+EOS_APPLICATION
+EOS_APPLICATION_CLASS
+EOS_APPLICATION_GET_CLASS
+EOS_IS_APPLICATION
+EOS_IS_APPLICATION_CLASS
+EOS_TYPE_APPLICATION
+eos_application_get_type
+<SUBSECTION Private>
+EosApplicationPrivate
+</SECTION>
+
+<SECTION>
+<FILE>window</FILE>
+EosWindow
+eos_window_new
+<SUBSECTION Standard>
+EosWindowClass
+EOS_IS_WINDOW
+EOS_IS_WINDOW_CLASS
+EOS_TYPE_WINDOW
+EOS_WINDOW
+EOS_WINDOW_CLASS
+EOS_WINDOW_GET_CLASS
+eos_window_get_type
+<SUBSECTION Private>
+EosWindowPrivate
+</SECTION>
diff --git a/endless/Makefile.am b/endless/Makefile.am
index e653097..583ca74 100644
--- a/endless/Makefile.am
+++ b/endless/Makefile.am
@@ -4,13 +4,17 @@ endless_public_installed_headers = endless/endless.h
endless_private_installed_headers = \
endless/apiversion.h \
+ endless/application.h \
endless/enums.h \
endless/macros.h \
- endless/types.h
+ endless/types.h \
+ endless/window.h
endless_library_sources = \
+ endless/application.c \
endless/hello.c \
- endless/init.c endless/init-private.h
+ endless/init.c endless/init-private.h \
+ endless/window.c
# Endless GUI library
lib_LTLIBRARIES = libendless-@EOS_SDK_API_VERSION@.la
diff --git a/endless/application.c b/endless/application.c
new file mode 100644
index 0000000..ef93e13
--- /dev/null
+++ b/endless/application.c
@@ -0,0 +1,165 @@
+/* Copyright 2013 Endless Mobile, Inc. */
+
+#include "config.h"
+#include "application.h"
+
+#include <gtk/gtk.h>
+
+#include "window.h"
+
+/**
+ * SECTION:application
+ * @short_description: Start here with your application
+ * @title: Applications
+ *
+ * The #EosApplication class is where you start when programming your
+ * application.
+ * You should create a class that extends #EosApplication.
+ *
+ * You also need to think up an application ID.
+ * This takes the form of a reverse domain name, and it should be unique.
+ * This ID is used to make sure that only one copy of your application is
+ * running at any time; if a user tries to start a second copy, then the first
+ * copy is brought to the front.
+ *
+ * To set up your application's data and window, override the
+ * #GApplication::startup function, like this example do-nothing application,
+ * <quote>Smoke Grinder</quote>:
+ * |[
+ * const Lang = imports.lang;
+ * const Endless = imports.gi.Endless;
+ *
+ * const SmokeGrinder = new Lang.Class ({
+ * Name: 'SmokeGrinder',
+ * Extends: Endless.Application,
+ *
+ * vfunc_startup: function() {
+ * this.parent();
+ * this._window = new Endless.Window({application: this});
+ * this._window.show_all();
+ * },
+ * });
+ *
+ * let app = new SmokeGrinder({ application_id: "com.example.smokegrinder",
+ * flags: 0 });
+ * app.run(ARGV);
+ * ]|
+ */
+
+G_DEFINE_TYPE (EosApplication, eos_application, GTK_TYPE_APPLICATION)
+
+#define APPLICATION_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), EOS_TYPE_APPLICATION, EosApplicationPrivate))
+
+struct _EosApplicationPrivate
+{
+ EosWindow *main_application_window;
+};
+
+static void
+eos_application_activate (GApplication *application)
+{
+ EosApplication *self = EOS_APPLICATION (application);
+
+ G_APPLICATION_CLASS (eos_application_parent_class)->activate (application);
+
+ /* Raise the main application window if it is iconified. This behavior will
+ be default in GTK at some future point, in which case the following
+ paragraph can be removed. */
+ if (self->priv->main_application_window)
+ {
+ gtk_window_present (GTK_WINDOW (self->priv->main_application_window));
+ }
+
+ /* TODO: Should it be required to override activate() as in GApplication? */
+}
+
+static void
+eos_application_window_added (GtkApplication *application,
+ GtkWindow *window)
+{
+ EosApplication *self = EOS_APPLICATION (application);
+
+ GTK_APPLICATION_CLASS (eos_application_parent_class)->window_added (
+ application, window);
+
+ /* If the new window is an EosWindow, then it is our main application window;
+ it should be raised when the application is activated */
+ if (EOS_IS_WINDOW (window))
+ {
+ if (self->priv->main_application_window != NULL)
+ {
+ g_error ("You should not add more than one application window.");
+ }
+ g_object_ref (window);
+ self->priv->main_application_window = EOS_WINDOW (window);
+ }
+}
+
+static void
+eos_application_window_removed (GtkApplication *application,
+ GtkWindow *window)
+{
+ EosApplication *self = EOS_APPLICATION (application);
+
+ GTK_APPLICATION_CLASS (eos_application_parent_class)->window_removed (
+ application, window);
+
+ if (EOS_IS_WINDOW (window))
+ {
+ if (self->priv->main_application_window == NULL)
+ {
+ g_warning ("EosWindow is being removed from EosApplication, although "
+ "none was added.");
+ return;
+ }
+ if (self->priv->main_application_window != EOS_WINDOW (window))
+ g_warning ("A different EosWindow is being removed from EosApplication "
+ "than the one that was added.");
+ g_object_unref (window);
+ self->priv->main_application_window = NULL;
+ }
+}
+
+static void
+eos_application_class_init (EosApplicationClass *klass)
+{
+ GApplicationClass *g_application_class = G_APPLICATION_CLASS (klass);
+ GtkApplicationClass *gtk_application_class = GTK_APPLICATION_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (EosApplicationPrivate));
+
+ g_application_class->activate = eos_application_activate;
+ gtk_application_class->window_added = eos_application_window_added;
+ gtk_application_class->window_removed = eos_application_window_removed;
+}
+
+static void
+eos_application_init (EosApplication *self)
+{
+ self->priv = APPLICATION_PRIVATE (self);
+}
+
+/* Public API */
+
+/**
+ * eos_application_new:
+ * @application_id: a unique identifier for the application, for example a
+ * reverse domain name.
+ * @flags: flags to apply to the application; see #GApplicationFlags.
+ *
+ * Create a new application. For the application ID, use a reverse domain name,
+ * such as <code>com.endlessm.weather</code>. See g_application_id_is_valid()
+ * for the full rules for application IDs.
+ *
+ * Returns: a pointer to the application.
+ */
+EosApplication *
+eos_application_new (const gchar *application_id,
+ GApplicationFlags flags)
+{
+ return g_object_new (EOS_TYPE_APPLICATION,
+ "application-id", application_id,
+ "flags", flags,
+ NULL);
+}
diff --git a/endless/application.h b/endless/application.h
new file mode 100644
index 0000000..5089c12
--- /dev/null
+++ b/endless/application.h
@@ -0,0 +1,70 @@
+/* Copyright 2013 Endless Mobile, Inc. */
+
+#if !(defined(_EOS_SDK_INSIDE_ENDLESS_H) || defined(COMPILING_EOS_SDK))
+#error "Please do not include this header file directly."
+#endif
+
+#ifndef EOS_APPLICATION_H
+#define EOS_APPLICATION_H
+
+#include "types.h"
+
+#include <gtk/gtk.h>
+
+#define EOS_TYPE_APPLICATION eos_application_get_type()
+
+#define EOS_APPLICATION(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ EOS_TYPE_APPLICATION, EosApplication))
+
+#define EOS_APPLICATION_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ EOS_TYPE_APPLICATION, EosApplicationClass))
+
+#define EOS_IS_APPLICATION(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ EOS_TYPE_APPLICATION))
+
+#define EOS_IS_APPLICATION_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ EOS_TYPE_APPLICATION))
+
+#define EOS_APPLICATION_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ EOS_TYPE_APPLICATION, EosApplicationClass))
+
+typedef struct _EosApplication EosApplication;
+typedef struct _EosApplicationClass EosApplicationClass;
+typedef struct _EosApplicationPrivate EosApplicationPrivate;
+
+/**
+ * EosApplication:
+ *
+ * This class structure contains no public members.
+ */
+struct _EosApplication
+{
+ /*< private >*/
+ GtkApplication parent;
+
+ EosApplicationPrivate *priv;
+};
+
+struct _EosApplicationClass
+{
+ GtkApplicationClass parent_class;
+
+ /* For further expansion */
+ gpointer _padding[8];
+};
+
+EOS_SDK_ALL_API_VERSIONS
+GType eos_application_get_type (void) G_GNUC_CONST;
+
+EOS_SDK_ALL_API_VERSIONS
+EosApplication *eos_application_new (const gchar *application_id,
+ GApplicationFlags flags);
+
+G_END_DECLS
+
+#endif /* EOS_APPLICATION_H */
diff --git a/endless/endless.h b/endless/endless.h
index 84a33b0..b452247 100644
--- a/endless/endless.h
+++ b/endless/endless.h
@@ -12,6 +12,8 @@ G_BEGIN_DECLS
/* Pull in other header files */
#include "types.h"
+#include "application.h"
+#include "window.h"
#undef _EOS_SDK_INSIDE_ENDLESS_H
diff --git a/endless/types.h b/endless/types.h
index a572d7c..bfa5c1b 100644
--- a/endless/types.h
+++ b/endless/types.h
@@ -11,6 +11,8 @@
#include "macros.h"
#include "apiversion.h"
+#include <glib-object.h>
+
/* Shared typedefs for structures */
#endif /* EOS_TYPES_H */
diff --git a/endless/window.c b/endless/window.c
new file mode 100644
index 0000000..86c95fa
--- /dev/null
+++ b/endless/window.c
@@ -0,0 +1,121 @@
+/* Copyright 2013 Endless Mobile, Inc. */
+
+#include "config.h"
+#include "window.h"
+
+#include "application.h"
+
+#include <gtk/gtk.h>
+
+/**
+ * SECTION:window
+ * @short_description: A window for your application
+ * @title: Window
+ *
+ * Stub
+ */
+
+G_DEFINE_TYPE (EosWindow, eos_window, GTK_TYPE_APPLICATION_WINDOW)
+
+#define WINDOW_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), EOS_TYPE_WINDOW, EosWindowPrivate))
+
+struct _EosWindowPrivate
+{
+ EosApplication *application;
+};
+
+enum
+{
+ PROP_0,
+ PROP_APPLICATION,
+ NPROPS
+};
+
+static GParamSpec *eos_window_props[NPROPS] = { NULL, };
+
+static void
+eos_window_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ EosWindow *self = EOS_WINDOW (object);
+
+ switch (property_id)
+ {
+ case PROP_APPLICATION:
+ g_value_set_object (value, self->priv->application);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+eos_window_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EosWindow *self = EOS_WINDOW (object);
+
+ switch (property_id)
+ {
+ case PROP_APPLICATION:
+ self->priv->application = g_value_get_object (value);
+ gtk_window_set_application (GTK_WINDOW (self),
+ GTK_APPLICATION (self->priv->application));
+ if (self->priv->application == NULL)
+ g_critical ("In order to create a window, you must have an application "
+ "for it to connect to.");
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+eos_window_class_init (EosWindowClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (EosWindowPrivate));
+
+ object_class->get_property = eos_window_get_property;
+ object_class->set_property = eos_window_set_property;
+
+ eos_window_props[PROP_APPLICATION] =
+ g_param_spec_object ("application", "Application",
+ "Application associated with this window",
+ EOS_TYPE_APPLICATION,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, NPROPS, eos_window_props);
+}
+
+static void
+eos_window_init (EosWindow *self)
+{
+ self->priv = WINDOW_PRIVATE (self);
+}
+
+/* Public API */
+
+/**
+ * eos_window_new:
+ * @application: the #EosApplication that the window belongs to.
+ *
+ * Create a window. It is invisible by default.
+ *
+ * Returns: a pointer to the window.
+ */
+GtkWidget *
+eos_window_new (EosApplication *application)
+{
+ return GTK_WIDGET (g_object_new (EOS_TYPE_WINDOW,
+ "application", application,
+ NULL));
+}
diff --git a/endless/window.h b/endless/window.h
new file mode 100644
index 0000000..b92b4eb
--- /dev/null
+++ b/endless/window.h
@@ -0,0 +1,71 @@
+/* Copyright 2013 Endless Mobile, Inc. */
+
+#if !(defined(_EOS_SDK_INSIDE_ENDLESS_H) || defined(COMPILING_EOS_SDK))
+#error "Please do not include this header file directly."
+#endif
+
+#ifndef EOS_WINDOW_H
+#define EOS_WINDOW_H
+
+#include "types.h"
+
+#include "application.h"
+
+G_BEGIN_DECLS
+
+#define EOS_TYPE_WINDOW eos_window_get_type()
+
+#define EOS_WINDOW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ EOS_TYPE_WINDOW, EosWindow))
+
+#define EOS_WINDOW_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ EOS_TYPE_WINDOW, EosWindowClass))
+
+#define EOS_IS_WINDOW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ EOS_TYPE_WINDOW))
+
+#define EOS_IS_WINDOW_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ EOS_TYPE_WINDOW))
+
+#define EOS_WINDOW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ EOS_TYPE_WINDOW, EosWindowClass))
+
+typedef struct _EosWindow EosWindow;
+typedef struct _EosWindowClass EosWindowClass;
+typedef struct _EosWindowPrivate EosWindowPrivate;
+
+/**
+ * EosWindow:
+ *
+ * This class structure contains no public members.
+ */
+struct _EosWindow
+{
+ /*< private >*/
+ GtkApplicationWindow parent;
+
+ EosWindowPrivate *priv;
+};
+
+struct _EosWindowClass
+{
+ GtkApplicationWindowClass parent_class;
+
+ /* For further expansion */
+ gpointer _padding[8];
+};
+
+EOS_SDK_ALL_API_VERSIONS
+GType eos_window_get_type (void) G_GNUC_CONST;
+
+EOS_SDK_ALL_API_VERSIONS
+GtkWidget *eos_window_new (EosApplication *application);
+
+G_END_DECLS
+
+#endif /* EOS_WINDOW_H */
diff --git a/test/Makefile.am b/test/Makefile.am
index 85c0fe7..0211c7e 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -10,7 +10,9 @@ TEST_LIBS = @EOS_SDK_LIBS@ $(top_builddir)/libendless-@EOS_SDK_API_VERSION@.la
test_run_tests_SOURCES = \
test/run-tests.c \
test/test-init.c \
- test/test-hello.c
+ test/test-hello.c \
+ test/test-application.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 ba016bc..96cd4b8 100644
--- a/test/run-tests.c
+++ b/test/run-tests.c
@@ -2,6 +2,7 @@
#include <glib-object.h>
#include <glib.h>
+#include <gtk/gtk.h>
#include "run-tests.h"
@@ -10,9 +11,12 @@ main (int argc,
char **argv)
{
g_test_init (&argc, &argv, NULL);
+ gtk_init (&argc, &argv);
add_init_tests ();
add_hello_tests ();
+ add_application_tests ();
+ add_window_tests ();
return g_test_run ();
}
diff --git a/test/run-tests.h b/test/run-tests.h
index 3efac9e..1d4c402 100644
--- a/test/run-tests.h
+++ b/test/run-tests.h
@@ -3,7 +3,9 @@
#ifndef RUN_TESTS_H
#define RUN_TESTS_H
-void add_init_tests (void);
-void add_hello_tests (void);
+void add_init_tests (void);
+void add_hello_tests (void);
+void add_application_tests (void);
+void add_window_tests (void);
#endif /* RUN_TESTS_H */
diff --git a/test/smoke-tests/app-window.js b/test/smoke-tests/app-window.js
new file mode 100644
index 0000000..ab89961
--- /dev/null
+++ b/test/smoke-tests/app-window.js
@@ -0,0 +1,21 @@
+// Copyright 2013 Endless Mobile, Inc.
+
+const Lang = imports.lang;
+const Endless = imports.gi.Endless;
+
+const TEST_APPLICATION_ID = 'com.endlessm.example.test';
+
+const TestApplication = new Lang.Class ({
+ Name: 'TestApplication',
+ Extends: Endless.Application,
+
+ vfunc_startup: function() {
+ this.parent();
+ this._window = new Endless.Window({application: this});
+ this._window.show_all();
+ },
+});
+
+let app = new TestApplication({ application_id: TEST_APPLICATION_ID,
+ flags: 0 });
+app.run(ARGV);
diff --git a/test/test-application.c b/test/test-application.c
new file mode 100644
index 0000000..2b2411c
--- /dev/null
+++ b/test/test-application.c
@@ -0,0 +1,48 @@
+/* Copyright 2013 Endless Mobile, Inc. */
+
+#include <stdlib.h>
+#include <gtk/gtk.h>
+#include <endless/endless.h>
+
+#include "run-tests.h"
+
+#define TEST_APPLICATION_ID "com.endlessm.example.test"
+#define EXPECTED_TWO_WINDOW_ERRMSG "*You should not add more than one application window*"
+
+static void
+_two_windows_on_startup (EosApplication *app, gpointer data)
+{
+ GtkWidget *win1, *win2;
+ win1 = eos_window_new (app);
+ win2 = eos_window_new (app);
+
+ /* Destroy the windows so that the application exits */
+ gtk_widget_destroy (win1);
+ gtk_widget_destroy (win2);
+}
+
+static void
+test_undefined_two_windows (void)
+{
+ EosApplication *app = eos_application_new(TEST_APPLICATION_ID, 0);
+ g_signal_connect (app, "startup",
+ G_CALLBACK (_two_windows_on_startup), NULL);
+
+ /* Unix-only test */
+ if (g_test_trap_fork(0 /* timeout */, G_TEST_TRAP_SILENCE_STDERR))
+ {
+ g_application_run (G_APPLICATION (app), 0, NULL);
+ exit (0);
+ }
+
+ g_test_trap_assert_failed ();
+ g_test_trap_assert_stderr (EXPECTED_TWO_WINDOW_ERRMSG);
+}
+
+void
+add_application_tests (void)
+{
+ /* Tests for undefined behavior, i.e. programming errors */
+ if (g_test_undefined ())
+ g_test_add_func ("/application/two-windows", test_undefined_two_windows);
+}
diff --git a/test/test-window.c b/test/test-window.c
new file mode 100644
index 0000000..831d94c
--- /dev/null
+++ b/test/test-window.c
@@ -0,0 +1,24 @@
+/* Copyright 2013 Endless Mobile, Inc. */
+
+#include <stdlib.h>
+#include <gtk/gtk.h>
+#include <endless/endless.h>
+
+#include "run-tests.h"
+
+static void
+test_assign_application (GApplication *app)
+{
+ GtkWidget *win = eos_window_new (EOS_APPLICATION (app));
+
+ g_assert(EOS_APPLICATION (app)
+ == EOS_APPLICATION (gtk_window_get_application (GTK_WINDOW (win))));
+
+ gtk_widget_destroy (win);
+}
+
+void
+add_window_tests (void)
+{
+ ADD_APP_WINDOW_TEST ("/window/assign-application", test_assign_application);
+}