#include "cog-view.h"
#include "cog-platform.h"
#include "cog-view-private.h"
typedef struct {
gboolean use_key_bindings;
GWeakRef viewport;
} CogViewPrivate;
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(CogView, cog_view, WEBKIT_TYPE_WEB_VIEW)
struct _CogCoreViewClass {
CogViewClass parent_class;
};
enum {
PROP_0,
PROP_USE_KEY_BINDINGS,
PROP_VIEWPORT,
N_PROPERTIES,
};
static GParamSpec *s_properties[N_PROPERTIES] = {
NULL,
};
G_DECLARE_DERIVABLE_TYPE(CogCoreView, cog_core_view, COG, CORE_VIEW, CogView)
G_DEFINE_TYPE(CogCoreView, cog_core_view, COG_TYPE_VIEW)
static GObject *
cog_view_constructor(GType type, unsigned n_properties, GObjectConstructParam *properties)
{
GObject *object = G_OBJECT_CLASS(cog_view_parent_class)->constructor(type, n_properties, properties);
CogViewClass *view_class = COG_VIEW_GET_CLASS(object);
if (view_class->create_backend) {
WebKitWebViewBackend *backend = (*view_class->create_backend)((CogView *) object);
GValue backend_value = G_VALUE_INIT;
g_value_take_boxed(g_value_init(&backend_value, WEBKIT_TYPE_WEB_VIEW_BACKEND), backend);
g_object_set_property(object, "backend", &backend_value);
} else {
g_error("Type %s did not define the create_backend vfunc", g_type_name(type));
}
return object;
}
static void
cog_view_set_property(GObject *object, unsigned prop_id, const GValue *value, GParamSpec *pspec)
{
CogView *self = COG_VIEW(object);
switch (prop_id) {
case PROP_USE_KEY_BINDINGS:
cog_view_set_use_key_bindings(self, g_value_get_boolean(value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
}
}
static void
cog_view_get_property(GObject *object, unsigned prop_id, GValue *value, GParamSpec *pspec)
{
CogView *self = COG_VIEW(object);
switch (prop_id) {
case PROP_USE_KEY_BINDINGS:
g_value_set_boolean(value, cog_view_get_use_key_bindings(self));
break;
case PROP_VIEWPORT:
g_value_take_object(value, cog_view_get_viewport(self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
}
}
static void
cog_view_class_init(CogViewClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
object_class->set_property = cog_view_set_property;
object_class->get_property = cog_view_get_property;
object_class->constructor = cog_view_constructor;
s_properties[PROP_USE_KEY_BINDINGS] =
g_param_spec_boolean("use-key-bindings", NULL, NULL, TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
s_properties[PROP_VIEWPORT] =
g_param_spec_object("viewport", NULL, NULL, G_TYPE_OBJECT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties(object_class, N_PROPERTIES, s_properties);
}
static void
cog_view_init(CogView *self)
{
CogViewPrivate *priv = cog_view_get_instance_private(self);
g_weak_ref_init(&priv->viewport, NULL);
}
static inline struct wpe_view_backend *
cog_view_get_backend_internal(CogView *self)
{
WebKitWebViewBackend *backend = webkit_web_view_get_backend((WebKitWebView *) self);
return webkit_web_view_backend_get_wpe_backend(backend);
}
struct wpe_view_backend *
cog_view_get_backend(CogView *self)
{
g_return_val_if_fail(COG_IS_VIEW(self), NULL);
return cog_view_get_backend_internal(self);
}
static void *
_cog_view_get_impl_type_init(GType *type)
{
*type = cog_core_view_get_type();
CogPlatform *platform = cog_platform_get();
if (platform) {
CogPlatformClass *platform_class = COG_PLATFORM_GET_CLASS(platform);
if (platform_class->get_view_type) {
GType view_type = (*platform_class->get_view_type)();
*type = view_type;
}
}
g_debug("%s: using %s", G_STRFUNC, g_type_name(*type));
return NULL;
}
GType
cog_view_get_impl_type(void)
{
static GType view_type;
static GOnce once = G_ONCE_INIT;
g_once(&once, (GThreadFunc) _cog_view_get_impl_type_init, &view_type);
return view_type;
}
CogView *
cog_view_new(const char *first_property_name, ...)
{
va_list args;
va_start(args, first_property_name);
void *view = g_object_new_valist(cog_view_get_impl_type(), first_property_name, args);
va_end(args);
return view;
}
static WebKitWebViewBackend *
cog_core_view_create_backend(CogView *view G_GNUC_UNUSED)
{
g_autoptr(GError) error = NULL;
WebKitWebViewBackend *backend = cog_platform_get_view_backend(cog_platform_get(), NULL, &error);
if (!backend)
g_error("%s: Could not create view backend, %s", G_STRFUNC, error->message);
g_debug("%s: backend %p", G_STRFUNC, backend);
return backend;
}
static void
cog_core_view_class_init(CogCoreViewClass *klass)
{
CogViewClass *view_class = COG_VIEW_CLASS(klass);
view_class->create_backend = cog_core_view_create_backend;
}
static void
cog_core_view_init(CogCoreView *self)
{
}
static gboolean
cog_view_try_handle_key_binding(CogView *self, const struct wpe_input_keyboard_event *event)
{
static const float DEFAULT_ZOOM_STEP = 0.1f;
if (!event->pressed)
return FALSE;
if (event->modifiers == wpe_input_keyboard_modifier_control && event->key_code == WPE_KEY_w) {
GApplication *app = g_application_get_default();
if (app)
g_application_quit(app);
else
exit(EXIT_SUCCESS);
return TRUE;
}
if (event->modifiers == wpe_input_keyboard_modifier_control && event->key_code == WPE_KEY_plus) {
const double level = webkit_web_view_get_zoom_level(WEBKIT_WEB_VIEW(self));
webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(self), level + DEFAULT_ZOOM_STEP);
return TRUE;
}
if (event->modifiers == wpe_input_keyboard_modifier_control && event->key_code == WPE_KEY_minus) {
const double level = webkit_web_view_get_zoom_level(WEBKIT_WEB_VIEW(self));
webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(self), level - DEFAULT_ZOOM_STEP);
return TRUE;
}
if (event->modifiers == wpe_input_keyboard_modifier_control && event->key_code == WPE_KEY_0) {
webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(self), 1.0f);
return TRUE;
}
if (event->modifiers == wpe_input_keyboard_modifier_alt && event->key_code == WPE_KEY_Left) {
webkit_web_view_go_back(WEBKIT_WEB_VIEW(self));
return TRUE;
}
if (event->modifiers == wpe_input_keyboard_modifier_alt && event->key_code == WPE_KEY_Right) {
webkit_web_view_go_forward(WEBKIT_WEB_VIEW(self));
return TRUE;
}
if ((event->modifiers == wpe_input_keyboard_modifier_control && event->key_code == WPE_KEY_r) ||
(!event->modifiers && event->key_code == WPE_KEY_F5)) {
webkit_web_view_reload(WEBKIT_WEB_VIEW(self));
return true;
}
if ((event->modifiers == (wpe_input_keyboard_modifier_control | wpe_input_keyboard_modifier_shift) &&
event->key_code == WPE_KEY_R) ||
(event->modifiers == wpe_input_keyboard_modifier_shift && event->key_code == WPE_KEY_F5)) {
webkit_web_view_reload_bypass_cache(WEBKIT_WEB_VIEW(self));
return TRUE;
}
if (!event->modifiers && event->key_code == WPE_KEY_F11)
return cog_view_set_fullscreen(self, !cog_view_is_fullscreen(self));
return FALSE;
}
void
cog_view_handle_key_event(CogView *self, const struct wpe_input_keyboard_event *event)
{
g_return_if_fail(COG_IS_VIEW(self));
g_return_if_fail(event);
CogViewPrivate *priv = cog_view_get_instance_private(self);
if (priv->use_key_bindings && cog_view_try_handle_key_binding(self, event))
return;
struct wpe_input_keyboard_event event_copy = *event;
wpe_view_backend_dispatch_keyboard_event(cog_view_get_backend_internal(self), &event_copy);
}
void
cog_view_set_use_key_bindings(CogView *self, gboolean enable)
{
g_return_if_fail(COG_IS_VIEW(self));
CogViewPrivate *priv = cog_view_get_instance_private(COG_VIEW(self));
enable = !!enable;
if (priv->use_key_bindings == enable)
return;
priv->use_key_bindings = enable;
g_object_notify_by_pspec(G_OBJECT(self), s_properties[PROP_USE_KEY_BINDINGS]);
}
void
cog_view_set_viewport(CogView *self, CogViewport *viewport)
{
g_return_if_fail(COG_IS_VIEW(self));
CogViewPrivate *priv = cog_view_get_instance_private(self);
g_weak_ref_set(&priv->viewport, viewport);
g_object_notify_by_pspec(G_OBJECT(self), s_properties[PROP_VIEWPORT]);
}
gboolean
cog_view_get_use_key_bindings(CogView *self)
{
g_return_val_if_fail(COG_IS_VIEW(self), FALSE);
CogViewPrivate *priv = cog_view_get_instance_private(COG_VIEW(self));
return priv->use_key_bindings;
}
CogViewport *
cog_view_get_viewport(CogView *self)
{
g_return_val_if_fail(COG_IS_VIEW(self), NULL);
return g_weak_ref_get(&((CogViewPrivate *) cog_view_get_instance_private(self))->viewport);
}
gboolean
cog_view_is_visible(CogView *self)
{
g_return_val_if_fail(COG_IS_VIEW(self), false);
g_autoptr(CogViewport) viewport = cog_view_get_viewport(self);
return viewport && self == cog_viewport_get_visible_view(viewport);
}
gboolean
cog_view_set_visible(CogView *self)
{
g_assert(COG_IS_VIEW(self));
g_autoptr(CogViewport) viewport = cog_view_get_viewport(self);
if (!viewport)
return FALSE;
cog_viewport_set_visible_view(viewport, self);
return TRUE;
}
gboolean
cog_view_set_fullscreen(CogView *self, gboolean enable)
{
g_return_val_if_fail(COG_IS_VIEW(self), FALSE);
CogViewClass *klass = COG_VIEW_GET_CLASS(self);
if (klass->set_fullscreen)
return (*klass->set_fullscreen)(self, enable);
return FALSE;
}
gboolean
cog_view_is_fullscreen(CogView *self)
{
g_return_val_if_fail(COG_IS_VIEW(self), FALSE);
CogViewClass *klass = COG_VIEW_GET_CLASS(self);
if (klass->is_fullscreen)
return (*klass->is_fullscreen)(self);
return FALSE;
}