summaryrefslogtreecommitdiff
path: root/endless/eosapplication.c
diff options
context:
space:
mode:
Diffstat (limited to 'endless/eosapplication.c')
-rw-r--r--endless/eosapplication.c404
1 files changed, 404 insertions, 0 deletions
diff --git a/endless/eosapplication.c b/endless/eosapplication.c
index 72016c1..510ff3b 100644
--- a/endless/eosapplication.c
+++ b/endless/eosapplication.c
@@ -2,12 +2,16 @@
#include "config.h"
#include "eosapplication.h"
+#include "eosattribution-private.h"
+#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
#include "eoswindow.h"
#define CSS_THEME_URI "resource:///com/endlessm/sdk/css/endless-widgets.css"
+#define _CREDITS_DIALOG_DEFAULT_HEIGHT 450
+#define _CREDITS_DIALOG_DEFAULT_WIDTH 750
/**
* SECTION:application
@@ -46,12 +50,186 @@
* flags: 0 });
* app.run(ARGV);
* ]|
+ *
+ * You can specify attribution for images used in your application.
+ * This is important if you use images that require you to credit the original
+ * author, or Creative Commons-licenses.
+ * The attribution takes the form of a JSON file, an array of objects with the
+ * properties listed in <xref linkend="image-attribution-properties"/>.
+ * See #EosApplication:image-attribution-file.
+ *
+ * <table id="image-attribution-properties">
+ * <thead>
+ * <tr>
+ * <th align="left">Property</th>
+ * <th align="left">Required?</th>
+ * <th align="left">Type</th>
+ * <th align="left">Description</th>
+ * </tr>
+ * </thead>
+ * <tr>
+ * <td><code>resource_path</code></td>
+ * <td>Yes</td>
+ * <td>string</td>
+ * <td>
+ * Resource path to the image (e.g. <code>/com/example/...</code>)
+ * </td>
+ * </tr>
+ * <tr>
+ * <td><code>uri</code></td>
+ * <td>No</td>
+ * <td>string</td>
+ * <td>
+ * URI where the original image is to be found: e.g., a Flickr link.
+ * </td>
+ * </tr>
+ * <tr>
+ * <td><code>license</code></td>
+ * <td>*</td>
+ * <td>string</td>
+ * <td>
+ * Text identifying the license under which you are using this image.
+ * This field is not free-form; the allowed values are listed in <xref
+ * linkend="image-attribution-licenses"/>.
+ * If the license is not listed there, leave this field blank and clarify
+ * the license in the <code>comment</code> field.
+ * </td>
+ * </tr>
+ * <tr>
+ * <td><code>license_uri</code></td>
+ * <td>*</td>
+ * <td>string</td>
+ * <td>
+ * URI linking to the text of the image license.
+ * If you use the <code>license</code> field, this field may be
+ * automatically filled in, so you can leave it blank.
+ * If you do specify a value, then your value will override any automatic
+ * value.
+ * Note that you will then lose any localization from the automatic value;
+ * localization of this field is planned for later.
+ * </td>
+ * </tr>
+ * <tr>
+ * <td><code>credit</code></td>
+ * <td>*</td>
+ * <td>string</td>
+ * <td>
+ * The name or username of the author of the image.
+ * This is appropriate when the terms of use specify that the author is to
+ * be credited when the image is used.
+ * </td>
+ * </tr>
+ * <tr>
+ * <td><code>credit_contact</code></td>
+ * <td>No</td>
+ * <td>string</td>
+ * <td>
+ * URI at which the author can be contacted.
+ * (If this is an e-mail address, prefix it with <code>mailto:</code> so
+ * that it is a valid URI.)
+ * </td>
+ * </tr>
+ * <tr>
+ * <td><code>copyright_holder</code></td>
+ * <td>*</td>
+ * <td>string</td>
+ * <td>
+ * Copyright holder of the image.
+ * </td>
+ * </tr>
+ * <tr>
+ * <td><code>copyright_year</code></td>
+ * <td>No</td>
+ * <td>integer</td>
+ * <td>
+ * Copyright year of the image.
+ * This will be displayed along with the copyright holder.
+ * </td>
+ * </tr>
+ * <tr>
+ * <td><code>permission</code></td>
+ * <td>No</td>
+ * <td>boolean</td>
+ * <td>
+ * Whether the image is used with permission.
+ * If this is specified, a string such as <quote>Used with
+ * permission</quote> may be displayed.
+ * </td>
+ * </tr>
+ * <tr>
+ * <td><code>comment</code></td>
+ * <td>No</td>
+ * <td>string</td>
+ * <td>
+ * Any other comments about the image license, terms of use, or source.
+ * </td>
+ * </tr>
+ * <tfoot>
+ * <tr>
+ * <td colspan="4">*At least one of these properties is required.</td>
+ * </tr>
+ * </tfoot>
+ * <caption>Allowed properties of the objects in the image attribution JSON
+ * file</caption>
+ * </table>
+ * <para></para>
+ * <table id="image-attribution-licenses">
+ * <thead>
+ * <tr>
+ * <th align="left">String</th>
+ * <th align="left">Description</th>
+ * </tr>
+ * </thead>
+ * <tr>
+ * <td>Public domain</td>
+ * <td>Public domain</td>
+ * </tr>
+ * <tr>
+ * <td>CC0 1.0</td>
+ * <td><ulink url="http://creativecommons.org/publicdomain/zero/1.0/">CC0
+ * 1.0 Universal (Public domain)</ulink></td>
+ * </tr>
+ * <tr>
+ * <td>CC BY 2.0</td>
+ * <td><ulink url="http://creativecommons.org/licenses/by/2.0/">Creative
+ * Commons Attribution 2.0</ulink></td>
+ * </tr>
+ * <tr>
+ * <td>CC BY 3.0</td>
+ * <td><ulink url="http://creativecommons.org/licenses/by/3.0/">Creative
+ * Commons Attribution 3.0</ulink></td>
+ * </tr>
+ * <tr>
+ * <td>CC BY-SA 2.0</td>
+ * <td><ulink url="http://creativecommons.org/licenses/by-sa/2.0/">Creative
+ * Commons Attribution-ShareAlike 2.0</ulink></td>
+ * </tr>
+ * <tr>
+ * <td>CC BY-SA 3.0</td>
+ * <td><ulink url="http://creativecommons.org/licenses/by-sa/3.0/">Creative
+ * Commons Attribution-ShareAlike 3.0</ulink></td>
+ * </tr>
+ * <tr>
+ * <td>CC BY-ND 2.0</td>
+ * <td><ulink url="http://creativecommons.org/licenses/by-nd/2.0/">Creative
+ * Commons Attribution-NoDerivs 2.0</ulink></td>
+ * </tr>
+ * <tr>
+ * <td>CC BY-ND 3.0</td>
+ * <td><ulink url="http://creativecommons.org/licenses/by-nd/3.0/">Creative
+ * Commons Attribution-NoDerivs 3.0</ulink></td>
+ * </tr>
+ * <caption>Allowed values for the <code>license</code> property in the image
+ * attribution JSON file</caption>
+ * </table>
*/
typedef struct {
GOnce init_config_dir_once;
GFile *config_dir;
+ GFile *image_attribution_file;
+
EosWindow *main_application_window;
} EosApplicationPrivate;
@@ -61,11 +239,65 @@ enum
{
PROP_0,
PROP_CONFIG_DIR,
+ PROP_IMAGE_ATTRIBUTION_FILE,
NPROPS
};
static GParamSpec *eos_application_props[NPROPS] = { NULL, };
+/* Signal handler for attribution widget requesting to show uri */
+static void
+on_attribution_show_uri (EosAttribution *attribution,
+ const gchar *uri,
+ EosApplication *self)
+{
+ GError *error = NULL;
+ if (!gtk_show_uri (NULL, uri, GDK_CURRENT_TIME, &error))
+ {
+ g_critical ("Error showing URI %s: %s", uri, error->message);
+ g_error_free (error);
+ }
+}
+
+/* Signal handler for app.image-credits::activate action */
+static void
+on_image_credits_activate (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer data)
+{
+ EosApplication *self = EOS_APPLICATION (data);
+ EosApplicationPrivate *priv = eos_application_get_instance_private (self);
+ GtkWidget *dialog, *attribution, *content;
+ GError *error = NULL;
+
+ attribution = eos_attribution_new_sync (priv->image_attribution_file, NULL,
+ &error);
+ if (attribution == NULL)
+ {
+ g_warning ("Error loading image attribution file: %s", error->message);
+ return;
+ }
+ gtk_widget_set_hexpand (attribution, TRUE);
+ gtk_widget_set_vexpand (attribution, TRUE);
+ g_signal_connect (attribution, "show-uri",
+ G_CALLBACK (on_attribution_show_uri), self);
+ gtk_widget_show_all (attribution);
+
+ dialog = g_object_new (GTK_TYPE_DIALOG,
+ "default-height", _CREDITS_DIALOG_DEFAULT_HEIGHT,
+ "default-width", _CREDITS_DIALOG_DEFAULT_WIDTH,
+ "destroy-with-parent", TRUE,
+ "modal", TRUE,
+ "title", _("Image credits"),
+ "transient-for", GTK_WINDOW (priv->main_application_window),
+ "use-header-bar", TRUE,
+ NULL);
+ content = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+ gtk_container_add (GTK_CONTAINER (content), attribution);
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+}
+
static void
eos_application_get_property (GObject *object,
guint property_id,
@@ -80,6 +312,30 @@ eos_application_get_property (GObject *object,
g_value_set_object (value, eos_application_get_config_dir (self));
break;
+ case PROP_IMAGE_ATTRIBUTION_FILE:
+ g_value_set_object (value, eos_application_get_image_attribution_file (self));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+eos_application_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ EosApplication *self = EOS_APPLICATION (object);
+
+ switch (property_id)
+ {
+ case PROP_IMAGE_ATTRIBUTION_FILE:
+ eos_application_set_image_attribution_file (self,
+ g_value_get_object (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@@ -91,6 +347,7 @@ eos_application_finalize (GObject *object)
EosApplication *self = EOS_APPLICATION (object);
EosApplicationPrivate *priv = eos_application_get_instance_private (self);
g_clear_object (&priv->config_dir);
+ g_clear_object (&priv->image_attribution_file);
G_OBJECT_CLASS (eos_application_parent_class)->finalize (object);
}
@@ -172,6 +429,12 @@ eos_application_startup (GApplication *application)
{
G_APPLICATION_CLASS (eos_application_parent_class)->startup (application);
+ /* Set up the hotkey for the image credit dialog */
+ static const gchar * const accelerators[] = { "<Primary><Shift>a", NULL };
+ gtk_application_set_accels_for_action (GTK_APPLICATION (application),
+ "app.image-credits",
+ accelerators);
+
GtkCssProvider *provider = gtk_css_provider_new ();
/* Reset CSS for SDK applications and apply our own theme on top of it. This
@@ -265,6 +528,7 @@ eos_application_class_init (EosApplicationClass *klass)
GtkApplicationClass *gtk_application_class = GTK_APPLICATION_CLASS (klass);
object_class->get_property = eos_application_get_property;
+ object_class->set_property = eos_application_set_property;
object_class->finalize = eos_application_finalize;
g_application_class->activate = eos_application_activate;
g_application_class->startup = eos_application_startup;
@@ -285,16 +549,92 @@ eos_application_class_init (EosApplicationClass *klass)
"User configuration directory for this application",
G_TYPE_FILE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ /**
+ * EosApplication:image-attribution-file:
+ *
+ * A #GFile handle to a file for storing attribution information for the
+ * images included in this application's resource file.
+ *
+ * This attribution file must be a JSON file.
+ * Here is an example of the required format:
+ * |[
+ * [
+ * {
+ * "resource_path": "/com/example/smokegrinder/image1.jpg",
+ * "license": "Public domain",
+ * "uri": "http://www.photos.com/photos/12345",
+ * "comment": "No known copyright restrictions"
+ * },
+ * {
+ * "resource_path": "/com/example/smokegrinder/image2.jpg",
+ * "license_uri": "http://example.com/image-license",
+ * "uri": "http://www.photos.com/photos/54321",
+ * "credit": "Edward X. Ample",
+ * "credit_contact": "http://www.photos.com/users/example"
+ * },
+ * {
+ * "resource_path": "/com/example/smokegrinder/image3.jpg",
+ * "copyright_holder": "Jane Q. Hacker",
+ * "copyright_year": 2014,
+ * "permission": true
+ * }
+ * ]
+ * ]|
+ *
+ * The JSON object is an array of objects that each contain information about
+ * one image.
+ * The only required property is <code>resource_path</code>, which is the path
+ * to the image in the resource file.
+ *
+ * The recognized properties are shown in <xref
+ * linkend="image-attribution-properties"/>.
+ *
+ * Nothing is guaranteed about how the application uses this information.
+ * It can display it to the user or make it available to other programs.
+ *
+ * <note><para>
+ * Currently, pressing <keycombo><keycap>Control</keycap>
+ * <keycap>Shift</keycap><keycap>A</keycap></keycombo> brings up a credits
+ * dialog.
+ * This is liable to change in future versions.
+ * </para></note>
+ *
+ * Since: 0.2
+ */
+ eos_application_props[PROP_IMAGE_ATTRIBUTION_FILE] =
+ g_param_spec_object ("image-attribution-file", "Image attribution file",
+ "File with attribution information for images in this application",
+ G_TYPE_FILE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, NPROPS,
eos_application_props);
}
static void
+set_image_credits_action_enabled (EosApplication *self,
+ gboolean enabled)
+{
+ GAction *action = g_action_map_lookup_action (G_ACTION_MAP (self),
+ "image-credits");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), enabled);
+ /* action map owns action */
+}
+
+static void
eos_application_init (EosApplication *self)
{
EosApplicationPrivate *priv = eos_application_get_instance_private (self);
priv->init_config_dir_once = (GOnce)G_ONCE_INIT;
+
+ /* Set up app actions */
+ static const GActionEntry actions[] = {
+ { "image-credits", on_image_credits_activate },
+ };
+ g_action_map_add_action_entries (G_ACTION_MAP (self), actions,
+ G_N_ELEMENTS (actions), self);
+ set_image_credits_action_enabled (self, FALSE);
+
g_signal_connect (self, "notify::application-id",
G_CALLBACK (on_app_id_set), self);
}
@@ -353,3 +693,67 @@ eos_application_get_config_dir (EosApplication *self)
(GThreadFunc)ensure_config_dir_exists_and_is_writable, self);
return priv->config_dir;
}
+
+/**
+ * eos_application_get_image_attribution_file:
+ * @self: the application
+ *
+ * Gets a #GFile pointing to a JSON file containing credits for images included
+ * in the app's resources.
+ * See #EosApplication:image-attribution-file.
+ *
+ * Returns: (transfer none) (allow-none): A #GFile pointing to the image
+ * attribution file, or %NULL if one has not been set.
+ *
+ * Since: 0.2
+ */
+GFile *
+eos_application_get_image_attribution_file (EosApplication *self)
+{
+ g_return_val_if_fail (self != NULL && EOS_IS_APPLICATION (self), NULL);
+
+ EosApplicationPrivate *priv = eos_application_get_instance_private (self);
+ return priv->image_attribution_file;
+}
+
+/**
+ * eos_application_set_image_attribution_file:
+ * @self: the application
+ * @file: (allow-none): a #GFile pointing to a file in the proper format, or
+ * %NULL to unset.
+ *
+ * You can provide attribution and credit for images included in the application
+ * by giving this function a JSON file with image credits.
+ * See #EosApplication:image-attribution-file for the JSON file's required
+ * format.
+ *
+ * Since: 0.2
+ */
+void
+eos_application_set_image_attribution_file (EosApplication *self,
+ GFile *file)
+{
+ g_return_if_fail (self != NULL && EOS_IS_APPLICATION (self));
+ g_return_if_fail (file == NULL || G_IS_FILE (file));
+
+ EosApplicationPrivate *priv = eos_application_get_instance_private (self);
+
+ if (priv->image_attribution_file == file ||
+ (priv->image_attribution_file != NULL && file != NULL &&
+ g_file_equal (file, priv->image_attribution_file)))
+ return;
+
+ if (priv->image_attribution_file == NULL || file == NULL)
+ {
+ gboolean enabled = (file != NULL);
+ set_image_credits_action_enabled (self, enabled);
+ }
+
+ g_clear_object (&priv->image_attribution_file);
+ if (file != NULL)
+ g_object_ref (file);
+ priv->image_attribution_file = file;
+
+ g_object_notify_by_pspec (G_OBJECT (self),
+ eos_application_props[PROP_IMAGE_ATTRIBUTION_FILE]);
+}