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