blob: 79eb81b7058e8f69737ca299a403a6be7632093b [file] [log] [blame]
/*
* Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia
* Copyright (C) 2009, 2010 ProFUSION embedded systems
* Copyright (C) 2009, 2010, 2011 Samsung Electronics
* Copyright (C) 2012 Intel Corporation
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "EWebKit.h"
#include "url_bar.h"
#include "url_utils.h"
#include <Ecore.h>
#include <Ecore_Evas.h>
#include <Ecore_File.h>
#include <Ecore_Getopt.h>
#include <Ecore_X.h>
#include <Edje.h>
#include <Evas.h>
#include <ctype.h>
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define DEFAULT_WIDTH 800
#define DEFAULT_HEIGHT 600
#define DEFAULT_ZOOM_INIT 1.0
#define info(format, args...) \
do { \
if (verbose) \
printf(format"\n", ##args); \
} while (0)
#define MIN_ZOOM_LEVEL 0
#define DEFAULT_ZOOM_LEVEL 5
#define MAX_ZOOM_LEVEL 13
static int currentZoomLevel = DEFAULT_ZOOM_LEVEL;
static float currentZoom = 1.0;
// the zoom values are chosen to be like in Mozilla Firefox 3
static int zoomLevels[] = {30, 50, 67, 80, 90,
100,
110, 120, 133, 150, 170, 200, 240, 300};
static int verbose = 0;
static Eina_List *windows = NULL;
static char *themePath = NULL;
static const char *backingStores[] = {
"tiled",
"single",
NULL
};
typedef struct _Window_Properties {
Eina_Bool toolbarsVisible:1;
Eina_Bool statusbarVisible:1;
Eina_Bool scrollbarsVisible:1;
Eina_Bool menubarVisible:1;
} Window_Properties;
Window_Properties windowProperties = { /* Pretend we have them and they are initially visible */
EINA_TRUE,
EINA_TRUE,
EINA_TRUE,
EINA_TRUE
};
static const Ecore_Getopt options = {
"EWebLauncher",
"%prog [options] [url]",
"0.0.1",
"(C)2008 INdT (The Nokia Technology Institute)\n"
"(C)2009, 2010 ProFUSION embedded systems\n"
"(C)2009, 2010, 2011 Samsung Electronics\n"
"(C)2012 Intel Corporation\n",
"GPL",
"Test Web Browser using the Enlightenment Foundation Libraries of WebKit",
EINA_TRUE, {
ECORE_GETOPT_STORE_STR
('e', "engine", "ecore-evas engine to use."),
ECORE_GETOPT_CALLBACK_NOARGS
('E', "list-engines", "list ecore-evas engines.",
ecore_getopt_callback_ecore_evas_list_engines, NULL),
ECORE_GETOPT_CHOICE
('b', "backing-store", "choose backing store to use.", backingStores),
ECORE_GETOPT_STORE_DOUBLE
('r', "device-pixel-ratio", "Ratio between the CSS units and device pixels."),
ECORE_GETOPT_STORE_DEF_BOOL
('c', "encoding-detector", "enable/disable encoding detector", 0),
ECORE_GETOPT_STORE_DEF_BOOL
('f', "flattening", "frame flattening.", 0),
ECORE_GETOPT_STORE_DEF_BOOL
('F', "fullscreen", "fullscreen mode.", 0),
ECORE_GETOPT_CALLBACK_ARGS
('g', "geometry", "geometry to use in x:y:w:h form.", "X:Y:W:H",
ecore_getopt_callback_geometry_parse, NULL),
ECORE_GETOPT_STORE_STR
('t', "theme", "path to read the theme file from."),
ECORE_GETOPT_STORE_DEF_BOOL
('T', "tiled-backing-store", "enable/disable WebCore's tiled backingstore(ewk_view_single only)", 0),
ECORE_GETOPT_STORE_STR
('U', "user-agent", "custom user agent string to use."),
ECORE_GETOPT_COUNT
('v', "verbose", "be more verbose."),
ECORE_GETOPT_VERSION
('V', "version"),
ECORE_GETOPT_COPYRIGHT
('R', "copyright"),
ECORE_GETOPT_LICENSE
('L', "license"),
ECORE_GETOPT_HELP
('h', "help"),
ECORE_GETOPT_SENTINEL
}
};
typedef struct _User_Arguments {
char *engine;
Eina_Bool quitOption;
char *backingStore;
double device_pixel_ratio;
Eina_Bool enableEncodingDetector;
Eina_Bool enableTiledBackingStore;
Eina_Bool isFlattening;
Eina_Bool isFullscreen;
Eina_Rectangle geometry;
char *theme;
char *userAgent;
char *databasePath;
} User_Arguments;
typedef struct _ELauncher {
Ecore_Evas *ee;
Evas *evas;
Evas_Object *browser;
Url_Bar *url_bar;
User_Arguments *userArgs;
} ELauncher;
static void windowDestroy(Ecore_Evas *ee);
static void closeWindow(Ecore_Evas *ee);
static int browserCreate(const char *url, User_Arguments *userArgs);
static int webInspectorCreate(ELauncher *appBrowser);
static ELauncher *windowCreate(User_Arguments *userArgs);
static ELauncher *
find_app_from_ee(Ecore_Evas *ee)
{
Eina_List *l;
void *data;
EINA_LIST_FOREACH(windows, l, data)
{
ELauncher *app = (ELauncher *) data;
if (app->ee == ee)
return app;
}
return NULL;
}
static void
print_history(Eina_List *list)
{
Eina_List *l;
void *d;
if (!verbose)
return;
printf("Session history contains:\n");
EINA_LIST_FOREACH(list, l, d) {
Ewk_History_Item *item = (Ewk_History_Item*)d;
cairo_surface_t *cs = ewk_history_item_icon_surface_get(item);
char buf[PATH_MAX];
int s = snprintf(buf, sizeof(buf), "/tmp/favicon-%s.png", ewk_history_item_uri_original_get(item));
for (s--; s >= (int)sizeof("/tmp/favicon-"); s--) {
if (!isalnum(buf[s]) && buf[s] != '.')
buf[s] = '_';
}
cs = ewk_history_item_icon_surface_get(item);
if (cs && cairo_surface_status(cs) == CAIRO_STATUS_SUCCESS)
cairo_surface_write_to_png(cs, buf);
else
buf[0] = '\0';
printf("* '%s' title='%s' icon='%s'\n",
ewk_history_item_uri_original_get(item),
ewk_history_item_title_get(item), buf);
}
}
static int
nearest_zoom_level_get(float factor)
{
int i, intFactor = (int)(factor * 100.0);
for (i = 0; zoomLevels[i] <= intFactor; i++) { }
printf("factor=%f, intFactor=%d, zoomLevels[%d]=%d, zoomLevels[%d]=%d\n",
factor, intFactor, i-1, zoomLevels[i-1], i, zoomLevels[i]);
if (intFactor - zoomLevels[i-1] < zoomLevels[i] - intFactor)
return i - 1;
return i;
}
static Eina_Bool
zoom_level_set(Evas_Object *webview, int level)
{
float factor = ((float) zoomLevels[level]) / 100.0;
Evas_Coord ox, oy, mx, my, cx, cy;
evas_pointer_canvas_xy_get(evas_object_evas_get(webview), &mx, &my);
evas_object_geometry_get(webview, &ox, &oy, NULL, NULL);
cx = mx - ox;
cy = my - oy;
return ewk_view_zoom_animated_set(webview, factor, 0.5, cx, cy);
}
static void
on_browser_ecore_evas_resize(Ecore_Evas *ee)
{
ELauncher *app;
Evas_Object *webview;
int w, h;
ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
/* Resize URL bar */
app = find_app_from_ee(ee);
url_bar_width_set(app->url_bar, w);
webview = evas_object_name_find(ecore_evas_get(ee), "browser");
evas_object_move(webview, 0, URL_BAR_HEIGHT);
evas_object_resize(webview, w, h - URL_BAR_HEIGHT);
}
static void
on_inspector_ecore_evas_resize(Ecore_Evas *ee)
{
Evas_Object *webview;
int w, h;
ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
webview = evas_object_name_find(ecore_evas_get(ee), "inspector");
evas_object_move(webview, 0, 0);
evas_object_resize(webview, w, h);
}
static void
title_set(Ecore_Evas *ee, const Ewk_Text_With_Direction *title, int progress)
{
const char *appname = "EFL Test Launcher";
const char *separator = " - ";
char label[4096];
int size;
if (!title || !title->string || !strcmp(title->string, "")) {
ecore_evas_title_set(ee, appname);
return;
}
if (progress < 100)
size = snprintf(label, sizeof(label), "%s (%d%%)%s%s", title->string, progress, separator, appname);
else
size = snprintf(label, sizeof(label), "%s %s%s", title->string, separator, appname);
if (size >= (int)sizeof(label))
return;
ecore_evas_title_set(ee, label);
}
static void
on_title_changed(void *user_data, Evas_Object *webview, void *event_info)
{
ELauncher *app = (ELauncher *)user_data;
const Ewk_Text_With_Direction *title = (const Ewk_Text_With_Direction *)event_info;
title_set(app->ee, title, 100);
}
static void
on_progress(void *user_data, Evas_Object *webview, void *event_info)
{
ELauncher *app = (ELauncher *)user_data;
double *progress = (double *)event_info;
title_set(app->ee, ewk_view_title_get(app->browser), *progress * 100);
}
static void
on_load_finished(void *user_data, Evas_Object *webview, void *event_info)
{
const Ewk_Frame_Load_Error *err = (const Ewk_Frame_Load_Error *)event_info;
if (!err)
info("Succeeded loading page.");
else if (err->is_cancellation)
info("Load was cancelled.");
else
info("Failed loading page: %d %s \"%s\", url=%s",
err->code, err->domain, err->description, err->failing_url);
currentZoom = ewk_view_zoom_get(webview);
currentZoomLevel = nearest_zoom_level_get(currentZoom);
info("WebCore Zoom=%f, currentZoomLevel=%d", currentZoom, currentZoomLevel);
}
static void
on_load_error(void *user_data, Evas_Object *webview, void *event_info)
{
const Ewk_Frame_Load_Error *err = (const Ewk_Frame_Load_Error *)event_info;
char message[1024];
snprintf(message, 1024, "<html><body><div style=\"color:#ff0000\">ERROR!</div><br><div>Code: %d<br>Domain: %s<br>Description: %s<br>URL: %s</div></body</html>",
err->code, err->domain, err->description, err->failing_url);
ewk_frame_contents_set(err->frame, message, 0, "text/html", "UTF-8", err->failing_url);
}
static void
on_toolbars_visible_set(void* user_data, Evas_Object* webview, void* event_info)
{
Eina_Bool *visible = (Eina_Bool *)event_info;
if (*visible) {
info("Toolbars visible changed: show");
windowProperties.toolbarsVisible = EINA_TRUE;
} else {
info("Toolbars visible changed: hide");
windowProperties.toolbarsVisible = EINA_FALSE;
}
}
static void
on_toolbars_visible_get(void* user_data, Evas_Object* webview, void* event_info)
{
Eina_Bool *visible = (Eina_Bool *)event_info;
*visible = windowProperties.toolbarsVisible;
}
static void
on_statusbar_visible_set(void* user_data, Evas_Object* webview, void* event_info)
{
Eina_Bool *visible = (Eina_Bool *)event_info;
if (*visible) {
info("Statusbar visible changed: show");
windowProperties.statusbarVisible = EINA_TRUE;
} else {
info("Statusbar visible changed: hide");
windowProperties.statusbarVisible = EINA_FALSE;
}
}
static void
on_statusbar_visible_get(void* user_data, Evas_Object* webview, void* event_info)
{
Eina_Bool *visible = (Eina_Bool *)event_info;
*visible = windowProperties.statusbarVisible;
}
static void
on_scrollbars_visible_set(void* user_data, Evas_Object* webview, void* event_info)
{
Eina_Bool *visible = (Eina_Bool *)event_info;
if (*visible) {
info("Scrollbars visible changed: show");
windowProperties.scrollbarsVisible = EINA_TRUE;
} else {
info("Scrollbars visible changed: hide");
windowProperties.scrollbarsVisible = EINA_FALSE;
}
}
static void
on_scrollbars_visible_get(void* user_data, Evas_Object* webview, void* event_info)
{
Eina_Bool *visible = (Eina_Bool *)event_info;
*visible = windowProperties.scrollbarsVisible;
}
static void
on_menubar_visible_set(void* user_data, Evas_Object* webview, void* event_info)
{
Eina_Bool *visible = (Eina_Bool *)event_info;
if (*visible) {
info("Menubar visible changed: show");
windowProperties.menubarVisible = EINA_TRUE;
} else {
info("Menubar visible changed: hide");
windowProperties.menubarVisible = EINA_FALSE;
}
}
static void
on_menubar_visible_get(void* user_data, Evas_Object* webview, void* event_info)
{
Eina_Bool *visible = (Eina_Bool *)event_info;
*visible = windowProperties.menubarVisible;
}
static void
on_tooltip_text_set(void* user_data, Evas_Object* webview, void* event_info)
{
const char *text = (const char *)event_info;
info("Tooltip is set: %s", text);
}
static void
on_tooltip_text_unset(void* user_data, Evas_Object* webview, void* event_info)
{
info("Tooltip is unset");
}
static void
on_inputmethod_changed(void* user_data, Evas_Object* webview, void* event_info)
{
Eina_Bool active = (Eina_Bool)(long)event_info;
unsigned int imh;
info("Keyboard changed: %d", active);
if (!active)
return;
imh = ewk_view_imh_get(webview);
info(" Keyboard flags: %#.2x", imh);
}
static void
on_url_changed(void* user_data, Evas_Object* webview, void* event_info)
{
ELauncher *app = (ELauncher *)user_data;
url_bar_url_set(app->url_bar, ewk_view_uri_get(app->browser));
}
static void
on_mouse_down(void* data, Evas* e, Evas_Object* webview, void* event_info)
{
Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down *)event_info;
if (ev->button == 1)
evas_object_focus_set(webview, EINA_TRUE);
else if (ev->button == 2)
evas_object_focus_set(webview, !evas_object_focus_get(webview));
}
static void
on_focus_out(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
info("the webview lost keyboard focus");
}
static void
on_focus_in(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
info("the webview gained keyboard focus");
}
static void
on_key_down(void *data, Evas *e, Evas_Object *obj, void *event_info)
{
Evas_Event_Key_Down *ev = (Evas_Event_Key_Down*) event_info;
ELauncher *app = data;
static const char *encodings[] = {
"ISO-8859-1",
"UTF-8",
NULL
};
static int currentEncoding = -1;
const Evas_Modifier *mod = evas_key_modifier_get(e);
Eina_Bool ctrlPressed = evas_key_modifier_is_set(mod, "Control");
Eina_Bool altPressed = evas_key_modifier_is_set(mod, "Alt");
if (!strcmp(ev->key, "Escape")) {
closeWindow(app->ee);
} else if (!strcmp(ev->key, "Left") && altPressed) {
info("Back (Alt+Left) was pressed");
if (ewk_view_back_possible(obj)) {
Ewk_History *history = ewk_view_history_get(obj);
Eina_List *list = ewk_history_back_list_get(history);
print_history(list);
ewk_history_item_list_free(list);
ewk_view_back(obj);
} else
info("Back ignored: No back history");
} else if (!strcmp(ev->key, "Right") && altPressed) {
info("Forward (Alt+Right) was pressed");
if (ewk_view_forward_possible(obj)) {
Ewk_History *history = ewk_view_history_get(obj);
Eina_List *list = ewk_history_forward_list_get(history);
print_history(list);
ewk_history_item_list_free(list);
ewk_view_forward(obj);
} else
info("Forward ignored: No forward history");
} else if (!strcmp(ev->key, "F3")) {
currentEncoding++;
currentEncoding %= (sizeof(encodings) / sizeof(encodings[0]));
info("Set encoding (F3) pressed. New encoding to %s", encodings[currentEncoding]);
ewk_view_setting_encoding_custom_set(obj, encodings[currentEncoding]);
} else if (!strcmp(ev->key, "F4")) {
Evas_Object *frame = ewk_view_frame_main_get(obj);
Evas_Coord x, y;
Ewk_Hit_Test *ht;
evas_pointer_canvas_xy_get(evas_object_evas_get(obj), &x, &y);
ht = ewk_frame_hit_test_new(frame, x, y);
if (!ht)
printf("No hit test returned for point %d,%d\n", x, y);
else {
printf("Hit test for point %d,%d\n"
" pos=%3d,%3d\n"
" bounding_box=%d,%d + %dx%d\n"
" title='%s'\n"
" alternate_text='%s'\n"
" frame=%p (%s)\n"
" link {\n"
" text='%s'\n"
" url='%s'\n"
" title='%s'\n"
" target frame=%p (%s)\n"
" }\n"
"context:\n"
"%s"
"%s"
"%s"
"%s"
"%s\n",
x, y,
ht->x, ht->y,
ht->bounding_box.x, ht->bounding_box.y, ht->bounding_box.w, ht->bounding_box.h,
ht->title.string,
ht->alternate_text,
ht->frame, evas_object_name_get(ht->frame),
ht->link.text,
ht->link.url,
ht->link.title,
ht->link.target_frame, evas_object_name_get(ht->link.target_frame),
ht->context & EWK_HIT_TEST_RESULT_CONTEXT_LINK ? " LINK\n" : "",
ht->context & EWK_HIT_TEST_RESULT_CONTEXT_IMAGE ? " IMAGE\n" : "",
ht->context & EWK_HIT_TEST_RESULT_CONTEXT_MEDIA ? " MEDIA\n" : "",
ht->context & EWK_HIT_TEST_RESULT_CONTEXT_SELECTION ? " SELECTION\n" : "",
ht->context & EWK_HIT_TEST_RESULT_CONTEXT_EDITABLE ? " EDITABLE" : "");
ewk_frame_hit_test_free(ht);
}
} else if (!strcmp(ev->key, "F5")) {
info("Reload (F5) was pressed, reloading.");
ewk_view_reload(obj);
} else if (!strcmp(ev->key, "F6")) {
info("Stop (F6) was pressed, stop loading.");
ewk_view_stop(obj);
} else if (!strcmp(ev->key, "F12")) {
Eina_Bool status = ewk_view_setting_spatial_navigation_get(obj);
ewk_view_setting_spatial_navigation_set(obj, !status);
info("Command::keyboard navigation toggle");
} else if ((!strcmp(ev->key, "minus") || !strcmp(ev->key, "KP_Subtract")) && ctrlPressed) {
if (currentZoomLevel > MIN_ZOOM_LEVEL && zoom_level_set(obj, currentZoomLevel - 1))
currentZoomLevel--;
info("Zoom out (Ctrl + '-') was pressed, zoom level became %.2f", zoomLevels[currentZoomLevel] / 100.0);
} else if ((!strcmp(ev->key, "equal") || !strcmp(ev->key, "KP_Add")) && ctrlPressed) {
if (currentZoomLevel < MAX_ZOOM_LEVEL && zoom_level_set(obj, currentZoomLevel + 1))
currentZoomLevel++;
info("Zoom in (Ctrl + '+') was pressed, zoom level became %.2f", zoomLevels[currentZoomLevel] / 100.0);
} else if (!strcmp(ev->key, "0") && ctrlPressed) {
if (zoom_level_set(obj, DEFAULT_ZOOM_LEVEL))
currentZoomLevel = DEFAULT_ZOOM_LEVEL;
info("Zoom to default (Ctrl + '0') was pressed, zoom level became %.2f", zoomLevels[currentZoomLevel] / 100.0);
} else if (!strcmp(ev->key, "n") && ctrlPressed) {
info("Create new window (Ctrl+n) was pressed.");
browserCreate("http://www.google.com", app->userArgs);
} else if (!strcmp(ev->key, "g") && ctrlPressed ) {
Evas_Coord x, y, w, h;
Evas_Object *frame = ewk_view_frame_main_get(obj);
float zoom = zoomLevels[currentZoomLevel] / 100.0;
ewk_frame_visible_content_geometry_get(frame, EINA_FALSE, &x, &y, &w, &h);
x -= w;
y -= h;
w *= 4;
h *= 4;
info("Pre-render %d,%d + %dx%d", x, y, w, h);
ewk_view_pre_render_region(obj, x, y, w, h, zoom);
} else if (!strcmp(ev->key, "r") && ctrlPressed) {
info("Pre-render 1 extra column/row with current zoom");
ewk_view_pre_render_relative_radius(obj, 1);
} else if (!strcmp(ev->key, "p") && ctrlPressed) {
info("Pre-rendering start");
ewk_view_pre_render_start(obj);
} else if (!strcmp(ev->key, "d") && ctrlPressed) {
info("Render suspended");
ewk_view_disable_render(obj);
} else if (!strcmp(ev->key, "e") && ctrlPressed) {
info("Render resumed");
ewk_view_enable_render(obj);
} else if (!strcmp(ev->key, "s") && ctrlPressed) {
Evas_Object *frame = ewk_view_frame_main_get(obj);
Ewk_Security_Origin *origin = ewk_frame_security_origin_get(frame);
printf("Security origin information:\n"
" protocol=%s\n"
" host=%s\n"
" port=%d\n"
" web database quota=%" PRIu64 "\n",
ewk_security_origin_protocol_get(origin),
ewk_security_origin_host_get(origin),
ewk_security_origin_port_get(origin),
ewk_security_origin_web_database_quota_get(origin));
Eina_List *databaseList = ewk_security_origin_web_database_get_all(origin);
Eina_List *listIterator = 0;
Ewk_Web_Database *database;
EINA_LIST_FOREACH(databaseList, listIterator, database)
printf("Database information:\n"
" name=%s\n"
" display name=%s\n"
" filename=%s\n"
" expected size=%" PRIu64 "\n"
" size=%" PRIu64 "\n",
ewk_web_database_name_get(database),
ewk_web_database_display_name_get(database),
ewk_web_database_filename_get(database),
ewk_web_database_expected_size_get(database),
ewk_web_database_size_get(database));
ewk_security_origin_free(origin);
ewk_web_database_list_free(databaseList);
} else if (!strcmp(ev->key, "i") && ctrlPressed) {
Evas_Object *inspector_view = ewk_view_inspector_view_get(obj);
if (inspector_view) {
info("Web Inspector close");
ewk_view_inspector_close(obj);
} else {
info("Web Inspector show");
ewk_view_inspector_show(obj);
}
}
}
static void
on_browser_del(void *data, Evas *evas, Evas_Object *browser, void *event)
{
ELauncher *app = (ELauncher*) data;
evas_object_event_callback_del(app->browser, EVAS_CALLBACK_KEY_DOWN, on_key_down);
evas_object_event_callback_del(app->browser, EVAS_CALLBACK_MOUSE_DOWN, on_mouse_down);
evas_object_event_callback_del(app->browser, EVAS_CALLBACK_FOCUS_IN, on_focus_in);
evas_object_event_callback_del(app->browser, EVAS_CALLBACK_FOCUS_OUT, on_focus_out);
evas_object_event_callback_del(app->browser, EVAS_CALLBACK_DEL, on_browser_del);
}
static void
on_inspector_view_create(void *user_data, Evas_Object *webview, void *event_info)
{
ELauncher *app_browser = (ELauncher *)user_data;
webInspectorCreate(app_browser);
}
static void
on_inspector_view_close(void *user_data, Evas_Object *webview, void *event_info)
{
Eina_List *l;
void *app;
ELauncher *app_browser = (ELauncher *)user_data;
Evas_Object *inspector_view = (Evas_Object *)event_info;
ewk_view_inspector_view_set(app_browser->browser, NULL);
EINA_LIST_FOREACH(windows, l, app)
if (((ELauncher *)app)->browser == inspector_view)
break;
windows = eina_list_remove(windows, app);
windowDestroy(((ELauncher *)app)->ee);
free(app);
}
static void
on_inspector_view_destroyed(Ecore_Evas *ee)
{
ELauncher *app;
app = find_app_from_ee(ee);
evas_object_smart_callback_call(app->browser, "inspector,view,destroy", NULL);
}
static int
quit(Eina_Bool success, const char *msg)
{
edje_shutdown();
ecore_evas_shutdown();
ecore_file_shutdown();
if (msg)
fputs(msg, (success) ? stdout : stderr);
if (themePath) {
free(themePath);
themePath = NULL;
}
if (!success)
return EXIT_FAILURE;
return EXIT_SUCCESS;
}
static int
browserCreate(const char *url, User_Arguments *userArgs)
{
ELauncher *appBrowser = windowCreate(userArgs);
if (!appBrowser)
return quit(EINA_FALSE, "ERROR: could not create a browser window\n");
ecore_evas_title_set(appBrowser->ee, "EFL Test Launcher");
ecore_evas_callback_resize_set(appBrowser->ee, on_browser_ecore_evas_resize);
ecore_evas_callback_delete_request_set(appBrowser->ee, closeWindow);
evas_object_name_set(appBrowser->browser, "browser");
evas_object_smart_callback_add(appBrowser->browser, "inputmethod,changed", on_inputmethod_changed, appBrowser);
evas_object_smart_callback_add(appBrowser->browser, "inspector,view,close", on_inspector_view_close, appBrowser);
evas_object_smart_callback_add(appBrowser->browser, "inspector,view,create", on_inspector_view_create, appBrowser);
evas_object_smart_callback_add(appBrowser->browser, "load,error", on_load_error, appBrowser);
evas_object_smart_callback_add(appBrowser->browser, "load,finished", on_load_finished, appBrowser);
evas_object_smart_callback_add(appBrowser->browser, "load,progress", on_progress, appBrowser);
evas_object_smart_callback_add(appBrowser->browser, "menubar,visible,get", on_menubar_visible_get, appBrowser);
evas_object_smart_callback_add(appBrowser->browser, "menubar,visible,set", on_menubar_visible_set, appBrowser);
evas_object_smart_callback_add(appBrowser->browser, "scrollbars,visible,get", on_scrollbars_visible_get, appBrowser);
evas_object_smart_callback_add(appBrowser->browser, "scrollbars,visible,set", on_scrollbars_visible_set, appBrowser);
evas_object_smart_callback_add(appBrowser->browser, "statusbar,visible,get", on_statusbar_visible_get, appBrowser);
evas_object_smart_callback_add(appBrowser->browser, "statusbar,visible,set", on_statusbar_visible_set, appBrowser);
evas_object_smart_callback_add(appBrowser->browser, "title,changed", on_title_changed, appBrowser);
evas_object_smart_callback_add(appBrowser->browser, "toolbars,visible,get", on_toolbars_visible_get, appBrowser);
evas_object_smart_callback_add(appBrowser->browser, "toolbars,visible,set", on_toolbars_visible_set, appBrowser);
evas_object_smart_callback_add(appBrowser->browser, "tooltip,text,set", on_tooltip_text_set, appBrowser);
evas_object_smart_callback_add(appBrowser->browser, "tooltip,text,unset", on_tooltip_text_unset, appBrowser);
evas_object_smart_callback_add(appBrowser->browser, "uri,changed", on_url_changed, appBrowser);
evas_object_event_callback_add(appBrowser->browser, EVAS_CALLBACK_DEL, on_browser_del, appBrowser);
evas_object_event_callback_add(appBrowser->browser, EVAS_CALLBACK_FOCUS_IN, on_focus_in, appBrowser);
evas_object_event_callback_add(appBrowser->browser, EVAS_CALLBACK_FOCUS_OUT, on_focus_out, appBrowser);
evas_object_event_callback_add(appBrowser->browser, EVAS_CALLBACK_KEY_DOWN, on_key_down, appBrowser);
evas_object_event_callback_add(appBrowser->browser, EVAS_CALLBACK_MOUSE_DOWN, on_mouse_down, appBrowser);
ewk_view_setting_enable_developer_extras_set(appBrowser->browser, EINA_TRUE);
appBrowser->url_bar = url_bar_add(appBrowser->browser, DEFAULT_WIDTH);
evas_object_move(appBrowser->browser, 0, URL_BAR_HEIGHT);
evas_object_resize(appBrowser->browser, userArgs->geometry.w, userArgs->geometry.h - URL_BAR_HEIGHT);
ewk_view_uri_set(appBrowser->browser, url);
evas_object_show(appBrowser->browser);
ecore_evas_show(appBrowser->ee);
evas_object_focus_set(appBrowser->browser, EINA_TRUE);
return 1;
}
static int
webInspectorCreate(ELauncher *appBrowser)
{
ELauncher *appInspector = windowCreate(appBrowser->userArgs);
if (!appInspector)
return quit(EINA_FALSE, "ERROR: could not create an inspector window\n");
ecore_evas_title_set(appInspector->ee, "Web Inspector");
ecore_evas_callback_resize_set(appInspector->ee, on_inspector_ecore_evas_resize);
ecore_evas_callback_delete_request_set(appInspector->ee, on_inspector_view_destroyed);
evas_object_name_set(appInspector->browser, "inspector");
evas_object_move(appInspector->browser, 0, 0);
evas_object_resize(appInspector->browser, appInspector->userArgs->geometry.w, appInspector->userArgs->geometry.h);
evas_object_show(appInspector->browser);
ecore_evas_show(appInspector->ee);
evas_object_focus_set(appInspector->browser, EINA_TRUE);
ewk_view_inspector_view_set(appBrowser->browser, appInspector->browser);
return 1;
}
static ELauncher *
windowCreate(User_Arguments *userArgs)
{
ELauncher *app = (ELauncher *)malloc(sizeof(ELauncher));
if (!app) {
quit(EINA_FALSE, "ERROR: could not create an ELauncher\n");
return NULL;
}
#if defined(WTF_USE_ACCELERATED_COMPOSITING) && defined(HAVE_ECORE_X)
if (userArgs->engine)
#endif
app->ee = ecore_evas_new(userArgs->engine, 0, 0, userArgs->geometry.w, userArgs->geometry.h, NULL);
#if defined(WTF_USE_ACCELERATED_COMPOSITING) && defined(HAVE_ECORE_X)
else {
const char* engine = "opengl_x11";
app->ee = ecore_evas_new(engine, 0, 0, userArgs->geometry.w, userArgs->geometry.h, NULL);
}
#endif
if (!app->ee) {
quit(EINA_FALSE, "ERROR: could not construct evas-ecore\n");
return NULL;
}
if (userArgs->isFullscreen)
ecore_evas_fullscreen_set(app->ee, EINA_TRUE);
app->evas = ecore_evas_get(app->ee);
if (!app->evas) {
quit(EINA_FALSE, "ERROR: could not get evas from evas-ecore\n");
return NULL;
}
if (userArgs->backingStore && !strcasecmp(userArgs->backingStore, "tiled")) {
app->browser = ewk_view_tiled_add(app->evas);
info("backing store: tiled");
} else {
app->browser = ewk_view_single_add(app->evas);
info("backing store: single");
ewk_view_setting_tiled_backing_store_enabled_set(app->browser, userArgs->enableTiledBackingStore);
}
ewk_view_theme_set(app->browser, themePath);
if (userArgs->userAgent)
ewk_view_setting_user_agent_set(app->browser, userArgs->userAgent);
ewk_view_setting_local_storage_database_path_set(app->browser, userArgs->databasePath);
ewk_view_setting_enable_frame_flattening_set(app->browser, userArgs->isFlattening);
ewk_view_setting_encoding_detector_set(app->browser, userArgs->enableEncodingDetector);
ewk_view_device_pixel_ratio_set(app->browser, userArgs->device_pixel_ratio);
app->userArgs = userArgs;
app->url_bar = NULL;
windows = eina_list_append(windows, app);
return app;
}
static void
windowDestroy(Ecore_Evas *ee)
{
ecore_evas_free(ee);
if (!eina_list_count(windows))
ecore_main_loop_quit();
}
static void
closeWindow(Ecore_Evas *ee)
{
ELauncher *app;
app = find_app_from_ee(ee);
ewk_view_inspector_close(app->browser);
windows = eina_list_remove(windows, app);
url_bar_del(app->url_bar);
windowDestroy(ee);
free(app);
}
static Eina_Bool
main_signal_exit(void *data, int ev_type, void *ev)
{
ELauncher *app;
while (windows) {
app = (ELauncher*) eina_list_data_get(windows);
ewk_view_inspector_close(app->browser);
ecore_evas_free(app->ee);
windows = eina_list_remove(windows, app);
}
if (!eina_list_count(windows))
ecore_main_loop_quit();
return EINA_TRUE;
}
static char *
findThemePath(const char *theme)
{
const char *default_theme = TEST_THEME_DIR "/default.edj";
char *rpath;
struct stat st;
if (!theme)
theme = default_theme;
rpath = ecore_file_realpath(theme);
if (!strlen(rpath) || stat(rpath, &st)) {
free(rpath);
return NULL;
}
return rpath;
}
int
parseUserArguments(int argc, char *argv[], User_Arguments *userArgs)
{
int args;
userArgs->engine = NULL;
userArgs->quitOption = EINA_FALSE;
userArgs->backingStore = (char *)backingStores[1];
userArgs->device_pixel_ratio = 1.0;
userArgs->enableEncodingDetector = EINA_FALSE;
userArgs->enableTiledBackingStore = EINA_FALSE;
userArgs->isFlattening = EINA_FALSE;
userArgs->isFullscreen = EINA_FALSE;
userArgs->geometry.x = 0;
userArgs->geometry.y = 0;
userArgs->geometry.w = 0;
userArgs->geometry.h = 0;
userArgs->theme = NULL;
userArgs->userAgent = NULL;
Ecore_Getopt_Value values[] = {
ECORE_GETOPT_VALUE_STR(userArgs->engine),
ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
ECORE_GETOPT_VALUE_STR(userArgs->backingStore),
ECORE_GETOPT_VALUE_DOUBLE(userArgs->device_pixel_ratio),
ECORE_GETOPT_VALUE_BOOL(userArgs->enableEncodingDetector),
ECORE_GETOPT_VALUE_BOOL(userArgs->isFlattening),
ECORE_GETOPT_VALUE_BOOL(userArgs->isFullscreen),
ECORE_GETOPT_VALUE_PTR_CAST(userArgs->geometry),
ECORE_GETOPT_VALUE_STR(userArgs->theme),
ECORE_GETOPT_VALUE_BOOL(userArgs->enableTiledBackingStore),
ECORE_GETOPT_VALUE_STR(userArgs->userAgent),
ECORE_GETOPT_VALUE_INT(verbose),
ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
ECORE_GETOPT_VALUE_NONE
};
ecore_app_args_set(argc, (const char**) argv);
args = ecore_getopt_parse(&options, values, argc, argv);
themePath = findThemePath(userArgs->theme);
if ((userArgs->geometry.w <= 0) || (userArgs->geometry.h <= 0)) {
userArgs->geometry.w = DEFAULT_WIDTH;
userArgs->geometry.h = DEFAULT_HEIGHT;
}
return args;
}
int
main(int argc, char *argv[])
{
const char *default_url = "http://www.google.com/";
const char *tmp;
const char *proxyUri;
char path[PATH_MAX];
int args;
User_Arguments userArgs;
if (!ewk_init())
return EXIT_FAILURE;
if (!ecore_file_init()) {
ewk_shutdown();
return EXIT_FAILURE;
}
args = parseUserArguments(argc, argv, &userArgs);
if (args < 0)
return quit(EINA_FALSE, "ERROR: could not parse options.\n");
if (userArgs.quitOption)
return quit(EINA_TRUE, NULL);
if (!themePath)
return quit(EINA_FALSE, "ERROR: could not find theme.\n");
tmp = getenv("TMPDIR");
if (!tmp)
tmp = "/tmp";
snprintf(path, sizeof(path), "%s/.ewebkit-%u", tmp, getuid());
if (!ecore_file_mkpath(path))
return quit(EINA_FALSE, "ERROR: could not create settings database directory.\n");
userArgs.databasePath = path;
ewk_settings_icon_database_path_set(path);
ewk_settings_web_database_path_set(path);
proxyUri = getenv("http_proxy");
if (proxyUri)
ewk_network_proxy_uri_set(proxyUri);
if (args < argc) {
char *url = url_from_user_input(argv[args]);
browserCreate(url, &userArgs);
free(url);
} else
browserCreate(default_url, &userArgs);
ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT, main_signal_exit, &windows);
ecore_main_loop_begin();
ecore_file_shutdown();
ewk_shutdown();
return quit(EINA_TRUE, NULL);
}