[EFL] Small clean up in MiniBrowser
[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 <Ecore.h>
22 #include <Ecore_Evas.h>
23 #include <Ecore_Getopt.h>
24 #include <Eet.h>
25 #include <Eina.h>
26 #include <Elementary.h>
27 #include <Evas.h>
28
29 extern int efreet_cache_update;
30
31 static const char DEFAULT_URL[] = "http://www.ewebkit.org/";
32 static const char APP_NAME[] = "EFL MiniBrowser";
33 static const char JAVASCRIPT_SCHEME[] = "javascript:";
34 static const char FILE_SCHEME[] = "file://";
35 static const char HTTP_SCHEME[] = "http://";
36 static const int TOOL_BAR_ICON_SIZE = 24;
37 static const int TOOL_BAR_BUTTON_SIZE = 32;
38 static const int SEARCH_FIELD_SIZE = 200;
39 static const int SEARCH_BUTTON_SIZE = 30;
40 static const int MAX_SEARCH_COUNT = 1000;
41 static const double TOOLTIP_DELAY_SECONDS = 1.0;
42 static const double LONGPRESS_INTERVAL_SECONDS = 1.5;
43 static const double LIST_ITEM_HEIGHT = 24.35;
44
45 static Eina_List *windows = NULL;
46 static char *evas_engine_name = NULL;
47 static char *user_agent_string = NULL;
48 static char *extensions_path = NULL;
49 static char *background_color_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 offline_web_application_cache_enabled = EINA_TRUE;
54 static Eina_Bool fullscreen_enabled = EINA_FALSE;
55 static Eina_Bool spell_checking_enabled = EINA_FALSE;
56 static Eina_Bool web_security_enabled = EINA_TRUE;
57 static Eina_Bool touch_events_enabled = EINA_FALSE;
58 static Eina_Bool fixed_layout_enabled = EINA_TRUE;
59 static Eina_Bool separated_process_enabled = EINA_FALSE;
60 static Eina_Bool longpress_enabled = EINA_FALSE;
61 static int window_width = 1000;
62 static int window_height = 800;
63 static int search_flags = EWK_FIND_OPTIONS_SHOW_HIGHLIGHT | EWK_FIND_OPTIONS_WRAP_AROUND | EWK_FIND_OPTIONS_CASE_INSENSITIVE;
64 /* Default value of device_pixel_ratio is '0' so that we don't set custom device
65  * scale factor unless it's required by the User. */
66 static double device_pixel_ratio = 0;
67 static Eina_Bool legacy_behavior_enabled = EINA_FALSE;
68
69 #define DEFAULT_ZOOM_LEVEL 5 // Set default zoom level to 1.0 (index 5 on zoomLevels).
70 // The zoom values are chosen to be like in Mozilla Firefox 3.
71 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};
72 static int _log_domain_id = -1;
73
74 #define INFO(...) EINA_LOG_DOM_INFO(_log_domain_id, __VA_ARGS__)
75 #define ERROR(...) EINA_LOG_DOM_ERR(_log_domain_id, __VA_ARGS__)
76
77 static Eina_Bool
78 zoom_level_set(Evas_Object *webview, int level)
79 {
80     if (level < 0  || level >= sizeof(zoomLevels) / sizeof(float))
81         return EINA_FALSE;
82
83     return ewk_view_page_zoom_set(webview, zoomLevels[level]);
84 }
85
86 static Ewk_View_Smart_Class *miniBrowserViewSmartClass()
87 {
88     static Ewk_View_Smart_Class ewkViewClass = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION("MiniBrowser_View");
89     return &ewkViewClass;
90 }
91
92 typedef struct _Tooltip_Information {
93     Ecore_Timer *show_timer;
94     Eina_Bool activated;
95     Eina_Bool text_set;
96     Eina_Bool shown;
97 } Tooltip_Information;
98
99 typedef struct _Color_Selector {
100     Ewk_Color_Picker *ewk_picker;
101     Evas_Object *elm_selector;
102     Evas_Object *elm_selector_window;
103 } Color_Selector;
104
105 typedef struct _Browser_Window {
106     Evas_Object *elm_window;
107     Evas_Object *ewk_view;
108     Evas_Object *horizontal_layout;
109     Evas_Object *vertical_layout;
110     Evas_Object *url_bar;
111     Evas_Object *back_button;
112     Evas_Object *forward_button;
113     struct {
114         Evas_Object *elm_menu;
115         Ewk_Popup_Menu *ewk_menu;
116     } popup;
117     struct {
118         Evas_Object *search_bar;
119         Evas_Object *search_field;
120         Evas_Object *search_field_count;
121         Evas_Object *backward_button;
122         Evas_Object *forward_button;
123         Evas_Object *search_case_check_box;
124         Evas_Object *search_word_start_check_box;
125         Evas_Object *close_button;
126     } search;
127     struct {
128         Evas_Object *history_box;
129         Evas_Object *history_list;
130         Eina_List *history_list_items;
131     } history;
132     int current_zoom_level;
133     Tooltip_Information tooltip;
134     Color_Selector color_selector;
135     struct {
136         Evas_Object *elm_menu;
137         Ewk_Context_Menu *ewk_menu;
138     } context_menu;
139 } Browser_Window;
140
141 typedef struct _File_Selector_Data {
142     Browser_Window* parent;
143     Evas_Object *elm_window;
144     Ewk_File_Chooser_Request *request;
145 } File_Selector_Data;
146
147 typedef struct _Auth_Data {
148     Evas_Object *popup;
149     Ewk_Auth_Request *request;
150     Evas_Object *username_entry;
151     Evas_Object *password_entry;
152 } Auth_Data;
153
154 static const Ecore_Getopt options = {
155     "MiniBrowser",
156     "%prog [options] [url]",
157     "0.0.1",
158     "(C)2012 Samsung Electronics\n (C)2012 Intel Corporation\n",
159     "",
160     "Test Web Browser using the Enlightenment Foundation Libraries (EFL) port of WebKit2",
161     EINA_TRUE, {
162         ECORE_GETOPT_STORE_STR
163             ('e', "engine", "Ecore-evas engine to use."),
164         ECORE_GETOPT_STORE_STR
165             ('s', "window-size", "Window size in following format (width)x(height)."),
166         ECORE_GETOPT_STORE_STR
167             ('u', "user-agent", "User agent to set."),
168         ECORE_GETOPT_STORE_STR
169             ('x', "extensions-path", "The path which extensions are stored."),
170         ECORE_GETOPT_STORE_DOUBLE
171             ('r', "device-pixel-ratio", "Ratio between the CSS units and device pixels."),
172         ECORE_GETOPT_CALLBACK_NOARGS
173             ('E', "list-engines", "List ecore-evas engines.",
174              ecore_getopt_callback_ecore_evas_list_engines, NULL),
175         ECORE_GETOPT_STORE_DEF_BOOL
176             ('c', "encoding-detector", "Enable/disable encoding detector.", EINA_FALSE),
177         ECORE_GETOPT_STORE_STR
178             ('C', "background-color", "Background color of page. ex) -C=255:255:255:255"),
179         ECORE_GETOPT_STORE_DEF_BOOL
180             ('f', "flattening", "Enable/disable frame flattening.", EINA_FALSE),
181         ECORE_GETOPT_STORE_DEF_BOOL
182             ('l', "local-storage", "Enable/disable HTML5 local storage.", EINA_TRUE),
183         ECORE_GETOPT_STORE_DEF_BOOL
184             ('o', "offline-web-application-cache", "Enable/disable offline web application cache.", EINA_TRUE),
185         ECORE_GETOPT_STORE_DEF_BOOL
186             ('F', "full-screen", "Start in full-screen.", EINA_FALSE),
187         ECORE_GETOPT_STORE_DEF_BOOL
188             ('t', "text-checking", "Enable/disable text spell checking.", EINA_FALSE),
189         ECORE_GETOPT_STORE_DEF_BOOL
190             ('T', "touch-events", "Enable/disable touch events.", EINA_FALSE),
191         ECORE_GETOPT_STORE_DEF_BOOL
192             ('L', "fixed-layout", "Enable/disable fixed layout.", EINA_TRUE),
193         ECORE_GETOPT_STORE_DEF_STR
194             ('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"),
195         ECORE_GETOPT_STORE_DEF_BOOL
196             ('w', "web-security", "enable/disable web security.", EINA_TRUE),
197         ECORE_GETOPT_STORE_DEF_BOOL
198             ('S', "separate-process", "Create new window in separated web process.", EINA_FALSE),
199         ECORE_GETOPT_VERSION
200             ('V', "version"),
201         ECORE_GETOPT_COPYRIGHT
202             ('R', "copyright"),
203         ECORE_GETOPT_HELP
204             ('h', "help"),
205         ECORE_GETOPT_SENTINEL
206     }
207 };
208
209 static Eina_Stringshare *show_file_entry_dialog(Browser_Window *window, const char *label_tag, const char *default_text);
210 static Browser_Window *window_create(Ewk_View_Configuration* configuration, int width, int height);
211 static Ewk_View_Configuration* configuration();
212
213 static Browser_Window *window_find_with_elm_window(Evas_Object *elm_window)
214 {
215     Eina_List *l;
216     void *data;
217
218     if (!elm_window)
219         return NULL;
220
221     EINA_LIST_FOREACH(windows, l, data) {
222         Browser_Window *window = (Browser_Window *)data;
223         if (window->elm_window == elm_window)
224             return window;
225     }
226     return NULL;
227 }
228
229 static Browser_Window *window_find_with_ewk_view(Evas_Object *ewk_view)
230 {
231     Eina_List *l;
232     void *data;
233
234     if (!ewk_view)
235         return NULL;
236
237     EINA_LIST_FOREACH(windows, l, data) {
238         Browser_Window *window = (Browser_Window *)data;
239         if (window->ewk_view == ewk_view)
240             return window;
241     }
242     return NULL;
243 }
244
245 static Eina_Bool
246 on_tooltip_show(void *user_data)
247 {
248     Browser_Window *window = (Browser_Window *)user_data;
249
250     window->tooltip.show_timer = NULL;
251     elm_object_tooltip_show(window->elm_window);
252     window->tooltip.shown = EINA_TRUE;
253     return ECORE_CALLBACK_CANCEL;
254 }
255
256 static void
257 window_tooltip_hide(Browser_Window *window)
258 {
259     if (window->tooltip.show_timer) {
260         ecore_timer_del(window->tooltip.show_timer);
261         window->tooltip.show_timer = NULL;
262     }
263
264     if (window->tooltip.shown) {
265         elm_object_tooltip_hide(window->elm_window);
266         window->tooltip.shown = EINA_FALSE;
267     }
268 }
269
270 static void
271 window_tooltip_update(Browser_Window *window)
272 {
273     window_tooltip_hide(window);
274
275     if (window->tooltip.activated && window->tooltip.text_set)
276         window->tooltip.show_timer = ecore_timer_add(TOOLTIP_DELAY_SECONDS, on_tooltip_show, window);
277 }
278
279 static void
280 on_mouse_in(void *user_data, Evas *e, Evas_Object *ewk_view, void *event_info)
281 {
282     Browser_Window *window = (Browser_Window *)user_data;
283
284     window->tooltip.activated = EINA_TRUE;
285     window_tooltip_update(window);
286 }
287
288 static void
289 on_mouse_move(void *user_data, Evas *e, Evas_Object *ewk_view, void *event_info)
290 {
291     window_tooltip_update((Browser_Window *)user_data);
292 }
293
294 static void
295 on_mouse_out(void *user_data, Evas *e, Evas_Object *ewk_view, void *event_info)
296 {
297     Browser_Window *window = (Browser_Window *)user_data;
298
299     window->tooltip.activated = EINA_FALSE;
300     window_tooltip_update(window);
301 }
302
303 static void
304 on_mouse_wheel(void *user_data, Evas *e, Evas_Object *ewk_view, void *event_info)
305 {
306     Browser_Window *window = (Browser_Window *)user_data;
307     const Evas_Modifier *mod = evas_key_modifier_get(e);
308     Evas_Event_Mouse_Wheel *ev = (Evas_Event_Mouse_Wheel *)event_info;
309     Eina_Bool shiftPressed = evas_key_modifier_is_set(mod, "Shift");
310     Eina_Bool ctrlPressed = evas_key_modifier_is_set(mod, "Control");
311
312     if (!shiftPressed && !ctrlPressed)
313         return;
314
315     /* navigate history or zoom web page based on mouse wheel scroll action with shift or control key */
316     if (shiftPressed) {
317         if (ev->z == -1 && ewk_view_forward_possible(ewk_view)) {
318             ewk_view_forward(ewk_view);
319             elm_object_disabled_set(window->forward_button, !ewk_view_forward_possible(ewk_view));
320         } else if (ev->z == 1 && ewk_view_back_possible(ewk_view)) {
321             ewk_view_back(ewk_view);
322             elm_object_disabled_set(window->back_button, !ewk_view_back_possible(ewk_view));
323         }
324     } else if (ctrlPressed) {
325         if (ev->z == -1 && zoom_level_set(ewk_view, window->current_zoom_level + 1)) {
326             window->current_zoom_level++;
327             INFO("Zoom in (Ctrl + 'scroll up') was pressed, zoom level became %.2f", zoomLevels[window->current_zoom_level]);
328         } else if (ev->z == 1 && zoom_level_set(ewk_view, window->current_zoom_level - 1)) {
329             window->current_zoom_level--;
330             INFO("Zoom out (Ctrl + 'scroll down') was pressed, zoom level became %.2f", zoomLevels[window->current_zoom_level]);
331         }
332     }
333 }
334
335 static void
336 on_window_resize(void *user_data, Evas *e, Evas_Object *elm_window, void *event_info)
337 {
338     Browser_Window *window = (Browser_Window *)user_data;
339
340     if (!window) {
341         ERROR("Window is NULL.");
342         return;
343     }
344
345     if (window->context_menu.ewk_menu)
346         ewk_context_menu_hide(window->context_menu.ewk_menu);
347     if (window->popup.ewk_menu)
348         ewk_popup_menu_close(window->popup.ewk_menu);
349     if (window->popup.elm_menu)
350         elm_menu_close(window->popup.elm_menu);
351 }
352
353 static void
354 update_view_favicon(Browser_Window *window, Evas_Object *icon)
355 {
356     /* Remove previous icon from URL bar */
357     Evas_Object *old_icon = elm_object_part_content_unset(window->url_bar, "icon");
358     if (old_icon) {
359         evas_object_unref(old_icon);
360         evas_object_del(old_icon);
361     }
362
363     /* Show new icon in URL bar */
364     if (icon) {
365         evas_object_size_hint_min_set(icon, 32, 32);
366         elm_object_part_content_set(window->url_bar, "icon", icon);
367         evas_object_ref(icon);
368     }
369 }
370
371 static void
372 on_icon_changed_cb(Ewk_Favicon_Database *database, const char *url, void *user_data)
373 {
374     Browser_Window *window = (Browser_Window *)user_data;
375     Evas_Object *ewk_view = window->ewk_view;
376
377     if (strcmp(url, ewk_view_url_get(ewk_view)))
378         return;
379
380     Evas_Object *favicon = ewk_favicon_database_icon_get(database, url, evas_object_evas_get(ewk_view));
381     update_view_favicon(window, favicon);
382
383     if (favicon)
384         evas_object_unref(favicon);
385 }
386
387 static void window_free(Browser_Window *window)
388 {
389     evas_object_event_callback_del(window->ewk_view, EVAS_CALLBACK_MOUSE_IN, on_mouse_in);
390     evas_object_event_callback_del(window->ewk_view, EVAS_CALLBACK_MOUSE_OUT, on_mouse_out);
391     evas_object_event_callback_del(window->ewk_view, EVAS_CALLBACK_MOUSE_MOVE, on_mouse_move);
392     evas_object_event_callback_del(window->ewk_view, EVAS_CALLBACK_MOUSE_WHEEL, on_mouse_wheel);
393
394     evas_object_event_callback_del(window->elm_window, EVAS_CALLBACK_RESIZE, on_window_resize);
395
396     ewk_favicon_database_icon_change_callback_del(ewk_context_favicon_database_get(ewk_view_context_get(window->ewk_view)), on_icon_changed_cb);
397
398     evas_object_del(window->ewk_view);
399     /* The elm_win will take care of freeing its children */
400     evas_object_del(window->elm_window);
401
402     if (window->tooltip.show_timer)
403         ecore_timer_del(window->tooltip.show_timer);
404
405     if (window->color_selector.elm_selector_window)
406         evas_object_del(window->color_selector.elm_selector_window);
407
408     free(window);
409 }
410
411 static void window_close(Browser_Window *window)
412 {
413     windows = eina_list_remove(windows, window);
414     window_free(window);
415
416     if (!windows)
417         elm_exit();
418 }
419
420 static void
421 search_icon_show(Browser_Window *window)
422 {
423     Evas_Object *icon = elm_icon_add(window->elm_window);
424     elm_icon_standard_set(icon, "edit-find");
425     elm_object_part_content_set(window->search.search_field, "icon", icon);
426     evas_object_size_hint_min_set(icon, 20, 20);
427     evas_object_size_hint_max_set(icon, 20, 20);
428     elm_entry_icon_visible_set(window->search.search_field, EINA_TRUE);
429     evas_object_show(icon);
430 }
431
432 static void
433 search_box_show(Browser_Window *window)
434 {
435     evas_object_size_hint_min_set(window->search.search_bar, SEARCH_FIELD_SIZE + 2 * SEARCH_BUTTON_SIZE, SEARCH_BUTTON_SIZE);
436
437     search_icon_show(window);
438     evas_object_show(window->search.search_bar);
439     evas_object_show(window->search.search_field);
440     evas_object_show(window->search.search_field_count);
441     evas_object_show(window->search.backward_button);
442     evas_object_show(window->search.forward_button);
443     evas_object_show(window->search.search_case_check_box);
444     evas_object_show(window->search.search_word_start_check_box);
445     evas_object_show(window->search.close_button);
446
447     /* Grab focus from the view */
448     evas_object_focus_set(window->ewk_view, EINA_FALSE);
449     elm_object_focus_set(window->search.search_field, EINA_TRUE);
450 }
451
452 static void
453 search_box_hide(Browser_Window *window)
454 {
455     ewk_view_text_find_highlight_clear(window->ewk_view);
456
457     evas_object_size_hint_min_set(window->search.search_bar, SEARCH_FIELD_SIZE + 2 * SEARCH_BUTTON_SIZE, 0);
458     evas_object_hide(window->search.search_bar);
459     evas_object_hide(window->search.search_field);
460     evas_object_hide(window->search.search_field_count);
461     evas_object_hide(window->search.backward_button);
462     evas_object_hide(window->search.forward_button);
463     evas_object_hide(window->search.search_case_check_box);
464     evas_object_hide(window->search.search_word_start_check_box);
465     evas_object_hide(window->search.close_button);
466
467     /* Give focus back to the view */
468     elm_object_focus_set(window->search.search_field, EINA_FALSE);
469     evas_object_focus_set(window->ewk_view, EINA_TRUE);
470 }
471
472 static void
473 history_list_hide(Browser_Window *window)
474 {
475     /* Hide history list */
476     evas_object_hide(window->history.history_box);
477     evas_object_hide(window->history.history_list);
478
479     /* Dereference the list items and clear the history list */
480     void *data;
481     EINA_LIST_FREE(window->history.history_list_items, data) {
482         ewk_object_unref(data);
483     }
484
485     elm_genlist_clear(window->history.history_list);
486
487     /* Give focus back to the view */
488     elm_object_focus_set(window->history.history_box, EINA_FALSE);
489     elm_object_focus_set(window->history.history_list, EINA_FALSE);
490     evas_object_focus_set(window->ewk_view, EINA_TRUE);
491
492     /* Reset flags */
493     longpress_enabled = EINA_FALSE;
494 }
495
496 static void save_page_contents_callback(Ewk_Page_Contents_Type type, const char *data, void *user_data)
497 {
498     Eet_File *ef;
499     Eina_Stringshare *fileName = (Eina_Stringshare *)user_data;
500
501     if (!eina_str_has_extension(fileName, ".mht")) {
502         Eina_Strbuf *fileNameWithMht = eina_strbuf_new();
503         eina_strbuf_append_printf(fileNameWithMht, "%s.mht", fileName);
504         ef = eet_open(eina_strbuf_string_get(fileNameWithMht), EET_FILE_MODE_WRITE);
505         INFO("Saving file to: %s", eina_strbuf_string_get(fileNameWithMht));
506         eina_strbuf_free(fileNameWithMht);
507     } else {
508         ef = eet_open(fileName, EET_FILE_MODE_WRITE);
509         INFO("Saving file to: %s", fileName);
510     }
511
512     if (!ef) {
513         ERROR("Could not create File");
514         return;
515     }
516
517     eet_write(ef, "MHTML data", data, strlen(data), 0 /* compress */);
518     eet_close(ef);
519     INFO("SUCCESS: saved.");
520
521     eina_stringshare_del(fileName);
522 }
523
524 static void
525 script_execute_callback(Evas_Object *ewk_view, const char *return_value, void *user_data)
526 {
527     Browser_Window *window = (Browser_Window *)user_data;
528
529     Eina_Strbuf *text_buffer = eina_strbuf_new();
530
531     if (return_value) {
532         eina_strbuf_append(text_buffer, return_value);
533         INFO("selected text is: %s", eina_strbuf_string_get(text_buffer));
534         elm_entry_entry_set(window->search.search_field, eina_strbuf_string_get(text_buffer));
535     }
536     eina_strbuf_free(text_buffer);
537     search_box_show(window);
538 }
539
540 static void
541 toggle_window_fullscreen(Browser_Window *window, Eina_Bool isFullScreen)
542 {
543     if (isFullScreen) {
544         evas_object_hide(window->horizontal_layout);
545         elm_box_unpack(window->vertical_layout, window->horizontal_layout);
546         elm_win_fullscreen_set(window->elm_window, EINA_TRUE);
547     } else {
548         elm_win_fullscreen_set(window->elm_window, EINA_FALSE);
549         elm_box_pack_start(window->vertical_layout, window->horizontal_layout);
550         evas_object_show(window->horizontal_layout);
551     }
552 }
553
554 static void
555 on_key_down(void *user_data, Evas *e, Evas_Object *ewk_view, void *event_info)
556 {
557     Browser_Window *window = (Browser_Window *)user_data;
558     Evas_Event_Key_Down *ev = (Evas_Event_Key_Down*) event_info;
559
560     static const char *encodings[] = {
561         "ISO-8859-1",
562         "UTF-8",
563         NULL
564     };
565     static int currentEncoding = -1;
566     const Evas_Modifier *mod = evas_key_modifier_get(e);
567     Eina_Bool ctrlPressed = evas_key_modifier_is_set(mod, "Control");
568     Eina_Bool altPressed = evas_key_modifier_is_set(mod, "Alt");
569     Eina_Bool shiftPressed = evas_key_modifier_is_set(mod, "Shift");
570
571     if (!strcmp(ev->key, "Left") && altPressed) {
572         INFO("Back (Alt+Left) was pressed");
573         if (!ewk_view_back(ewk_view))
574             INFO("Back ignored: No back history");
575     } else if (!strcmp(ev->key, "Right") && altPressed) {
576         INFO("Forward (Alt+Right) was pressed");
577         if (!ewk_view_forward(ewk_view))
578             INFO("Forward ignored: No forward history");
579     } else if (!strcmp(ev->key, "Home") && altPressed) {
580         INFO("Home (Alt+Home) was pressed");
581         ewk_view_url_set(window->ewk_view, DEFAULT_URL);
582     } else if (!strcmp(ev->key, "F3")) {
583         currentEncoding = (currentEncoding + 1) % (sizeof(encodings) / sizeof(encodings[0]));
584         INFO("Set encoding (F3) pressed. New encoding to %s", encodings[currentEncoding]);
585         ewk_view_custom_encoding_set(ewk_view, encodings[currentEncoding]);
586     } else if ((!strcmp(ev->key, "F5") && ctrlPressed) || (!strcmp(ev->key, "r") && (shiftPressed & ctrlPressed))) {
587         INFO("Reload ignoring cache (Ctrl+F5 or Ctrl+Shift+r) was pressed, reloading and bypassing cache...");
588         ewk_view_reload_bypass_cache(ewk_view);
589     } else if (!strcmp(ev->key, "F5") || (!strcmp(ev->key, "r") && ctrlPressed)) {
590         INFO("Reload (F5 or Ctrl+r) was pressed, reloading...");
591         ewk_view_reload(ewk_view);
592     } else if (!strcmp(ev->key, "F6")) {
593         INFO("Stop (F6) was pressed, stop loading.");
594         ewk_view_stop(ewk_view);
595     } else if (!strcmp(ev->key, "F7")) {
596         Ewk_Pagination_Mode mode =  ewk_view_pagination_mode_get(ewk_view);
597         mode = (mode + 1) % (EWK_PAGINATION_MODE_BOTTOM_TO_TOP + 1);
598         if (ewk_view_pagination_mode_set(ewk_view, mode))
599             INFO("Change Pagination Mode (F7) was pressed, changed to: %d", mode);
600         else
601             INFO("Change Pagination Mode (F7) was pressed, but NOT changed!");
602     } else if (!strcmp(ev->key, "F11")) {
603         INFO("Fullscreen (F11) was pressed, toggling window/fullscreen.");
604         toggle_window_fullscreen(window, !elm_win_fullscreen_get(window->elm_window));
605     } else if (!strcmp(ev->key, "n") && ctrlPressed) {
606         INFO("Create new window (Ctrl+n) was pressed.");
607         Browser_Window *window = window_create(configuration(), 0, 0);
608         ewk_view_url_set(window->ewk_view, DEFAULT_URL);
609         // 0 equals default width and height.
610         windows = eina_list_append(windows, window);
611     } else if (!strcmp(ev->key, "i") && ctrlPressed) {
612         INFO("Show Inspector (Ctrl+i) was pressed.");
613         ewk_view_inspector_show(ewk_view);
614     } else if (!strcmp(ev->key, "f") && ctrlPressed) {
615         INFO("Show Search Box (Ctrl+f) was pressed.");
616         const char get_data_script[] = "window.getSelection().toString();";
617         ewk_view_script_execute(ewk_view, get_data_script, script_execute_callback, (void*)(window));
618     } else if (!strcmp(ev->key, "Escape")) {
619         if (evas_object_visible_get(window->search.search_bar))
620             search_box_hide(window);
621         else if (evas_object_visible_get(window->history.history_box))
622             history_list_hide(window);
623         else if (elm_win_fullscreen_get(window->elm_window))
624             ewk_view_fullscreen_exit(ewk_view);
625         else
626             ewk_view_stop(ewk_view);
627     } else if (ctrlPressed && (!strcmp(ev->key, "minus") || !strcmp(ev->key, "KP_Subtract"))) {
628         if (zoom_level_set(ewk_view, window->current_zoom_level - 1))
629             window->current_zoom_level--;
630         INFO("Zoom out (Ctrl + '-') was pressed, zoom level became %.2f", zoomLevels[window->current_zoom_level]);
631     } else if (ctrlPressed && (!strcmp(ev->key, "equal") || !strcmp(ev->key, "KP_Add"))) {
632         if (zoom_level_set(ewk_view, window->current_zoom_level + 1))
633             window->current_zoom_level++;
634         INFO("Zoom in (Ctrl + '+') was pressed, zoom level became %.2f", zoomLevels[window->current_zoom_level]);
635     } else if (ctrlPressed && !strcmp(ev->key, "0")) {
636         if (zoom_level_set(ewk_view, DEFAULT_ZOOM_LEVEL))
637             window->current_zoom_level = DEFAULT_ZOOM_LEVEL;
638         INFO("Zoom to default (Ctrl + '0') was pressed, zoom level became %.2f", zoomLevels[window->current_zoom_level]);
639     } else if (ctrlPressed && !strcmp(ev->key, "s")) {
640         Eina_Strbuf *default_file = eina_strbuf_new();
641         const char *home_path = getenv("HOME");
642         const char *title = ewk_view_title_get(window->ewk_view);
643         eina_strbuf_append_printf(default_file, "%s/%s.mht", home_path ? home_path : "/home", title ? title : "title");
644         INFO("Pressed (CTRL + S) : Saving Current Page.");
645         Eina_Stringshare *save_file_name = show_file_entry_dialog(window, "SAVE", eina_strbuf_string_get(default_file));
646         if (!save_file_name)
647             return;
648         ewk_view_page_contents_get(ewk_view, EWK_PAGE_CONTENTS_TYPE_MHTML, save_page_contents_callback, (void *)save_file_name);
649         eina_strbuf_free(default_file);
650     } else if (ctrlPressed && !strcmp(ev->key, "l")) {
651         const char *home_path =  getenv("HOME");
652         Eina_Stringshare *open_file_name = show_file_entry_dialog(window, "LOAD", home_path ? home_path : "/home");
653         if (!open_file_name)
654             return;
655         Eina_Strbuf *uri_path = eina_strbuf_new();
656         eina_strbuf_append_printf(uri_path, "%s%s", FILE_SCHEME, open_file_name);
657         INFO("pressed (CTRL + L) : Loading Page %s", eina_strbuf_string_get(uri_path));
658         ewk_view_url_set(ewk_view, eina_strbuf_string_get(uri_path));
659         eina_strbuf_free(uri_path);
660         eina_stringshare_del(open_file_name);
661     }
662 }
663
664 static void
665 view_focus_set(Browser_Window *window, Eina_Bool focus)
666 {
667     /* We steal focus away from elm's focus model and start to do things
668      * manually here, so elm now has no clue what's up. Tell elm that its
669      * toplevel widget is to be unfocused so elm gives up the focus */
670     elm_object_focus_set(elm_object_top_widget_get(window->elm_window), EINA_FALSE);
671     evas_object_focus_set(window->ewk_view, focus);
672 }
673
674 static void
675 on_mouse_down(void *user_data, Evas *e, Evas_Object *ewk_view, void *event_info)
676 {
677     Browser_Window *window = (Browser_Window *)user_data;
678     Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down *)event_info;
679
680     /* Clear selection from the URL bar */
681     elm_entry_select_none(window->url_bar);
682
683     if (longpress_enabled)
684         history_list_hide(window);
685     if (ev->button == 1)
686         view_focus_set(window, EINA_TRUE);
687     else if (ev->button == 2)
688         view_focus_set(window, !evas_object_focus_get(ewk_view));
689 }
690
691 static void
692 title_set(Evas_Object *elm_window, const char *title, int progress)
693 {
694     Eina_Strbuf *buffer;
695
696     if (!title || !*title) {
697         elm_win_title_set(elm_window, APP_NAME);
698         return;
699     }
700
701     buffer = eina_strbuf_new();
702     if (progress < 100)
703         eina_strbuf_append_printf(buffer, "%s (%d%%) - %s", title, progress, APP_NAME);
704     else
705         eina_strbuf_append_printf(buffer, "%s - %s", title, APP_NAME);
706
707     elm_win_title_set(elm_window, eina_strbuf_string_get(buffer));
708     eina_strbuf_free(buffer);
709 }
710
711 static void
712 on_title_changed(void *user_data, Evas_Object *ewk_view, void *event_info)
713 {
714     Browser_Window *window = (Browser_Window *)user_data;
715     const char *title = (const char *)event_info;
716
717     title_set(window->elm_window, title, 100);
718 }
719
720 static void
721 on_url_changed(void *user_data, Evas_Object *ewk_view, void *event_info)
722 {
723     Browser_Window *window = (Browser_Window *)user_data;
724     const char *url = ewk_view_url_get(window->ewk_view);
725     char *converted_url = elm_entry_utf8_to_markup(url);
726     elm_entry_entry_set(window->url_bar, converted_url);
727
728     on_icon_changed_cb(ewk_context_favicon_database_get(ewk_view_context_get(ewk_view)), url, user_data);
729
730     free(converted_url);
731
732     search_box_hide(window);
733 }
734
735 static void
736 on_back_forward_list_changed(void *user_data, Evas_Object *ewk_view, void *event_info)
737 {
738     Browser_Window *window = (Browser_Window *)user_data;
739
740     /* Update navigation buttons state */
741     elm_object_disabled_set(window->back_button, !ewk_view_back_possible(ewk_view));
742     elm_object_disabled_set(window->forward_button, !ewk_view_forward_possible(ewk_view));
743 }
744
745 static void
746 on_progress(void *user_data, Evas_Object *ewk_view, void *event_info)
747 {
748     Browser_Window *window = (Browser_Window *)user_data;
749     double progress = *(double *)event_info;
750
751     title_set(window->elm_window, ewk_view_title_get(window->ewk_view), progress * 100);
752 }
753
754 static void
755 on_error(void *user_data, Evas_Object *ewk_view, void *event_info)
756 {
757     Eina_Strbuf *buffer;
758     const Ewk_Error *error = (const Ewk_Error *)event_info;
759
760     /* This is a cancellation, do not display the error page */
761     if (ewk_error_cancellation_get(error))
762         return;
763
764     buffer = eina_strbuf_new();
765     eina_strbuf_append_printf(buffer,
766         "<html><body><div style=\"color:#ff0000\">ERROR!</div><br><div>Code: %d<br>Description: %s<br>URL: %s</div></body</html>",
767         ewk_error_code_get(error), ewk_error_description_get(error), ewk_error_url_get(error));
768
769     ewk_view_html_string_load(ewk_view, eina_strbuf_string_get(buffer), 0, ewk_error_url_get(error));
770     eina_strbuf_free(buffer);
771 }
772
773 static void
774 on_download_request(Ewk_Download_Job *download, void *user_data)
775 {
776     Browser_Window *window = (Browser_Window *)user_data;
777
778     Eina_Strbuf *destination_path = eina_strbuf_new();
779
780     const char *home_path = getenv("HOME");
781     Eina_Stringshare *save_file_path = show_file_entry_dialog(window, "DOWNLOAD", home_path ? home_path : "/tmp");
782
783     if (save_file_path)
784         eina_strbuf_append_printf(destination_path, "%s", save_file_path);
785     else
786         eina_strbuf_append(destination_path, "/tmp");
787
788     const char *suggested_name = ewk_download_job_suggested_filename_get(download);
789     if (suggested_name && *suggested_name)
790         eina_strbuf_append_printf(destination_path, "/%s", suggested_name);
791     else {
792         // Generate a unique file name since no name was suggested.
793         eina_strbuf_append(destination_path, "/downloaded-file.XXXXXX");
794         char *url = NULL;
795         url = eina_strbuf_string_steal(destination_path);
796         if (mkstemp(url) == -1) {
797             ERROR("Could not generate a unique file name.");
798             return;
799         }
800         eina_strbuf_append(destination_path, url);
801     }
802
803     ewk_download_job_destination_set(download, eina_strbuf_string_get(destination_path));
804     INFO("Downloading: %s", eina_strbuf_string_get(destination_path));
805     eina_strbuf_free(destination_path);
806     eina_stringshare_del(save_file_path);
807 }
808
809 static void on_filepicker_parent_deletion(void *user_data, Evas *evas, Evas_Object *elm_window, void *event);
810
811 static void close_file_picker(File_Selector_Data *fs_data)
812 {
813     evas_object_event_callback_del(fs_data->parent->elm_window, EVAS_CALLBACK_DEL, on_filepicker_parent_deletion);
814     evas_object_del(fs_data->elm_window);
815     ewk_object_unref(fs_data->request);
816     free(fs_data);
817 }
818
819 static void
820 on_filepicker_parent_deletion(void *user_data, Evas *evas, Evas_Object *elm_window, void *event)
821 {
822     close_file_picker((File_Selector_Data *)user_data);
823 }
824
825 static void
826 on_filepicker_deletion(void *user_data, Evas_Object *elm_window, void *event_info)
827 {
828     close_file_picker((File_Selector_Data *)user_data);
829 }
830
831 static void
832 on_fileselector_done(void *user_data, Evas_Object *file_selector, void *event_info)
833 {
834     File_Selector_Data *fs_data = (File_Selector_Data *)user_data;
835
836     const char *selected = (const char *)event_info;
837     if (selected && *selected)
838         ewk_file_chooser_request_file_choose(fs_data->request, selected);
839
840     close_file_picker(fs_data);
841 }
842
843 static void
844 on_file_chooser_request(void *user_data, Evas_Object *ewk_view, void *event_info)
845 {
846     Evas_Object *bg;
847     Browser_Window *window = (Browser_Window *)user_data;
848     Ewk_File_Chooser_Request *request = (Ewk_File_Chooser_Request *)event_info;
849
850     // Show basic file picker which does not currently support multiple files
851     // or MIME type filtering.
852     Evas_Object *elm_window = elm_win_add(window->elm_window, "file-picker-window", ELM_WIN_DIALOG_BASIC);
853     elm_win_title_set(elm_window, "File picker");
854     elm_win_modal_set(elm_window, EINA_TRUE);
855
856     bg = elm_bg_add(elm_window);
857     evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
858     elm_win_resize_object_add(elm_window, bg);
859     evas_object_show(bg);
860
861     File_Selector_Data *fs_data = (File_Selector_Data *)malloc(sizeof(File_Selector_Data));
862     fs_data->parent = window;
863     fs_data->elm_window = elm_window;
864     fs_data->request = ewk_object_ref(request);
865     evas_object_smart_callback_add(elm_window, "delete,request", on_filepicker_deletion, fs_data);
866     evas_object_event_callback_add(window->elm_window, EVAS_CALLBACK_DEL, on_filepicker_parent_deletion, fs_data);
867
868     Evas_Object *file_selector = elm_fileselector_add(elm_window);
869     const char *home_path = getenv("HOME");
870     elm_fileselector_path_set(file_selector, home_path ? home_path : "/home");
871     evas_object_size_hint_weight_set(file_selector, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
872     elm_win_resize_object_add(elm_window, file_selector);
873     evas_object_show(file_selector);
874
875     evas_object_smart_callback_add(file_selector, "done", on_fileselector_done, fs_data);
876
877     evas_object_resize(elm_window, 400, 400);
878     elm_win_center(elm_window, EINA_TRUE, EINA_TRUE);
879     evas_object_show(elm_window);
880 }
881
882 static void
883 on_download_finished(Ewk_Download_Job *download, void *user_data)
884 {
885     INFO("Download finished: %s",  ewk_download_job_destination_get(download));
886 }
887
888 static void
889 on_download_failed(Ewk_Download_Job_Error *download_error, void *user_data)
890 {
891     Ewk_Error *error = download_error->error;
892
893     INFO("Download failed! Error code: %d, Error description: %s, Error URL: %s", ewk_error_code_get(error), ewk_error_description_get(error), ewk_error_url_get(error));
894 }
895
896 static void
897 on_color_changed(void *data, Evas_Object *obj, void *event_info)
898 {
899     int r, g, b, a;
900
901     elm_colorselector_color_get(obj, &r, &g, &b, &a);
902     evas_object_color_set(data, r, g, b, a);
903 }
904
905 static void
906 on_color_item_selected(void *data, Evas_Object *obj, void *event_info)
907 {
908     int r, g, b, a;
909     Elm_Object_Item *color_item = (Elm_Object_Item *)event_info;
910
911     elm_colorselector_palette_item_color_get(color_item, &r, &g, &b, &a);
912     evas_object_color_set(data, r, g, b, a);
913 }
914
915 static void
916 on_color_picker_ok_clicked(void *data, Evas_Object *obj, void *event_info)
917 {
918     int r, g, b, a;
919     Color_Selector *color_selector = (Color_Selector *)data;
920
921     elm_colorselector_color_get(color_selector->elm_selector, &r, &g, &b, &a);
922     ewk_color_picker_color_set(color_selector->ewk_picker, r, g, b, a);
923 }
924
925 static void
926 on_color_picker_cancel_clicked(void *data, Evas_Object *obj, void *event_info)
927 {
928     int r, g, b, a;
929
930     ewk_color_picker_color_get(data, &r, &g, &b, &a);
931     ewk_color_picker_color_set(data, r, g, b, a);
932 }
933
934 static Eina_Bool
935 on_color_picker_dismiss(Ewk_View_Smart_Data *sd)
936 {
937     Browser_Window *window = window_find_with_ewk_view(sd->self);
938
939     evas_object_del(window->color_selector.elm_selector_window);
940     window->color_selector.elm_selector_window = NULL;
941
942     return EINA_TRUE;
943 }
944
945 static Eina_Bool
946 on_color_picker_request(Ewk_View_Smart_Data *sd, Ewk_Color_Picker *color_picker)
947 {
948     int r, g, b, a;
949     Evas_Object *background, *rect, *box, *button_box, *rect_frame, *cs_frame, *ok_button, *cancel_button;
950
951     Browser_Window *window = window_find_with_ewk_view(sd->self);
952     window->color_selector.elm_selector_window = elm_win_add(window->elm_window, "color selector", ELM_WIN_BASIC);
953     window->color_selector.ewk_picker = color_picker;
954
955     elm_win_title_set(window->color_selector.elm_selector_window, "Color selector");
956
957     /* Show color view */
958     background = elm_bg_add(window->color_selector.elm_selector_window);
959     evas_object_size_hint_weight_set(background, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
960     elm_win_resize_object_add(window->color_selector.elm_selector_window, background);
961     evas_object_show(background);
962
963     box = elm_box_add(window->color_selector.elm_selector_window);
964     evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
965     elm_win_resize_object_add(window->color_selector.elm_selector_window, box);
966     evas_object_show(box);
967
968     rect_frame = elm_frame_add(window->color_selector.elm_selector_window);
969     evas_object_size_hint_weight_set(rect_frame, EVAS_HINT_EXPAND, 0.3);
970     evas_object_size_hint_align_set(rect_frame, EVAS_HINT_FILL, EVAS_HINT_FILL);
971     elm_object_text_set(rect_frame, "Color View");
972     elm_box_pack_end(box, rect_frame);
973     evas_object_show(rect_frame);
974
975     rect = evas_object_rectangle_add(evas_object_evas_get(window->color_selector.elm_selector_window));
976     elm_object_content_set(rect_frame, rect);
977     ewk_color_picker_color_get(window->color_selector.ewk_picker, &r, &g, &b, &a);
978     evas_object_color_set(rect, r, g, b, a);
979     evas_object_show(rect);
980
981     /* Show color selector */
982     cs_frame = elm_frame_add(window->color_selector.elm_selector_window);
983     evas_object_size_hint_weight_set(cs_frame, EVAS_HINT_EXPAND, 0.7);
984     evas_object_size_hint_align_set(cs_frame, EVAS_HINT_FILL, EVAS_HINT_FILL);
985     elm_object_text_set(cs_frame, "Color Selector");
986     elm_box_pack_end(box, cs_frame);
987     evas_object_show(cs_frame);
988
989     window->color_selector.elm_selector = elm_colorselector_add(window->color_selector.elm_selector_window);
990     elm_object_content_set(cs_frame, window->color_selector.elm_selector);
991     evas_object_show(window->color_selector.elm_selector);
992
993     /* OK, Cancel Buttons */
994     button_box = elm_box_add(window->color_selector.elm_selector_window);
995     elm_box_horizontal_set(button_box, EINA_TRUE);
996     evas_object_size_hint_min_set(button_box, 200, 50);
997     elm_box_pack_end(box, button_box);
998     evas_object_show(button_box);
999
1000     ok_button = elm_button_add(window->color_selector.elm_selector_window);
1001     elm_object_text_set(ok_button, "OK");
1002     elm_box_pack_end(button_box, ok_button);
1003     evas_object_show(ok_button);
1004
1005     cancel_button = elm_button_add(window->color_selector.elm_selector_window);
1006     elm_object_text_set(cancel_button, "Cancel");
1007     elm_box_pack_end(button_box, cancel_button);
1008     evas_object_show(cancel_button);
1009
1010     evas_object_smart_callback_add(ok_button, "clicked", on_color_picker_ok_clicked, &(window->color_selector));
1011     evas_object_smart_callback_add(cancel_button, "clicked", on_color_picker_cancel_clicked,
1012         window->color_selector.ewk_picker);
1013     evas_object_smart_callback_add(window->color_selector.elm_selector_window, "delete,request",
1014         on_color_picker_cancel_clicked, window->color_selector.ewk_picker);
1015     evas_object_smart_callback_add(window->color_selector.elm_selector, "changed", on_color_changed, rect);
1016     evas_object_smart_callback_add(window->color_selector.elm_selector, "color,item,selected", on_color_item_selected,
1017         rect);
1018
1019     elm_win_center(window->color_selector.elm_selector_window, EINA_TRUE, EINA_TRUE);
1020     evas_object_resize(window->color_selector.elm_selector_window, 350, 500);
1021     evas_object_show(window->color_selector.elm_selector_window);
1022
1023     return EINA_TRUE;
1024 }
1025
1026 static int
1027 quit(Eina_Bool success, const char *msg)
1028 {
1029     if (msg)
1030         success ? INFO("%s", msg) : ERROR("%s", msg);
1031
1032     eina_log_domain_unregister(_log_domain_id);
1033     ewk_object_unref(configuration());
1034     ewk_shutdown();
1035     elm_shutdown();
1036
1037     if (!success)
1038         return EXIT_FAILURE;
1039
1040     return EXIT_SUCCESS;
1041 }
1042
1043 static Eina_Bool
1044 has_scheme(const char *url)
1045 {
1046     return !!strstr(url, "://");
1047 }
1048
1049 static char *
1050 url_from_user_input(const char *arg)
1051 {
1052     /* If it is already a URL, return the argument as is. */
1053     if (has_scheme(arg) || eina_str_has_prefix(arg, JAVASCRIPT_SCHEME) || !strcasecmp(arg, "about:blank"))
1054         return strdup(arg);
1055
1056     Eina_Strbuf *buf = eina_strbuf_manage_new(eina_file_path_sanitize(arg));
1057
1058     /* Check if the path exists. */
1059     if (ecore_file_exists(eina_strbuf_string_get(buf))) {
1060         /* File exists, convert local path to a URL. */
1061         eina_strbuf_prepend(buf, FILE_SCHEME);
1062     } else {
1063         /* The path does not exist, convert it to a URL by
1064            prepending http:// scheme:
1065            www.google.com -> http://www.google.com */
1066         eina_strbuf_string_free(buf);
1067         eina_strbuf_append_printf(buf, "%s%s", HTTP_SCHEME, arg);
1068     }
1069     char *url = eina_strbuf_string_steal(buf);
1070     eina_strbuf_free(buf);
1071
1072     return url;
1073 }
1074
1075 static Eina_Bool
1076 url_load_from_user_input(Evas_Object *ewk_view, const char *url)
1077 {
1078     if (!ewk_view || !url)
1079         return EINA_FALSE;
1080
1081     if (eina_str_has_prefix(url, JAVASCRIPT_SCHEME))
1082         return ewk_view_script_execute(ewk_view, strstr(url, JAVASCRIPT_SCHEME), 0, 0);
1083
1084     return ewk_view_url_set(ewk_view, url);
1085 }
1086
1087 static void
1088 on_url_bar_activated(void *user_data, Evas_Object *url_bar, void *event_info)
1089 {
1090     Browser_Window *window = (Browser_Window *)user_data;
1091
1092     const char *markup_url = elm_entry_entry_get(url_bar);
1093     char *user_url = elm_entry_markup_to_utf8(markup_url);
1094     char *url = url_from_user_input(user_url);
1095     url_load_from_user_input(window->ewk_view, url);
1096
1097     free(user_url);
1098     free(url);
1099
1100     /* Give focus back to the view */
1101     view_focus_set(window, EINA_TRUE);
1102 }
1103
1104 static void
1105 on_url_bar_clicked(void *user_data, Evas_Object *url_bar, void *event_info)
1106 {
1107     Browser_Window *window = (Browser_Window *)user_data;
1108
1109     /* Grab focus from the view */
1110     evas_object_focus_set(window->ewk_view, EINA_FALSE);
1111     elm_object_focus_set(url_bar, EINA_TRUE);
1112 }
1113
1114 static void
1115 on_search_field_aborted(void *user_data, Evas_Object *search_field, void *event_info)
1116 {
1117     Browser_Window *window = (Browser_Window *)user_data;
1118     search_box_hide(window);
1119
1120     /* Give focus back to the view */
1121     view_focus_set(window, EINA_TRUE);
1122 }
1123
1124 static void
1125 on_search_field_activated(void *user_data, Evas_Object *search_field, void *event_info)
1126 {
1127     Browser_Window *window = (Browser_Window *)user_data;
1128
1129     const char *markup_text = elm_entry_entry_get(search_field);
1130     char *text = elm_entry_markup_to_utf8(markup_text);
1131     ewk_view_text_find(window->ewk_view, text, search_flags, MAX_SEARCH_COUNT);
1132     free(text);
1133
1134     /* Grab focus from the view */
1135     evas_object_focus_set(window->ewk_view, EINA_FALSE);
1136     elm_object_focus_set(search_field, EINA_TRUE);
1137 }
1138
1139 static void
1140 on_search_field_clicked(void *user_data, Evas_Object *search_field, void *event_info)
1141 {
1142     Browser_Window *window = (Browser_Window *)user_data;
1143
1144     /* Grab focus from the view */
1145     evas_object_focus_set(window->ewk_view, EINA_FALSE);
1146     elm_object_focus_set(search_field, EINA_TRUE);
1147 }
1148
1149 static void
1150 on_back_button_clicked(void *user_data, Evas_Object *back_button, void *event_info)
1151 {
1152     if (longpress_enabled)
1153         return;
1154
1155     Browser_Window *window = (Browser_Window *)user_data;
1156
1157     ewk_view_back(window->ewk_view);
1158     /* Update back button state */
1159     elm_object_disabled_set(back_button, !ewk_view_back_possible(window->ewk_view));
1160 }
1161
1162 static void
1163 on_forward_button_clicked(void *user_data, Evas_Object *forward_button, void *event_info)
1164 {
1165     if (longpress_enabled)
1166         return;
1167
1168     Browser_Window *window = (Browser_Window *)user_data;
1169
1170     ewk_view_forward(window->ewk_view);
1171     /* Update forward button state */
1172     elm_object_disabled_set(forward_button, !ewk_view_forward_possible(window->ewk_view));
1173 }
1174
1175 static void
1176 on_search_backward_button_clicked(void *user_data, Evas_Object *search_backward_button, void *event_info)
1177 {
1178     Browser_Window *window = (Browser_Window *)user_data;
1179
1180     char *text = elm_entry_markup_to_utf8(elm_entry_entry_get(window->search.search_field));
1181     ewk_view_text_find(window->ewk_view, text, search_flags | EWK_FIND_OPTIONS_BACKWARDS, MAX_SEARCH_COUNT);
1182     free(text);
1183 }
1184
1185 static void
1186 on_search_forward_button_clicked(void *user_data, Evas_Object *search_forward_button, void *event_info)
1187 {
1188     Browser_Window *window = (Browser_Window *)user_data;
1189
1190     char *text = elm_entry_markup_to_utf8(elm_entry_entry_get(window->search.search_field));
1191     ewk_view_text_find(window->ewk_view, text, search_flags, MAX_SEARCH_COUNT);
1192     free(text);
1193 }
1194
1195 static void
1196 on_search_case_option_changed(void *user_data, Evas_Object *search_case_check_box, void *event_info)
1197 {
1198     Browser_Window *window = (Browser_Window *)user_data;
1199     char *text = elm_entry_markup_to_utf8(elm_entry_entry_get(window->search.search_field));
1200
1201     /* Bit toggle the case sensitive flag */
1202     search_flags = search_flags ^ EWK_FIND_OPTIONS_CASE_INSENSITIVE;
1203
1204     ewk_view_text_find(window->ewk_view, text, search_flags, MAX_SEARCH_COUNT);
1205     free(text);
1206 }
1207
1208 static void
1209 on_search_word_start_option_changed(void *user_data, Evas_Object *search_word_start_check_box, void *event_info)
1210 {
1211     Browser_Window *window = (Browser_Window *)user_data;
1212     char *text = elm_entry_markup_to_utf8(elm_entry_entry_get(window->search.search_field));
1213
1214     /* Bit toggle the word start flag */
1215     search_flags = search_flags ^ EWK_FIND_OPTIONS_AT_WORD_STARTS;
1216
1217     ewk_view_text_find(window->ewk_view, text, search_flags, MAX_SEARCH_COUNT);
1218     free(text);
1219 }
1220
1221 static void
1222 on_search_close_button_clicked(void *user_data, Evas_Object *search_close_button, void *event_info)
1223 {
1224     Browser_Window *window = (Browser_Window *)user_data;
1225
1226     search_box_hide(window);
1227 }
1228
1229 static void
1230 on_refresh_button_clicked(void *user_data, Evas_Object *refresh_button, void *event_info)
1231 {
1232     Browser_Window *window = (Browser_Window *)user_data;
1233
1234     Evas *evas = evas_object_evas_get(refresh_button);
1235     Eina_Bool ctrlPressed = evas_key_modifier_is_set(evas_key_modifier_get(evas), "Control");
1236     if (ctrlPressed) {
1237         INFO("Reloading and bypassing cache...");
1238         ewk_view_reload_bypass_cache(window->ewk_view);
1239     } else {
1240         INFO("Reloading...");
1241         ewk_view_reload(window->ewk_view);
1242     }
1243 }
1244
1245 static void
1246 on_stop_button_clicked(void *user_data, Evas_Object *stop_button, void *event_info)
1247 {
1248     Browser_Window *window = (Browser_Window *)user_data;
1249
1250     INFO("Stop was Pressed. Aborting load...");
1251     ewk_view_stop(window->ewk_view);
1252 }
1253
1254 static char *
1255 list_item_label_get(void *data, Evas_Object *obj, const char *part)
1256 {
1257     int len = strlen((char *)data);
1258     char *buf = (char *)malloc(sizeof(char) * (len + 1));
1259     snprintf(buf, len + 1, "%s", (char *)data);
1260     return buf;
1261 }
1262
1263 static void
1264 on_list_item_select(void *user_data, Evas_Object *obj, void *event_info)
1265 {
1266     Browser_Window *window = evas_object_data_get(obj, "Browser_Window");
1267     ewk_view_navigate_to(window->ewk_view, user_data);
1268     history_list_hide(window);
1269     evas_object_data_del(obj, "Browser_Window");
1270 }
1271
1272 static void
1273 navigation_button_longpress_process(void *user_data, Eina_Bool forward_navigation_enabled)
1274 {
1275     if (longpress_enabled)
1276         return;
1277
1278     longpress_enabled = EINA_TRUE;
1279     Browser_Window *window = (Browser_Window *)user_data;
1280
1281     Ewk_Back_Forward_List *list = ewk_view_back_forward_list_get(window->ewk_view);
1282     const Eina_List *l;
1283     void *data;
1284     static Elm_Genlist_Item_Class *list_item = NULL;
1285     const char *title = NULL;
1286     int item_count;
1287     int x;
1288     int y;
1289     int width;
1290     int height;
1291     size_t index;
1292
1293     evas_object_data_set(window->history.history_list, "Browser_Window", window);
1294
1295     if (forward_navigation_enabled)
1296         window->history.history_list_items = ewk_back_forward_list_forward_items_copy(list);
1297     else
1298         window->history.history_list_items = ewk_back_forward_list_back_items_copy(list);
1299
1300     if (!list_item) {
1301         list_item = elm_genlist_item_class_new();
1302         list_item->item_style = "default";
1303         list_item->func.text_get = list_item_label_get;
1304         list_item->func.content_get = NULL;
1305         list_item->func.state_get = NULL;
1306         list_item->func.del = NULL;
1307     }
1308
1309     item_count = eina_list_count(window->history.history_list_items);
1310     INFO("navigation_button_longpress_process : Item count = %d forward_navigation_enabled = %d", item_count, forward_navigation_enabled);
1311
1312     EINA_LIST_FOREACH(window->history.history_list_items, l, data) {
1313         title = ewk_back_forward_list_item_title_get(data);
1314         INFO(" title = %s", title);
1315         elm_genlist_item_append(window->history.history_list, list_item, (void *)(title), NULL, ELM_GENLIST_ITEM_NONE, on_list_item_select, data);
1316     }
1317
1318     if (item_count > 0) {
1319         evas_object_geometry_get(window->elm_window, &x, &y, &width, &height);
1320         elm_list_go(window->history.history_list);
1321         evas_object_resize(window->history.history_box , width / 3 , LIST_ITEM_HEIGHT * item_count);
1322
1323         if (forward_navigation_enabled) {
1324             evas_object_move(window->history.history_box , x + TOOL_BAR_BUTTON_SIZE + 1, y + TOOL_BAR_BUTTON_SIZE);
1325             evas_object_move(window->history.history_list , x + TOOL_BAR_BUTTON_SIZE + 1, y + TOOL_BAR_BUTTON_SIZE);
1326         } else {
1327             evas_object_move(window->history.history_box , x, y + TOOL_BAR_BUTTON_SIZE);
1328             evas_object_move(window->history.history_list , x, y + TOOL_BAR_BUTTON_SIZE);
1329         }
1330
1331         elm_genlist_mode_set(window->history.history_list, ELM_LIST_COMPRESS);
1332         evas_object_show(window->history.history_box);
1333         evas_object_show(window->history.history_list);
1334         evas_object_focus_set(window->ewk_view, EINA_FALSE);
1335         elm_object_focus_set(window->history.history_list, EINA_TRUE);
1336     } else
1337         longpress_enabled = EINA_FALSE;
1338 }
1339
1340 static void
1341 on_forward_button_longpress(void *user_data, Evas_Object *forward_button, void *event_info)
1342 {
1343     Browser_Window *window = (Browser_Window *)user_data;
1344
1345     navigation_button_longpress_process(user_data, EINA_TRUE);
1346     elm_object_disabled_set(forward_button, !ewk_view_back_possible(window->ewk_view));
1347 }
1348
1349 static void
1350 on_back_button_longpress(void *user_data, Evas_Object *back_button, void *event_info)
1351 {
1352     Browser_Window *window = (Browser_Window *)user_data;
1353
1354     navigation_button_longpress_process(user_data, EINA_FALSE);
1355     elm_object_disabled_set(back_button, !ewk_view_back_possible(window->ewk_view));
1356 }
1357
1358 static void
1359 quit_event_loop(void *user_data, Evas_Object *obj, void *event_info)
1360 {
1361     ecore_main_loop_quit();
1362 }
1363
1364 static void
1365 on_ok_clicked(void *user_data, Evas_Object *obj, void *event_info)
1366 {
1367     Eina_Bool *confirmed = (Eina_Bool *)user_data;
1368     *confirmed = EINA_TRUE;
1369
1370     ecore_main_loop_quit();
1371 }
1372
1373 static Eina_Stringshare *
1374 show_file_entry_dialog(Browser_Window *window, const char *label_tag, const char *default_text)
1375 {
1376     Evas_Object *file_popup = elm_popup_add(window->elm_window);
1377     evas_object_size_hint_weight_set(file_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1378     evas_object_show(file_popup);
1379
1380     Evas_Object *vbox = elm_box_add(file_popup);
1381     evas_object_size_hint_weight_set(vbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1382     evas_object_size_hint_align_set(vbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
1383     elm_object_content_set(file_popup, vbox);
1384     evas_object_show(vbox);
1385
1386     Evas_Object *label = elm_label_add(window->elm_window);
1387     elm_object_text_set(label, label_tag);
1388     evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, 0.0);
1389     evas_object_size_hint_align_set(label, EVAS_HINT_FILL, 0.5);
1390     evas_object_color_set(label, 23, 45, 67, 142);
1391     elm_box_pack_end(vbox, label);
1392     evas_object_show(label);
1393
1394     Evas_Object *fs_entry = elm_fileselector_entry_add(file_popup);
1395     elm_fileselector_is_save_set(fs_entry, EINA_TRUE);
1396     evas_object_size_hint_align_set(fs_entry, EVAS_HINT_FILL, 0);
1397     elm_fileselector_path_set(fs_entry, default_text);
1398     elm_object_text_set(fs_entry, "FileChooser");
1399     elm_box_pack_end(vbox, fs_entry);
1400     evas_object_show(fs_entry);
1401
1402     Evas_Object *hbox = elm_box_add(file_popup);
1403     evas_object_size_hint_weight_set(hbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1404     elm_box_horizontal_set(hbox, EINA_TRUE);
1405     evas_object_size_hint_align_set(hbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
1406     elm_box_pack_end(vbox, hbox);
1407     evas_object_show(hbox);
1408
1409     Eina_Bool ok = EINA_FALSE;
1410     Evas_Object *ok_button = elm_button_add(file_popup);
1411     elm_object_text_set(ok_button, "OK");
1412     evas_object_smart_callback_add(ok_button, "clicked", on_ok_clicked, &ok);
1413     elm_box_pack_end(hbox, ok_button);
1414     evas_object_show(ok_button);
1415
1416     Evas_Object *cancel_button = elm_button_add(file_popup);
1417     elm_object_text_set(cancel_button, "Cancel");
1418     evas_object_smart_callback_add(cancel_button, "clicked", quit_event_loop, NULL);
1419     elm_box_pack_end(hbox, cancel_button);
1420     evas_object_show(cancel_button);
1421
1422     ecore_main_loop_begin();
1423
1424     Eina_Stringshare *file_path = ok ? eina_stringshare_add(elm_fileselector_path_get(fs_entry)) : NULL;
1425     evas_object_del(file_popup);
1426     return file_path;
1427 }
1428
1429 static void
1430 on_javascript_alert(Ewk_View_Smart_Data *smartData, const char *message)
1431 {
1432     Browser_Window *window = window_find_with_ewk_view(smartData->self);
1433
1434     Evas_Object *alert_popup = elm_popup_add(window->elm_window);
1435     evas_object_size_hint_weight_set(alert_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1436     elm_object_text_set(alert_popup, message);
1437     elm_object_part_text_set(alert_popup, "title,text", "Alert");
1438
1439     /* Popup buttons */
1440     Evas_Object *button = elm_button_add(alert_popup);
1441     elm_object_text_set(button, "OK");
1442     elm_object_part_content_set(alert_popup, "button1", button);
1443     evas_object_smart_callback_add(button, "clicked", quit_event_loop, NULL);
1444     elm_object_focus_set(button, EINA_TRUE);
1445     evas_object_show(alert_popup);
1446
1447     /* Make modal */
1448     ecore_main_loop_begin();
1449
1450     evas_object_del(alert_popup);
1451 }
1452
1453 static Eina_Bool
1454 on_javascript_confirm(Ewk_View_Smart_Data *smartData, const char *message)
1455 {
1456     Browser_Window *window = window_find_with_ewk_view(smartData->self);
1457
1458     Eina_Bool ok = EINA_FALSE;
1459
1460     Evas_Object *confirm_popup = elm_popup_add(window->elm_window);
1461     evas_object_size_hint_weight_set(confirm_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1462     elm_object_text_set(confirm_popup, message);
1463     elm_object_part_text_set(confirm_popup, "title,text", "Confirmation");
1464
1465     /* Popup buttons */
1466     Evas_Object *cancel_button = elm_button_add(confirm_popup);
1467     elm_object_text_set(cancel_button, "Cancel");
1468     elm_object_part_content_set(confirm_popup, "button1", cancel_button);
1469     evas_object_smart_callback_add(cancel_button, "clicked", quit_event_loop, NULL);
1470     Evas_Object *ok_button = elm_button_add(confirm_popup);
1471     elm_object_text_set(ok_button, "OK");
1472     elm_object_part_content_set(confirm_popup, "button2", ok_button);
1473     evas_object_smart_callback_add(ok_button, "clicked", on_ok_clicked, &ok);
1474     elm_object_focus_set(ok_button, EINA_TRUE);
1475     evas_object_show(confirm_popup);
1476
1477     /* Make modal */
1478     ecore_main_loop_begin();
1479
1480     evas_object_del(confirm_popup);
1481
1482     return ok;
1483 }
1484
1485 static const char *
1486 on_javascript_prompt(Ewk_View_Smart_Data *smartData, const char *message, const char *default_value)
1487 {
1488     Browser_Window *window = window_find_with_ewk_view(smartData->self);
1489
1490     Eina_Bool ok = EINA_FALSE;
1491
1492     Evas_Object *prompt_popup = elm_popup_add(window->elm_window);
1493     evas_object_size_hint_weight_set(prompt_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1494     elm_object_part_text_set(prompt_popup, "title,text", "Prompt");
1495
1496     /* Popup Content */
1497     Evas_Object *box = elm_box_add(window->elm_window);
1498     elm_box_padding_set(box, 0, 4);
1499     evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1500     evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);
1501     evas_object_show(box);
1502
1503     Evas_Object *prompt = elm_label_add(window->elm_window);
1504     elm_object_text_set(prompt, message);
1505     evas_object_size_hint_weight_set(prompt, EVAS_HINT_EXPAND, 0.0);
1506     evas_object_size_hint_align_set(prompt, EVAS_HINT_FILL, 0.5);
1507     elm_box_pack_end(box, prompt);
1508     evas_object_show(prompt);
1509
1510     Evas_Object *entry = elm_entry_add(window->elm_window);
1511     elm_entry_scrollable_set(entry, EINA_TRUE);
1512     elm_entry_single_line_set(entry, EINA_TRUE);
1513     elm_entry_text_style_user_push(entry, "DEFAULT='font_size=18'");
1514     elm_entry_entry_set(entry, default_value ? default_value : "");
1515     elm_entry_select_all(entry);
1516     evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, 0.0);
1517     evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, 0.5);
1518     elm_box_pack_end(box, entry);
1519     elm_object_focus_set(entry, EINA_TRUE);
1520     evas_object_show(entry);
1521
1522     elm_object_content_set(prompt_popup, box);
1523
1524     /* Popup buttons */
1525     Evas_Object *cancel_button = elm_button_add(prompt_popup);
1526     elm_object_text_set(cancel_button, "Cancel");
1527     elm_object_part_content_set(prompt_popup, "button1", cancel_button);
1528     evas_object_smart_callback_add(cancel_button, "clicked", quit_event_loop, NULL);
1529     Evas_Object *ok_button = elm_button_add(prompt_popup);
1530     elm_object_text_set(ok_button, "OK");
1531     elm_object_part_content_set(prompt_popup, "button2", ok_button);
1532     evas_object_smart_callback_add(ok_button, "clicked", on_ok_clicked, &ok);
1533     evas_object_show(prompt_popup);
1534
1535     /* Make modal */
1536     ecore_main_loop_begin();
1537
1538     /* The return string need to be stringshared */
1539     const char *prompt_text = ok ? eina_stringshare_add(elm_entry_entry_get(entry)) : NULL;
1540     evas_object_del(prompt_popup);
1541
1542     return prompt_text;
1543 }
1544
1545 static Eina_Bool
1546 on_javascript_before_unload_confirm(Ewk_View_Smart_Data *smartData, const char *message)
1547 {
1548     return on_javascript_confirm(smartData, "Will you leave this page?");
1549 }
1550
1551 static void
1552 on_popup_menu_item_clicked(void *user_data, Evas_Object *obj, void *event_info)
1553 {
1554     Browser_Window *window = (Browser_Window *)user_data;
1555     Elm_Object_Item *item = (Elm_Object_Item *)event_info;
1556
1557     INFO("Selected popup menu index: %u", elm_menu_item_index_get(item));
1558     ewk_popup_menu_selected_index_set(window->popup.ewk_menu, elm_menu_item_index_get(item));
1559
1560     // Close popup menu.
1561     ewk_popup_menu_close(window->popup.ewk_menu);
1562 }
1563
1564 static void
1565 popup_menu_populate(Evas_Object *elm_menu, Ewk_Popup_Menu *ewk_menu, void *user_data)
1566 {
1567     const Eina_List* ewk_items = ewk_popup_menu_items_get(ewk_menu);
1568
1569     void *data;
1570     const Eina_List *l;
1571     EINA_LIST_FOREACH(ewk_items, l, data) {
1572         Ewk_Popup_Menu_Item *ewk_item = (Ewk_Popup_Menu_Item *)data;
1573         switch (ewk_popup_menu_item_type_get(ewk_item)) {
1574         case EWK_POPUP_MENU_SEPARATOR:
1575             elm_menu_item_separator_add(elm_menu, NULL);
1576             break;
1577         case EWK_POPUP_MENU_ITEM:
1578             if (ewk_popup_menu_item_is_label_get(ewk_item)) {
1579                 Elm_Object_Item *item = elm_menu_item_add(elm_menu, NULL, NULL, ewk_popup_menu_item_text_get(ewk_item), NULL, NULL);
1580                 elm_object_item_disabled_set(item, EINA_TRUE);
1581             } else {
1582                 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);
1583                 const char *tooltip_text = ewk_popup_menu_item_tooltip_get(ewk_item);
1584                 if (tooltip_text && tooltip_text[0] != '\0')
1585                     elm_object_item_tooltip_text_set(item, tooltip_text);
1586                 elm_object_item_disabled_set(item, !ewk_popup_menu_item_enabled_get(ewk_item));
1587                 elm_menu_item_selected_set(item, ewk_popup_menu_item_selected_get(ewk_item));
1588             }
1589             break;
1590         default:
1591             INFO("Unrecognized popup menu item type!");
1592             break;
1593         }
1594     }
1595 }
1596
1597 static Eina_Bool
1598 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)
1599 {
1600     Browser_Window *window = window_find_with_ewk_view(smartData->self);
1601
1602     if (window->popup.elm_menu)
1603         evas_object_del(window->popup.elm_menu);
1604
1605     window->popup.elm_menu = elm_menu_add(window->elm_window);
1606     window->popup.ewk_menu = ewk_menu;
1607
1608     popup_menu_populate(window->popup.elm_menu, ewk_menu, window);
1609
1610     INFO("Showing popup menu at (%d, %d)", rect.x, rect.y);
1611     elm_menu_move(window->popup.elm_menu, rect.x, rect.y);
1612     evas_object_show(window->popup.elm_menu);
1613
1614     return EINA_TRUE;
1615 }
1616
1617 static Eina_Bool
1618 on_popup_menu_hide(Ewk_View_Smart_Data *smartData)
1619 {
1620     Browser_Window *window = window_find_with_ewk_view(smartData->self);
1621
1622     if (!window->popup.elm_menu)
1623         return EINA_FALSE;
1624
1625     elm_menu_close(window->popup.elm_menu);
1626     window->popup.ewk_menu = NULL;
1627
1628     return EINA_TRUE;
1629 }
1630
1631 static Eina_Bool on_window_geometry_get(Ewk_View_Smart_Data *sd, Evas_Coord *x, Evas_Coord *y, Evas_Coord *width, Evas_Coord *height)
1632 {
1633     Browser_Window *window = window_find_with_ewk_view(sd->self);
1634
1635     evas_object_geometry_get(window->elm_window, x, y, width, height);
1636
1637     return EINA_TRUE;
1638 }
1639
1640 static Eina_Bool on_window_geometry_set(Ewk_View_Smart_Data *sd, Evas_Coord x, Evas_Coord y, Evas_Coord width, Evas_Coord height)
1641 {
1642     Browser_Window *window = window_find_with_ewk_view(sd->self);
1643
1644     evas_object_move(window->elm_window, x, y);
1645     evas_object_resize(window->elm_window, width, height);
1646
1647     return EINA_TRUE;
1648 }
1649
1650 typedef struct {
1651     Evas_Object *ewk_view;
1652     Evas_Object *permission_popup;
1653 } PermissionData;
1654
1655 static void
1656 on_fullscreen_accept(void *user_data, Evas_Object *obj, void *event_info)
1657 {
1658     PermissionData *permission_data = (PermissionData *)user_data;
1659     Browser_Window *window = window_find_with_ewk_view(permission_data->ewk_view);
1660
1661     elm_win_resize_object_del(window->elm_window, permission_data->permission_popup);
1662     evas_object_del(permission_data->permission_popup);
1663     evas_object_focus_set(permission_data->ewk_view, EINA_TRUE);
1664     free(permission_data);
1665 }
1666
1667 static void
1668 on_fullscreen_deny(void *user_data, Evas_Object *obj, void *event_info)
1669 {
1670     PermissionData *permission_data = (PermissionData *)user_data;
1671     Browser_Window *window = window_find_with_ewk_view(permission_data->ewk_view);
1672
1673     ewk_view_fullscreen_exit(permission_data->ewk_view);
1674     elm_win_resize_object_del(window->elm_window, permission_data->permission_popup);
1675     evas_object_del(permission_data->permission_popup);
1676     evas_object_focus_set(permission_data->ewk_view, EINA_TRUE);
1677     free(permission_data);
1678 }
1679
1680 static Eina_Bool on_fullscreen_enter(Ewk_View_Smart_Data *sd, Ewk_Security_Origin *origin)
1681 {
1682     Browser_Window *window = window_find_with_ewk_view(sd->self);
1683
1684     /* Go fullscreen */
1685     toggle_window_fullscreen(window, EINA_TRUE);
1686
1687     /* Show user popup */
1688     Evas_Object *permission_popup = elm_popup_add(window->elm_window);
1689     evas_object_size_hint_weight_set(permission_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1690
1691     Eina_Strbuf *message = eina_strbuf_new();
1692     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));
1693     elm_object_text_set(permission_popup, eina_strbuf_string_get(message));
1694     eina_strbuf_free(message);
1695     elm_object_part_text_set(permission_popup, "title,text", "Fullscreen Permission");
1696
1697     /* Popup buttons */
1698     PermissionData *permission_data = (PermissionData *)malloc(sizeof(PermissionData));
1699     permission_data->ewk_view = window->ewk_view;
1700     permission_data->permission_popup = permission_popup;
1701     Evas_Object *accept_button = elm_button_add(permission_popup);
1702     elm_object_text_set(accept_button, "Accept");
1703     elm_object_part_content_set(permission_popup, "button1", accept_button);
1704     evas_object_smart_callback_add(accept_button, "clicked", on_fullscreen_accept, permission_data);
1705
1706     Evas_Object *deny_button = elm_button_add(permission_popup);
1707     elm_object_text_set(deny_button, "Deny");
1708     elm_object_part_content_set(permission_popup, "button2", deny_button);
1709     evas_object_smart_callback_add(deny_button, "clicked", on_fullscreen_deny, permission_data);
1710     elm_win_resize_object_add(window->elm_window, permission_popup);
1711     evas_object_show(permission_popup);
1712
1713     return EINA_TRUE;
1714 }
1715
1716 static Eina_Bool on_fullscreen_exit(Ewk_View_Smart_Data *sd)
1717 {
1718     Browser_Window *window = window_find_with_ewk_view(sd->self);
1719
1720     toggle_window_fullscreen(window, EINA_FALSE);
1721
1722     return EINA_TRUE;
1723 }
1724
1725 static Evas_Object *
1726 on_window_create(Ewk_View_Smart_Data *smartData, Ewk_View_Configuration* configuration, const Ewk_Window_Features *window_features)
1727 {
1728     int x = 0;
1729     int y = 0;
1730     int width = 0;
1731     int height = 0;
1732
1733     ewk_window_features_geometry_get(window_features, &x, &y, &width, &height);
1734
1735     if (!width)
1736         width = window_width;
1737
1738     if (!height)
1739         height = window_height;
1740
1741     Browser_Window *window = window_create(configuration, width, height);
1742     Evas_Object *new_view = window->ewk_view;
1743
1744     windows = eina_list_append(windows, window);
1745
1746     INFO("minibrowser: location(%d,%d) size=(%d,%d)", x, y, width, height);
1747
1748     return new_view;
1749 }
1750
1751 static void
1752 on_window_close(Ewk_View_Smart_Data *smartData)
1753 {
1754     Browser_Window *window = window_find_with_ewk_view(smartData->self);
1755     window_close(window);
1756 }
1757
1758 static void
1759 context_menu_item_selected_cb(void *data, Evas_Object *obj, void *event_info)
1760 {
1761     if (!data) {
1762         ERROR("Context menu callback data is NULL.");
1763         return;
1764     }
1765
1766     Ewk_Context_Menu_Item *ewk_item = (Ewk_Context_Menu_Item *)data;
1767     INFO("Selected context menu item: %s.", ewk_context_menu_item_title_get(ewk_item));
1768     ewk_context_menu_item_select(ewk_context_menu_item_parent_menu_get(ewk_item), ewk_item);
1769     ewk_context_menu_hide(ewk_context_menu_item_parent_menu_get(ewk_item));
1770 }
1771
1772 static void
1773 context_menu_populate(Evas_Object* context_menu, Ewk_Context_Menu *ewk_menu, Elm_Object_Item *parent_item)
1774 {
1775     if (!context_menu || !ewk_menu) {
1776         ERROR("Necessary objects are NULL.");
1777         return;
1778     }
1779
1780     const Eina_List *list = ewk_context_menu_items_get(ewk_menu);
1781     const Eina_List *l;
1782     void *data;
1783
1784     Ewk_Context_Menu_Item *ewk_item;
1785     Elm_Object_Item *elm_menu_item;
1786     Evas_Object *elm_check_item;
1787
1788     EINA_LIST_FOREACH(list, l, data) {
1789         ewk_item = (Ewk_Context_Menu_Item *)data;
1790         switch (ewk_context_menu_item_type_get(ewk_item)) {
1791         case EWK_ACTION_TYPE:
1792             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);
1793             break;
1794         case EWK_CHECKABLE_ACTION_TYPE:
1795             elm_check_item = elm_check_add(context_menu);
1796             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);
1797             elm_object_item_content_set(elm_menu_item, elm_check_item);
1798             elm_check_state_set(elm_check_item, ewk_context_menu_item_checked_get(ewk_item));
1799             break;
1800         case EWK_SUBMENU_TYPE:
1801             elm_menu_item = elm_menu_item_add(context_menu, parent_item, NULL, ewk_context_menu_item_title_get(ewk_item), NULL, ewk_item);
1802             if (elm_menu_item)
1803                 context_menu_populate(context_menu, ewk_context_menu_item_submenu_get(ewk_item), elm_menu_item);
1804             break;
1805         default:
1806             continue;
1807         }
1808         elm_object_item_disabled_set(elm_menu_item, !ewk_context_menu_item_enabled_get(ewk_item));
1809     }
1810 }
1811
1812 static Eina_Bool
1813 on_context_menu_show(Ewk_View_Smart_Data *sd, Evas_Coord x, Evas_Coord y, Ewk_Context_Menu *menu)
1814 {
1815     Browser_Window *window = window_find_with_ewk_view(sd->self);
1816
1817     if (!window || !menu) {
1818         ERROR("Necessary objects are NULL.");
1819         return EINA_FALSE;
1820     }
1821
1822     window->context_menu.elm_menu = elm_menu_add(window->elm_window);
1823
1824     if (!window->context_menu.elm_menu) {
1825         ERROR("Could not create menu widget.");
1826         return EINA_FALSE;
1827     }
1828
1829     window->context_menu.ewk_menu = menu;
1830
1831     context_menu_populate(window->context_menu.elm_menu, menu, NULL);
1832
1833     INFO("Showing context menu at (%d, %d).", x, y);
1834     elm_menu_move(window->context_menu.elm_menu, x, y);
1835     evas_object_show(window->context_menu.elm_menu);
1836
1837     return EINA_TRUE;
1838 }
1839
1840 static Eina_Bool
1841 on_context_menu_hide(Ewk_View_Smart_Data *sd)
1842 {
1843     Browser_Window *window = window_find_with_ewk_view(sd->self);
1844
1845     if (!window || !window->context_menu.elm_menu) {
1846         ERROR("Necessary objects are NULL.");
1847         return EINA_FALSE;
1848     }
1849
1850     elm_menu_close(window->context_menu.elm_menu);
1851     evas_object_del(window->context_menu.elm_menu);
1852     window->context_menu.elm_menu = NULL;
1853     window->context_menu.ewk_menu = NULL;
1854
1855     return EINA_TRUE;
1856 }
1857
1858 static void
1859 auth_popup_close(Auth_Data *auth_data)
1860 {
1861     ewk_object_unref(auth_data->request);
1862     evas_object_del(auth_data->popup);
1863     free(auth_data);
1864 }
1865
1866 static void
1867 on_auth_cancel(void *user_data, Evas_Object *obj, void *event_info)
1868 {
1869     Auth_Data *auth_data = (Auth_Data *)user_data;
1870
1871     ewk_auth_request_cancel(auth_data->request);
1872
1873     auth_popup_close(auth_data);
1874 }
1875
1876 static void
1877 on_auth_ok(void *user_data, Evas_Object *obj, void *event_info)
1878 {
1879     Auth_Data *auth_data = (Auth_Data *)user_data;
1880
1881     const char *username = elm_entry_entry_get(auth_data->username_entry);
1882     const char *password = elm_entry_entry_get(auth_data->password_entry);
1883     ewk_auth_request_authenticate(auth_data->request, username, password);
1884
1885     auth_popup_close(auth_data);
1886 }
1887
1888 static void
1889 on_authentication_request(void *user_data, Evas_Object *obj, void *event_info)
1890 {
1891     Browser_Window *window = (Browser_Window *)user_data;
1892     Ewk_Auth_Request *request = ewk_object_ref((Ewk_Auth_Request *)event_info);
1893
1894     Auth_Data *auth_data = (Auth_Data *)malloc(sizeof(Auth_Data));
1895     auth_data->request = request;
1896
1897     Evas_Object *auth_popup = elm_popup_add(window->elm_window);
1898     auth_data->popup = auth_popup;
1899     evas_object_size_hint_weight_set(auth_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1900     elm_object_part_text_set(auth_popup, "title,text", "Authentication Required");
1901
1902     /* Popup Content */
1903     Evas_Object *vbox = elm_box_add(auth_popup);
1904     elm_box_padding_set(vbox, 0, 4);
1905     evas_object_size_hint_weight_set(vbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1906     evas_object_size_hint_align_set(vbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
1907     elm_object_content_set(auth_popup, vbox);
1908     evas_object_show(vbox);
1909
1910     /* Authentication message */
1911     Evas_Object *label = elm_label_add(auth_popup);
1912     elm_label_line_wrap_set(label, ELM_WRAP_WORD);
1913     Eina_Strbuf *auth_text = eina_strbuf_new();
1914     const char *host = ewk_auth_request_host_get(request);
1915     const char *realm = ewk_auth_request_realm_get(request);
1916     eina_strbuf_append_printf(auth_text, "A username and password are being requested by %s. The site says: \"%s\"", host, realm ? realm : "");
1917     elm_object_text_set(label, eina_strbuf_string_get(auth_text));
1918     eina_strbuf_free(auth_text);
1919     evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1920     evas_object_size_hint_align_set(label, EVAS_HINT_FILL, EVAS_HINT_FILL);
1921     elm_box_pack_end(vbox, label);
1922     evas_object_show(label);
1923
1924     /* Credential table */
1925     Evas_Object *table = elm_table_add(auth_popup);
1926     elm_table_padding_set(table, 2, 2);
1927     elm_table_homogeneous_set(table, EINA_TRUE);
1928     evas_object_size_hint_weight_set(table, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1929     evas_object_size_hint_align_set(table, EVAS_HINT_FILL, EVAS_HINT_FILL);
1930     elm_box_pack_end(vbox, table);
1931     evas_object_show(table);
1932
1933     /* Username row */
1934     Evas_Object *username_label = elm_label_add(auth_popup);
1935     elm_object_text_set(username_label, "Username:");
1936     evas_object_size_hint_weight_set(username_label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1937     evas_object_size_hint_align_set(username_label, 1, EVAS_HINT_FILL);
1938     elm_table_pack(table, username_label, 0, 0, 1, 1);
1939     evas_object_show(username_label);
1940
1941     Evas_Object *username_entry = elm_entry_add(auth_popup);
1942     auth_data->username_entry = username_entry;
1943     elm_entry_scrollable_set(username_entry, EINA_TRUE);
1944     elm_entry_single_line_set(username_entry, EINA_TRUE);
1945     elm_entry_text_style_user_push(username_entry, "DEFAULT='font_size=18'");
1946     const char *suggested_username = ewk_auth_request_suggested_username_get(request);
1947     elm_entry_entry_set(username_entry, suggested_username ? suggested_username : "");
1948     evas_object_size_hint_weight_set(username_entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1949     evas_object_size_hint_align_set(username_entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1950     elm_table_pack(table, username_entry, 1, 0, 2, 1);
1951     elm_object_focus_set(username_entry, EINA_TRUE);
1952     evas_object_show(username_entry);
1953
1954     /* Password row */
1955     Evas_Object *password_label = elm_label_add(auth_popup);
1956     elm_object_text_set(password_label, "Password:");
1957     evas_object_size_hint_weight_set(password_label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1958     evas_object_size_hint_align_set(password_label, 1, EVAS_HINT_FILL);
1959     elm_table_pack(table, password_label, 0, 1, 1, 1);
1960     evas_object_show(password_label);
1961
1962     Evas_Object *password_entry = elm_entry_add(auth_popup);
1963     auth_data->password_entry = password_entry;
1964     elm_entry_scrollable_set(password_entry, EINA_TRUE);
1965     elm_entry_single_line_set(password_entry, EINA_TRUE);
1966     elm_entry_password_set(password_entry, EINA_TRUE);
1967     elm_entry_text_style_user_push(password_entry, "DEFAULT='font_size=18'");
1968     evas_object_size_hint_weight_set(password_entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1969     evas_object_size_hint_align_set(password_entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1970     elm_table_pack(table, password_entry, 1, 1, 2, 1);
1971     evas_object_show(password_entry);
1972
1973     /* Popup buttons */
1974     Evas_Object *cancel_button = elm_button_add(auth_popup);
1975     elm_object_text_set(cancel_button, "Cancel");
1976     elm_object_part_content_set(auth_popup, "button1", cancel_button);
1977     evas_object_smart_callback_add(cancel_button, "clicked", on_auth_cancel, auth_data);
1978     Evas_Object *ok_button = elm_button_add(auth_popup);
1979     elm_object_text_set(ok_button, "OK");
1980     elm_object_part_content_set(auth_popup, "button2", ok_button);
1981     evas_object_smart_callback_add(ok_button, "clicked", on_auth_ok, auth_data);
1982     evas_object_show(auth_popup);
1983 }
1984
1985 static void
1986 on_search_text_found(void *user_data, Evas_Object *obj, void *event_info)
1987 {
1988     Browser_Window *window = (Browser_Window *)user_data;
1989
1990     const int *match_count = (const int *)(event_info);
1991
1992     if (*match_count) {
1993         Eina_Strbuf *search_text = eina_strbuf_new();
1994         eina_strbuf_append_printf(search_text, "  %d  Matches Found " , *match_count);
1995         elm_object_text_set(window->search.search_field_count, eina_strbuf_string_get(search_text));
1996         eina_strbuf_free(search_text);
1997     } else
1998         elm_object_text_set(window->search.search_field_count, " No Matches Found");
1999
2000     evas_object_focus_set(window->ewk_view, EINA_FALSE);
2001     elm_object_focus_set(window->search.search_field_count, EINA_FALSE);
2002     elm_object_focus_set(window->search.search_field, EINA_TRUE);
2003 }
2004
2005 static void
2006 on_tooltip_text_set(void *user_data, Evas_Object *obj, void *event_info)
2007 {
2008     Browser_Window *window = (Browser_Window *)user_data;
2009     const char *message = (const char*)event_info;
2010
2011     elm_object_tooltip_text_set(window->elm_window, message);
2012     window->tooltip.text_set = EINA_TRUE;
2013     window_tooltip_update(window);
2014 }
2015
2016 static void
2017 on_tooltip_text_unset(void *user_data, Evas_Object *obj, void *event_info)
2018 {
2019     Browser_Window *window = (Browser_Window *)user_data;
2020
2021     window_tooltip_hide(window);
2022     elm_object_tooltip_unset(window->elm_window);
2023     window->tooltip.text_set = EINA_FALSE;
2024 }
2025
2026 static void
2027 on_navigation_policy_decision(void *user_data, Evas_Object *obj, void *event_info)
2028 {
2029     Ewk_Navigation_Policy_Decision *decision = (Ewk_Navigation_Policy_Decision *)event_info;
2030
2031     if (ewk_navigation_policy_mouse_button_get(decision) == EWK_EVENT_MOUSE_BUTTON_MIDDLE) {
2032         Browser_Window *window = window_create(NULL, 0, 0);
2033         ewk_view_url_set(window->ewk_view, ewk_url_request_url_get(ewk_navigation_policy_request_get(decision)));
2034         windows = eina_list_append(windows, window);
2035         INFO("Mouse middle button pressed, open link in new window");
2036
2037         ewk_navigation_policy_decision_reject(decision);
2038     }
2039 }
2040
2041 static void
2042 on_home_button_clicked(void *user_data, Evas_Object *home_button, void *event_info)
2043 {
2044     Browser_Window *window = (Browser_Window *)user_data;
2045
2046     ewk_view_url_set(window->ewk_view, DEFAULT_URL);
2047 }
2048
2049 static void
2050 on_window_deletion(void *user_data, Evas_Object *elm_window, void *event_info)
2051 {
2052     Browser_Window *window = (Browser_Window *)user_data;
2053     ewk_view_try_close(window->ewk_view);
2054 }
2055
2056 static Evas_Object *
2057 create_toolbar_button(Evas_Object *elm_window, const char *icon_name)
2058 {
2059     Evas_Object *button = elm_button_add(elm_window);
2060
2061     Evas_Object *icon = elm_icon_add(elm_window);
2062     elm_icon_standard_set(icon, icon_name);
2063     evas_object_size_hint_max_set(icon, TOOL_BAR_ICON_SIZE, TOOL_BAR_ICON_SIZE);
2064     evas_object_color_set(icon, 44, 44, 102, 128);
2065     evas_object_show(icon);
2066     elm_object_part_content_set(button, "icon", icon);
2067     evas_object_size_hint_min_set(button, TOOL_BAR_BUTTON_SIZE, TOOL_BAR_BUTTON_SIZE);
2068
2069     return button;
2070 }
2071
2072 static Browser_Window *window_create(Ewk_View_Configuration* configuration, int width, int height)
2073 {
2074     Browser_Window *window = calloc(1, sizeof(Browser_Window));
2075     if (!window) {
2076         ERROR("Could not create browser window.");
2077         return NULL;
2078     }
2079
2080     /* Initialize tooltip information */
2081     window->tooltip.show_timer = NULL;
2082     window->tooltip.activated = EINA_FALSE;
2083     window->tooltip.text_set = EINA_FALSE;
2084     window->tooltip.shown = EINA_FALSE;
2085
2086     /* Create window */
2087     window->elm_window = elm_win_add(NULL, "minibrowser-window", ELM_WIN_BASIC);
2088     elm_win_title_set(window->elm_window, APP_NAME);
2089     evas_object_smart_callback_add(window->elm_window, "delete,request", on_window_deletion, window);
2090
2091     /* Create window background */
2092     Evas_Object *bg = elm_bg_add(window->elm_window);
2093     elm_bg_color_set(bg, 193, 192, 191);
2094     evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2095     elm_win_resize_object_add(window->elm_window, bg);
2096     evas_object_show(bg);
2097
2098     /* Create conformant widget. */
2099     Evas_Object *conformant = elm_conformant_add(window->elm_window);
2100     evas_object_size_hint_weight_set(conformant, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2101     elm_win_resize_object_add(window->elm_window, conformant);
2102     evas_object_show(conformant);
2103
2104     /* Create vertical layout */
2105     window->vertical_layout = elm_box_add(window->elm_window);
2106     elm_object_content_set(conformant, window->vertical_layout);
2107     elm_box_padding_set(window->vertical_layout, 0, 2);
2108     evas_object_size_hint_weight_set(window->vertical_layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2109     evas_object_show(window->vertical_layout);
2110
2111     /* Create horizontal layout for top bar */
2112     window->horizontal_layout = elm_box_add(window->elm_window);
2113     elm_box_horizontal_set(window->horizontal_layout, EINA_TRUE);
2114     evas_object_size_hint_weight_set(window->horizontal_layout, EVAS_HINT_EXPAND, 0.0);
2115     evas_object_size_hint_align_set(window->horizontal_layout, EVAS_HINT_FILL, 0.0);
2116     elm_box_pack_end(window->vertical_layout, window->horizontal_layout);
2117     evas_object_show(window->horizontal_layout);
2118
2119     /* Create Back button */
2120     window->back_button = create_toolbar_button(window->elm_window, "arrow_left");
2121     evas_object_smart_callback_add(window->back_button, "clicked", on_back_button_clicked, window);
2122     evas_object_smart_callback_add(window->back_button, "repeated", on_back_button_longpress, window);
2123     elm_object_tooltip_text_set(window->back_button, "Click to go back, longpress to see session history");
2124     elm_object_tooltip_window_mode_set(window->back_button, EINA_TRUE);
2125     elm_object_disabled_set(window->back_button, EINA_TRUE);
2126     evas_object_size_hint_weight_set(window->back_button, 0.0, EVAS_HINT_EXPAND);
2127     evas_object_size_hint_align_set(window->back_button, 0.0, 0.5);
2128     elm_box_pack_end(window->horizontal_layout, window->back_button);
2129     evas_object_show(window->back_button);
2130
2131     /* Create Forward button */
2132     window->forward_button = create_toolbar_button(window->elm_window, "arrow_right");
2133     evas_object_smart_callback_add(window->forward_button, "clicked", on_forward_button_clicked, window);
2134     evas_object_smart_callback_add(window->forward_button, "repeated", on_forward_button_longpress, window);
2135     elm_object_tooltip_text_set(window->forward_button, "Click to go forward, longpress to see session history");
2136     elm_object_tooltip_window_mode_set(window->forward_button, EINA_TRUE);
2137     elm_object_disabled_set(window->forward_button, EINA_TRUE);
2138     evas_object_size_hint_weight_set(window->forward_button, 0.0, EVAS_HINT_EXPAND);
2139     evas_object_size_hint_align_set(window->forward_button, 0.0, 0.5);
2140     elm_box_pack_end(window->horizontal_layout, window->forward_button);
2141     evas_object_show(window->forward_button);
2142
2143     /* Create URL bar */
2144     window->url_bar = elm_entry_add(window->elm_window);
2145     elm_entry_scrollable_set(window->url_bar, EINA_TRUE);
2146     elm_scroller_policy_set(window->url_bar, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
2147     elm_entry_single_line_set(window->url_bar, EINA_TRUE);
2148     elm_entry_cnp_mode_set(window->url_bar, ELM_CNP_MODE_PLAINTEXT);
2149     elm_entry_text_style_user_push(window->url_bar, "DEFAULT='font_size=18'");
2150     evas_object_smart_callback_add(window->url_bar, "activated", on_url_bar_activated, window);
2151     evas_object_smart_callback_add(window->url_bar, "clicked", on_url_bar_clicked, window);
2152     evas_object_size_hint_weight_set(window->url_bar, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2153     evas_object_size_hint_align_set(window->url_bar, EVAS_HINT_FILL, EVAS_HINT_FILL);
2154     elm_box_pack_end(window->horizontal_layout, window->url_bar);
2155     evas_object_show(window->url_bar);
2156
2157     /* Create Refresh button */
2158     Evas_Object *refresh_button = create_toolbar_button(window->elm_window, "refresh");
2159     evas_object_smart_callback_add(refresh_button, "clicked", on_refresh_button_clicked, window);
2160     elm_object_tooltip_text_set(refresh_button, "Reload page");
2161     elm_object_tooltip_window_mode_set(refresh_button, EINA_TRUE);
2162     evas_object_size_hint_weight_set(refresh_button, 0.0, EVAS_HINT_EXPAND);
2163     evas_object_size_hint_align_set(refresh_button, 1.0, 0.5);
2164     elm_box_pack_end(window->horizontal_layout, refresh_button);
2165     evas_object_show(refresh_button);
2166
2167     /* Create Stop button */
2168     Evas_Object *stop_button = create_toolbar_button(window->elm_window, "close");
2169     evas_object_smart_callback_add(stop_button, "clicked", on_stop_button_clicked, window);
2170     elm_object_tooltip_text_set(stop_button, "Stop page load");
2171     elm_object_tooltip_window_mode_set(stop_button, EINA_TRUE);
2172     evas_object_size_hint_weight_set(stop_button, 0.0, EVAS_HINT_EXPAND);
2173     evas_object_size_hint_align_set(stop_button, 1.0, 0.5);
2174     elm_box_pack_end(window->horizontal_layout, stop_button);
2175     evas_object_show(stop_button);
2176
2177     /* Create Home button */
2178     Evas_Object *home_button = create_toolbar_button(window->elm_window, "home");
2179     evas_object_smart_callback_add(home_button, "clicked", on_home_button_clicked, window);
2180     elm_object_tooltip_text_set(home_button, "Home page");
2181     elm_object_tooltip_window_mode_set(home_button, EINA_TRUE);
2182     evas_object_size_hint_weight_set(home_button, 0.0, EVAS_HINT_EXPAND);
2183     evas_object_size_hint_align_set(home_button, 1.0, 0.5);
2184     elm_box_pack_end(window->horizontal_layout, home_button);
2185     evas_object_show(home_button);
2186
2187     /* Create Search bar */
2188     window->search.search_bar = elm_box_add(window->elm_window);
2189     elm_box_horizontal_set(window->search.search_bar, EINA_TRUE);
2190     evas_object_size_hint_min_set(window->search.search_bar, SEARCH_FIELD_SIZE + 2 * SEARCH_BUTTON_SIZE, 0);
2191     evas_object_size_hint_align_set(window->search.search_bar, EVAS_HINT_FILL, EVAS_HINT_FILL);
2192     elm_box_pack_end(window->vertical_layout, window->search.search_bar);
2193
2194     /* Create Search field */
2195     window->search.search_field = elm_entry_add(window->elm_window);
2196     elm_entry_scrollable_set(window->search.search_field, EINA_TRUE);
2197     elm_scroller_policy_set(window->search.search_field, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
2198     elm_entry_single_line_set(window->search.search_field, EINA_TRUE);
2199     elm_entry_cnp_mode_set(window->search.search_field, ELM_CNP_MODE_PLAINTEXT);
2200     elm_entry_text_style_user_push(window->search.search_field, "DEFAULT='font_size=14'");
2201     evas_object_smart_callback_add(window->search.search_field, "activated", on_search_field_activated, window);
2202     evas_object_smart_callback_add(window->search.search_field, "changed", on_search_field_activated, window);
2203     evas_object_smart_callback_add(window->search.search_field, "aborted", on_search_field_aborted, window);
2204     evas_object_smart_callback_add(window->search.search_field, "clicked", on_search_field_clicked, window);
2205     evas_object_size_hint_weight_set(window->search.search_field, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2206     evas_object_size_hint_align_set(window->search.search_field, EVAS_HINT_FILL, EVAS_HINT_FILL);
2207     elm_box_pack_end(window->search.search_bar, window->search.search_field);
2208
2209     /* Create Search backward button */
2210     window->search.backward_button = create_toolbar_button(window->elm_window, "arrow_up");
2211     evas_object_smart_callback_add(window->search.backward_button, "clicked", on_search_backward_button_clicked, window);
2212     elm_object_disabled_set(window->search.backward_button, EINA_FALSE);
2213     evas_object_size_hint_weight_set(window->search.backward_button, 0.0, EVAS_HINT_EXPAND);
2214     evas_object_size_hint_align_set(window->search.backward_button, 1.0, 0.5);
2215     evas_object_size_hint_min_set(window->search.backward_button, SEARCH_BUTTON_SIZE, SEARCH_BUTTON_SIZE);
2216     elm_box_pack_end(window->search.search_bar, window->search.backward_button);
2217
2218     /* Create Search forwardward button */
2219     window->search.forward_button = create_toolbar_button(window->elm_window, "arrow_down");
2220     evas_object_smart_callback_add(window->search.forward_button, "clicked", on_search_forward_button_clicked, window);
2221     elm_object_disabled_set(window->search.forward_button, EINA_FALSE);
2222     evas_object_size_hint_weight_set(window->search.forward_button, 0.0, EVAS_HINT_EXPAND);
2223     evas_object_size_hint_align_set(window->search.forward_button, 1.0, 0.5);
2224     evas_object_size_hint_min_set(window->search.forward_button, SEARCH_BUTTON_SIZE, SEARCH_BUTTON_SIZE);
2225     elm_box_pack_end(window->search.search_bar, window->search.forward_button);
2226
2227     /* Create Search count field */
2228     window->search.search_field_count = elm_label_add(window->elm_window);
2229     evas_object_size_hint_weight_set(window->search.search_field_count, 0.0, EVAS_HINT_EXPAND);
2230     evas_object_size_hint_align_set(window->search.search_field_count, EVAS_HINT_FILL, EVAS_HINT_FILL);
2231     elm_object_text_set(window->search.search_field_count, "");
2232     elm_box_pack_end(window->search.search_bar, window->search.search_field_count);
2233
2234     /* Create Search Case Sensitive Option check box */
2235     window->search.search_case_check_box = elm_check_add(window->elm_window);
2236     elm_object_text_set(window->search.search_case_check_box, "Case Sensitive");
2237     evas_object_smart_callback_add(window->search.search_case_check_box, "changed", on_search_case_option_changed, window);
2238     elm_box_pack_end(window->search.search_bar, window->search.search_case_check_box);
2239
2240     /* Create Search Word Start Option check box */
2241     window->search.search_word_start_check_box = elm_check_add(window->elm_window);
2242     elm_object_text_set(window->search.search_word_start_check_box, "Only Word Start");
2243     evas_object_smart_callback_add(window->search.search_word_start_check_box, "changed", on_search_word_start_option_changed, window);
2244     elm_box_pack_end(window->search.search_bar, window->search.search_word_start_check_box);
2245
2246     /* Create Search close button */
2247     window->search.close_button = create_toolbar_button(window->elm_window, "close");
2248     evas_object_smart_callback_add(window->search.close_button, "clicked", on_search_close_button_clicked, window);
2249     elm_object_disabled_set(window->search.close_button, EINA_FALSE);
2250     evas_object_size_hint_weight_set(window->search.close_button, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2251     evas_object_size_hint_align_set(window->search.close_button, 1.0, 0.5);
2252     evas_object_size_hint_min_set(window->search.close_button, SEARCH_BUTTON_SIZE, SEARCH_BUTTON_SIZE);
2253     elm_box_pack_end(window->search.search_bar, window->search.close_button);
2254
2255     /* Create history box */
2256     window->history.history_box = elm_box_add(window->elm_window);
2257     evas_object_size_hint_aspect_set(window->history.history_box, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
2258     evas_object_size_hint_weight_set(window->history.history_box, EVAS_HINT_EXPAND , EVAS_HINT_EXPAND);
2259
2260     /* Create history list */
2261     window->history.history_list = elm_genlist_add(window->elm_window);
2262     evas_object_size_hint_weight_set(window->history.history_list, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2263     evas_object_size_hint_align_set(window->history.history_list, EVAS_HINT_FILL, EVAS_HINT_FILL);
2264     elm_win_resize_object_add(window->elm_window, window->history.history_box);
2265     elm_box_pack_end(window->history.history_box, window->history.history_list);
2266
2267     /* Create ewk_view */
2268     Ewk_View_Smart_Class *ewkViewClass = miniBrowserViewSmartClass();
2269     ewkViewClass->run_javascript_alert = on_javascript_alert;
2270     ewkViewClass->run_javascript_confirm = on_javascript_confirm;
2271     ewkViewClass->run_javascript_prompt = on_javascript_prompt;
2272     ewkViewClass->run_javascript_before_unload_confirm = on_javascript_before_unload_confirm;
2273     ewkViewClass->window_geometry_get = on_window_geometry_get;
2274     ewkViewClass->window_geometry_set = on_window_geometry_set;
2275     ewkViewClass->fullscreen_enter = on_fullscreen_enter;
2276     ewkViewClass->fullscreen_exit = on_fullscreen_exit;
2277     ewkViewClass->window_create = on_window_create;
2278     ewkViewClass->window_close = on_window_close;
2279     ewkViewClass->popup_menu_show = on_popup_menu_show;
2280     ewkViewClass->popup_menu_hide = on_popup_menu_hide;
2281     ewkViewClass->context_menu_show = on_context_menu_show;
2282     ewkViewClass->context_menu_hide = on_context_menu_hide;
2283     ewkViewClass->input_picker_color_request = on_color_picker_request;
2284     ewkViewClass->input_picker_color_dismiss = on_color_picker_dismiss;
2285
2286     Evas *evas = evas_object_evas_get(window->elm_window);
2287     Evas_Smart *smart = evas_smart_class_new(&ewkViewClass->sc);
2288     window->ewk_view = ewk_view_add_with_configuration(evas, smart, configuration);
2289
2290     Ewk_Context *context = ewk_view_context_get(window->ewk_view);
2291     ewk_favicon_database_icon_change_callback_add(ewk_context_favicon_database_get(context), on_icon_changed_cb, window);
2292
2293     ewk_view_theme_set(window->ewk_view, DEFAULT_THEME_DIR "/default.edj");
2294     if (device_pixel_ratio)
2295         ewk_view_device_pixel_ratio_set(window->ewk_view, (float)device_pixel_ratio);
2296     ewk_view_user_agent_set(window->ewk_view, user_agent_string);
2297     ewk_view_layout_fixed_set(window->ewk_view, fixed_layout_enabled);
2298
2299     if (touch_events_enabled) {
2300         ewk_view_touch_events_enabled_set(window->ewk_view, EINA_TRUE);
2301         ewk_view_mouse_events_enabled_set(window->ewk_view, EINA_FALSE);
2302     }
2303
2304     if (background_color_string) {
2305         int red, green, blue, alpha;
2306
2307         if (sscanf(background_color_string, "%d:%d:%d:%d", &red, &green, &blue, &alpha))
2308             ewk_view_bg_color_set(window->ewk_view, red, green, blue, alpha);
2309     }
2310
2311     /* Set the zoom level to default */
2312     window->current_zoom_level = DEFAULT_ZOOM_LEVEL;
2313
2314     elm_win_fullscreen_set(window->elm_window, fullscreen_enabled);
2315
2316     evas_object_smart_callback_add(window->ewk_view, "authentication,request", on_authentication_request, window);
2317     evas_object_smart_callback_add(window->ewk_view, "file,chooser,request", on_file_chooser_request, window);
2318     evas_object_smart_callback_add(window->ewk_view, "load,error", on_error, window);
2319     evas_object_smart_callback_add(window->ewk_view, "load,provisional,failed", on_error, window);
2320     evas_object_smart_callback_add(window->ewk_view, "load,progress", on_progress, window);
2321     evas_object_smart_callback_add(window->ewk_view, "title,changed", on_title_changed, window);
2322     evas_object_smart_callback_add(window->ewk_view, "url,changed", on_url_changed, window);
2323     evas_object_smart_callback_add(window->ewk_view, "back,forward,list,changed", on_back_forward_list_changed, window);
2324     evas_object_smart_callback_add(window->ewk_view, "text,found", on_search_text_found, window);
2325     evas_object_smart_callback_add(window->ewk_view, "tooltip,text,set", on_tooltip_text_set, window);
2326     evas_object_smart_callback_add(window->ewk_view, "tooltip,text,unset", on_tooltip_text_unset, window);
2327     evas_object_smart_callback_add(window->ewk_view, "policy,decision,navigation", on_navigation_policy_decision, window);
2328
2329     evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_KEY_DOWN, on_key_down, window);
2330     evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_MOUSE_DOWN, on_mouse_down, window);
2331
2332     evas_object_size_hint_weight_set(window->ewk_view, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2333     evas_object_size_hint_align_set(window->ewk_view, EVAS_HINT_FILL, EVAS_HINT_FILL);
2334     elm_box_pack_before(window->vertical_layout, window->ewk_view, window->search.search_bar);
2335     evas_object_show(window->ewk_view);
2336
2337     evas_object_resize(window->elm_window, width ? width : window_width, height ? height : window_height);
2338     evas_object_show(window->elm_window);
2339     search_box_hide(window);
2340
2341     view_focus_set(window, EINA_TRUE);
2342     // Prevent window from stealing web view's focus on start up.
2343     elm_object_focus_allow_set(window->elm_window, EINA_FALSE);
2344
2345     evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_MOUSE_IN, on_mouse_in, window);
2346     evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_MOUSE_OUT, on_mouse_out, window);
2347     evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_MOUSE_MOVE, on_mouse_move, window);
2348     evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_MOUSE_WHEEL, on_mouse_wheel, window);
2349     evas_object_event_callback_add(window->elm_window, EVAS_CALLBACK_RESIZE, on_window_resize, window);
2350
2351     elm_button_autorepeat_set(window->back_button, EINA_TRUE);
2352     elm_button_autorepeat_set(window->forward_button, EINA_TRUE);
2353     elm_button_autorepeat_initial_timeout_set(window->back_button, LONGPRESS_INTERVAL_SECONDS);
2354     elm_button_autorepeat_initial_timeout_set(window->forward_button, LONGPRESS_INTERVAL_SECONDS);
2355
2356     return window;
2357 }
2358
2359 static Ewk_View_Configuration* configuration()
2360 {
2361     static Ewk_View_Configuration* default_configuration = 0;
2362
2363     if (default_configuration)
2364         return default_configuration;
2365
2366     default_configuration = ewk_view_configuration_new();
2367
2368     Ewk_Settings* settings = ewk_view_configuration_settings_get(default_configuration);
2369     ewk_settings_file_access_from_file_urls_allowed_set(settings, EINA_TRUE);
2370     ewk_settings_encoding_detector_enabled_set(settings, encoding_detector_enabled);
2371     ewk_settings_frame_flattening_enabled_set(settings, frame_flattening_enabled);
2372     ewk_settings_local_storage_enabled_set(settings, local_storage_enabled);
2373     ewk_settings_offline_web_application_cache_enabled_set(settings, offline_web_application_cache_enabled);
2374     INFO("HTML5 local storage is %s for this view.", local_storage_enabled ? "enabled" : "disabled");
2375     ewk_settings_developer_extras_enabled_set(settings, EINA_TRUE);
2376     ewk_settings_preferred_minimum_contents_width_set(settings, 0);
2377     ewk_text_checker_continuous_spell_checking_enabled_set(spell_checking_enabled);
2378     ewk_settings_web_security_enabled_set(settings, web_security_enabled);
2379
2380     return default_configuration;
2381 }
2382
2383 static Ewk_Cookie_Accept_Policy
2384 parse_cookies_policy(const char *input_string)
2385 {
2386     if (!strcmp(input_string, "always"))
2387         return EWK_COOKIE_ACCEPT_POLICY_ALWAYS;
2388     if (!strcmp(input_string, "never"))
2389         return EWK_COOKIE_ACCEPT_POLICY_NEVER;
2390     if (strcmp(input_string, "no-third-party"))
2391         INFO("Unrecognized type for cookies policy: %s.", input_string);
2392     return EWK_COOKIE_ACCEPT_POLICY_NO_THIRD_PARTY;
2393 }
2394
2395 static void
2396 parse_window_size(const char *input_string, int *width, int *height)
2397 {
2398     static const unsigned max_length = 4;
2399     int parsed_width;
2400     int parsed_height;
2401     char **arr;
2402     unsigned elements;
2403
2404     arr = eina_str_split_full(input_string, "x", 0, &elements);
2405
2406     if (elements == 2 && (strlen(arr[0]) <= max_length) && (strlen(arr[1]) <= max_length)) {
2407         parsed_width = atoi(arr[0]);
2408         if (width && parsed_width)
2409             *width = parsed_width;
2410
2411         parsed_height = atoi(arr[1]);
2412         if (height && parsed_height)
2413             *height = parsed_height;
2414     }
2415
2416     free(arr[0]);
2417     free(arr);
2418 }
2419
2420 EAPI_MAIN int
2421 elm_main(int argc, char *argv[])
2422 {
2423     int args = 1;
2424     unsigned char quitOption = 0;
2425     Browser_Window *window;
2426     char *window_size_string = NULL;
2427     char *cookies_policy_string = NULL;
2428
2429     Ecore_Getopt_Value values[] = {
2430         ECORE_GETOPT_VALUE_STR(evas_engine_name),
2431         ECORE_GETOPT_VALUE_STR(window_size_string),
2432         ECORE_GETOPT_VALUE_STR(user_agent_string),
2433         ECORE_GETOPT_VALUE_STR(extensions_path),
2434         ECORE_GETOPT_VALUE_DOUBLE(device_pixel_ratio),
2435         ECORE_GETOPT_VALUE_BOOL(quitOption),
2436         ECORE_GETOPT_VALUE_BOOL(encoding_detector_enabled),
2437         ECORE_GETOPT_VALUE_STR(background_color_string),
2438         ECORE_GETOPT_VALUE_BOOL(frame_flattening_enabled),
2439         ECORE_GETOPT_VALUE_BOOL(local_storage_enabled),
2440         ECORE_GETOPT_VALUE_BOOL(offline_web_application_cache_enabled),
2441         ECORE_GETOPT_VALUE_BOOL(fullscreen_enabled),
2442         ECORE_GETOPT_VALUE_BOOL(spell_checking_enabled),
2443         ECORE_GETOPT_VALUE_BOOL(touch_events_enabled),
2444         ECORE_GETOPT_VALUE_BOOL(fixed_layout_enabled),
2445         ECORE_GETOPT_VALUE_STR(cookies_policy_string),
2446         ECORE_GETOPT_VALUE_BOOL(web_security_enabled),
2447         ECORE_GETOPT_VALUE_BOOL(separated_process_enabled),
2448         ECORE_GETOPT_VALUE_BOOL(quitOption),
2449         ECORE_GETOPT_VALUE_BOOL(quitOption),
2450         ECORE_GETOPT_VALUE_BOOL(quitOption),
2451         ECORE_GETOPT_VALUE_NONE
2452     };
2453
2454     efreet_cache_update = 0;
2455
2456     if (!ewk_init())
2457         return EXIT_FAILURE;
2458
2459     _log_domain_id = eina_log_domain_register("minibrowser", EINA_COLOR_YELLOW);
2460
2461     ewk_view_smart_class_set(miniBrowserViewSmartClass());
2462
2463     ecore_app_args_set(argc, (const char **) argv);
2464     args = ecore_getopt_parse(&options, values, argc, argv);
2465
2466     if (args < 0)
2467         return quit(EINA_FALSE, "Could not parse options.");
2468
2469     if (quitOption)
2470         return quit(EINA_TRUE, NULL);
2471
2472     if (evas_engine_name)
2473         elm_config_accel_preference_set(evas_engine_name);
2474     else {
2475         evas_engine_name = "opengl:depth24:stencil8";
2476         elm_config_accel_preference_set(evas_engine_name);
2477     }
2478
2479     Ewk_Context *context = ewk_context_default_get();
2480
2481     if (separated_process_enabled)
2482         ewk_context_web_process_count_limit_set(context, 0);
2483
2484     // Enable favicon database.
2485     ewk_context_favicon_database_directory_set(context, NULL);
2486
2487     // Use a proper cache model.
2488     ewk_context_cache_model_set(context, EWK_CACHE_MODEL_PRIMARY_WEBBROWSER);
2489
2490     if (cookies_policy_string) {
2491         Ewk_Cookie_Accept_Policy cookie_policy = parse_cookies_policy(cookies_policy_string);
2492         ewk_cookie_manager_accept_policy_set(ewk_context_cookie_manager_get(context), cookie_policy);
2493
2494         if (cookie_policy == EWK_COOKIE_ACCEPT_POLICY_ALWAYS) {
2495             const char cookie_storage_directory[] = "/tmp/ewebkit2_minibrowser_cookie/";
2496             mkdir(cookie_storage_directory, S_IRWXU);
2497             char storage_name[64];
2498             snprintf(storage_name, sizeof(storage_name), "%stxt-cookie", cookie_storage_directory);
2499             ewk_cookie_manager_persistent_storage_set(ewk_context_cookie_manager_get(context), storage_name, EWK_COOKIE_PERSISTENT_STORAGE_TEXT);
2500         }
2501     }
2502
2503     if (window_size_string)
2504         parse_window_size(window_size_string, &window_width, &window_height);
2505
2506     window = window_create(configuration(), 0, 0);
2507     if (!window)
2508         return quit(EINA_FALSE, "Could not create browser window.");
2509
2510     // Set callbacks for download events.
2511     ewk_context_download_callbacks_set(context, on_download_request, on_download_failed, 0, on_download_finished, window);
2512
2513     if (args < argc) {
2514         char *url = url_from_user_input(argv[args]);
2515         url_load_from_user_input(window->ewk_view, url);
2516         free(url);
2517     } else
2518         ewk_view_url_set(window->ewk_view, DEFAULT_URL);
2519
2520     windows = eina_list_append(windows, window);
2521
2522     elm_run();
2523
2524     return quit(EINA_TRUE, NULL);
2525 }
2526 ELM_MAIN()
2527