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