From 8511b524fe027af47b19412925ef6e97426750d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Briano?= Date: Thu, 13 Oct 2011 04:45:18 +0000 Subject: [PATCH] simple example for elm_web. also simple external for it. need to figure how to properly forward signals to get some nice back/forward action though SVN revision: 64032 --- legacy/elementary/doc/examples.dox | 126 ++++ .../elementary/src/edje_externals/Makefile.am | 3 +- .../elementary/src/edje_externals/elm_web.c | 208 ++++++ .../elementary/src/edje_externals/modules.inc | 1 + legacy/elementary/src/examples/Makefile.am | 2 + legacy/elementary/src/examples/web_example.c | 619 ++++++++++++++++++ 6 files changed, 958 insertions(+), 1 deletion(-) create mode 100644 legacy/elementary/src/edje_externals/elm_web.c create mode 100644 legacy/elementary/src/examples/web_example.c diff --git a/legacy/elementary/doc/examples.dox b/legacy/elementary/doc/examples.dox index b6d7783c46..2e92f13882 100644 --- a/legacy/elementary/doc/examples.dox +++ b/legacy/elementary/doc/examples.dox @@ -5939,6 +5939,132 @@ * @example win_example.c */ +/** + * @page web_example_01 Web - Simple example + * + * WebKit-EFL is independent of any particular toolkit, such as Elementary, + * so using it on applications requires that the programmer writes a lot of + * boiler plate code to manage to manage the web object. + * + * For a full featured browser this may make sense, as the programmer will + * want to have full control of every aspect of the web object, since it's the + * main component of the application. But other programs with simpler + * requirements, having to write so much code is undesired. + * + * This is where elm_web comes in. Its purpose is to provide a simple way + * for developers to embed a simple web object in their programs, simplifying + * the common use cases. + * + * This is not to say that a browser can't be made out of it, as this example + * shows. + * + * We'll be making a simple browser, consisting of one window with an URL bar, + * a toolbar to be used for the tabs and a pager to show one page at a time. + * + * When all tabs are closed, we'll be showing a default view with some custom + * content, for which we need to get the internal @c ewk_view object and use + * some WebKit functions on it, thus we need to include the necessary headers + * first. + * + * @dontinclude web_example.c + * @skip include + * @until EWebKit + * + * A struct to keep track of the different widgets in use and the currently + * shown tab. There's also an @c exiting flag, used to work around the overly + * simplistic way in which this example is written, just to avoid some + * warnings when closing the program. + * + * @skip typedef + * @skip typedef + * @until App_Data + * + * Each tab has its own struct too, but there's not much to it. + * @until }; + * + * Whenever the currently selected tab changes, we need to update some state + * on the application. The back and forward buttons need to be disabled + * accordingly and the URL bar needs to show the right address. + * + * @skip static void + * @until pager_content_promote + * @until } + * + * Other updates happen based on events from the web object, like title change + * to update the name shown in the tab, and URL change which will update the + * URL bar if the event came from the currently selected tab. + * + * @skip tab_current_set + * @skip static void + * @until } + * @until } + * + * Adding a new tab is just a matter of creating a new web widget, its data + * and pushing it into the pager. A lot of the things that we should handle + * here, such as how to react to popups and JavaScript dialogs, are done + * already in the @c elm_web widget, so we can rely on their default + * implementations. For the JavaScript dialogs we are going to avoid having + * them open in a new window by setting the @c Inwin mode. + * + * There is no default implementation, however, for the requests to create a + * new window, so we have to handle them by setting a callback function that + * will ultimately call this very same function to add a new tab. + * + * @skip Tab_Data + * @until } + * + * Entering an address in the URL bar will check if a tab exists, and if not, + * create one and set the URL for it. The address needs to conform to the URI + * format, so we check that it does and add the protocol if it's missing. + * + * @skip static char + * @until eina_stringshare_del + * @until } + * + * The navigation buttons are simple enough. As for the refresh, it normally + * reloads the page using anything that may exist in the caches if applicable, + * but we can press it while holding the @c Shift key to avoid the cache. + * + * @skip static void + * @until web_forward + * @until } + * + * The callback set for the new window request creates a new tab and returns + * the web widget associated with it. This is important, this function must + * return a valid web widget returned by elm_web_add(). + * + * @skip static Evas_Object + * @until } + * + * Pressing @c Ctrl-F will bring up the search box. Nothing about the box + * itself is worth mentioning here, but it works as you would expect from any + * other browser. While typing on it, it will highlight all occurrences of the + * searched word. Pressing @c Enter will go to the next instance and the two + * buttons next to the entry will move forward and backwards through the found + * keywords. + * + * @skip win_del_request + * @skip static void + * @until win_search_trigger + * @until } + * + * Last, create the main window and put all of the things used above in it. It + * contains a default web widget that will be shown when no tabs exist. This + * web object is not browsable per se, so history is disabled in it, and we + * set the same callback to create new windows, on top of setting some custom + * content of our own on it, with some links that will open new tabs to start + * browsing quickly. + * + * @skip static void + * @until ELM_MAIN + * + * Some parts of the code were left out, as they are not relevant to the + * example, but the full listing can be found at @ref web_example.c + * "web_example.c". + * + * @example web_example.c + */ + /** * @page efl_thread_1 EFL Threading example 1 * diff --git a/legacy/elementary/src/edje_externals/Makefile.am b/legacy/elementary/src/edje_externals/Makefile.am index 18991f3a85..3bacdca331 100644 --- a/legacy/elementary/src/edje_externals/Makefile.am +++ b/legacy/elementary/src/edje_externals/Makefile.am @@ -61,7 +61,8 @@ elm_slideshow.c \ elm_spinner.c \ elm_thumb.c \ elm_toggle.c \ -elm_toolbar.c +elm_toolbar.c \ +elm_web.c module_la_LIBADD = $(top_builddir)/src/lib/libelementary.la module_la_LDFLAGS = -no-undefined -module -avoid-version -shared -fPIC diff --git a/legacy/elementary/src/edje_externals/elm_web.c b/legacy/elementary/src/edje_externals/elm_web.c new file mode 100644 index 0000000000..64fd37386a --- /dev/null +++ b/legacy/elementary/src/edje_externals/elm_web.c @@ -0,0 +1,208 @@ +#include "private.h" + +typedef struct _Elm_Params_Web +{ + Elm_Params base; + const char *uri; + double zoom; + Elm_Web_Zoom_Mode zoom_mode; + Eina_Bool inwin_mode; + Eina_Bool zoom_set:1; + Eina_Bool inwin_mode_set:1; +} Elm_Params_Web; + +static const char *zoom_choices[] = {"manual", "auto fit", "auto fill", NULL}; + +static Elm_Web_Zoom_Mode +_zoom_mode_get(const char *zoom) +{ + unsigned int i; + + for (i = 0; i < ELM_WEB_ZOOM_MODE_LAST; i++) + if (!strcmp(zoom, zoom_choices[i])) return i; + + return ELM_WEB_ZOOM_MODE_LAST; +} + +static void +external_web_state_set(void *data __UNUSED__, Evas_Object *obj, const void *from_params, const void *to_params, float pos __UNUSED__) +{ + const Elm_Params_Web *p; + + if (to_params) p = to_params; + else if (from_params) p = from_params; + else return; + + if (p->uri) + elm_web_uri_set(obj, p->uri); + if (p->zoom_mode < ELM_WEB_ZOOM_MODE_LAST) + elm_web_zoom_mode_set(obj, p->zoom_mode); + if (p->zoom_set) + elm_web_zoom_set(obj, p->zoom); + if (p->inwin_mode_set) + elm_web_inwin_mode_set(obj, p->inwin_mode); +} + +static Eina_Bool +external_web_param_set(void *data __UNUSED__, Evas_Object *obj, const Edje_External_Param *param) +{ + if (!strcmp(param->name, "uri")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_STRING) + { + elm_web_uri_set(obj, param->s); + return EINA_TRUE; + } + } + else if (!strcmp(param->name, "zoom level")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_DOUBLE) + { + elm_web_zoom_set(obj, param->d); + return EINA_TRUE; + } + } + else if (!strcmp(param->name, "zoom mode")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_CHOICE) + { + Elm_Web_Zoom_Mode mode = _zoom_mode_get(param->s); + if (mode == ELM_WEB_ZOOM_MODE_LAST) + return EINA_FALSE; + elm_web_zoom_mode_set(obj, mode); + return EINA_TRUE; + } + } + else if (!strcmp(param->name, "inwin mode")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_BOOL) + { + elm_web_inwin_mode_set(obj, !!param->i); + return EINA_TRUE; + } + } + + ERR("unknown parameter '%s' of type '%s'", + param->name, edje_external_param_type_str(param->type)); + + return EINA_FALSE; +} + +static Eina_Bool +external_web_param_get(void *data __UNUSED__, const Evas_Object *obj, Edje_External_Param *param) +{ + if (!strcmp(param->name, "uri")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_STRING) + { + param->s = elm_web_uri_get(obj); + return EINA_TRUE; + } + } + else if (!strcmp(param->name, "zoom level")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_DOUBLE) + { + param->d = elm_web_zoom_get(obj); + return EINA_TRUE; + } + } + else if (!strcmp(param->name, "zoom mode")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_CHOICE) + { + Elm_Web_Zoom_Mode mode = elm_web_zoom_mode_get(obj); + if (mode == ELM_WEB_ZOOM_MODE_LAST) + return EINA_FALSE; + param->s = zoom_choices[mode]; + return EINA_TRUE; + } + } + else if (!strcmp(param->name, "inwin mode")) + { + if (param->type == EDJE_EXTERNAL_PARAM_TYPE_BOOL) + { + param->i = elm_web_inwin_mode_get(obj); + return EINA_TRUE; + } + } + + ERR("unknown parameter '%s' of type '%s'", + param->name, edje_external_param_type_str(param->type)); + + return EINA_FALSE; +} + +static void * +external_web_params_parse(void *data __UNUSED__, Evas_Object *obj __UNUSED__, const Eina_List *params) +{ + Elm_Params_Web *mem; + Edje_External_Param *param; + const Eina_List *l; + + mem = calloc(1, sizeof(Elm_Params_Web)); + if (!mem) return NULL; + + mem->zoom_mode = ELM_WEB_ZOOM_MODE_LAST; + + EINA_LIST_FOREACH(params, l, param) + { + if (!strcmp(param->name, "zoom level")) + { + mem->zoom = param->d; + mem->zoom_set = EINA_TRUE; + } + else if (!strcmp(param->name, "zoom mode")) + mem->zoom_mode = _zoom_mode_get(param->s); + else if (!strcmp(param->name, "uri")) + mem->uri = eina_stringshare_add(param->s); + else if (!strcmp(param->name, "inwin mode")) + { + mem->inwin_mode = !!param->i; + mem->inwin_mode_set = EINA_TRUE; + } + } + + return mem; +} + +static void +external_web_params_free(void *params) +{ + Elm_Params_Web *mem = params; + + if (mem->uri) + eina_stringshare_del(mem->uri); + free(mem); +} + +static Evas_Object * +external_web_content_get(void *data __UNUSED__, const Evas_Object *obj __UNUSED__, const char *content __UNUSED__) +{ + return NULL; +} + +static Edje_External_Param_Info external_web_params[] = +{ + EDJE_EXTERNAL_PARAM_INFO_STRING("uri"), + EDJE_EXTERNAL_PARAM_INFO_DOUBLE_DEFAULT("zoom level", 1.0), + EDJE_EXTERNAL_PARAM_INFO_CHOICE_FULL("zoom mode", "manual", zoom_choices), + EDJE_EXTERNAL_PARAM_INFO_BOOL_DEFAULT("inwin mode", EINA_FALSE), + EDJE_EXTERNAL_PARAM_INFO_SENTINEL +}; + +static Evas_Object * +external_web_add(void *data __UNUSED__, Evas *evas __UNUSED__, Evas_Object *edje, const Eina_List *params __UNUSED__, const char *part_name) +{ + Evas_Object *parent, *obj; + external_elm_init(); + parent = elm_widget_parent_widget_get(edje); + if (!parent) parent = edje; + elm_need_web(); /* extra command needed */ + obj = elm_web_add(parent); + external_signals_proxy(obj, edje, part_name); + return obj; +} + +DEFINE_EXTERNAL_ICON_ADD(web, "web") +DEFINE_EXTERNAL_TYPE(web, "Web") diff --git a/legacy/elementary/src/edje_externals/modules.inc b/legacy/elementary/src/edje_externals/modules.inc index 753f0af746..0499345484 100644 --- a/legacy/elementary/src/edje_externals/modules.inc +++ b/legacy/elementary/src/edje_externals/modules.inc @@ -29,3 +29,4 @@ DEFINE_TYPE(icon) DEFINE_TYPE(scroller) DEFINE_TYPE(segment_control) DEFINE_TYPE(index) +DEFINE_TYPE(web) diff --git a/legacy/elementary/src/examples/Makefile.am b/legacy/elementary/src/examples/Makefile.am index e1ae01d04b..533f035b6b 100644 --- a/legacy/elementary/src/examples/Makefile.am +++ b/legacy/elementary/src/examples/Makefile.am @@ -115,6 +115,7 @@ SRCS = \ table_example_02.c \ menu_example_01.c \ thumb_example_01.c \ + web_example.c \ win_example.c \ efl_thread_1.c \ efl_thread_2.c \ @@ -223,6 +224,7 @@ pkglib_PROGRAMS += \ table_example_02 \ menu_example_01 \ thumb_example_01 \ + web_example \ win_example \ efl_thread_1 \ efl_thread_2 \ diff --git a/legacy/elementary/src/examples/web_example.c b/legacy/elementary/src/examples/web_example.c new file mode 100644 index 0000000000..f2b72f2ed5 --- /dev/null +++ b/legacy/elementary/src/examples/web_example.c @@ -0,0 +1,619 @@ +/* + * gcc -o web_example web_example.c `pkg-config --cflags --libs elementary ewebkit` -D_GNU_SOURCE + */ +#include +#include +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#else +# define __UNUSED__ __attribute__((unused)) +#endif + +typedef struct _Tab_Data Tab_Data; + +typedef struct +{ + Evas_Object *win; + Evas_Object *main_box; + Evas_Object *pager; + Evas_Object *url; + Evas_Object *default_web; + Evas_Object *tabs; + Evas_Object *close_tab; + Evas_Object *search_box; + Evas_Object *search_entry; + + struct { + Evas_Object *back; + Evas_Object *fwd; + Evas_Object *refresh; + } nav; + + Tab_Data *current_tab; + + Eina_Bool exiting : 1; +} App_Data; + +struct _Tab_Data +{ + Evas_Object *web; + App_Data *app; + Elm_Toolbar_Item *tab; +}; + +static Evas_Object * _web_create_window_cb(void *data, Evas_Object *obj, Eina_Bool js, const Elm_Web_Window_Features *wf); + +static void +nav_button_update(App_Data *ad) +{ + Eina_Bool back, fwd; + + back = !elm_web_back_possible(ad->current_tab->web); + fwd = !elm_web_forward_possible(ad->current_tab->web); + + elm_object_disabled_set(ad->nav.back, back); + elm_object_disabled_set(ad->nav.fwd, fwd); +} + +static void +tab_current_set(Tab_Data *td) +{ + const char *uri; + + if (td == td->app->current_tab) + return; + + td->app->current_tab = td; + + uri = elm_web_uri_get(td->web); + elm_object_text_set(td->app->url, uri); + + nav_button_update(td->app); + elm_entry_icon_visible_set(td->app->url, EINA_TRUE); + + elm_pager_content_promote(td->app->pager, td->web); +} + +static void +_tab_clicked_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info) +{ + Tab_Data *td = data; + /* the first toolbar_item_append() calls the select callback before the item + * is assigned, so we need a workaround for that. */ + if (!td->tab) + td->tab = event_info; + tab_current_set(td); +} + +static void +_title_changed_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info) +{ + Tab_Data *td = data; + const char *title = event_info; + char buf[20] = ""; + + if (title) + strncpy(buf, title, sizeof(buf) - 1); + elm_toolbar_item_label_set(td->tab, buf); +} + +static void +_uri_changed_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info) +{ + Tab_Data *td = data; + const char *uri = event_info; + + if (td != td->app->current_tab) + return; + + nav_button_update(td->app); + elm_object_text_set(td->app->url, uri); +} + +static void +_web_free_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Tab_Data *td = data; + + if (td->tab) + elm_toolbar_item_del(td->tab); + + free(td); +} + +static void +_tb_item_del_cb(void *data, Evas_Object *obj, void *event_info __UNUSED__) +{ + Tab_Data *td = data; + if (!td->app->exiting && !elm_toolbar_selected_item_get(obj)) + { + td->app->current_tab = NULL; + elm_entry_icon_visible_set(td->app->url, EINA_FALSE); + if (td->app->search_box) + evas_object_del(td->app->search_box); + } + td->tab = NULL; +} + +Tab_Data * +tab_add(App_Data *ad) +{ + Tab_Data *td; + + td = calloc(1, sizeof(Tab_Data)); + if (!td) return NULL; + + td->web = elm_web_add(ad->win); + elm_web_window_create_hook_set(td->web, _web_create_window_cb, ad); + elm_web_inwin_mode_set(td->web, EINA_TRUE); + evas_object_size_hint_weight_set(td->web, EVAS_HINT_EXPAND, + EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(td->web, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_pager_content_push(ad->pager, td->web); + + td->app = ad; + td->tab = elm_toolbar_item_append(td->app->tabs, NULL, "New tab", + _tab_clicked_cb, td); + elm_toolbar_item_del_cb_set(td->tab, _tb_item_del_cb); + + evas_object_data_set(td->web, "tab_data", td); + + evas_object_smart_callback_add(td->web, "title,changed", _title_changed_cb, + td); + evas_object_smart_callback_add(td->web, "uri,changed", _uri_changed_cb, td); + evas_object_event_callback_add(td->web, EVAS_CALLBACK_FREE, _web_free_cb, + td); + + elm_toolbar_item_selected_set(td->tab, EINA_TRUE); + return td; +} + +static char * +uri_sanitize(const char *uri) +{ + char *fixed_uri; + char *schema; + char *tmp; + + if (!uri || !*uri) return NULL; + + tmp = strstr(uri, "://"); + if (!tmp || (tmp == uri) || (tmp > (uri + 15))) + { + char *new_uri = NULL; + if (ecore_file_exists(uri)) + { + schema = "file"; + new_uri = ecore_file_realpath(uri); + } + else + schema = "http"; + + if (asprintf(&fixed_uri, "%s://%s", schema, new_uri ? new_uri : uri) > + 0) + { + free(new_uri); + return fixed_uri; + } + free(new_uri); + } + else + return strdup(uri); + + return NULL; +} + +static void +tab_uri_set(Tab_Data *td, const char *uri) +{ + char *sane_uri = uri_sanitize(uri); + elm_web_uri_set(td->web, sane_uri); + free(sane_uri); +} + +static void +_url_activated_cb(void *data, Evas_Object *obj, void *event_info __UNUSED__) +{ + App_Data *ad = data; + Tab_Data *td; + const char *uri = eina_stringshare_ref(elm_object_text_get(obj)); + + if (!ad->current_tab) + td = tab_add(ad); + else + td = ad->current_tab; + tab_uri_set(td, uri); + eina_stringshare_del(uri); +} + +static void +_nav_back_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + App_Data *ad = data; + + elm_web_back(ad->current_tab->web); +} + +static void +_nav_refresh_cb(void *data, Evas_Object *obj, void *event_info __UNUSED__) +{ + App_Data *ad = data; + const Evas_Modifier *mods = evas_key_modifier_get(evas_object_evas_get(obj)); + + if (evas_key_modifier_is_set(mods, "Shift")) + elm_web_reload_full(ad->current_tab->web); + else + elm_web_reload(ad->current_tab->web); +} + +static void +_nav_fwd_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + App_Data *ad = data; + + elm_web_forward(ad->current_tab->web); +} + +static void +_close_tab_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + App_Data *ad = data; + + if (!ad->current_tab) + return; + evas_object_del(ad->current_tab->web); +} + +static void +_add_tab_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + App_Data *ad = data; + tab_add(ad); + elm_object_focus_set(ad->url, EINA_TRUE); +} + +static Evas_Object * +_web_create_window_cb(void *data, Evas_Object *obj __UNUSED__, Eina_Bool js __UNUSED__, const Elm_Web_Window_Features *wf __UNUSED__) +{ + App_Data *ad = data; + Tab_Data *td; + + td = tab_add(ad); + return td->web; +} + +static void +_win_del_request_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + App_Data *ad = data; + ad->exiting = EINA_TRUE; +} + +static void +_win_free_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + free(data); +} + +static void +_search_entry_changed_cb(void *data, Evas_Object *obj, void *event_info __UNUSED__) +{ + App_Data *ad = data; + const char *text; + + text = elm_object_text_get(obj); + elm_web_text_search(ad->current_tab->web, text, EINA_FALSE, EINA_TRUE, + EINA_TRUE); + elm_web_text_matches_unmark_all(ad->current_tab->web); + elm_web_text_matches_mark(ad->current_tab->web, text, EINA_FALSE, EINA_TRUE, + 0); +} + +static void +_search_entry_activate_cb(void *data, Evas_Object *obj, void *event_info __UNUSED__) +{ + App_Data *ad = data; + const char *text; + + text = elm_object_text_get(obj); + elm_web_text_search(ad->current_tab->web, text, EINA_FALSE, EINA_TRUE, + EINA_TRUE); +} + +static void +_search_next_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + App_Data *ad = data; + const char *text; + + text = elm_object_text_get(ad->search_entry); + elm_web_text_search(ad->current_tab->web, text, EINA_FALSE, EINA_TRUE, + EINA_TRUE); +} + +static void +_search_prev_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + App_Data *ad = data; + const char *text; + + text = elm_object_text_get(ad->search_entry); + elm_web_text_search(ad->current_tab->web, text, EINA_FALSE, EINA_FALSE, + EINA_TRUE); +} + +static void +_search_close_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + App_Data *ad = data; + evas_object_del(ad->search_box); +} + +static void +_search_box_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + App_Data *ad = data; + ad->search_box = NULL; + ad->search_entry = NULL; +} + +static void +_win_search_trigger_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Evas_Event_Key_Down *ev = event_info; + App_Data *ad = data; + Evas_Object *box, *box2, *entry, *btn, *ic; + + if (strcmp(ev->keyname, "f") || + !evas_key_modifier_is_set(ev->modifiers, "Control")) + return; + if (ad->search_box || !ad->current_tab) + return; + + box = elm_box_add(ad->win); + elm_box_horizontal_set(box, EINA_TRUE); + evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(box, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_pack_after(ad->main_box, box, ad->url); + evas_object_show(box); + + evas_object_event_callback_add(box, EVAS_CALLBACK_DEL, _search_box_del_cb, + ad); + + entry = elm_entry_add(ad->win); + elm_entry_single_line_set(entry, EINA_TRUE); + elm_entry_scrollable_set(entry, EINA_TRUE); + evas_object_size_hint_weight_set(entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(entry, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_pack_end(box, entry); + evas_object_show(entry); + + evas_object_smart_callback_add(entry, "changed", _search_entry_changed_cb, + ad); + evas_object_smart_callback_add(entry, "activated", _search_entry_activate_cb, + ad); + + box2 = elm_box_add(ad->win); + elm_box_horizontal_set(box2, EINA_TRUE); + elm_entry_end_set(entry, box2); + + btn = elm_button_add(ad->win); + elm_box_pack_end(box2, btn); + evas_object_show(btn); + + ic = elm_icon_add(ad->win); + elm_icon_standard_set(ic, "arrow_up"); + elm_button_icon_set(btn, ic); + + evas_object_smart_callback_add(btn, "clicked", _search_prev_cb, ad); + + btn = elm_button_add(ad->win); + elm_box_pack_end(box2, btn); + evas_object_show(btn); + + ic = elm_icon_add(ad->win); + elm_icon_standard_set(ic, "arrow_down"); + elm_button_icon_set(btn, ic); + + evas_object_smart_callback_add(btn, "clicked", _search_next_cb, ad); + + btn = elm_button_add(ad->win); + elm_box_pack_end(box, btn); + evas_object_show(btn); + + ic = elm_icon_add(ad->win); + elm_icon_standard_set(ic, "close"); + elm_button_icon_set(btn, ic); + + evas_object_smart_callback_add(btn, "clicked", _search_close_cb, ad); + + ad->search_box = box; + ad->search_entry = entry; + + elm_object_focus_set(entry, EINA_TRUE); +} + +static void +default_content_set(Evas_Object *web) +{ + Evas_Object *view, *frame; + const char contents[] = "" + "\n" + " \n" + " Nothing to see here, move along\n" + " \n" + " \n" + " E\n" + "
\n" + " Google\n" + "
\n" + " \n" + "\n"; + + view = elm_web_webkit_view_get(web); + frame = ewk_view_frame_main_get(view); + ewk_frame_contents_set(frame, contents, sizeof(contents) - 1, "text/html", + "UTF-8", NULL); +} + +int +elm_main(int argc __UNUSED__, char *argv[] __UNUSED__) +{ + Evas_Object *win, *bg, *box, *box2, *btn, *ic, *url, *pager, *tabs, *web; + Evas *e; + Evas_Modifier_Mask ctrl_mask; + App_Data *ad; + + if (!elm_need_web()) + return -1; + + ad = calloc(1, sizeof(App_Data)); + if (!ad) return -1; + + elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); + + win = elm_win_add(NULL, "example-web", ELM_WIN_BASIC); + elm_win_autodel_set(win, EINA_TRUE); + + e = evas_object_evas_get(win); + ctrl_mask = evas_key_modifier_mask_get(e, "Control"); + if (!evas_object_key_grab(win, "f", ctrl_mask, 0, EINA_TRUE)) + fprintf(stderr, "Could not grab trigger for search dialog\n"); + + evas_object_smart_callback_add(win, "delete,request", _win_del_request_cb, + ad); + evas_object_event_callback_add(win, EVAS_CALLBACK_KEY_DOWN, + _win_search_trigger_cb, ad); + evas_object_event_callback_add(win, EVAS_CALLBACK_FREE, _win_free_cb, ad); + + bg = elm_bg_add(win); + evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, bg); + evas_object_show(bg); + + box = elm_box_add(win); + evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, box); + evas_object_show(box); + + url = elm_entry_add(win); + elm_entry_single_line_set(url, EINA_TRUE); + elm_entry_scrollable_set(url, EINA_TRUE); + evas_object_size_hint_weight_set(url, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(url, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_pack_end(box, url); + evas_object_show(url); + + evas_object_smart_callback_add(url, "activated", _url_activated_cb, ad); + + box2 = elm_box_add(win); + elm_box_horizontal_set(box2, EINA_TRUE); + elm_entry_icon_set(url, box2); + elm_entry_icon_visible_set(url, EINA_FALSE); + + btn = elm_button_add(win); + elm_box_pack_end(box2, btn); + evas_object_show(btn); + + ad->nav.back = btn; + + ic = elm_icon_add(win); + elm_icon_standard_set(ic, "arrow_left"); + elm_button_icon_set(btn, ic); + + evas_object_smart_callback_add(btn, "clicked", _nav_back_cb, ad); + + btn = elm_button_add(win); + elm_box_pack_end(box2, btn); + evas_object_show(btn); + + ad->nav.refresh = btn; + + ic = elm_icon_add(win); + elm_icon_standard_set(ic, "refresh"); + elm_button_icon_set(btn, ic); + + evas_object_smart_callback_add(btn, "clicked", _nav_refresh_cb, ad); + + btn = elm_button_add(win); + elm_box_pack_end(box2, btn); + evas_object_show(btn); + + ad->nav.fwd = btn; + + ic = elm_icon_add(win); + elm_icon_standard_set(ic, "arrow_right"); + elm_button_icon_set(btn, ic); + + evas_object_smart_callback_add(btn, "clicked", _nav_fwd_cb, ad); + + box2 = elm_box_add(win); + elm_box_horizontal_set(box2, EINA_TRUE); + evas_object_size_hint_weight_set(box2, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(box2, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_pack_end(box, box2); + evas_object_show(box2); + + btn = elm_button_add(win); + elm_box_pack_end(box2, btn); + evas_object_show(btn); + + ic = elm_icon_add(win); + elm_icon_standard_set(ic, "file"); + elm_button_icon_set(btn, ic); + + evas_object_smart_callback_add(btn, "clicked", _add_tab_cb, ad); + + tabs = elm_toolbar_add(win); + elm_toolbar_align_set(tabs, 0.0); + elm_toolbar_always_select_mode_set(tabs, EINA_TRUE); + elm_toolbar_homogeneous_set(tabs, EINA_FALSE); + elm_toolbar_mode_shrink_set(tabs, ELM_TOOLBAR_SHRINK_MENU); + evas_object_size_hint_weight_set(tabs, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(tabs, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_pack_end(box2, tabs); + evas_object_show(tabs); + + btn = elm_button_add(win); + elm_box_pack_end(box2, btn); + evas_object_show(btn); + + evas_object_smart_callback_add(btn, "clicked", _close_tab_cb, ad); + + ic = elm_icon_add(win); + elm_icon_standard_set(ic, "close"); + elm_button_icon_set(btn, ic); + + pager = elm_pager_add(win); + evas_object_size_hint_weight_set(pager, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(pager, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_pack_end(box, pager); + evas_object_show(pager); + + elm_toolbar_menu_parent_set(tabs, pager); + + web = elm_web_add(win); + elm_web_window_create_hook_set(web, _web_create_window_cb, ad); + elm_web_history_enable_set(web, EINA_FALSE); + evas_object_size_hint_weight_set(web, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(web, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_pager_content_push(pager, web); + + default_content_set(web); + + ad->win = win; + ad->main_box = box; + ad->pager = pager; + ad->url = url; + ad->default_web = web; + ad->tabs = tabs; + ad->close_tab = btn; + + evas_object_resize(win, 480, 640); + evas_object_show(win); + + elm_run(); + + return 0; +} +ELM_MAIN();