From: Hyoyoung Chang <hyoyoung@gmail.com>
[framework/uifw/elementary.git] / src / lib / elm_web.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 // TODO:
5 //  1 - easy to use zoom like elm_photocam API
6 //  2 - review scrolling to match elm_scroller. Maybe in future use elm_scroller
7
8 #ifdef HAVE_ELEMENTARY_WEB
9 #include <EWebKit.h>
10
11 /* Similar to iPhone */
12 // TODO: switch between iPhone, iPad or Chrome/Safari based on some elm setting?
13 #define ELM_WEB_USER_AGENT "Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543a Safari/419.3 " PACKAGE_NAME "/" PACKAGE_VERSION
14
15 static Ewk_View_Smart_Class _parent_sc = EWK_VIEW_SMART_CLASS_INIT_NULL;
16
17 typedef struct _View_Smart_Data View_Smart_Data;
18 struct _View_Smart_Data
19 {
20    Ewk_View_Smart_Data base;
21    struct {
22       Evas_Event_Mouse_Down event;
23       Evas_Coord x, y;
24       unsigned int move_count;
25       Ecore_Timer *longpress_timer;
26       Ecore_Animator *pan_anim;
27    } mouse;
28 };
29 #endif
30
31 typedef struct _Widget_Data Widget_Data;
32 struct _Widget_Data
33 {
34    Evas_Object *self;
35 #ifdef HAVE_ELEMENTARY_WEB
36    Evas_Object *ewk_view;
37    struct {
38       Elm_Web_Window_Open window_create;
39       void *window_create_data;
40       Elm_Web_Dialog_Alert alert;
41       void *alert_data;
42       Elm_Web_Dialog_Confirm confirm;
43       void *confirm_data;
44       Elm_Web_Dialog_Prompt prompt;
45       void *prompt_data;
46       Elm_Web_Dialog_File_Selector file_selector;
47       void *file_selector_data;
48       Elm_Web_Console_Message console_message;
49       void *console_message_data;
50    } hook;
51    Elm_Win_Keyboard_Mode input_method;
52    struct {
53         Elm_Web_Zoom_Mode mode;
54         float current;
55         float min, max;
56         Eina_Bool no_anim;
57         Ecore_Timer *timer;
58    } zoom;
59    struct {
60         struct {
61              int x, y;
62         } start, end;
63         Ecore_Animator *animator;
64    } bring_in;
65    Eina_Bool tab_propagate : 1;
66    Eina_Bool inwin_mode : 1;
67 #else
68    Evas_Object *label;
69 #endif
70 };
71
72 enum Dialog_Type
73 {
74    DIALOG_ALERT,
75    DIALOG_CONFIRM,
76    DIALOG_PROMPT,
77    DIALOG_FILE_SELECTOR
78 };
79
80 typedef struct _Dialog_Data Dialog_Data;
81 struct _Dialog_Data
82 {
83    enum Dialog_Type type;
84    Evas_Object *dialog;
85    Evas_Object *box;
86    Evas_Object *bt_ok, *bt_cancel;
87    Evas_Object *entry;
88    Evas_Object *file_sel;
89
90    Eina_Bool   *response;
91    char       **entry_value;
92    Eina_List  **selected_files;
93 };
94
95 struct _Elm_Web_Callback_Proxy_Context
96 {
97    const char *name;
98    Evas_Object *obj;
99 };
100 typedef struct _Elm_Web_Callback_Proxy_Context Elm_Web_Callback_Proxy_Context;
101
102 static const char *widtype = NULL;
103 static const Evas_Smart_Cb_Description _elm_web_callback_names[] = {
104    { "download,request", "p" },
105    { "editorclient,contents,changed", "" },
106    { "editorclient,selection,changed", "" },
107    { "frame,created", "p" },
108    { "icon,received", "" },
109    { "inputmethod,changed", "b" },
110    { "js,windowobject,clear", "" },
111    { "link,hover,in", "p" },
112    { "link,hover,out", "" },
113    { "load,document,finished", "p" },
114    { "load,error", "p" },
115    { "load,finished", "p" },
116    { "load,newwindow,show", "" },
117    { "load,progress", "d" },
118    { "load,provisional", "" },
119    { "load,started", "" },
120    { "menubar,visible,get", "b" },
121    { "menubar,visible,set", "b" },
122    { "popup,created", "p" },
123    { "popup,willdelete", "p" },
124    { "ready", "" },
125    { "scrollbars,visible,get", "b" },
126    { "scrollbars,visible,set", "b" },
127    { "statusbar,text,set", "s" },
128    { "statusbar,visible,get", "b" },
129    { "statusbar,visible,set", "b" },
130    { "title,changed", "s" },
131    { "toolbars,visible,get", "b" },
132    { "toolbars,visible,set", "b" },
133    { "tooltip,text,set", "s" },
134    { "uri,changed", "s" },
135    { "view,resized", "" },
136    { "windows,close,request", ""},
137    { "zoom,animated,end", "" },
138    { NULL, NULL }
139 };
140
141 #ifdef HAVE_ELEMENTARY_WEB
142 static char *
143 _webkit_theme_find(const Eina_List *list)
144 {
145    const Eina_List *l;
146    const char *th;
147
148    EINA_LIST_FOREACH(list, l, th)
149      {
150         char *path = elm_theme_list_item_path_get(th, NULL);
151         if (!path) continue;
152         if (edje_file_group_exists(path, "webkit/base"))
153           return path;
154         free(path);
155      }
156
157    return NULL;
158 }
159 #endif
160
161 static void
162 _theme_hook(Evas_Object *obj)
163 {
164 #ifdef HAVE_ELEMENTARY_WEB
165    Elm_Theme *theme = elm_object_theme_get(obj);
166    Widget_Data *wd = elm_widget_data_get(obj);
167    const Eina_List *themes;
168    char *view_theme = NULL;
169
170    themes = elm_theme_overlay_list_get(theme);
171    view_theme = _webkit_theme_find(themes);
172    if (view_theme) goto set;
173
174    themes = elm_theme_list_get(theme);
175    view_theme = _webkit_theme_find(themes);
176    if (view_theme) goto set;
177
178    themes = elm_theme_extension_list_get(theme);
179    view_theme = _webkit_theme_find(themes);
180
181 set:
182    if (view_theme)
183      {
184         ewk_view_theme_set(wd->ewk_view, view_theme);
185         free(view_theme);
186      }
187    else
188      ewk_view_theme_set(wd->ewk_view, WEBKIT_DATADIR"/themes/default.edj");
189 #else
190    (void)obj;
191 #endif
192 }
193
194 static void
195 _on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
196 {
197 #ifdef HAVE_ELEMENTARY_WEB
198    Widget_Data *wd = elm_widget_data_get(obj);
199    Evas_Object *top = elm_widget_top_get(obj);
200
201    if (!wd) return;
202
203    if (elm_object_focus_get(obj))
204      {
205         evas_object_focus_set(wd->ewk_view, EINA_TRUE);
206         if (top) elm_win_keyboard_mode_set(top, wd->input_method);
207      }
208    else
209      {
210         evas_object_focus_set(wd->ewk_view, EINA_FALSE);
211         if (top) elm_win_keyboard_mode_set(top, ELM_WIN_KEYBOARD_OFF);
212      }
213 #else
214    (void)obj;
215 #endif
216 }
217
218 static Eina_Bool
219 _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type type, void *event_info)
220 {
221 #ifdef HAVE_ELEMENTARY_WEB
222    Evas_Event_Key_Down *ev = event_info;
223    Widget_Data *wd = elm_widget_data_get(obj);
224
225    if (!wd) return EINA_FALSE;
226    if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
227    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
228    if (elm_widget_disabled_get(obj)) return EINA_FALSE;
229
230    if ((!strcmp(ev->keyname, "Tab")) && (!wd->tab_propagate))
231      {
232         ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
233         return EINA_TRUE;
234      }
235    else
236      return EINA_FALSE;
237 #else
238    return EINA_FALSE;
239    (void)obj;
240    (void)type;
241    (void)event_info;
242 #endif
243 }
244
245 #ifdef HAVE_ELEMENTARY_WEB
246 static Eina_Bool
247 _view_pan_animator(void *data)
248 {
249    View_Smart_Data *sd = data;
250    Evas_Coord x, y, dx, dy;
251
252    evas_pointer_canvas_xy_get(sd->base.base.evas, &x, &y);
253
254    dx = sd->mouse.x - x;
255    dy = sd->mouse.y - y;
256
257    if ((dx == 0) && (dy == 0))
258      goto end;
259
260    ewk_frame_scroll_add(sd->base.main_frame, dx, dy);
261
262    sd->mouse.x = x;
263    sd->mouse.y = y;
264
265  end:
266    return EINA_TRUE;
267 }
268
269 static void
270 _view_smart_add(Evas_Object *obj)
271 {
272    View_Smart_Data *sd;
273
274    sd = calloc(1, sizeof(View_Smart_Data));
275    evas_object_smart_data_set(obj, sd);
276
277    _parent_sc.sc.add(obj);
278
279    ewk_view_history_enable_set(obj, EINA_TRUE);
280    ewk_history_limit_set(ewk_view_history_get(obj), 100);
281    // TODO: auto toggle between smooth/nearest during bring-in animations
282    //ewk_view_zoom_weak_smooth_scale_set(obj, EINA_TRUE);
283 }
284
285 static void
286 _view_smart_del(Evas_Object *obj)
287 {
288    View_Smart_Data *sd;
289
290    sd = evas_object_smart_data_get(obj);
291
292    if (sd->mouse.pan_anim)
293      ecore_animator_del(sd->mouse.pan_anim);
294
295    _parent_sc.sc.del(obj);
296 }
297
298 static Eina_Bool
299 _view_longpress_timer(void *data)
300 {
301    View_Smart_Data *sd = data;
302
303    sd->mouse.move_count = 0;
304    sd->mouse.longpress_timer = NULL;
305    return ECORE_CALLBACK_CANCEL;
306 }
307
308 static Eina_Bool
309 _view_smart_mouse_down(Ewk_View_Smart_Data *esd, const Evas_Event_Mouse_Down *event)
310 {
311    // TODO: mimic elm_scroller and like
312    // TODO-minor: offer hook?
313    View_Smart_Data *sd = (View_Smart_Data *)esd;
314
315    if (event->button != 1)
316      return _parent_sc.mouse_down(esd, event);
317
318    sd->mouse.pan_anim = ecore_animator_add(_view_pan_animator, sd);
319    sd->mouse.longpress_timer = ecore_timer_add(_elm_config->longpress_timeout, _view_longpress_timer, sd);
320    sd->mouse.move_count = 1;
321    sd->mouse.x = event->canvas.x;
322    sd->mouse.y = event->canvas.y;
323    sd->mouse.event = *event;
324
325    return EINA_TRUE;
326 }
327
328 static Eina_Bool
329 _view_smart_mouse_up(Ewk_View_Smart_Data *esd, const Evas_Event_Mouse_Up *event)
330 {
331    // TODO: mimic elm_scroller and like
332    // TODO-minor: offer hook?
333    View_Smart_Data *sd = (View_Smart_Data *)esd;
334
335    if (sd->mouse.pan_anim)
336      {
337         ecore_animator_del(sd->mouse.pan_anim);
338         sd->mouse.pan_anim = NULL;
339
340         if (sd->mouse.longpress_timer)
341           _parent_sc.mouse_down(esd, &sd->mouse.event);
342         else
343           return EINA_TRUE;
344      }
345
346    if (sd->mouse.longpress_timer)
347      {
348         ecore_timer_del(sd->mouse.longpress_timer);
349         sd->mouse.longpress_timer = NULL;
350      }
351
352    sd->mouse.move_count = 0;
353    return _parent_sc.mouse_up(esd, event);
354 }
355
356 static Eina_Bool
357 _view_smart_mouse_move(Ewk_View_Smart_Data *esd, const Evas_Event_Mouse_Move *event)
358 {
359    // TODO: mimic elm_scroller and like
360    // TODO-minor: offer hook?
361    View_Smart_Data *sd = (View_Smart_Data *)esd;
362    sd->mouse.move_count++;
363
364    if (sd->mouse.longpress_timer &&
365        (((sd->mouse.x ^ sd->mouse.event.canvas.x) |
366          (sd->mouse.y ^ sd->mouse.event.canvas.y)) & (~0x07)))
367      {
368         ecore_timer_del(sd->mouse.longpress_timer);
369         sd->mouse.longpress_timer = NULL;
370      }
371
372    if (sd->mouse.pan_anim)
373      {
374         return EINA_FALSE;
375      }
376
377    return _parent_sc.mouse_move(esd, event);
378 }
379
380 static Evas_Object *
381 _view_smart_window_create(Ewk_View_Smart_Data *sd, Eina_Bool javascript, const Ewk_Window_Features *window_features)
382 {
383    Evas_Object *new;
384    Evas_Object *obj = evas_object_smart_parent_get(sd->self);
385    Widget_Data *wd = elm_widget_data_get(obj);
386
387    if (!wd->hook.window_create) return NULL;
388    new = wd->hook.window_create(wd->hook.window_create_data, obj, javascript,
389                         (const Elm_Web_Window_Features *)window_features);
390    if (new) return elm_web_webkit_view_get(new);
391
392    return NULL;
393 }
394
395 static void
396 _view_smart_window_close(Ewk_View_Smart_Data *sd)
397 {
398    Evas_Object *obj = evas_object_smart_parent_get(sd->self);
399    evas_object_smart_callback_call(obj, "windows,close,request", NULL);
400 }
401
402 static void
403 _bt_close(void *data, Evas_Object *obj, void *event_info __UNUSED__)
404 {
405    Dialog_Data *d = data;
406
407    *d->response = (obj == d->bt_ok);
408    if ((d->type == DIALOG_PROMPT) && (*d->response == EINA_TRUE))
409      *d->entry_value = strdup(elm_entry_entry_get(d->entry));
410    evas_object_del(d->dialog);
411 }
412
413 static void
414 _file_sel_done(void *data, Evas_Object *obj __UNUSED__, void *event_info)
415 {
416    Dialog_Data *d = data;
417    if (event_info)
418      {
419         *d->selected_files = eina_list_append(NULL, strdup(event_info));
420         *d->response = EINA_TRUE;
421      }
422    else
423      *d->response = EINA_FALSE;
424    evas_object_del(d->dialog);
425    free(d);
426 }
427
428 static Dialog_Data *
429 _dialog_new(Evas_Object *parent)
430 {
431    Dialog_Data *d;
432    Widget_Data *wd = elm_widget_data_get(parent);
433
434    d = calloc(1, sizeof(Dialog_Data));
435    if (!d) return NULL;
436
437    if (!parent || wd->inwin_mode)
438      {
439         Evas_Object *bg;
440
441         d->dialog = elm_win_add(NULL, "elm-web-popup", ELM_WIN_DIALOG_BASIC);
442         evas_object_smart_callback_add(d->dialog, "delete,request",
443                                        _bt_close, d);
444
445         bg = elm_bg_add(d->dialog);
446         evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND,
447                                          EVAS_HINT_EXPAND);
448         elm_win_resize_object_add(d->dialog, bg);
449         evas_object_show(bg);
450
451         d->box = elm_box_add(d->dialog);
452         evas_object_size_hint_weight_set(d->box, EVAS_HINT_EXPAND,
453                                          EVAS_HINT_EXPAND);
454         elm_win_resize_object_add(d->dialog, d->box);
455         evas_object_show(d->box);
456      }
457    else
458      {
459         Evas_Object *win = elm_widget_top_get(parent);
460         d->dialog = elm_win_inwin_add(win);
461         elm_object_style_set(d->dialog, "minimal");
462         evas_object_size_hint_weight_set(d->dialog, EVAS_HINT_EXPAND,
463                                          EVAS_HINT_EXPAND);
464
465         d->box = elm_box_add(win);
466         evas_object_size_hint_weight_set(d->box, EVAS_HINT_EXPAND,
467                                          EVAS_HINT_EXPAND);
468         elm_win_inwin_content_set(d->dialog, d->box);
469         evas_object_show(d->box);
470      }
471
472    return d;
473 }
474
475 static Evas_Object *
476 _run_dialog(Evas_Object *parent, enum Dialog_Type type, const char *message, const char *default_entry_value, char **entry_value, Eina_Bool allows_multiple_files __UNUSED__, Eina_List *accept_types __UNUSED__, Eina_List **selected_filenames, Eina_Bool *response)
477 {
478    EINA_SAFETY_ON_TRUE_RETURN_VAL((type != DIALOG_PROMPT) && (!!default_entry_value), EINA_FALSE);
479    EINA_SAFETY_ON_TRUE_RETURN_VAL((type != DIALOG_PROMPT) && (!!entry_value), EINA_FALSE);
480
481    Dialog_Data *dialog_data = _dialog_new(evas_object_smart_parent_get(parent));
482    Evas_Object *lb;
483
484    if (type != DIALOG_FILE_SELECTOR)
485      {
486         lb = elm_label_add(dialog_data->box);
487         elm_object_text_set(lb, message);
488         elm_box_pack_end(dialog_data->box, lb);
489         evas_object_show(lb);
490      }
491
492    dialog_data->type = type;
493    dialog_data->response = response;
494    dialog_data->entry_value = entry_value;
495    dialog_data->selected_files = selected_filenames;
496
497    if (type == DIALOG_ALERT)
498      {
499         dialog_data->bt_ok = elm_button_add(dialog_data->box);
500         elm_object_text_set(dialog_data->bt_ok, "Close");
501         elm_box_pack_end(dialog_data->box, dialog_data->bt_ok);
502         evas_object_size_hint_align_set(dialog_data->bt_ok, EVAS_HINT_FILL, EVAS_HINT_FILL);
503         evas_object_smart_callback_add(dialog_data->bt_ok, "clicked", _bt_close, dialog_data);
504         evas_object_show(dialog_data->bt_ok);
505      }
506    else if (type == DIALOG_FILE_SELECTOR)
507      {
508         dialog_data->file_sel = elm_fileselector_add(dialog_data->dialog);
509         evas_object_size_hint_weight_set(dialog_data->file_sel,
510                                          EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
511         evas_object_size_hint_align_set(dialog_data->file_sel, EVAS_HINT_FILL,
512                                         EVAS_HINT_FILL);
513         elm_box_pack_end(dialog_data->box, dialog_data->file_sel);
514         evas_object_show(dialog_data->file_sel);
515
516         elm_fileselector_path_set(dialog_data->file_sel, ".");
517         elm_fileselector_is_save_set(dialog_data->file_sel, EINA_FALSE);
518         elm_fileselector_folder_only_set(dialog_data->file_sel, EINA_FALSE);
519         elm_fileselector_buttons_ok_cancel_set(dialog_data->file_sel,
520                                                EINA_TRUE);
521         elm_fileselector_expandable_set(dialog_data->file_sel, EINA_FALSE);
522         evas_object_smart_callback_add(dialog_data->file_sel, "done",
523                                        _file_sel_done, dialog_data);
524         // fileselector can't set it's minimum size correctly
525         evas_object_size_hint_min_set(dialog_data->file_sel, 300, 400);
526      }
527    else
528      {
529         if (type == DIALOG_PROMPT)
530           {
531              dialog_data->entry = elm_entry_add(dialog_data->box);
532              elm_entry_single_line_set(dialog_data->entry, EINA_TRUE);
533              elm_entry_scrollable_set(dialog_data->entry, EINA_TRUE);
534              elm_entry_entry_set(dialog_data->entry, default_entry_value);
535              evas_object_size_hint_align_set(dialog_data->entry, EVAS_HINT_FILL, EVAS_HINT_FILL);
536              evas_object_size_hint_weight_set(dialog_data->entry, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
537              elm_box_pack_end(dialog_data->box, dialog_data->entry);
538              evas_object_show(dialog_data->entry);
539           }
540
541         if (type == DIALOG_PROMPT || type == DIALOG_CONFIRM)
542           {
543              Evas_Object *bx_h = elm_box_add(dialog_data->box);
544              elm_box_horizontal_set(bx_h, 1);
545              elm_box_pack_end(dialog_data->box, bx_h);
546              evas_object_size_hint_weight_set(bx_h, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
547              evas_object_size_hint_align_set(bx_h, EVAS_HINT_FILL, EVAS_HINT_FILL);
548              evas_object_show(bx_h);
549
550              dialog_data->bt_cancel = elm_button_add(bx_h);
551              elm_object_text_set(dialog_data->bt_cancel, "Cancel");
552              elm_box_pack_end(bx_h, dialog_data->bt_cancel);
553              evas_object_size_hint_weight_set(dialog_data->bt_cancel, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
554              evas_object_size_hint_align_set(dialog_data->bt_cancel, EVAS_HINT_FILL, EVAS_HINT_FILL);
555              evas_object_smart_callback_add(dialog_data->bt_cancel, "clicked", _bt_close, dialog_data);
556              evas_object_show(dialog_data->bt_cancel);
557
558              dialog_data->bt_ok = elm_button_add(bx_h);
559              elm_object_text_set(dialog_data->bt_ok, "Ok");
560              elm_box_pack_end(bx_h, dialog_data->bt_ok);
561              evas_object_size_hint_weight_set(dialog_data->bt_ok, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
562              evas_object_size_hint_align_set(dialog_data->bt_ok, EVAS_HINT_FILL, EVAS_HINT_FILL);
563              evas_object_smart_callback_add(dialog_data->bt_ok, "clicked", _bt_close, dialog_data);
564              evas_object_show(dialog_data->bt_ok);
565           }
566         else
567            return EINA_FALSE;
568      }
569
570    evas_object_show(dialog_data->dialog);
571
572    return dialog_data->dialog;
573 }
574
575 static void
576 _dialog_del_cb(void *data __UNUSED__, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
577 {
578    ecore_main_loop_quit();
579 }
580
581 static void
582 _exec_dialog(Evas_Object *dialog)
583 {
584    evas_object_event_callback_add(dialog, EVAS_CALLBACK_DEL, _dialog_del_cb,
585                                   NULL);
586    ecore_main_loop_begin();
587 }
588
589 /* called by ewk_view when javascript called alert()
590  *
591  */
592 static void
593 _view_smart_run_javascript_alert(Ewk_View_Smart_Data *esd, Evas_Object *frame __UNUSED__, const char *message)
594 {
595    View_Smart_Data *sd = (View_Smart_Data *)esd;
596    Evas_Object *view = sd->base.self;
597    Evas_Object *obj = evas_object_smart_parent_get(view);
598    Evas_Object *diag = NULL;
599    Widget_Data *wd = elm_widget_data_get(obj);
600    Eina_Bool response = EINA_FALSE;
601
602    if (wd->hook.alert)
603      diag = wd->hook.alert(wd->hook.alert_data, obj, message);
604    else
605      diag = _run_dialog(view, DIALOG_ALERT, message, NULL, NULL, EINA_FALSE,
606                         NULL, NULL, &response);
607    if (diag) _exec_dialog(diag);
608 }
609
610 /* called by ewk_view when javascript called confirm()
611  *
612  */
613 static Eina_Bool
614 _view_smart_run_javascript_confirm(Ewk_View_Smart_Data *esd, Evas_Object *frame __UNUSED__, const char *message)
615 {
616    View_Smart_Data *sd = (View_Smart_Data *)esd;
617    Evas_Object *view = sd->base.self;
618    Evas_Object *obj = evas_object_smart_parent_get(view);
619    Evas_Object *diag = NULL;
620    Widget_Data *wd = elm_widget_data_get(obj);
621    Eina_Bool response = EINA_FALSE;
622
623    if (wd->hook.confirm)
624      diag = wd->hook.confirm(wd->hook.confirm_data, obj, message, &response);
625    else
626     diag = _run_dialog(view, DIALOG_CONFIRM, message, NULL, NULL, EINA_FALSE,
627                        NULL, NULL, &response);
628    if (diag) _exec_dialog(diag);
629    return response;
630 }
631
632 /* called by ewk_view when javascript called confirm()
633  *
634  */
635 static Eina_Bool
636 _view_smart_run_javascript_prompt(Ewk_View_Smart_Data *esd, Evas_Object *frame __UNUSED__, const char *message, const char *default_value, char **value)
637 {
638    View_Smart_Data *sd = (View_Smart_Data *)esd;
639    Evas_Object *view = sd->base.self;
640    Evas_Object *obj = evas_object_smart_parent_get(view);
641    Evas_Object *diag = NULL;
642    Widget_Data *wd = elm_widget_data_get(obj);
643    Eina_Bool response = EINA_FALSE;
644
645    if (wd->hook.prompt)
646      diag = wd->hook.prompt(wd->hook.prompt_data, obj, message, default_value,
647                             value, &response);
648    else
649      diag = _run_dialog(view, DIALOG_PROMPT, message, default_value, value,
650                         EINA_FALSE, NULL, NULL, &response);
651    if (diag) _exec_dialog(diag);
652    if (!response)
653       *value = NULL;
654
655    return EINA_TRUE;
656 }
657
658 static Eina_Bool
659 _view_smart_run_open_panel(Ewk_View_Smart_Data *esd, Evas_Object *frame __UNUSED__, Eina_Bool allows_multiple_files, Eina_List *accept_types, Eina_List **selected_filenames)
660 {
661    View_Smart_Data *sd = (View_Smart_Data *)esd;
662    Evas_Object *view = sd->base.self;
663    Evas_Object *obj = evas_object_smart_parent_get(view);
664    Evas_Object *diag = NULL;
665    Widget_Data *wd = elm_widget_data_get(obj);
666    Eina_Bool response = EINA_FALSE;
667
668    if (wd->hook.file_selector)
669      diag = wd->hook.file_selector(wd->hook.file_selector_data, obj,
670                                    allows_multiple_files, accept_types,
671                                    selected_filenames, &response);
672    else
673      diag = _run_dialog(view, DIALOG_FILE_SELECTOR, NULL, NULL, NULL,
674                         allows_multiple_files, accept_types, selected_filenames,
675                         &response);
676    if (diag) _exec_dialog(diag);
677
678    return response;
679 }
680
681 static void
682 _view_smart_add_console_message(Ewk_View_Smart_Data *esd, const char *message, unsigned int line_number, const char *source_id)
683 {
684    Evas_Object *obj = evas_object_smart_parent_get(esd->self);
685    Widget_Data *wd = elm_widget_data_get(obj);
686
687    if (wd->hook.console_message)
688      wd->hook.console_message(wd->hook.console_message_data, obj, message,
689                               line_number, source_id);
690 }
691
692 static Eina_Bool
693 _view_smart_focus_can_cycle(Ewk_View_Smart_Data *sd, Ewk_Focus_Direction direction)
694 {
695    Evas_Object *obj = evas_object_smart_parent_get(sd->self);
696    Elm_Focus_Direction dir;
697
698    switch (direction)
699      {
700       case EWK_FOCUS_DIRECTION_FORWARD:
701          dir = ELM_FOCUS_NEXT;
702          break;
703       case EWK_FOCUS_DIRECTION_BACKWARD:
704          dir = ELM_FOCUS_PREVIOUS;
705          break;
706       default:
707          return EINA_FALSE;
708      }
709
710    elm_widget_focus_cycle(elm_widget_parent_get(obj), dir);
711
712    return EINA_TRUE;
713 }
714
715 /**
716  * Creates a new view object given the parent.
717  *
718  * @param parent object to use as parent.
719  *
720  * @return newly added Evas_Object or @c NULL on errors.
721  */
722 Evas_Object *
723 _view_add(Evas_Object *parent)
724 {
725    static Evas_Smart *smart = NULL;
726    Evas *canvas = evas_object_evas_get(parent);
727    Evas_Object *view;
728
729    if (!smart)
730      {
731         static Ewk_View_Smart_Class api = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION("EWK_View_Elementary");
732
733 #ifndef TILED_BACKING_STORE
734         ewk_view_single_smart_set(&api);
735 #else
736         ewk_view_tiled_smart_set(&api);
737 #endif
738
739         _parent_sc = api;
740
741         // TODO: check every api method and provide overrides with hooks!
742         // TODO: hooks should provide extension points
743         // TODO: extension should have some kind of "default implementation",
744         // TODO: that can be replaced or controlled by hooks.
745         // TODO: ie: run_javascript_alert() should present an elm_win
746         // TODO: by default, but user could override it to show as inwin.
747         api.sc.add = _view_smart_add;
748         api.sc.del = _view_smart_del;
749         //api.sc.calculate = _view_smart_calculate;
750         api.mouse_down = _view_smart_mouse_down;
751         api.mouse_up = _view_smart_mouse_up;
752         api.mouse_move = _view_smart_mouse_move;
753         api.add_console_message = _view_smart_add_console_message;
754         api.window_create = _view_smart_window_create;
755         api.window_close = _view_smart_window_close;
756         api.run_javascript_alert = _view_smart_run_javascript_alert;
757         api.run_javascript_confirm = _view_smart_run_javascript_confirm;
758         api.run_javascript_prompt = _view_smart_run_javascript_prompt;
759         api.run_open_panel = _view_smart_run_open_panel;
760         api.focus_can_cycle = _view_smart_focus_can_cycle;
761
762         smart = evas_smart_class_new(&api.sc);
763         if (!smart)
764           {
765              CRITICAL("Could not create smart class");
766              return NULL;
767           }
768      }
769
770    view = evas_object_smart_add(canvas, smart);
771    if (!view)
772      {
773         ERR("Could not create smart object object for view");
774         return NULL;
775      }
776
777    return view;
778 }
779
780 static void
781 _ewk_view_inputmethod_change_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info)
782 {
783    Widget_Data *wd = data;
784    Evas_Object *top = elm_widget_top_get(wd->self);
785    if (!top) return;
786
787    if (event_info)
788      wd->input_method = ELM_WIN_KEYBOARD_ON;
789    else
790      wd->input_method = ELM_WIN_KEYBOARD_OFF;
791    elm_win_keyboard_mode_set(top, wd->input_method);
792 }
793
794 static void
795 _ewk_view_load_started_cb(void *data, Evas_Object *obj, void *event_info __UNUSED__)
796 {
797    _ewk_view_inputmethod_change_cb(data, obj, (void *)(long)EINA_FALSE);
798 }
799
800 static void
801 _ewk_view_load_finished_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info)
802 {
803    Widget_Data *wd = data;
804
805    if (event_info)
806      return;
807
808    if (wd->zoom.mode != ELM_WEB_ZOOM_MODE_MANUAL)
809      {
810         float tz = wd->zoom.current;
811         wd->zoom.current = 0.0;
812         elm_web_zoom_set(wd->self, tz);
813      }
814 }
815
816 static void
817 _ewk_view_viewport_changed_cb(void *data, Evas_Object *obj, void *event_info __UNUSED__)
818 {
819    Widget_Data *wd = data;
820
821    if (wd->zoom.mode != ELM_WEB_ZOOM_MODE_MANUAL)
822      {
823         ewk_view_zoom_set(obj, 1.0, 0, 0);
824         wd->zoom.no_anim = EINA_TRUE;
825      }
826 }
827
828 static Eina_Bool
829 _restore_zoom_mode_timer_cb(void *data)
830 {
831    Widget_Data *wd = data;
832    float tz = wd->zoom.current;
833    wd->zoom.timer = NULL;
834    wd->zoom.current = 0.0;
835    wd->zoom.no_anim = EINA_TRUE;
836    elm_web_zoom_set(wd->self, tz);
837    return EINA_FALSE;
838 }
839
840 static Eina_Bool
841 _reset_zoom_timer_cb(void *data)
842 {
843    Widget_Data *wd = data;
844    wd->zoom.timer = ecore_timer_add(0.0, _restore_zoom_mode_timer_cb, wd);
845    ewk_view_zoom_set(wd->ewk_view, 1.0, 0, 0);
846    return EINA_FALSE;
847 }
848
849 static void
850 _ewk_view_resized_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
851 {
852    Widget_Data *wd = data;
853    if (!(wd->zoom.mode != ELM_WEB_ZOOM_MODE_MANUAL))
854      return;
855    if (wd->zoom.timer)
856      ecore_timer_del(wd->zoom.timer);
857    wd->zoom.timer = ecore_timer_add(0.5, _reset_zoom_timer_cb, wd);
858 }
859
860 static void
861 _popup_del_job(void *data)
862 {
863    evas_object_del(data);
864 }
865
866 static void
867 _popup_will_delete(void *data, Evas_Object *obj, void *event_info __UNUSED__)
868 {
869    ecore_job_add(_popup_del_job, data);
870    evas_object_smart_callback_del(obj, "popup,willdelete", _popup_will_delete);
871 }
872
873 static void
874 _popup_item_selected(void *data, Evas_Object *obj, void *event_info __UNUSED__)
875 {
876    Evas_Object *view = data;
877    Elm_Object_Item *list_it = elm_list_selected_item_get(obj);
878    const Eina_List *itr, *list = elm_list_items_get(obj);
879    void *d;
880    int i = 0;
881
882    EINA_LIST_FOREACH(list, itr, d)
883    {
884       if (d == list_it)
885          break;
886
887       i++;
888    }
889
890    ewk_view_popup_selected_set(view, i);
891    ewk_view_popup_destroy(view);
892 }
893
894 static void
895 _popup_dismiss_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
896 {
897    ewk_view_popup_destroy(data);
898 }
899
900 static void
901 _ewk_view_popup_create_cb(void *data, Evas_Object *obj, void *event_info)
902 {
903    Widget_Data *wd = data;
904    Ewk_Menu *m = event_info;
905    Elm_Web_Menu m2;
906    Ewk_Menu_Item *it;
907    Eina_List *itr;
908    Evas_Object *notify, *list;
909
910    m2.items = m->items;
911    m2.x = m->x;
912    m2.y = m->y;
913    m2.width = m->width;
914    m2.height = m->height;
915    m2.handled = EINA_FALSE;
916    evas_object_smart_callback_call(wd->self, "popup,create", &m2);
917    if (m2.handled)
918      return;
919
920    notify = elm_notify_add(obj);
921    elm_notify_allow_events_set(notify, EINA_FALSE);
922    elm_notify_orient_set(notify, ELM_NOTIFY_ORIENT_BOTTOM);
923
924    list = elm_list_add(obj);
925    elm_list_always_select_mode_set(list, EINA_TRUE);
926    elm_list_bounce_set(list, EINA_FALSE, EINA_FALSE);
927    elm_list_mode_set(list, ELM_LIST_EXPAND);
928    evas_object_size_hint_weight_set(list, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
929    evas_object_size_hint_align_set(list, EVAS_HINT_FILL, EVAS_HINT_FILL);
930    elm_object_content_set(notify, list);
931    evas_object_show(list);
932
933    EINA_LIST_FOREACH(m->items, itr, it)
934       elm_list_item_append(list, it->text, NULL, NULL, _popup_item_selected,
935                            obj);
936    elm_list_go(list);
937
938    evas_object_show(notify);
939
940    evas_object_smart_callback_add(obj, "popup,willdelete", _popup_will_delete,
941                                   notify);
942    evas_object_smart_callback_add(notify, "block,clicked", _popup_dismiss_cb,
943                                   obj);
944 }
945
946 static void
947 _view_smart_callback_proxy_free_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
948 {
949    free(data);
950 }
951
952 static void
953 _view_smart_callback_proxy_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info)
954 {
955    Elm_Web_Callback_Proxy_Context *ctxt = data;
956
957    evas_object_smart_callback_call(ctxt->obj, ctxt->name, event_info);
958 }
959
960 static void
961 _view_smart_callback_proxy(Evas_Object *view, Evas_Object *parent)
962 {
963    const Evas_Smart_Cb_Description **cls_descs, **inst_descs;
964    unsigned int cls_count, inst_count, total;
965    Elm_Web_Callback_Proxy_Context *ctxt;
966
967    evas_object_smart_callbacks_descriptions_get(view, &cls_descs, &cls_count,
968                                                 &inst_descs, &inst_count);
969    total = cls_count + inst_count;
970    if (!total) return;
971    ctxt = malloc(sizeof(Elm_Web_Callback_Proxy_Context) * total);
972    if (!ctxt) return;
973    evas_object_event_callback_add(view, EVAS_CALLBACK_FREE,
974                                   _view_smart_callback_proxy_free_cb, ctxt);
975
976    for (; cls_count > 0; cls_count--, cls_descs++, ctxt++)
977      {
978         const Evas_Smart_Cb_Description *d = *cls_descs;
979         if (!strcmp(d->name, "popup,create"))
980           continue;
981         ctxt->name = d->name;
982         ctxt->obj = parent;
983         evas_object_smart_callback_add(view, d->name,
984                                        _view_smart_callback_proxy_cb, ctxt);
985      }
986
987    for (; inst_count > 0; inst_count--, inst_descs++, ctxt++)
988      {
989         const Evas_Smart_Cb_Description *d = *inst_descs;
990         ctxt->name = d->name;
991         ctxt->obj = parent;
992         evas_object_smart_callback_add(view, d->name,
993                                        _view_smart_callback_proxy_cb, ctxt);
994      }
995 }
996
997 static Eina_Bool
998 _bring_in_anim_cb(void *data, double pos)
999 {
1000    Widget_Data *wd = data;
1001    Evas_Object *frame = ewk_view_frame_main_get(wd->ewk_view);
1002    int sx, sy, rx, ry;
1003
1004    sx = wd->bring_in.start.x;
1005    sy = wd->bring_in.start.y;
1006    rx = (wd->bring_in.end.x - sx) * pos;
1007    ry = (wd->bring_in.end.y - sy) * pos;
1008
1009    ewk_frame_scroll_set(frame, rx + sx, ry + sy);
1010
1011    if (pos == 1.0)
1012      {
1013         wd->bring_in.end.x = wd->bring_in.end.y = wd->bring_in.start.x =
1014            wd->bring_in.start.y = 0;
1015         wd->bring_in.animator = NULL;
1016      }
1017
1018    return EINA_TRUE;
1019 }
1020 #endif
1021
1022 #ifdef HAVE_ELEMENTARY_WEB
1023 static int _elm_need_web = 0;
1024 #endif
1025
1026 void
1027 _elm_unneed_web(void)
1028 {
1029 #ifdef HAVE_ELEMENTARY_WEB
1030    if (--_elm_need_web) return;
1031
1032    _elm_need_web = 0;
1033    ewk_shutdown();
1034 #endif
1035 }
1036
1037 EAPI Eina_Bool
1038 elm_need_web(void)
1039 {
1040 #ifdef HAVE_ELEMENTARY_WEB
1041    if (_elm_need_web++) return EINA_TRUE;
1042    ewk_init();
1043    return EINA_TRUE;
1044 #else
1045    return EINA_FALSE;
1046 #endif
1047 }
1048
1049 EAPI Evas_Object *
1050 elm_web_add(Evas_Object *parent)
1051 {
1052    Evas_Object *obj;
1053    Widget_Data *wd;
1054    Evas *e;
1055
1056    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
1057
1058    wd = calloc(1, sizeof(Widget_Data));
1059    e = evas_object_evas_get(parent);
1060    if (!e)
1061      return NULL;
1062    obj = elm_widget_add(e);
1063    wd->self = obj;
1064
1065    if (!widtype)
1066      {
1067         widtype = eina_stringshare_add("web");
1068         elm_widget_type_register(&widtype);
1069      }
1070
1071    elm_widget_type_set(obj, widtype);
1072    elm_widget_sub_object_add(parent, obj);
1073    elm_widget_theme_hook_set(obj, _theme_hook);
1074    elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
1075    elm_widget_event_hook_set(obj, _event_hook);
1076    elm_widget_data_set(obj, wd);
1077    elm_widget_can_focus_set(obj, EINA_TRUE);
1078
1079 #ifdef HAVE_ELEMENTARY_WEB
1080    wd->ewk_view = _view_add(obj);
1081    ewk_view_setting_user_agent_set(wd->ewk_view, ELM_WEB_USER_AGENT);
1082
1083    wd->input_method = ELM_WIN_KEYBOARD_OFF;
1084    evas_object_smart_callback_add(wd->ewk_view, "inputmethod,changed",
1085                                   _ewk_view_inputmethod_change_cb, wd);
1086    evas_object_smart_callback_add(wd->ewk_view, "load,started",
1087                                   _ewk_view_load_started_cb, wd);
1088    evas_object_smart_callback_add(wd->ewk_view, "popup,create",
1089                                   _ewk_view_popup_create_cb, wd);
1090    evas_object_smart_callback_add(wd->ewk_view, "load,finished",
1091                                   _ewk_view_load_finished_cb, wd);
1092    evas_object_smart_callback_add(wd->ewk_view, "viewport,changed",
1093                                   _ewk_view_viewport_changed_cb, wd);
1094    evas_object_smart_callback_add(wd->ewk_view, "view,resized",
1095                                   _ewk_view_resized_cb, wd);
1096
1097    elm_widget_resize_object_set(obj, wd->ewk_view);
1098
1099    wd->tab_propagate = EINA_FALSE;
1100    wd->inwin_mode = _elm_config->inwin_dialogs_enable;
1101    wd->zoom.min = ewk_view_zoom_range_min_get(wd->ewk_view);
1102    wd->zoom.max = ewk_view_zoom_range_max_get(wd->ewk_view);
1103    wd->zoom.current = 1.0;
1104
1105    _view_smart_callback_proxy(wd->ewk_view, wd->self);
1106    evas_object_smart_callbacks_descriptions_set(obj, _elm_web_callback_names);
1107
1108    _theme_hook(obj);
1109
1110 #else
1111    wd->label = elm_label_add(obj);
1112    elm_object_text_set(wd->label, "WebKit not supported!");
1113    evas_object_show(wd->label);
1114    elm_widget_resize_object_set(obj, wd->label);
1115 #endif
1116
1117    return obj;
1118 }
1119
1120 EAPI Evas_Object *
1121 elm_web_webkit_view_get(const Evas_Object *obj)
1122 {
1123    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1124 #ifdef HAVE_ELEMENTARY_WEB
1125    Widget_Data *wd = elm_widget_data_get(obj);
1126    if (!wd) return NULL;
1127    return wd->ewk_view;
1128 #else
1129    ERR("Elementary not compiled with EWebKit support.");
1130    return NULL;
1131 #endif
1132 }
1133
1134 EAPI void
1135 elm_web_window_create_hook_set(Evas_Object *obj, Elm_Web_Window_Open func, void *data)
1136 {
1137    ELM_CHECK_WIDTYPE(obj, widtype);
1138 #ifdef HAVE_ELEMENTARY_WEB
1139    Widget_Data *wd = elm_widget_data_get(obj);
1140    if (!wd) return;
1141    wd->hook.window_create = func;
1142    wd->hook.window_create_data = data;
1143 #else
1144    (void)func;
1145    (void)data;
1146 #endif
1147 }
1148
1149 EAPI void
1150 elm_web_dialog_alert_hook_set(Evas_Object *obj, Elm_Web_Dialog_Alert func, void *data)
1151 {
1152    ELM_CHECK_WIDTYPE(obj, widtype);
1153 #ifdef HAVE_ELEMENTARY_WEB
1154    Widget_Data *wd = elm_widget_data_get(obj);
1155    if (!wd) return;
1156    wd->hook.alert = func;
1157    wd->hook.alert_data = data;
1158 #else
1159    (void)func;
1160    (void)data;
1161 #endif
1162 }
1163
1164 EAPI void
1165 elm_web_dialog_confirm_hook_set(Evas_Object *obj, Elm_Web_Dialog_Confirm func, void *data)
1166 {
1167    ELM_CHECK_WIDTYPE(obj, widtype);
1168 #ifdef HAVE_ELEMENTARY_WEB
1169    Widget_Data *wd = elm_widget_data_get(obj);
1170    if (!wd) return;
1171    wd->hook.confirm = func;
1172    wd->hook.confirm_data = data;
1173 #else
1174    (void)func;
1175    (void)data;
1176 #endif
1177 }
1178
1179 EAPI void
1180 elm_web_dialog_prompt_hook_set(Evas_Object *obj, Elm_Web_Dialog_Prompt func, void *data)
1181 {
1182    ELM_CHECK_WIDTYPE(obj, widtype);
1183 #ifdef HAVE_ELEMENTARY_WEB
1184    Widget_Data *wd = elm_widget_data_get(obj);
1185    if (!wd) return;
1186    wd->hook.prompt = func;
1187    wd->hook.prompt_data = data;
1188 #else
1189    (void)func;
1190    (void)data;
1191 #endif
1192 }
1193
1194 EAPI void
1195 elm_web_dialog_file_selector_hook_set(Evas_Object *obj, Elm_Web_Dialog_File_Selector func, void *data)
1196 {
1197    ELM_CHECK_WIDTYPE(obj, widtype);
1198 #ifdef HAVE_ELEMENTARY_WEB
1199    Widget_Data *wd = elm_widget_data_get(obj);
1200    if (!wd) return;
1201    wd->hook.file_selector = func;
1202    wd->hook.file_selector_data = data;
1203 #else
1204    (void)func;
1205    (void)data;
1206 #endif
1207 }
1208
1209 EAPI void
1210 elm_web_console_message_hook_set(Evas_Object *obj, Elm_Web_Console_Message func, void *data)
1211 {
1212    ELM_CHECK_WIDTYPE(obj, widtype);
1213 #ifdef HAVE_ELEMENTARY_WEB
1214    Widget_Data *wd = elm_widget_data_get(obj);
1215    if (!wd) return;
1216    wd->hook.console_message = func;
1217    wd->hook.console_message_data = data;
1218 #else
1219    (void)func;
1220    (void)data;
1221 #endif
1222 }
1223
1224 EAPI void 
1225 elm_web_useragent_set(Evas_Object *obj, const char *user_agent)
1226 {
1227    ELM_CHECK_WIDTYPE(obj, widtype);
1228 #ifdef HAVE_ELEMENTARY_WEB
1229    Widget_Data *wd = elm_widget_data_get(obj);
1230    if (!wd) return;
1231    ewk_view_setting_user_agent_set(wd->ewk_view, user_agent);
1232 #else
1233    (void)user_agent;
1234 #endif
1235 }
1236
1237 EAPI const char* 
1238 elm_web_useragent_get(const Evas_Object *obj)
1239 {
1240    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1241 #ifdef HAVE_ELEMENTARY_WEB
1242    Widget_Data *wd = elm_widget_data_get(obj);
1243    if (!wd) return NULL;
1244    return ewk_view_setting_user_agent_get(wd->ewk_view);
1245 #else
1246    return NULL;
1247 #endif
1248 }
1249
1250 EAPI Eina_Bool
1251 elm_web_tab_propagate_get(const Evas_Object *obj)
1252 {
1253    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1254 #ifdef HAVE_ELEMENTARY_WEB
1255    Widget_Data *wd = elm_widget_data_get(obj);
1256    if (!wd) return EINA_FALSE;
1257    return wd->tab_propagate;
1258 #else
1259    return EINA_FALSE;
1260 #endif
1261 }
1262
1263 EAPI void
1264 elm_web_tab_propagate_set(Evas_Object *obj, Eina_Bool propagate)
1265 {
1266    ELM_CHECK_WIDTYPE(obj, widtype);
1267 #ifdef HAVE_ELEMENTARY_WEB
1268    Widget_Data *wd = elm_widget_data_get(obj);
1269    if (!wd) return;
1270    wd->tab_propagate = propagate;
1271 #else
1272    (void)propagate;
1273 #endif
1274 }
1275
1276 EAPI Eina_Bool
1277 elm_web_uri_set(Evas_Object *obj, const char *uri)
1278 {
1279    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1280 #ifdef HAVE_ELEMENTARY_WEB
1281    Widget_Data *wd = elm_widget_data_get(obj);
1282    if (!wd) return EINA_FALSE;
1283    return ewk_view_uri_set(wd->ewk_view, uri);
1284 #else
1285    (void)uri;
1286    return EINA_FALSE;
1287 #endif
1288 }
1289
1290 EAPI const char *
1291 elm_web_uri_get(const Evas_Object *obj)
1292 {
1293    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1294 #ifdef HAVE_ELEMENTARY_WEB
1295    Widget_Data *wd = elm_widget_data_get(obj);
1296    if (!wd) return NULL;
1297    return ewk_view_uri_get(wd->ewk_view);
1298 #else
1299    return NULL;
1300 #endif
1301 }
1302
1303 EAPI const char *
1304 elm_web_title_get(const Evas_Object *obj)
1305 {
1306    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1307 #ifdef HAVE_ELEMENTARY_WEB
1308    Widget_Data *wd = elm_widget_data_get(obj);
1309    if (!wd) return NULL;
1310    return ewk_view_title_get(wd->ewk_view);
1311 #else
1312    return NULL;
1313 #endif
1314 }
1315
1316 EAPI void
1317 elm_web_bg_color_set(Evas_Object *obj, int r, int g, int b, int a)
1318 {
1319    ELM_CHECK_WIDTYPE(obj, widtype);
1320 #ifdef HAVE_ELEMENTARY_WEB
1321    Widget_Data *wd = elm_widget_data_get(obj);
1322    if (!wd) return;
1323    ewk_view_bg_color_set(wd->ewk_view, r, g, b, a);
1324 #else
1325    (void)r;
1326    (void)g;
1327    (void)b;
1328    (void)a;
1329 #endif
1330 }
1331
1332 EAPI void
1333 elm_web_bg_color_get(const Evas_Object *obj, int *r, int *g, int *b, int *a)
1334 {
1335    if (r) *r = 0;
1336    if (g) *g = 0;
1337    if (b) *b = 0;
1338    if (a) *a = 0;
1339    ELM_CHECK_WIDTYPE(obj, widtype);
1340 #ifdef HAVE_ELEMENTARY_WEB
1341    Widget_Data *wd = elm_widget_data_get(obj);
1342    if (!wd) return;
1343    return ewk_view_bg_color_get(wd->ewk_view, r, g, b, a);
1344 #endif
1345 }
1346
1347 EAPI char *
1348 elm_web_selection_get(const Evas_Object *obj)
1349 {
1350    ELM_CHECK_WIDTYPE(obj, widtype) NULL;
1351 #ifdef HAVE_ELEMENTARY_WEB
1352    Widget_Data *wd = elm_widget_data_get(obj);
1353    if (!wd) return NULL;
1354    return ewk_view_selection_get(wd->ewk_view);
1355 #else
1356    return NULL;
1357 #endif
1358 }
1359
1360 EAPI void
1361 elm_web_popup_selected_set(Evas_Object *obj, int idx)
1362 {
1363    ELM_CHECK_WIDTYPE(obj, widtype);
1364 #ifdef HAVE_ELEMENTARY_WEB
1365    Widget_Data *wd = elm_widget_data_get(obj);
1366    ewk_view_popup_selected_set(wd->ewk_view, idx);
1367 #else
1368    (void)idx;
1369 #endif
1370 }
1371
1372 EAPI Eina_Bool
1373 elm_web_popup_destroy(Evas_Object *obj)
1374 {
1375    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1376 #ifdef HAVE_ELEMENTARY_WEB
1377    Widget_Data *wd = elm_widget_data_get(obj);
1378    return ewk_view_popup_destroy(wd->ewk_view);
1379 #else
1380    return EINA_FALSE;
1381 #endif
1382 }
1383
1384 EAPI Eina_Bool
1385 elm_web_text_search(const Evas_Object *obj, const char *string, Eina_Bool case_sensitive, Eina_Bool forward, Eina_Bool wrap)
1386 {
1387    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1388 #ifdef HAVE_ELEMENTARY_WEB
1389    Widget_Data *wd = elm_widget_data_get(obj);
1390    if (!wd) return EINA_FALSE;
1391    return ewk_view_text_search
1392      (wd->ewk_view, string, case_sensitive, forward, wrap);
1393 #else
1394    (void)string;
1395    (void)case_sensitive;
1396    (void)forward;
1397    (void)wrap;
1398    return EINA_FALSE;
1399 #endif
1400 }
1401
1402 EAPI unsigned int
1403 elm_web_text_matches_mark(Evas_Object *obj, const char *string, Eina_Bool case_sensitive, Eina_Bool highlight, unsigned int limit)
1404 {
1405    ELM_CHECK_WIDTYPE(obj, widtype) 0;
1406 #ifdef HAVE_ELEMENTARY_WEB
1407    Widget_Data *wd = elm_widget_data_get(obj);
1408    if (!wd) return 0;
1409    return ewk_view_text_matches_mark
1410      (wd->ewk_view, string, case_sensitive, highlight, limit);
1411 #else
1412    (void)string;
1413    (void)case_sensitive;
1414    (void)highlight;
1415    (void)limit;
1416    return 0;
1417 #endif
1418 }
1419
1420 EAPI Eina_Bool
1421 elm_web_text_matches_unmark_all(Evas_Object *obj)
1422 {
1423    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1424 #ifdef HAVE_ELEMENTARY_WEB
1425    Widget_Data *wd = elm_widget_data_get(obj);
1426    if (!wd) return EINA_FALSE;
1427    return ewk_view_text_matches_unmark_all(wd->ewk_view);
1428 #else
1429    return EINA_FALSE;
1430 #endif
1431 }
1432
1433 EAPI Eina_Bool
1434 elm_web_text_matches_highlight_set(Evas_Object *obj, Eina_Bool highlight)
1435 {
1436    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1437 #ifdef HAVE_ELEMENTARY_WEB
1438    Widget_Data *wd = elm_widget_data_get(obj);
1439    if (!wd) return EINA_FALSE;
1440    return ewk_view_text_matches_highlight_set(wd->ewk_view, highlight);
1441 #else
1442    (void)highlight;
1443    return EINA_FALSE;
1444 #endif
1445 }
1446
1447 EAPI Eina_Bool
1448 elm_web_text_matches_highlight_get(const Evas_Object *obj)
1449 {
1450    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1451 #ifdef HAVE_ELEMENTARY_WEB
1452    Widget_Data *wd = elm_widget_data_get(obj);
1453    if (!wd) return EINA_FALSE;
1454    return ewk_view_text_matches_highlight_get(wd->ewk_view);
1455 #else
1456    return EINA_FALSE;
1457 #endif
1458 }
1459
1460 EAPI double
1461 elm_web_load_progress_get(const Evas_Object *obj)
1462 {
1463    ELM_CHECK_WIDTYPE(obj, widtype) -1.0;
1464 #ifdef HAVE_ELEMENTARY_WEB
1465    Widget_Data *wd = elm_widget_data_get(obj);
1466    if (!wd) return -1.0;
1467    return ewk_view_load_progress_get(wd->ewk_view);
1468 #else
1469    return EINA_FALSE;
1470 #endif
1471 }
1472
1473 EAPI Eina_Bool
1474 elm_web_stop(Evas_Object *obj)
1475 {
1476    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1477 #ifdef HAVE_ELEMENTARY_WEB
1478    Widget_Data *wd = elm_widget_data_get(obj);
1479    if (!wd) return EINA_FALSE;
1480    return ewk_view_stop(wd->ewk_view);
1481 #else
1482    return EINA_FALSE;
1483 #endif
1484 }
1485
1486 EAPI Eina_Bool
1487 elm_web_reload(Evas_Object *obj)
1488 {
1489    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1490 #ifdef HAVE_ELEMENTARY_WEB
1491    Widget_Data *wd = elm_widget_data_get(obj);
1492    if (!wd) return EINA_FALSE;
1493    return ewk_view_reload(wd->ewk_view);
1494 #else
1495    return EINA_FALSE;
1496 #endif
1497 }
1498
1499 EAPI Eina_Bool
1500 elm_web_reload_full(Evas_Object *obj)
1501 {
1502    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1503 #ifdef HAVE_ELEMENTARY_WEB
1504    Widget_Data *wd = elm_widget_data_get(obj);
1505    if (!wd) return EINA_FALSE;
1506    return ewk_view_reload_full(wd->ewk_view);
1507 #else
1508    return EINA_FALSE;
1509 #endif
1510 }
1511
1512
1513 EAPI Eina_Bool
1514 elm_web_back(Evas_Object *obj)
1515 {
1516    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1517 #ifdef HAVE_ELEMENTARY_WEB
1518    Widget_Data *wd = elm_widget_data_get(obj);
1519    if (!wd) return EINA_FALSE;
1520    return ewk_view_back(wd->ewk_view);
1521 #else
1522    return EINA_FALSE;
1523 #endif
1524 }
1525
1526 EAPI Eina_Bool
1527 elm_web_forward(Evas_Object *obj)
1528 {
1529    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1530 #ifdef HAVE_ELEMENTARY_WEB
1531    Widget_Data *wd = elm_widget_data_get(obj);
1532    if (!wd) return EINA_FALSE;
1533    return ewk_view_forward(wd->ewk_view);
1534 #else
1535    return EINA_FALSE;
1536 #endif
1537 }
1538
1539 EAPI Eina_Bool
1540 elm_web_navigate(Evas_Object *obj, int steps)
1541 {
1542    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1543 #ifdef HAVE_ELEMENTARY_WEB
1544    Widget_Data *wd = elm_widget_data_get(obj);
1545    if (!wd) return EINA_FALSE;
1546    return ewk_view_navigate(wd->ewk_view, steps);
1547 #else
1548    return EINA_FALSE;
1549    (void)steps;
1550 #endif
1551 }
1552
1553 EAPI Eina_Bool
1554 elm_web_back_possible(Evas_Object *obj)
1555 {
1556    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1557 #ifdef HAVE_ELEMENTARY_WEB
1558    Widget_Data *wd = elm_widget_data_get(obj);
1559    if (!wd) return EINA_FALSE;
1560    return ewk_view_back_possible(wd->ewk_view);
1561 #else
1562    return EINA_FALSE;
1563 #endif
1564 }
1565
1566 EAPI Eina_Bool
1567 elm_web_forward_possible(Evas_Object *obj)
1568 {
1569    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1570 #ifdef HAVE_ELEMENTARY_WEB
1571    Widget_Data *wd = elm_widget_data_get(obj);
1572    if (!wd) return EINA_FALSE;
1573    return ewk_view_forward_possible(wd->ewk_view);
1574 #else
1575    return EINA_FALSE;
1576 #endif
1577 }
1578
1579 EAPI Eina_Bool
1580 elm_web_navigate_possible(Evas_Object *obj, int steps)
1581 {
1582    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1583 #ifdef HAVE_ELEMENTARY_WEB
1584    Widget_Data *wd = elm_widget_data_get(obj);
1585    if (!wd) return EINA_FALSE;
1586    return ewk_view_navigate_possible(wd->ewk_view, steps);
1587 #else
1588    return EINA_FALSE;
1589    (void)steps;
1590 #endif
1591 }
1592
1593 EINA_DEPRECATED EAPI Eina_Bool
1594 elm_web_history_enable_get(const Evas_Object *obj)
1595 {
1596    return elm_web_history_enabled_get(obj);
1597 }
1598
1599 EAPI Eina_Bool
1600 elm_web_history_enabled_get(const Evas_Object *obj)
1601 {
1602    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1603 #ifdef HAVE_ELEMENTARY_WEB
1604    Widget_Data *wd = elm_widget_data_get(obj);
1605    if (!wd) return EINA_FALSE;
1606    return ewk_view_history_enable_get(wd->ewk_view);
1607 #else
1608    return EINA_FALSE;
1609 #endif
1610 }
1611
1612 EINA_DEPRECATED EAPI void
1613 elm_web_history_enable_set(Evas_Object *obj, Eina_Bool enable)
1614 {
1615    elm_web_history_enabled_set(obj, enable);
1616 }
1617
1618 EAPI void
1619 elm_web_history_enabled_set(Evas_Object *obj, Eina_Bool enable)
1620 {
1621    ELM_CHECK_WIDTYPE(obj, widtype);
1622 #ifdef HAVE_ELEMENTARY_WEB
1623    Widget_Data *wd = elm_widget_data_get(obj);
1624    if (!wd) return;
1625    ewk_view_history_enable_set(wd->ewk_view, enable);
1626 #else
1627    (void)enable;
1628 #endif
1629 }
1630
1631 //EAPI Ewk_History *ewk_view_history_get(const Evas_Object *obj); // TODO:
1632
1633 EAPI void
1634 elm_web_zoom_set(Evas_Object *obj, double zoom)
1635 {
1636    ELM_CHECK_WIDTYPE(obj, widtype);
1637 #ifdef HAVE_ELEMENTARY_WEB
1638    Widget_Data *wd = elm_widget_data_get(obj);
1639    int vw, vh, cx, cy;
1640    float z = 1.0;
1641    evas_object_geometry_get(wd->ewk_view, NULL, NULL, &vw, &vh);
1642    cx = vw / 2;
1643    cy = vh / 2;
1644    if (zoom > wd->zoom.max)
1645      zoom = wd->zoom.max;
1646    else if (zoom < wd->zoom.min)
1647      zoom = wd->zoom.min;
1648    if (zoom == wd->zoom.current) return;
1649    wd->zoom.current = zoom;
1650    if (wd->zoom.mode == ELM_WEB_ZOOM_MODE_MANUAL)
1651      z = zoom;
1652    else if (wd->zoom.mode == ELM_WEB_ZOOM_MODE_AUTO_FIT)
1653      {
1654         Evas_Object *frame = ewk_view_frame_main_get(wd->ewk_view);
1655         Evas_Coord fw, fh, pw, ph;
1656         if (!ewk_frame_contents_size_get(frame, &fw, &fh))
1657           return;
1658         z = ewk_frame_page_zoom_get(frame);
1659         fw /= z;
1660         fh /= z;
1661         if ((fw > 0) && (fh > 0))
1662           {
1663              ph = (fh * vw) / fw;
1664              if (ph > vh)
1665                {
1666                   pw = (fw * vh) / fh;
1667                   ph = vh;
1668                }
1669              else
1670                pw = vw;
1671              if (fw > fh)
1672                z = (float)pw / fw;
1673              else
1674                z = (float)ph / fh;
1675           }
1676      }
1677    else if (wd->zoom.mode == ELM_WEB_ZOOM_MODE_AUTO_FILL)
1678      {
1679         Evas_Object *frame = ewk_view_frame_main_get(wd->ewk_view);
1680         Evas_Coord fw, fh, pw, ph;
1681         if (!ewk_frame_contents_size_get(frame, &fw, &fh))
1682           return;
1683         z = ewk_frame_page_zoom_get(frame);
1684         fw /= z;
1685         fh /= z;
1686         if ((fw > 0) && (fh > 0))
1687           {
1688              ph = (fh * vw) / fw;
1689              if (ph < vh)
1690                {
1691                   pw = (fw * vh) / fh;
1692                   ph = vh;
1693                }
1694              else
1695                pw = vw;
1696              if (fw > fh)
1697                z = (float)pw / fw;
1698              else
1699                z = (float)ph / fh;
1700           }
1701      }
1702    if (wd->zoom.no_anim)
1703      ewk_view_zoom_set(wd->ewk_view, z, cx, cy);
1704    else
1705      ewk_view_zoom_animated_set(wd->ewk_view, z, _elm_config->zoom_friction,
1706                                 cx, cy);
1707    wd->zoom.no_anim = EINA_FALSE;
1708 #else
1709    (void)zoom;
1710 #endif
1711 }
1712
1713 EAPI double
1714 elm_web_zoom_get(const Evas_Object *obj)
1715 {
1716    ELM_CHECK_WIDTYPE(obj, widtype) -1.0;
1717 #ifdef HAVE_ELEMENTARY_WEB
1718    Widget_Data *wd = elm_widget_data_get(obj);
1719    return wd->zoom.current;
1720 #else
1721    return -1.0;
1722 #endif
1723 }
1724
1725 EAPI void
1726 elm_web_zoom_mode_set(Evas_Object *obj, Elm_Web_Zoom_Mode mode)
1727 {
1728    ELM_CHECK_WIDTYPE(obj, widtype);
1729 #ifdef HAVE_ELEMENTARY_WEB
1730    Widget_Data *wd = elm_widget_data_get(obj);
1731    float tz;
1732    if (mode >= ELM_WEB_ZOOM_MODE_LAST)
1733      return;
1734    if (mode == wd->zoom.mode)
1735      return;
1736    wd->zoom.mode = mode;
1737    tz = wd->zoom.current;
1738    wd->zoom.current = 0.0;
1739    elm_web_zoom_set(obj, tz);
1740 #else
1741    (void)mode;
1742 #endif
1743 }
1744
1745 EAPI Elm_Web_Zoom_Mode
1746 elm_web_zoom_mode_get(const Evas_Object *obj)
1747 {
1748    ELM_CHECK_WIDTYPE(obj, widtype) ELM_WEB_ZOOM_MODE_LAST;
1749 #ifdef HAVE_ELEMENTARY_WEB
1750    Widget_Data *wd = elm_widget_data_get(obj);
1751    return wd->zoom.mode;
1752 #else
1753    return ELM_WEB_ZOOM_MODE_LAST;
1754 #endif
1755 }
1756
1757 EAPI void
1758 elm_web_region_show(Evas_Object *obj, int x, int y, int w __UNUSED__, int h __UNUSED__)
1759 {
1760    ELM_CHECK_WIDTYPE(obj, widtype);
1761 #ifdef HAVE_ELEMENTARY_WEB
1762    Widget_Data *wd = elm_widget_data_get(obj);
1763    Evas_Object *frame = ewk_view_frame_main_get(wd->ewk_view);
1764    int fw, fh, zw, zh, rx, ry;
1765    float zoom;
1766    ewk_frame_contents_size_get(frame, &fw, &fh);
1767    zoom = ewk_frame_page_zoom_get(frame);
1768    zw = fw / zoom;
1769    zh = fh / zoom;
1770    rx = (x * fw) / zw;
1771    ry = (y * fh) / zh;
1772    if (wd->bring_in.animator)
1773      {
1774         ecore_animator_del(wd->bring_in.animator);
1775         wd->bring_in.animator = NULL;
1776      }
1777    ewk_frame_scroll_set(frame, rx, ry);
1778 #else
1779    (void)x;
1780    (void)y;
1781 #endif
1782 }
1783
1784 EAPI void
1785 elm_web_region_bring_in(Evas_Object *obj, int x, int y, int w __UNUSED__, int h __UNUSED__)
1786 {
1787    ELM_CHECK_WIDTYPE(obj, widtype);
1788 #ifdef HAVE_ELEMENTARY_WEB
1789    Widget_Data *wd = elm_widget_data_get(obj);
1790    Evas_Object *frame = ewk_view_frame_main_get(wd->ewk_view);
1791    int fw, fh, zw, zh, rx, ry, sx, sy;
1792    float zoom;
1793    ewk_frame_contents_size_get(frame, &fw, &fh);
1794    ewk_frame_scroll_pos_get(frame, &sx, &sy);
1795    zoom = ewk_frame_page_zoom_get(frame);
1796    zw = fw / zoom;
1797    zh = fh / zoom;
1798    rx = (x * fw) / zw;
1799    ry = (y * fh) / zh;
1800    if ((wd->bring_in.end.x == rx) && (wd->bring_in.end.y == ry))
1801      return;
1802    wd->bring_in.start.x = sx;
1803    wd->bring_in.start.y = sy;
1804    wd->bring_in.end.x = rx;
1805    wd->bring_in.end.y = ry;
1806    if (wd->bring_in.animator)
1807      ecore_animator_del(wd->bring_in.animator);
1808    wd->bring_in.animator = ecore_animator_timeline_add(
1809       _elm_config->bring_in_scroll_friction, _bring_in_anim_cb, wd);
1810 #else
1811    (void)x;
1812    (void)y;
1813 #endif
1814 }
1815
1816 EAPI void
1817 elm_web_inwin_mode_set(Evas_Object *obj, Eina_Bool value)
1818 {
1819    ELM_CHECK_WIDTYPE(obj, widtype);
1820 #ifdef HAVE_ELEMENTARY_WEB
1821    Widget_Data *wd = elm_widget_data_get(obj);
1822
1823    wd->inwin_mode = value;
1824 #else
1825    (void)value;
1826 #endif
1827 }
1828
1829 EAPI Eina_Bool
1830 elm_web_inwin_mode_get(const Evas_Object *obj)
1831 {
1832    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
1833 #ifdef HAVE_ELEMENTARY_WEB
1834    Widget_Data *wd = elm_widget_data_get(obj);
1835
1836    return wd->inwin_mode;
1837 #else
1838    return EINA_FALSE;
1839 #endif
1840 }
1841
1842 EAPI void
1843 elm_web_window_features_ref(Elm_Web_Window_Features *wf)
1844 {
1845 #ifdef HAVE_ELEMENTARY_WEB
1846    ewk_window_features_ref((Ewk_Window_Features *)wf);
1847 #else
1848    (void)wf;
1849 #endif
1850 }
1851
1852 EAPI void
1853 elm_web_window_features_unref(Elm_Web_Window_Features *wf)
1854 {
1855 #ifdef HAVE_ELEMENTARY_WEB
1856    ewk_window_features_unref((Ewk_Window_Features *)wf);
1857 #else
1858    (void)wf;
1859 #endif
1860 }
1861
1862 EAPI void
1863 elm_web_window_features_bool_property_get(const Elm_Web_Window_Features *wf, Eina_Bool *toolbar_visible, Eina_Bool *statusbar_visible, Eina_Bool *scrollbars_visible, Eina_Bool *menubar_visible, Eina_Bool *locationbar_visible, Eina_Bool *fullscreen)
1864 {
1865 #ifdef HAVE_ELEMENTARY_WEB
1866    ewk_window_features_bool_property_get((const Ewk_Window_Features *)wf,
1867                                          toolbar_visible, statusbar_visible,
1868                                          scrollbars_visible, menubar_visible,
1869                                          locationbar_visible, fullscreen);
1870 #else
1871    (void)wf;
1872    (void)toolbar_visible;
1873    (void)statusbar_visible;
1874    (void)scrollbars_visible;
1875    (void)menubar_visible;
1876    (void)locationbar_visible;
1877    (void)fullscreen;
1878 #endif
1879 }
1880
1881 EAPI void
1882 elm_web_window_features_int_property_get(const Elm_Web_Window_Features *wf, int *x, int *y, int *w, int *h)
1883 {
1884 #ifdef HAVE_ELEMENTARY_WEB
1885    ewk_window_features_int_property_get((const Ewk_Window_Features *)wf,
1886                                         x, y, w, h);
1887 #else
1888    (void)wf;
1889    (void)x;
1890    (void)y;
1891    (void)w;
1892    (void)h;
1893 #endif
1894 }
1895
1896 // TODO: use all ewk_view_zoom stuff to implement bring-in and animated zoom like elm_photocam. Should be simple to use, must not expose every single bit to users!