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