2 * Copyright (C) 2012 Samsung Electronics
3 * Copyright (C) 2012 Intel Corporation. All rights reserved.
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.
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.
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
21 #include "url_utils.h"
23 #include <Ecore_Evas.h>
25 #include <Elementary.h>
28 static const int DEFAULT_WIDTH = 800;
29 static const int DEFAULT_HEIGHT = 600;
30 static const char DEFAULT_URL[] = "http://www.google.com/";
31 static const char APP_NAME[] = "EFL MiniBrowser";
32 static const int TOOL_BAR_ICON_SIZE = 24;
33 static const int TOOL_BAR_BUTTON_SIZE = 32;
35 #define info(format, args...) \
38 printf(format, ##args); \
41 static int verbose = 1;
42 static Eina_List *windows = NULL;
43 static char *evas_engine_name = NULL;
44 static Eina_Bool frame_flattening_enabled = EINA_FALSE;
45 static Eina_Bool fullscreen_enabled = EINA_FALSE;
47 typedef struct _Browser_Window {
51 Evas_Object *back_button;
52 Evas_Object *forward_button;
55 static const Ecore_Getopt options = {
57 "%prog [options] [url]",
59 "(C)2012 Samsung Electronics\n",
61 "Test Web Browser using the Enlightenment Foundation Libraries of WebKit2",
63 ECORE_GETOPT_STORE_STR
64 ('e', "engine", "ecore-evas engine to use."),
65 ECORE_GETOPT_CALLBACK_NOARGS
66 ('E', "list-engines", "list ecore-evas engines.",
67 ecore_getopt_callback_ecore_evas_list_engines, NULL),
68 ECORE_GETOPT_STORE_DEF_BOOL
69 ('f', "flattening", "frame flattening.", EINA_FALSE),
70 ECORE_GETOPT_STORE_DEF_BOOL
71 ('F', "full-screen", "start in full-screen.", EINA_FALSE),
74 ECORE_GETOPT_COPYRIGHT
82 static Browser_Window *window_create(const char *url);
84 static Browser_Window *browser_window_find(Evas_Object *window)
92 EINA_LIST_FOREACH(windows, l, data) {
93 Browser_Window *browser_window = (Browser_Window *)data;
94 if (browser_window->window == window)
95 return browser_window;
100 static void window_free(Browser_Window *window)
102 evas_object_del(window->webview);
103 /* The elm_win will take care of freeing its children */
104 evas_object_del(window->window);
108 static void window_close(Browser_Window *window)
110 windows = eina_list_remove(windows, window);
118 on_key_down(void *data, Evas *e, Evas_Object *obj, void *event_info)
120 Evas_Event_Key_Down *ev = (Evas_Event_Key_Down*) event_info;
121 static const char *encodings[] = {
126 static int currentEncoding = -1;
127 Eina_Bool ctrlPressed = evas_key_modifier_is_set(evas_key_modifier_get(e), "Control");
129 if (!strcmp(ev->key, "F1")) {
130 info("Back (F1) was pressed\n");
131 if (!ewk_view_back(obj))
132 info("Back ignored: No back history\n");
133 } else if (!strcmp(ev->key, "F2")) {
134 info("Forward (F2) was pressed\n");
135 if (!ewk_view_forward(obj))
136 info("Forward ignored: No forward history\n");
137 } else if (!strcmp(ev->key, "F3")) {
138 currentEncoding = (currentEncoding + 1) % (sizeof(encodings) / sizeof(encodings[0]));
139 info("Set encoding (F3) pressed. New encoding to %s", encodings[currentEncoding]);
140 ewk_view_custom_encoding_set(obj, encodings[currentEncoding]);
141 } else if (!strcmp(ev->key, "F5")) {
142 info("Reload (F5) was pressed, reloading.\n");
143 ewk_view_reload(obj);
144 } else if (!strcmp(ev->key, "F6")) {
145 info("Stop (F6) was pressed, stop loading.\n");
147 } else if (!strcmp(ev->key, "n") && ctrlPressed) {
148 info("Create new window (Ctrl+n) was pressed.\n");
149 Browser_Window *window = window_create(DEFAULT_URL);
150 windows = eina_list_append(windows, window);
155 view_focus_set(Browser_Window *window, Eina_Bool focus)
157 /* We steal focus away from elm's focus model and start to do things
158 * manually here, so elm now has no clue what's up. Tell elm that its
159 * toplevel widget is to be unfocused so elm gives up the focus */
160 elm_object_focus_set(elm_object_top_widget_get(window->window), EINA_FALSE);
161 evas_object_focus_set(window->webview, focus);
165 on_mouse_down(void *user_data, Evas *e, Evas_Object *webview, void *event_info)
167 Browser_Window *window = (Browser_Window *)user_data;
168 Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down *)event_info;
170 /* Clear selection from the URL bar */
171 elm_entry_select_none(window->url_bar);
174 view_focus_set(window, EINA_TRUE);
175 else if (ev->button == 2)
176 view_focus_set(window, !evas_object_focus_get(webview));
180 title_set(Evas_Object *window, const char *title, int progress)
184 if (!title || !*title) {
185 elm_win_title_set(window, APP_NAME);
189 buffer = eina_strbuf_new();
191 eina_strbuf_append_printf(buffer, "%s (%d%%) - %s", title, progress, APP_NAME);
193 eina_strbuf_append_printf(buffer, "%s - %s", title, APP_NAME);
195 elm_win_title_set(window, eina_strbuf_string_get(buffer));
196 eina_strbuf_free(buffer);
200 on_title_changed(void *user_data, Evas_Object *webview, void *event_info)
202 Browser_Window *window = (Browser_Window *)user_data;
203 const char *title = (const char *)event_info;
205 title_set(window->window, title, 100);
209 on_url_changed(void *user_data, Evas_Object *webview, void *event_info)
211 Browser_Window *window = (Browser_Window *)user_data;
212 elm_entry_entry_set(window->url_bar, ewk_view_url_get(window->webview));
216 on_back_forward_list_changed(void *user_data, Evas_Object *webview, void *event_info)
218 Browser_Window *window = (Browser_Window *)user_data;
220 /* Update navigation buttons state */
221 elm_object_disabled_set(window->back_button, !ewk_view_back_possible(webview));
222 elm_object_disabled_set(window->forward_button, !ewk_view_forward_possible(webview));
226 on_new_window(void *user_data, Evas_Object *webview, void *event_info)
228 Evas_Object **new_view = (Evas_Object **)event_info;
229 Browser_Window *window = window_create(NULL);
230 *new_view = window->webview;
231 windows = eina_list_append(windows, window);
235 on_close_window(void *user_data, Evas_Object *webview, void *event_info)
237 window_close((Browser_Window *)user_data);
241 on_progress(void *user_data, Evas_Object *webview, void *event_info)
243 Browser_Window *window = (Browser_Window *)user_data;
244 double progress = *(double *)event_info;
246 title_set(window->window, ewk_view_title_get(window->webview), progress * 100);
250 on_error(void *user_data, Evas_Object *webview, void *event_info)
253 const Ewk_Error *error = (const Ewk_Error *)event_info;
255 /* This is a cancellation, do not display the error page */
256 if (ewk_error_cancellation_get(error))
259 buffer = eina_strbuf_new();
260 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>",
261 ewk_error_code_get(error), ewk_error_description_get(error), ewk_error_url_get(error));
263 ewk_view_html_string_load(webview, eina_strbuf_string_get(buffer), 0, ewk_error_url_get(error));
264 eina_strbuf_free(buffer);
268 on_download_request(void *user_data, Evas_Object *webview, void *event_info)
270 Ewk_Download_Job *download = (Ewk_Download_Job *)event_info;
272 // FIXME: The destination folder should be selected by the user but we set it to '/tmp' for now.
273 Eina_Strbuf *destination_path = eina_strbuf_new();
275 const char *suggested_name = ewk_download_job_suggested_filename_get(download);
276 if (suggested_name && *suggested_name)
277 eina_strbuf_append_printf(destination_path, "/tmp/%s", suggested_name);
279 // Generate a unique file name since no name was suggested.
280 char unique_path[] = "/tmp/downloaded-file.XXXXXX";
281 // change from org distribution
282 eina_strbuf_append(destination_path, mktemp(unique_path));
285 ewk_download_job_destination_set(download, eina_strbuf_string_get(destination_path));
286 info("Downloading: %s\n", eina_strbuf_string_get(destination_path));
287 eina_strbuf_free(destination_path);
291 on_download_finished(void *user_data, Evas_Object *webview, void *event_info)
293 Ewk_Download_Job *download = (Ewk_Download_Job *)event_info;
294 info("Download finished: %s\n", ewk_download_job_destination_get(download));
298 on_download_failed(void *user_data, Evas_Object *webview, void *event_info)
300 info("Download failed!\n");
304 quit(Eina_Bool success, const char *msg)
310 fputs(msg, (success) ? stdout : stderr);
319 on_url_bar_activated(void *user_data, Evas_Object *url_bar, void *event_info)
321 Browser_Window *app_data = (Browser_Window *)user_data;
323 const char *user_url = elm_entry_entry_get(url_bar);
324 char *url = url_from_user_input(user_url);
325 ewk_view_url_set(app_data->webview, url);
328 /* Give focus back to the view */
329 view_focus_set(app_data, EINA_TRUE);
333 on_url_bar_clicked(void *user_data, Evas_Object *url_bar, void *event_info)
335 Browser_Window *app_data = (Browser_Window *)user_data;
337 /* Grab focus from the view */
338 evas_object_focus_set(app_data->webview, EINA_FALSE);
339 elm_object_focus_set(url_bar, EINA_TRUE);
343 on_back_button_clicked(void *user_data, Evas_Object *back_button, void *event_info)
345 Browser_Window *app_data = (Browser_Window *)user_data;
347 ewk_view_back(app_data->webview);
348 /* Update back button state */
349 elm_object_disabled_set(back_button, !ewk_view_back_possible(app_data->webview));
353 on_forward_button_clicked(void *user_data, Evas_Object *forward_button, void *event_info)
355 Browser_Window *app_data = (Browser_Window *)user_data;
357 ewk_view_forward(app_data->webview);
358 /* Update forward button state */
359 elm_object_disabled_set(forward_button, !ewk_view_forward_possible(app_data->webview));
363 on_refresh_button_clicked(void *user_data, Evas_Object *refresh_button, void *event_info)
365 Browser_Window *app_data = (Browser_Window *)user_data;
367 Evas *evas = evas_object_evas_get(refresh_button);
368 Eina_Bool ctrlPressed = evas_key_modifier_is_set(evas_key_modifier_get(evas), "Control");
370 info("Reloading and bypassing cache...\n");
371 ewk_view_reload_bypass_cache(app_data->webview);
373 info("Reloading...\n");
374 ewk_view_reload(app_data->webview);
379 on_home_button_clicked(void *user_data, Evas_Object *home_button, void *event_info)
381 Browser_Window *app_data = (Browser_Window *)user_data;
383 ewk_view_url_set(app_data->webview, DEFAULT_URL);
387 on_window_deletion(void *user_data, Evas_Object *window, void *event_info)
389 window_close(browser_window_find(window));
393 create_toolbar_button(Evas_Object *window, const char *icon_name)
395 Evas_Object *button = elm_button_add(window);
397 Evas_Object *icon = elm_icon_add(window);
398 elm_icon_standard_set(icon, icon_name);
399 evas_object_size_hint_max_set(icon, TOOL_BAR_ICON_SIZE, TOOL_BAR_ICON_SIZE);
400 evas_object_color_set(icon, 44, 44, 102, 128);
401 evas_object_show(icon);
402 elm_object_part_content_set(button, "icon", icon);
403 evas_object_size_hint_min_set(button, TOOL_BAR_BUTTON_SIZE, TOOL_BAR_BUTTON_SIZE);
408 static Browser_Window *window_create(const char *url)
410 Browser_Window *app_data = malloc(sizeof(Browser_Window));
412 info("ERROR: could not create browser window.\n");
417 app_data->window = elm_win_add(NULL, "minibrowser-window", ELM_WIN_BASIC);
418 elm_win_title_set(app_data->window, APP_NAME);
419 evas_object_smart_callback_add(app_data->window, "delete,request", on_window_deletion, &app_data);
421 /* Create window background */
422 Evas_Object *bg = elm_bg_add(app_data->window);
423 elm_bg_color_set(bg, 193, 192, 191);
424 evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
425 elm_win_resize_object_add(app_data->window, bg);
426 evas_object_show(bg);
428 /* Create vertical layout */
429 Evas_Object *vertical_layout = elm_box_add(app_data->window);
430 elm_box_padding_set(vertical_layout, 0, 2);
431 evas_object_size_hint_weight_set(vertical_layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
432 elm_win_resize_object_add(app_data->window, vertical_layout);
433 evas_object_show(vertical_layout);
435 /* Create horizontal layout for top bar */
436 Evas_Object *horizontal_layout = elm_box_add(app_data->window);
437 elm_box_horizontal_set(horizontal_layout, EINA_TRUE);
438 evas_object_size_hint_weight_set(horizontal_layout, EVAS_HINT_EXPAND, 0.0);
439 evas_object_size_hint_align_set(horizontal_layout, EVAS_HINT_FILL, 0.0);
440 elm_box_pack_end(vertical_layout, horizontal_layout);
441 evas_object_show(horizontal_layout);
443 /* Create Back button */
444 app_data->back_button = create_toolbar_button(app_data->window, "arrow_left");
445 evas_object_smart_callback_add(app_data->back_button, "clicked", on_back_button_clicked, app_data);
446 elm_object_disabled_set(app_data->back_button, EINA_TRUE);
447 evas_object_size_hint_weight_set(app_data->back_button, 0.0, EVAS_HINT_EXPAND);
448 evas_object_size_hint_align_set(app_data->back_button, 0.0, 0.5);
449 elm_box_pack_end(horizontal_layout, app_data->back_button);
450 evas_object_show(app_data->back_button);
452 /* Create Forward button */
453 app_data->forward_button = create_toolbar_button(app_data->window, "arrow_right");
454 evas_object_smart_callback_add(app_data->forward_button, "clicked", on_forward_button_clicked, app_data);
455 elm_object_disabled_set(app_data->forward_button, EINA_TRUE);
456 evas_object_size_hint_weight_set(app_data->forward_button, 0.0, EVAS_HINT_EXPAND);
457 evas_object_size_hint_align_set(app_data->forward_button, 0.0, 0.5);
458 elm_box_pack_end(horizontal_layout, app_data->forward_button);
459 evas_object_show(app_data->forward_button);
462 app_data->url_bar = elm_entry_add(app_data->window);
463 elm_entry_scrollable_set(app_data->url_bar, EINA_TRUE);
464 elm_entry_single_line_set(app_data->url_bar, EINA_TRUE);
465 elm_entry_cnp_mode_set(app_data->url_bar, ELM_CNP_MODE_PLAINTEXT);
466 elm_entry_text_style_user_push(app_data->url_bar, "DEFAULT='font_size=18'");
467 evas_object_smart_callback_add(app_data->url_bar, "activated", on_url_bar_activated, app_data);
468 evas_object_smart_callback_add(app_data->url_bar, "clicked", on_url_bar_clicked, app_data);
469 evas_object_size_hint_weight_set(app_data->url_bar, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
470 evas_object_size_hint_align_set(app_data->url_bar, EVAS_HINT_FILL, EVAS_HINT_FILL);
471 elm_box_pack_end(horizontal_layout, app_data->url_bar);
472 evas_object_show(app_data->url_bar);
474 /* Create Refresh button */
475 Evas_Object *refresh_button = create_toolbar_button(app_data->window, "refresh");
476 evas_object_smart_callback_add(refresh_button, "clicked", on_refresh_button_clicked, app_data);
477 evas_object_size_hint_weight_set(refresh_button, 0.0, EVAS_HINT_EXPAND);
478 evas_object_size_hint_align_set(refresh_button, 1.0, 0.5);
479 elm_box_pack_end(horizontal_layout, refresh_button);
480 evas_object_show(refresh_button);
482 /* Create Home button */
483 Evas_Object *home_button = create_toolbar_button(app_data->window, "home");
484 evas_object_smart_callback_add(home_button, "clicked", on_home_button_clicked, app_data);
485 evas_object_size_hint_weight_set(home_button, 0.0, EVAS_HINT_EXPAND);
486 evas_object_size_hint_align_set(home_button, 1.0, 0.5);
487 elm_box_pack_end(horizontal_layout, home_button);
488 evas_object_show(home_button);
491 Evas *evas = evas_object_evas_get(app_data->window);
492 app_data->webview = ewk_view_add(evas);
493 ewk_view_theme_set(app_data->webview, THEME_DIR "/default.edj");
495 /* set a file containing certificates for recognized SSL Certificate Authorities */
496 ewk_context_certificate_file_set(ewk_context_default_get(), "/var/lib/ca-certificates/ca-bundle.pem");
498 // Ewk_Settings *settings = ewk_view_settings_get(app_data->webview);
499 // ewk_settings_file_access_from_file_urls_allowed_set(settings, EINA_TRUE);
500 // ewk_settings_enable_frame_flattening_set(settings, frame_flattening_enabled);
501 elm_win_fullscreen_set(app_data->window, fullscreen_enabled);
503 evas_object_smart_callback_add(app_data->webview, "close,window", on_close_window, app_data);
504 evas_object_smart_callback_add(app_data->webview, "create,window", on_new_window, app_data);
505 evas_object_smart_callback_add(app_data->webview, "download,failed", on_download_failed, app_data);
506 evas_object_smart_callback_add(app_data->webview, "download,finished", on_download_finished, app_data);
507 evas_object_smart_callback_add(app_data->webview, "download,request", on_download_request, app_data);
508 evas_object_smart_callback_add(app_data->webview, "load,error", on_error, app_data);
509 evas_object_smart_callback_add(app_data->webview, "load,progress", on_progress, app_data);
510 evas_object_smart_callback_add(app_data->webview, "title,changed", on_title_changed, app_data);
511 evas_object_smart_callback_add(app_data->webview, "url,changed", on_url_changed, app_data);
512 evas_object_smart_callback_add(app_data->webview, "back,forward,list,changed", on_back_forward_list_changed, app_data);
514 evas_object_event_callback_add(app_data->webview, EVAS_CALLBACK_KEY_DOWN, on_key_down, app_data);
515 evas_object_event_callback_add(app_data->webview, EVAS_CALLBACK_MOUSE_DOWN, on_mouse_down, app_data);
517 evas_object_size_hint_weight_set(app_data->webview, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
518 evas_object_size_hint_align_set(app_data->webview, EVAS_HINT_FILL, EVAS_HINT_FILL);
519 elm_box_pack_end(vertical_layout, app_data->webview);
520 evas_object_show(app_data->webview);
523 ewk_view_url_set(app_data->webview, url);
525 evas_object_resize(app_data->window, DEFAULT_WIDTH, DEFAULT_HEIGHT);
526 elm_win_center(app_data->window, EINA_TRUE, EINA_TRUE);
527 evas_object_show(app_data->window);
529 view_focus_set(app_data, EINA_TRUE);
535 elm_main(int argc, char *argv[])
538 unsigned char quitOption = 0;
539 Browser_Window *window;
541 Ecore_Getopt_Value values[] = {
542 ECORE_GETOPT_VALUE_STR(evas_engine_name),
543 ECORE_GETOPT_VALUE_BOOL(quitOption),
544 ECORE_GETOPT_VALUE_BOOL(frame_flattening_enabled),
545 ECORE_GETOPT_VALUE_BOOL(fullscreen_enabled),
546 ECORE_GETOPT_VALUE_BOOL(quitOption),
547 ECORE_GETOPT_VALUE_BOOL(quitOption),
548 ECORE_GETOPT_VALUE_BOOL(quitOption),
549 ECORE_GETOPT_VALUE_NONE
555 ecore_app_args_set(argc, (const char **) argv);
556 args = ecore_getopt_parse(&options, values, argc, argv);
559 return quit(EINA_FALSE, "ERROR: could not parse options.\n");
562 return quit(EINA_TRUE, NULL);
565 char *url = url_from_user_input(argv[args]);
566 window = window_create(url);
569 window = window_create(DEFAULT_URL);
572 return quit(EINA_FALSE, "ERROR: could not create browser window.\n");
574 windows = eina_list_append(windows, window);
578 return quit(EINA_TRUE, NULL);