5dce08c22d641a8a893cdfd3350d12ff50177341
[WebKit-https.git] / Tools / MiniBrowser / efl / main.c
1 /*
2  * Copyright (C) 2012 Samsung Electronics
3  * Copyright (C) 2012 Intel Corporation. All rights reserved.
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19
20 #include "EWebKit2.h"
21 #include "url_utils.h"
22 #include <Ecore.h>
23 #include <Ecore_Evas.h>
24 #include <Ecore_Getopt.h>
25 #include <Eet.h>
26 #include <Eina.h>
27 #include <Elementary.h>
28 #include <Evas.h>
29
30 static const char DEFAULT_URL[] = "http://www.google.com/";
31 static const char APP_NAME[] = "EFL MiniBrowser";
32 static const int TOOL_BAR_ICON_SIZE = 24;
33 static const int TOOL_BAR_BUTTON_SIZE = 32;
34 static const int SEARCH_FIELD_SIZE = 200;
35 static const int SEARCH_BUTTON_SIZE = 25;
36 static const int MAX_SEARCH_COUNT = 100;
37 static const int DEFAULT_SEARCH_FLAGS = EWK_FIND_OPTIONS_SHOW_HIGHLIGHT | EWK_FIND_OPTIONS_CASE_INSENSITIVE | EWK_FIND_OPTIONS_WRAP_AROUND;
38 static const double TOOLTIP_DELAY_SECONDS = 1.0;
39
40 #define info(format, args...)       \
41     do {                            \
42         if (verbose)                \
43             printf(format"\n", ##args); \
44     } while (0)
45
46 static int verbose = 1;
47 static Eina_List *windows = NULL;
48 static char *evas_engine_name = NULL;
49 static char *user_agent_string = NULL;
50 static Eina_Bool encoding_detector_enabled = EINA_FALSE;
51 static Eina_Bool frame_flattening_enabled = EINA_FALSE;
52 static Eina_Bool local_storage_enabled = EINA_TRUE;
53 static Eina_Bool fullscreen_enabled = EINA_FALSE;
54 static Eina_Bool spell_checking_enabled = EINA_FALSE;
55 static Eina_Bool touch_events_enabled = EINA_FALSE;
56 static Eina_Bool fixed_layout_enabled = EINA_FALSE;
57 static int window_width = 800;
58 static int window_height = 600;
59 /* Default value of device_pixel_ratio is '0' so that we don't set custom device
60  * scale factor unless it's required by the User. */
61 static double device_pixel_ratio = 0;
62 static Eina_Bool legacy_behavior_enabled = EINA_FALSE;
63
64 #define DEFAULT_ZOOM_LEVEL 5 // Set default zoom level to 1.0 (index 5 on zoomLevels).
65 // The zoom values are chosen to be like in Mozilla Firefox 3.
66 const static float zoomLevels[] = {0.3, 0.5, 0.67, 0.8, 0.9, 1.0, 1.1, 1.2, 1.33, 1.5, 1.7, 2.0, 2.4, 3.0};
67
68 static Eina_Bool
69 zoom_level_set(Evas_Object *webview, int level)
70 {
71     if (level < 0  || level >= sizeof(zoomLevels) / sizeof(float))
72         return EINA_FALSE;
73
74     Evas_Coord ox, oy, mx, my, cx, cy;
75     evas_pointer_canvas_xy_get(evas_object_evas_get(webview), &mx, &my); // Get current mouse position on window.
76     evas_object_geometry_get(webview, &ox, &oy, NULL, NULL); // Get webview's position on window.
77     cx = mx - ox; // current x position = mouse x position - webview x position
78     cy = my - oy; // current y position = mouse y position - webview y position
79
80     Eina_Bool result = ewk_view_scale_set(webview, zoomLevels[level], cx, cy);
81     return result;
82 }
83
84 static Ewk_View_Smart_Class *miniBrowserViewSmartClass()
85 {
86     static Ewk_View_Smart_Class ewkViewClass = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION("MiniBrowser_View");
87     return &ewkViewClass;
88 }
89
90 typedef struct _Tooltip_Information {
91     Ecore_Timer *show_timer;
92     Eina_Bool activated;
93     Eina_Bool text_set;
94     Eina_Bool shown;
95 } Tooltip_Information;
96
97 typedef struct _Color_Selector {
98     Ewk_Color_Picker *ewk_picker;
99     Evas_Object *elm_selector;
100     Evas_Object *elm_selector_window;
101 } Color_Selector;
102
103 typedef struct _Browser_Window {
104     Evas_Object *elm_window;
105     Evas_Object *ewk_view;
106     Evas_Object *url_bar;
107     Evas_Object *back_button;
108     Evas_Object *forward_button;
109     struct {
110         Evas_Object *elm_menu;
111         Ewk_Popup_Menu *ewk_menu;
112     } popup;
113     struct {
114         Evas_Object *search_bar;
115         Evas_Object *search_field;
116         Evas_Object *backward_button;
117         Evas_Object *forward_button;
118     } search;
119     int current_zoom_level; 
120     Tooltip_Information tooltip;
121     Color_Selector color_selector;
122     struct {
123         Evas_Object *elm_menu;
124         Ewk_Context_Menu *ewk_menu;
125     } context_menu;
126 } Browser_Window;
127
128 typedef struct _File_Selector_Data {
129     Browser_Window* parent;
130     Evas_Object *elm_window;
131     Ewk_File_Chooser_Request *request;
132 } File_Selector_Data;
133
134 typedef struct _Auth_Data {
135     Evas_Object *popup;
136     Ewk_Auth_Request *request;
137     Evas_Object *username_entry;
138     Evas_Object *password_entry;
139 } Auth_Data;
140
141 static const Ecore_Getopt options = {
142     "MiniBrowser",
143     "%prog [options] [url]",
144     "0.0.1",
145     "(C)2012 Samsung Electronics\n (C)2012 Intel Corporation\n",
146     "",
147     "Test Web Browser using the Enlightenment Foundation Libraries (EFL) port of WebKit2",
148     EINA_TRUE, {
149         ECORE_GETOPT_STORE_STR
150             ('e', "engine", "Ecore-evas engine to use."),
151         ECORE_GETOPT_STORE_STR
152             ('s', "window-size", "Window size in following format (width)x(height)."),
153         ECORE_GETOPT_STORE_STR
154             ('u', "user-agent", "User agent to set."),
155         ECORE_GETOPT_STORE_DOUBLE
156             ('r', "device-pixel-ratio", "Ratio between the CSS units and device pixels."),
157         ECORE_GETOPT_CALLBACK_NOARGS
158             ('E', "list-engines", "List ecore-evas engines.",
159              ecore_getopt_callback_ecore_evas_list_engines, NULL),
160         ECORE_GETOPT_STORE_DEF_BOOL
161             ('c', "encoding-detector", "Enable/disable encoding detector.", EINA_FALSE),
162         ECORE_GETOPT_STORE_DEF_BOOL
163             ('f', "flattening", "Enable/disable frame flattening.", EINA_FALSE),
164         ECORE_GETOPT_STORE_DEF_BOOL
165             ('l', "local-storage", "Enable/disable HTML5 local storage.", EINA_TRUE),
166         ECORE_GETOPT_STORE_DEF_BOOL
167             ('F', "full-screen", "Start in full-screen.", EINA_FALSE),
168         ECORE_GETOPT_STORE_DEF_BOOL
169             ('t', "text-checking", "Enable/disable text spell checking.", EINA_FALSE),
170         ECORE_GETOPT_STORE_DEF_BOOL
171             ('T', "touch-events", "Enable/disable touch events.", EINA_FALSE),
172         ECORE_GETOPT_STORE_DEF_BOOL
173             ('L', "fixed-layout", "Enable/disable fixed layout.", EINA_FALSE),
174         ECORE_GETOPT_STORE_DEF_STR
175             ('p', "policy-cookies", "Cookies policy:\n  always - always accept,\n  never - never accept,\n  no-third-party - don't accept third-party cookies.", "no-third-party"),
176         ECORE_GETOPT_VERSION
177             ('V', "version"),
178         ECORE_GETOPT_COPYRIGHT
179             ('R', "copyright"),
180         ECORE_GETOPT_HELP
181             ('h', "help"),
182         ECORE_GETOPT_SENTINEL
183     }
184 };
185
186 static Eina_Stringshare *show_file_entry_dialog(Browser_Window *window, const char *label_tag, const char *default_text);
187 static Browser_Window *window_create(Evas_Object* opener, int width, int height);
188
189 static Browser_Window *window_find_with_elm_window(Evas_Object *elm_window)
190 {
191     Eina_List *l;
192     void *data;
193
194     if (!elm_window)
195         return NULL;
196
197     EINA_LIST_FOREACH(windows, l, data) {
198         Browser_Window *window = (Browser_Window *)data;
199         if (window->elm_window == elm_window)
200             return window;
201     }
202     return NULL;
203 }
204
205 static Browser_Window *window_find_with_ewk_view(Evas_Object *ewk_view)
206 {
207     Eina_List *l;
208     void *data;
209
210     if (!ewk_view)
211         return NULL;
212
213     EINA_LIST_FOREACH(windows, l, data) {
214         Browser_Window *window = (Browser_Window *)data;
215         if (window->ewk_view == ewk_view)
216             return window;
217     }
218     return NULL;
219 }
220
221 static Eina_Bool
222 on_tooltip_show(void *user_data)
223 {
224     Browser_Window *window = (Browser_Window *)user_data;
225
226     window->tooltip.show_timer = NULL;
227     elm_object_tooltip_show(window->elm_window);
228     window->tooltip.shown = EINA_TRUE;
229     return ECORE_CALLBACK_CANCEL;
230 }
231
232 static void
233 window_tooltip_hide(Browser_Window *window)
234 {
235     if (window->tooltip.show_timer) {
236         ecore_timer_del(window->tooltip.show_timer);
237         window->tooltip.show_timer = NULL;
238     }
239
240     if (window->tooltip.shown) {
241         elm_object_tooltip_hide(window->elm_window);
242         window->tooltip.shown = EINA_FALSE;
243     }
244 }
245
246 static void
247 window_tooltip_update(Browser_Window *window)
248 {
249     window_tooltip_hide(window);
250
251     if (window->tooltip.activated && window->tooltip.text_set)
252         window->tooltip.show_timer = ecore_timer_add(TOOLTIP_DELAY_SECONDS, on_tooltip_show, window);
253 }
254
255 static void
256 on_mouse_in(void *user_data, Evas *e, Evas_Object *ewk_view, void *event_info)
257 {
258     Browser_Window *window = (Browser_Window *)user_data;
259
260     window->tooltip.activated = EINA_TRUE;
261     window_tooltip_update(window);
262 }
263
264 static void
265 on_mouse_move(void *user_data, Evas *e, Evas_Object *ewk_view, void *event_info)
266 {
267     window_tooltip_update((Browser_Window *)user_data);
268 }
269
270 static void
271 on_mouse_out(void *user_data, Evas *e, Evas_Object *ewk_view, void *event_info)
272 {
273     Browser_Window *window = (Browser_Window *)user_data;
274
275     window->tooltip.activated = EINA_FALSE;
276     window_tooltip_update(window);
277 }
278
279 static void
280 on_window_resize(void *user_data, Evas *e, Evas_Object *elm_window, void *event_info)
281 {
282     Browser_Window *window = (Browser_Window *)user_data;
283
284     if (!window) {
285         info("ERROR: window is NULL.");
286         return;
287     }
288
289     if (window->context_menu.ewk_menu)
290         ewk_context_menu_hide(window->context_menu.ewk_menu);
291     if (window->popup.ewk_menu)
292         ewk_popup_menu_close(window->popup.ewk_menu);
293     if (window->popup.elm_menu)
294         elm_menu_close(window->popup.elm_menu);
295 }
296
297 static void window_free(Browser_Window *window)
298 {
299     evas_object_event_callback_del(window->ewk_view, EVAS_CALLBACK_MOUSE_IN, on_mouse_in);
300     evas_object_event_callback_del(window->ewk_view, EVAS_CALLBACK_MOUSE_OUT, on_mouse_out);
301     evas_object_event_callback_del(window->ewk_view, EVAS_CALLBACK_MOUSE_MOVE, on_mouse_move);
302
303     evas_object_event_callback_del(window->elm_window, EVAS_CALLBACK_RESIZE, on_window_resize);
304
305     evas_object_del(window->ewk_view);
306     /* The elm_win will take care of freeing its children */
307     evas_object_del(window->elm_window);
308
309     if (window->tooltip.show_timer)
310         ecore_timer_del(window->tooltip.show_timer);
311
312     if (window->color_selector.elm_selector_window)
313         evas_object_del(window->color_selector.elm_selector_window);
314
315     free(window);
316 }
317
318 static void window_close(Browser_Window *window)
319 {
320     windows = eina_list_remove(windows, window);
321     window_free(window);
322
323     if (!windows)
324         elm_exit();
325 }
326
327 static void
328 search_box_show(Browser_Window *window)
329 {
330     evas_object_size_hint_min_set(window->search.search_bar, SEARCH_FIELD_SIZE + 2 * SEARCH_BUTTON_SIZE, SEARCH_BUTTON_SIZE);
331
332     evas_object_show(window->search.search_bar);
333     evas_object_show(window->search.search_field);
334     evas_object_show(window->search.backward_button);
335     evas_object_show(window->search.forward_button);
336
337     /* Grab focus from the view */
338     evas_object_focus_set(window->ewk_view, EINA_FALSE);
339     elm_object_focus_set(window->search.search_field, EINA_TRUE);
340 }
341
342 static void
343 search_box_hide(Browser_Window *window)
344 {
345     ewk_view_text_find_highlight_clear(window->ewk_view);
346
347     evas_object_size_hint_min_set(window->search.search_bar, SEARCH_FIELD_SIZE + 2 * SEARCH_BUTTON_SIZE, 0);
348     evas_object_hide(window->search.search_bar);
349     evas_object_hide(window->search.search_field);
350     evas_object_hide(window->search.backward_button);
351     evas_object_hide(window->search.forward_button);
352
353     /* Give focus back to the view */
354     elm_object_focus_set(window->search.search_field, EINA_FALSE);
355     evas_object_focus_set(window->ewk_view, EINA_TRUE);
356 }
357
358 static void save_page_contents_callback(Ewk_Page_Contents_Type type, const char *data, void *user_data)
359 {
360     Eet_File *ef;
361     Eina_Stringshare *fileName = (Eina_Stringshare *)user_data;
362
363     if (!eina_str_has_extension(fileName, ".mht")) {
364         Eina_Strbuf *fileNameWithMht = eina_strbuf_new();
365         eina_strbuf_append_printf(fileNameWithMht, "%s.mht", fileName);
366         ef = eet_open(eina_strbuf_string_get(fileNameWithMht), EET_FILE_MODE_WRITE);
367         info("Saving file to: %s", eina_strbuf_string_get(fileNameWithMht));
368         eina_strbuf_free(fileNameWithMht);
369     } else {
370         ef = eet_open(fileName, EET_FILE_MODE_WRITE);
371         info("Saving file to: %s", fileName);
372     }
373
374     if (!ef) {
375         info("ERROR: Could not create File");
376         return;
377     }
378
379     eet_write(ef, "MHTML data", data, strlen(data), 0 /* compress */);
380     eet_close(ef);
381     info("SUCCESS: saved.");
382
383     eina_stringshare_del(fileName);
384 }
385
386 static void
387 on_key_down(void *user_data, Evas *e, Evas_Object *ewk_view, void *event_info)
388 {
389     Browser_Window *window = (Browser_Window *)user_data;
390     Evas_Event_Key_Down *ev = (Evas_Event_Key_Down*) event_info;
391
392     static const char *encodings[] = {
393         "ISO-8859-1",
394         "UTF-8",
395         NULL
396     };
397     static int currentEncoding = -1;
398     const Evas_Modifier *mod = evas_key_modifier_get(e);
399     Eina_Bool ctrlPressed = evas_key_modifier_is_set(mod, "Control");
400     Eina_Bool altPressed = evas_key_modifier_is_set(mod, "Alt");
401
402     if (!strcmp(ev->key, "Left") && altPressed) {
403         info("Back (Alt+Left) was pressed");
404         if (!ewk_view_back(ewk_view))
405             info("Back ignored: No back history");
406     } else if (!strcmp(ev->key, "Right") && altPressed) {
407         info("Forward (Alt+Right) was pressed");
408         if (!ewk_view_forward(ewk_view))
409             info("Forward ignored: No forward history");
410     } else if (!strcmp(ev->key, "Home") && altPressed) {
411         info("Home (Alt+Home) was pressed");
412         ewk_view_url_set(window->ewk_view, DEFAULT_URL);
413     } else if (!strcmp(ev->key, "F3")) {
414         currentEncoding = (currentEncoding + 1) % (sizeof(encodings) / sizeof(encodings[0]));
415         info("Set encoding (F3) pressed. New encoding to %s", encodings[currentEncoding]);
416         ewk_view_custom_encoding_set(ewk_view, encodings[currentEncoding]);
417     } else if (!strcmp(ev->key, "F5")) {
418         info("Reload (F5) was pressed, reloading.");
419         ewk_view_reload(ewk_view);
420     } else if (!strcmp(ev->key, "F6")) {
421         info("Stop (F6) was pressed, stop loading.");
422         ewk_view_stop(ewk_view);
423     } else if (!strcmp(ev->key, "F7")) {
424         Ewk_Pagination_Mode mode =  ewk_view_pagination_mode_get(ewk_view);
425         mode = (++mode) % (EWK_PAGINATION_MODE_BOTTOM_TO_TOP + 1);
426         if (ewk_view_pagination_mode_set(ewk_view, mode))
427             info("Change Pagination Mode (F7) was pressed, changed to: %d", mode);
428         else
429             info("Change Pagination Mode (F7) was pressed, but NOT changed!");
430     } else if (!strcmp(ev->key, "F11")) {
431         info("Fullscreen (F11) was pressed, toggling window/fullscreen.");
432         elm_win_fullscreen_set(window->elm_window, !elm_win_fullscreen_get(window->elm_window));
433     } else if (!strcmp(ev->key, "n") && ctrlPressed) {
434         info("Create new window (Ctrl+n) was pressed.");
435         Browser_Window *window = window_create(NULL, 0, 0);
436         ewk_view_url_set(window->ewk_view, DEFAULT_URL);
437         // 0 equals default width and height.
438         windows = eina_list_append(windows, window);
439     } else if (!strcmp(ev->key, "i") && ctrlPressed) {
440         info("Show Inspector (Ctrl+i) was pressed.");
441         ewk_view_inspector_show(ewk_view);
442     } else if (!strcmp(ev->key, "f") && ctrlPressed) {
443         info("Show Search Box (Ctrl+f) was pressed.");
444         search_box_show(window);
445     } else if (!strcmp(ev->key, "Escape")) {
446         if (evas_object_visible_get(window->search.search_bar))
447             search_box_hide(window);
448         else if (elm_win_fullscreen_get(window->elm_window))
449             ewk_view_fullscreen_exit(ewk_view);
450     } else if (ctrlPressed && (!strcmp(ev->key, "minus") || !strcmp(ev->key, "KP_Subtract"))) {
451         if (zoom_level_set(ewk_view, window->current_zoom_level - 1))
452             window->current_zoom_level--;
453         info("Zoom out (Ctrl + '-') was pressed, zoom level became %.2f", zoomLevels[window->current_zoom_level]);
454     } else if (ctrlPressed && (!strcmp(ev->key, "equal") || !strcmp(ev->key, "KP_Add"))) {
455         if (zoom_level_set(ewk_view, window->current_zoom_level + 1))
456             window->current_zoom_level++;
457         info("Zoom in (Ctrl + '+') was pressed, zoom level became %.2f", zoomLevels[window->current_zoom_level]);
458     } else if (ctrlPressed && !strcmp(ev->key, "0")) {
459         if (zoom_level_set(ewk_view, DEFAULT_ZOOM_LEVEL))
460             window->current_zoom_level = DEFAULT_ZOOM_LEVEL;
461         info("Zoom to default (Ctrl + '0') was pressed, zoom level became %.2f", zoomLevels[window->current_zoom_level]);
462     } else if (ctrlPressed && !strcmp(ev->key, "s")) {
463         Eina_Strbuf *default_file = eina_strbuf_new();
464         const char *home_path = getenv("HOME");
465         const char *title = ewk_view_title_get(window->ewk_view);
466         eina_strbuf_append_printf(default_file, "%s/%s.mht", home_path ? home_path : "/home", title ? title : "title");
467         info("Pressed (CTRL + S) : Saving Current Page.");
468         Eina_Stringshare *save_file_name = show_file_entry_dialog(window, "SAVE", eina_strbuf_string_get(default_file));
469         if (!save_file_name)
470             return;
471         ewk_view_page_contents_get(ewk_view, EWK_PAGE_CONTENTS_TYPE_MHTML, save_page_contents_callback, (void *)save_file_name);
472         eina_strbuf_free(default_file);
473     } else if (ctrlPressed && !strcmp(ev->key, "l")) {
474         const char *home_path =  getenv("HOME");
475         Eina_Stringshare *open_file_name = show_file_entry_dialog(window, "LOAD", home_path ? home_path : "/home");
476         if (!open_file_name)
477             return;
478         Eina_Strbuf *uri_path = eina_strbuf_new();
479         eina_strbuf_append_printf(uri_path, "file://%s", open_file_name);
480         info("pressed (CTRL + L) : Loading Page %s", eina_strbuf_string_get(uri_path));
481         ewk_view_url_set(ewk_view, eina_strbuf_string_get(uri_path));
482         eina_strbuf_free(uri_path);
483         eina_stringshare_del(open_file_name);
484     }
485 }
486
487 static void
488 view_focus_set(Browser_Window *window, Eina_Bool focus)
489 {
490     /* We steal focus away from elm's focus model and start to do things
491      * manually here, so elm now has no clue what's up. Tell elm that its
492      * toplevel widget is to be unfocused so elm gives up the focus */
493     elm_object_focus_set(elm_object_top_widget_get(window->elm_window), EINA_FALSE);
494     evas_object_focus_set(window->ewk_view, focus);
495 }
496
497 static void
498 on_mouse_down(void *user_data, Evas *e, Evas_Object *ewk_view, void *event_info)
499 {
500     Browser_Window *window = (Browser_Window *)user_data;
501     Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down *)event_info;
502
503     /* Clear selection from the URL bar */
504     elm_entry_select_none(window->url_bar);
505
506     if (ev->button == 1)
507         view_focus_set(window, EINA_TRUE);
508     else if (ev->button == 2)
509         view_focus_set(window, !evas_object_focus_get(ewk_view));
510 }
511
512 static void
513 title_set(Evas_Object *elm_window, const char *title, int progress)
514 {
515     Eina_Strbuf *buffer;
516
517     if (!title || !*title) {
518         elm_win_title_set(elm_window, APP_NAME);
519         return;
520     }
521
522     buffer = eina_strbuf_new();
523     if (progress < 100)
524         eina_strbuf_append_printf(buffer, "%s (%d%%) - %s", title, progress, APP_NAME);
525     else
526         eina_strbuf_append_printf(buffer, "%s - %s", title, APP_NAME);
527
528     elm_win_title_set(elm_window, eina_strbuf_string_get(buffer));
529     eina_strbuf_free(buffer);
530 }
531
532 static void
533 on_title_changed(void *user_data, Evas_Object *ewk_view, void *event_info)
534 {
535     Browser_Window *window = (Browser_Window *)user_data;
536     const char *title = (const char *)event_info;
537
538     title_set(window->elm_window, title, 100);
539 }
540
541 static void
542 on_url_changed(void *user_data, Evas_Object *ewk_view, void *event_info)
543 {
544     Browser_Window *window = (Browser_Window *)user_data;
545
546     char *url = elm_entry_utf8_to_markup(ewk_view_url_get(window->ewk_view));
547     elm_entry_entry_set(window->url_bar, url);
548
549     free(url);
550
551     search_box_hide(window);
552 }
553
554 static void
555 on_back_forward_list_changed(void *user_data, Evas_Object *ewk_view, void *event_info)
556 {
557     Browser_Window *window = (Browser_Window *)user_data;
558
559     /* Update navigation buttons state */
560     elm_object_disabled_set(window->back_button, !ewk_view_back_possible(ewk_view));
561     elm_object_disabled_set(window->forward_button, !ewk_view_forward_possible(ewk_view));
562 }
563
564 static void
565 on_progress(void *user_data, Evas_Object *ewk_view, void *event_info)
566 {
567     Browser_Window *window = (Browser_Window *)user_data;
568     double progress = *(double *)event_info;
569
570     title_set(window->elm_window, ewk_view_title_get(window->ewk_view), progress * 100);
571 }
572
573 static void
574 on_error(void *user_data, Evas_Object *ewk_view, void *event_info)
575 {
576     Eina_Strbuf *buffer;
577     const Ewk_Error *error = (const Ewk_Error *)event_info;
578
579     /* This is a cancellation, do not display the error page */
580     if (ewk_error_cancellation_get(error))
581         return;
582
583     buffer = eina_strbuf_new();
584     eina_strbuf_append_printf(buffer, "<html><body><div style=\"color:#ff0000\">ERROR!</div><br><div>Code: %d<br>Description: %s<br>URL: %s</div></body</html>",
585         ewk_error_code_get(error), ewk_error_description_get(error), ewk_error_url_get(error));
586
587     ewk_view_html_string_load(ewk_view, eina_strbuf_string_get(buffer), 0, ewk_error_url_get(error));
588     eina_strbuf_free(buffer);
589 }
590
591 static void
592 on_download_request(void *user_data, Evas_Object *ewk_view, void *event_info)
593 {
594     Ewk_Download_Job *download = (Ewk_Download_Job *)event_info;
595
596     // FIXME: The destination folder should be selected by the user but we set it to '/tmp' for now.
597     Eina_Strbuf *destination_path = eina_strbuf_new();
598
599     const char *suggested_name = ewk_download_job_suggested_filename_get(download);
600     if (suggested_name && *suggested_name)
601         eina_strbuf_append_printf(destination_path, "/tmp/%s", suggested_name);
602     else {
603         // Generate a unique file name since no name was suggested.
604         char unique_path[] = "/tmp/downloaded-file.XXXXXX";
605         if (mkstemp(unique_path) == -1) {
606             info("ERROR: Could not generate a unique file name.");
607             return;
608         }
609         eina_strbuf_append(destination_path, unique_path);
610     }
611
612     ewk_download_job_destination_set(download, eina_strbuf_string_get(destination_path));
613     info("Downloading: %s", eina_strbuf_string_get(destination_path));
614     eina_strbuf_free(destination_path);
615 }
616
617 static void on_filepicker_parent_deletion(void *user_data, Evas *evas, Evas_Object *elm_window, void *event);
618
619 static void close_file_picker(File_Selector_Data *fs_data)
620 {
621     evas_object_event_callback_del(fs_data->parent->elm_window, EVAS_CALLBACK_DEL, on_filepicker_parent_deletion);
622     evas_object_del(fs_data->elm_window);
623     ewk_object_unref(fs_data->request);
624     free(fs_data);
625 }
626
627 static void
628 on_filepicker_parent_deletion(void *user_data, Evas *evas, Evas_Object *elm_window, void *event)
629 {
630     close_file_picker((File_Selector_Data *)user_data);
631 }
632
633 static void
634 on_filepicker_deletion(void *user_data, Evas_Object *elm_window, void *event_info)
635 {
636     close_file_picker((File_Selector_Data *)user_data);
637 }
638
639 static void
640 on_fileselector_done(void *user_data, Evas_Object *file_selector, void *event_info)
641 {
642     File_Selector_Data *fs_data = (File_Selector_Data *)user_data;
643
644     const char *selected = (const char *)event_info;
645     if (selected && *selected)
646         ewk_file_chooser_request_file_choose(fs_data->request, selected);
647
648     close_file_picker(fs_data);
649 }
650
651 static void
652 on_file_chooser_request(void *user_data, Evas_Object *ewk_view, void *event_info)
653 {
654     Evas_Object *bg;
655     Browser_Window *window = (Browser_Window *)user_data;
656     Ewk_File_Chooser_Request *request = (Ewk_File_Chooser_Request *)event_info;
657
658     // Show basic file picker which does not currently support multiple files
659     // or MIME type filtering.
660     Evas_Object *elm_window = elm_win_add(window->elm_window, "file-picker-window", ELM_WIN_DIALOG_BASIC);
661     elm_win_title_set(elm_window, "File picker");
662     elm_win_modal_set(elm_window, EINA_TRUE);
663
664     bg = elm_bg_add(elm_window);
665     evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
666     elm_win_resize_object_add(elm_window, bg);
667     evas_object_show(bg);
668
669     File_Selector_Data *fs_data = (File_Selector_Data *)malloc(sizeof(File_Selector_Data));
670     fs_data->parent = window;
671     fs_data->elm_window = elm_window;
672     fs_data->request = ewk_object_ref(request);
673     evas_object_smart_callback_add(elm_window, "delete,request", on_filepicker_deletion, fs_data);
674     evas_object_event_callback_add(window->elm_window, EVAS_CALLBACK_DEL, on_filepicker_parent_deletion, fs_data);
675
676     Evas_Object *file_selector = elm_fileselector_add(elm_window);
677     const char *home_path = getenv("HOME");
678     elm_fileselector_path_set(file_selector, home_path ? home_path : "/home");
679     evas_object_size_hint_weight_set(file_selector, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
680     elm_win_resize_object_add(elm_window, file_selector);
681     evas_object_show(file_selector);
682
683     evas_object_smart_callback_add(file_selector, "done", on_fileselector_done, fs_data);
684
685     evas_object_resize(elm_window, 400, 400);
686     elm_win_center(elm_window, EINA_TRUE, EINA_TRUE);
687     evas_object_show(elm_window);
688 }
689
690 static void
691 on_download_finished(void *user_data, Evas_Object *ewk_view, void *event_info)
692 {
693     Ewk_Download_Job *download = (Ewk_Download_Job *)event_info;
694     info("Download finished: %s",  ewk_download_job_destination_get(download));
695 }
696
697 static void
698 on_download_failed(void *user_data, Evas_Object *ewk_view, void *event_info)
699 {
700     info("Download failed!");
701 }
702
703 static void
704 on_color_changed(void *data, Evas_Object *obj, void *event_info)
705 {
706     int r, g, b, a;
707
708     elm_colorselector_color_get(obj, &r, &g, &b, &a);
709     evas_object_color_set(data, r, g, b, a);
710 }
711
712 static void
713 on_color_item_selected(void *data, Evas_Object *obj, void *event_info)
714 {
715     int r, g, b, a;
716     Elm_Object_Item *color_item = (Elm_Object_Item *)event_info;
717
718     elm_colorselector_palette_item_color_get(color_item, &r, &g, &b, &a);
719     evas_object_color_set(data, r, g, b, a);
720 }
721
722 static void
723 on_color_picker_ok_clicked(void *data, Evas_Object *obj, void *event_info)
724 {
725     int r, g, b, a;
726     Color_Selector *color_selector = (Color_Selector *)data;
727
728     elm_colorselector_color_get(color_selector->elm_selector, &r, &g, &b, &a);
729     ewk_color_picker_color_set(color_selector->ewk_picker, r, g, b, a);
730 }
731
732 static void
733 on_color_picker_cancel_clicked(void *data, Evas_Object *obj, void *event_info)
734 {
735     int r, g, b, a;
736
737     ewk_color_picker_color_get(data, &r, &g, &b, &a);
738     ewk_color_picker_color_set(data, r, g, b, a);
739 }
740
741 static Eina_Bool
742 on_color_picker_dismiss(Ewk_View_Smart_Data *sd)
743 {
744     Browser_Window *window = window_find_with_ewk_view(sd->self);
745
746     evas_object_del(window->color_selector.elm_selector_window);
747     window->color_selector.elm_selector_window = NULL;
748
749     return EINA_TRUE;
750 }
751
752 static Eina_Bool
753 on_color_picker_request(Ewk_View_Smart_Data *sd, Ewk_Color_Picker *color_picker)
754 {
755     int r, g, b, a;
756     Evas_Object *background, *rect, *box, *button_box, *rect_frame, *cs_frame, *ok_button, *cancel_button;
757
758     Browser_Window *window = window_find_with_ewk_view(sd->self);
759     window->color_selector.elm_selector_window = elm_win_add(window->elm_window, "color selector", ELM_WIN_BASIC);
760     window->color_selector.ewk_picker = color_picker;
761
762     elm_win_title_set(window->color_selector.elm_selector_window, "Color selector");
763
764     /* Show color view */
765     background = elm_bg_add(window->color_selector.elm_selector_window);
766     evas_object_size_hint_weight_set(background, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
767     elm_win_resize_object_add(window->color_selector.elm_selector_window, background);
768     evas_object_show(background);
769
770     box = elm_box_add(window->color_selector.elm_selector_window);
771     evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
772     elm_win_resize_object_add(window->color_selector.elm_selector_window, box);
773     evas_object_show(box);
774
775     rect_frame = elm_frame_add(window->color_selector.elm_selector_window);
776     evas_object_size_hint_weight_set(rect_frame, EVAS_HINT_EXPAND, 0.3);
777     evas_object_size_hint_align_set(rect_frame, EVAS_HINT_FILL, EVAS_HINT_FILL);
778     elm_object_text_set(rect_frame, "Color View");
779     elm_box_pack_end(box, rect_frame);
780     evas_object_show(rect_frame);
781
782     rect = evas_object_rectangle_add(evas_object_evas_get(window->color_selector.elm_selector_window));
783     elm_object_content_set(rect_frame, rect);
784     ewk_color_picker_color_get(window->color_selector.ewk_picker, &r, &g, &b, &a);
785     evas_object_color_set(rect, r, g, b, a);
786     evas_object_show(rect);
787
788     /* Show color selector */
789     cs_frame = elm_frame_add(window->color_selector.elm_selector_window);
790     evas_object_size_hint_weight_set(cs_frame, EVAS_HINT_EXPAND, 0.7);
791     evas_object_size_hint_align_set(cs_frame, EVAS_HINT_FILL, EVAS_HINT_FILL);
792     elm_object_text_set(cs_frame, "Color Selector");
793     elm_box_pack_end(box, cs_frame);
794     evas_object_show(cs_frame);
795
796     window->color_selector.elm_selector = elm_colorselector_add(window->color_selector.elm_selector_window);
797     elm_object_content_set(cs_frame, window->color_selector.elm_selector);
798     evas_object_show(window->color_selector.elm_selector);
799
800     /* OK, Cancel Buttons */
801     button_box = elm_box_add(window->color_selector.elm_selector_window);
802     elm_box_horizontal_set(button_box, EINA_TRUE);
803     evas_object_size_hint_min_set(button_box, 200, 50);
804     elm_box_pack_end(box, button_box);
805     evas_object_show(button_box);
806
807     ok_button = elm_button_add(window->color_selector.elm_selector_window);
808     elm_object_text_set(ok_button, "OK");
809     elm_box_pack_end(button_box, ok_button);
810     evas_object_show(ok_button);
811
812     cancel_button = elm_button_add(window->color_selector.elm_selector_window);
813     elm_object_text_set(cancel_button, "Cancel");
814     elm_box_pack_end(button_box, cancel_button);
815     evas_object_show(cancel_button);
816
817     evas_object_smart_callback_add(ok_button, "clicked", on_color_picker_ok_clicked, &(window->color_selector));
818     evas_object_smart_callback_add(cancel_button, "clicked", on_color_picker_cancel_clicked, window->color_selector.ewk_picker);
819     evas_object_smart_callback_add(window->color_selector.elm_selector_window, "delete,request", on_color_picker_cancel_clicked, window->color_selector.ewk_picker);
820     evas_object_smart_callback_add(window->color_selector.elm_selector, "changed", on_color_changed, rect);
821     evas_object_smart_callback_add(window->color_selector.elm_selector, "color,item,selected", on_color_item_selected, rect);
822
823     elm_win_center(window->color_selector.elm_selector_window, EINA_TRUE, EINA_TRUE);
824     evas_object_resize(window->color_selector.elm_selector_window, 350, 500);
825     evas_object_show(window->color_selector.elm_selector_window);
826
827     return EINA_TRUE;
828 }
829
830 static void
831 update_view_favicon(Browser_Window *window, Evas_Object *icon)
832 {
833     /* Remove previous icon from URL bar */
834     Evas_Object *old_icon = elm_object_part_content_unset(window->url_bar, "icon");
835     if (old_icon) {
836         evas_object_unref(old_icon);
837         evas_object_del(old_icon);
838     }
839
840     /* Show new icon in URL bar */
841     if (icon) {
842         /* Workaround for icon display bug:
843          * http://trac.enlightenment.org/e/ticket/1616 */
844         evas_object_size_hint_min_set(icon, 48, 24);
845         evas_object_image_filled_set(icon, EINA_FALSE);
846         evas_object_image_fill_set(icon, 24, 0, 24, 24);
847         elm_object_part_content_set(window->url_bar, "icon", icon);
848         evas_object_ref(icon);
849     }
850 }
851
852 static void
853 on_view_favicon_changed(void *user_data, Evas_Object *ewk_view, void *event_info)
854 {
855     Browser_Window *window = (Browser_Window *)user_data;
856
857     Evas_Object* favicon = ewk_view_favicon_get(ewk_view);
858     update_view_favicon(window, favicon);
859
860     if (favicon)
861         evas_object_unref(favicon);
862 }
863
864 static int
865 quit(Eina_Bool success, const char *msg)
866 {
867     ewk_shutdown();
868     elm_shutdown();
869
870     if (msg)
871         fputs(msg, (success) ? stdout : stderr);
872
873     if (!success)
874         return EXIT_FAILURE;
875
876     return EXIT_SUCCESS;
877 }
878
879 static void
880 on_url_bar_activated(void *user_data, Evas_Object *url_bar, void *event_info)
881 {
882     Browser_Window *window = (Browser_Window *)user_data;
883
884     const char *markup_url = elm_entry_entry_get(url_bar);
885     char *user_url = elm_entry_markup_to_utf8(markup_url);
886     char *url = url_from_user_input(user_url);
887     ewk_view_url_set(window->ewk_view, url);
888
889     free(user_url);
890     free(url);
891
892     /* Give focus back to the view */
893     view_focus_set(window, EINA_TRUE);
894 }
895
896 static void
897 on_url_bar_clicked(void *user_data, Evas_Object *url_bar, void *event_info)
898 {
899     Browser_Window *window = (Browser_Window *)user_data;
900
901     /* Grab focus from the view */
902     evas_object_focus_set(window->ewk_view, EINA_FALSE);
903     elm_object_focus_set(url_bar, EINA_TRUE);
904 }
905
906 static void
907 on_search_field_aborted(void *user_data, Evas_Object *search_field, void *event_info)
908 {
909     Browser_Window *window = (Browser_Window *)user_data;
910     search_box_hide(window);
911
912     /* Give focus back to the view */
913     view_focus_set(window, EINA_TRUE);
914 }
915
916 static void
917 on_search_field_activated(void *user_data, Evas_Object *search_field, void *event_info)
918 {
919     Browser_Window *window = (Browser_Window *)user_data;
920
921     const char *markup_text = elm_entry_entry_get(search_field);
922     char *text = elm_entry_markup_to_utf8(markup_text);
923     ewk_view_text_find(window->ewk_view, text, DEFAULT_SEARCH_FLAGS, MAX_SEARCH_COUNT);
924     free(text);
925
926     /* Grab focus from the view */
927     evas_object_focus_set(window->ewk_view, EINA_FALSE);
928     elm_object_focus_set(search_field, EINA_TRUE);
929 }
930
931 static void
932 on_search_field_clicked(void *user_data, Evas_Object *search_field, void *event_info)
933 {
934     Browser_Window *window = (Browser_Window *)user_data;
935
936     /* Grab focus from the view */
937     evas_object_focus_set(window->ewk_view, EINA_FALSE);
938     elm_object_focus_set(search_field, EINA_TRUE);
939 }
940
941 static void
942 on_back_button_clicked(void *user_data, Evas_Object *back_button, void *event_info)
943 {
944     Browser_Window *window = (Browser_Window *)user_data;
945
946     ewk_view_back(window->ewk_view);
947     /* Update back button state */
948     elm_object_disabled_set(back_button, !ewk_view_back_possible(window->ewk_view));
949 }
950
951 static void
952 on_forward_button_clicked(void *user_data, Evas_Object *forward_button, void *event_info)
953 {
954     Browser_Window *window = (Browser_Window *)user_data;
955
956     ewk_view_forward(window->ewk_view);
957     /* Update forward button state */
958     elm_object_disabled_set(forward_button, !ewk_view_forward_possible(window->ewk_view));
959 }
960
961 static void
962 on_search_backward_button_clicked(void *user_data, Evas_Object *search_backward_button, void *event_info)
963 {
964     Browser_Window *window = (Browser_Window *)user_data;
965
966     char *text = elm_entry_markup_to_utf8(elm_entry_entry_get(window->search.search_field));
967     ewk_view_text_find(window->ewk_view, text, DEFAULT_SEARCH_FLAGS | EWK_FIND_OPTIONS_BACKWARDS, MAX_SEARCH_COUNT);
968     free(text);
969 }
970
971 static void
972 on_search_forward_button_clicked(void *user_data, Evas_Object *search_forward_button, void *event_info)
973 {
974     Browser_Window *window = (Browser_Window *)user_data;
975
976     char *text = elm_entry_markup_to_utf8(elm_entry_entry_get(window->search.search_field));
977     ewk_view_text_find(window->ewk_view, text, DEFAULT_SEARCH_FLAGS, MAX_SEARCH_COUNT);
978     free(text);
979 }
980
981 static void
982 on_refresh_button_clicked(void *user_data, Evas_Object *refresh_button, void *event_info)
983 {
984     Browser_Window *window = (Browser_Window *)user_data;
985
986     Evas *evas = evas_object_evas_get(refresh_button);
987     Eina_Bool ctrlPressed = evas_key_modifier_is_set(evas_key_modifier_get(evas), "Control");
988     if (ctrlPressed) {
989         info("Reloading and bypassing cache...");
990         ewk_view_reload_bypass_cache(window->ewk_view);
991     } else {
992         info("Reloading...");
993         ewk_view_reload(window->ewk_view);
994     }
995 }
996
997 static void
998 quit_event_loop(void *user_data, Evas_Object *obj, void *event_info)
999 {
1000     ecore_main_loop_quit();
1001 }
1002
1003 static void
1004 on_ok_clicked(void *user_data, Evas_Object *obj, void *event_info)
1005 {
1006     Eina_Bool *confirmed = (Eina_Bool *)user_data;
1007     *confirmed = EINA_TRUE;
1008
1009     ecore_main_loop_quit();
1010 }
1011
1012 static Eina_Stringshare *
1013 show_file_entry_dialog(Browser_Window *window, const char *label_tag, const char *default_text)
1014 {
1015     Evas_Object *file_popup = elm_popup_add(window->elm_window);
1016     evas_object_size_hint_weight_set(file_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1017     evas_object_show(file_popup);
1018
1019     Evas_Object *vbox = elm_box_add(file_popup);
1020     evas_object_size_hint_weight_set(vbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1021     evas_object_size_hint_align_set(vbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
1022     elm_object_content_set(file_popup, vbox);
1023     evas_object_show(vbox);
1024
1025     Evas_Object *label = elm_label_add(window->elm_window);
1026     elm_object_text_set(label, label_tag);
1027     evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, 0.0);
1028     evas_object_size_hint_align_set(label, EVAS_HINT_FILL, 0.5);
1029     evas_object_color_set(label, 23, 45, 67, 142);
1030     elm_box_pack_end(vbox, label);
1031     evas_object_show(label);
1032
1033     Evas_Object *fs_entry = elm_fileselector_entry_add(file_popup);
1034     elm_fileselector_entry_is_save_set(fs_entry, EINA_TRUE);
1035     evas_object_size_hint_align_set(fs_entry, EVAS_HINT_FILL, 0);
1036     elm_fileselector_entry_path_set(fs_entry, default_text);
1037     elm_object_text_set(fs_entry, "FileChooser");
1038     elm_box_pack_end(vbox, fs_entry);
1039     evas_object_show(fs_entry);
1040
1041     Evas_Object *hbox = elm_box_add(file_popup);
1042     evas_object_size_hint_weight_set(hbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1043     elm_box_horizontal_set(hbox, EINA_TRUE);
1044     evas_object_size_hint_align_set(hbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
1045     elm_box_pack_end(vbox, hbox);
1046     evas_object_show(hbox);
1047
1048     Eina_Bool ok = EINA_FALSE;
1049     Evas_Object *ok_button = elm_button_add(file_popup);
1050     elm_object_text_set(ok_button, "OK");
1051     evas_object_smart_callback_add(ok_button, "clicked", on_ok_clicked, &ok);
1052     elm_box_pack_end(hbox, ok_button);
1053     evas_object_show(ok_button);
1054
1055     Evas_Object *cancel_button = elm_button_add(file_popup);
1056     elm_object_text_set(cancel_button, "Cancel");
1057     evas_object_smart_callback_add(cancel_button, "clicked", quit_event_loop, NULL);
1058     elm_box_pack_end(hbox, cancel_button);
1059     evas_object_show(cancel_button);
1060
1061     ecore_main_loop_begin();
1062
1063     Eina_Stringshare *file_path = ok ? eina_stringshare_add(elm_fileselector_entry_path_get(fs_entry)) : NULL;
1064     evas_object_del(file_popup);
1065     return file_path;
1066 }
1067
1068 static void
1069 on_javascript_alert(Ewk_View_Smart_Data *smartData, const char *message)
1070 {
1071     Browser_Window *window = window_find_with_ewk_view(smartData->self);
1072
1073     Evas_Object *alert_popup = elm_popup_add(window->elm_window);
1074     evas_object_size_hint_weight_set(alert_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1075     elm_object_text_set(alert_popup, message);
1076     elm_object_part_text_set(alert_popup, "title,text", "Alert");
1077
1078     /* Popup buttons */
1079     Evas_Object *button = elm_button_add(alert_popup);
1080     elm_object_text_set(button, "OK");
1081     elm_object_part_content_set(alert_popup, "button1", button);
1082     evas_object_smart_callback_add(button, "clicked", quit_event_loop, NULL);
1083     elm_object_focus_set(button, EINA_TRUE);
1084     evas_object_show(alert_popup);
1085
1086     /* Make modal */
1087     ecore_main_loop_begin();
1088
1089     evas_object_del(alert_popup);
1090 }
1091
1092 static Eina_Bool
1093 on_javascript_confirm(Ewk_View_Smart_Data *smartData, const char *message)
1094 {
1095     Browser_Window *window = window_find_with_ewk_view(smartData->self);
1096
1097     Eina_Bool ok = EINA_FALSE;
1098
1099     Evas_Object *confirm_popup = elm_popup_add(window->elm_window);
1100     evas_object_size_hint_weight_set(confirm_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1101     elm_object_text_set(confirm_popup, message);
1102     elm_object_part_text_set(confirm_popup, "title,text", "Confirmation");
1103
1104     /* Popup buttons */
1105     Evas_Object *cancel_button = elm_button_add(confirm_popup);
1106     elm_object_text_set(cancel_button, "Cancel");
1107     elm_object_part_content_set(confirm_popup, "button1", cancel_button);
1108     evas_object_smart_callback_add(cancel_button, "clicked", quit_event_loop, NULL);
1109     Evas_Object *ok_button = elm_button_add(confirm_popup);
1110     elm_object_text_set(ok_button, "OK");
1111     elm_object_part_content_set(confirm_popup, "button2", ok_button);
1112     evas_object_smart_callback_add(ok_button, "clicked", on_ok_clicked, &ok);
1113     elm_object_focus_set(ok_button, EINA_TRUE);
1114     evas_object_show(confirm_popup);
1115
1116     /* Make modal */
1117     ecore_main_loop_begin();
1118
1119     evas_object_del(confirm_popup);
1120
1121     return ok;
1122 }
1123
1124 static const char *
1125 on_javascript_prompt(Ewk_View_Smart_Data *smartData, const char *message, const char *default_value)
1126 {
1127     Browser_Window *window = window_find_with_ewk_view(smartData->self);
1128
1129     Eina_Bool ok = EINA_FALSE;
1130
1131     Evas_Object *prompt_popup = elm_popup_add(window->elm_window);
1132     evas_object_size_hint_weight_set(prompt_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1133     elm_object_part_text_set(prompt_popup, "title,text", "Prompt");
1134
1135     /* Popup Content */
1136     Evas_Object *box = elm_box_add(window->elm_window);
1137     elm_box_padding_set(box, 0, 4);
1138     evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1139     evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);
1140     evas_object_show(box);
1141
1142     Evas_Object *prompt = elm_label_add(window->elm_window);
1143     elm_object_text_set(prompt, message);
1144     evas_object_size_hint_weight_set(prompt, EVAS_HINT_EXPAND, 0.0);
1145     evas_object_size_hint_align_set(prompt, EVAS_HINT_FILL, 0.5);
1146     elm_box_pack_end(box, prompt);
1147     evas_object_show(prompt);
1148
1149     Evas_Object *entry = elm_entry_add(window->elm_window);
1150     elm_entry_scrollable_set(entry, EINA_TRUE);
1151     elm_entry_single_line_set(entry, EINA_TRUE);
1152     elm_entry_text_style_user_push(entry, "DEFAULT='font_size=18'");
1153     elm_entry_entry_set(entry, default_value ? default_value : "");
1154     elm_entry_select_all(entry);
1155     evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, 0.0);
1156     evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, 0.5);
1157     elm_box_pack_end(box, entry);
1158     elm_object_focus_set(entry, EINA_TRUE);
1159     evas_object_show(entry);
1160
1161     elm_object_content_set(prompt_popup, box);
1162
1163     /* Popup buttons */
1164     Evas_Object *cancel_button = elm_button_add(prompt_popup);
1165     elm_object_text_set(cancel_button, "Cancel");
1166     elm_object_part_content_set(prompt_popup, "button1", cancel_button);
1167     evas_object_smart_callback_add(cancel_button, "clicked", quit_event_loop, NULL);
1168     Evas_Object *ok_button = elm_button_add(prompt_popup);
1169     elm_object_text_set(ok_button, "OK");
1170     elm_object_part_content_set(prompt_popup, "button2", ok_button);
1171     evas_object_smart_callback_add(ok_button, "clicked", on_ok_clicked, &ok);
1172     evas_object_show(prompt_popup);
1173
1174     /* Make modal */
1175     ecore_main_loop_begin();
1176
1177     /* The return string need to be stringshared */
1178     const char *prompt_text = ok ? eina_stringshare_add(elm_entry_entry_get(entry)) : NULL;
1179     evas_object_del(prompt_popup);
1180
1181     return prompt_text;
1182 }
1183
1184 static void
1185 on_popup_menu_discarded(void *user_data, Evas_Object *obj, void *event_info)
1186 {
1187     // The user clicked outside the menu to discard it.
1188     info("Popup menu was discarded.");
1189     Browser_Window *window = (Browser_Window *)user_data;
1190     ewk_popup_menu_close(window->popup.ewk_menu);
1191 }
1192
1193 static void
1194 on_popup_menu_item_clicked(void *user_data, Evas_Object *obj, void *event_info)
1195 {
1196     Browser_Window *window = (Browser_Window *)user_data;
1197     Elm_Object_Item *item = (Elm_Object_Item *)event_info;
1198
1199     info("Selected popup menu index: %u", elm_menu_item_index_get(item));
1200     ewk_popup_menu_selected_index_set(window->popup.ewk_menu, elm_menu_item_index_get(item));
1201
1202     // Close popup menu.
1203     ewk_popup_menu_close(window->popup.ewk_menu);
1204 }
1205
1206 static void
1207 popup_menu_populate(Evas_Object *elm_menu, Ewk_Popup_Menu *ewk_menu, void *user_data)
1208 {
1209     const Eina_List* ewk_items = ewk_popup_menu_items_get(ewk_menu);
1210
1211     void *data;
1212     const Eina_List *l;
1213     EINA_LIST_FOREACH(ewk_items, l, data) {
1214         Ewk_Popup_Menu_Item *ewk_item = (Ewk_Popup_Menu_Item *)data;
1215         switch (ewk_popup_menu_item_type_get(ewk_item)) {
1216         case EWK_POPUP_MENU_SEPARATOR:
1217             elm_menu_item_separator_add(elm_menu, NULL);
1218             break;
1219         case EWK_POPUP_MENU_ITEM:
1220             if (ewk_popup_menu_item_is_label_get(ewk_item)) {
1221                 Elm_Object_Item *item = elm_menu_item_add(elm_menu, NULL, NULL, ewk_popup_menu_item_text_get(ewk_item), NULL, NULL);
1222                 elm_object_item_disabled_set(item, EINA_TRUE);
1223             } else {
1224                 Elm_Object_Item *item = elm_menu_item_add(elm_menu, NULL, NULL, ewk_popup_menu_item_text_get(ewk_item), on_popup_menu_item_clicked, user_data);
1225                 const char *tooltip_text = ewk_popup_menu_item_tooltip_get(ewk_item);
1226                 if (tooltip_text && tooltip_text[0] != '\0')
1227                     elm_object_item_tooltip_text_set(item, tooltip_text);
1228                 elm_object_item_disabled_set(item, !ewk_popup_menu_item_enabled_get(ewk_item));
1229                 elm_menu_item_selected_set(item, ewk_popup_menu_item_selected_get(ewk_item));
1230             }
1231             break;
1232         default:
1233             info("Unrecognized popup menu item type!");
1234             break;
1235         }
1236     }
1237 }
1238
1239 static Eina_Bool
1240 on_popup_menu_show(Ewk_View_Smart_Data *smartData, Eina_Rectangle rect, Ewk_Text_Direction text_direction, double page_scale_factor, Ewk_Popup_Menu *ewk_menu)
1241 {
1242     Browser_Window *window = window_find_with_ewk_view(smartData->self);
1243
1244     if (window->popup.elm_menu)
1245         evas_object_del(window->popup.elm_menu);
1246
1247     window->popup.elm_menu = elm_menu_add(window->elm_window);
1248     window->popup.ewk_menu = ewk_menu;
1249     evas_object_smart_callback_add(window->popup.elm_menu, "clicked", on_popup_menu_discarded, window);
1250
1251     popup_menu_populate(window->popup.elm_menu, ewk_menu, window);
1252
1253     info("Showing popup menu at (%d, %d)", rect.x, rect.y);
1254     elm_menu_move(window->popup.elm_menu, rect.x, rect.y);
1255     evas_object_show(window->popup.elm_menu);
1256
1257     return EINA_TRUE;
1258 }
1259
1260 static Eina_Bool
1261 on_popup_menu_hide(Ewk_View_Smart_Data *smartData)
1262 {
1263     Browser_Window *window = window_find_with_ewk_view(smartData->self);
1264
1265     if (!window->popup.elm_menu)
1266         return EINA_FALSE;
1267
1268     elm_menu_close(window->popup.elm_menu);
1269
1270     return EINA_TRUE;
1271 }
1272
1273 static Eina_Bool on_window_geometry_get(Ewk_View_Smart_Data *sd, Evas_Coord *x, Evas_Coord *y, Evas_Coord *width, Evas_Coord *height)
1274 {
1275     Browser_Window *window = window_find_with_ewk_view(sd->self);
1276
1277     evas_object_geometry_get(window->elm_window, x, y, width, height);
1278
1279     return EINA_TRUE;
1280 }
1281
1282 static Eina_Bool on_window_geometry_set(Ewk_View_Smart_Data *sd, Evas_Coord x, Evas_Coord y, Evas_Coord width, Evas_Coord height)
1283 {
1284     Browser_Window *window = window_find_with_ewk_view(sd->self);
1285
1286     evas_object_move(window->elm_window, x, y);
1287     evas_object_resize(window->elm_window, width, height);
1288
1289     return EINA_TRUE;
1290 }
1291
1292 typedef struct {
1293     Evas_Object *ewk_view;
1294     Evas_Object *permission_popup;
1295 } PermissionData;
1296
1297 static void
1298 on_fullscreen_accept(void *user_data, Evas_Object *obj, void *event_info)
1299 {
1300     PermissionData *permission_data = (PermissionData *)user_data;
1301
1302     evas_object_del(permission_data->permission_popup);
1303     evas_object_focus_set(permission_data->ewk_view, EINA_TRUE);
1304     free(permission_data);
1305 }
1306
1307 static void
1308 on_fullscreen_deny(void *user_data, Evas_Object *obj, void *event_info)
1309 {
1310     PermissionData *permission_data = (PermissionData *)user_data;
1311
1312     ewk_view_fullscreen_exit(permission_data->ewk_view);
1313     evas_object_del(permission_data->permission_popup);
1314     evas_object_focus_set(permission_data->ewk_view, EINA_TRUE);
1315     free(permission_data);
1316 }
1317
1318 static Eina_Bool on_fullscreen_enter(Ewk_View_Smart_Data *sd, Ewk_Security_Origin *origin)
1319 {
1320     Browser_Window *window = window_find_with_ewk_view(sd->self);
1321
1322     /* Go fullscreen */
1323     elm_win_fullscreen_set(window->elm_window, EINA_TRUE);
1324
1325     /* Show user popup */
1326     Evas_Object *permission_popup = elm_popup_add(window->elm_window);
1327     evas_object_size_hint_weight_set(permission_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1328
1329     Eina_Strbuf *message = eina_strbuf_new();
1330     eina_strbuf_append_printf(message, "%s is now fullscreen.<br>Press ESC at any time to exit fullscreen.<br>Allow fullscreen?", ewk_security_origin_host_get(origin));
1331     elm_object_text_set(permission_popup, eina_strbuf_string_get(message));
1332     eina_strbuf_free(message);
1333     elm_object_part_text_set(permission_popup, "title,text", "Fullscreen Permission");
1334
1335     /* Popup buttons */
1336     PermissionData *permission_data = (PermissionData *)malloc(sizeof(PermissionData));
1337     permission_data->ewk_view = window->ewk_view;
1338     permission_data->permission_popup = permission_popup;
1339     Evas_Object *accept_button = elm_button_add(permission_popup);
1340     elm_object_text_set(accept_button, "Accept");
1341     elm_object_part_content_set(permission_popup, "button1", accept_button);
1342     evas_object_smart_callback_add(accept_button, "clicked", on_fullscreen_accept, permission_data);
1343
1344     Evas_Object *deny_button = elm_button_add(permission_popup);
1345     elm_object_text_set(deny_button, "Deny");
1346     elm_object_part_content_set(permission_popup, "button2", deny_button);
1347     evas_object_smart_callback_add(deny_button, "clicked", on_fullscreen_deny, permission_data);
1348
1349     evas_object_show(permission_popup);
1350
1351     return EINA_TRUE;
1352 }
1353
1354 static Eina_Bool on_fullscreen_exit(Ewk_View_Smart_Data *sd)
1355 {
1356     Browser_Window *window = window_find_with_ewk_view(sd->self);
1357
1358     elm_win_fullscreen_set(window->elm_window, EINA_FALSE);
1359
1360     return EINA_TRUE;
1361 }
1362
1363 static Evas_Object *
1364 on_window_create(Ewk_View_Smart_Data *smartData, const Ewk_Window_Features *window_features)
1365 {
1366     int x = 0;
1367     int y = 0;
1368     int width = 0;
1369     int height = 0;
1370
1371     ewk_window_features_geometry_get(window_features, &x, &y, &width, &height);
1372
1373     if (!width)
1374         width = window_width;
1375
1376     if (!height)
1377         height = window_height;
1378
1379     Browser_Window *window = window_create(smartData->self, width, height);
1380     Evas_Object *new_view = window->ewk_view;
1381
1382     windows = eina_list_append(windows, window);
1383
1384     info("minibrowser: location(%d,%d) size=(%d,%d)", x, y, width, height);
1385
1386     return new_view;
1387 }
1388
1389 static void
1390 on_window_close(Ewk_View_Smart_Data *smartData)
1391 {
1392     Browser_Window *window = window_find_with_ewk_view(smartData->self);
1393     window_close(window);
1394 }
1395
1396 static void
1397 context_menu_item_selected_cb(void *data, Evas_Object *obj, void *event_info)
1398 {
1399     if (!data) {
1400         info("ERROR: context menu callback data is NULL.");
1401         return;
1402     }
1403
1404     Ewk_Context_Menu_Item *ewk_item = (Ewk_Context_Menu_Item *)data;
1405     info("Selected context menu item: %s.", ewk_context_menu_item_title_get(ewk_item));
1406     ewk_context_menu_item_select(ewk_context_menu_item_parent_menu_get(ewk_item), ewk_item);
1407     ewk_context_menu_hide(ewk_context_menu_item_parent_menu_get(ewk_item));
1408 }
1409
1410 static void
1411 context_menu_populate(Evas_Object* context_menu, Ewk_Context_Menu *ewk_menu, Elm_Object_Item *parent_item)
1412 {
1413     if (!context_menu || !ewk_menu) {
1414         info("ERROR: necessary objects are NULL.");
1415         return;
1416     }
1417
1418     const Eina_List *list = ewk_context_menu_items_get(ewk_menu);
1419     const Eina_List *l;
1420     void *data;
1421
1422     Ewk_Context_Menu_Item *ewk_item;
1423     Elm_Object_Item *elm_menu_item;
1424     Evas_Object *elm_check_item;
1425
1426     EINA_LIST_FOREACH(list, l, data) {
1427         ewk_item = (Ewk_Context_Menu_Item *)data;
1428         switch (ewk_context_menu_item_type_get(ewk_item)) {
1429         case EWK_ACTION_TYPE:
1430             elm_menu_item = elm_menu_item_add(context_menu, parent_item, NULL, ewk_context_menu_item_title_get(ewk_item), context_menu_item_selected_cb, ewk_item);
1431             break;
1432         case EWK_CHECKABLE_ACTION_TYPE:
1433             elm_check_item = elm_check_add(context_menu);
1434             elm_menu_item = elm_menu_item_add(context_menu, parent_item, NULL, ewk_context_menu_item_title_get(ewk_item), context_menu_item_selected_cb, ewk_item);
1435             elm_object_item_content_set(elm_menu_item, elm_check_item);
1436             elm_check_state_set(elm_check_item, ewk_context_menu_item_checked_get(ewk_item));
1437             break;
1438         case EWK_SUBMENU_TYPE:
1439             elm_menu_item = elm_menu_item_add(context_menu, parent_item, NULL, ewk_context_menu_item_title_get(ewk_item), NULL, ewk_item);
1440             if (elm_menu_item)
1441                 context_menu_populate(context_menu, ewk_context_menu_item_submenu_get(ewk_item), elm_menu_item);
1442             break;
1443         default:
1444             continue;
1445         }
1446         elm_object_item_disabled_set(elm_menu_item, !ewk_context_menu_item_enabled_get(ewk_item));
1447     }
1448 }
1449
1450 static Eina_Bool
1451 on_context_menu_show(Ewk_View_Smart_Data *sd, Evas_Coord x, Evas_Coord y, Ewk_Context_Menu *menu)
1452 {
1453     Browser_Window *window = window_find_with_ewk_view(sd->self);
1454
1455     if (!window || !menu) {
1456         info("ERROR: necessary objects are NULL.");
1457         return EINA_FALSE;
1458     }
1459
1460     window->context_menu.elm_menu = elm_menu_add(window->elm_window);
1461
1462     if (!window->context_menu.elm_menu) {
1463         info("ERROR: could not create menu widget.");
1464         return EINA_FALSE;
1465     }
1466
1467     window->context_menu.ewk_menu = menu;
1468
1469     context_menu_populate(window->context_menu.elm_menu, menu, NULL);
1470
1471     info("Showing context menu at (%d, %d).", x, y);
1472     elm_menu_move(window->context_menu.elm_menu, x, y);
1473     evas_object_show(window->context_menu.elm_menu);
1474
1475     return EINA_TRUE;
1476 }
1477
1478 static Eina_Bool
1479 on_context_menu_hide(Ewk_View_Smart_Data *sd)
1480 {
1481     Browser_Window *window = window_find_with_ewk_view(sd->self);
1482
1483     if (!window || !window->context_menu.elm_menu) {
1484         info("ERROR: necessary objects are NULL.");
1485         return EINA_FALSE;
1486     }
1487
1488     elm_menu_close(window->context_menu.elm_menu);
1489     evas_object_del(window->context_menu.elm_menu);
1490     window->context_menu.elm_menu = NULL;
1491     window->context_menu.ewk_menu = NULL;
1492
1493     return EINA_TRUE;
1494 }
1495
1496 static void
1497 auth_popup_close(Auth_Data *auth_data)
1498 {
1499     ewk_object_unref(auth_data->request);
1500     evas_object_del(auth_data->popup);
1501     free(auth_data);
1502 }
1503
1504 static void
1505 on_auth_cancel(void *user_data, Evas_Object *obj, void *event_info)
1506 {
1507     Auth_Data *auth_data = (Auth_Data *)user_data;
1508
1509     ewk_auth_request_cancel(auth_data->request);
1510
1511     auth_popup_close(auth_data);
1512 }
1513
1514 static void
1515 on_auth_ok(void *user_data, Evas_Object *obj, void *event_info)
1516 {
1517     Auth_Data *auth_data = (Auth_Data *)user_data;
1518
1519     const char *username = elm_entry_entry_get(auth_data->username_entry);
1520     const char *password = elm_entry_entry_get(auth_data->password_entry);
1521     ewk_auth_request_authenticate(auth_data->request, username, password);
1522
1523     auth_popup_close(auth_data);
1524 }
1525
1526 static void
1527 on_authentication_request(void *user_data, Evas_Object *obj, void *event_info)
1528 {
1529     Browser_Window *window = (Browser_Window *)user_data;
1530     Ewk_Auth_Request *request = ewk_object_ref((Ewk_Auth_Request *)event_info);
1531
1532     Auth_Data *auth_data = (Auth_Data *)malloc(sizeof(Auth_Data));
1533     auth_data->request = request;
1534
1535     Evas_Object *auth_popup = elm_popup_add(window->elm_window);
1536     auth_data->popup = auth_popup;
1537     evas_object_size_hint_weight_set(auth_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1538     elm_object_part_text_set(auth_popup, "title,text", "Authentication Required");
1539
1540     /* Popup Content */
1541     Evas_Object *vbox = elm_box_add(auth_popup);
1542     elm_box_padding_set(vbox, 0, 4);
1543     evas_object_size_hint_weight_set(vbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1544     evas_object_size_hint_align_set(vbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
1545     elm_object_content_set(auth_popup, vbox);
1546     evas_object_show(vbox);
1547
1548     /* Authentication message */
1549     Evas_Object *label = elm_label_add(auth_popup);
1550     elm_label_line_wrap_set(label, ELM_WRAP_WORD);
1551     Eina_Strbuf *auth_text = eina_strbuf_new();
1552     const char *host = ewk_auth_request_host_get(request);
1553     const char *realm = ewk_auth_request_realm_get(request);
1554     eina_strbuf_append_printf(auth_text, "A username and password are being requested by %s. The site says: \"%s\"", host, realm ? realm : "");
1555     elm_object_text_set(label, eina_strbuf_string_get(auth_text));
1556     eina_strbuf_free(auth_text);
1557     evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1558     evas_object_size_hint_align_set(label, EVAS_HINT_FILL, EVAS_HINT_FILL);
1559     elm_box_pack_end(vbox, label);
1560     evas_object_show(label);
1561
1562     /* Credential table */
1563     Evas_Object *table = elm_table_add(auth_popup);
1564     elm_table_padding_set(table, 2, 2);
1565     elm_table_homogeneous_set(table, EINA_TRUE);
1566     evas_object_size_hint_weight_set(table, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1567     evas_object_size_hint_align_set(table, EVAS_HINT_FILL, EVAS_HINT_FILL);
1568     elm_box_pack_end(vbox, table);
1569     evas_object_show(table);
1570
1571     /* Username row */
1572     Evas_Object *username_label = elm_label_add(auth_popup);
1573     elm_object_text_set(username_label, "Username:");
1574     evas_object_size_hint_weight_set(username_label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1575     evas_object_size_hint_align_set(username_label, 1, EVAS_HINT_FILL);
1576     elm_table_pack(table, username_label, 0, 0, 1, 1);
1577     evas_object_show(username_label);
1578
1579     Evas_Object *username_entry = elm_entry_add(auth_popup);
1580     auth_data->username_entry = username_entry;
1581     elm_entry_scrollable_set(username_entry, EINA_TRUE);
1582     elm_entry_single_line_set(username_entry, EINA_TRUE);
1583     elm_entry_text_style_user_push(username_entry, "DEFAULT='font_size=18'");
1584     const char *suggested_username = ewk_auth_request_suggested_username_get(request);
1585     elm_entry_entry_set(username_entry, suggested_username ? suggested_username : "");
1586     evas_object_size_hint_weight_set(username_entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1587     evas_object_size_hint_align_set(username_entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1588     elm_table_pack(table, username_entry, 1, 0, 2, 1);
1589     elm_object_focus_set(username_entry, EINA_TRUE);
1590     evas_object_show(username_entry);
1591
1592     /* Password row */
1593     Evas_Object *password_label = elm_label_add(auth_popup);
1594     elm_object_text_set(password_label, "Password:");
1595     evas_object_size_hint_weight_set(password_label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1596     evas_object_size_hint_align_set(password_label, 1, EVAS_HINT_FILL);
1597     elm_table_pack(table, password_label, 0, 1, 1, 1);
1598     evas_object_show(password_label);
1599
1600     Evas_Object *password_entry = elm_entry_add(auth_popup);
1601     auth_data->password_entry = password_entry;
1602     elm_entry_scrollable_set(password_entry, EINA_TRUE);
1603     elm_entry_single_line_set(password_entry, EINA_TRUE);
1604     elm_entry_password_set(password_entry, EINA_TRUE);
1605     elm_entry_text_style_user_push(password_entry, "DEFAULT='font_size=18'");
1606     evas_object_size_hint_weight_set(password_entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1607     evas_object_size_hint_align_set(password_entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1608     elm_table_pack(table, password_entry, 1, 1, 2, 1);
1609     evas_object_show(password_entry);
1610
1611     /* Popup buttons */
1612     Evas_Object *cancel_button = elm_button_add(auth_popup);
1613     elm_object_text_set(cancel_button, "Cancel");
1614     elm_object_part_content_set(auth_popup, "button1", cancel_button);
1615     evas_object_smart_callback_add(cancel_button, "clicked", on_auth_cancel, auth_data);
1616     Evas_Object *ok_button = elm_button_add(auth_popup);
1617     elm_object_text_set(ok_button, "OK");
1618     elm_object_part_content_set(auth_popup, "button2", ok_button);
1619     evas_object_smart_callback_add(ok_button, "clicked", on_auth_ok, auth_data);
1620     evas_object_show(auth_popup);
1621 }
1622
1623 static void
1624 on_tooltip_text_set(void *user_data, Evas_Object *obj, void *event_info)
1625 {
1626     Browser_Window *window = (Browser_Window *)user_data;
1627     const char *message = (const char*)event_info;
1628
1629     elm_object_tooltip_text_set(window->elm_window, message);
1630     window->tooltip.text_set = EINA_TRUE;
1631     window_tooltip_update(window);
1632 }
1633
1634 static void
1635 on_tooltip_text_unset(void *user_data, Evas_Object *obj, void *event_info)
1636 {
1637     Browser_Window *window = (Browser_Window *)user_data;
1638
1639     window_tooltip_hide(window);
1640     elm_object_tooltip_unset(window->elm_window);
1641     window->tooltip.text_set = EINA_FALSE;
1642 }
1643
1644 static void
1645 on_home_button_clicked(void *user_data, Evas_Object *home_button, void *event_info)
1646 {
1647     Browser_Window *window = (Browser_Window *)user_data;
1648
1649     ewk_view_url_set(window->ewk_view, DEFAULT_URL);
1650 }
1651
1652 static void
1653 on_window_deletion(void *user_data, Evas_Object *elm_window, void *event_info)
1654 {
1655     window_close(window_find_with_elm_window(elm_window));
1656 }
1657
1658 static Evas_Object *
1659 create_toolbar_button(Evas_Object *elm_window, const char *icon_name)
1660 {
1661     Evas_Object *button = elm_button_add(elm_window);
1662
1663     Evas_Object *icon = elm_icon_add(elm_window);
1664     elm_icon_standard_set(icon, icon_name);
1665     evas_object_size_hint_max_set(icon, TOOL_BAR_ICON_SIZE, TOOL_BAR_ICON_SIZE);
1666     evas_object_color_set(icon, 44, 44, 102, 128);
1667     evas_object_show(icon);
1668     elm_object_part_content_set(button, "icon", icon);
1669     evas_object_size_hint_min_set(button, TOOL_BAR_BUTTON_SIZE, TOOL_BAR_BUTTON_SIZE);
1670
1671     return button;
1672 }
1673
1674 static Browser_Window *window_create(Evas_Object *opener, int width, int height)
1675 {
1676     Browser_Window *window = calloc(1, sizeof(Browser_Window));
1677     if (!window) {
1678         info("ERROR: could not create browser window.");
1679         return NULL;
1680     }
1681
1682     /* Initialize tooltip information */
1683     window->tooltip.show_timer = NULL;
1684     window->tooltip.activated = EINA_FALSE;
1685     window->tooltip.text_set = EINA_FALSE;
1686     window->tooltip.shown = EINA_FALSE;
1687
1688     /* Create window */
1689     window->elm_window = elm_win_add(NULL, "minibrowser-window", ELM_WIN_BASIC);
1690     elm_win_title_set(window->elm_window, APP_NAME);
1691     evas_object_smart_callback_add(window->elm_window, "delete,request", on_window_deletion, &window);
1692
1693     /* Create window background */
1694     Evas_Object *bg = elm_bg_add(window->elm_window);
1695     elm_bg_color_set(bg, 193, 192, 191);
1696     evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1697     elm_win_resize_object_add(window->elm_window, bg);
1698     evas_object_show(bg);
1699
1700     /* Create vertical layout */
1701     Evas_Object *vertical_layout = elm_box_add(window->elm_window);
1702     elm_box_padding_set(vertical_layout, 0, 2);
1703     evas_object_size_hint_weight_set(vertical_layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1704     elm_win_resize_object_add(window->elm_window, vertical_layout);
1705     evas_object_show(vertical_layout);
1706
1707     /* Create horizontal layout for top bar */
1708     Evas_Object *horizontal_layout = elm_box_add(window->elm_window);
1709     elm_box_horizontal_set(horizontal_layout, EINA_TRUE);
1710     evas_object_size_hint_weight_set(horizontal_layout, EVAS_HINT_EXPAND, 0.0);
1711     evas_object_size_hint_align_set(horizontal_layout, EVAS_HINT_FILL, 0.0);
1712     elm_box_pack_end(vertical_layout, horizontal_layout);
1713     evas_object_show(horizontal_layout);
1714
1715     /* Create Back button */
1716     window->back_button = create_toolbar_button(window->elm_window, "arrow_left");
1717     evas_object_smart_callback_add(window->back_button, "clicked", on_back_button_clicked, window);
1718     elm_object_disabled_set(window->back_button, EINA_TRUE);
1719     evas_object_size_hint_weight_set(window->back_button, 0.0, EVAS_HINT_EXPAND);
1720     evas_object_size_hint_align_set(window->back_button, 0.0, 0.5);
1721     elm_box_pack_end(horizontal_layout, window->back_button);
1722     evas_object_show(window->back_button);
1723
1724     /* Create Forward button */
1725     window->forward_button = create_toolbar_button(window->elm_window, "arrow_right");
1726     evas_object_smart_callback_add(window->forward_button, "clicked", on_forward_button_clicked, window);
1727     elm_object_disabled_set(window->forward_button, EINA_TRUE);
1728     evas_object_size_hint_weight_set(window->forward_button, 0.0, EVAS_HINT_EXPAND);
1729     evas_object_size_hint_align_set(window->forward_button, 0.0, 0.5);
1730     elm_box_pack_end(horizontal_layout, window->forward_button);
1731     evas_object_show(window->forward_button);
1732
1733     /* Create URL bar */
1734     window->url_bar = elm_entry_add(window->elm_window);
1735     elm_entry_scrollable_set(window->url_bar, EINA_TRUE);
1736     elm_entry_scrollbar_policy_set(window->url_bar, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
1737     elm_entry_single_line_set(window->url_bar, EINA_TRUE);
1738     elm_entry_cnp_mode_set(window->url_bar, ELM_CNP_MODE_PLAINTEXT);
1739     elm_entry_text_style_user_push(window->url_bar, "DEFAULT='font_size=18'");
1740     evas_object_smart_callback_add(window->url_bar, "activated", on_url_bar_activated, window);
1741     evas_object_smart_callback_add(window->url_bar, "clicked", on_url_bar_clicked, window);
1742     evas_object_size_hint_weight_set(window->url_bar, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1743     evas_object_size_hint_align_set(window->url_bar, EVAS_HINT_FILL, EVAS_HINT_FILL);
1744     elm_box_pack_end(horizontal_layout, window->url_bar);
1745     evas_object_show(window->url_bar);
1746
1747     /* Create Refresh button */
1748     Evas_Object *refresh_button = create_toolbar_button(window->elm_window, "refresh");
1749     evas_object_smart_callback_add(refresh_button, "clicked", on_refresh_button_clicked, window);
1750     evas_object_size_hint_weight_set(refresh_button, 0.0, EVAS_HINT_EXPAND);
1751     evas_object_size_hint_align_set(refresh_button, 1.0, 0.5);
1752     elm_box_pack_end(horizontal_layout, refresh_button);
1753     evas_object_show(refresh_button);
1754
1755     /* Create Home button */
1756     Evas_Object *home_button = create_toolbar_button(window->elm_window, "home");
1757     evas_object_smart_callback_add(home_button, "clicked", on_home_button_clicked, window);
1758     evas_object_size_hint_weight_set(home_button, 0.0, EVAS_HINT_EXPAND);
1759     evas_object_size_hint_align_set(home_button, 1.0, 0.5);
1760     elm_box_pack_end(horizontal_layout, home_button);
1761     evas_object_show(home_button);
1762
1763     /* Create Search bar */
1764     window->search.search_bar = elm_box_add(window->elm_window);
1765     elm_box_horizontal_set(window->search.search_bar, EINA_TRUE);
1766     evas_object_size_hint_min_set(window->search.search_bar, SEARCH_FIELD_SIZE + 2 * SEARCH_BUTTON_SIZE, 0);
1767     evas_object_size_hint_align_set(window->search.search_bar, 0.0, EVAS_HINT_FILL);
1768     elm_box_pack_end(vertical_layout, window->search.search_bar);
1769
1770     /* Create Search field */
1771     window->search.search_field = elm_entry_add(window->elm_window);
1772     elm_entry_scrollable_set(window->search.search_field, EINA_TRUE);
1773     elm_entry_scrollbar_policy_set(window->search.search_field, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
1774     elm_entry_single_line_set(window->search.search_field, EINA_TRUE);
1775     elm_entry_cnp_mode_set(window->search.search_field, ELM_CNP_MODE_PLAINTEXT);
1776     elm_entry_text_style_user_push(window->search.search_field, "DEFAULT='font_size=14'");
1777     evas_object_smart_callback_add(window->search.search_field, "activated", on_search_field_activated, window);
1778     evas_object_smart_callback_add(window->search.search_field, "changed", on_search_field_activated, window);
1779     evas_object_smart_callback_add(window->search.search_field, "aborted", on_search_field_aborted, window);
1780     evas_object_smart_callback_add(window->search.search_field, "clicked", on_search_field_clicked, window);
1781     evas_object_size_hint_weight_set(window->search.search_field, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1782     evas_object_size_hint_align_set(window->search.search_field, EVAS_HINT_FILL, EVAS_HINT_FILL);
1783     elm_box_pack_end(window->search.search_bar, window->search.search_field);
1784
1785     /* Create Search backward button */
1786     window->search.backward_button = create_toolbar_button(window->elm_window, "arrow_up");
1787     evas_object_smart_callback_add(window->search.backward_button, "clicked", on_search_backward_button_clicked, window);
1788     elm_object_disabled_set(window->search.backward_button, EINA_FALSE);
1789     evas_object_size_hint_weight_set(window->search.backward_button, 0.0, EVAS_HINT_EXPAND);
1790     evas_object_size_hint_align_set(window->search.backward_button, 1.0, 0.5);
1791     evas_object_size_hint_min_set(window->search.backward_button, SEARCH_BUTTON_SIZE, SEARCH_BUTTON_SIZE);
1792     elm_box_pack_end(window->search.search_bar, window->search.backward_button);
1793
1794     /* Create Search forwardward button */
1795     window->search.forward_button = create_toolbar_button(window->elm_window, "arrow_down");
1796     evas_object_smart_callback_add(window->search.forward_button, "clicked", on_search_forward_button_clicked, window);
1797     elm_object_disabled_set(window->search.forward_button, EINA_FALSE);
1798     evas_object_size_hint_weight_set(window->search.forward_button, 0.0, EVAS_HINT_EXPAND);
1799     evas_object_size_hint_align_set(window->search.forward_button, 1.0, 0.5);
1800     evas_object_size_hint_min_set(window->search.forward_button, SEARCH_BUTTON_SIZE, SEARCH_BUTTON_SIZE);
1801     elm_box_pack_end(window->search.search_bar, window->search.forward_button);
1802
1803     /* Create ewk_view */
1804     Ewk_View_Smart_Class *ewkViewClass = miniBrowserViewSmartClass();
1805     ewkViewClass->run_javascript_alert = on_javascript_alert;
1806     ewkViewClass->run_javascript_confirm = on_javascript_confirm;
1807     ewkViewClass->run_javascript_prompt = on_javascript_prompt;
1808     ewkViewClass->window_geometry_get = on_window_geometry_get;
1809     ewkViewClass->window_geometry_set = on_window_geometry_set;
1810     ewkViewClass->fullscreen_enter = on_fullscreen_enter;
1811     ewkViewClass->fullscreen_exit = on_fullscreen_exit;
1812     ewkViewClass->window_create = on_window_create;
1813     ewkViewClass->window_close = on_window_close;
1814     ewkViewClass->popup_menu_show = on_popup_menu_show;
1815     ewkViewClass->popup_menu_hide = on_popup_menu_hide;
1816     ewkViewClass->context_menu_show = on_context_menu_show;
1817     ewkViewClass->context_menu_hide = on_context_menu_hide;
1818     ewkViewClass->input_picker_color_request = on_color_picker_request;
1819     ewkViewClass->input_picker_color_dismiss = on_color_picker_dismiss;
1820
1821     Evas *evas = evas_object_evas_get(window->elm_window);
1822     Evas_Smart *smart = evas_smart_class_new(&ewkViewClass->sc);
1823     Ewk_Context *context = opener ? ewk_view_context_get(opener) : ewk_context_default_get();
1824     Ewk_Page_Group *pageGroup = opener ? ewk_view_page_group_get(opener) : ewk_page_group_create("");
1825     window->ewk_view = ewk_view_smart_add(evas, smart, context, pageGroup);
1826
1827     ewk_view_theme_set(window->ewk_view, TEST_THEME_DIR "/default.edj");
1828     if (device_pixel_ratio)
1829         ewk_view_device_pixel_ratio_set(window->ewk_view, (float)device_pixel_ratio);
1830     ewk_view_user_agent_set(window->ewk_view, user_agent_string);
1831     ewk_view_layout_fixed_set(window->ewk_view, fixed_layout_enabled);
1832
1833     if (touch_events_enabled) {
1834         ewk_view_touch_events_enabled_set(window->ewk_view, EINA_TRUE);
1835         ewk_view_mouse_events_enabled_set(window->ewk_view, EINA_FALSE);
1836     }
1837
1838     /* Set the zoom level to default */
1839     window->current_zoom_level = DEFAULT_ZOOM_LEVEL;
1840
1841     Ewk_Settings *settings = ewk_view_settings_get(window->ewk_view);
1842     ewk_settings_file_access_from_file_urls_allowed_set(settings, EINA_TRUE);
1843     ewk_settings_encoding_detector_enabled_set(settings, encoding_detector_enabled);
1844     ewk_settings_frame_flattening_enabled_set(settings, frame_flattening_enabled);
1845     ewk_settings_local_storage_enabled_set(settings, local_storage_enabled);
1846     info("HTML5 local storage is %s for this view.", local_storage_enabled ? "enabled" : "disabled");
1847     elm_win_fullscreen_set(window->elm_window, fullscreen_enabled);
1848     ewk_settings_developer_extras_enabled_set(settings, EINA_TRUE);
1849     ewk_settings_preferred_minimum_contents_width_set(settings, 0);
1850     ewk_text_checker_continuous_spell_checking_enabled_set(spell_checking_enabled);
1851
1852     evas_object_smart_callback_add(window->ewk_view, "authentication,request", on_authentication_request, window);
1853     evas_object_smart_callback_add(window->ewk_view, "download,failed", on_download_failed, window);
1854     evas_object_smart_callback_add(window->ewk_view, "download,finished", on_download_finished, window);
1855     evas_object_smart_callback_add(window->ewk_view, "download,request", on_download_request, window);
1856     evas_object_smart_callback_add(window->ewk_view, "file,chooser,request", on_file_chooser_request, window);
1857     evas_object_smart_callback_add(window->ewk_view, "favicon,changed", on_view_favicon_changed, window);
1858     evas_object_smart_callback_add(window->ewk_view, "load,error", on_error, window);
1859     evas_object_smart_callback_add(window->ewk_view, "load,provisional,failed", on_error, window);
1860     evas_object_smart_callback_add(window->ewk_view, "load,progress", on_progress, window);
1861     evas_object_smart_callback_add(window->ewk_view, "title,changed", on_title_changed, window);
1862     evas_object_smart_callback_add(window->ewk_view, "url,changed", on_url_changed, window);
1863     evas_object_smart_callback_add(window->ewk_view, "back,forward,list,changed", on_back_forward_list_changed, window);
1864     evas_object_smart_callback_add(window->ewk_view, "tooltip,text,set", on_tooltip_text_set, window);
1865     evas_object_smart_callback_add(window->ewk_view, "tooltip,text,unset", on_tooltip_text_unset, window);
1866
1867     evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_KEY_DOWN, on_key_down, window);
1868     evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_MOUSE_DOWN, on_mouse_down, window);
1869
1870     evas_object_size_hint_weight_set(window->ewk_view, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1871     evas_object_size_hint_align_set(window->ewk_view, EVAS_HINT_FILL, EVAS_HINT_FILL);
1872     elm_box_pack_before(vertical_layout, window->ewk_view, window->search.search_bar);
1873     evas_object_show(window->ewk_view);
1874
1875     evas_object_resize(window->elm_window, width ? width : window_width, height ? height : window_height);
1876     evas_object_show(window->elm_window);
1877     search_box_hide(window);
1878
1879     view_focus_set(window, EINA_TRUE);
1880
1881     evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_MOUSE_IN, on_mouse_in, window);
1882     evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_MOUSE_OUT, on_mouse_out, window);
1883     evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_MOUSE_MOVE, on_mouse_move, window);
1884     evas_object_event_callback_add(window->elm_window, EVAS_CALLBACK_RESIZE, on_window_resize, window);
1885
1886     return window;
1887 }
1888
1889 static Ewk_Cookie_Accept_Policy
1890 parse_cookies_policy(const char *input_string)
1891 {
1892     if (!strcmp(input_string, "always")) 
1893         return EWK_COOKIE_ACCEPT_POLICY_ALWAYS;
1894     if (!strcmp(input_string, "never"))
1895         return EWK_COOKIE_ACCEPT_POLICY_NEVER;
1896     if (strcmp(input_string, "no-third-party"))
1897         info("Unrecognized type for cookies policy: %s.", input_string);
1898     return EWK_COOKIE_ACCEPT_POLICY_NO_THIRD_PARTY;
1899 }
1900
1901 static void
1902 parse_window_size(const char *input_string, int *width, int *height)
1903 {
1904     static const unsigned max_length = 4;
1905     int parsed_width;
1906     int parsed_height;
1907     char **arr;
1908     unsigned elements;
1909
1910     arr = eina_str_split_full(input_string, "x", 0, &elements);
1911
1912     if (elements == 2 && (strlen(arr[0]) <= max_length) && (strlen(arr[1]) <= max_length)) {
1913         parsed_width = atoi(arr[0]);
1914         if (width && parsed_width)
1915             *width = parsed_width;
1916
1917         parsed_height = atoi(arr[1]);
1918         if (height && parsed_height)
1919             *height = parsed_height;
1920     }
1921
1922     free(arr[0]);
1923     free(arr);
1924 }
1925
1926 EAPI_MAIN int
1927 elm_main(int argc, char *argv[])
1928 {
1929     int args = 1;
1930     unsigned char quitOption = 0;
1931     Browser_Window *window;
1932     char *window_size_string = NULL;
1933     char *cookies_policy_string = NULL;
1934
1935     Ecore_Getopt_Value values[] = {
1936         ECORE_GETOPT_VALUE_STR(evas_engine_name),
1937         ECORE_GETOPT_VALUE_STR(window_size_string),
1938         ECORE_GETOPT_VALUE_STR(user_agent_string),
1939         ECORE_GETOPT_VALUE_DOUBLE(device_pixel_ratio),
1940         ECORE_GETOPT_VALUE_BOOL(quitOption),
1941         ECORE_GETOPT_VALUE_BOOL(encoding_detector_enabled),
1942         ECORE_GETOPT_VALUE_BOOL(frame_flattening_enabled),
1943         ECORE_GETOPT_VALUE_BOOL(local_storage_enabled),
1944         ECORE_GETOPT_VALUE_BOOL(fullscreen_enabled),
1945         ECORE_GETOPT_VALUE_BOOL(spell_checking_enabled),
1946         ECORE_GETOPT_VALUE_BOOL(touch_events_enabled),
1947         ECORE_GETOPT_VALUE_BOOL(fixed_layout_enabled),
1948         ECORE_GETOPT_VALUE_STR(cookies_policy_string),
1949         ECORE_GETOPT_VALUE_BOOL(quitOption),
1950         ECORE_GETOPT_VALUE_BOOL(quitOption),
1951         ECORE_GETOPT_VALUE_BOOL(quitOption),
1952         ECORE_GETOPT_VALUE_NONE
1953     };
1954
1955     if (!ewk_init())
1956         return EXIT_FAILURE;
1957
1958     ewk_view_smart_class_set(miniBrowserViewSmartClass());
1959
1960     ecore_app_args_set(argc, (const char **) argv);
1961     args = ecore_getopt_parse(&options, values, argc, argv);
1962
1963     if (args < 0)
1964         return quit(EINA_FALSE, "ERROR: could not parse options.\n");
1965
1966     if (quitOption)
1967         return quit(EINA_TRUE, NULL);
1968
1969     if (evas_engine_name)
1970         elm_config_preferred_engine_set(evas_engine_name);
1971 #if defined(HAVE_ECORE_X)
1972     else {
1973         evas_engine_name = "opengl_x11";
1974         elm_config_preferred_engine_set(evas_engine_name);
1975     }
1976 #endif
1977
1978     // Enable favicon database.
1979     Ewk_Context *context = ewk_context_default_get();
1980     ewk_context_favicon_database_directory_set(context, NULL);
1981
1982     if (cookies_policy_string)
1983         ewk_cookie_manager_accept_policy_set(ewk_context_cookie_manager_get(context), parse_cookies_policy(cookies_policy_string));
1984
1985     if (window_size_string)
1986         parse_window_size(window_size_string, &window_width, &window_height);
1987
1988     if (args < argc) {
1989         char *url = url_from_user_input(argv[args]);
1990         window = window_create(NULL, 0, 0);
1991         ewk_view_url_set(window->ewk_view, url);
1992         free(url);
1993     } else {
1994         window = window_create(NULL, 0, 0);
1995         ewk_view_url_set(window->ewk_view, DEFAULT_URL);
1996     }
1997
1998     if (!window)
1999         return quit(EINA_FALSE, "ERROR: could not create browser window.\n");
2000
2001     windows = eina_list_append(windows, window);
2002
2003     elm_run();
2004
2005     return quit(EINA_TRUE, NULL);
2006 }
2007 ELM_MAIN()
2008