viking

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

commit 2b016d347691d9d3aadd29512ff3bfaea2d4f155
parent 2915e290b79a6f31e79c51e355437f41cbccc7eb
Author: Kyle Milz <kmilz@ucalgary.ca>
Date:   Fri,  5 Oct 2012 16:26:13 -0600

implement ewebkit2 style downloads

the webkit2 download api is much richer than the webkit one. use all of
the download signals avaiable and put down download infrastructure.

also do some more end-of-program memory freeing.

Diffstat:
Msrc/callbacks.c | 182+++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/main.c | 32++++++++++++++------------------
Msrc/utilities.c | 20+++++++++-----------
Msrc/viking.h | 7+++++--
4 files changed, 140 insertions(+), 101 deletions(-)

diff --git a/src/callbacks.c b/src/callbacks.c @@ -13,9 +13,8 @@ static Eina_Bool commandhistoryfetch (const Arg *, void *); static Eina_Bool process_keypress (void *, void*); +Eina_Bool download_gui_update(void *data); -void download_complete_cb(void*, const char*, int); -int download_progress_cb(void*, const char*, long int, long int, long int, long int); #define IS_ESCAPE(ev) ((!strcmp(ev->keyname, "Escape")) || \ (!strcmp(ev->keyname, "[") && evas_key_modifier_is_set(ev->modifiers, "Control"))) @@ -306,80 +305,115 @@ webview_mimetype_cb(WebKitWebView *webview, WebKitWebFrame *frame, WebKitNetwork */ -void -download_complete_cb(void *data, const char *file, int status) + +/* + * Download Callbacks + */ + +Eina_Bool +download_gui_update(void *data) { + Eina_List *l; + void *list_data; Window_Data *wd = data; App_Data *ad = wd->app; - Arg a; - a.i = Info; - a.s = strdup_printf("Download %s finished, status %i", file, status); - echo(&a, wd); - free(a.s); + unsigned int dl_count = eina_list_count(ad->downloads); - // ad->active_downloads = eina_list_remove(ad->active_downloads, file); - eina_hash_del(ad->downloads, file, NULL); + char *tmp = strdup_printf("<font=Monospace font_size=11 color=#FFF>%i DL", eina_list_count(ad->downloads)); - update_state(wd); + /* 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; } -int -download_progress_cb(void *data, const char *file, long int dltotal, long int dlnow, long int ultotal, long int ulnow) +static void +download_request_cb(void *data, Evas_Object *obj, void *event_info) { Window_Data *wd = data; App_Data *ad = wd->app; - void *stat_old; - struct dl *stat = malloc(sizeof(struct dl)); + Ewk_Download_Job *dl = event_info; - stat->dltotal = dltotal; - stat->dlnow = dlnow; + 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); - stat_old = eina_hash_modify(ad->downloads, file, (const void *)stat); - free(stat_old); + ewk_download_job_ref(dl); + ad->downloads = eina_list_append(ad->downloads, dl); - update_state(wd); + if (eina_list_count(ad->downloads) == 1) + ad->download_gui_timer = ecore_timer_loop_add(1, download_gui_update, wd); - return 0; + download_gui_update(wd); } static void -webview_download_cb(void *data, Evas_Object *obj, void *event_info) +download_remove(Window_Data *wd, Ewk_Download_Job *dl) { - /* - Eina_Bool ret; - Buffer_Data *bd = data; - Window_Data *wd = bd->window; App_Data *ad = wd->app; - Ewk_Download *dl = event_info; - char *suggested_name = strdup(strrchr(dl->url, '/')); + ewk_download_job_unref(dl); + ad->downloads = eina_list_remove(ad->downloads, dl); - char *full_path = strdup_printf("/home/kyle/%s", suggested_name); + if (eina_list_count(ad->downloads) == 0) + ecore_timer_del(ad->download_gui_timer); - ret = ecore_file_download(dl->url, full_path, download_complete_cb, - download_progress_cb, wd, NULL); + download_gui_update(wd); +} - // if file already exists, ret == NULL - if (!ret) { - Arg a; - a.i = Info; - a.s = strdup_printf("%s already exists!", suggested_name); - echo(&a, wd); - free(a.s); - return; - } +static void +download_finished_cb(void *data, Evas_Object *obj, void *event_info) +{ + Window_Data *wd = data; + Ewk_Download_Job *dl = event_info; - // ad->active_downloads = eina_list_append(ad->active_downloads, strdup(full_path)); - eina_hash_add(ad->downloads, full_path, calloc(1, sizeof(struct dl))); - - // free(full_path); - free(suggested_name); + download_remove(wd, dl); +} - // update_state(ad); - */ +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) @@ -755,6 +789,7 @@ inputbox_keypress_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) } } +/* static void inputmethod_changed_cb(void *data, Evas_Object *obj, void *event_info) { @@ -788,7 +823,6 @@ inputmethod_changed_cb(void *data, Evas_Object *obj, void *event_info) } } -/* 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) @@ -1036,30 +1070,38 @@ webview_create_window_cb(void *data, Evas_Object *obj, Eina_Bool js, const Elm_W void setup_buffer_callbacks(Buffer_Data *td) { + Evas_Object *v = td->view; + Window_Data *wd = td->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(td->view, "title,changed", webview_title_changed_cb, td); - evas_object_smart_callback_add(td->view, "uri,changed", webview_uri_changed_cb, td); - evas_object_smart_callback_add(td->view, "load,progress", webview_progress_changed_cb, td); - // evas_object_smart_callback_add(td->web, "load,started", webview_load_committed_cb, td); - // evas_object_smart_callback_add(td->view, "load,document,finished", webview_document_finished_cb, td); - evas_object_smart_callback_add(td->view, "load,finished", webview_load_finished_cb, td); - evas_object_smart_callback_add(td->view, "download,request", webview_download_cb, td); - // evas_object_smart_callback_add(td->view, "link,hover,in", webview_hoverlink_cb, td); - // evas_object_smart_callback_add(td->view, "link,hover,out", webview_hoverlink_out_cb, td); - evas_object_smart_callback_add(td->view, "inputmethod,changed", inputmethod_changed_cb, td); - - /* these signals are not offered by elm_web */ - evas_object_smart_callback_add(td->view, "load,error", load_error_cb, td); - // evas_object_smart_callback_add(td->view, "inspector,view,create", webview_inspector_cb, td); - // evas_object_smart_callback_add(td->view, "inspector,view,close", webview_inspector_close_cb, td); - // evas_object_smart_callback_add(td->view, "populate,visited,links", populate_visited_links_cb, td); - - evas_object_event_callback_add(td->view, EVAS_CALLBACK_FREE, _web_free_cb, td); - evas_object_event_callback_add(td->view, EVAS_CALLBACK_KEY_DOWN, webview_keypress_cb, td); - // evas_object_event_callback_add(td->web, EVAS_CALLBACK_MOUSE_UP, notify_event_cb, td); - evas_object_event_callback_add(td->view, EVAS_CALLBACK_MOUSE_WHEEL, webview_mousewheel_cb, td); + /* 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", webview_title_changed_cb, td); + evas_object_smart_callback_add(v, "uri,changed", webview_uri_changed_cb, td); + evas_object_smart_callback_add(v, "load,progress", webview_progress_changed_cb, td); + evas_object_smart_callback_add(v, "load,finished", webview_load_finished_cb, td); + evas_object_smart_callback_add(v, "load,error", load_error_cb, td); + + /* not yet implemented in ewebkitw */ + // evas_object_smart_callback_add(v, "link,hover,in", webview_hoverlink_cb, td); + // evas_object_smart_callback_add(v, "link,hover,out",webview_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", webview_inspector_cb, td); + // evas_object_smart_callback_add(v, "inspector,view,close", webview_inspector_close_cb, td); + // evas_object_smart_callback_add(v, "populate,visited,links", populate_visited_links_cb, td); + + /* input events */ + evas_object_event_callback_add(v, EVAS_CALLBACK_FREE, _web_free_cb, td); + evas_object_event_callback_add(v, EVAS_CALLBACK_KEY_DOWN, webview_keypress_cb, td); + // evas_object_event_callback_add(v, EVAS_CALLBACK_MOUSE_UP, notify_event_cb, td); + evas_object_event_callback_add(v, EVAS_CALLBACK_MOUSE_WHEEL, webview_mousewheel_cb, td); } void diff --git a/src/main.c b/src/main.c @@ -28,7 +28,6 @@ EAPI_MAIN int elm_main(int argc, char *argv[]); /* functions */ char *uri_sanitize(const char *); -static void download_entry_free_cb(void *data); static Eina_Bool _cb_session_save(void *data) @@ -376,12 +375,6 @@ fd_handler_cb(void *data, Ecore_Fd_Handler *handler) } */ -static void -download_entry_free_cb(void *data) -{ - free(data); -} - EAPI_MAIN int elm_main(int argc, char *argv[]) { @@ -449,7 +442,6 @@ elm_main(int argc, char *argv[]) /* initialize fields that are non-zero */ ad->keylistroot = make_keyslist(); ad->zoomstep = 0.1f; - ad->downloads = eina_hash_string_superfast_new(download_entry_free_cb); /* main loop */ elm_run(); @@ -463,20 +455,24 @@ elm_main(int argc, char *argv[]) //if (ad->session_save_timer) // ecore_timer_del(ad->session_save_timer); -// eina_log_domain_unregister(ad->log_domain); -// ad->log_domain = -1; - - ewk_shutdown(); - viking_state_shutdown(); + Eina_List *w; + void *data; + Window_Data *wd; + EINA_LIST_FOREACH(ad->windows, w, data) { + wd = data; + eina_list_free(wd->buffer_list); + eina_list_free(wd->commandhistory); + } - free(ad->modkeys); - // each window needs this done to it - // eina_list_free(wd->buffer_list); - eina_hash_free(ad->downloads); + /* need to free ->keyslistroot here too */ eina_list_free(ad->windows); - // eina_list_free(ad->keylistroot; + eina_list_free(ad->downloads); + free(ad->modkeys); free(ad); + ewk_shutdown(); + viking_state_shutdown(); + return 0; } ELM_MAIN() diff --git a/src/utilities.c b/src/utilities.c @@ -1201,7 +1201,7 @@ window_add(const Arg *arg, App_Data *ad) if (!wd) return; Evas_Object *win, *bg, *box, *status_bar, *url, *naviframe, *status_url; - Evas_Object *status_state, *event_box, *web_inspector, *progress; + Evas_Object *status_state, *event_box, *web_inspector, *progress, *downloads; elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); @@ -1261,6 +1261,12 @@ window_add(const Arg *arg, App_Data *ad) 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); @@ -1301,6 +1307,7 @@ window_add(const Arg *arg, App_Data *ad) wd->event_box = event_box; wd->web_inspector = web_inspector; wd->progress_bar = progress; + wd->downloads = downloads; wd->app = ad; setup_window_callbacks(wd); @@ -1345,15 +1352,13 @@ update_state(void *data) { // char *markup; Window_Data *wd = data; - App_Data *ad = wd->app; + // App_Data *ad = wd->app; if (!wd->cur_buf) return; // Evas_Object *view = wd->cur_buf->view; // Evas_Object *frame = ewk_view_frame_main_get(view); - int download_count = eina_hash_population(ad->downloads); - // GString *status = g_string_new(""); char status[512] = ""; /* construct the status line */ @@ -1369,13 +1374,6 @@ update_state(void *data) // if (ad->current_modkey) g_string_append_c(status, ad->current_modkey); if (wd->current_modkey) strcat(status, &wd->current_modkey); - if (download_count) { - char *download_status = strdup_printf(" %d DL%s", download_count, - (download_count == 1) ? "" : "s"); - strcat(status, download_status); - free(download_status); - } - /* put a notification if we are zoomed // double zoom = elm_web_zoom_get(wd->cur_buf->web); float zoom = ewk_view_zoom_get(wd->cur_buf->view); diff --git a/src/viking.h b/src/viking.h @@ -210,18 +210,20 @@ typedef struct _Buffer_Data Buffer_Data; typedef struct { Eina_List *windows; - Eina_Hash *downloads; + Eina_List *downloads; KeyList *keylistroot; float zoomstep; char *modkeys; int log_domain; + Ecore_Timer *session_save_timer; + Ecore_Timer *download_gui_timer; + SoupSession *soup_session; Hist *history; Config *config; Session *session; - Ecore_Timer *session_save_timer; Ewk_Context *ewk_context; Ewk_Cookie_Manager *cookie_manager; @@ -240,6 +242,7 @@ typedef struct Evas_Object *status_state; Evas_Object *web_inspector; Evas_Object *progress_bar; + Evas_Object *downloads; Eina_List *commandhistory; Eina_List *buffer_list;