viking

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

main.c (12855B)


      1 /*
      2     (c) 2009 by Leon Winter
      3     (c) 2009-2012 by Hannes Schueller
      4     (c) 2009-2010 by Matto Fransen
      5     (c) 2010-2011 by Hans-Peter Deifel
      6     (c) 2010-2011 by Thomas Adam
      7     (c) 2011 by Albert Kim
      8     (c) 2011 by Daniel Carl
      9     (c) 2012 by Matthew Carter
     10     see LICENSE file
     11 */
     12 
     13 #include <Elementary.h>
     14 #include <EWebKit2.h>
     15 
     16 #include "viking_state.h"
     17 #include "viking.h"
     18 #include "utilities.h"
     19 #include "window.h"
     20 #include "buffer.h"
     21 
     22 
     23 /* functions */
     24 EAPI_MAIN int elm_main(int argc, char *argv[]);
     25 const char *uri_sanitize(const char *);
     26 
     27 static Eina_Bool
     28 session_save_cb(void *data)
     29 {
     30 	Window_Data *wd;
     31 	Buffer_Data *bd;
     32 	Eina_List *buffer_iter, *win_iter;
     33 	Session_Item *si;
     34 	App_Data *ad = data;
     35 	Eina_Bool focused;
     36 	// int sx, sy;
     37 
     38 	/* TODO: only save when something has changed */
     39 	if (!config_restore_state_get(ad->config)) goto end;
     40 
     41 	EINA_LIST_FOREACH(ad->windows, win_iter, wd) {
     42 
     43 		EINA_LIST_FOREACH(wd->buffer_list, buffer_iter, bd) {
     44 
     45 			Evas_Object *view = bd->view;
     46 			focused = (bd == wd->cur_buf);
     47 
     48 			si = evas_object_data_get(bd->view, "session");
     49 			if (!si)
     50 				printf("buffer %p doesn't have a Session_Item, ignoring\n", bd);
     51 
     52 			session_item_url_set(si, ewk_view_url_get(view));
     53 
     54 			/*
     55 			ewk_frame_scroll_pos_get(frame, &sx, &sy);
     56 			if (session_item_scroll_x_get(si) != sx || session_item_scroll_y_get(si) != sy) {
     57 				session_item_scroll_x_set(si, sx);
     58 				session_item_scroll_y_set(si, sy);
     59 			}
     60 			*/
     61 
     62 			if (session_item_focused_get(si) != focused)
     63 				session_item_focused_set(si, focused);
     64 		}
     65 	}
     66 
     67 	session_save(ad->session, NULL);
     68 end:
     69 	return ECORE_CALLBACK_RENEW;
     70 }
     71 
     72 static Eina_Bool
     73 session_restore(App_Data *ad)
     74 {
     75 	Eina_List *windows, *window_iter;
     76 	Eina_List *buffers, *buffers_iter;
     77 	Session_Window *window;
     78 	Session_Item *buffer;
     79 	Window_Data *wd;
     80 	Buffer_Data *bd, *focused_buffer = NULL;
     81 	int n_tabs = 0;
     82 
     83 	windows = session_windows_list_get(ad->session);
     84 	EINA_LIST_FOREACH(windows, window_iter, window) {
     85 
     86 		buffers = session_window_tabs_list_get(window);
     87 		wd = window_add(ad, window);
     88 		EINA_LIST_FOREACH(buffers, buffers_iter, buffer) {
     89 			bd = buffer_add(0, wd, session_item_url_get(buffer), buffer);
     90 			// session_restore_delayed_scroll(win->current_view, item);
     91 			if (session_item_focused_get(buffer))
     92 				focused_buffer = bd;
     93 			n_tabs++;
     94 		}
     95 		window_main_buffer_set(focused_buffer);
     96 	}
     97 
     98 	return !!n_tabs;
     99 }
    100 
    101 static void
    102 hist_nav_cb(const Evas_Object *view, Ewk_Navigation_Data *nav_data, void *data)
    103 {
    104 	Hist_Item *item;
    105 	App_Data *ad = data;
    106 	Eina_Strbuf *proto = eina_strbuf_new();
    107 	Eina_Stringshare *title = ewk_navigation_data_title_get(nav_data);
    108 	Eina_Stringshare *url = ewk_navigation_data_url_get(nav_data);
    109 
    110 	if (strncmp(url, "http://", 7) == 0) {
    111 		eina_strbuf_append(proto, "http");
    112 		url += 7;
    113 	}
    114 	else if (strncmp(url, "https://", 8) == 0) {
    115 		eina_strbuf_append(proto, "https");
    116 		url += 8;
    117 	}
    118 
    119 	item = hist_items_get(ad->history, url);
    120 	if (item && hist_item_enabled_get(item)) {
    121 		hist_item_visit_count_set(item, hist_item_visit_count_get(item) + 1);
    122 		hist_item_last_visit_set(item, ecore_time_unix_get());
    123 		hist_item_title_set(item, title);
    124 		hist_item_proto_set(item, eina_strbuf_string_get(proto));
    125 	}
    126 	else if (!item && config_enable_history_get(ad->config)) {
    127 		hist_items_add(ad->history, url, hist_item_new(
    128 					EINA_TRUE,
    129 					title,
    130 					url,
    131 					eina_strbuf_string_get(proto),
    132 					1,
    133 					ecore_time_unix_get()));
    134 	}
    135 
    136 	eina_strbuf_free(proto);
    137 }
    138 
    139 static void
    140 hist_redir_cb(const Evas_Object *view, const char *source_url, const char *dest_url, void *data)
    141 {
    142 	int prefix, min, suffix, src_len, dest_len;
    143 
    144 	if (strcmp(ewk_view_url_get(view), dest_url) != 0) {
    145 		printf("hist_redir_cb() not showing third party redirect\n");
    146 		return;
    147 	}
    148 
    149 	src_len = strlen(source_url);
    150 	dest_len = strlen(dest_url);
    151 
    152 	if (src_len < dest_len)
    153 		min = src_len;
    154 	else
    155 		min = dest_len;
    156 
    157 	prefix = 0;
    158 	while (source_url[prefix] == dest_url[prefix] && prefix < min)
    159 			prefix++;
    160 
    161 	suffix = 0;
    162 	while (source_url[src_len - suffix - 1] == dest_url[dest_len - suffix - 1] && suffix < min)
    163 		suffix++;
    164 
    165 	// printf("redir: prefix = %i, suffix = %i, min = %i\n", prefix, suffix, min);
    166 
    167 	if (min - suffix - prefix < 0) {
    168 		printf("redirecion() from %s to %s\n", source_url, dest_url);
    169 		return;
    170 	}
    171 
    172 	Eina_Strbuf *buf = eina_strbuf_new();
    173 	eina_strbuf_append_n(buf, source_url, prefix);
    174 	eina_strbuf_append(buf, "{");
    175 	eina_strbuf_append_n(buf, source_url + prefix, src_len - suffix - prefix);
    176 	eina_strbuf_append(buf, " => ");
    177 	eina_strbuf_append_n(buf, dest_url + prefix, dest_len - suffix - prefix);
    178 	eina_strbuf_append(buf, "}");
    179 	eina_strbuf_append_n(buf, source_url + src_len - suffix, suffix);
    180 
    181 	printf("redirection() %s\n", eina_strbuf_string_steal(buf));
    182 }
    183 
    184 static void
    185 hist_client_redir_cb(const Evas_Object *view, const char *source_url, const char *dest_url, void *data)
    186 {
    187 	printf("client cur url = %s\n", ewk_view_url_get(view));
    188 	printf("client ");
    189 	hist_redir_cb(view, source_url, dest_url, data);
    190 }
    191 
    192 static void
    193 hist_server_redir_cb(const Evas_Object *view, const char *source_url, const char *dest_url, void *data)
    194 {
    195 	printf("server cur url = %s\n", ewk_view_url_get(view));
    196 	printf("server ");
    197 	hist_redir_cb(view, source_url, dest_url, data);
    198 }
    199 
    200 static void
    201 hist_visited_cb(void *data)
    202 {
    203 	App_Data *ad = data;
    204 	void *hash_data;
    205 	Eina_Strbuf *url_buf = eina_strbuf_new();
    206 	Eina_Iterator *it = eina_hash_iterator_tuple_new(hist_items_hash_get(ad->history));
    207 
    208 	while (eina_iterator_next(it, &hash_data)) {
    209 		Eina_Hash_Tuple *t = hash_data;
    210 		Hist_Item *hist_item = t->data;
    211 
    212 		eina_strbuf_append(url_buf, hist_item_proto_get(hist_item));
    213 		eina_strbuf_append(url_buf, "://");
    214 		eina_strbuf_append(url_buf, hist_item_url_get(hist_item));
    215 		ewk_context_visited_link_add(ewk_context_default_get(), eina_strbuf_string_get(url_buf));
    216 		eina_strbuf_reset(url_buf);
    217 	}
    218 
    219 	eina_iterator_free(it);
    220 }
    221 
    222 static void
    223 hist_title_updated_cb(const Evas_Object *vew, const char *title, const char *url, void *data)
    224 {
    225 	// printf("title_update() %s has new title %s\n", url, title);
    226 }
    227 
    228 static void
    229 generic_url_scheme_request_cb(Ewk_Url_Scheme_Request *request, void *user_data)
    230 {
    231 	Eina_Strbuf *buf = eina_strbuf_new();
    232 	char *handler = user_data;
    233 	const char *url = ewk_url_scheme_request_url_get(request);
    234 	eina_strbuf_append_printf(buf, "%s \"%s\"\n", handler, url);
    235 	printf("%s\n", eina_strbuf_string_get(buf));
    236 	ecore_exe_run(eina_strbuf_string_steal(buf), NULL);
    237 	// ewk_url_scheme_request_finish(request, NULL, 0, "text/html");
    238 }
    239 
    240 static void
    241 setup_main_callbacks(App_Data *ad, const char *cookie_path)
    242 {
    243 	int i;
    244 	Ewk_Cookie_Manager *cookie_manager;
    245 	Ewk_Context *context = ewk_context_default_get();
    246 
    247 	ewk_context_cache_model_set(context, EWK_CACHE_MODEL_PRIMARY_WEBBROWSER);
    248 	ewk_context_favicon_database_directory_set(context, NULL);
    249 
    250 	/* set cookie policy to use text file and no third party cookies */
    251 	cookie_manager = ewk_context_cookie_manager_get(context);
    252 	ewk_cookie_manager_persistent_storage_set(cookie_manager, cookie_path,
    253 			EWK_COOKIE_PERSISTENT_STORAGE_TEXT);
    254 	ewk_cookie_manager_accept_policy_set(cookie_manager,
    255 			EWK_COOKIE_ACCEPT_POLICY_NO_THIRD_PARTY);
    256 
    257 	/* history hooks */
    258 	ewk_context_history_callbacks_set(
    259 			context,
    260 			hist_nav_cb,
    261 			hist_client_redir_cb,
    262 			hist_server_redir_cb,
    263 			hist_title_updated_cb,
    264 			hist_visited_cb,
    265 			ad
    266 	);
    267 
    268 	/* url scheme registration */
    269 	URIHandler uri_handlers[] = {
    270 		{ "mailto",       "terminology -e mutt" },
    271 		{ "ftp",          "terminology -e wget ftp://" },
    272 		{ "magnet",       "xterm -e rtorrent" },
    273 	};
    274 
    275 	for (i = 0; i < LENGTH(uri_handlers); i++)
    276 		ewk_context_url_scheme_register(context, uri_handlers[i].handle, 
    277 				generic_url_scheme_request_cb, uri_handlers[i].handler);
    278 }
    279 
    280 
    281 static Eina_Bool
    282 _client_add(void *data, int type, void *event_info)
    283 {
    284 	Ecore_Con_Event_Server_Add *ev = event_info;
    285 	char *url = data;
    286 
    287 	ecore_con_server_send(ev->server, url, strlen(url));
    288 	ecore_con_server_flush(ev->server);
    289 
    290 	ecore_main_loop_quit();
    291 	return ECORE_CALLBACK_RENEW;
    292 }
    293 
    294 static Eina_Bool
    295 _client_del(void *data, int type, void *event_info)
    296 {
    297 	Ecore_Con_Event_Server_Del *ev = event_info;
    298 	if (!ev->server)
    299 	{
    300 		printf("Failed to establish connection to the server.\nExiting.\n");
    301 		ecore_main_loop_quit();
    302 		return ECORE_CALLBACK_RENEW;
    303 	}
    304 
    305 	ecore_con_server_del(ev->server);
    306 
    307 	ecore_main_loop_quit();
    308 	return ECORE_CALLBACK_RENEW;
    309 }
    310 
    311 static Eina_Bool
    312 _server_data(void *data, int type, void *event_info)
    313 {
    314 	Ecore_Con_Event_Client_Data *ev = event_info;
    315 	char *uri = ev->data;
    316 	App_Data *ad = data;
    317 
    318 	Window_Data *wd = window_add(ad, NULL);
    319 	buffer_add(SwitchToBuffer, wd, uri, NULL);
    320 
    321 	return ECORE_CALLBACK_RENEW;
    322 }
    323 
    324 static Eina_Bool
    325 _server_del(void *data, int type, void *event_info)
    326 {
    327 	Ecore_Con_Event_Client_Del *ev = event_info;
    328 
    329 	if (!ev->client)
    330 		return ECORE_CALLBACK_RENEW;
    331 
    332 	ecore_con_client_del(ev->client);
    333 	return ECORE_CALLBACK_RENEW;
    334 }
    335 
    336 EAPI_MAIN int
    337 elm_main(int argc, char *argv[])
    338 {
    339 	App_Data *ad;
    340 	char *basename, path[PATH_MAX];
    341 	const char *uri = NULL;
    342 	Config *config;
    343 	Hist *hist;
    344 	Session *session;
    345 	size_t dirlen;
    346 	Ecore_Timer *session_save_timer = NULL;
    347 	Ecore_Con_Server *svr;
    348 
    349 	if (argc == 2)
    350 		uri = uri_sanitize(argv[1]);
    351 
    352 	ecore_con_init();
    353 	if ((svr = ecore_con_server_connect(ECORE_CON_LOCAL_USER, "viking", 0, NULL))) {
    354 		if (!uri)
    355 			uri = DEFAULT_URL;
    356 
    357 		ecore_event_handler_add(ECORE_CON_EVENT_SERVER_ADD, _client_add, uri);
    358 		ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DEL, _client_del, uri);
    359 
    360 		ecore_main_loop_begin();
    361 		ecore_con_shutdown();
    362 		elm_shutdown();
    363 		exit(0);
    364 	}
    365 
    366 	if (!ewk_init())
    367 		return EXIT_FAILURE;
    368 
    369 	ewk_view_smart_class_set(miniBrowserViewSmartClass());
    370 
    371 	eet_init();
    372 	viking_state_init();
    373 
    374 	/* calloc zeros the memory!! */
    375 	ad = calloc(1, sizeof(App_Data));
    376 	if (!ad) return -1;
    377 
    378 	/* see if ~/.config/viking exists and create it if not */
    379 	dirlen = snprintf(path, sizeof(path), "%s/viking", efreet_config_home_get());
    380 	if (dirlen >= sizeof(path))
    381 		ERR("Path is too long: %s/viking", efreet_config_home_get());
    382 	if (!ecore_file_mkpath(path))
    383 		ERR("Could not create %s", path);
    384 
    385 	basename = path + dirlen;
    386 	basename[0] = '/';
    387 	basename++;
    388 	dirlen++;
    389 
    390 	eina_strlcpy(basename, "config.eet", sizeof(path) - dirlen);
    391 	if (!(config = config_load(path))) {
    392 		config = config_new(EINA_TRUE /* allow_popup */,
    393 				EINA_TRUE /* enable_auto_load_images */,
    394 				EINA_TRUE /* enable_auto_shrink_images */,
    395 				EINA_TRUE /* enable_javascript */,
    396 				EINA_FALSE /* enable_private_mode */,
    397 				EINA_TRUE, /* global history */
    398 				DEFAULT_URL /* home_page */,
    399 				NULL /* proxy */,
    400 				EINA_TRUE /* restore_state */,
    401 				NULL, /* user agent string */
    402 				EINA_FALSE /* frame_flattening */,
    403 				EINA_FALSE /* text_only_zoom */,
    404 				12 /* minimum_font_size */,
    405 				EWK_COOKIE_ACCEPT_POLICY_NO_THIRD_PARTY);
    406 		if (!config_save(config, path))
    407 			ERR("Could not save new configuration at %s", path);
    408 	}
    409 
    410 	if (!(hist = hist_load(path))) {
    411 		hist = hist_new();
    412 		if (!hist_save(hist, path))
    413 			ERR("Could not save new history file at %s", path);
    414 	}
    415 
    416 	if (!(session = session_load(path))) {
    417 		session = session_new(NULL);
    418 		if (!session_save(session, path))
    419 			ERR("Could not save new session file at %s", path);
    420 	}
    421 
    422 	eina_strlcpy(basename, "cookies.txt", sizeof(path) - dirlen);
    423 	setup_main_callbacks(ad, path);
    424 
    425 	session_save_timer = ecore_timer_loop_add(30, session_save_cb, ad);
    426 	if (!session_save_timer)
    427 		ERR("Could not register session save timer");
    428 
    429 	elm_theme_overlay_add(NULL, "./default.edj");
    430 	elm_config_engine_set("opengl_x11");
    431 
    432 	setup_modkeys(ad);
    433 	ad->config = config;
    434 	ad->history = hist;
    435 	ad->session = session;
    436 	ad->session_save_timer = session_save_timer;
    437 	ad->keylistroot = make_keyslist();
    438 
    439 	if (!(svr = ecore_con_server_add(ECORE_CON_LOCAL_USER, "viking", 0, NULL))) {
    440 		printf("could not create server -- this is bad!\n");
    441 		exit(1);
    442 	}
    443 
    444 	ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DEL, _server_del, ad);
    445 	ecore_event_handler_add(ECORE_CON_EVENT_CLIENT_DATA, _server_data, ad);
    446 	ecore_con_server_timeout_set(svr, 10);
    447 	// ecore_con_server_client_limit_set(svr, 3, 0);
    448 
    449 	/* try to restore session */
    450 	if (session_windows_count(session) > 0 && session_restore(ad))
    451 		printf("session restored successfully.\n");
    452 	else
    453 		buffer_add(SwitchToBuffer, window_add(ad, NULL), uri, NULL);
    454 
    455 	elm_run();
    456 
    457 	session_save_cb(ad);
    458 	config_save(ad->config, NULL);
    459 	hist_save(ad->history, NULL);
    460 	if (ad->session_save_timer)
    461 		ecore_timer_del(ad->session_save_timer);
    462 
    463 	// printf("viking was up for %0.3f seconds\n", ecore_con_server_uptime_get(svr));
    464 	elm_shutdown();
    465 	viking_state_shutdown();
    466 	eet_shutdown();
    467 	ecore_con_shutdown();
    468 
    469 	config_free(ad->config);
    470 	hist_free(ad->history);
    471 	session_free(ad->session);
    472 	eina_list_free(ad->windows);
    473 	eina_list_free(ad->downloads);
    474 	eina_list_free(ad->keylistroot);
    475 	free(ad->modkeys);
    476 	free(ad);
    477 
    478 	return 0;
    479 }
    480 ELM_MAIN()
    481