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