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