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