[EFL] Add Web Inspector to EWebLauncher
[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 windowDestroy(Ecore_Evas *ee);
164 static void closeWindow(Ecore_Evas *ee);
165 static int browserCreate(const char *url, User_Arguments *userArgs);
166 static int webInspectorCreate(ELauncher *appBrowser);
167 static ELauncher *windowCreate(User_Arguments *userArgs);
168
169 static ELauncher *
170 find_app_from_ee(Ecore_Evas *ee)
171 {
172     Eina_List *l;
173     void *data;
174
175     EINA_LIST_FOREACH(windows, l, data)
176     {
177         ELauncher *app = (ELauncher *) data;
178         if (app->ee == ee)
179             return app;
180     }
181     return NULL;
182 }
183
184 static void
185 print_history(Eina_List *list)
186 {
187     Eina_List *l;
188     void *d;
189
190     if (!verbose)
191        return;
192
193     printf("Session history contains:\n");
194
195     EINA_LIST_FOREACH(list, l, d) {
196        Ewk_History_Item *item = (Ewk_History_Item*)d;
197        cairo_surface_t *cs = ewk_history_item_icon_surface_get(item);
198        char buf[PATH_MAX];
199        int s = snprintf(buf, sizeof(buf), "/tmp/favicon-%s.png", ewk_history_item_uri_original_get(item));
200        for (s--; s >= (int)sizeof("/tmp/favicon-"); s--) {
201            if (!isalnum(buf[s]) && buf[s] != '.')
202                buf[s] = '_';
203        }
204        cs = ewk_history_item_icon_surface_get(item);
205
206        if (cs && cairo_surface_status(cs) == CAIRO_STATUS_SUCCESS)
207            cairo_surface_write_to_png(cs, buf);
208        else
209            buf[0] = '\0';
210
211        printf("* '%s' title='%s' icon='%s'\n",
212               ewk_history_item_uri_original_get(item),
213               ewk_history_item_title_get(item), buf);
214     }
215 }
216
217 static int
218 nearest_zoom_level_get(float factor)
219 {
220     int i, intFactor = (int)(factor * 100.0);
221     for (i = 0; zoomLevels[i] <= intFactor; i++) { }
222     printf("factor=%f, intFactor=%d, zoomLevels[%d]=%d, zoomLevels[%d]=%d\n",
223            factor, intFactor, i-1, zoomLevels[i-1], i, zoomLevels[i]);
224     if (intFactor - zoomLevels[i-1] < zoomLevels[i] - intFactor)
225         return i - 1;
226     return i;
227 }
228
229 static Eina_Bool
230 zoom_level_set(Evas_Object *webview, int level)
231 {
232     float factor = ((float) zoomLevels[level]) / 100.0;
233     Evas_Coord ox, oy, mx, my, cx, cy;
234     evas_pointer_canvas_xy_get(evas_object_evas_get(webview), &mx, &my);
235     evas_object_geometry_get(webview, &ox, &oy, NULL, NULL);
236     cx = mx - ox;
237     cy = my - oy;
238     return ewk_view_zoom_animated_set(webview, factor, 0.5, cx, cy);
239 }
240
241 static void
242 on_browser_ecore_evas_resize(Ecore_Evas *ee)
243 {
244     ELauncher *app;
245     Evas_Object *webview;
246     int w, h;
247
248     ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
249
250     /* Resize URL bar */
251     app = find_app_from_ee(ee);
252     url_bar_width_set(app->url_bar, w);
253
254     webview = evas_object_name_find(ecore_evas_get(ee), "browser");
255     evas_object_move(webview, 0, URL_BAR_HEIGHT);
256     evas_object_resize(webview, w, h - URL_BAR_HEIGHT);
257 }
258
259 static void
260 on_web_inspector_ecore_evas_resize(Ecore_Evas *ee)
261 {
262     Evas_Object *webview;
263     int w, h;
264
265     ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
266
267     webview = evas_object_name_find(ecore_evas_get(ee), "inspector");
268     evas_object_move(webview, 0, 0);
269     evas_object_resize(webview, w, h);
270 }
271
272 static void
273 title_set(Ecore_Evas *ee, const Ewk_Text_With_Direction *title, int progress)
274 {
275     const char *appname = "EFL Test Launcher";
276     const char *separator = " - ";
277     char label[4096];
278     int size;
279
280     if (!title || !title->string || !strcmp(title->string, "")) {
281         ecore_evas_title_set(ee, appname);
282         return;
283     }
284
285     if (progress < 100)
286         size = snprintf(label, sizeof(label), "%s (%d%%)%s%s", title->string, progress, separator, appname);
287     else
288         size = snprintf(label, sizeof(label), "%s %s%s", title->string, separator, appname);
289
290     if (size >= (int)sizeof(label))
291         return;
292
293     ecore_evas_title_set(ee, label);
294 }
295
296 static void
297 on_title_changed(void *user_data, Evas_Object *webview, void *event_info)
298 {
299     ELauncher *app = (ELauncher *)user_data;
300     const Ewk_Text_With_Direction *title = (const Ewk_Text_With_Direction *)event_info;
301
302     title_set(app->ee, title, 100);
303 }
304
305 static void
306 on_progress(void *user_data, Evas_Object *webview, void *event_info)
307 {
308     ELauncher *app = (ELauncher *)user_data;
309     double *progress = (double *)event_info;
310
311     title_set(app->ee, ewk_view_title_get(app->browser), *progress * 100);
312 }
313
314 static void
315 on_load_finished(void *user_data, Evas_Object *webview, void *event_info)
316 {
317     const Ewk_Frame_Load_Error *err = (const Ewk_Frame_Load_Error *)event_info;
318
319     if (!err)
320         info("Succeeded loading page.\n");
321     else if (err->is_cancellation)
322         info("Load was cancelled.\n");
323     else
324         info("Failed loading page: %d %s \"%s\", url=%s\n",
325              err->code, err->domain, err->description, err->failing_url);
326
327     currentZoom = ewk_view_zoom_get(webview);
328     currentZoomLevel = nearest_zoom_level_get(currentZoom);
329     info("WebCore Zoom=%f, currentZoomLevel=%d\n", currentZoom, currentZoomLevel);
330 }
331
332 static void
333 on_load_error(void *user_data, Evas_Object *webview, void *event_info)
334 {
335     const Ewk_Frame_Load_Error *err = (const Ewk_Frame_Load_Error *)event_info;
336     char message[1024];
337     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>",
338              err->code, err->domain, err->description, err->failing_url);
339     ewk_frame_contents_set(err->frame, message, 0, "text/html", "UTF-8", err->failing_url);
340 }
341
342 static void
343 on_toolbars_visible_set(void* user_data, Evas_Object* webview, void* event_info)
344 {
345     Eina_Bool *visible = (Eina_Bool *)event_info;
346     if (*visible) {
347         info("Toolbars visible changed: show");
348         windowProperties.toolbarsVisible = EINA_TRUE;
349     } else {
350         info("Toolbars visible changed: hide");
351         windowProperties.toolbarsVisible = EINA_FALSE;
352     }
353 }
354
355 static void
356 on_toolbars_visible_get(void* user_data, Evas_Object* webview, void* event_info)
357 {
358     Eina_Bool *visible = (Eina_Bool *)event_info;
359     *visible = windowProperties.toolbarsVisible;
360 }
361
362 static void
363 on_statusbar_visible_set(void* user_data, Evas_Object* webview, void* event_info)
364 {
365     Eina_Bool *visible = (Eina_Bool *)event_info;
366     if (*visible) {
367         info("Statusbar visible changed: show");
368         windowProperties.statusbarVisible = EINA_TRUE;
369     } else {
370         info("Statusbar visible changed: hide");
371         windowProperties.statusbarVisible = EINA_FALSE;
372     }
373 }
374
375 static void
376 on_statusbar_visible_get(void* user_data, Evas_Object* webview, void* event_info)
377 {
378     Eina_Bool *visible = (Eina_Bool *)event_info;
379     *visible = windowProperties.statusbarVisible;
380 }
381
382 static void
383 on_scrollbars_visible_set(void* user_data, Evas_Object* webview, void* event_info)
384 {
385     Eina_Bool *visible = (Eina_Bool *)event_info;
386     if (*visible) {
387         info("Scrollbars visible changed: show");
388         windowProperties.scrollbarsVisible = EINA_TRUE;
389     } else {
390         info("Scrollbars visible changed: hide");
391         windowProperties.scrollbarsVisible = EINA_FALSE;
392     }
393 }
394
395 static void
396 on_scrollbars_visible_get(void* user_data, Evas_Object* webview, void* event_info)
397 {
398     Eina_Bool *visible = (Eina_Bool *)event_info;
399     *visible = windowProperties.scrollbarsVisible;
400 }
401
402 static void
403 on_menubar_visible_set(void* user_data, Evas_Object* webview, void* event_info)
404 {
405     Eina_Bool *visible = (Eina_Bool *)event_info;
406     if (*visible) {
407         info("Menubar visible changed: show");
408         windowProperties.menubarVisible = EINA_TRUE;
409     } else {
410         info("Menubar visible changed: hide");
411         windowProperties.menubarVisible = EINA_FALSE;
412     }
413 }
414
415 static void
416 on_menubar_visible_get(void* user_data, Evas_Object* webview, void* event_info)
417 {
418     Eina_Bool *visible = (Eina_Bool *)event_info;
419     *visible = windowProperties.menubarVisible;
420 }
421
422 static void
423 on_tooltip_text_set(void* user_data, Evas_Object* webview, void* event_info)
424 {
425     const char *text = (const char *)event_info;
426     if (text && *text != '\0')
427         info("%s\n", text);
428 }
429
430 static void
431 on_inputmethod_changed(void* user_data, Evas_Object* webview, void* event_info)
432 {
433     Eina_Bool active = (Eina_Bool)(long)event_info;
434     unsigned int imh;
435     info("Keyboard changed: %d\n", active);
436
437     if (!active)
438         return;
439
440     imh = ewk_view_imh_get(webview);
441     info("    Keyboard flags: %#.2x\n", imh);
442
443 }
444
445 static void
446 on_url_changed(void* user_data, Evas_Object* webview, void* event_info)
447 {
448     ELauncher *app = (ELauncher *)user_data;
449     url_bar_url_set(app->url_bar, ewk_view_uri_get(app->browser));
450 }
451
452 static void
453 on_mouse_down(void* data, Evas* e, Evas_Object* webview, void* event_info)
454 {
455     Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down *)event_info;
456
457     if (ev->button == 1)
458         evas_object_focus_set(webview, EINA_TRUE);
459     else if (ev->button == 2)
460         evas_object_focus_set(webview, !evas_object_focus_get(webview));
461 }
462
463 static void
464 on_focus_out(void *data, Evas *e, Evas_Object *obj, void *event_info)
465 {
466     info("the webview lost keyboard focus\n");
467 }
468
469 static void
470 on_focus_in(void *data, Evas *e, Evas_Object *obj, void *event_info)
471 {
472     info("the webview gained keyboard focus\n");
473 }
474
475 static void
476 on_key_down(void *data, Evas *e, Evas_Object *obj, void *event_info)
477 {
478     Evas_Event_Key_Down *ev = (Evas_Event_Key_Down*) event_info;
479     ELauncher *app = data;
480     static const char *encodings[] = {
481         "ISO-8859-1",
482         "UTF-8",
483         NULL
484     };
485     static int currentEncoding = -1;
486     Eina_Bool ctrlPressed = evas_key_modifier_is_set(evas_key_modifier_get(e), "Control");
487
488     if (!strcmp(ev->key, "Escape")) {
489         closeWindow(app->ee);
490     } else if (!strcmp(ev->key, "F1")) {
491         info("Back (F1) was pressed\n");
492         if (ewk_view_back_possible(obj)) {
493             Ewk_History *history = ewk_view_history_get(obj);
494             Eina_List *list = ewk_history_back_list_get(history);
495             print_history(list);
496             ewk_history_item_list_free(list);
497             ewk_view_back(obj);
498         } else
499             info("Back ignored: No back history\n");
500     } else if (!strcmp(ev->key, "F2")) {
501         info("Forward (F2) was pressed\n");
502         if (ewk_view_forward_possible(obj)) {
503             Ewk_History *history = ewk_view_history_get(obj);
504             Eina_List *list = ewk_history_forward_list_get(history);
505             print_history(list);
506             ewk_history_item_list_free(list);
507             ewk_view_forward(obj);
508         } else
509             info("Forward ignored: No forward history\n");
510     } else if (!strcmp(ev->key, "F3")) {
511         currentEncoding++;
512         currentEncoding %= (sizeof(encodings) / sizeof(encodings[0]));
513         info("Set encoding (F3) pressed. New encoding to %s", encodings[currentEncoding]);
514         ewk_view_setting_encoding_custom_set(obj, encodings[currentEncoding]);
515     } else if (!strcmp(ev->key, "F4")) {
516         Evas_Object *frame = ewk_view_frame_main_get(obj);
517         Evas_Coord x, y;
518         Ewk_Hit_Test *ht;
519
520         evas_pointer_canvas_xy_get(evas_object_evas_get(obj), &x, &y);
521         ht = ewk_frame_hit_test_new(frame, x, y);
522         if (!ht)
523             printf("No hit test returned for point %d,%d\n", x, y);
524         else {
525             printf("Hit test for point %d,%d\n"
526                    "  pos=%3d,%3d\n"
527                    "  bounding_box=%d,%d + %dx%d\n"
528                    "  title='%s'\n"
529                    "  alternate_text='%s'\n"
530                    "  frame=%p (%s)\n"
531                    "  link {\n"
532                    "    text='%s'\n"
533                    "    url='%s'\n"
534                    "    title='%s'\n"
535                    "    target frame=%p (%s)\n"
536                    "  }\n"
537                    "context:\n"
538                    "%s"
539                    "%s"
540                    "%s"
541                    "%s"
542                    "%s\n",
543                    x, y,
544                    ht->x, ht->y,
545                    ht->bounding_box.x, ht->bounding_box.y, ht->bounding_box.w, ht->bounding_box.h,
546                    ht->title.string,
547                    ht->alternate_text,
548                    ht->frame, evas_object_name_get(ht->frame),
549                    ht->link.text,
550                    ht->link.url,
551                    ht->link.title,
552                    ht->link.target_frame, evas_object_name_get(ht->link.target_frame),
553                    ht->context & EWK_HIT_TEST_RESULT_CONTEXT_LINK ? "  LINK\n" : "",
554                    ht->context & EWK_HIT_TEST_RESULT_CONTEXT_IMAGE ? "  IMAGE\n" : "",
555                    ht->context & EWK_HIT_TEST_RESULT_CONTEXT_MEDIA ? "   MEDIA\n" : "",
556                    ht->context & EWK_HIT_TEST_RESULT_CONTEXT_SELECTION ? "  SELECTION\n" : "",
557                    ht->context & EWK_HIT_TEST_RESULT_CONTEXT_EDITABLE ? "  EDITABLE" : "");
558             ewk_frame_hit_test_free(ht);
559         }
560
561     } else if (!strcmp(ev->key, "F5")) {
562         info("Reload (F5) was pressed, reloading.\n");
563         ewk_view_reload(obj);
564     } else if (!strcmp(ev->key, "F6")) {
565         info("Stop (F6) was pressed, stop loading.\n");
566         ewk_view_stop(obj);
567     } else if (!strcmp(ev->key, "F12")) {
568         Eina_Bool status = ewk_view_setting_spatial_navigation_get(obj);
569         ewk_view_setting_spatial_navigation_set(obj, !status);
570         info("Command::keyboard navigation toggle\n");
571     } else if (!strcmp(ev->key, "F7")) {
572         info("Zoom out (F7) was pressed.\n");
573         if (currentZoomLevel > MIN_ZOOM_LEVEL && zoom_level_set(obj, currentZoomLevel - 1))
574             currentZoomLevel--;
575     } else if (!strcmp(ev->key, "F8")) {
576         info("Zoom in (F8) was pressed.\n");
577         if (currentZoomLevel < MAX_ZOOM_LEVEL && zoom_level_set(obj, currentZoomLevel + 1))
578             currentZoomLevel++;
579     } else if (!strcmp(ev->key, "F9")) {
580         info("Create new window (F9) was pressed.\n");
581         browserCreate("http://www.google.com", app->userArgs);
582     } else if (!strcmp(ev->key, "g") && ctrlPressed ) {
583         Evas_Coord x, y, w, h;
584         Evas_Object *frame = ewk_view_frame_main_get(obj);
585         float zoom = zoomLevels[currentZoomLevel] / 100.0;
586
587         ewk_frame_visible_content_geometry_get(frame, EINA_FALSE, &x, &y, &w, &h);
588         x -= w;
589         y -= h;
590         w *= 4;
591         h *= 4;
592         info("Pre-render %d,%d + %dx%d\n", x, y, w, h);
593         ewk_view_pre_render_region(obj, x, y, w, h, zoom);
594     } else if (!strcmp(ev->key, "r") && ctrlPressed) {
595         info("Pre-render 1 extra column/row with current zoom");
596         ewk_view_pre_render_relative_radius(obj, 1);
597     } else if (!strcmp(ev->key, "p") && ctrlPressed) {
598         info("Pre-rendering start");
599         ewk_view_pre_render_start(obj);
600     } else if (!strcmp(ev->key, "d") && ctrlPressed) {
601         info("Render suspended");
602         ewk_view_disable_render(obj);
603     } else if (!strcmp(ev->key, "e") && ctrlPressed) {
604         info("Render resumed");
605         ewk_view_enable_render(obj);
606     } else if (!strcmp(ev->key, "s") && ctrlPressed) {
607         Evas_Object *frame = ewk_view_frame_main_get(obj);
608         Ewk_Security_Origin *origin = ewk_frame_security_origin_get(frame);
609         printf("Security origin information:\n"
610                "  protocol=%s\n"
611                "  host=%s\n"
612                "  port=%d\n"
613                "  web database quota=%" PRIu64 "\n",
614                ewk_security_origin_protocol_get(origin),
615                ewk_security_origin_host_get(origin),
616                ewk_security_origin_port_get(origin),
617                ewk_security_origin_web_database_quota_get(origin));
618
619         Eina_List *databaseList = ewk_security_origin_web_database_get_all(origin);
620         Eina_List *listIterator = 0;
621         Ewk_Web_Database *database;
622         EINA_LIST_FOREACH(databaseList, listIterator, database)
623             printf("Database information:\n"
624                    "  name=%s\n"
625                    "  display name=%s\n"
626                    "  filename=%s\n"
627                    "  expected size=%" PRIu64 "\n"
628                    "  size=%" PRIu64 "\n",
629                    ewk_web_database_name_get(database),
630                    ewk_web_database_display_name_get(database),
631                    ewk_web_database_filename_get(database),
632                    ewk_web_database_expected_size_get(database),
633                    ewk_web_database_size_get(database));
634
635         ewk_security_origin_free(origin);
636         ewk_web_database_list_free(databaseList);
637     } else if (!strcmp(ev->key, "i") && ctrlPressed) {
638         Evas_Object *inspector_view = ewk_view_web_inspector_view_get(obj);
639         if (inspector_view) {
640             info("Web Inspector close\n");
641             ewk_view_web_inspector_close(obj);
642         } else {
643             info("Web Inspector show\n");
644             ewk_view_web_inspector_show(obj);
645         }
646     }
647 }
648
649 static void
650 on_browser_del(void *data, Evas *evas, Evas_Object *browser, void *event)
651 {
652     ELauncher *app = (ELauncher*) data;
653
654     evas_object_event_callback_del(app->browser, EVAS_CALLBACK_KEY_DOWN, on_key_down);
655     evas_object_event_callback_del(app->browser, EVAS_CALLBACK_MOUSE_DOWN, on_mouse_down);
656     evas_object_event_callback_del(app->browser, EVAS_CALLBACK_FOCUS_IN, on_focus_in);
657     evas_object_event_callback_del(app->browser, EVAS_CALLBACK_FOCUS_OUT, on_focus_out);
658     evas_object_event_callback_del(app->browser, EVAS_CALLBACK_DEL, on_browser_del);
659 }
660
661 static void
662 on_web_inspector_view_create(void *user_data, Evas_Object *webview, void *event_info)
663 {
664     ELauncher *app_browser = (ELauncher *)user_data;
665
666     webInspectorCreate(app_browser);
667 }
668
669 static void
670 on_web_inspector_view_close(void *user_data, Evas_Object *webview, void *event_info)
671 {
672     Eina_List *l;
673     void *app;
674     ELauncher *app_browser = (ELauncher *)user_data;
675     Evas_Object *inspector_view = (Evas_Object *)event_info;
676
677     ewk_view_web_inspector_view_set(app_browser->browser, NULL);
678
679     EINA_LIST_FOREACH(windows, l, app)
680         if (((ELauncher *)app)->browser == inspector_view)
681             break;
682
683     windows = eina_list_remove(windows, app);
684     windowDestroy(((ELauncher *)app)->ee);
685     free(app);
686 }
687
688 static void
689 on_web_inspector_view_destroyed(Ecore_Evas *ee)
690 {
691     ELauncher *app;
692
693     app = find_app_from_ee(ee);
694     evas_object_smart_callback_call(app->browser, "inspector,view,destroy", NULL);
695 }
696
697 static int
698 quit(Eina_Bool success, const char *msg)
699 {
700     edje_shutdown();
701     ecore_evas_shutdown();
702     ecore_file_shutdown();
703
704     if (msg)
705         fputs(msg, (success) ? stdout : stderr);
706
707     if (themePath) {
708         free(themePath);
709         themePath = NULL;
710     }
711
712     if (!success)
713         return EXIT_FAILURE;
714
715     return EXIT_SUCCESS;
716 }
717
718 static int
719 browserCreate(const char *url, User_Arguments *userArgs)
720 {
721     ELauncher *appBrowser = windowCreate(userArgs);
722     if (!appBrowser)
723         return quit(EINA_FALSE, "ERROR: could not create a browser window\n");
724
725     ecore_evas_title_set(appBrowser->ee, "EFL Test Launcher");
726     ecore_evas_callback_resize_set(appBrowser->ee, on_browser_ecore_evas_resize);
727     ecore_evas_callback_delete_request_set(appBrowser->ee, closeWindow);
728
729     evas_object_name_set(appBrowser->browser, "browser");
730
731     evas_object_smart_callback_add(appBrowser->browser, "inputmethod,changed", on_inputmethod_changed, appBrowser);
732     evas_object_smart_callback_add(appBrowser->browser, "inspector,view,close", on_web_inspector_view_close, appBrowser);
733     evas_object_smart_callback_add(appBrowser->browser, "inspector,view,create", on_web_inspector_view_create, appBrowser);
734     evas_object_smart_callback_add(appBrowser->browser, "load,error", on_load_error, appBrowser);
735     evas_object_smart_callback_add(appBrowser->browser, "load,finished", on_load_finished, appBrowser);
736     evas_object_smart_callback_add(appBrowser->browser, "load,progress", on_progress, appBrowser);
737     evas_object_smart_callback_add(appBrowser->browser, "menubar,visible,get", on_menubar_visible_get, appBrowser);
738     evas_object_smart_callback_add(appBrowser->browser, "menubar,visible,set", on_menubar_visible_set, appBrowser);
739     evas_object_smart_callback_add(appBrowser->browser, "scrollbars,visible,get", on_scrollbars_visible_get, appBrowser);
740     evas_object_smart_callback_add(appBrowser->browser, "scrollbars,visible,set", on_scrollbars_visible_set, appBrowser);
741     evas_object_smart_callback_add(appBrowser->browser, "statusbar,visible,get", on_statusbar_visible_get, appBrowser);
742     evas_object_smart_callback_add(appBrowser->browser, "statusbar,visible,set", on_statusbar_visible_set, appBrowser);
743     evas_object_smart_callback_add(appBrowser->browser, "title,changed", on_title_changed, appBrowser);
744     evas_object_smart_callback_add(appBrowser->browser, "toolbars,visible,get", on_toolbars_visible_get, appBrowser);
745     evas_object_smart_callback_add(appBrowser->browser, "toolbars,visible,set", on_toolbars_visible_set, appBrowser);
746     evas_object_smart_callback_add(appBrowser->browser, "tooltip,text,set", on_tooltip_text_set, appBrowser);
747     evas_object_smart_callback_add(appBrowser->browser, "uri,changed", on_url_changed, appBrowser);
748
749     evas_object_event_callback_add(appBrowser->browser, EVAS_CALLBACK_DEL, on_browser_del, appBrowser);
750     evas_object_event_callback_add(appBrowser->browser, EVAS_CALLBACK_FOCUS_IN, on_focus_in, appBrowser);
751     evas_object_event_callback_add(appBrowser->browser, EVAS_CALLBACK_FOCUS_OUT, on_focus_out, appBrowser);
752     evas_object_event_callback_add(appBrowser->browser, EVAS_CALLBACK_KEY_DOWN, on_key_down, appBrowser);
753     evas_object_event_callback_add(appBrowser->browser, EVAS_CALLBACK_MOUSE_DOWN, on_mouse_down, appBrowser);
754
755     ewk_view_setting_enable_developer_extras_set(appBrowser->browser, EINA_TRUE);
756
757     appBrowser->url_bar = url_bar_add(appBrowser->browser, DEFAULT_WIDTH);
758
759     evas_object_move(appBrowser->browser, 0, URL_BAR_HEIGHT);
760     evas_object_resize(appBrowser->browser, userArgs->geometry.w, userArgs->geometry.h - URL_BAR_HEIGHT);
761
762     ewk_view_uri_set(appBrowser->browser, url);
763
764     evas_object_show(appBrowser->browser);
765     ecore_evas_show(appBrowser->ee);
766
767     evas_object_focus_set(appBrowser->browser, EINA_TRUE);
768
769     return 1;
770 }
771
772 static int
773 webInspectorCreate(ELauncher *appBrowser)
774 {
775     ELauncher *appInspector = windowCreate(appBrowser->userArgs);
776     if (!appInspector)
777         return quit(EINA_FALSE, "ERROR: could not create an inspector window\n");
778
779     ecore_evas_title_set(appInspector->ee, "Web Inspector");
780     ecore_evas_callback_resize_set(appInspector->ee, on_web_inspector_ecore_evas_resize);
781     ecore_evas_callback_delete_request_set(appInspector->ee, on_web_inspector_view_destroyed);
782
783     evas_object_name_set(appInspector->browser, "inspector");
784
785     evas_object_move(appInspector->browser, 0, 0);
786     evas_object_resize(appInspector->browser, appInspector->userArgs->geometry.w, appInspector->userArgs->geometry.h);
787
788     evas_object_show(appInspector->browser);
789     ecore_evas_show(appInspector->ee);
790
791     evas_object_focus_set(appInspector->browser, EINA_TRUE);
792
793     ewk_view_web_inspector_view_set(appBrowser->browser, appInspector->browser);
794
795     return 1;
796 }
797
798 static ELauncher *
799 windowCreate(User_Arguments *userArgs)
800 {
801     ELauncher *app = (ELauncher *)malloc(sizeof(ELauncher));
802     if (!app) {
803         quit(EINA_FALSE, "ERROR: could not create an ELauncher\n");
804         return NULL;
805     }
806
807     app->ee = ecore_evas_new(userArgs->engine, 0, 0, userArgs->geometry.w, userArgs->geometry.h, NULL);
808     if (!app->ee) {
809         quit(EINA_FALSE, "ERROR: could not construct evas-ecore\n");
810         return NULL;
811     }
812
813     if (userArgs->isFullscreen)
814         ecore_evas_fullscreen_set(app->ee, EINA_TRUE);
815
816     app->evas = ecore_evas_get(app->ee);
817     if (!app->evas) {
818         quit(EINA_FALSE, "ERROR: could not get evas from evas-ecore\n");
819         return NULL;
820     }
821
822     if (userArgs->backingStore && !strcasecmp(userArgs->backingStore, "tiled")) {
823         app->browser = ewk_view_tiled_add(app->evas);
824         info("backing store: tiled\n");
825     } else {
826         app->browser = ewk_view_single_add(app->evas);
827         info("backing store: single\n");
828     }
829
830     ewk_view_theme_set(app->browser, themePath);
831     if (userArgs->userAgent)
832         ewk_view_setting_user_agent_set(app->browser, userArgs->userAgent);
833
834     ewk_view_setting_local_storage_database_path_set(app->browser, userArgs->databasePath);
835     ewk_view_setting_enable_frame_flattening_set(app->browser, userArgs->isFlattening);
836
837     app->userArgs = userArgs;
838     app->url_bar = NULL;
839
840     windows = eina_list_append(windows, app);
841
842     return app;
843 }
844
845 static void
846 windowDestroy(Ecore_Evas *ee)
847 {
848     ecore_evas_free(ee);
849     if (!eina_list_count(windows))
850         ecore_main_loop_quit();
851 }
852
853 static void
854 closeWindow(Ecore_Evas *ee)
855 {
856     ELauncher *app;
857
858     app = find_app_from_ee(ee);
859     ewk_view_web_inspector_close(app->browser);
860
861     windows = eina_list_remove(windows, app);
862     url_bar_del(app->url_bar);
863     windowDestroy(ee);
864     free(app);
865 }
866
867 static Eina_Bool
868 main_signal_exit(void *data, int ev_type, void *ev)
869 {
870     ELauncher *app;
871     while (windows) {
872         app = (ELauncher*) eina_list_data_get(windows);
873         ewk_view_web_inspector_close(app->browser);
874
875         ecore_evas_free(app->ee);
876         windows = eina_list_remove(windows, app);
877     }
878     if (!eina_list_count(windows))
879         ecore_main_loop_quit();
880     return EINA_TRUE;
881 }
882
883 static char *
884 findThemePath(const char *theme)
885 {
886     const char *default_theme = THEME_DIR"/default.edj";
887     char *rpath;
888     struct stat st;
889
890     if (!theme)
891         theme = default_theme;
892
893     rpath = ecore_file_realpath(theme);
894
895     if (!strlen(rpath) || stat(rpath, &st)) {
896         free(rpath);
897         return NULL;
898     }
899
900     return rpath;
901 }
902
903 int
904 parseUserArguments(int argc, char *argv[], User_Arguments *userArgs)
905 {
906     int args;
907
908     userArgs->engine = NULL;
909     userArgs->quitOption = EINA_FALSE;
910     userArgs->backingStore = (char *)backingStores[1];
911     userArgs->isFlattening = EINA_FALSE;
912     userArgs->isFullscreen = EINA_FALSE;
913     userArgs->geometry.x = 0;
914     userArgs->geometry.y = 0;
915     userArgs->geometry.w = 0;
916     userArgs->geometry.h = 0;
917     userArgs->theme = NULL;
918     userArgs->userAgent = NULL;
919
920     Ecore_Getopt_Value values[] = {
921         ECORE_GETOPT_VALUE_STR(userArgs->engine),
922         ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
923         ECORE_GETOPT_VALUE_STR(userArgs->backingStore),
924         ECORE_GETOPT_VALUE_BOOL(userArgs->isFlattening),
925         ECORE_GETOPT_VALUE_BOOL(userArgs->isFullscreen),
926         ECORE_GETOPT_VALUE_PTR_CAST(userArgs->geometry),
927         ECORE_GETOPT_VALUE_STR(userArgs->theme),
928         ECORE_GETOPT_VALUE_STR(userArgs->userAgent),
929         ECORE_GETOPT_VALUE_INT(verbose),
930         ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
931         ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
932         ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
933         ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
934         ECORE_GETOPT_VALUE_NONE
935     };
936
937     ecore_app_args_set(argc, (const char**) argv);
938     args = ecore_getopt_parse(&options, values, argc, argv);
939
940     themePath = findThemePath(userArgs->theme);
941
942     if ((userArgs->geometry.w <= 0) || (userArgs->geometry.h <= 0)) {
943         userArgs->geometry.w = DEFAULT_WIDTH;
944         userArgs->geometry.h = DEFAULT_HEIGHT;
945     }
946
947     return args;
948 }
949
950 int
951 main(int argc, char *argv[])
952 {
953     const char *default_url = "http://www.google.com/";
954     const char *tmp;
955     const char *proxyUri;
956     char path[PATH_MAX];
957     int args;
958
959     User_Arguments userArgs;
960
961     if (!ecore_evas_init())
962         return EXIT_FAILURE;
963
964     if (!edje_init()) {
965         ecore_evas_shutdown();
966         return EXIT_FAILURE;
967     }
968
969     if (!ecore_file_init()) {
970         edje_shutdown();
971         ecore_evas_shutdown();
972         return EXIT_FAILURE;
973     }
974
975     args = parseUserArguments(argc, argv, &userArgs);
976     if (args < 0)
977        return quit(EINA_FALSE, "ERROR: could not parse options.\n");
978
979     if (userArgs.quitOption)
980         return quit(EINA_TRUE, NULL);
981
982     if (!themePath)
983         return quit(EINA_FALSE, "ERROR: could not find theme.\n");
984
985     ewk_init();
986     tmp = getenv("TMPDIR");
987     if (!tmp)
988         tmp = "/tmp";
989     snprintf(path, sizeof(path), "%s/.ewebkit-%u", tmp, getuid());
990     if (!ecore_file_mkpath(path))
991         return quit(EINA_FALSE, "ERROR: could not create settings database directory.\n");
992
993     userArgs.databasePath = path;
994
995     ewk_settings_icon_database_path_set(path);
996     ewk_settings_web_database_path_set(path);
997
998     proxyUri = getenv("http_proxy");
999     if (proxyUri)
1000         ewk_network_proxy_uri_set(proxyUri);
1001
1002     if (args < argc) {
1003         char *url = url_from_user_input(argv[args]);
1004         browserCreate(url, &userArgs);
1005         free(url);
1006     } else
1007         browserCreate(default_url, &userArgs);
1008
1009     ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT, main_signal_exit, &windows);
1010
1011     ecore_main_loop_begin();
1012
1013     ewk_shutdown();
1014
1015     return quit(EINA_TRUE, NULL);
1016 }