viking

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

buffer.c (14254B)


      1 
      2 #include <Elementary.h>
      3 #include <EWebKit2.h>
      4 
      5 #include "viking_state.h"
      6 #include "viking.h"
      7 #include "javascript.h"
      8 #include "utilities.h"
      9 #include "commands.h"
     10 #include "window.h"
     11 #include "buffer.h"
     12 #include "buffer_callback.h"
     13 #include "download.h"
     14 
     15 
     16 Ewk_View_Smart_Class* miniBrowserViewSmartClass(void)
     17 {
     18 	static Ewk_View_Smart_Class ewkViewClass = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION("MiniBrowser_View");
     19 	return &ewkViewClass;
     20 }
     21 
     22 /*
     23 static Browser_Window *browser_view_find(Evas_Object *view)
     24 {
     25 	Eina_List *l;
     26 	void *data;
     27 
     28 	if (!view)
     29 		return NULL;
     30 
     31 	EINA_LIST_FOREACH(windows, l, data) {
     32 		Browser_Window *browser_window = (Browser_Window *)data;
     33 		if (browser_window->webview == view)
     34 			return browser_window;
     35 	}
     36 	return NULL;
     37 }
     38 */
     39 
     40 
     41 /*
     42 static void
     43 webview_create_window_cb(void *data, Evas_Object *obj, Eina_Bool js, const Elm_Web_Window_Features *wf)
     44 {
     45 	Arg a;
     46 	Window_Data *wd = data;
     47 
     48 	buffer_add(&a, wd);
     49 }
     50 */
     51 
     52 static void
     53 title_changed_cb(void *data, Evas_Object *obj, void *event_info)
     54 {
     55 	Buffer_Data *bd = data;
     56 	Window_Data *wd = bd->window;
     57 	const char *title = event_info;
     58 	char buf[128] = "";
     59 
     60 	if (title)
     61 		strncpy(buf, title, sizeof(buf) - 1);
     62 
     63 	elm_win_title_set(wd->win, buf);
     64 }
     65 
     66 static void
     67 load_progress_cb(void *data, Evas_Object *obj, void *event_info)
     68 {
     69 	Buffer_Data *bd = data;
     70 	Window_Data *wd = bd->window;
     71 	double *val = event_info;
     72 
     73 	if (bd != bd->window->cur_buf)
     74 		return;
     75 	
     76 	elm_progressbar_value_set(wd->progress_bar, *val);
     77 
     78 	/*
     79 	if (*val == 1.0)
     80 		evas_object_hide(wd->progress_bar);
     81 	else
     82 		evas_object_show(wd->progress_bar);
     83 	*/
     84 }
     85 
     86 static void
     87 storage_origins_cb(Eina_List *origins, Ewk_Error *error, void *user_data)
     88 {
     89 	/*
     90 	Eina_List *l;
     91 	Ewk_Security_Origin *sec;
     92 
     93 	printf("storage_origins_cb() has %i origins\n", eina_list_count(origins));
     94 
     95 	EINA_LIST_FOREACH(origins, l, sec) {
     96 		printf(" -> %s://%s port %i\n",
     97 				ewk_security_origin_protocol_get(sec),
     98 				ewk_security_origin_host_get(sec),
     99 				ewk_security_origin_port_get(sec));
    100 	}
    101 	*/
    102 }
    103 
    104 static void
    105 url_changed_cb(void *data, Evas_Object *obj, void *event_info)
    106 {
    107 	Buffer_Data *bd = data;
    108 	Window_Data *wd = bd->window;
    109 	const char *url = event_info;
    110 	// Arg a = { .i = Silent, .s = strdup(JS_SETUP_HINTS) };
    111 
    112 	if (bd != wd->cur_buf)
    113 		return;
    114 
    115 	// userscript_hooks_start(elm_web_uri_get(td->web));
    116 	// script(&a, bd->window);
    117 	// free(a.s);
    118 
    119 	if (bd->window->mode == ModeInsert || bd->window->mode == ModeHints) {
    120 		Arg a = { .i = ModeNormal };
    121 		set(&a, bd->window);
    122 	}
    123 
    124 	bd->window->manual_focus = EINA_FALSE;
    125 
    126 	if (strncmp(url, "http://", 7) == 0)
    127 		url += 7;
    128 	else if (strncmp(url, "https://", 8) == 0)
    129 		url += 8;
    130 	elm_object_text_set(wd->status_url, url);
    131 	evas_object_show(wd->status_url);
    132 
    133 	// ewk_storage_manager_origins_get(ewk_context_storage_manager_get(ewk_context_default_get()), storage_origins_cb, bd);
    134 }
    135 
    136 static void
    137 load_finished_cb(void *data, Evas_Object *obj, void *event_info)
    138 {
    139 	Buffer_Data *bd = data;
    140 	Window_Data *wd = bd->window;
    141 	Eina_Bool scripts = 1;
    142 
    143 	/* g_object_get(settings, "enable-scripts", &scripts, NULL); */
    144 	/* TRUE will disable automatic focusing of input fields via Javascript*/
    145 	static Eina_Bool escape_input_on_load    = EINA_TRUE; 
    146 	if (escape_input_on_load && scripts && !wd->manual_focus && !elm_object_focus_get(wd->url)) {
    147 		Arg a = { .i = Silent, .s = strdup("hints.clearFocus();") };
    148 		script(&a, wd);
    149 		free(a.s);
    150 		a.i = ModeNormal;
    151 		a.s = NULL;
    152 		set(&a, wd);
    153 	}
    154 
    155 	// userscript_hooks_end(elm_web_uri_get(td->web));
    156 }
    157 
    158 static void
    159 load_error_cb(void *data, Evas_Object *webview, void *event_info)
    160 {
    161 	Eina_Strbuf* buffer;
    162 	const Ewk_Error *error = event_info;
    163 	unsigned int error_code = ewk_error_code_get(error);
    164 
    165 	/* This is a cancellation, do not display the error page */
    166 	if (ewk_error_cancellation_get(error))
    167 		return;
    168 
    169 	if (error_code == 204)
    170 		/* plugin will handle load, no need to report error */
    171 		return;
    172 
    173 	buffer = eina_strbuf_new();
    174 	eina_strbuf_append_printf(buffer, "<html><body><div style=\"background-color:rgba(0, 0, 200, 0.5);\">ERROR!</div><br><div>Code: %d<br>Description: %s<br>URL: %s</div></body</html>",
    175 			error_code, ewk_error_description_get(error), ewk_error_url_get(error));
    176 
    177 	ewk_view_html_string_load(webview, eina_strbuf_string_get(buffer), 0, ewk_error_url_get(error));
    178 	eina_strbuf_free(buffer);
    179 }
    180 
    181 static Eina_Bool
    182 process_keypress(void *event_info, Window_Data *wd)
    183 {
    184 	Key key, *inc_key;
    185 	App_Data *ad = wd->app;
    186 	Evas_Event_Key_Down *ev = event_info;
    187 	Eina_List *l;
    188 
    189 	EINA_LIST_FOREACH(ad->keylistroot, l, inc_key) {
    190 		/* avoid lots of dereferences */
    191 		key = *inc_key;
    192 		if ((key.mask == 0 || evas_key_modifier_is_set(ev->modifiers, key.mask))
    193 				&& (key.modkey == wd->current_modkey
    194 					|| (!key.modkey && !wd->current_modkey)
    195 				|| key.modkey ==  '*' )    // wildcard
    196 				&& !strcmp(key.key, ev->key)
    197 				&& key.func)
    198 			if (key.func(&key.arg, wd)) {
    199 				wd->current_modkey = wd->count = 0;
    200 				gui_count_update(wd);
    201 				gui_modkey_update(wd);
    202 				return EINA_TRUE;
    203 			}
    204 	}
    205 	return EINA_FALSE;
    206 }
    207 
    208 static void
    209 webview_keypress_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) 
    210 {
    211     Arg a = { .i = ModeNormal, .s = NULL };
    212     // int keyval;
    213 	Evas_Event_Key_Down *ev = event_info;
    214 	Buffer_Data *td = data;
    215 	Window_Data *wd = td->window;
    216 	App_Data *ad = wd->app;
    217     // GdkModifierType irrelevant;
    218 
    219     /* Get a mask of modifiers that shouldn't be considered for this event.
    220      * E.g.: It shouldn't matter whether ';' is shifted or not. */
    221     // gdk_keymap_translate_keyboard_state(keymap, event->hardware_keycode,
    222     //        event->state, event->group, &keyval, NULL, NULL, &irrelevant);
    223 
    224     switch (wd->mode) {
    225     case ModeNormal:
    226 		// if ((CLEAN(event->state) & ~irrelevant) == 0) {
    227 		if (IS_ESCAPE(ev)) {
    228 			a.i = Info;
    229 			a.s = strdup("");
    230 			echo(&a, wd);
    231 			elm_box_clear(wd->event_box);
    232 			evas_object_hide(wd->event_box);
    233 			free(a.s);
    234 		} else if (wd->current_modkey == 0 && 
    235 				(( strcmp(ev->key, "1") >= 0 && strcmp(ev->key, "9") <= 0)
    236 				 || (!strcmp(ev->key, "0") && wd->count))) {
    237 			// ad->count = (ad->count ? ad->count * 10 : 0) + (ev->key - "0");
    238 			wd->count = (wd->count ? wd->count * 10 : 0) + atoi(ev->key);
    239 			gui_count_update(wd);
    240 			return;
    241 		} else if (strchr(ad->modkeys, ev->key[0]) && wd->current_modkey != ev->key[0]) {
    242 			wd->current_modkey = ev->key[0];
    243 			gui_modkey_update(wd);
    244 			return;
    245 		}
    246 		// }
    247 		/* keybindings */
    248 		if (process_keypress(event_info, wd) == EINA_TRUE) return;
    249 
    250 		break;
    251     case ModeInsert:
    252 		if (IS_ESCAPE(ev)) {
    253 			a.i = Silent;
    254 			a.s = strdup("hints.clearFocus();");
    255 			script(&a, wd);
    256 			free(a.s);
    257 			a.i = ModeNormal;
    258 			set(&a, wd);
    259 			// ewk_view_input_method_state_set(td->web, FALSE);
    260 			return;
    261 		}
    262     case ModePassThrough:
    263 		if (IS_ESCAPE(ev)) {
    264 			echo(&a, wd);
    265 			set(&a, wd);
    266 			return;
    267 		}
    268 		break;
    269     case ModeSendKey:
    270 		echo(&a, wd);
    271 		set(&a, wd);
    272 		break;
    273 	}
    274 }
    275 
    276 /*
    277 static void
    278 console_cb(void *data, Evas_Object *obj, const char *message, unsigned int line, const char *source)
    279 {
    280     Arg a;
    281 	Buffer_Data *td = data;
    282 
    283     // Don't change internal mode if the browser doesn't have focus to prevent inconsistent states
    284     // if (gtk_window_has_toplevel_focus(window)) {
    285     if (elm_object_focus_get(td->window->win)) {
    286         if (!strcmp(message, "hintmode_off") || !strcmp(message, "insertmode_off")) {
    287             a.i = ModeNormal;
    288             set(&a, td->window);
    289 			return;
    290         } else if (!strcmp(message, "insertmode_on")) {
    291             a.i = ModeInsert;
    292             set(&a, td->window);
    293 			return;
    294         }
    295     }
    296 }
    297 */
    298 
    299 void
    300 icon_changed_cb(void *data, Evas_Object *obj, void *event_info)
    301 {
    302 	Buffer_Data *bd = data;
    303 	Window_Data *wd = bd->window;
    304 
    305 	if (bd != wd->cur_buf)
    306 		return;
    307 
    308 	make_favicon(wd->status_favicon, bd);
    309 }
    310 
    311 static void
    312 bf_list_changed_cb(void *data, Evas_Object *obj, void *event_info)
    313 {
    314 	Buffer_Data *bd = data;
    315 	Window_Data *wd = bd->window;
    316 
    317 	make_bf_list(wd->status_back_forward, bd);
    318 }
    319 
    320 static void
    321 policy_new_window_cb(void *data, Evas_Object *obj, void *event_info)
    322 {
    323 	Buffer_Data *bd = data;
    324 	Ewk_Navigation_Policy_Decision *decision = event_info;
    325 	Ewk_Url_Request *req = ewk_navigation_policy_request_get(decision);
    326 	const char *url = ewk_url_request_url_get(req);
    327 
    328 	buffer_add(0, bd->window, url, NULL);
    329 	printf("policy_new_window()\n");
    330 }
    331 
    332 static void
    333 close_window_cb(void *data, Evas_Object *obj, void *event_info)
    334 {
    335 	printf("close_window()\n");
    336 }
    337 
    338 static void
    339 create_window_cb(void *data, Evas_Object *obj, void *event_info)
    340 {
    341 	printf("create_window()\n");
    342 }
    343 
    344 static void
    345 free_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
    346 {
    347 	Buffer_Data *bd = data;
    348 	Window_Data *wd = bd->window;
    349 	Session_Item *si;
    350 
    351 	if ((si = evas_object_data_get(wd->cur_buf->view, "session")))
    352 		session_window_tabs_del(wd->session_window, si);
    353 
    354 	// if (!wd->app->exiting)
    355 	//	wd->cur_buf->view = NULL;
    356 
    357 	wd->buffer_list = eina_list_remove(wd->buffer_list, bd);
    358 
    359 	printf("buffer_free_cb()\n");
    360 	free(bd);
    361 }
    362 
    363 static void
    364 mousewheel_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
    365 {
    366 	Buffer_Data *bd = data;
    367 	gui_scroll_update(bd->window);
    368 }
    369 
    370 Buffer_Data*
    371 buffer_add(const unsigned char flags, Window_Data *wd, const char *url, Session_Item *session_item)
    372 {
    373 	Buffer_Data *bd;
    374 	Ewk_Settings *settings;
    375 
    376 	bd = calloc(1, sizeof(Buffer_Data));
    377 	if (!bd)
    378 		return NULL;
    379 
    380 	/* if the InNewWindow flag is set, create the buffer in a new window */
    381 	if (flags & InNewWindow)
    382 		wd = window_add(wd->app, NULL);
    383 
    384 	wd->buf_total++;
    385 
    386 	bd->window = wd;
    387 	bd->buf_number = wd->buf_total;
    388 	bd->inspector_enabled = EINA_FALSE;
    389 	bd->zoom_level = DEFAULT_ZOOM_LEVEL;
    390 
    391 #if 1
    392 	Ewk_View_Smart_Class *ewkViewClass = miniBrowserViewSmartClass();
    393 	/* located in buffer_callback.c */
    394 	ewkViewClass->run_javascript_alert = on_javascript_alert;
    395 	ewkViewClass->run_javascript_confirm = on_javascript_confirm;
    396 	ewkViewClass->run_javascript_prompt = on_javascript_prompt;
    397 	ewkViewClass->window_geometry_get = on_window_geometry_get;
    398 	ewkViewClass->window_geometry_set = on_window_geometry_set;
    399 	// ewkViewClass->fullscreen_enter = on_fullscreen_enter;
    400 	// ewkViewClass->fullscreen_exit = on_fullscreen_exit;
    401 
    402 	Evas *evas = evas_object_evas_get(wd->win);
    403 	Evas_Smart *smart = evas_smart_class_new(&ewkViewClass->sc);
    404 	bd->view = ewk_view_smart_add(evas, smart, ewk_context_default_get());
    405 	// ewk_view_theme_set(bd->view, THEME_DIR "/default.edj");
    406 	ewk_view_theme_set(bd->view, "/usr/share/ewebkit-0/themes/default.edj");
    407 #else
    408 	bd->view = ewk_view_add(evas_object_evas_get(wd->win));
    409 	ewk_view_theme_set(bd->view, "/usr/share/ewebkit-0/themes/default.edj");
    410 #endif
    411 
    412 	settings = ewk_view_settings_get(bd->view);
    413 	ewk_settings_file_access_from_file_urls_allowed_set(settings, EINA_TRUE);
    414 	ewk_settings_dns_prefetching_enabled_set(settings, EINA_TRUE);
    415 	ewk_settings_developer_extras_enabled_set(settings, EINA_TRUE);
    416 	ewk_settings_frame_flattening_enabled_set(settings, EINA_TRUE);
    417 	ewk_settings_preferred_minimum_contents_width_set(settings, 0);
    418 	ewk_settings_continuous_spell_checking_enabled_set(EINA_TRUE);
    419 
    420 	evas_object_size_hint_weight_set(bd->view, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    421 	evas_object_size_hint_align_set(bd->view, EVAS_HINT_FILL, EVAS_HINT_FILL);
    422 
    423 	if (wd->cur_buf)
    424 		wd->buffer_list = eina_list_append_relative(wd->buffer_list, bd, wd->cur_buf);
    425 	else
    426 		wd->buffer_list = eina_list_append(wd->buffer_list, bd);
    427 
    428 	Evas_Object *v = bd->view;
    429 
    430 	// elm_web_window_create_hook_set(td->web, webview_create_window_cb, td->window);
    431 	// elm_web_console_message_hook_set(td->web, webview_console_cb, td);
    432 
    433 	/* misc callbacks - buffer_callback.c */
    434 	evas_object_smart_callback_add(v, "webprocess,crashed", webprocess_crashed_cb, wd);
    435 	evas_object_smart_callback_add(v, "authentication,request", on_authentication_request, wd);
    436 	evas_object_smart_callback_add(v, "tooltip,text,set", on_tooltip_text_set, wd);
    437 	evas_object_smart_callback_add(v, "tooltip,text,unset", on_tooltip_text_unset, wd);
    438 	evas_object_smart_callback_add(v, "file,chooser,request", on_file_chooser_request, wd);
    439 	/* not yet implemented in ewebkit2
    440 	evas_object_smart_callback_add(v, "link,hover,in", hoverlink_cb, td);
    441 	evas_object_smart_callback_add(v, "link,hover,out",hoverlink_out_cb, td);
    442 	evas_object_smart_callback_add(v, "inputmethod,changed", inputmethod_changed_cb, td);
    443 	*/
    444 
    445 	/* downloads - download.h */
    446 	evas_object_smart_callback_add(v, "download,request", download_request_cb, wd);
    447 	evas_object_smart_callback_add(v, "download,finished", download_finished_cb, wd);
    448 	evas_object_smart_callback_add(v, "download,failed", download_failed_cb, wd);
    449 	evas_object_smart_callback_add(v, "download,cancelled", download_cancelled_cb, wd);
    450 
    451 	/* navigation */
    452 	evas_object_smart_callback_add(v, "title,changed", title_changed_cb, bd);
    453 	evas_object_smart_callback_add(v, "url,changed", url_changed_cb, bd);
    454 	evas_object_smart_callback_add(v, "load,progress", load_progress_cb, bd);
    455 	evas_object_smart_callback_add(v, "load,finished", load_finished_cb, bd);
    456 	evas_object_smart_callback_add(v, "load,error", load_error_cb, bd);
    457 
    458 	/* other */
    459 	evas_object_smart_callback_add(v, "icon,changed", icon_changed_cb, bd);
    460 	evas_object_smart_callback_add(v, "back,forward,list,changed", bf_list_changed_cb, bd);
    461 	evas_object_smart_callback_add(v, "policy,decision,new,window", policy_new_window_cb, bd);
    462 	evas_object_smart_callback_add(v, "close,window", close_window_cb, bd);
    463 	evas_object_smart_callback_add(v, "create,window", create_window_cb, bd);
    464 
    465 	/* evas events */
    466 	evas_object_event_callback_add(v, EVAS_CALLBACK_FREE, free_cb, bd);
    467 	evas_object_event_callback_add(v, EVAS_CALLBACK_KEY_DOWN, webview_keypress_cb, bd);
    468 	evas_object_event_callback_add(v, EVAS_CALLBACK_MOUSE_WHEEL, mousewheel_cb, bd);
    469 
    470 	if (url)
    471 		ewk_view_url_set(bd->view, url);
    472 	else
    473 		ewk_view_url_set(bd->view, config_home_page_get(wd->app->config));
    474 
    475 	if (!session_item) {
    476 		if (!(session_item = session_item_new(ewk_view_url_get(bd->view), EINA_FALSE, 0, 0)))
    477 			CRITICAL("Could not create session object");
    478 		session_window_tabs_add(wd->session_window, session_item);
    479 	}
    480 
    481 	evas_object_data_set(bd->view, "session", session_item);
    482 	evas_object_data_set(bd->view, "buffer_data", bd);
    483 	evas_object_hide(bd->view);
    484 
    485 	if (flags & SwitchToBuffer)
    486 		window_main_buffer_set(bd);
    487 
    488 	return bd;
    489 }
    490