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