e4d85148423a28c702a3acad39c31d29156a9353
[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_load_error(void *user_data, Evas_Object *webview, void *event_info)
318 {
319     const Ewk_Frame_Load_Error *err = (const Ewk_Frame_Load_Error *)event_info;
320     char message[1024];
321     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>",
322              err->code, err->domain, err->description, err->failing_url);
323     ewk_frame_contents_set(err->frame, message, 0, "text/html", "UTF-8", err->failing_url);
324 }
325
326 static void
327 on_toolbars_visible_set(void* user_data, Evas_Object* webview, void* event_info)
328 {
329     Eina_Bool *visible = (Eina_Bool *)event_info;
330     if (*visible) {
331         info("Toolbars visible changed: show");
332         windowProperties.toolbarsVisible = EINA_TRUE;
333     } else {
334         info("Toolbars visible changed: hide");
335         windowProperties.toolbarsVisible = EINA_FALSE;
336     }
337 }
338
339 static void
340 on_toolbars_visible_get(void* user_data, Evas_Object* webview, void* event_info)
341 {
342     Eina_Bool *visible = (Eina_Bool *)event_info;
343     *visible = windowProperties.toolbarsVisible;
344 }
345
346 static void
347 on_statusbar_visible_set(void* user_data, Evas_Object* webview, void* event_info)
348 {
349     Eina_Bool *visible = (Eina_Bool *)event_info;
350     if (*visible) {
351         info("Statusbar visible changed: show");
352         windowProperties.statusbarVisible = EINA_TRUE;
353     } else {
354         info("Statusbar visible changed: hide");
355         windowProperties.statusbarVisible = EINA_FALSE;
356     }
357 }
358
359 static void
360 on_statusbar_visible_get(void* user_data, Evas_Object* webview, void* event_info)
361 {
362     Eina_Bool *visible = (Eina_Bool *)event_info;
363     *visible = windowProperties.statusbarVisible;
364 }
365
366 static void
367 on_scrollbars_visible_set(void* user_data, Evas_Object* webview, void* event_info)
368 {
369     Eina_Bool *visible = (Eina_Bool *)event_info;
370     if (*visible) {
371         info("Scrollbars visible changed: show");
372         windowProperties.scrollbarsVisible = EINA_TRUE;
373     } else {
374         info("Scrollbars visible changed: hide");
375         windowProperties.scrollbarsVisible = EINA_FALSE;
376     }
377 }
378
379 static void
380 on_scrollbars_visible_get(void* user_data, Evas_Object* webview, void* event_info)
381 {
382     Eina_Bool *visible = (Eina_Bool *)event_info;
383     *visible = windowProperties.scrollbarsVisible;
384 }
385
386 static void
387 on_menubar_visible_set(void* user_data, Evas_Object* webview, void* event_info)
388 {
389     Eina_Bool *visible = (Eina_Bool *)event_info;
390     if (*visible) {
391         info("Menubar visible changed: show");
392         windowProperties.menubarVisible = EINA_TRUE;
393     } else {
394         info("Menubar visible changed: hide");
395         windowProperties.menubarVisible = EINA_FALSE;
396     }
397 }
398
399 static void
400 on_menubar_visible_get(void* user_data, Evas_Object* webview, void* event_info)
401 {
402     Eina_Bool *visible = (Eina_Bool *)event_info;
403     *visible = windowProperties.menubarVisible;
404 }
405
406 static void
407 on_tooltip_text_set(void* user_data, Evas_Object* webview, void* event_info)
408 {
409     const char *text = (const char *)event_info;
410     if (text && *text != '\0')
411         info("%s\n", text);
412 }
413
414 static void
415 on_inputmethod_changed(void* user_data, Evas_Object* webview, void* event_info)
416 {
417     Eina_Bool active = (Eina_Bool)(long)event_info;
418     unsigned int imh;
419     info("Keyboard changed: %d\n", active);
420
421     if (!active)
422         return;
423
424     imh = ewk_view_imh_get(webview);
425     info("    Keyboard flags: %#.2x\n", imh);
426
427 }
428
429 /**
430  * "viewport,changed" signal will be always emitted regardless of the viewport existence.
431  *
432  * If you don't want to process the viewport tag, you can either do nothing in this callback
433  * or simply ignore the signal in your application.
434  * 
435  * More information about this can be found at http://developer.apple.com/safari/library/docum
436  * entation/appleapplications/reference/safariwebcontent/usingtheviewport/usingtheviewport.html
437  */
438 static void
439 on_viewport_changed(void* user_data, Evas_Object* webview, void* event_info)
440 {
441     ELauncher *app = (ELauncher *)user_data;
442
443     float w, h, initScale, minScale, maxScale, devicePixelRatio;
444     Eina_Bool userScalable;
445
446     ewk_view_viewport_attributes_get(webview, &w, &h, &initScale, &maxScale, &minScale, &devicePixelRatio, &userScalable);
447
448     /**
449      * If there is no argument in viewport tag, argument's value is -1.
450      */
451     if ((int)w == -1)
452         w = DEFAULT_WIDTH;
453     if ((int)h == -1)
454         h = DEFAULT_HEIGHT;
455     if ((int)initScale == -1)
456         initScale = DEFAULT_ZOOM_INIT; // There's no scale separated from zooming in webkit-efl.
457     if ((int)minScale == -1)
458         minScale = ewk_view_zoom_range_min_get(webview);
459     if ((int)maxScale == -1)
460         maxScale = ewk_view_zoom_range_max_get(webview);
461     if ((int)devicePixelRatio == -1)
462         devicePixelRatio = ewk_view_device_pixel_ratio_get(webview);
463     if ((int)userScalable == -1)
464         userScalable = EINA_TRUE;
465
466     app->viewport.w = (int)w;
467     app->viewport.h = (int)h;
468     app->viewport.initScale = initScale;
469     app->viewport.minScale = minScale;
470     app->viewport.maxScale = maxScale;
471     app->viewport.devicePixelRatio = devicePixelRatio;
472     app->viewport.userScalable = userScalable;
473     viewport_set();
474 }
475
476 static void
477 on_mouse_down(void* data, Evas* e, Evas_Object* webview, void* event_info)
478 {
479     Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down*) event_info;
480     if (ev->button == 2)
481         evas_object_focus_set(webview, !evas_object_focus_get(webview));
482 }
483
484 static void
485 on_focus_out(void *data, Evas *e, Evas_Object *obj, void *event_info)
486 {
487     info("the webview lost keyboard focus\n");
488 }
489
490 static void
491 on_focus_in(void *data, Evas *e, Evas_Object *obj, void *event_info)
492 {
493     info("the webview gained keyboard focus\n");
494 }
495
496 static void
497 on_key_down(void *data, Evas *e, Evas_Object *obj, void *event_info)
498 {
499     Evas_Event_Key_Down *ev = (Evas_Event_Key_Down*) event_info;
500     ELauncher *app = data;
501     static const char *encodings[] = {
502         "ISO-8859-1",
503         "UTF-8",
504         NULL
505     };
506     static int currentEncoding = -1;
507
508     if (!strcmp(ev->key, "Escape")) {
509         closeWindow(app->ee);
510     } else if (!strcmp(ev->key, "F1")) {
511         info("Back (F1) was pressed\n");
512         if (ewk_view_back_possible(obj)) {
513             Ewk_History *history = ewk_view_history_get(obj);
514             Eina_List *list = ewk_history_back_list_get(history);
515             print_history(list);
516             ewk_history_item_list_free(list);
517             ewk_view_back(obj);
518         } else
519             info("Back ignored: No back history\n");
520     } else if (!strcmp(ev->key, "F2")) {
521         info("Forward (F2) was pressed\n");
522         if (ewk_view_forward_possible(obj)) {
523             Ewk_History *history = ewk_view_history_get(obj);
524             Eina_List *list = ewk_history_forward_list_get(history);
525             print_history(list);
526             ewk_history_item_list_free(list);
527             ewk_view_forward(obj);
528         } else
529             info("Forward ignored: No forward history\n");
530     } else if (!strcmp(ev->key, "F3")) {
531         currentEncoding++;
532         currentEncoding %= (sizeof(encodings) / sizeof(encodings[0]));
533         info("Set encoding (F3) pressed. New encoding to %s", encodings[currentEncoding]);
534         ewk_view_setting_encoding_custom_set(obj, encodings[currentEncoding]);
535     } else if (!strcmp(ev->key, "F4")) {
536         Evas_Object *frame = ewk_view_frame_main_get(obj);
537         Evas_Coord x, y;
538         Ewk_Hit_Test *ht;
539
540         evas_pointer_canvas_xy_get(evas_object_evas_get(obj), &x, &y);
541         ht = ewk_frame_hit_test_new(frame, x, y);
542         if (!ht)
543             printf("No hit test returned for point %d,%d\n", x, y);
544         else {
545             printf("Hit test for point %d,%d\n"
546                    "  pos=%3d,%3d\n"
547                    "  bounding_box=%d,%d + %dx%d\n"
548                    "  title='%s'\n"
549                    "  alternate_text='%s'\n"
550                    "  frame=%p (%s)\n"
551                    "  link {\n"
552                    "    text='%s'\n"
553                    "    url='%s'\n"
554                    "    title='%s'\n"
555                    "    target frame=%p (%s)\n"
556                    "  }\n"
557                    "  flags {\n"
558                    "    editable=%hhu\n"
559                    "    selected=%hhu\n"
560                    "  }\n",
561                    x, y,
562                    ht->x, ht->y,
563                    ht->bounding_box.x, ht->bounding_box.y, ht->bounding_box.w, ht->bounding_box.h,
564                    ht->title,
565                    ht->alternate_text,
566                    ht->frame, evas_object_name_get(ht->frame),
567                    ht->link.text,
568                    ht->link.url,
569                    ht->link.title,
570                    ht->link.target_frame, evas_object_name_get(ht->link.target_frame),
571                    ht->flags.editable,
572                    ht->flags.selected);
573             ewk_frame_hit_test_free(ht);
574         }
575
576     } else if (!strcmp(ev->key, "F5")) {
577         info("Reload (F5) was pressed, reloading.\n");
578         ewk_view_reload(obj);
579     } else if (!strcmp(ev->key, "F6")) {
580         info("Stop (F6) was pressed, stop loading.\n");
581         ewk_view_stop(obj);
582     } else if (!strcmp(ev->key, "F12")) {
583         Eina_Bool status = ewk_view_setting_spatial_navigation_get(obj);
584         ewk_view_setting_spatial_navigation_set(obj, !status);
585         info("Command::keyboard navigation toggle\n");
586     } else if (!strcmp(ev->key, "F7")) {
587         info("Zoom out (F7) was pressed.\n");
588         if (currentZoomLevel > MIN_ZOOM_LEVEL && zoom_level_set(obj, currentZoomLevel - 1))
589             currentZoomLevel--;
590     } else if (!strcmp(ev->key, "F8")) {
591         info("Zoom in (F8) was pressed.\n");
592         if (currentZoomLevel < MAX_ZOOM_LEVEL && zoom_level_set(obj, currentZoomLevel + 1))
593             currentZoomLevel++;
594     } else if (!strcmp(ev->key, "F9")) {
595         info("Create new window (F9) was pressed.\n");
596         Eina_Rectangle geometry = {0, 0, 0, 0};
597         browserCreate("http://www.google.com",
598                        app->theme, app->userAgent, geometry, app-> backingStore,
599                        NULL, app->isFlattening, 0, NULL);
600     } else if (!strcmp(ev->key, "F10")) {
601         Evas_Coord x, y, w, h;
602         Evas_Object *frame = ewk_view_frame_main_get(obj);
603         float zoom = zoomLevels[currentZoomLevel] / 100.0;
604
605         ewk_frame_visible_content_geometry_get(frame, EINA_FALSE, &x, &y, &w, &h);
606         x -= w;
607         y -= h;
608         w *= 4;
609         h *= 4;
610         info("Pre-render %d,%d + %dx%d\n", x, y, w, h);
611         ewk_view_pre_render_region(obj, x, y, w, h, zoom);
612     } else if (!strcmp(ev->key, "F11")) {
613         info("Pre-render 1 extra column/row with current zoom");
614         ewk_view_pre_render_relative_radius(obj, 1);
615     } else if (!strcmp(ev->key, "d")) {
616         info("Render suspended");
617         ewk_view_disable_render(obj);
618     } else if (!strcmp(ev->key, "e")) {
619         info("Render resumed");
620         ewk_view_enable_render(obj);
621     }
622 }
623
624 static void
625 on_browser_del(void *data, Evas *evas, Evas_Object *browser, void *event)
626 {
627     ELauncher *app = (ELauncher*) data;
628
629     evas_object_event_callback_del(app->browser, EVAS_CALLBACK_KEY_DOWN, on_key_down);
630     evas_object_event_callback_del(app->browser, EVAS_CALLBACK_MOUSE_DOWN, on_mouse_down);
631     evas_object_event_callback_del(app->browser, EVAS_CALLBACK_FOCUS_IN, on_focus_in);
632     evas_object_event_callback_del(app->browser, EVAS_CALLBACK_FOCUS_OUT, on_focus_out);
633     evas_object_event_callback_del(app->browser, EVAS_CALLBACK_DEL, on_browser_del);
634 }
635
636 static void
637 on_closeWindow(Ecore_Evas *ee)
638 {
639     browserDestroy(ee);
640 }
641
642 static int
643 quit(Eina_Bool success, const char *msg)
644 {
645     edje_shutdown();
646     ecore_evas_shutdown();
647     ecore_file_shutdown();
648
649     if (msg)
650         fputs(msg, (success) ? stdout : stderr);
651
652     if (themePath) {
653         free(themePath);
654         themePath = NULL;
655     }
656
657     if (!success)
658         return EXIT_FAILURE;
659
660     return EXIT_SUCCESS;
661 }
662
663 static int
664 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)
665 {
666     if ((geometry.w <= 0) && (geometry.h <= 0)) {
667         geometry.w = DEFAULT_WIDTH;
668         geometry.h = DEFAULT_HEIGHT;
669     }
670
671     ELauncher *app = (ELauncher*) malloc(sizeof(ELauncher));
672     if (!app)
673         return quit(EINA_FALSE, "ERROR: could not create EWebLauncher window\n");
674
675     app->ee = ecore_evas_new(engine, 0, 0, geometry.w, geometry.h, NULL);
676
677     if (!app->ee)
678         return quit(EINA_FALSE, "ERROR: could not construct evas-ecore\n");
679
680     if (isFullscreen)
681         ecore_evas_fullscreen_set(app->ee, EINA_TRUE);
682
683     ecore_evas_title_set(app->ee, "EFL Test Launcher");
684     ecore_evas_callback_resize_set(app->ee, on_ecore_evas_resize);
685     ecore_evas_callback_delete_request_set(app->ee, closeWindow);
686
687     app->evas = ecore_evas_get(app->ee);
688
689     if (!app->evas)
690         return quit(EINA_FALSE, "ERROR: could not get evas from evas-ecore\n");
691
692     app->theme = theme;
693     app->userAgent = userAgent;
694     app->backingStore = backingStore;
695     app->isFlattening = isFlattening;
696
697     app->bg = evas_object_rectangle_add(app->evas);
698     evas_object_name_set(app->bg, "bg");
699     evas_object_color_set(app->bg, 255, 0, 255, 255);
700     evas_object_move(app->bg, 0, 0);
701     evas_object_resize(app->bg, geometry.w, geometry.h);
702     evas_object_layer_set(app->bg, EVAS_LAYER_MIN);
703     evas_object_show(app->bg);
704
705     if (backingStore && !strcasecmp(backingStore, "tiled")) {
706         app->browser = ewk_view_tiled_add(app->evas);
707         info("backing store: tiled\n");
708     } else {
709         app->browser = ewk_view_single_add(app->evas);
710         info("backing store: single\n");
711     }
712
713     ewk_view_theme_set(app->browser, theme);
714     if (userAgent)
715         ewk_view_setting_user_agent_set(app->browser, userAgent);
716     ewk_view_setting_local_storage_database_path_set(app->browser, databasePath);
717     ewk_view_setting_enable_frame_flattening_set(app->browser, isFlattening);
718     
719     evas_object_name_set(app->browser, "browser");
720
721     evas_object_smart_callback_add(app->browser, "title,changed", on_title_changed, app);
722     evas_object_smart_callback_add(app->browser, "load,progress", on_progress, app);
723     evas_object_smart_callback_add(app->browser, "load,finished", on_load_finished, app);
724     evas_object_smart_callback_add(app->browser, "load,error", on_load_error, app);
725     evas_object_smart_callback_add(app->browser, "viewport,changed", on_viewport_changed, app);
726
727     evas_object_smart_callback_add(app->browser, "toolbars,visible,set", on_toolbars_visible_set, app);
728     evas_object_smart_callback_add(app->browser, "toolbars,visible,get", on_toolbars_visible_get, app);
729     evas_object_smart_callback_add(app->browser, "statusbar,visible,set", on_statusbar_visible_set, app);
730     evas_object_smart_callback_add(app->browser, "statusbar,visible,get", on_statusbar_visible_get, app);
731     evas_object_smart_callback_add(app->browser, "scrollbars,visible,set", on_scrollbars_visible_set, app);
732     evas_object_smart_callback_add(app->browser, "scrollbars,visible,get", on_scrollbars_visible_get, app);
733     evas_object_smart_callback_add(app->browser, "menubar,visible,set", on_menubar_visible_set, app);
734     evas_object_smart_callback_add(app->browser, "menubar,visible,get", on_menubar_visible_get, app);
735     evas_object_smart_callback_add(app->browser, "tooltip,text,set", on_tooltip_text_set, app);
736     evas_object_smart_callback_add(app->browser, "inputmethod,changed", on_inputmethod_changed, app);
737
738 /*     ewk_callback_resize_requested_add(app->browser, on_resize_requested, app->ee); */
739
740     evas_object_event_callback_add(app->browser, EVAS_CALLBACK_KEY_DOWN, on_key_down, app);
741     evas_object_event_callback_add(app->browser, EVAS_CALLBACK_MOUSE_DOWN, on_mouse_down, app);
742     evas_object_event_callback_add(app->browser, EVAS_CALLBACK_FOCUS_IN, on_focus_in, app);
743     evas_object_event_callback_add(app->browser, EVAS_CALLBACK_FOCUS_OUT, on_focus_out, app);
744     evas_object_event_callback_add(app->browser, EVAS_CALLBACK_DEL, on_browser_del, app);
745
746     evas_object_move(app->browser, 10, 10);
747     evas_object_resize(app->browser, geometry.w - 20, geometry.h - 20);
748
749     if (url && (url[0] != '\0'))
750         ewk_view_uri_set(app->browser, url);
751
752     evas_object_show(app->browser);
753     ecore_evas_show(app->ee);
754
755     evas_object_focus_set(app->browser, EINA_TRUE);
756
757     windows = eina_list_append(windows, app);
758
759     return 1;
760 }
761
762 static void
763 browserDestroy(Ecore_Evas *ee)
764 {
765     ecore_evas_free(ee);
766     if (!eina_list_count(windows))
767         ecore_main_loop_quit();
768 }
769
770 static void
771 closeWindow(Ecore_Evas *ee)
772 {
773     Eina_List *l;
774     void *app;
775     EINA_LIST_FOREACH(windows, l, app)
776     {
777         if (((ELauncher*) app)->ee == ee)
778             break;
779     }
780     windows = eina_list_remove(windows, app);
781     browserDestroy(ee);
782     free(app);
783 }
784
785 static Eina_Bool
786 main_signal_exit(void *data, int ev_type, void *ev)
787 {
788     ELauncher *app;
789     while (windows) {
790         app = (ELauncher*) eina_list_data_get(windows);
791         ecore_evas_free(app->ee);
792         windows = eina_list_remove(windows, app);
793     }
794     if (!eina_list_count(windows))
795         ecore_main_loop_quit();
796     return EINA_TRUE;
797 }
798
799 static char *
800 findThemePath(const char *theme)
801 {
802     const char *defaultTheme = DATA_DIR"/default.edj";
803     char *rpath;
804     struct stat st;
805
806     if (!theme)
807         theme = defaultTheme;
808
809     rpath = ecore_file_realpath(theme);
810     if (!strlen(rpath) || stat(rpath, &st)) {
811         free(rpath);
812         return NULL;
813     }
814
815     return rpath;
816 }
817
818 int
819 main(int argc, char *argv[])
820 {
821     const char *default_url = "http://www.google.com/";
822
823     Eina_Rectangle geometry = {0, 0, 0, 0};
824     char *url = NULL;
825     char *userAgent = NULL;
826     const char *tmp;
827     const char *proxyUri;
828     char path[PATH_MAX];
829
830     char *engine = NULL;
831     char *theme = NULL;
832     char *backingStore = (char *)backingStores[1];
833
834     unsigned char quitOption = 0;
835     unsigned char isFlattening = 0;
836     unsigned char isFullscreen = 0;
837     int args;
838
839     Ecore_Getopt_Value values[] = {
840         ECORE_GETOPT_VALUE_STR(engine),
841         ECORE_GETOPT_VALUE_BOOL(quitOption),
842         ECORE_GETOPT_VALUE_STR(backingStore),
843         ECORE_GETOPT_VALUE_BOOL(isFlattening),
844         ECORE_GETOPT_VALUE_BOOL(isFullscreen),
845         ECORE_GETOPT_VALUE_PTR_CAST(geometry),
846         ECORE_GETOPT_VALUE_STR(theme),
847         ECORE_GETOPT_VALUE_STR(userAgent),
848         ECORE_GETOPT_VALUE_INT(verbose),
849         ECORE_GETOPT_VALUE_BOOL(quitOption),
850         ECORE_GETOPT_VALUE_BOOL(quitOption),
851         ECORE_GETOPT_VALUE_BOOL(quitOption),
852         ECORE_GETOPT_VALUE_BOOL(quitOption),
853         ECORE_GETOPT_VALUE_NONE
854     };
855
856     if (!ecore_evas_init())
857         return EXIT_FAILURE;
858
859     if (!edje_init()) {
860         ecore_evas_shutdown();
861         return EXIT_FAILURE;
862     }
863
864     if (!ecore_file_init()) {
865         edje_shutdown();
866         ecore_evas_shutdown();
867         return EXIT_FAILURE;
868     }
869
870     ecore_app_args_set(argc, (const char**) argv);
871     args = ecore_getopt_parse(&options, values, argc, argv);
872
873     if (args < 0)
874        return quit(EINA_FALSE, "ERROR: could not parse options.\n");
875
876     if (quitOption)
877         return quit(EINA_TRUE, NULL);
878
879     if (args < argc)
880         url = argv[args];
881     else
882         url = (char*) default_url;
883
884     themePath = findThemePath(theme);
885     if (!themePath)
886         return quit(EINA_FALSE, "ERROR: could not find theme.\n");
887
888     ewk_init();
889     tmp = getenv("TMPDIR");
890     if (!tmp)
891         tmp = "/tmp";
892     snprintf(path, sizeof(path), "%s/.ewebkit-%u", tmp, getuid());
893     if (!ecore_file_mkpath(path))
894         return quit(EINA_FALSE, "ERROR: could not create settings database directory.\n");
895
896     ewk_settings_icon_database_path_set(path);
897     ewk_settings_web_database_path_set(path);
898
899     proxyUri = getenv("http_proxy");
900     if (proxyUri)
901         ewk_network_proxy_uri_set(proxyUri);
902
903     browserCreate(url, themePath, userAgent, geometry, engine, backingStore, isFlattening, isFullscreen, path);
904     ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT, main_signal_exit, &windows);
905
906     ecore_main_loop_begin();
907
908     ewk_shutdown();
909
910     return quit(EINA_TRUE, NULL);
911 }