/*
* Copyright (C) 2010-2011 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANAPPLICATIONILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authored by:
* Robert Carr
*
*/
#include
#include "bamf-unity-webapps-application.h"
#include "bamf-unity-webapps-tab.h"
#include "bamf-matcher.h"
#include
#define BAMF_UNITY_WEBAPPS_APPLICATION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE(obj, \
BAMF_TYPE_UNITY_WEBAPPS_APPLICATION, BamfUnityWebappsApplicationPrivate))
G_DEFINE_TYPE(BamfUnityWebappsApplication, bamf_unity_webapps_application, BAMF_TYPE_APPLICATION);
enum
{
PROP_0,
PROP_CONTEXT,
};
struct _BamfUnityWebappsApplicationPrivate
{
UnityWebappsContext *context;
};
static void
bamf_unity_webapps_application_get_application_menu (BamfApplication *application,
gchar **name,
gchar **path)
{
BamfUnityWebappsApplication *self;
self = (BamfUnityWebappsApplication *)application;
*name = g_strdup (unity_webapps_context_get_context_name (self->priv->context));
*path = g_strdup (UNITY_WEBAPPS_CONTEXT_MENU_PATH);
}
static void
bamf_unity_webapps_application_get_property (GObject *object, guint property_id, GValue *gvalue, GParamSpec *pspec)
{
BamfUnityWebappsApplication *self;
self = BAMF_UNITY_WEBAPPS_APPLICATION (object);
switch (property_id)
{
case PROP_CONTEXT:
g_value_set_object (gvalue, self->priv->context);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static BamfUnityWebappsTab *
bamf_unity_webapps_application_find_child_by_interest (BamfUnityWebappsApplication *application,
gint interest_id)
{
GList *children, *walk;
BamfUnityWebappsTab *child;
children = bamf_view_get_children (BAMF_VIEW (application));
for (walk = children; walk != NULL; walk = walk->next)
{
child = BAMF_UNITY_WEBAPPS_TAB (walk->data);
if (interest_id == bamf_unity_webapps_tab_get_interest_id (child))
{
return child;
}
}
return NULL;
}
static BamfView *
bamf_unity_webapps_application_get_focusable_child (BamfApplication *application)
{
BamfUnityWebappsApplication *self;
gint focus_interest;
self = BAMF_UNITY_WEBAPPS_APPLICATION (application);
focus_interest = unity_webapps_context_get_focus_interest (self->priv->context);
if (focus_interest == -1)
return NULL;
return (BamfView *)bamf_unity_webapps_application_find_child_by_interest (self, focus_interest);
}
static void
bamf_unity_webapps_application_interest_appeared (UnityWebappsContext *context,
gint interest_id,
gpointer user_data)
{
BamfUnityWebappsApplication *self;
BamfUnityWebappsTab *child;
self = BAMF_UNITY_WEBAPPS_APPLICATION (user_data);
child = bamf_unity_webapps_application_find_child_by_interest (self, interest_id);
if (child != NULL)
{
return;
}
child = bamf_unity_webapps_tab_new (context, interest_id);
bamf_view_add_child (BAMF_VIEW (self), BAMF_VIEW (child));
// It's possible that the context had become lonely (i.e. no children) but not yet shut down.
// however, if we gain an interest we are always running and "mapped".
bamf_view_set_running (BAMF_VIEW (self), TRUE);
bamf_view_set_user_visible (BAMF_VIEW (self), TRUE);
}
static void
bamf_unity_webapps_application_interest_vanished (UnityWebappsContext *context,
gint interest_id,
gpointer user_data)
{
BamfUnityWebappsApplication *self;
BamfUnityWebappsTab *child;
self = (BamfUnityWebappsApplication *)user_data;
child = bamf_unity_webapps_application_find_child_by_interest (self, interest_id);
if (child == NULL)
{
return;
}
bamf_view_remove_child (BAMF_VIEW (self), BAMF_VIEW (child));
}
/* It doesn't make any sense for a BamfUnityWebappsTab to live without it's assosciated context.
* so when our children are removed, dispose of them. */
static void
bamf_unity_webapps_application_child_removed (BamfView *view, BamfView *child)
{
// Chain up first before we destroy the object.
BAMF_VIEW_CLASS (bamf_unity_webapps_application_parent_class)->child_removed (view, child);
bamf_view_set_running (child, FALSE);
bamf_view_close (BAMF_VIEW (child));
}
void
bamf_unity_webapps_application_add_existing_interests (BamfUnityWebappsApplication *self)
{
GVariant *interests, *interest_variant;
GVariantIter *variant_iter;
interests = unity_webapps_context_list_interests (self->priv->context);
if (interests == NULL)
{
return;
}
variant_iter = g_variant_iter_new (interests);
while ((interest_variant = g_variant_iter_next_value (variant_iter)))
{
gint interest_id;
interest_id = g_variant_get_int32 (interest_variant);
bamf_unity_webapps_application_interest_appeared (self->priv->context, interest_id, self);
}
}
static void
bamf_unity_webapps_application_context_set (BamfUnityWebappsApplication *self)
{
bamf_application_set_desktop_file_from_id (BAMF_APPLICATION (self),
unity_webapps_context_get_desktop_name (self->priv->context));
unity_webapps_context_on_interest_appeared (self->priv->context, bamf_unity_webapps_application_interest_appeared, self);
unity_webapps_context_on_interest_vanished (self->priv->context, bamf_unity_webapps_application_interest_vanished, self);
}
static void
bamf_unity_webapps_application_set_property (GObject *object, guint property_id, const GValue *gvalue, GParamSpec *pspec)
{
BamfUnityWebappsApplication *self;
self = BAMF_UNITY_WEBAPPS_APPLICATION (object);
switch (property_id)
{
case PROP_CONTEXT:
g_assert (self->priv->context == NULL);
self->priv->context = g_value_get_object (gvalue);
bamf_unity_webapps_application_context_set (self);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
}
}
static gchar *
bamf_unity_webapps_application_get_stable_bus_name (BamfView *view)
{
const gchar *desktop_file;
desktop_file = bamf_application_get_desktop_file (BAMF_APPLICATION (view));
if (desktop_file)
{
return g_strdup_printf ("webapp/%i", abs (g_str_hash (desktop_file)));
}
return g_strdup_printf ("webapp/%p", view);
}
static void
bamf_unity_webapps_application_finalize (GObject *object)
{
BamfUnityWebappsApplication *self = BAMF_UNITY_WEBAPPS_APPLICATION (object);
g_object_unref (self->priv->context);
G_OBJECT_CLASS (bamf_unity_webapps_application_parent_class)->finalize (object);
}
static void
on_accept_data_changed (UnityWebappsContext *context, const gchar **file, gpointer user_data)
{
BamfUnityWebappsApplication *self = BAMF_UNITY_WEBAPPS_APPLICATION (user_data);
g_signal_emit_by_name (self, "supported-mimes-changed", file);
}
static void
bamf_unity_webapps_application_constructed (GObject *object)
{
BamfUnityWebappsApplication *self;
self = (BamfUnityWebappsApplication *)object;
g_signal_connect (self->priv->context, "accept-data-changed", G_CALLBACK (on_accept_data_changed), self);
}
static void
bamf_unity_webapps_application_init (BamfUnityWebappsApplication *self)
{
self->priv = BAMF_UNITY_WEBAPPS_APPLICATION_GET_PRIVATE (self);
bamf_application_set_application_type (BAMF_APPLICATION (self), BAMF_APPLICATION_WEB);
}
static char **
bamf_unity_webapps_application_get_supported_mime_types (BamfApplication *application)
{
BamfUnityWebappsApplication *self = BAMF_UNITY_WEBAPPS_APPLICATION (application);
return unity_webapps_context_get_application_accept_data (self->priv->context);
}
static gboolean
bamf_unity_webapps_application_get_close_when_empty (BamfApplication *application)
{
// Sometimes we might have no children for a short period (for example, the page is reloading), in the case
// Unity Webapps will keep the context alive for a while. Allowing for new children to appear...before eventually
// shutting it down. So we use this flag to ensure BAMF will not shut us down prematurely.
return FALSE;
}
static void
bamf_unity_webapps_application_class_init (BamfUnityWebappsApplicationClass * klass)
{
GParamSpec *pspec;
GObjectClass *object_class = G_OBJECT_CLASS (klass);
BamfApplicationClass *bamf_application_class = BAMF_APPLICATION_CLASS (klass);
BamfViewClass *bamf_view_class = BAMF_VIEW_CLASS (klass);
object_class->get_property = bamf_unity_webapps_application_get_property;
object_class->set_property = bamf_unity_webapps_application_set_property;
object_class->finalize = bamf_unity_webapps_application_finalize;
object_class->constructed = bamf_unity_webapps_application_constructed;
bamf_view_class->stable_bus_name = bamf_unity_webapps_application_get_stable_bus_name;
bamf_view_class->child_removed = bamf_unity_webapps_application_child_removed;
bamf_application_class->get_application_menu = bamf_unity_webapps_application_get_application_menu;
bamf_application_class->get_focusable_child = bamf_unity_webapps_application_get_focusable_child;
bamf_application_class->get_supported_mime_types = bamf_unity_webapps_application_get_supported_mime_types;
bamf_application_class->get_close_when_empty = bamf_unity_webapps_application_get_close_when_empty;
pspec = g_param_spec_object("context", "Context", "The Unity Webapps Context assosciated with the Application",
UNITY_WEBAPPS_TYPE_CONTEXT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_property (object_class, PROP_CONTEXT, pspec);
g_type_class_add_private (klass, sizeof (BamfUnityWebappsApplicationPrivate));
}
BamfApplication *
bamf_unity_webapps_application_new (UnityWebappsContext *context)
{
return (BamfApplication *)g_object_new (BAMF_TYPE_UNITY_WEBAPPS_APPLICATION, "context", context, NULL);
}
UnityWebappsContext *
bamf_unity_webapps_application_get_context (BamfUnityWebappsApplication *application)
{
return application->priv->context;
}