viking

webkit based web browser for Enlightenment
Log | Files | Refs | LICENSE

commit d021f36b29eb5e3c7ba2da4ca86f6836cb38d25e
parent 033b63a01f222e13c91cc297917fae8b10c240f9
Author: Kyle Milz <kmilz@ucalgary.ca>
Date:   Tue, 16 Oct 2012 18:19:16 -0600

make two new source files window and buffer

put all of the window related setup and callbacks into one file and all
the buffer related setup and callbacks into another. also merge some
callbacks into the main function.

also fix some Eina_Bool errors.

Diffstat:
Msrc/Makefile | 2+-
Asrc/buffer.c | 715+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/buffer.h | 3+++
Dsrc/callbacks.c | 1106-------------------------------------------------------------------------------
Dsrc/callbacks.h | 12------------
Msrc/commands.c | 1+
Msrc/main.c | 137+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/utilities.c | 256-------------------------------------------------------------------------------
Msrc/utilities.h | 2--
Asrc/window.c | 514+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/window.h | 6++++++
11 files changed, 1375 insertions(+), 1379 deletions(-)

diff --git a/src/Makefile b/src/Makefile @@ -1,7 +1,7 @@ TARGET = viking # Objectfiles, needed for $(TARGET) -OBJ = main.o utilities.o commands.o jsmn.o viking_state.o callbacks.o +OBJ = main.o utilities.o commands.o jsmn.o viking_state.o window.o buffer.o # Manpages MAN1 = evi2.1 MAN5 = evirc.5 diff --git a/src/buffer.c b/src/buffer.c @@ -0,0 +1,715 @@ + +#include <Elementary.h> +#include <EWebKit2.h> +#include <libsoup/soup.h> + +#include "viking_state.h" +#include "viking.h" +#include "javascript.h" +#include "utilities.h" +#include "commands.h" +#include "window.h" +#include "buffer.h" + + +static Eina_Bool process_keypress(void *, Window_Data*); +Eina_Bool download_gui_update(void *data); + + +static void +webprocess_crashed_cb(void *data, Evas_Object *obj, void *event_info) +{ + Window_Data *wd = data; + Eina_Bool *handled = event_info; + + const char html[] = "\ +<html>\ + <head>\ + <style type=\"text/css\">\ + body {\ + background-color: #660000;\ + color: white;\ + font-family: monospace;\ + font-size: 36px;\ + position: absolute;\ + top: 50%;\ + }\ + </style>\ + </head>\ + <body>\ + <h1>\ + Uh oh web process crashed!\ + </h1>\ + </body>\ +</html>"; + + ewk_view_html_string_load(wd->cur_buf->view, html, NULL, ewk_view_url_get(wd->cur_buf->view)); + *handled = EINA_TRUE; +} + +/* +static void +webview_create_window_cb(void *data, Evas_Object *obj, Eina_Bool js, const Elm_Web_Window_Features *wf) +{ + Arg a; + Window_Data *wd = data; + + buffer_add(&a, wd); +} +*/ + +Eina_Bool +download_gui_update(void *data) +{ + Eina_List *l; + void *list_data; + Window_Data *wd = data; + App_Data *ad = wd->app; + unsigned int dl_count = eina_list_count(ad->downloads); + + char *tmp = strdup_printf("<font=Monospace font_size=11 color=#FFF>%i DL", eina_list_count(ad->downloads)); + + /* downloads is a global thing, update all windows with information */ + EINA_LIST_FOREACH(ad->windows, l, list_data) { + Window_Data *wd_tmp = list_data; + + if (dl_count == 0) { + evas_object_size_hint_weight_set(wd_tmp->downloads, 0.0, 0.0); + } + else { + evas_object_size_hint_weight_set(wd_tmp->downloads, EVAS_HINT_EXPAND, 0.0); + elm_object_text_set(wd_tmp->downloads, tmp); + } + } + + free(tmp); + return EINA_TRUE; +} + +static void +download_request_cb(void *data, Evas_Object *obj, void *event_info) +{ + Window_Data *wd = data; + App_Data *ad = wd->app; + + Ewk_Download_Job *dl = event_info; + + const char *suggested_name = ewk_download_job_suggested_filename_get(dl); + char *full_path = strdup_printf("%s/%s", getenv("HOME"), suggested_name); + ewk_download_job_destination_set(dl, full_path); + free(full_path); + + ewk_download_job_ref(dl); + ad->downloads = eina_list_append(ad->downloads, dl); + + if (eina_list_count(ad->downloads) == 1) + ad->download_gui_timer = ecore_timer_loop_add(1, download_gui_update, wd); + + download_gui_update(wd); +} + +static void +download_remove(Window_Data *wd, Ewk_Download_Job *dl) +{ + App_Data *ad = wd->app; + + ewk_download_job_unref(dl); + ad->downloads = eina_list_remove(ad->downloads, dl); + + if (eina_list_count(ad->downloads) == 0) + ecore_timer_del(ad->download_gui_timer); + + download_gui_update(wd); +} + +static void +download_finished_cb(void *data, Evas_Object *obj, void *event_info) +{ + Window_Data *wd = data; + Ewk_Download_Job *dl = event_info; + + download_remove(wd, dl); +} + +static void +download_failed_cb(void *data, Evas_Object *obj, void *event_info) +{ + Arg a; + Window_Data *wd = data; + Ewk_Download_Job_Error *err = event_info; + Ewk_Download_Job *dl = err->download_job; + + a.i = Error; + a.s = strdup_printf("download of %s failed!", + ewk_download_job_suggested_filename_get(dl)); + echo(&a, wd); + free(a.s); + + download_remove(wd, dl); +} + +static void +download_cancelled_cb(void *data, Evas_Object *obj, void *event_info) +{ + Arg a; + Window_Data *wd = data; + Ewk_Download_Job *dl = event_info; + + a.i = Info; + a.s = strdup_printf("download %s cancelled", ewk_download_job_suggested_filename_get(dl)); + echo(&a, wd); + free(a.s); + + download_remove(wd, dl); +} + +static void +title_changed_cb(void *data, Evas_Object *obj, void *event_info) +{ + Buffer_Data *bd = data; + Window_Data *wd = bd->window; + const char *title = event_info; + char buf[128] = ""; + + if (title) + strncpy(buf, title, sizeof(buf) - 1); + + elm_win_title_set(wd->win, buf); +} + +static void +load_progress_cb(void *data, Evas_Object *obj, void *event_info) +{ + Buffer_Data *td = data; + Window_Data *wd = td->window; + double *val = event_info; + + elm_progressbar_value_set(wd->progress_bar, *val); + + /* + if (*val == 1.0) + evas_object_hide(wd->progress_bar); + else + evas_object_show(wd->progress_bar); + */ +} + +static void +inspector_cb(void *data, Evas_Object *obj, void *event_info) +{ + printf("inspector_cb()\n"); + /* + Buffer_Data *bd = data; + Window_Data *wd = bd->window; + + bd->web_inspector = ewk_view_add(evas_object_evas_get(wd->win)); + ewk_view_theme_set(bd->web_inspector, "/usr/share/ewebkit-0/themes/default.edj"); + + evas_object_size_hint_weight_set(bd->web_inspector, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(bd->web_inspector, EVAS_HINT_FILL, EVAS_HINT_FILL); + + ewk_view_web_inspector_view_set(bd->view, bd->web_inspector); + + evas_object_show(bd->web_inspector); + elm_box_pack_end(wd->web_inspector, bd->web_inspector); + + evas_object_size_hint_weight_set(wd->web_inspector, EVAS_HINT_EXPAND, 0.66); + evas_object_show(wd->web_inspector); + */ +} + +static void +inspector_close_cb(void *data, Evas_Object *obj, void *event_info) +{ + printf("inspector_close_cb()\n"); + /* + Buffer_Data *bd = data; + Window_Data *wd = bd->window; + + elm_box_clear(wd->web_inspector); + evas_object_size_hint_weight_set(wd->web_inspector, EVAS_HINT_EXPAND, 0.0); + ewk_view_web_inspector_view_set(bd->view, NULL); + + bd->web_inspector = NULL; + */ +} + +static void +uri_changed_cb(void *data, Evas_Object *obj, void *event_info) +{ + // Arg a = { .i = Silent, .s = strdup(JS_SETUP_HINTS) }; + Buffer_Data *bd = data; + const char *uri = event_info; + // int i; + + if (bd != bd->window->cur_buf) + return; + + // userscript_hooks_start(elm_web_uri_get(td->web)); + + // script(&a, bd->window); + // free(a.s); + + if (bd->window->mode == ModeInsert || bd->window->mode == ModeHints) { + Arg a = { .i = ModeNormal }; + set(&a, bd->window); + } + + bd->window->manual_focus = EINA_FALSE; + update_url(uri, bd->window); +} + +static void +load_finished_cb(void *data, Evas_Object *obj, void *event_info) +{ + /* WebKitWebSettings *settings = webkit_web_view_get_settings(webview); */ + Buffer_Data *bd = data; + Window_Data *wd = bd->window; + Eina_Bool scripts = 1; + // Ewk_Frame_Load_Error *frame_error = event_info; + + // if (frame_error) + // return; + + /* g_object_get(settings, "enable-scripts", &scripts, NULL); */ + /* TRUE will disable automatic focusing of input fields via Javascript*/ + static Eina_Bool escape_input_on_load = EINA_TRUE; + if (escape_input_on_load && scripts && !wd->manual_focus && !elm_object_focus_get(wd->url)) { + Arg a = { .i = Silent, .s = strdup("hints.clearFocus();") }; + script(&a, wd); + free(a.s); + a.i = ModeNormal; + a.s = NULL; + set(&a, wd); + } + + update_state(wd); + + // userscript_hooks_end(elm_web_uri_get(td->web)); + + elm_object_focus_set(elm_object_top_widget_get(wd->win), EINA_FALSE); + evas_object_focus_set(bd->view, EINA_TRUE); +} + +static void +load_error_cb(void *data, Evas_Object *obj, void *event_info) +{ + /* + char *contents; + Ewk_Frame_Load_Error *error = event_info; + + if (error->is_cancellation) + return; + + contents = strdup_printf("<html>\ + <head>\ + <style> h1 { color: blue; } </style>\ + </head>\ + <body>\ + <h1>Error %i</h1>\ + <h2>%s</h2>\ + <h2>%s</h2>\ + </body></html>", + error->code, error->failing_url, error->description); + + ewk_frame_contents_set(error->frame, contents, strlen(contents) - 1, + "text/html", "UTF-8", NULL); + free(contents);\ + */ +} + +static Eina_Bool +process_keypress(void *event_info, Window_Data *wd) +{ + Key key, *inc_key; + App_Data *ad = wd->app; + Evas_Event_Key_Down *ev = event_info; + Eina_List *l; + + EINA_LIST_FOREACH(ad->keylistroot, l, inc_key) { + /* avoid lots of dereferences */ + key = *inc_key; + if ((key.mask == 0 || evas_key_modifier_is_set(ev->modifiers, key.mask)) + && (key.modkey == wd->current_modkey + || (!key.modkey && !wd->current_modkey) + || key.modkey == '*' ) // wildcard + && !strcmp(key.key, ev->key) + && key.func) + if (key.func(&key.arg, wd)) { + wd->current_modkey = wd->count = 0; + update_state(wd); + return EINA_TRUE; + } + } + return EINA_FALSE; +} + +static void +webview_keypress_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Arg a = { .i = ModeNormal, .s = NULL }; + // int keyval; + Evas_Event_Key_Down *ev = event_info; + Buffer_Data *td = data; + Window_Data *wd = td->window; + App_Data *ad = wd->app; + // GdkModifierType irrelevant; + + /* Get a mask of modifiers that shouldn't be considered for this event. + * E.g.: It shouldn't matter whether ';' is shifted or not. */ + // gdk_keymap_translate_keyboard_state(keymap, event->hardware_keycode, + // event->state, event->group, &keyval, NULL, NULL, &irrelevant); + + switch (wd->mode) { + case ModeNormal: + // if ((CLEAN(event->state) & ~irrelevant) == 0) { + if (IS_ESCAPE(ev)) { + a.i = Info; + a.s = strdup(""); + echo(&a, wd); + elm_box_clear(wd->event_box); + evas_object_hide(wd->event_box); + free(a.s); + } else if (wd->current_modkey == 0 && + (( strcmp(ev->key, "1") >= 0 && strcmp(ev->key, "9") <= 0) + || (!strcmp(ev->key, "0") && wd->count))) { + // ad->count = (ad->count ? ad->count * 10 : 0) + (ev->key - "0"); + wd->count = (wd->count ? wd->count * 10 : 0) + atoi(ev->key); + update_state(wd); + return; + } else if (strchr(ad->modkeys, ev->key[0]) && wd->current_modkey != ev->key[0]) { + wd->current_modkey = ev->key[0]; + // ad->current_modkey = strdup(ev->key); + + update_state(wd); + return; + } + // } + /* keybindings */ + if (process_keypress(event_info, wd) == EINA_TRUE) return; + + break; + case ModeInsert: + if (IS_ESCAPE(ev)) { + a.i = Silent; + a.s = strdup("hints.clearFocus();"); + script(&a, wd); + free(a.s); + a.i = ModeNormal; + set(&a, wd); + // ewk_view_input_method_state_set(td->web, FALSE); + return; + } + case ModePassThrough: + if (IS_ESCAPE(ev)) { + echo(&a, wd); + set(&a, wd); + return; + } + break; + case ModeSendKey: + echo(&a, wd); + set(&a, wd); + break; + } +} + +/* +static void +hoverlink_cb(void *data, Evas_Object *obj, void *event_info) +{ + Buffer_Data *td = data; + const char *uri = ewk_view_uri_get(td->view); + // event_info is a char *link[2] where the first string contains the URL + // and the second the title of the link + char **link = event_info; + // char *markup; + + memset(td->window->rememberedURI, 0, 1024); + if (link && link[0]) { + // markup = g_markup_printf_escaped("<span font=\"%s\">Link: %s</span>", statusfont, link[0]); + // markup = strdup_printf("<font=Monospace font_size=10 color=#FF0>%s", link[0]); + // gtk_label_set_markup(GTK_LABEL(td->app->status_url), markup); + // elm_object_text_set(td->app->status_url, markup); + update_url(link[0], td->window); + strcpy(td->window->rememberedURI, link[0]); + // free(markup); + } else + update_url(uri, td->window); +} + +static void +hoverlink_out_cb(void *data, Evas_Object *obj, void *event_info) +{ + Buffer_Data *td = data; + update_url(ewk_view_uri_get(td->view), td->window); +} + +static void +console_cb(void *data, Evas_Object *obj, const char *message, unsigned int line, const char *source) +{ + Arg a; + Buffer_Data *td = data; + + // Don't change internal mode if the browser doesn't have focus to prevent inconsistent states + // if (gtk_window_has_toplevel_focus(window)) { + if (elm_object_focus_get(td->window->win)) { + if (!strcmp(message, "hintmode_off") || !strcmp(message, "insertmode_off")) { + a.i = ModeNormal; + set(&a, td->window); + return; + } else if (!strcmp(message, "insertmode_on")) { + a.i = ModeInsert; + set(&a, td->window); + return; + } + } +} +*/ + +static void +icon_changed_cb(void *data, Evas_Object *obj, void *event_info) +{ + printf("icon_changed()\n"); +} + +static void +webview_free_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Buffer_Data *bd = data; + Window_Data *wd = bd->window; + elm_naviframe_item_pop(wd->naviframe); + + if (!wd->app->exiting) + wd->cur_buf->view = NULL; + + wd->buffer_list = eina_list_remove(wd->buffer_list, bd); + + if (eina_list_count(wd->buffer_list)) { + buffer_current_set(eina_list_nth(wd->buffer_list, 0)); + } + + free(bd); +} + +/* +static void +inputmethod_changed_cb(void *data, Evas_Object *obj, void *event_info) +{ + const char *value = NULL; + Eina_Bool *enabled = event_info; + Buffer_Data *bd = data; + Window_Data *wd = bd->window; + // Evas_Object *frame = ewk_view_frame_main_get(bd->view); + + printf("inputmethod_changed()\n"); + + if (wd->mode == ModeNormal && enabled) { + Arg a = { .i = ModeInsert }; + set(&a, wd); + wd->manual_focus = TRUE; + } else if (wd->mode == ModeInsert && !enabled) { + Arg a = { .i = ModeNormal }; + set(&a, wd); + } else { + // char *value = NULL, *message = NULL; + // jsapi_evaluate_script("window.getSelection().focusNode", &value, &message, ad); + // value = ewk_frame_script_execute(frame, "window.getSelection().focusNode"); + if (value && !strcmp(value, "[object HTMLFormElement]")) { + Arg a = { .i = ModeInsert, .s = NULL }; + set(&a, wd); + wd->manual_focus = TRUE; + } + // free(value); + eina_stringshare_del(value); + // free(message); + } +} + +static void +// notify_event_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) { +notify_event_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + int i; + // WebKitHitTestResult *result; + // WebKitHitTestResultContext context; + Ewk_Hit_Test *result; + Ewk_Hit_Test_Result_Context context; + + Evas_Event_Mouse_Up *ev = event_info; + Buffer_Data *td = data; + App_Data *ad = td->app; + + Evas_Object *view = elm_web_webkit_view_get(td->web); + Evas_Object *frame = ewk_view_frame_main_get(view); + + // if (mode == ModeNormal && event->type == GDK_BUTTON_RELEASE) { + if (ad->mode == ModeNormal) { + // handle mouse click events + for (i = 0; i < LENGTH(mouse); i++) { + // if (mouse[i].mask == CLEAN(event->button.state) + if ( (mouse[i].mask == 0 || evas_key_modifier_is_set(ev->modifiers, mouse[i].mask)) + // && (mouse[i].modkey == current_modkey + && ((ad->current_modkey && !strcmp(mouse[i].modkey, ad->current_modkey)) + || (!mouse[i].modkey && !ad->current_modkey) + // || mouse[i].modkey == GDK_VoidSymbol) // wildcard + || !strcmp(mouse[i].modkey, "*")) // wildcard + // && mouse[i].button == event->button.button + && (mouse[i].button & ev->button) + && mouse[i].func) { + if (mouse[i].func(&mouse[i].arg, ad)) { + // current_modkey = count = 0; + ad->current_modkey = NULL; + ad->count = 0; + update_state(ad); + return TRUE; + } + } + } + // result = webkit_web_view_get_hit_test_result(WEBKIT_WEB_VIEW(widget), (GdkEventButton*)event); + result = ewk_frame_hit_test_new(frame, ev->canvas.x, ev->canvas.y); + context = result->context; + + // g_object_get(result, "context", &context, NULL); + // if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE) { + if (context & EWK_HIT_TEST_RESULT_CONTEXT_EDITABLE) { + Arg a = { .i = ModeInsert }; + set(&a, ad); + ad->manual_focus = TRUE; + } + // } else if (mode == ModeInsert && event->type == GDK_BUTTON_RELEASE) { + } else if (ad->mode == ModeInsert) { + //result = webkit_web_view_get_hit_test_result(WEBKIT_WEB_VIEW(widget), (GdkEventButton*)event); + result = ewk_frame_hit_test_new(frame, ev->output.x, ev->output.y); + + // g_object_get(result, "context", &context, NULL); + // if (!(context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE)) { + if (!(context & EWK_HIT_TEST_RESULT_CONTEXT_EDITABLE)) { + Arg a = { .i = ModeNormal }; + set(&a, ad); + } + } else { + char *value = NULL, *message = NULL; + jsapi_evaluate_script("window.getSelection().focusNode", &value, &message, ad); + if (value && !strcmp(value, "[object HTMLFormElement]")) { + Arg a = { .i = ModeInsert, .s = NULL }; + set(&a, ad); + ad->manual_focus = TRUE; + } + free(value); + free(message); + } + ewk_frame_hit_test_free(result); + return FALSE; +} + +static void +webview_mousewheel_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Buffer_Data *bd = data; + update_state(bd->window); +} +*/ + +Buffer_Data* +buffer_add(const unsigned char flags, Window_Data *wd, const char *url, Session_Item *session_item) +{ + Buffer_Data *bd; + Ewk_Settings *settings; + + bd = calloc(1, sizeof(Buffer_Data)); + if (!bd) return NULL; + + /* if the InNewWindow flag is set, create the buffer in a new window */ + if (flags & InNewWindow) + wd = window_add(wd->app, NULL); + + wd->buf_total++; + wd->buffer_list = eina_list_append(wd->buffer_list, bd); + + bd->window = wd; + bd->buf_number = wd->buf_total; + bd->inspector_enabled = EINA_FALSE; + bd->proxy_enabled = EINA_FALSE; + bd->cookies_enabled = EINA_FALSE; + bd->view = ewk_view_add(evas_object_evas_get(wd->win)); + ewk_view_theme_set(bd->view, "/usr/share/ewebkit-0/themes/default.edj"); + + settings = ewk_view_settings_get(bd->view); + ewk_settings_dns_prefetching_enabled_set(settings, EINA_TRUE); + ewk_settings_developer_extras_enabled_set(settings, EINA_TRUE); + + evas_object_size_hint_weight_set(bd->view, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(bd->view, EVAS_HINT_FILL, EVAS_HINT_FILL); + + elm_naviframe_item_simple_push(wd->naviframe, bd->view); + + /* + if (wd->cur_buf) + bd->elm_obj = elm_naviframe_item_insert_after(wd->naviframe, + wd->cur_buf->elm_obj, + NULL, + NULL, + NULL, + bd->view, + NULL); + else + bd->elm_obj = elm_naviframe_item_simple_push(wd->naviframe, bd->view); + */ + + Evas_Object *v = bd->view; + + // elm_web_window_create_hook_set(td->web, webview_create_window_cb, td->window); + // elm_web_console_message_hook_set(td->web, webview_console_cb, td); + evas_object_smart_callback_add(v, "webprocess,crashed", webprocess_crashed_cb, wd); + + /* downloads */ + evas_object_smart_callback_add(v, "download,request", download_request_cb, wd); + evas_object_smart_callback_add(v, "download,finished", download_finished_cb, wd); + evas_object_smart_callback_add(v, "download,failed", download_failed_cb, wd); + evas_object_smart_callback_add(v, "download,cancelled", download_cancelled_cb, wd); + + /* navigation */ + evas_object_smart_callback_add(v, "title,changed", title_changed_cb, bd); + evas_object_smart_callback_add(v, "uri,changed", uri_changed_cb, bd); + evas_object_smart_callback_add(v, "load,progress", load_progress_cb, bd); + evas_object_smart_callback_add(v, "load,finished", load_finished_cb, bd); + evas_object_smart_callback_add(v, "load,error", load_error_cb, bd); + + /* other */ + evas_object_smart_callback_add(v, "inspector,view,create", inspector_cb, bd); + evas_object_smart_callback_add(v, "inspector,view,close", inspector_close_cb, bd); + evas_object_smart_callback_add(v, "icon,changed", icon_changed_cb, bd); + + /* not yet implemented in ewebkit */ + // evas_object_smart_callback_add(v, "link,hover,in", hoverlink_cb, td); + // evas_object_smart_callback_add(v, "link,hover,out",hoverlink_out_cb, td); + // evas_object_smart_callback_add(v, "inputmethod,changed", inputmethod_changed_cb, td); + + /* evas events */ + evas_object_event_callback_add(v, EVAS_CALLBACK_FREE, webview_free_cb, bd); + evas_object_event_callback_add(v, EVAS_CALLBACK_KEY_DOWN, webview_keypress_cb, bd); + // evas_object_event_callback_add(v, EVAS_CALLBACK_MOUSE_UP, notify_event_cb, bd); + // evas_object_event_callback_add(v, EVAS_CALLBACK_MOUSE_WHEEL, webview_mousewheel_cb, bd); + + if (url) + ewk_view_url_set(bd->view, url); + else + ewk_view_url_set(bd->view, config_home_page_get(wd->app->config)); + + if (flags & SwitchToBuffer) + buffer_current_set(bd); + + if (!session_item) { + if (!(session_item = session_item_new(ewk_view_url_get(bd->view), EINA_FALSE, 0, 0))) + CRITICAL("Could not create session object"); + session_window_tabs_add(wd->session_window, session_item); + } + + evas_object_data_set(bd->view, "session", session_item); + evas_object_data_set(bd->view, "buffer_data", bd); + evas_object_show(bd->view); + + return bd; +} + diff --git a/src/buffer.h b/src/buffer.h @@ -0,0 +1,3 @@ + +Buffer_Data* buffer_add(const unsigned char, Window_Data *, const char *, Session_Item *); + diff --git a/src/callbacks.c b/src/callbacks.c @@ -1,1106 +0,0 @@ - -#include <Elementary.h> -#include <EWebKit2.h> -#include <libsoup/soup.h> - -#include "viking_state.h" -#include "viking.h" -#include "utilities.h" -#include "javascript.h" -#include "commands.h" -#include "callbacks.h" - - -static Eina_Bool commandhistoryfetch(const Arg *, void *); -static Eina_Bool process_keypress(void *, Window_Data*); -Eina_Bool download_gui_update(void *data); - - -#define IS_ESCAPE(ev) ((!strcmp(ev->keyname, "Escape")) || \ - (!strcmp(ev->keyname, "[") && evas_key_modifier_is_set(ev->modifiers, "Control"))) - - -static void -title_changed_cb(void *data, Evas_Object *obj, void *event_info) -{ - Buffer_Data *bd = data; - Window_Data *wd = bd->window; - const char *title = event_info; - char buf[128] = ""; - - if (title) - strncpy(buf, title, sizeof(buf) - 1); - - elm_win_title_set(wd->win, buf); -} - -static void -load_progress_cb(void *data, Evas_Object *obj, void *event_info) -{ - Buffer_Data *td = data; - Window_Data *wd = td->window; - double *val = event_info; - - elm_progressbar_value_set(wd->progress_bar, *val); - - /* - if (*val == 1.0) - evas_object_hide(wd->progress_bar); - else - evas_object_show(wd->progress_bar); - */ -} - -static void -load_error_cb(void *data, Evas_Object *obj, void *event_info) -{ - /* - char *contents; - Ewk_Frame_Load_Error *error = event_info; - - if (error->is_cancellation) - return; - - contents = strdup_printf("<html>\ - <head>\ - <style> h1 { color: blue; } </style>\ - </head>\ - <body>\ - <h1>Error %i</h1>\ - <h2>%s</h2>\ - <h2>%s</h2>\ - </body></html>", - error->code, error->failing_url, error->description); - - ewk_frame_contents_set(error->frame, contents, strlen(contents) - 1, - "text/html", "UTF-8", NULL); - free(contents);\ - */ -} - -static void -inspector_cb(void *data, Evas_Object *obj, void *event_info) -{ - printf("inspector_cb()\n"); - /* - Buffer_Data *bd = data; - Window_Data *wd = bd->window; - - bd->web_inspector = ewk_view_add(evas_object_evas_get(wd->win)); - ewk_view_theme_set(bd->web_inspector, "/usr/share/ewebkit-0/themes/default.edj"); - - evas_object_size_hint_weight_set(bd->web_inspector, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_size_hint_align_set(bd->web_inspector, EVAS_HINT_FILL, EVAS_HINT_FILL); - - ewk_view_web_inspector_view_set(bd->view, bd->web_inspector); - - evas_object_show(bd->web_inspector); - elm_box_pack_end(wd->web_inspector, bd->web_inspector); - - evas_object_size_hint_weight_set(wd->web_inspector, EVAS_HINT_EXPAND, 0.66); - evas_object_show(wd->web_inspector); - */ -} - -static void -inspector_close_cb(void *data, Evas_Object *obj, void *event_info) -{ - printf("inspector_close_cb()\n"); - /* - Buffer_Data *bd = data; - Window_Data *wd = bd->window; - - elm_box_clear(wd->web_inspector); - evas_object_size_hint_weight_set(wd->web_inspector, EVAS_HINT_EXPAND, 0.0); - ewk_view_web_inspector_view_set(bd->view, NULL); - - bd->web_inspector = NULL; - */ -} - -static void -uri_changed_cb(void *data, Evas_Object *obj, void *event_info) -{ - // Arg a = { .i = Silent, .s = strdup(JS_SETUP_HINTS) }; - Buffer_Data *bd = data; - const char *uri = event_info; - // int i; - - if (bd != bd->window->cur_buf) - return; - - // userscript_hooks_start(elm_web_uri_get(td->web)); - - // script(&a, bd->window); - // free(a.s); - - if (bd->window->mode == ModeInsert || bd->window->mode == ModeHints) { - Arg a = { .i = ModeNormal }; - set(&a, bd->window); - } - - bd->window->manual_focus = EINA_FALSE; - update_url(uri, bd->window); -} - -static void -load_finished_cb(void *data, Evas_Object *obj, void *event_info) -{ - /* WebKitWebSettings *settings = webkit_web_view_get_settings(webview); */ - Buffer_Data *bd = data; - Window_Data *wd = bd->window; - Eina_Bool scripts = 1; - // Ewk_Frame_Load_Error *frame_error = event_info; - - // if (frame_error) - // return; - - /* g_object_get(settings, "enable-scripts", &scripts, NULL); */ - /* TRUE will disable automatic focusing of input fields via Javascript*/ - static Eina_Bool escape_input_on_load = TRUE; - if (escape_input_on_load && scripts && !wd->manual_focus && !elm_object_focus_get(wd->url)) { - Arg a = { .i = Silent, .s = strdup("hints.clearFocus();") }; - script(&a, wd); - free(a.s); - a.i = ModeNormal; - a.s = NULL; - set(&a, wd); - } - - update_state(wd); - - // userscript_hooks_end(elm_web_uri_get(td->web)); - - elm_object_focus_set(elm_object_top_widget_get(wd->win), EINA_FALSE); - evas_object_focus_set(bd->view, EINA_TRUE); -} - -/* - * Download Callbacks - */ - -Eina_Bool -download_gui_update(void *data) -{ - Eina_List *l; - void *list_data; - Window_Data *wd = data; - App_Data *ad = wd->app; - unsigned int dl_count = eina_list_count(ad->downloads); - - char *tmp = strdup_printf("<font=Monospace font_size=11 color=#FFF>%i DL", eina_list_count(ad->downloads)); - - /* downloads is a global thing, update all windows with information */ - EINA_LIST_FOREACH(ad->windows, l, list_data) { - Window_Data *wd_tmp = list_data; - - if (dl_count == 0) { - evas_object_size_hint_weight_set(wd_tmp->downloads, 0.0, 0.0); - } - else { - evas_object_size_hint_weight_set(wd_tmp->downloads, EVAS_HINT_EXPAND, 0.0); - elm_object_text_set(wd_tmp->downloads, tmp); - } - } - - free(tmp); - return EINA_TRUE; -} - -static void -download_request_cb(void *data, Evas_Object *obj, void *event_info) -{ - Window_Data *wd = data; - App_Data *ad = wd->app; - - Ewk_Download_Job *dl = event_info; - - const char *suggested_name = ewk_download_job_suggested_filename_get(dl); - char *full_path = strdup_printf("%s/%s", getenv("HOME"), suggested_name); - ewk_download_job_destination_set(dl, full_path); - free(full_path); - - ewk_download_job_ref(dl); - ad->downloads = eina_list_append(ad->downloads, dl); - - if (eina_list_count(ad->downloads) == 1) - ad->download_gui_timer = ecore_timer_loop_add(1, download_gui_update, wd); - - download_gui_update(wd); -} - -static void -download_remove(Window_Data *wd, Ewk_Download_Job *dl) -{ - App_Data *ad = wd->app; - - ewk_download_job_unref(dl); - ad->downloads = eina_list_remove(ad->downloads, dl); - - if (eina_list_count(ad->downloads) == 0) - ecore_timer_del(ad->download_gui_timer); - - download_gui_update(wd); -} - -static void -download_finished_cb(void *data, Evas_Object *obj, void *event_info) -{ - Window_Data *wd = data; - Ewk_Download_Job *dl = event_info; - - download_remove(wd, dl); -} - -static void -download_failed_cb(void *data, Evas_Object *obj, void *event_info) -{ - Arg a; - Window_Data *wd = data; - Ewk_Download_Job_Error *err = event_info; - Ewk_Download_Job *dl = err->download_job; - - a.i = Error; - a.s = strdup_printf("download of %s failed!", - ewk_download_job_suggested_filename_get(dl)); - echo(&a, wd); - free(a.s); - - download_remove(wd, dl); -} - -static void -download_cancelled_cb(void *data, Evas_Object *obj, void *event_info) -{ - Arg a; - Window_Data *wd = data; - Ewk_Download_Job *dl = event_info; - - a.i = Info; - a.s = strdup_printf("download %s cancelled", ewk_download_job_suggested_filename_get(dl)); - echo(&a, wd); - free(a.s); - - download_remove(wd, dl); -} - -/* -static void -webview_mousewheel_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) -{ - Buffer_Data *bd = data; - update_state(bd->window); -} -*/ - -Eina_Bool -process_keypress(void *event_info, Window_Data *wd) -{ - Key key, *inc_key; - App_Data *ad = wd->app; - Evas_Event_Key_Down *ev = event_info; - Eina_List *l; - - EINA_LIST_FOREACH(ad->keylistroot, l, inc_key) { - /* avoid lots of dereferences */ - key = *inc_key; - if ((key.mask == 0 || evas_key_modifier_is_set(ev->modifiers, key.mask)) - && (key.modkey == wd->current_modkey - || (!key.modkey && !wd->current_modkey) - || key.modkey == '*' ) // wildcard - && !strcmp(key.key, ev->key) - && key.func) - if (key.func(&key.arg, wd)) { - wd->current_modkey = wd->count = 0; - update_state(wd); - return EINA_TRUE; - } - } - return EINA_FALSE; -} - -static void -webview_keypress_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) -{ - Arg a = { .i = ModeNormal, .s = NULL }; - // int keyval; - Evas_Event_Key_Down *ev = event_info; - Buffer_Data *td = data; - Window_Data *wd = td->window; - App_Data *ad = wd->app; - // GdkModifierType irrelevant; - - /* Get a mask of modifiers that shouldn't be considered for this event. - * E.g.: It shouldn't matter whether ';' is shifted or not. */ - // gdk_keymap_translate_keyboard_state(keymap, event->hardware_keycode, - // event->state, event->group, &keyval, NULL, NULL, &irrelevant); - - switch (wd->mode) { - case ModeNormal: - // if ((CLEAN(event->state) & ~irrelevant) == 0) { - if (IS_ESCAPE(ev)) { - a.i = Info; - a.s = strdup(""); - echo(&a, wd); - elm_box_clear(wd->event_box); - evas_object_hide(wd->event_box); - free(a.s); - } else if (wd->current_modkey == 0 && - (( strcmp(ev->key, "1") >= 0 && strcmp(ev->key, "9") <= 0) - || (!strcmp(ev->key, "0") && wd->count))) { - // ad->count = (ad->count ? ad->count * 10 : 0) + (ev->key - "0"); - wd->count = (wd->count ? wd->count * 10 : 0) + atoi(ev->key); - update_state(wd); - return; - } else if (strchr(ad->modkeys, ev->key[0]) && wd->current_modkey != ev->key[0]) { - wd->current_modkey = ev->key[0]; - // ad->current_modkey = strdup(ev->key); - - update_state(wd); - return; - } - // } - /* keybindings */ - if (process_keypress(event_info, wd) == EINA_TRUE) return; - - break; - case ModeInsert: - if (IS_ESCAPE(ev)) { - a.i = Silent; - a.s = strdup("hints.clearFocus();"); - script(&a, wd); - free(a.s); - a.i = ModeNormal; - set(&a, wd); - // ewk_view_input_method_state_set(td->web, FALSE); - return; - } - case ModePassThrough: - if (IS_ESCAPE(ev)) { - echo(&a, wd); - set(&a, wd); - return; - } - break; - case ModeSendKey: - echo(&a, wd); - set(&a, wd); - break; - } -} - -/* -static void -hoverlink_cb(void *data, Evas_Object *obj, void *event_info) -{ - Buffer_Data *td = data; - const char *uri = ewk_view_uri_get(td->view); - // event_info is a char *link[2] where the first string contains the URL - // and the second the title of the link - char **link = event_info; - // char *markup; - - memset(td->window->rememberedURI, 0, 1024); - if (link && link[0]) { - // markup = g_markup_printf_escaped("<span font=\"%s\">Link: %s</span>", statusfont, link[0]); - // markup = strdup_printf("<font=Monospace font_size=10 color=#FF0>%s", link[0]); - // gtk_label_set_markup(GTK_LABEL(td->app->status_url), markup); - // elm_object_text_set(td->app->status_url, markup); - update_url(link[0], td->window); - strcpy(td->window->rememberedURI, link[0]); - // free(markup); - } else - update_url(uri, td->window); -} - -static void -hoverlink_out_cb(void *data, Evas_Object *obj, void *event_info) -{ - Buffer_Data *td = data; - update_url(ewk_view_uri_get(td->view), td->window); -} - -static void -console_cb(void *data, Evas_Object *obj, const char *message, unsigned int line, const char *source) -{ - Arg a; - Buffer_Data *td = data; - - // Don't change internal mode if the browser doesn't have focus to prevent inconsistent states - // if (gtk_window_has_toplevel_focus(window)) { - if (elm_object_focus_get(td->window->win)) { - if (!strcmp(message, "hintmode_off") || !strcmp(message, "insertmode_off")) { - a.i = ModeNormal; - set(&a, td->window); - return; - } else if (!strcmp(message, "insertmode_on")) { - a.i = ModeInsert; - set(&a, td->window); - return; - } - } -} -*/ - -static void -inputbox_activate_cb(void *data, Evas_Object *obj, void *event_info) -{ - const char *text; - Window_Data *wd = data; - // App_Data *ad = wd->app; - uint16_t length = strlen(elm_entry_entry_get(wd->url)); - Arg a; - Eina_Bool forward = FALSE; - - // printf("In inputbox_activate\n"); - - a.i = HideCompletion; - complete(&a, data); - if (length == 0) - return; - text = elm_entry_entry_get(wd->url); - if (length > 1 && text[0] == ':') { - process_line((text + 1), data); - } else if (length > 1 && ((forward = text[0] == '/') || text[0] == '?')) { - ewk_view_text_find_highlight_clear(wd->cur_buf->view); - - ewk_view_text_find(wd->cur_buf->view, &text[1], - EWK_FIND_OPTIONS_SHOW_HIGHLIGHT | EWK_FIND_OPTIONS_CASE_INSENSITIVE, 1000); - - wd->count = 0; - wd->search_direction = forward; - wd->search_handle = strdup(&text[1]); - } else if (text[0] == '.' || text[0] == ',' || text[0] == ';') { - a.i = Silent; - a.s = strdup("hints.fire();"); - script(&a, data); - free(a.s); - update_state(data); - } else - return; - if (!wd->echo_active) - // gtk_entry_set_text(entry, ""); - elm_entry_entry_set(wd->url, ""); - // gtk_widget_grab_focus(GTK_WIDGET(webview)); - - /* process_line above may have deleted the tab, check if its still around */ - if (wd->cur_buf->view) { - elm_object_focus_set(elm_object_top_widget_get(wd->win), EINA_FALSE); - evas_object_focus_set(wd->cur_buf->view, EINA_TRUE); - } -} - -static Eina_Bool -commandhistoryfetch(const Arg *arg, void *data) -{ - Window_Data *wd = data; - // App_Data *ad = wd->app; - char *command; - const int length = eina_list_count(wd->commandhistory); - - if (length > 0) { - if (arg->i == DirectionPrev) { - wd->commandpointer = (length + wd->commandpointer - 1) % length; - } else { - wd->commandpointer = (length + wd->commandpointer + 1) % length; - } - - command = eina_list_nth(wd->commandhistory, wd->commandpointer); - // gtk_entry_set_text(GTK_ENTRY(inputbox), g_strconcat(":", command, NULL)); - // gtk_editable_set_position(GTK_EDITABLE(inputbox), -1); - command = strdup_printf(":%s", command); - elm_entry_entry_set(wd->url, command); - free(command); - elm_entry_cursor_line_end_set(wd->url); - return TRUE; - } - - return FALSE; -} - -static void -inputbox_keypress_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) -{ - Arg a; - int numval; - Evas_Event_Key_Down *ev = event_info; - Window_Data *wd = data; - // App_Data *ad = wd->app; - - if (wd->mode == ModeHints) { - // if (event->keyval == GDK_ISO_Left_Tab) { - if (!strcmp(ev->keyname, "Tab") && evas_key_modifier_is_set(ev->modifiers, "Shift")) { - a.i = Silent; - a.s = strdup("hints.focusPreviousHint();"); - script(&a, data); - free(a.s); - update_state(data); - return; - } - // if (event->keyval == GDK_Tab) { - if (!strcmp(ev->keyname, "Tab")) { - a.i = Silent; - a.s = strdup("hints.focusNextHint();"); - script(&a, data); - free(a.s); - update_state(data); - return; - } - // if (event->keyval == GDK_Return) { - if (!strcmp(ev->keyname, "Return")) { - a.i = Silent; - a.s = strdup_printf("hints.fire();"); - script(&a, data); - free(a.s); - update_state(data); - return; - } - } - if (!strcmp(ev->keyname, "[") || !strcmp(ev->keyname, "Escape")) { - a.i = HideCompletion; - complete(&a, data); - a.i = ModeNormal; - wd->commandpointer = 0; - set(&a, data); - return; - } - else if (!strcmp(ev->keyname, "Tab") && evas_key_modifier_is_set(ev->modifiers, "Shift")) { - a.i = DirectionPrev; - complete(&a, data); - return; - } - else if (!strcmp(ev->keyname, "Tab")) { - a.i = DirectionNext; - complete(&a, data); - return; - } - else if (!strcmp(ev->keyname, "Up")) { - a.i = DirectionPrev; - commandhistoryfetch(&a, data); - return; - } - else if (!strcmp(ev->keyname, "Down")) { - a.i = DirectionNext; - commandhistoryfetch(&a, data); - return; - } - - /* - switch (event->keyval) { - case GDK_bracketleft: - case GDK_Escape: - if (!IS_ESCAPE(event)) break; - a.i = HideCompletion; - complete(&a, data); - a.i = ModeNormal; - commandpointer = 0; - return set(&a, ad); - break; - case GDK_Tab: - a.i = DirectionNext; - return complete(&a, data); - break; - case GDK_Up: - a.i = DirectionPrev; - return commandhistoryfetch(&a); - break; - case GDK_Down: - a.i = DirectionNext; - return commandhistoryfetch(&a); - break; - case GDK_ISO_Left_Tab: - a.i = DirectionPrev; - return complete(&a, data); - break; - } - */ - - if (wd->mode == ModeHints) { -#if 0 - if ((CLEAN(event->state) & GDK_SHIFT_MASK) && - (CLEAN(event->state) & GDK_CONTROL_MASK) && - (event->keyval == GDK_BackSpace)) { - count /= 10; - a.i = Silent; - a.s = g_strdup_printf("hints.updateHints(%d);", count); - script(&a, data); - g_free(a.s); - update_state(); - return TRUE; - } -#endif - - // numval = g_unichar_digit_value((gunichar) gdk_keyval_to_unicode(event->keyval)); - numval = atoi(ev->key); - if ((numval >= 1 && numval <= 9) || (numval == 0 && wd->count)) { - /* allow a zero as non-first number */ - wd->count = (wd->count ? wd->count * 10 : 0) + numval; - a.i = Silent; - a.s = strdup_printf("hints.updateHints(%d);", wd->count); - script(&a, data); - free(a.s); - update_state(data); - return; - } - } -} - -/* -static void -inputmethod_changed_cb(void *data, Evas_Object *obj, void *event_info) -{ - const char *value = NULL; - Eina_Bool *enabled = event_info; - Buffer_Data *bd = data; - Window_Data *wd = bd->window; - // Evas_Object *frame = ewk_view_frame_main_get(bd->view); - - printf("inputmethod_changed()\n"); - - if (wd->mode == ModeNormal && enabled) { - Arg a = { .i = ModeInsert }; - set(&a, wd); - wd->manual_focus = TRUE; - } else if (wd->mode == ModeInsert && !enabled) { - Arg a = { .i = ModeNormal }; - set(&a, wd); - } else { - // char *value = NULL, *message = NULL; - // jsapi_evaluate_script("window.getSelection().focusNode", &value, &message, ad); - // value = ewk_frame_script_execute(frame, "window.getSelection().focusNode"); - if (value && !strcmp(value, "[object HTMLFormElement]")) { - Arg a = { .i = ModeInsert, .s = NULL }; - set(&a, wd); - wd->manual_focus = TRUE; - } - // free(value); - eina_stringshare_del(value); - // free(message); - } -} - -static void -// notify_event_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) { -notify_event_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) -{ - int i; - // WebKitHitTestResult *result; - // WebKitHitTestResultContext context; - Ewk_Hit_Test *result; - Ewk_Hit_Test_Result_Context context; - - Evas_Event_Mouse_Up *ev = event_info; - Buffer_Data *td = data; - App_Data *ad = td->app; - - Evas_Object *view = elm_web_webkit_view_get(td->web); - Evas_Object *frame = ewk_view_frame_main_get(view); - - // if (mode == ModeNormal && event->type == GDK_BUTTON_RELEASE) { - if (ad->mode == ModeNormal) { - // handle mouse click events - for (i = 0; i < LENGTH(mouse); i++) { - // if (mouse[i].mask == CLEAN(event->button.state) - if ( (mouse[i].mask == 0 || evas_key_modifier_is_set(ev->modifiers, mouse[i].mask)) - // && (mouse[i].modkey == current_modkey - && ((ad->current_modkey && !strcmp(mouse[i].modkey, ad->current_modkey)) - || (!mouse[i].modkey && !ad->current_modkey) - // || mouse[i].modkey == GDK_VoidSymbol) // wildcard - || !strcmp(mouse[i].modkey, "*")) // wildcard - // && mouse[i].button == event->button.button - && (mouse[i].button & ev->button) - && mouse[i].func) { - if (mouse[i].func(&mouse[i].arg, ad)) { - // current_modkey = count = 0; - ad->current_modkey = NULL; - ad->count = 0; - update_state(ad); - return TRUE; - } - } - } - // result = webkit_web_view_get_hit_test_result(WEBKIT_WEB_VIEW(widget), (GdkEventButton*)event); - result = ewk_frame_hit_test_new(frame, ev->canvas.x, ev->canvas.y); - context = result->context; - - // g_object_get(result, "context", &context, NULL); - // if (context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE) { - if (context & EWK_HIT_TEST_RESULT_CONTEXT_EDITABLE) { - Arg a = { .i = ModeInsert }; - set(&a, ad); - ad->manual_focus = TRUE; - } - // } else if (mode == ModeInsert && event->type == GDK_BUTTON_RELEASE) { - } else if (ad->mode == ModeInsert) { - //result = webkit_web_view_get_hit_test_result(WEBKIT_WEB_VIEW(widget), (GdkEventButton*)event); - result = ewk_frame_hit_test_new(frame, ev->output.x, ev->output.y); - - // g_object_get(result, "context", &context, NULL); - // if (!(context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE)) { - if (!(context & EWK_HIT_TEST_RESULT_CONTEXT_EDITABLE)) { - Arg a = { .i = ModeNormal }; - set(&a, ad); - } - } else { - char *value = NULL, *message = NULL; - jsapi_evaluate_script("window.getSelection().focusNode", &value, &message, ad); - if (value && !strcmp(value, "[object HTMLFormElement]")) { - Arg a = { .i = ModeInsert, .s = NULL }; - set(&a, ad); - ad->manual_focus = TRUE; - } - free(value); - free(message); - } - ewk_frame_hit_test_free(result); - return FALSE; -} -*/ - -static void -inputbox_keyrelease_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) -{ - Arg a; - Window_Data *wd = data; - // guint16 length = gtk_entry_get_text_length(entry); - uint16_t length = strlen(elm_entry_entry_get(wd->url)); - - if (!length) { - a.i = HideCompletion; - complete(&a, data); - a.i = ModeNormal; - set(&a, data); - } -} - -/* used for incremental search */ -static void -inputbox_changed_cb(void *data, Evas_Object *obj, void *event_info) -{ - Arg a; - Window_Data *wd = data; - const char *text = elm_entry_entry_get(wd->url); - uint16_t length = strlen(text); - Eina_Bool forward = FALSE; - - /* Update incremental search if the user changes the search text. - * - * Note: gtk_widget_is_focus() is a poor way to check if the change comes - * from the user. But if the entry is focused and the text is set - * through gtk_entry_set_text() in some asyncrounous operation, - * I would consider that a bug. - */ - - if (elm_object_focus_get(wd->url) && length > 1 && ((forward = text[0] == '/') || text[0] == '?')) { - ewk_view_text_find_highlight_clear(wd->cur_buf->view); - ewk_view_text_find(wd->cur_buf->view, &text[1], - EWK_FIND_OPTIONS_SHOW_HIGHLIGHT | EWK_FIND_OPTIONS_CASE_INSENSITIVE, 1000); - return; -} else if (elm_object_focus_get(wd->url) && length >= 1 && - (text[0] == '.' || text[0] == ',' || text[0] == ';')) { - a.i = Silent; - switch (text[0]) { - case '.': - a.s = strdup_printf("hints.createHints('%s', 'f');", text + 1); - break; - - case ',': - a.s = strdup_printf("hints.createHints('%s', 'F');", text + 1); - break; - - case ';': - a.s = NULL; - switch (text[1]) { - case 's': - a.s = strdup_printf("hints.createHints('%s', 's');", text + 2); - break; - case 'y': - a.s = strdup_printf("hints.createHints('%s', 'y');", text + 2); - break; - case 'o': - a.s = strdup_printf("hints.createHints('%s', 'f');", text + 2); - break; - case 't': case 'w': - a.s = strdup_printf("hints.createHints('%s', 'F');", text + 2); - break; - case 'O': case 'T': case 'W': - a.s = strdup_printf("hints.createHints('%s', 'O');", text + 2); - break; - case 'i': - a.s = strdup_printf("hints.createHints('%s', 'i');", text + 2); - break; - case 'I': - a.s = strdup_printf("hints.createHints('%s', 'I');", text + 2); - break; - } - break; - } - wd->count = 0; - if (a.s) { - script(&a, data); - free(a.s); - } - - return; -} else if (length == 0 && wd->followTarget[0]) { - wd->mode = ModeNormal; - a.i = Silent; - a.s = strdup("hints.clearHints();"); - script(&a, data); - free(a.s); - wd->count = 0; - update_state(data); -} -} - - -static void -hist_nav_cb(const Evas_Object *view, Ewk_Navigation_Data *nav_data, void *data) -{ - // printf("logging item to history.\n"); - Hist_Item *item; - App_Data *ad = data; - const char *title = ewk_navigation_data_title_get(nav_data); - const char *url = ewk_navigation_data_url_get(nav_data); - - item = hist_items_get(ad->history, url); - if (item && hist_item_enabled_get(item)) { - hist_item_visit_count_set(item, hist_item_visit_count_get(item) + 1); - hist_item_last_visit_set(item, ecore_time_unix_get()); - hist_item_title_set(item, title); - } - else if (!item && config_enable_history_get(ad->config)) { - hist_items_add(ad->history, url, hist_item_new(EINA_TRUE, title, url, 1, ecore_time_unix_get())); - } -} - -static void -hist_redir_cb(const Evas_Object *vew, const char *source_url, const char *dest_url, void *data) -{ - int prefix, min, suffix, src_len, dest_len; - - src_len = strlen(source_url); - dest_len = strlen(dest_url); - - if (src_len < dest_len) - min = src_len; - else - min = dest_len; - - prefix = 0; - while (source_url[prefix] == dest_url[prefix] && prefix < min) - prefix++; - - suffix = 0; - while (source_url[src_len - suffix - 1] == dest_url[dest_len - suffix - 1] && suffix < min) - suffix++; - - // printf("redir: prefix = %i, suffix = %i, min = %i\n", prefix, suffix, min); - - if (min - suffix - prefix < 0) { - printf("redirecion() from %s to %s\n", source_url, dest_url); - return; - } - - Eina_Strbuf *buf = eina_strbuf_new(); - eina_strbuf_append_n(buf, source_url, prefix); - eina_strbuf_append(buf, "{"); - eina_strbuf_append_n(buf, source_url + prefix, src_len - suffix - prefix); - eina_strbuf_append(buf, " => "); - eina_strbuf_append_n(buf, dest_url + prefix, dest_len - suffix - prefix); - eina_strbuf_append(buf, "}"); - eina_strbuf_append_n(buf, source_url + src_len - suffix, suffix); - - printf("redirection() %s\n", eina_strbuf_string_steal(buf)); - -} - -static void -hist_visited_cb(void *data) -{ - App_Data *ad = data; - void *hash_data; - Eina_Iterator *it = eina_hash_iterator_tuple_new(hist_items_hash_get(ad->history)); - - while (eina_iterator_next(it, &hash_data)) { - Eina_Hash_Tuple *t = hash_data; - Hist_Item *hist_item = t->data; - ewk_context_visited_link_add(ewk_context_default_get(), hist_item_url_get(hist_item)); - } - - eina_iterator_free(it); -} - -static void -hist_title_updated_cb(const Evas_Object *vew, const char *title, const char *url, void *data) -{ - // printf("title_update() %s has new title %s\n", url, title); -} - -static void -webview_free_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) -{ - Buffer_Data *bd = data; - Window_Data *wd = bd->window; - elm_naviframe_item_pop(wd->naviframe); - - if (!wd->app->exiting) - wd->cur_buf->view = NULL; - - wd->buffer_list = eina_list_remove(wd->buffer_list, bd); - - if (eina_list_count(wd->buffer_list)) { - buffer_current_set(eina_list_nth(wd->buffer_list, 0)); - } - - free(bd); -} - -static void -_win_del_request_cb(void *data, Evas_Object *obj, void *event_info) -{ - Window_Data *wd = data; - printf("window requested deletion ..\n"); - - free(wd); -} - -static void -webprocess_crashed_cb(void *data, Evas_Object *obj, void *event_info) -{ - Window_Data *wd = data; - Eina_Bool *handled = event_info; - - const char html[] = "\ -<html>\ - <head>\ - <style type=\"text/css\">\ - body {\ - background-color: #660000;\ - color: white;\ - font-family: monospace;\ - font-size: 36px;\ - position: absolute;\ - top: 50%;\ - }\ - </style>\ - </head>\ - <body>\ - <h1>\ - Uh oh web process crashed!\ - </h1>\ - </body>\ -</html>"; - - ewk_view_html_string_load(wd->cur_buf->view, html, NULL, ewk_view_url_get(wd->cur_buf->view)); - *handled = EINA_TRUE; -} - -/* -static void -webview_create_window_cb(void *data, Evas_Object *obj, Eina_Bool js, const Elm_Web_Window_Features *wf) -{ - Arg a; - Window_Data *wd = data; - - buffer_add(&a, wd); -} -*/ - -void -setup_buffer_callbacks(Buffer_Data *bd) -{ - Evas_Object *v = bd->view; - Window_Data *wd = bd->window; - - // elm_web_window_create_hook_set(td->web, webview_create_window_cb, td->window); - // elm_web_console_message_hook_set(td->web, webview_console_cb, td); - evas_object_smart_callback_add(v, "webprocess,crashed", webprocess_crashed_cb, wd); - - /* downloads */ - evas_object_smart_callback_add(v, "download,request", download_request_cb, wd); - evas_object_smart_callback_add(v, "download,finished", download_finished_cb, wd); - evas_object_smart_callback_add(v, "download,failed", download_failed_cb, wd); - evas_object_smart_callback_add(v, "download,cancelled", download_cancelled_cb, wd); - - /* navigation */ - evas_object_smart_callback_add(v, "title,changed", title_changed_cb, bd); - evas_object_smart_callback_add(v, "uri,changed", uri_changed_cb, bd); - evas_object_smart_callback_add(v, "load,progress", load_progress_cb, bd); - evas_object_smart_callback_add(v, "load,finished", load_finished_cb, bd); - evas_object_smart_callback_add(v, "load,error", load_error_cb, bd); - - /* not yet implemented in ewebkit */ - // evas_object_smart_callback_add(v, "link,hover,in", hoverlink_cb, td); - // evas_object_smart_callback_add(v, "link,hover,out",hoverlink_out_cb, td); - // evas_object_smart_callback_add(v, "inputmethod,changed", inputmethod_changed_cb, td); - evas_object_smart_callback_add(v, "inspector,view,create", inspector_cb, bd); - evas_object_smart_callback_add(v, "inspector,view,close", inspector_close_cb, bd); - - /* input events */ - evas_object_event_callback_add(v, EVAS_CALLBACK_FREE, webview_free_cb, bd); - evas_object_event_callback_add(v, EVAS_CALLBACK_KEY_DOWN, webview_keypress_cb, bd); - // evas_object_event_callback_add(v, EVAS_CALLBACK_MOUSE_UP, notify_event_cb, bd); - // evas_object_event_callback_add(v, EVAS_CALLBACK_MOUSE_WHEEL, webview_mousewheel_cb, bd); -} - -void -setup_window_callbacks(Window_Data *wd) -{ - evas_object_smart_callback_add(wd->win, "delete,request", _win_del_request_cb, wd); - - evas_object_smart_callback_add(wd->url, "activated", inputbox_activate_cb, wd); - evas_object_smart_callback_add(wd->url, "changed", inputbox_changed_cb, wd); - evas_object_event_callback_add(wd->url, EVAS_CALLBACK_KEY_DOWN, inputbox_keypress_cb, wd); - evas_object_event_callback_add(wd->url, EVAS_CALLBACK_KEY_UP, inputbox_keyrelease_cb, wd); -} - -static void -generic_url_scheme_request_cb(Ewk_Url_Scheme_Request *request, void *user_data) -{ - Eina_Strbuf *buf = eina_strbuf_new(); - char *handler = user_data; - const char *url = ewk_url_scheme_request_url_get(request); - eina_strbuf_append_printf(buf, "%s \"%s\"\n", handler, url); - printf("%s\n", eina_strbuf_string_get(buf)); - ecore_exe_run(eina_strbuf_string_steal(buf), NULL); - // ewk_url_scheme_request_finish(request, NULL, 0, "text/html"); -} - -void -setup_main_callbacks(App_Data *ad, const char *cookie_path) -{ - int i; - Ewk_Cookie_Manager *cookie_manager; - Ewk_Context *context = ewk_context_default_get(); - - /* set cookie policy to use text file and no third party cookies */ - cookie_manager = ewk_context_cookie_manager_get(context); - ewk_cookie_manager_persistent_storage_set(cookie_manager, cookie_path, - EWK_COOKIE_PERSISTENT_STORAGE_TEXT); - ewk_cookie_manager_accept_policy_set(cookie_manager, - EWK_COOKIE_ACCEPT_POLICY_NO_THIRD_PARTY); - - /* history hooks */ - ewk_context_history_callbacks_set( - context, - hist_nav_cb, - hist_redir_cb, - hist_redir_cb, - hist_title_updated_cb, - hist_visited_cb, - ad - ); - - /* url scheme registration */ - URIHandler uri_handlers[] = { - { "mailto", "terminology -e mutt" }, - { "ftp", "terminology -e wget ftp://" }, - { "magnet", "xterm -e rtorrent" }, - }; - - for (i = 0; i < LENGTH(uri_handlers); i++) - ewk_context_url_scheme_register(context, uri_handlers[i].handle, - generic_url_scheme_request_cb, uri_handlers[i].handler); -} - diff --git a/src/callbacks.h b/src/callbacks.h @@ -1,12 +0,0 @@ - -void setup_buffer_callbacks(Buffer_Data*); -void setup_window_callbacks(Window_Data*); -void setup_main_callbacks(App_Data*, const char*); - -/* -static Eina_Bool webview_mimetype_cb(WebKitWebView *webview, WebKitWebFrame *frame, WebKitNetworkRequest *request, char *mime_type, WebKitWebPolicyDecision *decision, gpointer user_data); -static void webview_open_js_window_cb(WebKitWebView* temp_view, GParamSpec param_spec); -static Eina_Bool webview_new_window_cb(WebKitWebView *webview, WebKitWebFrame *frame, WebKitNetworkRequest *request, WebKitWebNavigationAction *action, WebKitWebPolicyDecision *decision, gpointer user_data); -static WebKitWebView* webview_open_in_new_window_cb(WebKitWebView *webview, WebKitWebFrame *frame, gpointer user_data); -*/ - diff --git a/src/commands.c b/src/commands.c @@ -7,6 +7,7 @@ #include "viking.h" #include "commands.h" #include "utilities.h" +#include "buffer.h" // static unsigned int scrollstep = 40; /* cursor difference in pixel */ // static unsigned int pagingkeep = 40; /* pixels kept when paging */ diff --git a/src/main.c b/src/main.c @@ -17,8 +17,8 @@ #include "viking_state.h" #include "viking.h" #include "utilities.h" -#include "callbacks.h" - +#include "window.h" +#include "buffer.h" /* functions */ @@ -162,6 +162,139 @@ session_restore(App_Data *ad) return !!n_tabs; } +static void +hist_nav_cb(const Evas_Object *view, Ewk_Navigation_Data *nav_data, void *data) +{ + // printf("logging item to history.\n"); + Hist_Item *item; + App_Data *ad = data; + const char *title = ewk_navigation_data_title_get(nav_data); + const char *url = ewk_navigation_data_url_get(nav_data); + + item = hist_items_get(ad->history, url); + if (item && hist_item_enabled_get(item)) { + hist_item_visit_count_set(item, hist_item_visit_count_get(item) + 1); + hist_item_last_visit_set(item, ecore_time_unix_get()); + hist_item_title_set(item, title); + } + else if (!item && config_enable_history_get(ad->config)) { + hist_items_add(ad->history, url, hist_item_new(EINA_TRUE, title, url, 1, ecore_time_unix_get())); + } +} + +static void +hist_redir_cb(const Evas_Object *vew, const char *source_url, const char *dest_url, void *data) +{ + int prefix, min, suffix, src_len, dest_len; + + src_len = strlen(source_url); + dest_len = strlen(dest_url); + + if (src_len < dest_len) + min = src_len; + else + min = dest_len; + + prefix = 0; + while (source_url[prefix] == dest_url[prefix] && prefix < min) + prefix++; + + suffix = 0; + while (source_url[src_len - suffix - 1] == dest_url[dest_len - suffix - 1] && suffix < min) + suffix++; + + // printf("redir: prefix = %i, suffix = %i, min = %i\n", prefix, suffix, min); + + if (min - suffix - prefix < 0) { + printf("redirecion() from %s to %s\n", source_url, dest_url); + return; + } + + Eina_Strbuf *buf = eina_strbuf_new(); + eina_strbuf_append_n(buf, source_url, prefix); + eina_strbuf_append(buf, "{"); + eina_strbuf_append_n(buf, source_url + prefix, src_len - suffix - prefix); + eina_strbuf_append(buf, " => "); + eina_strbuf_append_n(buf, dest_url + prefix, dest_len - suffix - prefix); + eina_strbuf_append(buf, "}"); + eina_strbuf_append_n(buf, source_url + src_len - suffix, suffix); + + printf("redirection() %s\n", eina_strbuf_string_steal(buf)); + +} + +static void +hist_visited_cb(void *data) +{ + App_Data *ad = data; + void *hash_data; + Eina_Iterator *it = eina_hash_iterator_tuple_new(hist_items_hash_get(ad->history)); + + while (eina_iterator_next(it, &hash_data)) { + Eina_Hash_Tuple *t = hash_data; + Hist_Item *hist_item = t->data; + ewk_context_visited_link_add(ewk_context_default_get(), hist_item_url_get(hist_item)); + } + + eina_iterator_free(it); +} + +static void +hist_title_updated_cb(const Evas_Object *vew, const char *title, const char *url, void *data) +{ + // printf("title_update() %s has new title %s\n", url, title); +} + +static void +generic_url_scheme_request_cb(Ewk_Url_Scheme_Request *request, void *user_data) +{ + Eina_Strbuf *buf = eina_strbuf_new(); + char *handler = user_data; + const char *url = ewk_url_scheme_request_url_get(request); + eina_strbuf_append_printf(buf, "%s \"%s\"\n", handler, url); + printf("%s\n", eina_strbuf_string_get(buf)); + ecore_exe_run(eina_strbuf_string_steal(buf), NULL); + // ewk_url_scheme_request_finish(request, NULL, 0, "text/html"); +} + +static void +setup_main_callbacks(App_Data *ad, const char *cookie_path) +{ + int i; + Ewk_Cookie_Manager *cookie_manager; + Ewk_Context *context = ewk_context_default_get(); + + /* set cookie policy to use text file and no third party cookies */ + cookie_manager = ewk_context_cookie_manager_get(context); + ewk_cookie_manager_persistent_storage_set(cookie_manager, cookie_path, + EWK_COOKIE_PERSISTENT_STORAGE_TEXT); + ewk_cookie_manager_accept_policy_set(cookie_manager, + EWK_COOKIE_ACCEPT_POLICY_NO_THIRD_PARTY); + + /* history hooks */ + ewk_context_history_callbacks_set( + context, + hist_nav_cb, + hist_redir_cb, + hist_redir_cb, + hist_title_updated_cb, + hist_visited_cb, + ad + ); + + /* url scheme registration */ + URIHandler uri_handlers[] = { + { "mailto", "terminology -e mutt" }, + { "ftp", "terminology -e wget ftp://" }, + { "magnet", "xterm -e rtorrent" }, + }; + + for (i = 0; i < LENGTH(uri_handlers); i++) + ewk_context_url_scheme_register(context, uri_handlers[i].handle, + generic_url_scheme_request_cb, uri_handlers[i].handler); +} + + /* search engines */ static Searchengine searchengines[] = { { "d", "https://duckduckgo.com/?q=%s&t=Vimprobable" }, diff --git a/src/utilities.c b/src/utilities.c @@ -17,7 +17,6 @@ #include "commands.h" #include "utilities.h" #include "keymap.h" -#include "callbacks.h" #include "jsmn.h" @@ -609,261 +608,6 @@ setup_modkeys(void *data) // fprintf(stderr, "Modkey array looks like %s\n", ad->modkeys); } -Buffer_Data* -buffer_add(const unsigned char flags, Window_Data *wd, const char *url, Session_Item *session_item) -{ - Buffer_Data *bd; - Ewk_Settings *settings; - - bd = calloc(1, sizeof(Buffer_Data)); - if (!bd) return NULL; - - /* if the InNewWindow flag is set, create the buffer in a new window */ - if (flags & InNewWindow) - wd = window_add(wd->app, NULL); - - wd->buf_total++; - wd->buffer_list = eina_list_append(wd->buffer_list, bd); - - bd->window = wd; - bd->buf_number = wd->buf_total; - bd->inspector_enabled = EINA_FALSE; - bd->proxy_enabled = EINA_FALSE; - bd->cookies_enabled = EINA_FALSE; - bd->view = ewk_view_add(evas_object_evas_get(wd->win)); - ewk_view_theme_set(bd->view, "/usr/share/ewebkit-0/themes/default.edj"); - - settings = ewk_view_settings_get(bd->view); - ewk_settings_dns_prefetching_enabled_set(settings, EINA_TRUE); - ewk_settings_developer_extras_enabled_set(settings, EINA_TRUE); - - evas_object_size_hint_weight_set(bd->view, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_size_hint_align_set(bd->view, EVAS_HINT_FILL, EVAS_HINT_FILL); - - elm_naviframe_item_simple_push(wd->naviframe, bd->view); - - /* - if (wd->cur_buf) - bd->elm_obj = elm_naviframe_item_insert_after(wd->naviframe, - wd->cur_buf->elm_obj, - NULL, - NULL, - NULL, - bd->view, - NULL); - else - bd->elm_obj = elm_naviframe_item_simple_push(wd->naviframe, bd->view); - */ - - setup_buffer_callbacks(bd); - - - if (url) - ewk_view_url_set(bd->view, url); - else - ewk_view_url_set(bd->view, config_home_page_get(wd->app->config)); - - if (flags & SwitchToBuffer) - buffer_current_set(bd); - - if (!session_item) { - if (!(session_item = session_item_new(ewk_view_url_get(bd->view), EINA_FALSE, 0, 0))) - CRITICAL("Could not create session object"); - session_window_tabs_add(wd->session_window, session_item); - } - - evas_object_data_set(bd->view, "session", session_item); - evas_object_data_set(bd->view, "buffer_data", bd); - - return bd; -} - -void -buffer_current_set(Buffer_Data *new_buf) -{ - Window_Data *wd = new_buf->window; - Buffer_Data *old_buf = wd->cur_buf; - App_Data *ad = wd->app; - - if (new_buf == old_buf || ad->exiting) - return; - - if (old_buf) { - // ewk_view_visibility_state_set(old_buf->view, EWK_PAGE_VISIBILITY_STATE_HIDDEN, 0); - // if (old_buf->inspector_enabled) - // ewk_view_web_inspector_close(old_buf->view); - // if (old_buf->proxy_enabled) - // g_object_set(ad->soup_session, "proxy-uri", NULL, NULL); - evas_object_hide(old_buf->view); - } - - wd->cur_buf = new_buf; - - if (new_buf) { - // ewk_view_visibility_state_set(new_buf->view, EWK_PAGE_VISIBILITY_STATE_VISIBLE, 0); - //if (new_buf->inspector_enabled) { - // ewk_view_web_inspector_show(new_buf->view); - //} - - elm_naviframe_item_simple_promote(wd->naviframe, new_buf->view); - /* - if (new_buf->proxy_enabled) - enable_proxy(ad->cur_buf); - - if (new_buf->cookies_enabled) - ewk_cookies_policy_set(EWK_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY); - else - ewk_cookies_policy_set(EWK_COOKIE_JAR_ACCEPT_NEVER); - */ - evas_object_show(new_buf->view); - update_url(ewk_view_url_get(new_buf->view), wd); - } -} - -Window_Data* -window_add(App_Data *ad, Session_Window *session_window) -{ - // App_Data *ad = data; - Window_Data *wd; - Evas_Modifier_Mask mask; - Evas *e; - unsigned int i; - - wd = calloc(1, sizeof(Window_Data)); - if (!wd) return NULL; - - Evas_Object *win, *bg, *box, *status_bar, *url, *naviframe, *status_url; - Evas_Object *status_state, *event_box, *web_inspector, *progress, *downloads; - - elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); - - win = elm_win_add(NULL, "viking", ELM_WIN_BASIC); - elm_win_autodel_set(win, EINA_TRUE); - // elm_win_screen_constrain_set(win, EINA_TRUE); - - // elm_win_keyboard_mode_set(win, ELM_WIN_KEYBOARD_ON); - - e = evas_object_evas_get(win); - for (i = 0; i < LENGTH(keys); i++) { - mask = evas_key_modifier_mask_get(e, keys[i].mask); - if (keys[i].key && !evas_object_key_grab(win, keys[i].key, mask, 0, EINA_FALSE)) - fprintf(stderr, "grab failed mask = %s, key = %s\n", keys[i].mask , keys[i].key); - } - - elm_config_engine_set("opengl_x11"); - - /* program bacground */ - bg = elm_bg_add(win); - evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - elm_win_resize_object_add(win, bg); - elm_bg_color_set(bg, 0, 0, 0); - evas_object_layer_set(bg, EVAS_LAYER_MIN); - evas_object_show(bg); - - /* main box that everything goes into, resizes with window */ - box = elm_box_add(win); - evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - elm_win_resize_object_add(win, box); - evas_object_show(box); - - /* widget that shows the web pages */ - naviframe = elm_naviframe_add(win); - evas_object_size_hint_weight_set(naviframe, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_size_hint_align_set(naviframe, EVAS_HINT_FILL, EVAS_HINT_FILL); - elm_box_pack_end(box, naviframe); - evas_object_show(naviframe); - - /* status bar container */ - status_bar = elm_box_add(win); - elm_box_homogeneous_set(status_bar, EINA_FALSE); - elm_box_horizontal_set(status_bar, EINA_TRUE); - evas_object_size_hint_align_set(status_bar, EVAS_HINT_FILL, EVAS_HINT_FILL); - elm_box_pack_end(box, status_bar); - evas_object_show(status_bar); - - /* status bar url */ - status_url = elm_label_add(win); - evas_object_size_hint_weight_set(status_url, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_size_hint_align_set(status_url, 0.0, EVAS_HINT_FILL); - elm_box_pack_end(status_bar, status_url); - evas_object_show(status_url); - - /* status bar state (load progress, mod keys, scroll %) */ - status_state = elm_label_add(win); - evas_object_size_hint_weight_set(status_state, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - evas_object_size_hint_align_set(status_state, 1.0, EVAS_HINT_FILL); - elm_box_pack_end(status_bar, status_state); - evas_object_show(status_state); - - downloads = elm_label_add(win); - evas_object_size_hint_weight_set(status_state, 0.0, 0.0); - evas_object_size_hint_align_set(downloads, 1.0, EVAS_HINT_FILL); - elm_box_pack_end(status_bar, downloads); - evas_object_show(downloads); - - progress = elm_progressbar_add(win); - elm_progressbar_horizontal_set(progress, EINA_TRUE); - elm_progressbar_unit_format_set(progress, NULL); - evas_object_size_hint_align_set(progress, 1.0, EVAS_HINT_FILL); - evas_object_size_hint_min_set(progress, 100, 8); - evas_object_size_hint_max_set(progress, 100, 8); - elm_box_pack_end(status_bar, progress); - evas_object_show(progress); - - /* invisible until activated web inspector */ - web_inspector = elm_box_add(win); - evas_object_size_hint_align_set(web_inspector, EVAS_HINT_FILL, EVAS_HINT_FILL); - elm_box_pack_end(box, web_inspector); - evas_object_hide(web_inspector); - - /* invisible event box, populated on tab completions and :ls */ - event_box = elm_box_add(win); - evas_object_size_hint_align_set(event_box, EVAS_HINT_FILL, EVAS_HINT_FILL); - elm_box_pack_end(box, event_box); -// evas_object_hide(event_box); - - /* main entry widget */ - url = elm_entry_add(win); - elm_entry_single_line_set(url, EINA_TRUE); - elm_entry_scrollable_set(url, EINA_TRUE); - evas_object_size_hint_weight_set(url, EVAS_HINT_EXPAND, 0.0); - evas_object_size_hint_align_set(url, EVAS_HINT_FILL, EVAS_HINT_FILL); - elm_box_pack_end(box, url); - elm_entry_text_style_user_push(url, "DEFAULT='font=Monospace font_size=11'"); - evas_object_show(url); - - wd->win = win; - wd->main_box = box; - wd->naviframe = naviframe; - wd->url = url; - wd->status_url = status_url; - wd->status_state = status_state; - wd->event_box = event_box; - wd->web_inspector = web_inspector; - wd->progress_bar = progress; - wd->downloads = downloads; - wd->app = ad; - wd->mode = ModeNormal; - wd->echo_active = EINA_TRUE; - - if (session_window) { - wd->session_window = session_window; - } - else { - wd->session_window = session_window_new(NULL, EINA_FALSE); - session_windows_add(ad->session, wd->session_window); - } - - setup_window_callbacks(wd); - - ad->windows = eina_list_append(ad->windows, wd); - - evas_object_resize(wd->win, 1024, 768); - evas_object_show(wd->win); - - return wd; -} - Eina_Bool echo(const Arg *arg, void *data) { diff --git a/src/utilities.h b/src/utilities.h @@ -27,8 +27,6 @@ char * search_word(int whichword); void userscript_hooks_start(const char*); void userscript_hooks_end(const char*); void setup_modkeys(void *data); -Buffer_Data* buffer_add(const unsigned char, Window_Data *, const char *, Session_Item *); -Window_Data* window_add(App_Data *, Session_Window*); Eina_Bool echo(const Arg *arg, void *); void update_state(Window_Data*); void update_url(const char*, Window_Data*); diff --git a/src/window.c b/src/window.c @@ -0,0 +1,514 @@ + +#include <Elementary.h> +#include <EWebKit2.h> +#include <libsoup/soup.h> + +#include "viking_state.h" +#include "viking.h" +#include "utilities.h" +#include "commands.h" +#include "window.h" +#include "keymap.h" + + +static Eina_Bool commandhistoryfetch(const Arg *, void *); + +static void +inputbox_activate_cb(void *data, Evas_Object *obj, void *event_info) +{ + const char *text; + Window_Data *wd = data; + // App_Data *ad = wd->app; + uint16_t length = strlen(elm_entry_entry_get(wd->url)); + Arg a; + Eina_Bool forward = EINA_FALSE; + + // printf("In inputbox_activate\n"); + + a.i = HideCompletion; + complete(&a, data); + if (length == 0) + return; + text = elm_entry_entry_get(wd->url); + if (length > 1 && text[0] == ':') { + process_line((text + 1), data); + } else if (length > 1 && ((forward = text[0] == '/') || text[0] == '?')) { + ewk_view_text_find_highlight_clear(wd->cur_buf->view); + + ewk_view_text_find(wd->cur_buf->view, &text[1], + EWK_FIND_OPTIONS_SHOW_HIGHLIGHT | EWK_FIND_OPTIONS_CASE_INSENSITIVE, 1000); + + wd->count = 0; + wd->search_direction = forward; + wd->search_handle = strdup(&text[1]); + } else if (text[0] == '.' || text[0] == ',' || text[0] == ';') { + a.i = Silent; + a.s = strdup("hints.fire();"); + script(&a, data); + free(a.s); + update_state(data); + } else + return; + if (!wd->echo_active) + // gtk_entry_set_text(entry, ""); + elm_entry_entry_set(wd->url, ""); + // gtk_widget_grab_focus(GTK_WIDGET(webview)); + + /* process_line above may have deleted the tab, check if its still around */ + if (wd->cur_buf->view) { + elm_object_focus_set(elm_object_top_widget_get(wd->win), EINA_FALSE); + evas_object_focus_set(wd->cur_buf->view, EINA_TRUE); + } +} + +static Eina_Bool +commandhistoryfetch(const Arg *arg, void *data) +{ + Window_Data *wd = data; + // App_Data *ad = wd->app; + char *command; + const int length = eina_list_count(wd->commandhistory); + + if (length > 0) { + if (arg->i == DirectionPrev) { + wd->commandpointer = (length + wd->commandpointer - 1) % length; + } else { + wd->commandpointer = (length + wd->commandpointer + 1) % length; + } + + command = eina_list_nth(wd->commandhistory, wd->commandpointer); + // gtk_entry_set_text(GTK_ENTRY(inputbox), g_strconcat(":", command, NULL)); + // gtk_editable_set_position(GTK_EDITABLE(inputbox), -1); + command = strdup_printf(":%s", command); + elm_entry_entry_set(wd->url, command); + free(command); + elm_entry_cursor_line_end_set(wd->url); + return EINA_TRUE; + } + + return EINA_FALSE; +} + +static void +inputbox_keypress_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Arg a; + int numval; + Evas_Event_Key_Down *ev = event_info; + Window_Data *wd = data; + // App_Data *ad = wd->app; + + if (wd->mode == ModeHints) { + // if (event->keyval == GDK_ISO_Left_Tab) { + if (!strcmp(ev->keyname, "Tab") && evas_key_modifier_is_set(ev->modifiers, "Shift")) { + a.i = Silent; + a.s = strdup("hints.focusPreviousHint();"); + script(&a, data); + free(a.s); + update_state(data); + return; + } + // if (event->keyval == GDK_Tab) { + if (!strcmp(ev->keyname, "Tab")) { + a.i = Silent; + a.s = strdup("hints.focusNextHint();"); + script(&a, data); + free(a.s); + update_state(data); + return; + } + // if (event->keyval == GDK_Return) { + if (!strcmp(ev->keyname, "Return")) { + a.i = Silent; + a.s = strdup_printf("hints.fire();"); + script(&a, data); + free(a.s); + update_state(data); + return; + } + } + if (!strcmp(ev->keyname, "[") || !strcmp(ev->keyname, "Escape")) { + a.i = HideCompletion; + complete(&a, data); + a.i = ModeNormal; + wd->commandpointer = 0; + set(&a, data); + return; + } + else if (!strcmp(ev->keyname, "Tab") && evas_key_modifier_is_set(ev->modifiers, "Shift")) { + a.i = DirectionPrev; + complete(&a, data); + return; + } + else if (!strcmp(ev->keyname, "Tab")) { + a.i = DirectionNext; + complete(&a, data); + return; + } + else if (!strcmp(ev->keyname, "Up")) { + a.i = DirectionPrev; + commandhistoryfetch(&a, data); + return; + } + else if (!strcmp(ev->keyname, "Down")) { + a.i = DirectionNext; + commandhistoryfetch(&a, data); + return; + } + + /* + switch (event->keyval) { + case GDK_bracketleft: + case GDK_Escape: + if (!IS_ESCAPE(event)) break; + a.i = HideCompletion; + complete(&a, data); + a.i = ModeNormal; + commandpointer = 0; + return set(&a, ad); + break; + case GDK_Tab: + a.i = DirectionNext; + return complete(&a, data); + break; + case GDK_Up: + a.i = DirectionPrev; + return commandhistoryfetch(&a); + break; + case GDK_Down: + a.i = DirectionNext; + return commandhistoryfetch(&a); + break; + case GDK_ISO_Left_Tab: + a.i = DirectionPrev; + return complete(&a, data); + break; + } + */ + + if (wd->mode == ModeHints) { +#if 0 + if ((CLEAN(event->state) & GDK_SHIFT_MASK) && + (CLEAN(event->state) & GDK_CONTROL_MASK) && + (event->keyval == GDK_BackSpace)) { + count /= 10; + a.i = Silent; + a.s = g_strdup_printf("hints.updateHints(%d);", count); + script(&a, data); + g_free(a.s); + update_state(); + return TRUE; + } +#endif + + // numval = g_unichar_digit_value((gunichar) gdk_keyval_to_unicode(event->keyval)); + numval = atoi(ev->key); + if ((numval >= 1 && numval <= 9) || (numval == 0 && wd->count)) { + /* allow a zero as non-first number */ + wd->count = (wd->count ? wd->count * 10 : 0) + numval; + a.i = Silent; + a.s = strdup_printf("hints.updateHints(%d);", wd->count); + script(&a, data); + free(a.s); + update_state(data); + return; + } + } +} + +static void +inputbox_keyrelease_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) +{ + Arg a; + Window_Data *wd = data; + // guint16 length = gtk_entry_get_text_length(entry); + uint16_t length = strlen(elm_entry_entry_get(wd->url)); + + if (!length) { + a.i = HideCompletion; + complete(&a, data); + a.i = ModeNormal; + set(&a, data); + } +} + +/* used for incremental search */ +static void +inputbox_changed_cb(void *data, Evas_Object *obj, void *event_info) +{ + Arg a; + Window_Data *wd = data; + const char *text = elm_entry_entry_get(wd->url); + uint16_t length = strlen(text); + Eina_Bool forward = EINA_FALSE; + + /* Update incremental search if the user changes the search text. + * + * Note: gtk_widget_is_focus() is a poor way to check if the change comes + * from the user. But if the entry is focused and the text is set + * through gtk_entry_set_text() in some asyncrounous operation, + * I would consider that a bug. + */ + + if (elm_object_focus_get(wd->url) && length > 1 && ((forward = text[0] == '/') || text[0] == '?')) { + ewk_view_text_find_highlight_clear(wd->cur_buf->view); + ewk_view_text_find(wd->cur_buf->view, &text[1], + EWK_FIND_OPTIONS_SHOW_HIGHLIGHT | EWK_FIND_OPTIONS_CASE_INSENSITIVE, 1000); + return; + } else if (elm_object_focus_get(wd->url) && length >= 1 && + (text[0] == '.' || text[0] == ',' || text[0] == ';')) { + a.i = Silent; + switch (text[0]) { + case '.': + a.s = strdup_printf("hints.createHints('%s', 'f');", text + 1); + break; + + case ',': + a.s = strdup_printf("hints.createHints('%s', 'F');", text + 1); + break; + + case ';': + a.s = NULL; + switch (text[1]) { + case 's': + a.s = strdup_printf("hints.createHints('%s', 's');", text + 2); + break; + case 'y': + a.s = strdup_printf("hints.createHints('%s', 'y');", text + 2); + break; + case 'o': + a.s = strdup_printf("hints.createHints('%s', 'f');", text + 2); + break; + case 't': case 'w': + a.s = strdup_printf("hints.createHints('%s', 'F');", text + 2); + break; + case 'O': case 'T': case 'W': + a.s = strdup_printf("hints.createHints('%s', 'O');", text + 2); + break; + case 'i': + a.s = strdup_printf("hints.createHints('%s', 'i');", text + 2); + break; + case 'I': + a.s = strdup_printf("hints.createHints('%s', 'I');", text + 2); + break; + } + break; + } + wd->count = 0; + if (a.s) { + script(&a, data); + free(a.s); + } + + return; + } else if (length == 0 && wd->followTarget[0]) { + wd->mode = ModeNormal; + a.i = Silent; + a.s = strdup("hints.clearHints();"); + script(&a, data); + free(a.s); + wd->count = 0; + update_state(data); + } +} + +static void +_win_del_request_cb(void *data, Evas_Object *obj, void *event_info) +{ + Window_Data *wd = data; + printf("window requested deletion ..\n"); + + free(wd); +} + + +void +buffer_current_set(Buffer_Data *new_buf) +{ + Window_Data *wd = new_buf->window; + Buffer_Data *old_buf = wd->cur_buf; + App_Data *ad = wd->app; + + if (new_buf == old_buf || ad->exiting) + return; + + if (old_buf) { + // ewk_view_visibility_state_set(old_buf->view, EWK_PAGE_VISIBILITY_STATE_HIDDEN, 0); + // if (old_buf->inspector_enabled) + // ewk_view_web_inspector_close(old_buf->view); + // if (old_buf->proxy_enabled) + // g_object_set(ad->soup_session, "proxy-uri", NULL, NULL); + // evas_object_hide(old_buf->view); + } + + wd->cur_buf = new_buf; + + if (new_buf) { + // ewk_view_visibility_state_set(new_buf->view, EWK_PAGE_VISIBILITY_STATE_VISIBLE, 0); + //if (new_buf->inspector_enabled) { + // ewk_view_web_inspector_show(new_buf->view); + //} + + elm_naviframe_item_simple_promote(wd->naviframe, new_buf->view); + /* + if (new_buf->proxy_enabled) + enable_proxy(ad->cur_buf); + + if (new_buf->cookies_enabled) + ewk_cookies_policy_set(EWK_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY); + else + ewk_cookies_policy_set(EWK_COOKIE_JAR_ACCEPT_NEVER); + */ + // evas_object_show(new_buf->view); + update_url(ewk_view_url_get(new_buf->view), wd); + } +} + +Window_Data* +window_add(App_Data *ad, Session_Window *session_window) +{ + // App_Data *ad = data; + Window_Data *wd; + Evas_Modifier_Mask mask; + Evas *e; + unsigned int i; + + wd = calloc(1, sizeof(Window_Data)); + if (!wd) return NULL; + + Evas_Object *win, *bg, *box, *status_bar, *url, *naviframe, *status_url; + Evas_Object *status_state, *event_box, *web_inspector, *progress, *downloads; + + elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); + + win = elm_win_add(NULL, "viking", ELM_WIN_BASIC); + elm_win_autodel_set(win, EINA_TRUE); + // elm_win_screen_constrain_set(win, EINA_TRUE); + + // elm_win_keyboard_mode_set(win, ELM_WIN_KEYBOARD_ON); + + e = evas_object_evas_get(win); + for (i = 0; i < LENGTH(keys); i++) { + mask = evas_key_modifier_mask_get(e, keys[i].mask); + if (keys[i].key && !evas_object_key_grab(win, keys[i].key, mask, 0, EINA_FALSE)) + fprintf(stderr, "grab failed mask = %s, key = %s\n", keys[i].mask , keys[i].key); + } + + elm_config_engine_set("opengl_x11"); + + /* program bacground */ + bg = elm_bg_add(win); + evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, bg); + elm_bg_color_set(bg, 0, 0, 0); + evas_object_layer_set(bg, EVAS_LAYER_MIN); + evas_object_show(bg); + + /* main box that everything goes into, resizes with window */ + box = elm_box_add(win); + evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, box); + evas_object_show(box); + + /* widget that shows the web pages */ + naviframe = elm_naviframe_add(win); + evas_object_size_hint_weight_set(naviframe, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(naviframe, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_pack_end(box, naviframe); + evas_object_show(naviframe); + + /* status bar container */ + status_bar = elm_box_add(win); + elm_box_homogeneous_set(status_bar, EINA_FALSE); + elm_box_horizontal_set(status_bar, EINA_TRUE); + evas_object_size_hint_align_set(status_bar, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_pack_end(box, status_bar); + evas_object_show(status_bar); + + /* status bar url */ + status_url = elm_label_add(win); + evas_object_size_hint_weight_set(status_url, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(status_url, 0.0, EVAS_HINT_FILL); + elm_box_pack_end(status_bar, status_url); + evas_object_show(status_url); + + /* status bar state (load progress, mod keys, scroll %) */ + status_state = elm_label_add(win); + evas_object_size_hint_weight_set(status_state, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(status_state, 1.0, EVAS_HINT_FILL); + elm_box_pack_end(status_bar, status_state); + evas_object_show(status_state); + + downloads = elm_label_add(win); + evas_object_size_hint_weight_set(status_state, 0.0, 0.0); + evas_object_size_hint_align_set(downloads, 1.0, EVAS_HINT_FILL); + elm_box_pack_end(status_bar, downloads); + evas_object_show(downloads); + + progress = elm_progressbar_add(win); + elm_progressbar_horizontal_set(progress, EINA_TRUE); + elm_progressbar_unit_format_set(progress, NULL); + evas_object_size_hint_align_set(progress, 1.0, EVAS_HINT_FILL); + evas_object_size_hint_min_set(progress, 100, 8); + evas_object_size_hint_max_set(progress, 100, 8); + elm_box_pack_end(status_bar, progress); + evas_object_show(progress); + + /* invisible until activated web inspector */ + web_inspector = elm_box_add(win); + evas_object_size_hint_align_set(web_inspector, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_pack_end(box, web_inspector); + evas_object_hide(web_inspector); + + /* invisible event box, populated on tab completions and :ls */ + event_box = elm_box_add(win); + evas_object_size_hint_align_set(event_box, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_pack_end(box, event_box); +// evas_object_hide(event_box); + + /* main entry widget */ + url = elm_entry_add(win); + elm_entry_single_line_set(url, EINA_TRUE); + elm_entry_scrollable_set(url, EINA_TRUE); + evas_object_size_hint_weight_set(url, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(url, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_pack_end(box, url); + elm_entry_text_style_user_push(url, "DEFAULT='font=Monospace font_size=11'"); + evas_object_show(url); + + wd->win = win; + wd->main_box = box; + wd->naviframe = naviframe; + wd->url = url; + wd->status_url = status_url; + wd->status_state = status_state; + wd->event_box = event_box; + wd->web_inspector = web_inspector; + wd->progress_bar = progress; + wd->downloads = downloads; + wd->app = ad; + wd->mode = ModeNormal; + wd->echo_active = EINA_TRUE; + + if (session_window) { + wd->session_window = session_window; + } + else { + wd->session_window = session_window_new(NULL, EINA_FALSE); + session_windows_add(ad->session, wd->session_window); + } + + evas_object_smart_callback_add(wd->win, "delete,request", _win_del_request_cb, wd); + evas_object_smart_callback_add(wd->url, "activated", inputbox_activate_cb, wd); + evas_object_smart_callback_add(wd->url, "changed", inputbox_changed_cb, wd); + evas_object_event_callback_add(wd->url, EVAS_CALLBACK_KEY_DOWN, inputbox_keypress_cb, wd); + evas_object_event_callback_add(wd->url, EVAS_CALLBACK_KEY_UP, inputbox_keyrelease_cb, wd); + + ad->windows = eina_list_append(ad->windows, wd); + + evas_object_resize(wd->win, 1024, 768); + evas_object_show(wd->win); + + return wd; +} + diff --git a/src/window.h b/src/window.h @@ -0,0 +1,6 @@ + +Window_Data* window_add(App_Data *, Session_Window*); + +#define IS_ESCAPE(ev) ((!strcmp(ev->keyname, "Escape")) || \ + (!strcmp(ev->keyname, "[") && evas_key_modifier_is_set(ev->modifiers, "Control"))) +