#include "cog-shell.h"
#include "cog-view.h"
#include "cog-viewport.h"
typedef struct {
char *name;
GKeyFile *config_file;
gdouble device_scale_factor;
GHashTable *request_handlers;
gboolean automated;
WebKitSettings *web_settings;
WebKitWebContext *web_context;
#if !COG_USE_WPE2
WebKitWebsiteDataManager *web_data_manager;
#endif
#if COG_HAVE_MEM_PRESSURE
WebKitMemoryPressureSettings *web_mem_settings;
WebKitMemoryPressureSettings *net_mem_settings;
#endif
} CogShellPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (CogShell, cog_shell, G_TYPE_OBJECT)
#define PRIV(obj) \
((CogShellPrivate*) cog_shell_get_instance_private (COG_SHELL (obj)))
enum {
PROP_0,
PROP_NAME,
PROP_WEB_SETTINGS,
PROP_WEB_CONTEXT,
PROP_CONFIG_FILE,
PROP_DEVICE_SCALE_FACTOR,
PROP_AUTOMATED,
PROP_WEB_DATA_MANAGER,
#if COG_HAVE_MEM_PRESSURE
PROP_WEB_MEMORY_SETTINGS,
PROP_NETWORK_MEMORY_SETTINGS,
#endif
N_PROPERTIES,
};
static GParamSpec *s_properties[N_PROPERTIES] = { NULL, };
enum {
STARTUP,
SHUTDOWN,
N_SIGNALS,
};
typedef struct {
CogRequestHandler *handler;
gboolean registered;
} RequestHandlerMapEntry;
static inline RequestHandlerMapEntry*
request_handler_map_entry_new (CogRequestHandler *handler)
{
g_assert (COG_IS_REQUEST_HANDLER (handler));
RequestHandlerMapEntry *entry = g_slice_new (RequestHandlerMapEntry);
entry->handler = g_object_ref_sink (handler);
entry->registered = FALSE;
return entry;
}
static inline void
request_handler_map_entry_free (void *pointer)
{
if (pointer) {
RequestHandlerMapEntry *entry = pointer;
g_clear_object (&entry->handler);
g_slice_free (RequestHandlerMapEntry, entry);
}
}
static void
handle_uri_scheme_request (WebKitURISchemeRequest *request,
void *userdata)
{
RequestHandlerMapEntry *entry = userdata;
g_assert (COG_IS_REQUEST_HANDLER (entry->handler));
cog_request_handler_run (entry->handler, request);
}
static void
request_handler_map_entry_register (const char *scheme,
RequestHandlerMapEntry *entry,
WebKitWebContext *context)
{
if (context && !entry->registered) {
webkit_web_context_register_uri_scheme (context,
scheme,
handle_uri_scheme_request,
entry,
NULL);
entry->registered = TRUE;
}
}
static void
cog_shell_get_property (GObject *object,
unsigned prop_id,
GValue *value,
GParamSpec *pspec)
{
CogShell *shell = COG_SHELL (object);
switch (prop_id) {
case PROP_NAME:
g_value_set_string (value, cog_shell_get_name (shell));
break;
case PROP_WEB_SETTINGS:
g_value_set_object (value, cog_shell_get_web_settings (shell));
break;
case PROP_WEB_CONTEXT:
g_value_set_object (value, cog_shell_get_web_context (shell));
break;
#if COG_HAVE_MEM_PRESSURE
case PROP_WEB_MEMORY_SETTINGS:
g_value_set_boxed(value, PRIV(shell)->web_mem_settings);
break;
case PROP_NETWORK_MEMORY_SETTINGS:
g_value_set_boxed(value, PRIV(shell)->net_mem_settings);
break;
#endif
case PROP_WEB_DATA_MANAGER:
#if COG_USE_WPE2
g_value_set_object(value, NULL);
#else
g_value_set_object(value, PRIV(shell)->web_data_manager);
#endif
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
cog_shell_set_property (GObject *object,
unsigned prop_id,
const GValue *value,
GParamSpec *pspec)
{
CogShell *shell = COG_SHELL(object);
CogShellPrivate *priv = PRIV(shell);
switch (prop_id) {
case PROP_NAME:
priv->name = g_value_dup_string(value);
break;
case PROP_WEB_SETTINGS:
g_clear_object(&priv->web_settings);
priv->web_settings = g_value_dup_object(value);
break;
case PROP_CONFIG_FILE:
priv->config_file = g_value_dup_boxed(value);
break;
case PROP_DEVICE_SCALE_FACTOR:
priv->device_scale_factor = g_value_get_double(value);
break;
case PROP_AUTOMATED:
priv->automated = g_value_get_boolean(value);
break;
#if COG_HAVE_MEM_PRESSURE
case PROP_WEB_MEMORY_SETTINGS:
g_clear_pointer(&priv->web_mem_settings, webkit_memory_pressure_settings_free);
priv->web_mem_settings = g_value_dup_boxed(value);
break;
case PROP_NETWORK_MEMORY_SETTINGS:
g_clear_pointer(&priv->net_mem_settings, webkit_memory_pressure_settings_free);
priv->net_mem_settings = g_value_dup_boxed(value);
break;
#endif
case PROP_WEB_DATA_MANAGER:
#if !COG_USE_WPE2
g_clear_object(&priv->web_data_manager);
priv->web_data_manager = g_value_dup_object(value);
#endif
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
}
}
static void
cog_shell_constructed(GObject *object)
{
G_OBJECT_CLASS(cog_shell_parent_class)->constructed(object);
CogShellPrivate *priv = PRIV (object);
if (!priv->web_settings)
priv->web_settings = g_object_ref_sink(webkit_settings_new());
#if !COG_USE_WPE2
g_autofree char *data_dir =
g_build_filename (g_get_user_data_dir (), priv->name, NULL);
g_autofree char *cache_dir =
g_build_filename (g_get_user_cache_dir (), priv->name, NULL);
if (!priv->web_data_manager) {
if (priv->automated)
priv->web_data_manager = webkit_website_data_manager_new_ephemeral();
else
priv->web_data_manager = webkit_website_data_manager_new("base-data-directory", data_dir,
"base-cache-directory", cache_dir, NULL);
}
#endif
priv->web_context = g_object_new(WEBKIT_TYPE_WEB_CONTEXT,
#if !COG_USE_WPE2
"website-data-manager", priv->web_data_manager,
#endif
#if COG_HAVE_MEM_PRESSURE
"memory-pressure-settings", priv->web_mem_settings,
#endif
NULL);
webkit_web_context_set_automation_allowed(priv->web_context, priv->automated);
}
static void
cog_shell_dispose(GObject *object)
{
CogShellPrivate *priv = PRIV(object);
g_clear_object(&priv->web_context);
g_clear_object(&priv->web_settings);
#if !COG_USE_WPE2
g_clear_object(&priv->web_data_manager);
#endif
g_clear_pointer(&priv->request_handlers, g_hash_table_unref);
g_clear_pointer(&priv->name, g_free);
g_clear_pointer(&priv->config_file, g_key_file_unref);
G_OBJECT_CLASS(cog_shell_parent_class)->dispose(object);
}
static void
cog_shell_class_init(CogShellClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = cog_shell_dispose;
object_class->constructed = cog_shell_constructed;
object_class->get_property = cog_shell_get_property;
object_class->set_property = cog_shell_set_property;
s_properties[PROP_NAME] =
g_param_spec_string ("name",
"Name",
"Name of the CogShell instance",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
s_properties[PROP_WEB_SETTINGS] =
g_param_spec_object("web-settings",
"Web Settings",
"The WebKitSettings used by the shell",
WEBKIT_TYPE_SETTINGS,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
s_properties[PROP_WEB_CONTEXT] =
g_param_spec_object ("web-context",
"Web Contxt",
"The WebKitWebContext used by the shell",
WEBKIT_TYPE_WEB_CONTEXT,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
s_properties[PROP_CONFIG_FILE] =
g_param_spec_boxed ("config-file",
"Configuration File",
"Configuration file made available to the platform plugin",
G_TYPE_KEY_FILE,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
s_properties[PROP_DEVICE_SCALE_FACTOR] =
g_param_spec_double ("device-scale-factor",
"Device Scale Factor",
"Device scale factor used for this shell",
0, 64.0, 1.0,
G_PARAM_READWRITE);
s_properties[PROP_AUTOMATED] = g_param_spec_boolean("automated",
"Automated",
"Whether this session is automated",
FALSE,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
#if COG_HAVE_MEM_PRESSURE
s_properties[PROP_WEB_MEMORY_SETTINGS] =
g_param_spec_boxed("web-memory-settings",
"Web process memory pressure settings",
"Memory pressure handling settings for web processes",
WEBKIT_TYPE_MEMORY_PRESSURE_SETTINGS,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
s_properties[PROP_NETWORK_MEMORY_SETTINGS] =
g_param_spec_boxed("network-memory-settings",
"Network process memory pressure settings",
"Memory pressure handling settings for network processes",
WEBKIT_TYPE_MEMORY_PRESSURE_SETTINGS,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
#endif
s_properties[PROP_WEB_DATA_MANAGER] =
g_param_spec_object("web-data-manager",
"Website data manager",
"Data manager applied to web views managed by the shell",
WEBKIT_TYPE_WEBSITE_DATA_MANAGER,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties(object_class, N_PROPERTIES, s_properties);
}
static void
cog_shell_init(CogShell *shell G_GNUC_UNUSED)
{
CogShellPrivate *priv = PRIV(shell);
if (!priv->name)
priv->name = g_strdup(g_get_prgname());
}
CogShell *
cog_shell_new(const char *name, gboolean automated)
{
return g_object_new(COG_TYPE_SHELL, "name", name, "automated", automated, NULL);
}
WebKitWebContext *
cog_shell_get_web_context(CogShell *shell)
{
g_return_val_if_fail(COG_IS_SHELL(shell), NULL);
return PRIV(shell)->web_context;
}
WebKitSettings*
cog_shell_get_web_settings (CogShell *shell)
{
g_return_val_if_fail (COG_IS_SHELL (shell), NULL);
return PRIV (shell)->web_settings;
}
const char*
cog_shell_get_name (CogShell *shell)
{
g_return_val_if_fail (COG_IS_SHELL (shell), NULL);
return PRIV (shell)->name;
}
GKeyFile*
cog_shell_get_config_file (CogShell *shell)
{
g_return_val_if_fail (COG_IS_SHELL (shell), NULL);
return PRIV (shell)->config_file;
}
gdouble
cog_shell_get_device_scale_factor (CogShell *shell)
{
g_return_val_if_fail (COG_IS_SHELL (shell), 0);
return PRIV(shell)->device_scale_factor;
}
gboolean
cog_shell_is_automated(CogShell *shell)
{
g_return_val_if_fail(COG_IS_SHELL(shell), 0);
return PRIV(shell)->automated;
}
void
cog_shell_set_request_handler(CogShell *shell, const char *scheme, CogRequestHandler *handler)
{
g_return_if_fail(COG_IS_SHELL(shell));
g_return_if_fail(scheme != NULL);
g_return_if_fail(COG_IS_REQUEST_HANDLER(handler));
CogShellPrivate *priv = PRIV(shell);
if (!priv->request_handlers) {
priv->request_handlers =
g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
request_handler_map_entry_free);
}
RequestHandlerMapEntry *entry =
g_hash_table_lookup (priv->request_handlers, scheme);
if (!entry) {
entry = request_handler_map_entry_new (handler);
g_hash_table_insert (priv->request_handlers, g_strdup (scheme), entry);
} else if (entry->handler != handler) {
g_clear_object (&entry->handler);
entry->handler = g_object_ref_sink (handler);
}
request_handler_map_entry_register (scheme, entry, priv->web_context);
}