From 096c63f7ed002b99a995c35a407483a0bfa161c5 Mon Sep 17 00:00:00 2001 From: "P. F. Chimento" Date: Mon, 15 Apr 2013 18:04:27 +0200 Subject: 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] --- endless/Makefile.am | 8 ++- endless/application.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++++++ endless/application.h | 70 +++++++++++++++++++++ endless/endless.h | 2 + endless/types.h | 2 + endless/window.c | 121 ++++++++++++++++++++++++++++++++++++ endless/window.h | 71 ++++++++++++++++++++++ 7 files changed, 437 insertions(+), 2 deletions(-) create mode 100644 endless/application.c create mode 100644 endless/application.h create mode 100644 endless/window.c create mode 100644 endless/window.h (limited to 'endless') 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 + +#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, + * Smoke Grinder: + * |[ + * 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 com.endlessm.weather. 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 + +#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 + /* 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 + +/** + * 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 */ -- cgit v1.2.3