dd392e4e18b09a06e841c5e725560a3134278ee9
[WebKit-https.git] / Tools / EWebLauncher / main.c
1 /*
2  * Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia
3  * Copyright (C) 2009, 2010 ProFUSION embedded systems
4  * Copyright (C) 2009, 2010, 2011 Samsung Electronics
5  * Copyright (C) 2012 Intel Corporation
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "EWebKit.h"
32
33 #include "url_bar.h"
34 #include "url_utils.h"
35 #include <Ecore.h>
36 #include <Ecore_Evas.h>
37 #include <Ecore_File.h>
38 #include <Ecore_Getopt.h>
39 #include <Ecore_X.h>
40 #include <Edje.h>
41 #include <Evas.h>
42 #include <ctype.h>
43 #include <inttypes.h>
44 #include <limits.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <sys/stat.h>
49 #include <sys/types.h>
50 #include <unistd.h>
51
52 #define DEFAULT_WIDTH      800
53 #define DEFAULT_HEIGHT     600
54 #define DEFAULT_ZOOM_INIT  1.0
55
56 #define info(format, args...)       \
57     do {                            \
58         if (verbose)                \
59             printf(format, ##args); \
60     } while (0)
61
62 #define MIN_ZOOM_LEVEL 0
63 #define DEFAULT_ZOOM_LEVEL 5
64 #define MAX_ZOOM_LEVEL 13
65
66 static int currentZoomLevel = DEFAULT_ZOOM_LEVEL;
67 static float currentZoom = 1.0;
68
69 // the zoom values are chosen to be like in Mozilla Firefox 3
70 static int zoomLevels[] = {30, 50, 67, 80, 90,
71                             100,
72                             110, 120, 133, 150, 170, 200, 240, 300};
73
74 static int verbose = 0;
75
76 static Eina_List *windows = NULL;
77
78 static char *themePath = NULL;
79
80 static const char *backingStores[] = {
81     "tiled",
82     "single",
83     NULL
84 };
85
86 typedef struct _Window_Properties {
87     Eina_Bool toolbarsVisible:1;
88     Eina_Bool statusbarVisible:1;
89     Eina_Bool scrollbarsVisible:1;
90     Eina_Bool menubarVisible:1;
91 } Window_Properties;
92
93 Window_Properties windowProperties = { /* Pretend we have them and they are initially visible */
94     EINA_TRUE,
95     EINA_TRUE,
96     EINA_TRUE,
97     EINA_TRUE
98 };
99
100 static const Ecore_Getopt options = {
101     "EWebLauncher",
102     "%prog [options] [url]",
103     "0.0.1",
104     "(C)2008 INdT (The Nokia Technology Institute)\n"
105     "(C)2009, 2010 ProFUSION embedded systems\n"
106     "(C)2009, 2010, 2011 Samsung Electronics\n"
107     "(C)2012 Intel Corporation\n",
108     "GPL",
109     "Test Web Browser using the Enlightenment Foundation Libraries of WebKit",
110     EINA_TRUE, {
111         ECORE_GETOPT_STORE_STR
112             ('e', "engine", "ecore-evas engine to use."),
113         ECORE_GETOPT_CALLBACK_NOARGS
114             ('E', "list-engines", "list ecore-evas engines.",
115              ecore_getopt_callback_ecore_evas_list_engines, NULL),
116         ECORE_GETOPT_CHOICE
117             ('b', "backing-store", "choose backing store to use.", backingStores),
118         ECORE_GETOPT_STORE_DEF_BOOL
119             ('f', "flattening", "frame flattening.", 0),
120         ECORE_GETOPT_STORE_DEF_BOOL
121             ('F', "fullscreen", "fullscreen mode.", 0),
122         ECORE_GETOPT_CALLBACK_ARGS
123             ('g', "geometry", "geometry to use in x:y:w:h form.", "X:Y:W:H",
124              ecore_getopt_callback_geometry_parse, NULL),
125         ECORE_GETOPT_STORE_STR
126             ('t', "theme", "path to read the theme file from."),
127         ECORE_GETOPT_STORE_STR
128             ('U', "user-agent", "custom user agent string to use."),
129         ECORE_GETOPT_COUNT
130             ('v', "verbose", "be more verbose."),
131         ECORE_GETOPT_VERSION
132             ('V', "version"),
133         ECORE_GETOPT_COPYRIGHT
134             ('R', "copyright"),
135         ECORE_GETOPT_LICENSE
136             ('L', "license"),
137         ECORE_GETOPT_HELP
138             ('h', "help"),
139         ECORE_GETOPT_SENTINEL
140     }
141 };
142
143 typedef struct _User_Arguments {
144     const char *engine;
145     Eina_Bool quitOption;
146     const char *backingStore;
147     Eina_Bool isFlattening;
148     Eina_Bool isFullscreen;
149     Eina_Rectangle geometry;
150     const char *theme;
151     const char *userAgent;
152     const char *databasePath;
153 } User_Arguments;
154
155 typedef struct _ELauncher {
156     Ecore_Evas *ee;
157     Evas *evas;
158     Evas_Object *browser;
159     Url_Bar *url_bar;
160     User_Arguments *userArgs;
161 } ELauncher;
162
163 static void browserDestroy(Ecore_Evas *ee);
164 static void closeWindow(Ecore_Evas *ee);
165 static int browserCreate(const char *url, User_Arguments *userArgs);
166
167 static ELauncher *
168 find_app_from_ee(Ecore_Evas *ee)
169 {
170     Eina_List *l;
171     void *data;
172
173     EINA_LIST_FOREACH(windows, l, data)
174     {
175         ELauncher *app = (ELauncher *) data;
176         if (app->ee == ee)
177             return app;
178     }
179     return NULL;
180 }
181
182 static void
183 print_history(Eina_List *list)
184 {
185     Eina_List *l;
186     void *d;
187
188     if (!verbose)
189        return;
190
191     printf("Session history contains:\n");
192
193     EINA_LIST_FOREACH(list, l, d) {
194        Ewk_History_Item *item = (Ewk_History_Item*)d;
195        cairo_surface_t *cs = ewk_history_item_icon_surface_get(item);
196        char buf[PATH_MAX];
197        int s = snprintf(buf, sizeof(buf), "/tmp/favicon-%s.png", ewk_history_item_uri_original_get(item));
198        for (s--; s >= (int)sizeof("/tmp/favicon-"); s--) {
199            if (!isalnum(buf[s]) && buf[s] != '.')
200                buf[s] = '_';
201        }
202        cs = ewk_history_item_icon_surface_get(item);
203
204        if (cs && cairo_surface_status(cs) == CAIRO_STATUS_SUCCESS)
205            cairo_surface_write_to_png(cs, buf);
206        else
207            buf[0] = '\0';
208
209        printf("* '%s' title='%s' icon='%s'\n",
210               ewk_history_item_uri_original_get(item),
211               ewk_history_item_title_get(item), buf);
212     }
213 }
214
215 static int
216 nearest_zoom_level_get(float factor)
217 {
218     int i, intFactor = (int)(factor * 100.0);
219     for (i = 0; zoomLevels[i] <= intFactor; i++) { }
220     printf("factor=%f, intFactor=%d, zoomLevels[%d]=%d, zoomLevels[%d]=%d\n",
221            factor, intFactor, i-1, zoomLevels[i-1], i, zoomLevels[i]);
222     if (intFactor - zoomLevels[i-1] < zoomLevels[i] - intFactor)
223         return i - 1;
224     return i;
225 }
226
227 static Eina_Bool
228 zoom_level_set(Evas_Object *webview, int level)
229 {
230     float factor = ((float) zoomLevels[level]) / 100.0;
231     Evas_Coord ox, oy, mx, my, cx, cy;
232     evas_pointer_canvas_xy_get(evas_object_evas_get(webview), &mx, &my);
233     evas_object_geometry_get(webview, &ox, &oy, NULL, NULL);
234     cx = mx - ox;
235     cy = my - oy;
236     return ewk_view_zoom_animated_set(webview, factor, 0.5, cx, cy);
237 }
238
239 static void
240 on_ecore_evas_resize(Ecore_Evas *ee)
241 {
242     ELauncher *app;
243     Evas_Object *webview;
244     int w, h;
245
246     ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
247
248     /* Resize URL bar */
249     app = find_app_from_ee(ee);
250     url_bar_width_set(app->url_bar, w);
251
252     webview = evas_object_name_find(ecore_evas_get(ee), "browser");
253     evas_object_move(webview, 0, URL_BAR_HEIGHT);
254     evas_object_resize(webview, w, h - URL_BAR_HEIGHT);
255 }
256
257 static void
258 title_set(Ecore_Evas *ee, const Ewk_Text_With_Direction *title, int progress)
259 {
260     const char *appname = "EFL Test Launcher";
261     const char *separator = " - ";
262     char label[4096];
263     int size;
264
265     if (!title || !title->string || !strcmp(title->string, "")) {
266         ecore_evas_title_set(ee, appname);
267         return;
268     }
269
270     if (progress < 100)
271         size = snprintf(label, sizeof(label), "%s (%d%%)%s%s", title->string, progress, separator, appname);
272     else
273         size = snprintf(label, sizeof(label), "%s %s%s", title->string, separator, appname);
274
275     if (size >= (int)sizeof(label))
276         return;
277
278     ecore_evas_title_set(ee, label);
279 }
280
281 static void
282 on_title_changed(void *user_data, Evas_Object *webview, void *event_info)
283 {
284     ELauncher *app = (ELauncher *)user_data;
285     const Ewk_Text_With_Direction *title = (const Ewk_Text_With_Direction *)event_info;
286
287     title_set(app->ee, title, 100);
288 }
289
290 static void
291 on_progress(void *user_data, Evas_Object *webview, void *event_info)
292 {
293     ELauncher *app = (ELauncher *)user_data;
294     double *progress = (double *)event_info;
295
296     title_set(app->ee, ewk_view_title_get(app->browser), *progress * 100);
297 }
298
299 static void
300 on_load_finished(void *user_data, Evas_Object *webview, void *event_info)
301 {
302     const Ewk_Frame_Load_Error *err = (const Ewk_Frame_Load_Error *)event_info;
303
304     if (!err)
305         info("Succeeded loading page.\n");
306     else if (err->is_cancellation)
307         info("Load was cancelled.\n");
308     else
309         info("Failed loading page: %d %s \"%s\", url=%s\n",
310              err->code, err->domain, err->description, err->failing_url);
311
312     currentZoom = ewk_view_zoom_get(webview);
313     currentZoomLevel = nearest_zoom_level_get(currentZoom);
314     info("WebCore Zoom=%f, currentZoomLevel=%d\n", currentZoom, currentZoomLevel);
315 }
316
317 static void
318 on_load_error(void *user_data, Evas_Object *webview, void *event_info)
319 {
320     const Ewk_Frame_Load_Error *err = (const Ewk_Frame_Load_Error *)event_info;
321     char message[1024];
322     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>",
323              err->code, err->domain, err->description, err->failing_url);
324     ewk_frame_contents_set(err->frame, message, 0, "text/html", "UTF-8", err->failing_url);
325 }
326
327 static void
328 on_toolbars_visible_set(void* user_data, Evas_Object* webview, void* event_info)
329 {
330     Eina_Bool *visible = (Eina_Bool *)event_info;
331     if (*visible) {
332         info("Toolbars visible changed: show");
333         windowProperties.toolbarsVisible = EINA_TRUE;
334     } else {
335         info("Toolbars visible changed: hide");
336         windowProperties.toolbarsVisible = EINA_FALSE;
337     }
338 }
339
340 static void
341 on_toolbars_visible_get(void* user_data, Evas_Object* webview, void* event_info)
342 {
343     Eina_Bool *visible = (Eina_Bool *)event_info;
344     *visible = windowProperties.toolbarsVisible;
345 }
346
347 static void
348 on_statusbar_visible_set(void* user_data, Evas_Object* webview, void* event_info)
349 {
350     Eina_Bool *visible = (Eina_Bool *)event_info;
351     if (*visible) {
352         info("Statusbar visible changed: show");
353         windowProperties.statusbarVisible = EINA_TRUE;
354     } else {
355         info("Statusbar visible changed: hide");
356         windowProperties.statusbarVisible = EINA_FALSE;
357     }
358 }
359
360 static void
361 on_statusbar_visible_get(void* user_data, Evas_Object* webview, void* event_info)
362 {
363     Eina_Bool *visible = (Eina_Bool *)event_info;
364     *visible = windowProperties.statusbarVisible;
365 }
366
367 static void
368 on_scrollbars_visible_set(void* user_data, Evas_Object* webview, void* event_info)
369 {
370     Eina_Bool *visible = (Eina_Bool *)event_info;
371     if (*visible) {
372         info("Scrollbars visible changed: show");
373         windowProperties.scrollbarsVisible = EINA_TRUE;
374     } else {
375         info("Scrollbars visible changed: hide");
376         windowProperties.scrollbarsVisible = EINA_FALSE;
377     }
378 }
379
380 static void
381 on_scrollbars_visible_get(void* user_data, Evas_Object* webview, void* event_info)
382 {
383     Eina_Bool *visible = (Eina_Bool *)event_info;
384     *visible = windowProperties.scrollbarsVisible;
385 }
386
387 static void
388 on_menubar_visible_set(void* user_data, Evas_Object* webview, void* event_info)
389 {
390     Eina_Bool *visible = (Eina_Bool *)event_info;
391     if (*visible) {
392         info("Menubar visible changed: show");
393         windowProperties.menubarVisible = EINA_TRUE;
394     } else {
395         info("Menubar visible changed: hide");
396         windowProperties.menubarVisible = EINA_FALSE;
397     }
398 }
399
400 static void
401 on_menubar_visible_get(void* user_data, Evas_Object* webview, void* event_info)
402 {
403     Eina_Bool *visible = (Eina_Bool *)event_info;
404     *visible = windowProperties.menubarVisible;
405 }
406
407 static void
408 on_tooltip_text_set(void* user_data, Evas_Object* webview, void* event_info)
409 {
410     const char *text = (const char *)event_info;
411     if (text && *text != '\0')
412         info("%s\n", text);
413 }
414
415 static void
416 on_inputmethod_changed(void* user_data, Evas_Object* webview, void* event_info)
417 {
418     Eina_Bool active = (Eina_Bool)(long)event_info;
419     unsigned int imh;
420     info("Keyboard changed: %d\n", active);
421
422     if (!active)
423         return;
424
425     imh = ewk_view_imh_get(webview);
426     info("    Keyboard flags: %#.2x\n", imh);
427
428 }
429
430 static void
431 on_url_changed(void* user_data, Evas_Object* webview, void* event_info)
432 {
433     ELauncher *app = (ELauncher *)user_data;
434     url_bar_url_set(app->url_bar, ewk_view_uri_get(app->browser));
435 }
436
437 static void
438 on_mouse_down(void* data, Evas* e, Evas_Object* webview, void* event_info)
439 {
440     Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down *)event_info;
441
442     if (ev->button == 1)
443         evas_object_focus_set(webview, EINA_TRUE);
444     else if (ev->button == 2)
445         evas_object_focus_set(webview, !evas_object_focus_get(webview));
446 }
447
448 static void
449 on_focus_out(void *data, Evas *e, Evas_Object *obj, void *event_info)
450 {
451     info("the webview lost keyboard focus\n");
452 }
453
454 static void
455 on_focus_in(void *data, Evas *e, Evas_Object *obj, void *event_info)
456 {
457     info("the webview gained keyboard focus\n");
458 }
459
460 static void
461 on_key_down(void *data, Evas *e, Evas_Object *obj, void *event_info)
462 {
463     Evas_Event_Key_Down *ev = (Evas_Event_Key_Down*) event_info;
464     ELauncher *app = data;
465     static const char *encodings[] = {
466         "ISO-8859-1",
467         "UTF-8",
468         NULL
469     };
470     static int currentEncoding = -1;
471     Eina_Bool ctrlPressed = evas_key_modifier_is_set(evas_key_modifier_get(e), "Control");
472
473     if (!strcmp(ev->key, "Escape")) {
474         closeWindow(app->ee);
475     } else if (!strcmp(ev->key, "F1")) {
476         info("Back (F1) was pressed\n");
477         if (ewk_view_back_possible(obj)) {
478             Ewk_History *history = ewk_view_history_get(obj);
479             Eina_List *list = ewk_history_back_list_get(history);
480             print_history(list);
481             ewk_history_item_list_free(list);
482             ewk_view_back(obj);
483         } else
484             info("Back ignored: No back history\n");
485     } else if (!strcmp(ev->key, "F2")) {
486         info("Forward (F2) was pressed\n");
487         if (ewk_view_forward_possible(obj)) {
488             Ewk_History *history = ewk_view_history_get(obj);
489             Eina_List *list = ewk_history_forward_list_get(history);
490             print_history(list);
491             ewk_history_item_list_free(list);
492             ewk_view_forward(obj);
493         } else
494             info("Forward ignored: No forward history\n");
495     } else if (!strcmp(ev->key, "F3")) {
496         currentEncoding++;
497         currentEncoding %= (sizeof(encodings) / sizeof(encodings[0]));
498         info("Set encoding (F3) pressed. New encoding to %s", encodings[currentEncoding]);
499         ewk_view_setting_encoding_custom_set(obj, encodings[currentEncoding]);
500     } else if (!strcmp(ev->key, "F4")) {
501         Evas_Object *frame = ewk_view_frame_main_get(obj);
502         Evas_Coord x, y;
503         Ewk_Hit_Test *ht;
504
505         evas_pointer_canvas_xy_get(evas_object_evas_get(obj), &x, &y);
506         ht = ewk_frame_hit_test_new(frame, x, y);
507         if (!ht)
508             printf("No hit test returned for point %d,%d\n", x, y);
509         else {
510             printf("Hit test for point %d,%d\n"
511                    "  pos=%3d,%3d\n"
512                    "  bounding_box=%d,%d + %dx%d\n"
513                    "  title='%s'\n"
514                    "  alternate_text='%s'\n"
515                    "  frame=%p (%s)\n"
516                    "  link {\n"
517                    "    text='%s'\n"
518                    "    url='%s'\n"
519                    "    title='%s'\n"
520                    "    target frame=%p (%s)\n"
521                    "  }\n"
522                    "context:\n"
523                    "%s"
524                    "%s"
525                    "%s"
526                    "%s"
527                    "%s\n",
528                    x, y,
529                    ht->x, ht->y,
530                    ht->bounding_box.x, ht->bounding_box.y, ht->bounding_box.w, ht->bounding_box.h,
531                    ht->title.string,
532                    ht->alternate_text,
533                    ht->frame, evas_object_name_get(ht->frame),
534                    ht->link.text,
535                    ht->link.url,
536                    ht->link.title,
537                    ht->link.target_frame, evas_object_name_get(ht->link.target_frame),
538                    ht->context & EWK_HIT_TEST_RESULT_CONTEXT_LINK ? "  LINK\n" : "",
539                    ht->context & EWK_HIT_TEST_RESULT_CONTEXT_IMAGE ? "  IMAGE\n" : "",
540                    ht->context & EWK_HIT_TEST_RESULT_CONTEXT_MEDIA ? "   MEDIA\n" : "",
541                    ht->context & EWK_HIT_TEST_RESULT_CONTEXT_SELECTION ? "  SELECTION\n" : "",
542                    ht->context & EWK_HIT_TEST_RESULT_CONTEXT_EDITABLE ? "  EDITABLE" : "");
543             ewk_frame_hit_test_free(ht);
544         }
545
546     } else if (!strcmp(ev->key, "F5")) {
547         info("Reload (F5) was pressed, reloading.\n");
548         ewk_view_reload(obj);
549     } else if (!strcmp(ev->key, "F6")) {
550         info("Stop (F6) was pressed, stop loading.\n");
551         ewk_view_stop(obj);
552     } else if (!strcmp(ev->key, "F12")) {
553         Eina_Bool status = ewk_view_setting_spatial_navigation_get(obj);
554         ewk_view_setting_spatial_navigation_set(obj, !status);
555         info("Command::keyboard navigation toggle\n");
556     } else if (!strcmp(ev->key, "F7")) {
557         info("Zoom out (F7) was pressed.\n");
558         if (currentZoomLevel > MIN_ZOOM_LEVEL && zoom_level_set(obj, currentZoomLevel - 1))
559             currentZoomLevel--;
560     } else if (!strcmp(ev->key, "F8")) {
561         info("Zoom in (F8) was pressed.\n");
562         if (currentZoomLevel < MAX_ZOOM_LEVEL && zoom_level_set(obj, currentZoomLevel + 1))
563             currentZoomLevel++;
564     } else if (!strcmp(ev->key, "F9")) {
565         info("Create new window (F9) was pressed.\n");
566         browserCreate("http://www.google.com", app->userArgs);
567     } else if (!strcmp(ev->key, "g") && ctrlPressed ) {
568         Evas_Coord x, y, w, h;
569         Evas_Object *frame = ewk_view_frame_main_get(obj);
570         float zoom = zoomLevels[currentZoomLevel] / 100.0;
571
572         ewk_frame_visible_content_geometry_get(frame, EINA_FALSE, &x, &y, &w, &h);
573         x -= w;
574         y -= h;
575         w *= 4;
576         h *= 4;
577         info("Pre-render %d,%d + %dx%d\n", x, y, w, h);
578         ewk_view_pre_render_region(obj, x, y, w, h, zoom);
579     } else if (!strcmp(ev->key, "r") && ctrlPressed) {
580         info("Pre-render 1 extra column/row with current zoom");
581         ewk_view_pre_render_relative_radius(obj, 1);
582     } else if (!strcmp(ev->key, "p") && ctrlPressed) {
583         info("Pre-rendering start");
584         ewk_view_pre_render_start(obj);
585     } else if (!strcmp(ev->key, "d") && ctrlPressed) {
586         info("Render suspended");
587         ewk_view_disable_render(obj);
588     } else if (!strcmp(ev->key, "e") && ctrlPressed) {
589         info("Render resumed");
590         ewk_view_enable_render(obj);
591     } else if (!strcmp(ev->key, "s") && ctrlPressed) {
592         Evas_Object *frame = ewk_view_frame_main_get(obj);
593         Ewk_Security_Origin *origin = ewk_frame_security_origin_get(frame);
594         printf("Security origin information:\n"
595                "  protocol=%s\n"
596                "  host=%s\n"
597                "  port=%d\n"
598                "  web database quota=%" PRIu64 "\n",
599                ewk_security_origin_protocol_get(origin),
600                ewk_security_origin_host_get(origin),
601                ewk_security_origin_port_get(origin),
602                ewk_security_origin_web_database_quota_get(origin));
603
604         Eina_List *databaseList = ewk_security_origin_web_database_get_all(origin);
605         Eina_List *listIterator = 0;
606         Ewk_Web_Database *database;
607         EINA_LIST_FOREACH(databaseList, listIterator, database)
608             printf("Database information:\n"
609                    "  name=%s\n"
610                    "  display name=%s\n"
611                    "  filename=%s\n"
612                    "  expected size=%" PRIu64 "\n"
613                    "  size=%" PRIu64 "\n",
614                    ewk_web_database_name_get(database),
615                    ewk_web_database_display_name_get(database),
616                    ewk_web_database_filename_get(database),
617                    ewk_web_database_expected_size_get(database),
618                    ewk_web_database_size_get(database));
619
620         ewk_security_origin_free(origin);
621         ewk_web_database_list_free(databaseList);
622     }
623 }
624
625 static void
626 on_browser_del(void *data, Evas *evas, Evas_Object *browser, void *event)
627 {
628     ELauncher *app = (ELauncher*) data;
629
630     evas_object_event_callback_del(app->browser, EVAS_CALLBACK_KEY_DOWN, on_key_down);
631     evas_object_event_callback_del(app->browser, EVAS_CALLBACK_MOUSE_DOWN, on_mouse_down);
632     evas_object_event_callback_del(app->browser, EVAS_CALLBACK_FOCUS_IN, on_focus_in);
633     evas_object_event_callback_del(app->browser, EVAS_CALLBACK_FOCUS_OUT, on_focus_out);
634     evas_object_event_callback_del(app->browser, EVAS_CALLBACK_DEL, on_browser_del);
635 }
636
637 static int
638 quit(Eina_Bool success, const char *msg)
639 {
640     edje_shutdown();
641     ecore_evas_shutdown();
642     ecore_file_shutdown();
643
644     if (msg)
645         fputs(msg, (success) ? stdout : stderr);
646
647     if (themePath) {
648         free(themePath);
649         themePath = NULL;
650     }
651
652     if (!success)
653         return EXIT_FAILURE;
654
655     return EXIT_SUCCESS;
656 }
657
658 static int
659 browserCreate(const char *url, User_Arguments *userArgs)
660 {
661     Eina_Rectangle geometry = userArgs->geometry;
662     if ((geometry.w <= 0) && (geometry.h <= 0)) {
663         geometry.w = DEFAULT_WIDTH;
664         geometry.h = DEFAULT_HEIGHT;
665     }
666
667     ELauncher *app = (ELauncher*) malloc(sizeof(ELauncher));
668     if (!app)
669         return quit(EINA_FALSE, "ERROR: could not create EWebLauncher window\n");
670
671     app->ee = ecore_evas_new(userArgs->engine, 0, 0, geometry.w, geometry.h, NULL);
672
673     if (!app->ee)
674         return quit(EINA_FALSE, "ERROR: could not construct evas-ecore\n");
675
676     if (userArgs->isFullscreen)
677         ecore_evas_fullscreen_set(app->ee, EINA_TRUE);
678
679     ecore_evas_title_set(app->ee, "EFL Test Launcher");
680     ecore_evas_callback_resize_set(app->ee, on_ecore_evas_resize);
681     ecore_evas_callback_delete_request_set(app->ee, closeWindow);
682
683     app->evas = ecore_evas_get(app->ee);
684
685     if (!app->evas)
686         return quit(EINA_FALSE, "ERROR: could not get evas from evas-ecore\n");
687
688     if (userArgs->backingStore && !strcasecmp(userArgs->backingStore, "tiled")) {
689         app->browser = ewk_view_tiled_add(app->evas);
690         info("backing store: tiled\n");
691     } else {
692         app->browser = ewk_view_single_add(app->evas);
693         info("backing store: single\n");
694     }
695
696     ewk_view_theme_set(app->browser, themePath);
697     if (userArgs->userAgent)
698         ewk_view_setting_user_agent_set(app->browser, userArgs->userAgent);
699     ewk_view_setting_local_storage_database_path_set(app->browser, userArgs->databasePath);
700     ewk_view_setting_enable_frame_flattening_set(app->browser, userArgs->isFlattening);
701     
702     app->userArgs = userArgs;
703     evas_object_name_set(app->browser, "browser");
704
705     evas_object_smart_callback_add(app->browser, "title,changed", on_title_changed, app);
706     evas_object_smart_callback_add(app->browser, "load,progress", on_progress, app);
707     evas_object_smart_callback_add(app->browser, "load,finished", on_load_finished, app);
708     evas_object_smart_callback_add(app->browser, "load,error", on_load_error, app);
709
710     evas_object_smart_callback_add(app->browser, "toolbars,visible,set", on_toolbars_visible_set, app);
711     evas_object_smart_callback_add(app->browser, "toolbars,visible,get", on_toolbars_visible_get, app);
712     evas_object_smart_callback_add(app->browser, "statusbar,visible,set", on_statusbar_visible_set, app);
713     evas_object_smart_callback_add(app->browser, "statusbar,visible,get", on_statusbar_visible_get, app);
714     evas_object_smart_callback_add(app->browser, "scrollbars,visible,set", on_scrollbars_visible_set, app);
715     evas_object_smart_callback_add(app->browser, "scrollbars,visible,get", on_scrollbars_visible_get, app);
716     evas_object_smart_callback_add(app->browser, "menubar,visible,set", on_menubar_visible_set, app);
717     evas_object_smart_callback_add(app->browser, "menubar,visible,get", on_menubar_visible_get, app);
718     evas_object_smart_callback_add(app->browser, "tooltip,text,set", on_tooltip_text_set, app);
719     evas_object_smart_callback_add(app->browser, "inputmethod,changed", on_inputmethod_changed, app);
720     evas_object_smart_callback_add(app->browser, "uri,changed", on_url_changed, app);
721
722 /*     ewk_callback_resize_requested_add(app->browser, on_resize_requested, app->ee); */
723
724     evas_object_event_callback_add(app->browser, EVAS_CALLBACK_KEY_DOWN, on_key_down, app);
725     evas_object_event_callback_add(app->browser, EVAS_CALLBACK_MOUSE_DOWN, on_mouse_down, app);
726     evas_object_event_callback_add(app->browser, EVAS_CALLBACK_FOCUS_IN, on_focus_in, app);
727     evas_object_event_callback_add(app->browser, EVAS_CALLBACK_FOCUS_OUT, on_focus_out, app);
728     evas_object_event_callback_add(app->browser, EVAS_CALLBACK_DEL, on_browser_del, app);
729
730     app->url_bar = url_bar_add(app->browser, DEFAULT_WIDTH);
731
732     evas_object_move(app->browser, 0, URL_BAR_HEIGHT);
733     evas_object_resize(app->browser, geometry.w, geometry.h - URL_BAR_HEIGHT);
734
735     if (url && (url[0] != '\0'))
736         ewk_view_uri_set(app->browser, url);
737
738     evas_object_show(app->browser);
739     ecore_evas_show(app->ee);
740
741     evas_object_focus_set(app->browser, EINA_TRUE);
742
743     windows = eina_list_append(windows, app);
744
745     return 1;
746 }
747
748 static void
749 browserDestroy(Ecore_Evas *ee)
750 {
751     ecore_evas_free(ee);
752     if (!eina_list_count(windows))
753         ecore_main_loop_quit();
754 }
755
756 static void
757 closeWindow(Ecore_Evas *ee)
758 {
759     ELauncher *app;
760
761     app = find_app_from_ee(ee);
762     windows = eina_list_remove(windows, app);
763     url_bar_del(app->url_bar);
764     browserDestroy(ee);
765     free(app);
766 }
767
768 static Eina_Bool
769 main_signal_exit(void *data, int ev_type, void *ev)
770 {
771     ELauncher *app;
772     while (windows) {
773         app = (ELauncher*) eina_list_data_get(windows);
774         ecore_evas_free(app->ee);
775         windows = eina_list_remove(windows, app);
776     }
777     if (!eina_list_count(windows))
778         ecore_main_loop_quit();
779     return EINA_TRUE;
780 }
781
782 static char *
783 findThemePath(const char *theme)
784 {
785     const char *default_theme = THEME_DIR"/default.edj";
786     char *rpath;
787     struct stat st;
788
789     if (!theme)
790         theme = default_theme;
791
792     rpath = ecore_file_realpath(theme);
793
794     if (!strlen(rpath) || stat(rpath, &st)) {
795         free(rpath);
796         return NULL;
797     }
798
799     return rpath;
800 }
801
802 int
803 parseUserArguments(int argc, char *argv[], User_Arguments *userArgs)
804 {
805     int args;
806
807     userArgs->engine = NULL;
808     userArgs->quitOption = EINA_FALSE;
809     userArgs->backingStore = (char *)backingStores[1];
810     userArgs->isFlattening = EINA_FALSE;
811     userArgs->isFullscreen = EINA_FALSE;
812     userArgs->geometry.x = 0;
813     userArgs->geometry.y = 0;
814     userArgs->geometry.w = 0;
815     userArgs->geometry.h = 0;
816     userArgs->theme = NULL;
817     userArgs->userAgent = NULL;
818
819     Ecore_Getopt_Value values[] = {
820         ECORE_GETOPT_VALUE_STR(userArgs->engine),
821         ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
822         ECORE_GETOPT_VALUE_STR(userArgs->backingStore),
823         ECORE_GETOPT_VALUE_BOOL(userArgs->isFlattening),
824         ECORE_GETOPT_VALUE_BOOL(userArgs->isFullscreen),
825         ECORE_GETOPT_VALUE_PTR_CAST(userArgs->geometry),
826         ECORE_GETOPT_VALUE_STR(userArgs->theme),
827         ECORE_GETOPT_VALUE_STR(userArgs->userAgent),
828         ECORE_GETOPT_VALUE_INT(verbose),
829         ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
830         ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
831         ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
832         ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
833         ECORE_GETOPT_VALUE_NONE
834     };
835
836     ecore_app_args_set(argc, (const char**) argv);
837     args = ecore_getopt_parse(&options, values, argc, argv);
838
839     themePath = findThemePath(userArgs->theme);
840
841     return args;
842 }
843
844 int
845 main(int argc, char *argv[])
846 {
847     const char *default_url = "http://www.google.com/";
848     const char *tmp;
849     const char *proxyUri;
850     char path[PATH_MAX];
851     int args;
852
853     User_Arguments userArgs;
854
855     if (!ecore_evas_init())
856         return EXIT_FAILURE;
857
858     if (!edje_init()) {
859         ecore_evas_shutdown();
860         return EXIT_FAILURE;
861     }
862
863     if (!ecore_file_init()) {
864         edje_shutdown();
865         ecore_evas_shutdown();
866         return EXIT_FAILURE;
867     }
868
869     args = parseUserArguments(argc, argv, &userArgs);
870     if (args < 0)
871        return quit(EINA_FALSE, "ERROR: could not parse options.\n");
872
873     if (userArgs.quitOption)
874         return quit(EINA_TRUE, NULL);
875
876     if (!themePath)
877         return quit(EINA_FALSE, "ERROR: could not find theme.\n");
878
879     ewk_init();
880     tmp = getenv("TMPDIR");
881     if (!tmp)
882         tmp = "/tmp";
883     snprintf(path, sizeof(path), "%s/.ewebkit-%u", tmp, getuid());
884     if (!ecore_file_mkpath(path))
885         return quit(EINA_FALSE, "ERROR: could not create settings database directory.\n");
886
887     userArgs.databasePath = path;
888
889     ewk_settings_icon_database_path_set(path);
890     ewk_settings_web_database_path_set(path);
891
892     proxyUri = getenv("http_proxy");
893     if (proxyUri)
894         ewk_network_proxy_uri_set(proxyUri);
895
896     if (args < argc) {
897         char *url = url_from_user_input(argv[args]);
898         browserCreate(url, &userArgs);
899         free(url);
900     } else
901         browserCreate(default_url, &userArgs);
902
903     ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT, main_signal_exit, &windows);
904
905     ecore_main_loop_begin();
906
907     ewk_shutdown();
908
909     return quit(EINA_TRUE, NULL);
910 }