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