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 ewk_view
object and use some WebKit functions on it, thus we need to include the necessary headers first.
#include <Elementary.h>
#ifdef HAVE_ELEMENTARY_WEB
#include <EWebKit.h>
A struct to keep track of the different widgets in use and the currently shown tab. There's also an 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.
typedef struct _Tab_Data Tab_Data;
typedef struct
{
struct {
} nav;
Tab_Data *current_tab;
} App_Data;
unsigned char Eina_Bool
Type to mimic a boolean.
Definition: eina_types.h:527
Efl_Canvas_Object Evas_Object
An Evas Object handle.
Definition: Evas_Common.h:185
Each tab has its own struct too, but there's not much to it.
struct _Tab_Data
{
App_Data *app;
};
Eo Elm_Object_Item
An Elementary Object item handle.
Definition: elm_object_item.h:6
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.
static void
nav_button_update(App_Data *ad)
{
back = !elm_web_back_possible_get(ad->current_tab->web);
fwd = !elm_web_forward_possible_get(ad->current_tab->web);
}
static void
tab_current_set(Tab_Data *td)
{
const char *url;
if (td == td->app->current_tab)
return;
td->app->current_tab = td;
url = elm_web_url_get(td->web);
elm_object_text_set(td->app->url_entry, url);
nav_button_update(td->app);
#define EINA_TRUE
boolean value TRUE (numerical value 1)
Definition: eina_types.h:539
void elm_entry_icon_visible_set(Elm_Entry *obj, Eina_Bool setting)
Sets the visibility of the left-side widget of the entry, set by elm_object_part_content_set.
Definition: elm_entry_eo.legacy.c:267
void elm_object_disabled_set(Evas_Object *obj, Eina_Bool disabled)
Set the disabled state of an Elementary object.
Definition: elm_main.c:1613
void elm_naviframe_item_simple_promote(Elm_Naviframe *obj, Efl_Canvas_Object *content)
Simple version of item_promote.
Definition: elm_naviframe_eo.legacy.c:75
}
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.
static void
{
Tab_Data *td = data;
const char *title = event_info;
char buf[20] = "";
if (title)
strncpy(buf, title, sizeof(buf) - 1);
}
#define EINA_UNUSED
Used to indicate that a function parameter is purposely unused.
Definition: eina_types.h:339
#define elm_object_item_text_set(it, label)
Macro to set a label of an object item.
Definition: elm_object_item.h:44
static void
{
Tab_Data *td = data;
const char *url = event_info;
if (td != td->app->current_tab)
return;
nav_button_update(td->app);
elm_object_text_set(td->app->url_entry, url);
}
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 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 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.
Tab_Data *
tab_add(App_Data *ad)
{
Tab_Data *td;
td = calloc(1, sizeof(Tab_Data));
if (!td) return NULL;
elm_web_window_create_hook_set(td->web, _web_create_window_cb, ad);
elm_naviframe_item_simple_push(ad->naviframe, td->web);
td->app = ad;
_tab_clicked_cb, td);
td);
td);
elm_toolbar_item_selected_set(td->tab,
EINA_TRUE);
return td;
}
#define EVAS_HINT_EXPAND
Use with evas_object_size_hint_weight_set(), evas_object_size_hint_weight_get(), evas_object_size_hin...
Definition: Evas_Common.h:297
@ EVAS_CALLBACK_FREE
Object Being Freed (Called after Del)
Definition: Evas_Common.h:429
#define EVAS_HINT_FILL
Use with evas_object_size_hint_align_set(), evas_object_size_hint_align_get(), evas_object_size_hint_...
Definition: Evas_Common.h:298
void elm_object_item_del_cb_set(Elm_Widget_Item *obj, Evas_Smart_Cb del_cb)
Set the function to be called when an item from the widget is freed.
Definition: elm_widget_item_eo.legacy.c:231
Evas_Object * elm_web_add(Evas_Object *parent)
Add a new web object to the parent.
Definition: elm_web2.c:80
EVAS_API void evas_object_event_callback_add(Evas_Object *eo_obj, Evas_Callback_Type type, Evas_Object_Event_Cb func, const void *data)
Add (register) a callback function to a given Evas object event.
Definition: evas_callbacks.c:478
EVAS_API void evas_object_size_hint_weight_set(Evas_Object *obj, double x, double y)
Sets the hints for an object's weight.
Definition: evas_object_main.c:2638
EVAS_API void evas_object_size_hint_align_set(Evas_Object *obj, double x, double y)
Sets the hints for an object's alignment.
Definition: evas_object_main.c:2650
EVAS_API void evas_object_smart_callback_add(Evas_Object *eo_obj, const char *event, Evas_Smart_Cb func, const void *data)
Add (register) a callback function to the smart event specified by event on the smart object obj.
Definition: evas_object_smart.c:1040
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.
static char *
url_sanitize(const char *url)
{
char *fixed_url;
char *schema;
char *tmp;
if (!url || !*url) return NULL;
tmp = strstr(url, "://");
if (!tmp || (tmp == url) || (tmp > (url + 15)))
{
char *new_url = NULL;
{
schema = "file";
}
else
schema = "http";
if (asprintf(&fixed_url, "%s://%s", schema, new_url ? new_url : url) >
0)
{
free(new_url);
return fixed_url;
}
free(new_url);
}
else
return strdup(url);
return NULL;
}
static void
tab_url_set(Tab_Data *td, const char *url)
{
char *sane_url = url_sanitize(url);
elm_web_url_set(td->web, sane_url);
free(sane_url);
}
static void
{
App_Data *ad = data;
Tab_Data *td;
if (!ad->current_tab)
td = tab_add(ad);
else
td = ad->current_tab;
tab_url_set(td, url);
char * ecore_file_realpath(const char *file)
Gets the canonicalized absolute path name.
Definition: ecore_file.c:554
Eina_Bool ecore_file_exists(const char *file)
Checks if the given file exists.
Definition: ecore_file.c:165
EINA_API void eina_stringshare_del(Eina_Stringshare *str)
Notes that the given string has lost an instance.
Definition: eina_stringshare.c:533
EINA_API Eina_Stringshare * eina_stringshare_ref(Eina_Stringshare *str)
Increment references of the given shared string.
Definition: eina_stringshare.c:685
}
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 Shift
key to avoid the cache.
static void
{
App_Data *ad = data;
elm_web_back(ad->current_tab->web);
}
static void
{
App_Data *ad = data;
elm_web_reload_full(ad->current_tab->web);
else
elm_web_reload(ad->current_tab->web);
}
static void
{
App_Data *ad = data;
elm_web_forward(ad->current_tab->web);
EVAS_API const Evas_Modifier * evas_key_modifier_get(const Evas *eo_e)
Returns a handle to the list of modifier keys registered in the canvas e.
Definition: evas_key.c:35
EVAS_API Eina_Bool evas_key_modifier_is_set(const Evas_Modifier *m, const char *keyname)
Checks the state of a given modifier of the default seat, at the time of the call.
Definition: evas_key.c:76
EVAS_API Evas * evas_object_evas_get(const Eo *eo_obj)
Get the Evas to which this object belongs to.
Definition: evas_object_main.c:2662
}
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().
{
App_Data *ad = data;
Tab_Data *td;
td = tab_add(ad);
return td->web;
}
struct _Elm_Web_Window_Features Elm_Web_Window_Features
Opaque handler containing the features (such as statusbar, menubar, etc) that are to be set on a newl...
Definition: elm_web_common.h:121
Pressing 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 Enter
will go to the next instance and the two buttons next to the entry will move forward and backwards through the found keywords.
static void
{
free(data);
}
static void
{
App_Data *ad = data;
const char *text;
text = elm_object_text_get(obj);
elm_web_text_matches_unmark_all(ad->current_tab->web);
0);
}
static void
{
App_Data *ad = data;
const char *text;
text = elm_object_text_get(obj);
}
static void
{
App_Data *ad = data;
const char *text;
text = elm_object_text_get(ad->search_entry);
}
static void
{
App_Data *ad = data;
const char *text;
text = elm_object_text_get(ad->search_entry);
}
static void
{
App_Data *ad = data;
}
static void
{
App_Data *ad = data;
ad->search_box = NULL;
ad->search_entry = NULL;
}
static void
#define EINA_FALSE
boolean value FALSE (numerical value 0)
Definition: eina_types.h:533
Eo Evas
An opaque handle to an Evas canvas.
Definition: Evas_Common.h:163
EVAS_API void evas_object_del(Evas_Object *obj)
Marks the given Evas object for deletion (when Evas will free its memory).
Definition: evas_object_main.c:928
{
App_Data *ad = data;
return;
if (ad->search_box || !ad->current_tab)
return;
ad);
ad);
ad);
ad->search_box = box;
ad->search_entry = entry;
}
@ EVAS_CALLBACK_DEL
Object Being Deleted (called before Free)
Definition: Evas_Common.h:439
void elm_box_horizontal_set(Elm_Box *obj, Eina_Bool horizontal)
Set the horizontal orientation.
Definition: elm_box_eo.legacy.c:27
void elm_box_pack_after(Elm_Box *obj, Efl_Canvas_Object *subobj, Efl_Canvas_Object *after)
Adds an object to the box after the indicated object.
Definition: elm_box_eo.legacy.c:75
Evas_Object * elm_box_add(Evas_Object *parent)
Add a new box to the parent.
Definition: elm_box.c:363
void elm_box_pack_end(Elm_Box *obj, Efl_Canvas_Object *subobj)
Add an object at the end of the pack list.
Definition: elm_box_eo.legacy.c:57
void elm_entry_scrollable_set(Elm_Entry *obj, Eina_Bool scroll)
Enable or disable scrolling in entry.
Definition: elm_entry_eo.legacy.c:3
void elm_entry_single_line_set(Elm_Entry *obj, Eina_Bool single_line)
Sets the entry to single line mode.
Definition: elm_entry_eo.legacy.c:123
Evas_Object * elm_entry_add(Evas_Object *parent)
This adds an entry to parent object.
Definition: elm_entry.c:4184
void elm_object_focus_set(Evas_Object *obj, Eina_Bool focus)
Set/unset focus to a given Elementary object.
Definition: elm_focus_legacy.c:374
void elm_object_part_content_set(Evas_Object *obj, const char *part, Evas_Object *content)
Set the content on part of a given container widget.
Definition: elm_main.c:1562
Eina_Bool elm_icon_standard_set(Evas_Object *obj, const char *name)
Set the icon by icon standards names.
Definition: elm_icon.c:885
Evas_Object * elm_icon_add(Evas_Object *parent)
Add a new icon object to the parent.
Definition: elm_icon.c:613
EVAS_API void evas_object_show(Evas_Object *eo_obj)
Makes the given Evas object visible.
Definition: evas_object_main.c:1814
Key press event.
Definition: Evas_Legacy.h:314
char * keyname
the name string of the key pressed
Definition: Evas_Legacy.h:315
Evas_Modifier * modifiers
modifier keys pressed during the event
Definition: Evas_Legacy.h:317
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.
static void
{
#ifdef HAVE_ELEMENTARY_WEB
const char contents[] = ""
"<html>\n"
" <head>\n"
" <title>Nothing to see here, move along</title>\n"
" </head>\n"
" <body>\n"
" <a href=\"http://www.enlightenment.org\" target=\"_blank\">E</a>\n"
" <br />\n"
" <a href=\"http://www.google.com\" target=\"_blank\">Google</a>\n"
" <br />\n"
" </body>\n"
"</html>\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);
#else
(void) web;
#endif
}
EAPI_MAIN int
{
Evas_Object *win, *box, *box2, *btn, *ic, *url_bar, *naviframe, *tabs, *web;
App_Data *ad;
return -1;
ad = calloc(1, sizeof(App_Data));
if (!ad) return -1;
fprintf(stderr, "Could not grab trigger for search dialog\n");
ad);
_win_search_trigger_cb, ad);
ad->nav.back = btn;
ad->nav.refresh = btn;
ad->nav.fwd = btn;
elm_web_window_create_hook_set(web, _web_create_window_cb, ad);
elm_naviframe_item_simple_push(naviframe, web);
default_content_set(web);
ad->win = win;
ad->main_box = box;
ad->naviframe = naviframe;
ad->url_entry = url_bar;
ad->default_web = web;
ad->tabs = tabs;
ad->close_tab = btn;
return 0;
}
@ EVAS_CALLBACK_KEY_DOWN
Key Press Event.
Definition: Evas_Common.h:430
#define ELM_MAIN()
macro to be used after the elm_main() function
Definition: elm_general.h:556
Eina_Bool elm_policy_set(unsigned int policy, int value)
Set a new policy's value (for a given policy group/identifier).
Definition: elm_main.c:1380
void elm_run(void)
Run Elementary's main loop.
Definition: elm_main.c:1357
@ ELM_POLICY_QUIT_LAST_WINDOW_CLOSED
quit when the application's last window is closed
Definition: elm_general.h:248
@ ELM_OBJECT_SELECT_MODE_ALWAYS
always select mode.
Definition: elm_general.h:39
@ ELM_POLICY_QUIT
under which circumstances the application should quit automatically.
Definition: elm_general.h:227
Evas_Object * elm_naviframe_add(Evas_Object *parent)
Add a new Naviframe object to the parent.
Definition: elc_naviframe.c:1605
Eina_Bool elm_need_web(void)
Request that your elementary application needs web support.
Definition: elm_web2.c:73
Evas_Object * elm_win_util_standard_add(const char *name, const char *title)
Adds a window object with standard setup.
Definition: efl_ui_win.c:9582
void elm_win_resize_object_add(Eo *obj, Evas_Object *subobj)
Add subobj as a resize object of window obj.
Definition: efl_ui_win.c:8997
void elm_win_autodel_set(Eo *obj, Eina_Bool autodel)
Set the window's autodel state.
Definition: efl_ui_win.c:6194
EVAS_API Evas_Modifier_Mask evas_key_modifier_mask_get(const Evas *eo_e, const char *keyname)
Creates a bit mask from the keyname modifier key.
Definition: evas_key.c:271
unsigned long long Evas_Modifier_Mask
A bitmask of modifier keys.
Definition: Evas_Legacy.h:132
EVAS_API Eina_Bool evas_object_key_grab(Evas_Object *obj, const char *keyname, Evas_Modifier_Mask modifiers, Evas_Modifier_Mask not_modifiers, Eina_Bool exclusive)
Requests keyname key events be directed to obj.
Definition: evas_key_grab.c:247
EVAS_API void evas_object_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
Changes the size of the given Evas object.
Definition: evas_object_main.c:1236
Some parts of the code were left out, as they are not relevant to the example, but the full listing can be found at web_example_02.c.