[EFL] Adjust EFL indentation to EFL MiniBrowser
[WebKit-https.git] / Tools / MiniBrowser / efl / main.c
1 /*
2  * Copyright (C) 2012 Samsung Electronics
3  * Copyright (C) 2012 Intel Corporation. All rights reserved.
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19
20 #include "EWebKit2.h"
21 #include <Ecore.h>
22 #include <Ecore_Evas.h>
23 #include <Ecore_Getopt.h>
24 #include <Eet.h>
25 #include <Eina.h>
26 #include <Elementary.h>
27 #include <Evas.h>
28
29 extern int efreet_cache_update;
30
31 static const char DEFAULT_URL[] = "http://www.ewebkit.org/";
32 static const char APP_NAME[] = "EFL MiniBrowser";
33 static const char JAVASCRIPT_SCHEME[] = "javascript:";
34 static const char FILE_SCHEME[] = "file://";
35 static const char HTTP_SCHEME[] = "http://";
36 static const int TOOL_BAR_ICON_SIZE = 24;
37 static const int TOOL_BAR_BUTTON_SIZE = 32;
38 static const int SEARCH_FIELD_SIZE = 200;
39 static const int SEARCH_BUTTON_SIZE = 30;
40 static const int MAX_SEARCH_COUNT = 1000;
41 static const double TOOLTIP_DELAY_SECONDS = 1.0;
42 static const double LONGPRESS_INTERVAL_SECONDS = 1.5;
43 static const double LIST_ITEM_HEIGHT = 24.35;
44
45 static Eina_List *windows = NULL;
46 static char *evas_engine_name = NULL;
47 static char *user_agent_string = NULL;
48 static char *extensions_path = NULL;
49 static char *background_color_string = NULL;
50 static Eina_Bool encoding_detector_enabled = EINA_FALSE;
51 static Eina_Bool frame_flattening_enabled = EINA_FALSE;
52 static Eina_Bool local_storage_enabled = EINA_TRUE;
53 static Eina_Bool offline_web_application_cache_enabled = EINA_TRUE;
54 static Eina_Bool fullscreen_enabled = EINA_FALSE;
55 static Eina_Bool spell_checking_enabled = EINA_FALSE;
56 static Eina_Bool web_security_enabled = EINA_TRUE;
57 static Eina_Bool touch_events_enabled = EINA_FALSE;
58 static Eina_Bool fixed_layout_enabled = EINA_TRUE;
59 static Eina_Bool separated_process_enabled = EINA_FALSE;
60 static Eina_Bool longpress_enabled = EINA_FALSE;
61 static int window_width = 1000;
62 static int window_height = 800;
63 static int search_flags = EWK_FIND_OPTIONS_SHOW_HIGHLIGHT | EWK_FIND_OPTIONS_WRAP_AROUND | EWK_FIND_OPTIONS_CASE_INSENSITIVE;
64 /* Default value of device_pixel_ratio is '0' so that we don't set custom device
65  * scale factor unless it's required by the User. */
66 static double device_pixel_ratio = 0;
67 static Eina_Bool legacy_behavior_enabled = EINA_FALSE;
68
69 #define DEFAULT_ZOOM_LEVEL 5 // Set default zoom level to 1.0 (index 5 on zoomLevels).
70 // The zoom values are chosen to be like in Mozilla Firefox 3.
71 const static float zoomLevels[] = {0.3, 0.5, 0.67, 0.8, 0.9, 1.0, 1.1, 1.2, 1.33, 1.5, 1.7, 2.0, 2.4, 3.0};
72 static int _log_domain_id = -1;
73
74 #define INFO(...) EINA_LOG_DOM_INFO(_log_domain_id, __VA_ARGS__)
75 #define ERROR(...) EINA_LOG_DOM_ERR(_log_domain_id, __VA_ARGS__)
76
77 static Eina_Bool
78 zoom_level_set(Evas_Object *webview, int level)
79 {
80    if (level < 0  || level >= sizeof(zoomLevels) / sizeof(float))
81      return EINA_FALSE;
82
83    return ewk_view_page_zoom_set(webview, zoomLevels[level]);
84 }
85
86 static Ewk_View_Smart_Class *miniBrowserViewSmartClass()
87 {
88    static Ewk_View_Smart_Class ewkViewClass = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION("MiniBrowser_View");
89    return &ewkViewClass;
90 }
91
92 typedef struct _Tooltip_Information {
93    Ecore_Timer *show_timer;
94    Eina_Bool activated;
95    Eina_Bool text_set;
96    Eina_Bool shown;
97 } Tooltip_Information;
98
99 typedef struct _Color_Selector {
100    Ewk_Color_Picker *ewk_picker;
101    Evas_Object *elm_selector;
102    Evas_Object *elm_selector_window;
103 } Color_Selector;
104
105 typedef struct _Browser_Window {
106    Evas_Object *elm_window;
107    Evas_Object *ewk_view;
108    Evas_Object *horizontal_layout;
109    Evas_Object *vertical_layout;
110    Evas_Object *url_bar;
111    Evas_Object *back_button;
112    Evas_Object *forward_button;
113    struct {
114      Evas_Object *elm_menu;
115      Ewk_Popup_Menu *ewk_menu;
116     } popup;
117    struct {
118      Evas_Object *search_bar;
119      Evas_Object *search_field;
120      Evas_Object *search_field_count;
121      Evas_Object *backward_button;
122      Evas_Object *forward_button;
123      Evas_Object *search_case_check_box;
124      Evas_Object *search_word_start_check_box;
125      Evas_Object *close_button;
126    } search;
127    struct {
128      Evas_Object *history_box;
129      Evas_Object *history_list;
130      Eina_List *history_list_items;
131    } history;
132    int current_zoom_level;
133    Tooltip_Information tooltip;
134    Color_Selector color_selector;
135    struct {
136      Evas_Object *elm_menu;
137      Ewk_Context_Menu *ewk_menu;
138    } context_menu;
139 } Browser_Window;
140
141 typedef struct _File_Selector_Data {
142    Browser_Window* parent;
143    Evas_Object *elm_window;
144    Ewk_File_Chooser_Request *request;
145 } File_Selector_Data;
146
147 typedef struct _Auth_Data {
148    Evas_Object *popup;
149    Ewk_Auth_Request *request;
150    Evas_Object *username_entry;
151    Evas_Object *password_entry;
152 } Auth_Data;
153
154 static const Ecore_Getopt options = {
155    "MiniBrowser",
156    "%prog [options] [url]",
157    "0.0.1",
158    "(C)2012 Samsung Electronics\n (C)2012 Intel Corporation\n",
159    "",
160    "Test Web Browser using the Enlightenment Foundation Libraries (EFL) port of WebKit2",
161    EINA_TRUE, {
162      ECORE_GETOPT_STORE_STR
163          ('e', "engine", "Ecore-evas engine to use."),
164      ECORE_GETOPT_STORE_STR
165          ('s', "window-size", "Window size in following format (width)x(height)."),
166      ECORE_GETOPT_STORE_STR
167          ('u', "user-agent", "User agent to set."),
168      ECORE_GETOPT_STORE_STR
169          ('x', "extensions-path", "The path which extensions are stored."),
170      ECORE_GETOPT_STORE_DOUBLE
171          ('r', "device-pixel-ratio", "Ratio between the CSS units and device pixels."),
172      ECORE_GETOPT_CALLBACK_NOARGS
173          ('E', "list-engines", "List ecore-evas engines.",
174           ecore_getopt_callback_ecore_evas_list_engines, NULL),
175      ECORE_GETOPT_STORE_DEF_BOOL
176          ('c', "encoding-detector", "Enable/disable encoding detector.", EINA_FALSE),
177      ECORE_GETOPT_STORE_STR
178          ('C', "background-color", "Background color of page. ex) -C=255:255:255:255"),
179      ECORE_GETOPT_STORE_DEF_BOOL
180          ('f', "flattening", "Enable/disable frame flattening.", EINA_FALSE),
181      ECORE_GETOPT_STORE_DEF_BOOL
182          ('l', "local-storage", "Enable/disable HTML5 local storage.", EINA_TRUE),
183      ECORE_GETOPT_STORE_DEF_BOOL
184          ('o', "offline-web-application-cache", "Enable/disable offline web application cache.", EINA_TRUE),
185      ECORE_GETOPT_STORE_DEF_BOOL
186          ('F', "full-screen", "Start in full-screen.", EINA_FALSE),
187      ECORE_GETOPT_STORE_DEF_BOOL
188          ('t', "text-checking", "Enable/disable text spell checking.", EINA_FALSE),
189      ECORE_GETOPT_STORE_DEF_BOOL
190          ('T', "touch-events", "Enable/disable touch events.", EINA_FALSE),
191      ECORE_GETOPT_STORE_DEF_BOOL
192          ('L', "fixed-layout", "Enable/disable fixed layout.", EINA_TRUE),
193      ECORE_GETOPT_STORE_DEF_STR
194          ('p', "policy-cookies", "Cookies policy:\n  always - always accept,\n  never - never accept,\n  no-third-party - don't accept third-party cookies.", "no-third-party"),
195      ECORE_GETOPT_STORE_DEF_BOOL
196          ('w', "web-security", "enable/disable web security.", EINA_TRUE),
197      ECORE_GETOPT_STORE_DEF_BOOL
198          ('S', "separate-process", "Create new window in separated web process.", EINA_FALSE),
199      ECORE_GETOPT_VERSION
200          ('V', "version"),
201      ECORE_GETOPT_COPYRIGHT
202          ('R', "copyright"),
203      ECORE_GETOPT_HELP
204          ('h', "help"),
205      ECORE_GETOPT_SENTINEL
206    }
207 };
208
209 static Eina_Stringshare *_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    int x, y, width, height;
1020    evas_object_geometry_get(window->elm_window, &x, &y, &width, &height);
1021
1022    elm_win_center(window->color_selector.elm_selector_window, EINA_TRUE, EINA_TRUE);
1023    evas_object_resize(window->color_selector.elm_selector_window, 350, 500);
1024    evas_object_show(window->color_selector.elm_selector_window);
1025
1026    return EINA_TRUE;
1027 }
1028
1029 static int
1030 quit(Eina_Bool success, const char *msg)
1031 {
1032    if (msg)
1033      success ? INFO("%s", msg) : ERROR("%s", msg);
1034
1035    eina_log_domain_unregister(_log_domain_id);
1036    ewk_object_unref(configuration());
1037    ewk_shutdown();
1038    elm_shutdown();
1039
1040    if (!success)
1041      return EXIT_FAILURE;
1042
1043    return EXIT_SUCCESS;
1044 }
1045
1046 static Eina_Bool
1047 has_scheme(const char *url)
1048 {
1049    return !!strstr(url, "://");
1050 }
1051
1052 static char *
1053 url_from_user_input(const char *arg)
1054 {
1055    /* If it is already a URL, return the argument as is. */
1056    if (has_scheme(arg) || eina_str_has_prefix(arg, JAVASCRIPT_SCHEME) || !strcasecmp(arg, "about:blank"))
1057      return strdup(arg);
1058
1059    Eina_Strbuf *buf = eina_strbuf_manage_new(eina_file_path_sanitize(arg));
1060
1061    /* Check if the path exists. */
1062    if (ecore_file_exists(eina_strbuf_string_get(buf))) {
1063      /* File exists, convert local path to a URL. */
1064      eina_strbuf_prepend(buf, FILE_SCHEME);
1065    } else {
1066      /* The path does not exist, convert it to a URL by
1067         prepending http:// scheme:
1068         www.google.com -> http://www.google.com */
1069      eina_strbuf_string_free(buf);
1070      eina_strbuf_append_printf(buf, "%s%s", HTTP_SCHEME, arg);
1071    }
1072    char *url = eina_strbuf_string_steal(buf);
1073    eina_strbuf_free(buf);
1074
1075    return url;
1076 }
1077
1078 static Eina_Bool
1079 url_load_from_user_input(Evas_Object *ewk_view, const char *url)
1080 {
1081    if (!ewk_view || !url)
1082      return EINA_FALSE;
1083
1084    if (eina_str_has_prefix(url, JAVASCRIPT_SCHEME))
1085      return ewk_view_script_execute(ewk_view, strstr(url, JAVASCRIPT_SCHEME), 0, 0);
1086
1087    return ewk_view_url_set(ewk_view, url);
1088 }
1089
1090 static void
1091 _url_bar_activated_cb(void *user_data, Evas_Object *url_bar, void *event_info)
1092 {
1093    Browser_Window *window = (Browser_Window *)user_data;
1094
1095    const char *markup_url = elm_entry_entry_get(url_bar);
1096    char *user_url = elm_entry_markup_to_utf8(markup_url);
1097    char *url = url_from_user_input(user_url);
1098    url_load_from_user_input(window->ewk_view, url);
1099
1100    free(user_url);
1101    free(url);
1102
1103    /* Give focus back to the view */
1104    view_focus_set(window, EINA_TRUE);
1105 }
1106
1107 static void
1108 _url_bar_clicked_cb(void *user_data, Evas_Object *url_bar, void *event_info)
1109 {
1110    Browser_Window *window = (Browser_Window *)user_data;
1111
1112    /* Grab focus from the view */
1113    evas_object_focus_set(window->ewk_view, EINA_FALSE);
1114    elm_object_focus_set(url_bar, EINA_TRUE);
1115 }
1116
1117 static void
1118 _search_field_aborted_cb(void *user_data, Evas_Object *search_field, void *event_info)
1119 {
1120    Browser_Window *window = (Browser_Window *)user_data;
1121    search_box_hide(window);
1122
1123    /* Give focus back to the view */
1124    view_focus_set(window, EINA_TRUE);
1125 }
1126
1127 static void
1128 _search_field_activated_cb(void *user_data, Evas_Object *search_field, void *event_info)
1129 {
1130    Browser_Window *window = (Browser_Window *)user_data;
1131
1132    const char *markup_text = elm_entry_entry_get(search_field);
1133    char *text = elm_entry_markup_to_utf8(markup_text);
1134    ewk_view_text_find(window->ewk_view, text, search_flags, MAX_SEARCH_COUNT);
1135    free(text);
1136
1137    /* Grab focus from the view */
1138    evas_object_focus_set(window->ewk_view, EINA_FALSE);
1139    elm_object_focus_set(search_field, EINA_TRUE);
1140 }
1141
1142 static void
1143 _search_field_clicked_cb(void *user_data, Evas_Object *search_field, void *event_info)
1144 {
1145    Browser_Window *window = (Browser_Window *)user_data;
1146
1147    /* Grab focus from the view */
1148    evas_object_focus_set(window->ewk_view, EINA_FALSE);
1149    elm_object_focus_set(search_field, EINA_TRUE);
1150 }
1151
1152 static void
1153 _back_button_clicked_cb(void *user_data, Evas_Object *back_button, void *event_info)
1154 {
1155    if (longpress_enabled)
1156      return;
1157
1158    Browser_Window *window = (Browser_Window *)user_data;
1159
1160    ewk_view_back(window->ewk_view);
1161    /* Update back button state */
1162    elm_object_disabled_set(back_button, !ewk_view_back_possible(window->ewk_view));
1163 }
1164
1165 static void
1166 _forward_button_clicked_cb(void *user_data, Evas_Object *forward_button, void *event_info)
1167 {
1168    if (longpress_enabled)
1169      return;
1170
1171    Browser_Window *window = (Browser_Window *)user_data;
1172
1173    ewk_view_forward(window->ewk_view);
1174    /* Update forward button state */
1175    elm_object_disabled_set(forward_button, !ewk_view_forward_possible(window->ewk_view));
1176 }
1177
1178 static void
1179 _search_backward_button_clicked_cb(void *user_data, Evas_Object *search_backward_button, void *event_info)
1180 {
1181    Browser_Window *window = (Browser_Window *)user_data;
1182
1183    char *text = elm_entry_markup_to_utf8(elm_entry_entry_get(window->search.search_field));
1184    ewk_view_text_find(window->ewk_view, text, search_flags | EWK_FIND_OPTIONS_BACKWARDS, MAX_SEARCH_COUNT);
1185    free(text);
1186 }
1187
1188 static void
1189 _search_forward_button_clicked_cb(void *user_data, Evas_Object *search_forward_button, void *event_info)
1190 {
1191    Browser_Window *window = (Browser_Window *)user_data;
1192
1193    char *text = elm_entry_markup_to_utf8(elm_entry_entry_get(window->search.search_field));
1194    ewk_view_text_find(window->ewk_view, text, search_flags, MAX_SEARCH_COUNT);
1195    free(text);
1196 }
1197
1198 static void
1199 _search_case_option_changed(void *user_data, Evas_Object *search_case_check_box, void *event_info)
1200 {
1201    Browser_Window *window = (Browser_Window *)user_data;
1202    char *text = elm_entry_markup_to_utf8(elm_entry_entry_get(window->search.search_field));
1203
1204    /* Bit toggle the case sensitive flag */
1205    search_flags = search_flags ^ EWK_FIND_OPTIONS_CASE_INSENSITIVE;
1206
1207    ewk_view_text_find(window->ewk_view, text, search_flags, MAX_SEARCH_COUNT);
1208    free(text);
1209 }
1210
1211 static void
1212 _search_word_start_option_changed_cb(void *user_data, Evas_Object *search_word_start_check_box, void *event_info)
1213 {
1214    Browser_Window *window = (Browser_Window *)user_data;
1215    char *text = elm_entry_markup_to_utf8(elm_entry_entry_get(window->search.search_field));
1216
1217    /* Bit toggle the word start flag */
1218    search_flags = search_flags ^ EWK_FIND_OPTIONS_AT_WORD_STARTS;
1219
1220    ewk_view_text_find(window->ewk_view, text, search_flags, MAX_SEARCH_COUNT);
1221    free(text);
1222 }
1223
1224 static void
1225 _search_close_button_clicked_cb(void *user_data, Evas_Object *search_close_button, void *event_info)
1226 {
1227    Browser_Window *window = (Browser_Window *)user_data;
1228
1229    search_box_hide(window);
1230 }
1231
1232 static void
1233 _refresh_button_clicked_cb(void *user_data, Evas_Object *refresh_button, void *event_info)
1234 {
1235    Browser_Window *window = (Browser_Window *)user_data;
1236
1237    Evas *evas = evas_object_evas_get(refresh_button);
1238    Eina_Bool ctrlPressed = evas_key_modifier_is_set(evas_key_modifier_get(evas), "Control");
1239    if (ctrlPressed) {
1240      INFO("Reloading and bypassing cache...");
1241      ewk_view_reload_bypass_cache(window->ewk_view);
1242    } else {
1243      INFO("Reloading...");
1244      ewk_view_reload(window->ewk_view);
1245    }
1246 }
1247
1248 static void
1249 _stop_button_clicked_cb(void *user_data, Evas_Object *stop_button, void *event_info)
1250 {
1251    Browser_Window *window = (Browser_Window *)user_data;
1252
1253    INFO("Stop was Pressed. Aborting load...");
1254    ewk_view_stop(window->ewk_view);
1255 }
1256
1257 static char *
1258 list_item_label_get(void *data, Evas_Object *obj, const char *part)
1259 {
1260    int len = strlen((char *)data);
1261    char *buf = (char *)malloc(sizeof(char) * (len + 1));
1262    snprintf(buf, len + 1, "%s", (char *)data);
1263    return buf;
1264 }
1265
1266 static void
1267 _list_item_select_cb(void *user_data, Evas_Object *obj, void *event_info)
1268 {
1269    Browser_Window *window = evas_object_data_get(obj, "Browser_Window");
1270    ewk_view_navigate_to(window->ewk_view, user_data);
1271    history_list_hide(window);
1272    evas_object_data_del(obj, "Browser_Window");
1273 }
1274
1275 static void
1276 navigation_button_longpress_process(void *user_data, Eina_Bool forward_navigation_enabled)
1277 {
1278    if (longpress_enabled)
1279      return;
1280
1281    longpress_enabled = EINA_TRUE;
1282    Browser_Window *window = (Browser_Window *)user_data;
1283
1284    Ewk_Back_Forward_List *list = ewk_view_back_forward_list_get(window->ewk_view);
1285    const Eina_List *l;
1286    void *data;
1287    static Elm_Genlist_Item_Class *list_item = NULL;
1288    const char *title = NULL;
1289    int item_count;
1290    int x;
1291    int y;
1292    int width;
1293    int height;
1294    size_t index;
1295
1296    evas_object_data_set(window->history.history_list, "Browser_Window", window);
1297
1298    if (forward_navigation_enabled)
1299      window->history.history_list_items = ewk_back_forward_list_forward_items_copy(list);
1300    else
1301      window->history.history_list_items = ewk_back_forward_list_back_items_copy(list);
1302
1303    if (!list_item) {
1304      list_item = elm_genlist_item_class_new();
1305      list_item->item_style = "default";
1306      list_item->func.text_get = list_item_label_get;
1307      list_item->func.content_get = NULL;
1308      list_item->func.state_get = NULL;
1309      list_item->func.del = NULL;
1310    }
1311
1312    item_count = eina_list_count(window->history.history_list_items);
1313    INFO("navigation_button_longpress_process : Item count = %d forward_navigation_enabled = %d", item_count, forward_navigation_enabled);
1314
1315    EINA_LIST_FOREACH(window->history.history_list_items, l, data) {
1316      title = ewk_back_forward_list_item_title_get(data);
1317      INFO(" title = %s", title);
1318      elm_genlist_item_append(window->history.history_list, list_item, (void *)(title), NULL, ELM_GENLIST_ITEM_NONE, _list_item_select_cb, data);
1319    }
1320
1321    if (item_count > 0) {
1322      evas_object_geometry_get(window->elm_window, &x, &y, &width, &height);
1323      elm_list_go(window->history.history_list);
1324      evas_object_resize(window->history.history_box , width / 3 , LIST_ITEM_HEIGHT * item_count);
1325
1326      if (forward_navigation_enabled) {
1327        evas_object_move(window->history.history_box , x + TOOL_BAR_BUTTON_SIZE + 1, y + TOOL_BAR_BUTTON_SIZE);
1328        evas_object_move(window->history.history_list , x + TOOL_BAR_BUTTON_SIZE + 1, y + TOOL_BAR_BUTTON_SIZE);
1329      } else {
1330        evas_object_move(window->history.history_box , x, y + TOOL_BAR_BUTTON_SIZE);
1331        evas_object_move(window->history.history_list , x, y + TOOL_BAR_BUTTON_SIZE);
1332      }
1333
1334      elm_genlist_mode_set(window->history.history_list, ELM_LIST_COMPRESS);
1335      evas_object_show(window->history.history_box);
1336      evas_object_show(window->history.history_list);
1337      evas_object_focus_set(window->ewk_view, EINA_FALSE);
1338      elm_object_focus_set(window->history.history_list, EINA_TRUE);
1339    } else
1340      longpress_enabled = EINA_FALSE;
1341 }
1342
1343 static void
1344 _forward_button_longpress_cb(void *user_data, Evas_Object *forward_button, void *event_info)
1345 {
1346    Browser_Window *window = (Browser_Window *)user_data;
1347
1348    navigation_button_longpress_process(user_data, EINA_TRUE);
1349    elm_object_disabled_set(forward_button, !ewk_view_back_possible(window->ewk_view));
1350 }
1351
1352 static void
1353 _back_button_longpress_cb(void *user_data, Evas_Object *back_button, void *event_info)
1354 {
1355    Browser_Window *window = (Browser_Window *)user_data;
1356
1357    navigation_button_longpress_process(user_data, EINA_FALSE);
1358    elm_object_disabled_set(back_button, !ewk_view_back_possible(window->ewk_view));
1359 }
1360
1361 static void
1362 _ok_clicked_cb(void *user_data, Evas_Object *obj, void *event_info)
1363 {
1364    Eina_Bool *confirmed = (Eina_Bool *)user_data;
1365    *confirmed = EINA_TRUE;
1366 }
1367
1368 static Eina_Stringshare *
1369 _file_entry_dialog_show(Browser_Window *window, const char *label_tag, const char *default_text)
1370 {
1371    Evas_Object *file_popup = elm_popup_add(window->elm_window);
1372    evas_object_size_hint_weight_set(file_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1373    evas_object_show(file_popup);
1374
1375    Evas_Object *vbox = elm_box_add(file_popup);
1376    evas_object_size_hint_weight_set(vbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1377    evas_object_size_hint_align_set(vbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
1378    elm_object_content_set(file_popup, vbox);
1379    evas_object_show(vbox);
1380
1381    Evas_Object *label = elm_label_add(window->elm_window);
1382    elm_object_text_set(label, label_tag);
1383    evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, 0.0);
1384    evas_object_size_hint_align_set(label, EVAS_HINT_FILL, 0.5);
1385    evas_object_color_set(label, 23, 45, 67, 142);
1386    elm_box_pack_end(vbox, label);
1387    evas_object_show(label);
1388
1389    Evas_Object *fs_entry = elm_fileselector_entry_add(file_popup);
1390    elm_fileselector_is_save_set(fs_entry, EINA_TRUE);
1391    evas_object_size_hint_align_set(fs_entry, EVAS_HINT_FILL, 0);
1392    elm_fileselector_path_set(fs_entry, default_text);
1393    elm_object_text_set(fs_entry, "FileChooser");
1394    elm_box_pack_end(vbox, fs_entry);
1395    evas_object_show(fs_entry);
1396
1397    Evas_Object *hbox = elm_box_add(file_popup);
1398    evas_object_size_hint_weight_set(hbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1399    elm_box_horizontal_set(hbox, EINA_TRUE);
1400    evas_object_size_hint_align_set(hbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
1401    elm_box_pack_end(vbox, hbox);
1402    evas_object_show(hbox);
1403
1404    Eina_Bool ok = EINA_FALSE;
1405    Evas_Object *ok_button = elm_button_add(file_popup);
1406    elm_object_text_set(ok_button, "OK");
1407    evas_object_smart_callback_add(ok_button, "clicked", _ok_clicked_cb, &ok);
1408    elm_box_pack_end(hbox, ok_button);
1409    evas_object_show(ok_button);
1410
1411    Eina_Bool cancel = EINA_FALSE;
1412    Evas_Object *cancel_button = elm_button_add(file_popup);
1413    elm_object_text_set(cancel_button, "Cancel");
1414    evas_object_smart_callback_add(cancel_button, "clicked", _ok_clicked_cb, &cancel);
1415    elm_box_pack_end(hbox, cancel_button);
1416    evas_object_show(cancel_button);
1417
1418    while (ok != EINA_TRUE && cancel != EINA_TRUE)
1419     ecore_main_loop_iterate();
1420
1421    Eina_Stringshare *file_path = ok ? eina_stringshare_add(elm_fileselector_path_get(fs_entry)) : NULL;
1422    evas_object_del(file_popup);
1423    return file_path;
1424 }
1425
1426 static void
1427 _javascript_alert_cb(Ewk_View_Smart_Data *smartData, const char *message)
1428 {
1429    Browser_Window *window = window_find_with_ewk_view(smartData->self);
1430
1431    Evas_Object *alert_popup = elm_popup_add(window->elm_window);
1432    evas_object_size_hint_weight_set(alert_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1433    elm_object_text_set(alert_popup, message);
1434    elm_object_part_text_set(alert_popup, "title,text", "Alert");
1435
1436    /* Popup buttons */
1437    Eina_Bool ok = EINA_FALSE;
1438    Evas_Object *button = elm_button_add(alert_popup);
1439    elm_object_text_set(button, "OK");
1440    elm_object_part_content_set(alert_popup, "button1", button);
1441    evas_object_smart_callback_add(button, "clicked", _ok_clicked_cb, &ok);
1442    elm_object_focus_set(button, EINA_TRUE);
1443    evas_object_show(alert_popup);
1444
1445    while (ok != EINA_TRUE)
1446       ecore_main_loop_iterate();
1447
1448    evas_object_del(alert_popup);
1449 }
1450
1451 static Eina_Bool
1452 _javascript_confirm_cb(Ewk_View_Smart_Data *smartData, const char *message)
1453 {
1454    Browser_Window *window = window_find_with_ewk_view(smartData->self);
1455
1456    Evas_Object *confirm_popup = elm_popup_add(window->elm_window);
1457    evas_object_size_hint_weight_set(confirm_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1458    elm_object_text_set(confirm_popup, message);
1459    elm_object_part_text_set(confirm_popup, "title,text", "Confirmation");
1460
1461    /* Popup buttons */
1462    Eina_Bool cancel = EINA_FALSE;
1463    Evas_Object *cancel_button = elm_button_add(confirm_popup);
1464    elm_object_text_set(cancel_button, "Cancel");
1465    elm_object_part_content_set(confirm_popup, "button1", cancel_button);
1466    evas_object_smart_callback_add(cancel_button, "clicked", _ok_clicked_cb, &cancel);
1467    Evas_Object *ok_button = elm_button_add(confirm_popup);
1468    Eina_Bool ok = EINA_FALSE;
1469    elm_object_text_set(ok_button, "OK");
1470    elm_object_part_content_set(confirm_popup, "button2", ok_button);
1471    evas_object_smart_callback_add(ok_button, "clicked", _ok_clicked_cb, &ok);
1472    elm_object_focus_set(ok_button, EINA_TRUE);
1473    evas_object_show(confirm_popup);
1474
1475    while (cancel != EINA_TRUE && ok != EINA_TRUE)
1476       ecore_main_loop_iterate();
1477
1478    evas_object_del(confirm_popup);
1479
1480    return ok;
1481 }
1482
1483 static const char *
1484 _javascript_prompt_cb(Ewk_View_Smart_Data *smartData, const char *message, const char *default_value)
1485 {
1486    Browser_Window *window = window_find_with_ewk_view(smartData->self);
1487
1488    Evas_Object *prompt_popup = elm_popup_add(window->elm_window);
1489    evas_object_size_hint_weight_set(prompt_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1490    elm_object_part_text_set(prompt_popup, "title,text", "Prompt");
1491
1492    /* Popup Content */
1493    Evas_Object *box = elm_box_add(window->elm_window);
1494    elm_box_padding_set(box, 0, 4);
1495    evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1496    evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL);
1497    evas_object_show(box);
1498
1499    Evas_Object *prompt = elm_label_add(window->elm_window);
1500    elm_object_text_set(prompt, message);
1501    evas_object_size_hint_weight_set(prompt, EVAS_HINT_EXPAND, 0.0);
1502    evas_object_size_hint_align_set(prompt, EVAS_HINT_FILL, 0.5);
1503    elm_box_pack_end(box, prompt);
1504    evas_object_show(prompt);
1505
1506    Evas_Object *entry = elm_entry_add(window->elm_window);
1507    elm_entry_scrollable_set(entry, EINA_TRUE);
1508    elm_entry_single_line_set(entry, EINA_TRUE);
1509    elm_entry_text_style_user_push(entry, "DEFAULT='font_size=18'");
1510    elm_entry_entry_set(entry, default_value ? default_value : "");
1511    elm_entry_select_all(entry);
1512    evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, 0.0);
1513    evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, 0.5);
1514    elm_box_pack_end(box, entry);
1515    elm_object_focus_set(entry, EINA_TRUE);
1516    evas_object_show(entry);
1517
1518    elm_object_content_set(prompt_popup, box);
1519
1520    /* Popup buttons */
1521    Eina_Bool cancel = EINA_FALSE;
1522    Evas_Object *cancel_button = elm_button_add(prompt_popup);
1523    elm_object_text_set(cancel_button, "Cancel");
1524    elm_object_part_content_set(prompt_popup, "button1", cancel_button);
1525    evas_object_smart_callback_add(cancel_button, "clicked", _ok_clicked_cb, &cancel);
1526    Eina_Bool ok = EINA_FALSE;
1527    Evas_Object *ok_button = elm_button_add(prompt_popup);
1528    elm_object_text_set(ok_button, "OK");
1529    elm_object_part_content_set(prompt_popup, "button2", ok_button);
1530    evas_object_smart_callback_add(ok_button, "clicked", _ok_clicked_cb, &ok);
1531    evas_object_show(prompt_popup);
1532
1533    while (cancel != EINA_TRUE && ok != EINA_TRUE)
1534       ecore_main_loop_iterate();
1535
1536    /* The return string need to be stringshared */
1537    const char *prompt_text = ok ? eina_stringshare_add(elm_entry_entry_get(entry)) : NULL;
1538    evas_object_del(prompt_popup);
1539
1540    return prompt_text;
1541 }
1542
1543 static Eina_Bool
1544 _javascript_before_unload_confirm_cb(Ewk_View_Smart_Data *smartData, const char *message)
1545 {
1546    return _javascript_confirm_cb(smartData, "Will you leave this page?");
1547 }
1548
1549 static void
1550 _popup_menu_item_clicked_cb(void *user_data, Evas_Object *obj, void *event_info)
1551 {
1552    Browser_Window *window = (Browser_Window *)user_data;
1553    Elm_Object_Item *item = (Elm_Object_Item *)event_info;
1554
1555    INFO("Selected popup menu index: %u", elm_menu_item_index_get(item));
1556    ewk_popup_menu_selected_index_set(window->popup.ewk_menu, elm_menu_item_index_get(item));
1557
1558    // Close popup menu.
1559    ewk_popup_menu_close(window->popup.ewk_menu);
1560 }
1561
1562 static void
1563 popup_menu_populate(Evas_Object *elm_menu, Ewk_Popup_Menu *ewk_menu, void *user_data)
1564 {
1565    const Eina_List* ewk_items = ewk_popup_menu_items_get(ewk_menu);
1566
1567    void *data;
1568    const Eina_List *l;
1569    EINA_LIST_FOREACH(ewk_items, l, data) {
1570      Ewk_Popup_Menu_Item *ewk_item = (Ewk_Popup_Menu_Item *)data;
1571      switch (ewk_popup_menu_item_type_get(ewk_item)) {
1572      case EWK_POPUP_MENU_SEPARATOR:
1573        elm_menu_item_separator_add(elm_menu, NULL);
1574        break;
1575      case EWK_POPUP_MENU_ITEM:
1576        if (ewk_popup_menu_item_is_label_get(ewk_item)) {
1577          Elm_Object_Item *item = elm_menu_item_add(elm_menu, NULL, NULL, ewk_popup_menu_item_text_get(ewk_item), NULL, NULL);
1578          elm_object_item_disabled_set(item, EINA_TRUE);
1579        } else {
1580          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);
1581          const char *tooltip_text = ewk_popup_menu_item_tooltip_get(ewk_item);
1582          if (tooltip_text && tooltip_text[0] != '\0')
1583            elm_object_item_tooltip_text_set(item, tooltip_text);
1584          elm_object_item_disabled_set(item, !ewk_popup_menu_item_enabled_get(ewk_item));
1585          elm_menu_item_selected_set(item, ewk_popup_menu_item_selected_get(ewk_item));
1586        }
1587        break;
1588      default:
1589        INFO("Unrecognized popup menu item type!");
1590        break;
1591      }
1592    }
1593 }
1594
1595 static Eina_Bool
1596 _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)
1597 {
1598    Browser_Window *window = window_find_with_ewk_view(smartData->self);
1599
1600    if (window->popup.elm_menu)
1601      evas_object_del(window->popup.elm_menu);
1602
1603    window->popup.elm_menu = elm_menu_add(window->elm_window);
1604    window->popup.ewk_menu = ewk_menu;
1605
1606    popup_menu_populate(window->popup.elm_menu, ewk_menu, window);
1607
1608    INFO("Showing popup menu at (%d, %d)", rect.x, rect.y);
1609    elm_menu_move(window->popup.elm_menu, rect.x, rect.y);
1610    evas_object_show(window->popup.elm_menu);
1611
1612    return EINA_TRUE;
1613 }
1614
1615 static Eina_Bool
1616 _popup_menu_hide(Ewk_View_Smart_Data *smartData)
1617 {
1618    Browser_Window *window = window_find_with_ewk_view(smartData->self);
1619
1620    if (!window->popup.elm_menu)
1621      return EINA_FALSE;
1622
1623    elm_menu_close(window->popup.elm_menu);
1624    window->popup.ewk_menu = NULL;
1625
1626    return EINA_TRUE;
1627 }
1628
1629 static Eina_Bool
1630 _window_geometry_get(Ewk_View_Smart_Data *sd, Evas_Coord *x, Evas_Coord *y, Evas_Coord *width, Evas_Coord *height)
1631 {
1632    Browser_Window *window = window_find_with_ewk_view(sd->self);
1633
1634    evas_object_geometry_get(window->elm_window, x, y, width, height);
1635
1636    return EINA_TRUE;
1637 }
1638
1639 static Eina_Bool
1640 _window_geometry_set(Ewk_View_Smart_Data *sd, Evas_Coord x, Evas_Coord y, Evas_Coord width, Evas_Coord height)
1641 {
1642    Browser_Window *window = window_find_with_ewk_view(sd->self);
1643
1644    evas_object_move(window->elm_window, x, y);
1645    evas_object_resize(window->elm_window, width, height);
1646
1647    return EINA_TRUE;
1648 }
1649
1650 typedef struct {
1651    Evas_Object *ewk_view;
1652    Evas_Object *permission_popup;
1653 } PermissionData;
1654
1655 static void
1656 _fullscreen_accept_cb(void *user_data, Evas_Object *obj, void *event_info)
1657 {
1658    PermissionData *permission_data = (PermissionData *)user_data;
1659    Browser_Window *window = window_find_with_ewk_view(permission_data->ewk_view);
1660
1661    elm_win_resize_object_del(window->elm_window, permission_data->permission_popup);
1662    evas_object_del(permission_data->permission_popup);
1663    evas_object_focus_set(permission_data->ewk_view, EINA_TRUE);
1664    free(permission_data);
1665 }
1666
1667 static void
1668 _fullscreen_deny_cb(void *user_data, Evas_Object *obj, void *event_info)
1669 {
1670    PermissionData *permission_data = (PermissionData *)user_data;
1671    Browser_Window *window = window_find_with_ewk_view(permission_data->ewk_view);
1672
1673    ewk_view_fullscreen_exit(permission_data->ewk_view);
1674    elm_win_resize_object_del(window->elm_window, permission_data->permission_popup);
1675    evas_object_del(permission_data->permission_popup);
1676    evas_object_focus_set(permission_data->ewk_view, EINA_TRUE);
1677    free(permission_data);
1678 }
1679
1680 static Eina_Bool
1681 _fullscreen_enter_cb(Ewk_View_Smart_Data *sd, Ewk_Security_Origin *origin)
1682 {
1683    Browser_Window *window = window_find_with_ewk_view(sd->self);
1684
1685    /* Go fullscreen */
1686    toggle_window_fullscreen(window, EINA_TRUE);
1687
1688    /* Show user popup */
1689    Evas_Object *permission_popup = elm_popup_add(window->elm_window);
1690    evas_object_size_hint_weight_set(permission_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1691
1692    Eina_Strbuf *message = eina_strbuf_new();
1693    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));
1694    elm_object_text_set(permission_popup, eina_strbuf_string_get(message));
1695    eina_strbuf_free(message);
1696    elm_object_part_text_set(permission_popup, "title,text", "Fullscreen Permission");
1697
1698    /* Popup buttons */
1699    PermissionData *permission_data = (PermissionData *)malloc(sizeof(PermissionData));
1700    permission_data->ewk_view = window->ewk_view;
1701    permission_data->permission_popup = permission_popup;
1702    Evas_Object *accept_button = elm_button_add(permission_popup);
1703    elm_object_text_set(accept_button, "Accept");
1704    elm_object_part_content_set(permission_popup, "button1", accept_button);
1705    evas_object_smart_callback_add(accept_button, "clicked", _fullscreen_accept_cb, permission_data);
1706
1707    Evas_Object *deny_button = elm_button_add(permission_popup);
1708    elm_object_text_set(deny_button, "Deny");
1709    elm_object_part_content_set(permission_popup, "button2", deny_button);
1710    evas_object_smart_callback_add(deny_button, "clicked", _fullscreen_deny_cb, permission_data);
1711    elm_win_resize_object_add(window->elm_window, permission_popup);
1712    evas_object_show(permission_popup);
1713
1714    return EINA_TRUE;
1715 }
1716
1717 static Eina_Bool _fullscreen_exit_cb(Ewk_View_Smart_Data *sd)
1718 {
1719    Browser_Window *window = window_find_with_ewk_view(sd->self);
1720
1721    toggle_window_fullscreen(window, EINA_FALSE);
1722
1723    return EINA_TRUE;
1724 }
1725
1726 static Evas_Object *
1727 _window_create_cb(Ewk_View_Smart_Data *smartData, Ewk_View_Configuration* configuration, const Ewk_Window_Features *window_features)
1728 {
1729    int x = 0;
1730    int y = 0;
1731    int width = 0;
1732    int height = 0;
1733
1734    ewk_window_features_geometry_get(window_features, &x, &y, &width, &height);
1735
1736    if (!width)
1737      width = window_width;
1738
1739    if (!height)
1740      height = window_height;
1741
1742    Browser_Window *window = window_create(configuration, width, height);
1743    Evas_Object *new_view = window->ewk_view;
1744
1745    windows = eina_list_append(windows, window);
1746
1747    INFO("minibrowser: location(%d,%d) size=(%d,%d)", x, y, width, height);
1748
1749    return new_view;
1750 }
1751
1752 static void
1753 _window_close_cb(Ewk_View_Smart_Data *smartData)
1754 {
1755    Browser_Window *window = window_find_with_ewk_view(smartData->self);
1756    window_close(window);
1757 }
1758
1759 static void
1760 _context_menu_item_selected_cb(void *data, Evas_Object *obj, void *event_info)
1761 {
1762    if (!data) {
1763      ERROR("Context menu callback data is NULL.");
1764      return;
1765    }
1766
1767    Ewk_Context_Menu_Item *ewk_item = (Ewk_Context_Menu_Item *)data;
1768    INFO("Selected context menu item: %s.", ewk_context_menu_item_title_get(ewk_item));
1769    ewk_context_menu_item_select(ewk_context_menu_item_parent_menu_get(ewk_item), ewk_item);
1770    ewk_context_menu_hide(ewk_context_menu_item_parent_menu_get(ewk_item));
1771 }
1772
1773 static void
1774 context_menu_populate(Evas_Object* context_menu, Ewk_Context_Menu *ewk_menu, Elm_Object_Item *parent_item)
1775 {
1776    if (!context_menu || !ewk_menu) {
1777      ERROR("Necessary objects are NULL.");
1778      return;
1779    }
1780
1781    const Eina_List *list = ewk_context_menu_items_get(ewk_menu);
1782    const Eina_List *l;
1783    void *data;
1784
1785    Ewk_Context_Menu_Item *ewk_item;
1786    Elm_Object_Item *elm_menu_item;
1787    Evas_Object *elm_check_item;
1788
1789    EINA_LIST_FOREACH(list, l, data) {
1790      ewk_item = (Ewk_Context_Menu_Item *)data;
1791      switch (ewk_context_menu_item_type_get(ewk_item)) {
1792      case EWK_ACTION_TYPE:
1793        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);
1794        break;
1795      case EWK_CHECKABLE_ACTION_TYPE:
1796        elm_check_item = elm_check_add(context_menu);
1797        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);
1798        elm_object_item_content_set(elm_menu_item, elm_check_item);
1799        elm_check_state_set(elm_check_item, ewk_context_menu_item_checked_get(ewk_item));
1800        break;
1801      case EWK_SUBMENU_TYPE:
1802        elm_menu_item = elm_menu_item_add(context_menu, parent_item, NULL, ewk_context_menu_item_title_get(ewk_item), NULL, ewk_item);
1803        if (elm_menu_item)
1804          context_menu_populate(context_menu, ewk_context_menu_item_submenu_get(ewk_item), elm_menu_item);
1805        break;
1806      default:
1807        continue;
1808      }
1809      elm_object_item_disabled_set(elm_menu_item, !ewk_context_menu_item_enabled_get(ewk_item));
1810    }
1811 }
1812
1813 static Eina_Bool
1814 _context_menu_show(Ewk_View_Smart_Data *sd, Evas_Coord x, Evas_Coord y, Ewk_Context_Menu *menu)
1815 {
1816    Browser_Window *window = window_find_with_ewk_view(sd->self);
1817
1818    if (!window || !menu) {
1819      ERROR("Necessary objects are NULL.");
1820      return EINA_FALSE;
1821    }
1822
1823    window->context_menu.elm_menu = elm_menu_add(window->elm_window);
1824
1825    if (!window->context_menu.elm_menu) {
1826      ERROR("Could not create menu widget.");
1827      return EINA_FALSE;
1828    }
1829
1830    window->context_menu.ewk_menu = menu;
1831
1832    context_menu_populate(window->context_menu.elm_menu, menu, NULL);
1833
1834    INFO("Showing context menu at (%d, %d).", x, y);
1835    elm_menu_move(window->context_menu.elm_menu, x, y);
1836    evas_object_show(window->context_menu.elm_menu);
1837
1838    return EINA_TRUE;
1839 }
1840
1841 static Eina_Bool
1842 _context_menu_hide(Ewk_View_Smart_Data *sd)
1843 {
1844    Browser_Window *window = window_find_with_ewk_view(sd->self);
1845
1846    if (!window || !window->context_menu.elm_menu) {
1847      ERROR("Necessary objects are NULL.");
1848      return EINA_FALSE;
1849    }
1850
1851    elm_menu_close(window->context_menu.elm_menu);
1852    evas_object_del(window->context_menu.elm_menu);
1853    window->context_menu.elm_menu = NULL;
1854    window->context_menu.ewk_menu = NULL;
1855
1856    return EINA_TRUE;
1857 }
1858
1859 static void
1860 auth_popup_close(Auth_Data *auth_data)
1861 {
1862    ewk_object_unref(auth_data->request);
1863    evas_object_del(auth_data->popup);
1864    free(auth_data);
1865 }
1866
1867 static void
1868 _auth_cancel_cb(void *user_data, Evas_Object *obj, void *event_info)
1869 {
1870    Auth_Data *auth_data = (Auth_Data *)user_data;
1871
1872    ewk_auth_request_cancel(auth_data->request);
1873
1874    auth_popup_close(auth_data);
1875 }
1876
1877 static void
1878 _auth_ok_cb(void *user_data, Evas_Object *obj, void *event_info)
1879 {
1880    Auth_Data *auth_data = (Auth_Data *)user_data;
1881
1882    const char *username = elm_entry_entry_get(auth_data->username_entry);
1883    const char *password = elm_entry_entry_get(auth_data->password_entry);
1884    ewk_auth_request_authenticate(auth_data->request, username, password);
1885
1886    auth_popup_close(auth_data);
1887 }
1888
1889 static void
1890 _authentication_request_cb(void *user_data, Evas_Object *obj, void *event_info)
1891 {
1892    Browser_Window *window = (Browser_Window *)user_data;
1893    Ewk_Auth_Request *request = ewk_object_ref((Ewk_Auth_Request *)event_info);
1894
1895    Auth_Data *auth_data = (Auth_Data *)malloc(sizeof(Auth_Data));
1896    auth_data->request = request;
1897
1898    Evas_Object *auth_popup = elm_popup_add(window->elm_window);
1899    auth_data->popup = auth_popup;
1900    evas_object_size_hint_weight_set(auth_popup, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1901    elm_object_part_text_set(auth_popup, "title,text", "Authentication Required");
1902
1903    /* Popup Content */
1904    Evas_Object *vbox = elm_box_add(auth_popup);
1905    elm_box_padding_set(vbox, 0, 4);
1906    evas_object_size_hint_weight_set(vbox, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1907    evas_object_size_hint_align_set(vbox, EVAS_HINT_FILL, EVAS_HINT_FILL);
1908    elm_object_content_set(auth_popup, vbox);
1909    evas_object_show(vbox);
1910
1911    /* Authentication message */
1912    Evas_Object *label = elm_label_add(auth_popup);
1913    elm_label_line_wrap_set(label, ELM_WRAP_WORD);
1914    Eina_Strbuf *auth_text = eina_strbuf_new();
1915    const char *host = ewk_auth_request_host_get(request);
1916    const char *realm = ewk_auth_request_realm_get(request);
1917    eina_strbuf_append_printf(auth_text, "A username and password are being requested by %s. The site says: \"%s\"", host, realm ? realm : "");
1918    elm_object_text_set(label, eina_strbuf_string_get(auth_text));
1919    eina_strbuf_free(auth_text);
1920    evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1921    evas_object_size_hint_align_set(label, EVAS_HINT_FILL, EVAS_HINT_FILL);
1922    elm_box_pack_end(vbox, label);
1923    evas_object_show(label);
1924
1925    /* Credential table */
1926    Evas_Object *table = elm_table_add(auth_popup);
1927    elm_table_padding_set(table, 2, 2);
1928    elm_table_homogeneous_set(table, EINA_TRUE);
1929    evas_object_size_hint_weight_set(table, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1930    evas_object_size_hint_align_set(table, EVAS_HINT_FILL, EVAS_HINT_FILL);
1931    elm_box_pack_end(vbox, table);
1932    evas_object_show(table);
1933
1934    /* Username row */
1935    Evas_Object *username_label = elm_label_add(auth_popup);
1936    elm_object_text_set(username_label, "Username:");
1937    evas_object_size_hint_weight_set(username_label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1938    evas_object_size_hint_align_set(username_label, 1, EVAS_HINT_FILL);
1939    elm_table_pack(table, username_label, 0, 0, 1, 1);
1940    evas_object_show(username_label);
1941
1942    Evas_Object *username_entry = elm_entry_add(auth_popup);
1943    auth_data->username_entry = username_entry;
1944    elm_entry_scrollable_set(username_entry, EINA_TRUE);
1945    elm_entry_single_line_set(username_entry, EINA_TRUE);
1946    elm_entry_text_style_user_push(username_entry, "DEFAULT='font_size=18'");
1947    const char *suggested_username = ewk_auth_request_suggested_username_get(request);
1948    elm_entry_entry_set(username_entry, suggested_username ? suggested_username : "");
1949    evas_object_size_hint_weight_set(username_entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1950    evas_object_size_hint_align_set(username_entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1951    elm_table_pack(table, username_entry, 1, 0, 2, 1);
1952    elm_object_focus_set(username_entry, EINA_TRUE);
1953    evas_object_show(username_entry);
1954
1955    /* Password row */
1956    Evas_Object *password_label = elm_label_add(auth_popup);
1957    elm_object_text_set(password_label, "Password:");
1958    evas_object_size_hint_weight_set(password_label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1959    evas_object_size_hint_align_set(password_label, 1, EVAS_HINT_FILL);
1960    elm_table_pack(table, password_label, 0, 1, 1, 1);
1961    evas_object_show(password_label);
1962
1963    Evas_Object *password_entry = elm_entry_add(auth_popup);
1964    auth_data->password_entry = password_entry;
1965    elm_entry_scrollable_set(password_entry, EINA_TRUE);
1966    elm_entry_single_line_set(password_entry, EINA_TRUE);
1967    elm_entry_password_set(password_entry, EINA_TRUE);
1968    elm_entry_text_style_user_push(password_entry, "DEFAULT='font_size=18'");
1969    evas_object_size_hint_weight_set(password_entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1970    evas_object_size_hint_align_set(password_entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
1971    elm_table_pack(table, password_entry, 1, 1, 2, 1);
1972    evas_object_show(password_entry);
1973
1974    /* Popup buttons */
1975    Evas_Object *cancel_button = elm_button_add(auth_popup);
1976    elm_object_text_set(cancel_button, "Cancel");
1977    elm_object_part_content_set(auth_popup, "button1", cancel_button);
1978    evas_object_smart_callback_add(cancel_button, "clicked", _auth_cancel_cb, auth_data);
1979    Evas_Object *ok_button = elm_button_add(auth_popup);
1980    elm_object_text_set(ok_button, "OK");
1981    elm_object_part_content_set(auth_popup, "button2", ok_button);
1982    evas_object_smart_callback_add(ok_button, "clicked", _auth_ok_cb, auth_data);
1983    evas_object_show(auth_popup);
1984 }
1985
1986 static void
1987 _search_text_found_cb(void *user_data, Evas_Object *obj, void *event_info)
1988 {
1989    Browser_Window *window = (Browser_Window *)user_data;
1990
1991    const int *match_count = (const int *)(event_info);
1992
1993    if (*match_count) {
1994      Eina_Strbuf *search_text = eina_strbuf_new();
1995      eina_strbuf_append_printf(search_text, "  %d  Matches Found " , *match_count);
1996      elm_object_text_set(window->search.search_field_count, eina_strbuf_string_get(search_text));
1997      eina_strbuf_free(search_text);
1998    } else
1999      elm_object_text_set(window->search.search_field_count, " No Matches Found");
2000
2001    evas_object_focus_set(window->ewk_view, EINA_FALSE);
2002    elm_object_focus_set(window->search.search_field_count, EINA_FALSE);
2003    elm_object_focus_set(window->search.search_field, EINA_TRUE);
2004 }
2005
2006 static void
2007 _tooltip_text_set(void *user_data, Evas_Object *obj, void *event_info)
2008 {
2009    Browser_Window *window = (Browser_Window *)user_data;
2010    const char *message = (const char*)event_info;
2011
2012    elm_object_tooltip_text_set(window->elm_window, message);
2013    window->tooltip.text_set = EINA_TRUE;
2014    window_tooltip_update(window);
2015 }
2016
2017 static void
2018 _tooltip_text_unset(void *user_data, Evas_Object *obj, void *event_info)
2019 {
2020    Browser_Window *window = (Browser_Window *)user_data;
2021
2022    window_tooltip_hide(window);
2023    elm_object_tooltip_unset(window->elm_window);
2024    window->tooltip.text_set = EINA_FALSE;
2025 }
2026
2027 static void
2028 _navigation_policy_decision_cb(void *user_data, Evas_Object *obj, void *event_info)
2029 {
2030    Ewk_Navigation_Policy_Decision *decision = (Ewk_Navigation_Policy_Decision *)event_info;
2031
2032    if (ewk_navigation_policy_mouse_button_get(decision) == EWK_EVENT_MOUSE_BUTTON_MIDDLE) {
2033      Browser_Window *window = window_create(NULL, 0, 0);
2034      ewk_view_url_set(window->ewk_view, ewk_url_request_url_get(ewk_navigation_policy_request_get(decision)));
2035      windows = eina_list_append(windows, window);
2036      INFO("Mouse middle button pressed, open link in new window");
2037
2038      ewk_navigation_policy_decision_reject(decision);
2039    }
2040 }
2041
2042 static void
2043 _home_button_clicked_cb(void *user_data, Evas_Object *home_button, void *event_info)
2044 {
2045    Browser_Window *window = (Browser_Window *)user_data;
2046
2047    ewk_view_url_set(window->ewk_view, DEFAULT_URL);
2048 }
2049
2050 static void
2051 _window_deletion_cb(void *user_data, Evas_Object *elm_window, void *event_info)
2052 {
2053    Browser_Window *window = (Browser_Window *)user_data;
2054    ewk_view_try_close(window->ewk_view);
2055 }
2056
2057 static Evas_Object *
2058 create_toolbar_button(Evas_Object *elm_window, const char *icon_name)
2059 {
2060    Evas_Object *button = elm_button_add(elm_window);
2061
2062    Evas_Object *icon = elm_icon_add(elm_window);
2063    elm_icon_standard_set(icon, icon_name);
2064    evas_object_size_hint_max_set(icon, TOOL_BAR_ICON_SIZE, TOOL_BAR_ICON_SIZE);
2065    evas_object_color_set(icon, 44, 44, 102, 128);
2066    evas_object_show(icon);
2067    elm_object_part_content_set(button, "icon", icon);
2068    evas_object_size_hint_min_set(button, TOOL_BAR_BUTTON_SIZE, TOOL_BAR_BUTTON_SIZE);
2069
2070    return button;
2071 }
2072
2073 static Browser_Window *window_create(Ewk_View_Configuration* configuration, int width, int height)
2074 {
2075    Browser_Window *window = calloc(1, sizeof(Browser_Window));
2076    if (!window) {
2077      ERROR("Could not create browser window.");
2078      return NULL;
2079    }
2080
2081    /* Initialize tooltip information */
2082    window->tooltip.show_timer = NULL;
2083    window->tooltip.activated = EINA_FALSE;
2084    window->tooltip.text_set = EINA_FALSE;
2085    window->tooltip.shown = EINA_FALSE;
2086
2087    /* Create window */
2088    window->elm_window = elm_win_add(NULL, "minibrowser-window", ELM_WIN_BASIC);
2089    elm_win_title_set(window->elm_window, APP_NAME);
2090    evas_object_smart_callback_add(window->elm_window, "delete,request", _window_deletion_cb, window);
2091
2092    /* Create window background */
2093    Evas_Object *bg = elm_bg_add(window->elm_window);
2094    elm_bg_color_set(bg, 193, 192, 191);
2095    evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2096    elm_win_resize_object_add(window->elm_window, bg);
2097    evas_object_show(bg);
2098
2099    /* Create conformant widget. */
2100    Evas_Object *conformant = elm_conformant_add(window->elm_window);
2101    evas_object_size_hint_weight_set(conformant, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2102    elm_win_resize_object_add(window->elm_window, conformant);
2103    evas_object_show(conformant);
2104
2105    /* Create vertical layout */
2106    window->vertical_layout = elm_box_add(window->elm_window);
2107    elm_object_content_set(conformant, window->vertical_layout);
2108    elm_box_padding_set(window->vertical_layout, 0, 2);
2109    evas_object_size_hint_weight_set(window->vertical_layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2110    evas_object_show(window->vertical_layout);
2111
2112    /* Create horizontal layout for top bar */
2113    window->horizontal_layout = elm_box_add(window->elm_window);
2114    elm_box_horizontal_set(window->horizontal_layout, EINA_TRUE);
2115    evas_object_size_hint_weight_set(window->horizontal_layout, EVAS_HINT_EXPAND, 0.0);
2116    evas_object_size_hint_align_set(window->horizontal_layout, EVAS_HINT_FILL, 0.0);
2117    elm_box_pack_end(window->vertical_layout, window->horizontal_layout);
2118    evas_object_show(window->horizontal_layout);
2119
2120    /* Create Back button */
2121    window->back_button = create_toolbar_button(window->elm_window, "arrow_left");
2122    evas_object_smart_callback_add(window->back_button, "clicked", _back_button_clicked_cb, window);
2123    evas_object_smart_callback_add(window->back_button, "repeated", _back_button_longpress_cb, window);
2124    elm_object_tooltip_text_set(window->back_button, "Click to go back, longpress to see session history");
2125    elm_object_tooltip_window_mode_set(window->back_button, EINA_TRUE);
2126    elm_object_disabled_set(window->back_button, EINA_TRUE);
2127    evas_object_size_hint_weight_set(window->back_button, 0.0, EVAS_HINT_EXPAND);
2128    evas_object_size_hint_align_set(window->back_button, 0.0, 0.5);
2129    elm_box_pack_end(window->horizontal_layout, window->back_button);
2130    evas_object_show(window->back_button);
2131
2132    /* Create Forward button */
2133    window->forward_button = create_toolbar_button(window->elm_window, "arrow_right");
2134    evas_object_smart_callback_add(window->forward_button, "clicked", _forward_button_clicked_cb, window);
2135    evas_object_smart_callback_add(window->forward_button, "repeated", _forward_button_longpress_cb, window);
2136    elm_object_tooltip_text_set(window->forward_button, "Click to go forward, longpress to see session history");
2137    elm_object_tooltip_window_mode_set(window->forward_button, EINA_TRUE);
2138    elm_object_disabled_set(window->forward_button, EINA_TRUE);
2139    evas_object_size_hint_weight_set(window->forward_button, 0.0, EVAS_HINT_EXPAND);
2140    evas_object_size_hint_align_set(window->forward_button, 0.0, 0.5);
2141    elm_box_pack_end(window->horizontal_layout, window->forward_button);
2142    evas_object_show(window->forward_button);
2143
2144    /* Create URL bar */
2145    window->url_bar = elm_entry_add(window->elm_window);
2146    elm_entry_scrollable_set(window->url_bar, EINA_TRUE);
2147    elm_scroller_policy_set(window->url_bar, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
2148    elm_entry_single_line_set(window->url_bar, EINA_TRUE);
2149    elm_entry_cnp_mode_set(window->url_bar, ELM_CNP_MODE_PLAINTEXT);
2150    elm_entry_text_style_user_push(window->url_bar, "DEFAULT='font_size=18'");
2151    evas_object_smart_callback_add(window->url_bar, "activated", _url_bar_activated_cb, window);
2152    evas_object_smart_callback_add(window->url_bar, "clicked", _url_bar_clicked_cb, window);
2153    evas_object_size_hint_weight_set(window->url_bar, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2154    evas_object_size_hint_align_set(window->url_bar, EVAS_HINT_FILL, EVAS_HINT_FILL);
2155    elm_box_pack_end(window->horizontal_layout, window->url_bar);
2156    evas_object_show(window->url_bar);
2157
2158    /* Create Refresh button */
2159    Evas_Object *refresh_button = create_toolbar_button(window->elm_window, "refresh");
2160    evas_object_smart_callback_add(refresh_button, "clicked", _refresh_button_clicked_cb, window);
2161    elm_object_tooltip_text_set(refresh_button, "Reload page");
2162    elm_object_tooltip_window_mode_set(refresh_button, EINA_TRUE);
2163    evas_object_size_hint_weight_set(refresh_button, 0.0, EVAS_HINT_EXPAND);
2164    evas_object_size_hint_align_set(refresh_button, 1.0, 0.5);
2165    elm_box_pack_end(window->horizontal_layout, refresh_button);
2166    evas_object_show(refresh_button);
2167
2168    /* Create Stop button */
2169    Evas_Object *stop_button = create_toolbar_button(window->elm_window, "close");
2170    evas_object_smart_callback_add(stop_button, "clicked", _stop_button_clicked_cb, window);
2171    elm_object_tooltip_text_set(stop_button, "Stop page load");
2172    elm_object_tooltip_window_mode_set(stop_button, EINA_TRUE);
2173    evas_object_size_hint_weight_set(stop_button, 0.0, EVAS_HINT_EXPAND);
2174    evas_object_size_hint_align_set(stop_button, 1.0, 0.5);
2175    elm_box_pack_end(window->horizontal_layout, stop_button);
2176    evas_object_show(stop_button);
2177
2178    /* Create Home button */
2179    Evas_Object *home_button = create_toolbar_button(window->elm_window, "home");
2180    evas_object_smart_callback_add(home_button, "clicked", _home_button_clicked_cb, window);
2181    elm_object_tooltip_text_set(home_button, "Home page");
2182    elm_object_tooltip_window_mode_set(home_button, EINA_TRUE);
2183    evas_object_size_hint_weight_set(home_button, 0.0, EVAS_HINT_EXPAND);
2184    evas_object_size_hint_align_set(home_button, 1.0, 0.5);
2185    elm_box_pack_end(window->horizontal_layout, home_button);
2186    evas_object_show(home_button);
2187
2188    /* Create Search bar */
2189    window->search.search_bar = elm_box_add(window->elm_window);
2190    elm_box_horizontal_set(window->search.search_bar, EINA_TRUE);
2191    evas_object_size_hint_min_set(window->search.search_bar, SEARCH_FIELD_SIZE + 2 * SEARCH_BUTTON_SIZE, 0);
2192    evas_object_size_hint_align_set(window->search.search_bar, EVAS_HINT_FILL, EVAS_HINT_FILL);
2193    elm_box_pack_end(window->vertical_layout, window->search.search_bar);
2194
2195    /* Create Search field */
2196    window->search.search_field = elm_entry_add(window->elm_window);
2197    elm_entry_scrollable_set(window->search.search_field, EINA_TRUE);
2198    elm_scroller_policy_set(window->search.search_field, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
2199    elm_entry_single_line_set(window->search.search_field, EINA_TRUE);
2200    elm_entry_cnp_mode_set(window->search.search_field, ELM_CNP_MODE_PLAINTEXT);
2201    elm_entry_text_style_user_push(window->search.search_field, "DEFAULT='font_size=14'");
2202    evas_object_smart_callback_add(window->search.search_field, "activated", _search_field_activated_cb, window);
2203    evas_object_smart_callback_add(window->search.search_field, "changed", _search_field_activated_cb, window);
2204    evas_object_smart_callback_add(window->search.search_field, "aborted", _search_field_aborted_cb, window);
2205    evas_object_smart_callback_add(window->search.search_field, "clicked", _search_field_clicked_cb, window);
2206    evas_object_size_hint_weight_set(window->search.search_field, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2207    evas_object_size_hint_align_set(window->search.search_field, EVAS_HINT_FILL, EVAS_HINT_FILL);
2208    elm_box_pack_end(window->search.search_bar, window->search.search_field);
2209
2210    /* Create Search backward button */
2211    window->search.backward_button = create_toolbar_button(window->elm_window, "arrow_up");
2212    evas_object_smart_callback_add(window->search.backward_button, "clicked", _search_backward_button_clicked_cb, window);
2213    elm_object_disabled_set(window->search.backward_button, EINA_FALSE);
2214    evas_object_size_hint_weight_set(window->search.backward_button, 0.0, EVAS_HINT_EXPAND);
2215    evas_object_size_hint_align_set(window->search.backward_button, 1.0, 0.5);
2216    evas_object_size_hint_min_set(window->search.backward_button, SEARCH_BUTTON_SIZE, SEARCH_BUTTON_SIZE);
2217    elm_box_pack_end(window->search.search_bar, window->search.backward_button);
2218
2219    /* Create Search forwardward button */
2220    window->search.forward_button = create_toolbar_button(window->elm_window, "arrow_down");
2221    evas_object_smart_callback_add(window->search.forward_button, "clicked", _search_forward_button_clicked_cb, window);
2222    elm_object_disabled_set(window->search.forward_button, EINA_FALSE);
2223    evas_object_size_hint_weight_set(window->search.forward_button, 0.0, EVAS_HINT_EXPAND);
2224    evas_object_size_hint_align_set(window->search.forward_button, 1.0, 0.5);
2225    evas_object_size_hint_min_set(window->search.forward_button, SEARCH_BUTTON_SIZE, SEARCH_BUTTON_SIZE);
2226    elm_box_pack_end(window->search.search_bar, window->search.forward_button);
2227
2228    /* Create Search count field */
2229    window->search.search_field_count = elm_label_add(window->elm_window);
2230    evas_object_size_hint_weight_set(window->search.search_field_count, 0.0, EVAS_HINT_EXPAND);
2231    evas_object_size_hint_align_set(window->search.search_field_count, EVAS_HINT_FILL, EVAS_HINT_FILL);
2232    elm_object_text_set(window->search.search_field_count, "");
2233    elm_box_pack_end(window->search.search_bar, window->search.search_field_count);
2234
2235    /* Create Search Case Sensitive Option check box */
2236    window->search.search_case_check_box = elm_check_add(window->elm_window);
2237    elm_object_text_set(window->search.search_case_check_box, "Case Sensitive");
2238    evas_object_smart_callback_add(window->search.search_case_check_box, "changed", _search_case_option_changed, window);
2239    elm_box_pack_end(window->search.search_bar, window->search.search_case_check_box);
2240
2241    /* Create Search Word Start Option check box */
2242    window->search.search_word_start_check_box = elm_check_add(window->elm_window);
2243    elm_object_text_set(window->search.search_word_start_check_box, "Only Word Start");
2244    evas_object_smart_callback_add(window->search.search_word_start_check_box, "changed", _search_word_start_option_changed_cb, window);
2245    elm_box_pack_end(window->search.search_bar, window->search.search_word_start_check_box);
2246
2247    /* Create Search close button */
2248    window->search.close_button = create_toolbar_button(window->elm_window, "close");
2249    evas_object_smart_callback_add(window->search.close_button, "clicked", _search_close_button_clicked_cb, window);
2250    elm_object_disabled_set(window->search.close_button, EINA_FALSE);
2251    evas_object_size_hint_weight_set(window->search.close_button, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2252    evas_object_size_hint_align_set(window->search.close_button, 1.0, 0.5);
2253    evas_object_size_hint_min_set(window->search.close_button, SEARCH_BUTTON_SIZE, SEARCH_BUTTON_SIZE);
2254    elm_box_pack_end(window->search.search_bar, window->search.close_button);
2255
2256    /* Create history box */
2257    window->history.history_box = elm_box_add(window->elm_window);
2258    evas_object_size_hint_aspect_set(window->history.history_box, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
2259    evas_object_size_hint_weight_set(window->history.history_box, EVAS_HINT_EXPAND , EVAS_HINT_EXPAND);
2260
2261    /* Create history list */
2262    window->history.history_list = elm_genlist_add(window->elm_window);
2263    evas_object_size_hint_weight_set(window->history.history_list, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2264    evas_object_size_hint_align_set(window->history.history_list, EVAS_HINT_FILL, EVAS_HINT_FILL);
2265    elm_win_resize_object_add(window->elm_window, window->history.history_box);
2266    elm_box_pack_end(window->history.history_box, window->history.history_list);
2267
2268    /* Create ewk_view */
2269    Ewk_View_Smart_Class *ewkViewClass = miniBrowserViewSmartClass();
2270    ewkViewClass->run_javascript_alert = _javascript_alert_cb;
2271    ewkViewClass->run_javascript_confirm = _javascript_confirm_cb;
2272    ewkViewClass->run_javascript_prompt = _javascript_prompt_cb;
2273    ewkViewClass->run_javascript_before_unload_confirm = _javascript_before_unload_confirm_cb;
2274    ewkViewClass->window_geometry_get = _window_geometry_get;
2275    ewkViewClass->window_geometry_set = _window_geometry_set;
2276    ewkViewClass->fullscreen_enter = _fullscreen_enter_cb;
2277    ewkViewClass->fullscreen_exit = _fullscreen_exit_cb;
2278    ewkViewClass->window_create = _window_create_cb;
2279    ewkViewClass->window_close = _window_close_cb;
2280    ewkViewClass->popup_menu_show = _popup_menu_show;
2281    ewkViewClass->popup_menu_hide = _popup_menu_hide;
2282    ewkViewClass->context_menu_show = _context_menu_show;
2283    ewkViewClass->context_menu_hide = _context_menu_hide;
2284    ewkViewClass->input_picker_color_request = _color_picker_request_cb;
2285    ewkViewClass->input_picker_color_dismiss = _color_picker_dismiss_cb;
2286
2287    Evas *evas = evas_object_evas_get(window->elm_window);
2288    Evas_Smart *smart = evas_smart_class_new(&ewkViewClass->sc);
2289    window->ewk_view = ewk_view_add_with_configuration(evas, smart, configuration);
2290
2291    Ewk_Context *context = ewk_view_context_get(window->ewk_view);
2292    ewk_favicon_database_icon_change_callback_add(ewk_context_favicon_database_get(context), _icon_changed_cb, window);
2293
2294    ewk_view_theme_set(window->ewk_view, DEFAULT_THEME_DIR "/default.edj");
2295    if (device_pixel_ratio)
2296      ewk_view_device_pixel_ratio_set(window->ewk_view, (float)device_pixel_ratio);
2297    ewk_view_user_agent_set(window->ewk_view, user_agent_string);
2298    ewk_view_layout_fixed_set(window->ewk_view, fixed_layout_enabled);
2299
2300    if (touch_events_enabled) {
2301      ewk_view_touch_events_enabled_set(window->ewk_view, EINA_TRUE);
2302      ewk_view_mouse_events_enabled_set(window->ewk_view, EINA_FALSE);
2303    }
2304
2305    if (background_color_string) {
2306      int red, green, blue, alpha;
2307
2308      if (sscanf(background_color_string, "%d:%d:%d:%d", &red, &green, &blue, &alpha))
2309        ewk_view_bg_color_set(window->ewk_view, red, green, blue, alpha);
2310    }
2311
2312    /* Set the zoom level to default */
2313    window->current_zoom_level = DEFAULT_ZOOM_LEVEL;
2314
2315    elm_win_fullscreen_set(window->elm_window, fullscreen_enabled);
2316
2317    evas_object_smart_callback_add(window->ewk_view, "authentication,request", _authentication_request_cb, window);
2318    evas_object_smart_callback_add(window->ewk_view, "file,chooser,request", _file_chooser_request_cb, window);
2319    evas_object_smart_callback_add(window->ewk_view, "load,error", _error_cb, window);
2320    evas_object_smart_callback_add(window->ewk_view, "load,provisional,failed", _error_cb, window);
2321    evas_object_smart_callback_add(window->ewk_view, "load,progress", _progress_cb, window);
2322    evas_object_smart_callback_add(window->ewk_view, "title,changed", _title_changed_cb, window);
2323    evas_object_smart_callback_add(window->ewk_view, "url,changed", _url_changed_cb, window);
2324    evas_object_smart_callback_add(window->ewk_view, "back,forward,list,changed", _back_forward_list_changed_cb, window);
2325    evas_object_smart_callback_add(window->ewk_view, "text,found", _search_text_found_cb, window);
2326    evas_object_smart_callback_add(window->ewk_view, "tooltip,text,set", _tooltip_text_set, window);
2327    evas_object_smart_callback_add(window->ewk_view, "tooltip,text,unset", _tooltip_text_unset, window);
2328    evas_object_smart_callback_add(window->ewk_view, "policy,decision,navigation", _navigation_policy_decision_cb, window);
2329
2330    evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, window);
2331    evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, window);
2332
2333    evas_object_size_hint_weight_set(window->ewk_view, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
2334    evas_object_size_hint_align_set(window->ewk_view, EVAS_HINT_FILL, EVAS_HINT_FILL);
2335    elm_box_pack_before(window->vertical_layout, window->ewk_view, window->search.search_bar);
2336    evas_object_show(window->ewk_view);
2337
2338    evas_object_resize(window->elm_window, width ? width : window_width, height ? height : window_height);
2339    evas_object_show(window->elm_window);
2340    search_box_hide(window);
2341
2342    view_focus_set(window, EINA_TRUE);
2343    // Prevent window from stealing web view's focus on start up.
2344    elm_object_focus_allow_set(window->elm_window, EINA_FALSE);
2345
2346    evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_MOUSE_IN, _mouse_in_cb, window);
2347    evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_MOUSE_OUT, _mouse_out_cb, window);
2348    evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, window);
2349    evas_object_event_callback_add(window->ewk_view, EVAS_CALLBACK_MOUSE_WHEEL, _mouse_wheel_cb, window);
2350    evas_object_event_callback_add(window->elm_window, EVAS_CALLBACK_RESIZE, _window_resize_cb, window);
2351
2352    elm_button_autorepeat_set(window->back_button, EINA_TRUE);
2353    elm_button_autorepeat_set(window->forward_button, EINA_TRUE);
2354    elm_button_autorepeat_initial_timeout_set(window->back_button, LONGPRESS_INTERVAL_SECONDS);
2355    elm_button_autorepeat_initial_timeout_set(window->forward_button, LONGPRESS_INTERVAL_SECONDS);
2356
2357    return window;
2358 }
2359
2360 static Ewk_View_Configuration* configuration()
2361 {
2362     static Ewk_View_Configuration* default_configuration = 0;
2363
2364     if (default_configuration)
2365       return default_configuration;
2366
2367     default_configuration = ewk_view_configuration_new();
2368
2369     Ewk_Settings* settings = ewk_view_configuration_settings_get(default_configuration);
2370     ewk_settings_file_access_from_file_urls_allowed_set(settings, EINA_TRUE);
2371     ewk_settings_encoding_detector_enabled_set(settings, encoding_detector_enabled);
2372     ewk_settings_frame_flattening_enabled_set(settings, frame_flattening_enabled);
2373     ewk_settings_local_storage_enabled_set(settings, local_storage_enabled);
2374     ewk_settings_offline_web_application_cache_enabled_set(settings, offline_web_application_cache_enabled);
2375     INFO("HTML5 local storage is %s for this view.", local_storage_enabled ? "enabled" : "disabled");
2376     ewk_settings_developer_extras_enabled_set(settings, EINA_TRUE);
2377     ewk_settings_preferred_minimum_contents_width_set(settings, 0);
2378     ewk_text_checker_continuous_spell_checking_enabled_set(spell_checking_enabled);
2379     ewk_settings_web_security_enabled_set(settings, web_security_enabled);
2380
2381     return default_configuration;
2382 }
2383
2384 static Ewk_Cookie_Accept_Policy
2385 parse_cookies_policy(const char *input_string)
2386 {
2387    if (!strcmp(input_string, "always"))
2388      return EWK_COOKIE_ACCEPT_POLICY_ALWAYS;
2389    if (!strcmp(input_string, "never"))
2390      return EWK_COOKIE_ACCEPT_POLICY_NEVER;
2391    if (strcmp(input_string, "no-third-party"))
2392      INFO("Unrecognized type for cookies policy: %s.", input_string);
2393    return EWK_COOKIE_ACCEPT_POLICY_NO_THIRD_PARTY;
2394 }
2395
2396 static void
2397 parse_window_size(const char *input_string, int *width, int *height)
2398 {
2399    static const unsigned max_length = 4;
2400    int parsed_width;
2401    int parsed_height;
2402    char **arr;
2403    unsigned elements;
2404
2405    arr = eina_str_split_full(input_string, "x", 0, &elements);
2406
2407    if (elements == 2 && (strlen(arr[0]) <= max_length) && (strlen(arr[1]) <= max_length)) {
2408      parsed_width = atoi(arr[0]);
2409      if (width && parsed_width)
2410        *width = parsed_width;
2411
2412      parsed_height = atoi(arr[1]);
2413      if (height && parsed_height)
2414        *height = parsed_height;
2415    }
2416
2417    free(arr[0]);
2418    free(arr);
2419 }
2420
2421 EAPI_MAIN int
2422 elm_main(int argc, char *argv[])
2423 {
2424    int args = 1;
2425    unsigned char quitOption = 0;
2426    Browser_Window *window;
2427    char *window_size_string = NULL;
2428    char *cookies_policy_string = NULL;
2429
2430    Ecore_Getopt_Value values[] = {
2431      ECORE_GETOPT_VALUE_STR(evas_engine_name),
2432      ECORE_GETOPT_VALUE_STR(window_size_string),
2433      ECORE_GETOPT_VALUE_STR(user_agent_string),
2434      ECORE_GETOPT_VALUE_STR(extensions_path),
2435      ECORE_GETOPT_VALUE_DOUBLE(device_pixel_ratio),
2436      ECORE_GETOPT_VALUE_BOOL(quitOption),
2437      ECORE_GETOPT_VALUE_BOOL(encoding_detector_enabled),
2438      ECORE_GETOPT_VALUE_STR(background_color_string),
2439      ECORE_GETOPT_VALUE_BOOL(frame_flattening_enabled),
2440      ECORE_GETOPT_VALUE_BOOL(local_storage_enabled),
2441      ECORE_GETOPT_VALUE_BOOL(offline_web_application_cache_enabled),
2442      ECORE_GETOPT_VALUE_BOOL(fullscreen_enabled),
2443      ECORE_GETOPT_VALUE_BOOL(spell_checking_enabled),
2444      ECORE_GETOPT_VALUE_BOOL(touch_events_enabled),
2445      ECORE_GETOPT_VALUE_BOOL(fixed_layout_enabled),
2446      ECORE_GETOPT_VALUE_STR(cookies_policy_string),
2447      ECORE_GETOPT_VALUE_BOOL(web_security_enabled),
2448      ECORE_GETOPT_VALUE_BOOL(separated_process_enabled),
2449      ECORE_GETOPT_VALUE_BOOL(quitOption),
2450      ECORE_GETOPT_VALUE_BOOL(quitOption),
2451      ECORE_GETOPT_VALUE_BOOL(quitOption),
2452      ECORE_GETOPT_VALUE_NONE
2453    };
2454
2455    efreet_cache_update = 0;
2456
2457    if (!ewk_init())
2458      return EXIT_FAILURE;
2459
2460    _log_domain_id = eina_log_domain_register("minibrowser", EINA_COLOR_YELLOW);
2461
2462    ewk_view_smart_class_set(miniBrowserViewSmartClass());
2463
2464    ecore_app_args_set(argc, (const char **) argv);
2465    args = ecore_getopt_parse(&options, values, argc, argv);
2466
2467    if (args < 0)
2468      return quit(EINA_FALSE, "Could not parse options.");
2469
2470    if (quitOption)
2471      return quit(EINA_TRUE, NULL);
2472
2473    if (evas_engine_name)
2474      elm_config_accel_preference_set(evas_engine_name);
2475    else {
2476      evas_engine_name = "opengl:depth24:stencil8";
2477      elm_config_accel_preference_set(evas_engine_name);
2478    }
2479
2480    Ewk_Context *context = ewk_context_default_get();
2481
2482    if (separated_process_enabled)
2483      ewk_context_web_process_count_limit_set(context, 0);
2484
2485    // Enable favicon database.
2486    ewk_context_favicon_database_directory_set(context, NULL);
2487
2488    // Use a proper cache model.
2489    ewk_context_cache_model_set(context, EWK_CACHE_MODEL_PRIMARY_WEBBROWSER);
2490
2491    if (cookies_policy_string) {
2492      Ewk_Cookie_Accept_Policy cookie_policy = parse_cookies_policy(cookies_policy_string);
2493      ewk_cookie_manager_accept_policy_set(ewk_context_cookie_manager_get(context), cookie_policy);
2494
2495      if (cookie_policy == EWK_COOKIE_ACCEPT_POLICY_ALWAYS) {
2496        const char cookie_storage_directory[] = "/tmp/ewebkit2_minibrowser_cookie/";
2497        mkdir(cookie_storage_directory, S_IRWXU);
2498        char storage_name[64];
2499        snprintf(storage_name, sizeof(storage_name), "%stxt-cookie", cookie_storage_directory);
2500        ewk_cookie_manager_persistent_storage_set(ewk_context_cookie_manager_get(context), storage_name, EWK_COOKIE_PERSISTENT_STORAGE_TEXT);
2501      }
2502    }
2503
2504    if (window_size_string)
2505      parse_window_size(window_size_string, &window_width, &window_height);
2506
2507    window = window_create(configuration(), 0, 0);
2508    if (!window)
2509      return quit(EINA_FALSE, "Could not create browser window.");
2510
2511    // Set callbacks for download events.
2512    ewk_context_download_callbacks_set(context, _download_request_cb, _download_failed_cb, 0, _download_finished_cb, window);
2513
2514    if (args < argc) {
2515      char *url = url_from_user_input(argv[args]);
2516      url_load_from_user_input(window->ewk_view, url);
2517      free(url);
2518    } else
2519      ewk_view_url_set(window->ewk_view, DEFAULT_URL);
2520
2521    windows = eina_list_append(windows, window);
2522
2523    elm_run();
2524
2525    return quit(EINA_TRUE, NULL);
2526 }
2527 ELM_MAIN()
2528