viking

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

window.c (16521B)


      1 
      2 #include <Elementary.h>
      3 #include <EWebKit2.h>
      4 
      5 #include "viking_state.h"
      6 #include "viking.h"
      7 #include "utilities.h"
      8 #include "commands.h"
      9 #include "window.h"
     10 #include "keymap.h"
     11 
     12 
     13 static Eina_Bool commandhistoryfetch(const Arg *, void *);
     14 
     15 static void
     16 inputbox_activate_cb(void *data, Evas_Object *obj, void *event_info) 
     17 {
     18 	const char *text;
     19 	Window_Data *wd = data;
     20 	// App_Data *ad = wd->app;
     21 	uint16_t length = strlen(elm_entry_entry_get(wd->url));
     22 	Arg a;
     23 	Eina_Bool forward = EINA_FALSE;
     24 
     25 	// printf("In inputbox_activate\n");
     26 
     27 	a.i = HideCompletion;
     28 	complete(&a, data);
     29 	if (length == 0)
     30 		return;
     31 	text = elm_entry_entry_get(wd->url);
     32 	if (length > 1 && text[0] == ':') {
     33 		process_line((text + 1), data);
     34 	} else if (length > 1 && ((forward = text[0] == '/') || text[0] == '?')) {
     35 		ewk_view_text_find_highlight_clear(wd->cur_buf->view);
     36 
     37 		ewk_view_text_find(wd->cur_buf->view, &text[1],
     38 				EWK_FIND_OPTIONS_SHOW_HIGHLIGHT | EWK_FIND_OPTIONS_CASE_INSENSITIVE, 1000);
     39 
     40 		wd->count = 0;
     41 		wd->search_direction = forward;
     42 		wd->search_handle = strdup(&text[1]);
     43 	} else if (text[0] == '.' || text[0] == ',' || text[0] == ';') {
     44 		a.i = Silent;
     45 		a.s = strdup("hints.fire();");
     46 		script(&a, data);
     47 		free(a.s);
     48 		gui_scroll_update(wd);
     49 	} else
     50 		return;
     51 	if (!wd->echo_active)
     52 		// gtk_entry_set_text(entry, "");
     53 		elm_entry_entry_set(wd->url, "");
     54 	// gtk_widget_grab_focus(GTK_WIDGET(webview));
     55 
     56 	/* process_line above may have deleted the tab, check if its still around */
     57 	if (wd->cur_buf->view) {
     58 		// elm_object_focus_set(elm_object_top_widget_get(wd->win), EINA_FALSE);
     59 		evas_object_focus_set(wd->cur_buf->view, EINA_TRUE);
     60 	}
     61 }
     62 
     63 static Eina_Bool
     64 commandhistoryfetch(const Arg *arg, void *data)
     65 {
     66 	Window_Data *wd = data;
     67 	// App_Data *ad = wd->app;
     68 	char *command;
     69 	const int length = eina_list_count(wd->commandhistory);
     70 
     71 	if (length > 0) {
     72 		if (arg->i == DirectionPrev) {
     73 			wd->commandpointer = (length + wd->commandpointer - 1) % length;
     74 		} else {
     75 			wd->commandpointer = (length + wd->commandpointer + 1) % length;
     76 		}
     77 
     78 		command = eina_list_nth(wd->commandhistory, wd->commandpointer);
     79 		// gtk_entry_set_text(GTK_ENTRY(inputbox), g_strconcat(":", command, NULL));
     80 		// gtk_editable_set_position(GTK_EDITABLE(inputbox), -1);
     81 		command = strdup_printf(":%s", command);
     82 		elm_entry_entry_set(wd->url, command);
     83 		free(command);
     84 		elm_entry_cursor_line_end_set(wd->url);
     85 		return EINA_TRUE;
     86 	}
     87 
     88 	return EINA_FALSE;
     89 }
     90 
     91 static void
     92 inputbox_keypress_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) 
     93 {
     94 	Arg a;
     95 	int numval;
     96 	Evas_Event_Key_Down *ev = event_info;
     97 	Window_Data *wd = data;
     98 	// App_Data *ad = wd->app;
     99 
    100 	if (wd->mode == ModeHints) {
    101 		// if (event->keyval == GDK_ISO_Left_Tab) {
    102 		if (!strcmp(ev->keyname, "Tab") && evas_key_modifier_is_set(ev->modifiers, "Shift")) {
    103 			a.i = Silent;
    104 			a.s = strdup("hints.focusPreviousHint();");
    105 			script(&a, data);
    106 			free(a.s);
    107 			gui_scroll_update(wd);
    108 			return;
    109 		}
    110 		// if (event->keyval == GDK_Tab) {
    111 		if (!strcmp(ev->keyname, "Tab")) {
    112 			a.i = Silent;
    113 			a.s = strdup("hints.focusNextHint();");
    114 			script(&a, data);
    115 			free(a.s);
    116 			gui_scroll_update(wd);
    117 			return;
    118 		}
    119 		// if (event->keyval == GDK_Return) {
    120 		if (!strcmp(ev->keyname, "Return")) {
    121 			a.i = Silent;
    122 			a.s = strdup_printf("hints.fire();");
    123 			script(&a, data);
    124 			free(a.s);
    125 			gui_scroll_update(wd);
    126 			return;
    127 		}
    128 	}
    129 	if (!strcmp(ev->keyname, "[") || !strcmp(ev->keyname, "Escape")) {
    130 		a.i = HideCompletion;
    131 		complete(&a, data);
    132 		a.i = ModeNormal;
    133 		wd->commandpointer = 0;
    134 		set(&a, data);
    135 		return;
    136 	} 
    137 	else if (!strcmp(ev->keyname, "Tab") && evas_key_modifier_is_set(ev->modifiers, "Shift")) {
    138 		a.i = DirectionPrev;
    139 		complete(&a, data);
    140 		return;
    141 	}
    142 	else if (!strcmp(ev->keyname, "Tab")) {
    143 		a.i = DirectionNext;
    144 		complete(&a, data);
    145 		return;
    146 	}
    147 	else if (!strcmp(ev->keyname, "Up")) {
    148 		a.i = DirectionPrev;
    149 		commandhistoryfetch(&a, data);
    150 		return;
    151 	} 
    152 	else if (!strcmp(ev->keyname, "Down")) {
    153 		a.i = DirectionNext;
    154 		commandhistoryfetch(&a, data);
    155 		return;
    156 	}
    157 
    158 	/*
    159 	switch (event->keyval) {
    160 		case GDK_bracketleft:
    161 		case GDK_Escape:
    162 			if (!IS_ESCAPE(event)) break;
    163 			a.i = HideCompletion;
    164 			complete(&a, data);
    165 			a.i = ModeNormal;
    166 			commandpointer = 0;
    167 			return set(&a, ad);
    168 			break;
    169 		case GDK_Tab:
    170 			a.i = DirectionNext;
    171 			return complete(&a, data);
    172 			break;
    173 		case GDK_Up:
    174 			a.i = DirectionPrev;
    175 			return commandhistoryfetch(&a);
    176 			break;
    177 		case GDK_Down:
    178 			a.i = DirectionNext;
    179 			return commandhistoryfetch(&a);
    180 			break;
    181 		case GDK_ISO_Left_Tab:
    182 			a.i = DirectionPrev;
    183 			return complete(&a, data);
    184 			break;
    185 	}
    186 	*/
    187 
    188 	if (wd->mode == ModeHints) {
    189 #if 0
    190 		if ((CLEAN(event->state) & GDK_SHIFT_MASK) &&
    191 				(CLEAN(event->state) & GDK_CONTROL_MASK) &&
    192 				(event->keyval == GDK_BackSpace)) {
    193 			count /= 10;
    194 			a.i = Silent;
    195 			a.s = g_strdup_printf("hints.updateHints(%d);", count);
    196 			script(&a, data);
    197 			g_free(a.s);
    198 			update_state();
    199 			return TRUE;
    200 		}
    201 #endif
    202 
    203 		// numval = g_unichar_digit_value((gunichar) gdk_keyval_to_unicode(event->keyval));
    204 		numval = atoi(ev->key);
    205 		if ((numval >= 1 && numval <= 9) || (numval == 0 && wd->count)) {
    206 			/* allow a zero as non-first number */
    207 			wd->count = (wd->count ? wd->count * 10 : 0) + numval;
    208 			a.i = Silent;
    209 			a.s = strdup_printf("hints.updateHints(%d);", wd->count);
    210 			script(&a, data);
    211 			free(a.s);
    212 			gui_count_update(wd);
    213 			return;
    214 		}
    215 	}
    216 }
    217 
    218 static void
    219 inputbox_keyrelease_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
    220 {
    221 	Arg a;
    222 	Window_Data *wd = data;
    223 	// guint16 length = gtk_entry_get_text_length(entry);
    224 	uint16_t length = strlen(elm_entry_entry_get(wd->url));
    225 
    226 	if (!length) {
    227 		a.i = HideCompletion;
    228 		complete(&a, data);
    229 		a.i = ModeNormal;
    230 		set(&a, data);
    231 	}
    232 }
    233 
    234 /* used for incremental search */
    235 static void
    236 inputbox_changed_cb(void *data, Evas_Object *obj, void *event_info) 
    237 {
    238 	Arg a;
    239 	Window_Data *wd = data;
    240 	const char *text = elm_entry_entry_get(wd->url);
    241 	uint16_t length = strlen(text);
    242 	Eina_Bool forward = EINA_FALSE;
    243 
    244 	/* Update incremental search if the user changes the search text.
    245 	 *
    246 	 * Note: gtk_widget_is_focus() is a poor way to check if the change comes
    247 	 *       from the user. But if the entry is focused and the text is set
    248 	 *       through gtk_entry_set_text() in some asyncrounous operation,
    249 	 *       I would consider that a bug.
    250 	 */
    251 
    252 	if (elm_object_focus_get(wd->url) && length > 1 && ((forward = text[0] == '/') || text[0] == '?')) {
    253 		ewk_view_text_find_highlight_clear(wd->cur_buf->view);
    254 		ewk_view_text_find(wd->cur_buf->view, &text[1],
    255 				EWK_FIND_OPTIONS_SHOW_HIGHLIGHT | EWK_FIND_OPTIONS_CASE_INSENSITIVE, 1000);
    256 		return;
    257 	} else if (elm_object_focus_get(wd->url) && length >= 1 &&
    258 			(text[0] == '.' || text[0] == ',' || text[0] == ';')) {
    259 		a.i = Silent;
    260 		switch (text[0]) {
    261 			case '.':
    262 				a.s = strdup_printf("hints.createHints('%s', 'f');", text + 1);
    263 				break;
    264 
    265 			case ',':
    266 				a.s = strdup_printf("hints.createHints('%s', 'F');", text + 1);
    267 				break;
    268 
    269 			case ';':
    270 				a.s = NULL;
    271 				switch (text[1]) {
    272 					case 's':
    273 						a.s = strdup_printf("hints.createHints('%s', 's');", text + 2);
    274 						break;
    275 					case 'y':
    276 						a.s = strdup_printf("hints.createHints('%s', 'y');", text + 2);
    277 						break;
    278 					case 'o':
    279 						a.s = strdup_printf("hints.createHints('%s', 'f');", text + 2);
    280 						break;
    281 					case 't': case 'w':
    282 						a.s = strdup_printf("hints.createHints('%s', 'F');", text + 2);
    283 						break;
    284 					case 'O': case 'T': case 'W':
    285 						a.s = strdup_printf("hints.createHints('%s', 'O');", text + 2);
    286 						break;
    287 					case 'i':
    288 						a.s = strdup_printf("hints.createHints('%s', 'i');", text + 2);
    289 						break;
    290 					case 'I':
    291 						a.s = strdup_printf("hints.createHints('%s', 'I');", text + 2);
    292 						break;
    293 				}
    294 				break;
    295 		}
    296 		wd->count = 0;
    297 		if (a.s) {
    298 			script(&a, data);
    299 			free(a.s);
    300 		}
    301 
    302 		return;
    303 	} else if (length == 0 && wd->followTarget[0]) {
    304 		wd->mode = ModeNormal;
    305 		a.i = Silent;
    306 		a.s = strdup("hints.clearHints();");
    307 		script(&a, data);
    308 		free(a.s);
    309 		wd->count = 0;
    310 		gui_count_update(wd);
    311 	}
    312 }
    313 
    314 static void
    315 delete_request_cb(void *data, Evas_Object *obj, void *event_info)
    316 {
    317 	Window_Data *wd = data;
    318 
    319 	printf("window requested deletion ..");
    320 
    321 	if (eina_list_count(wd->buffer_list) > 1) {
    322 		printf("denied, more than 1 buffer open\n");
    323 	}
    324 	else {
    325 		printf("ok!\n");
    326 		evas_object_del(wd->win);
    327 	}
    328 }
    329 
    330 static void
    331 free_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
    332 {
    333 	Window_Data *wd = data;
    334 	App_Data *ad = wd->app;
    335 
    336 	session_windows_del(ad->session, wd->session_window);
    337 	session_window_free(wd->session_window);
    338 
    339 	ad->windows = eina_list_remove(ad->windows, wd);
    340 
    341 	eina_list_free(wd->buffer_list);
    342 	eina_list_free(wd->commandhistory);
    343 	free(wd);
    344 	printf("window_free_cb()\n");
    345 }
    346 
    347 static void
    348 maximized_cb(void *data, Evas_Object *obj, void *event_info)
    349 {
    350 	printf("browser window maximized\n");
    351 }
    352 
    353 void
    354 window_main_buffer_set(Buffer_Data *new_buf)
    355 {
    356 	Window_Data *wd = new_buf->window;
    357 	Buffer_Data *old_buf = wd->cur_buf;
    358 	App_Data *ad = wd->app;
    359 
    360 	if (new_buf == old_buf || ad->exiting)
    361 		return;
    362 
    363 	if (old_buf) {
    364 		elm_box_unpack_all(wd->webkit_box);
    365 		evas_object_hide(old_buf->view);
    366 
    367 		// if (old_buf->inspector_enabled)
    368 		//	ewk_view_web_inspector_close(old_buf->view);
    369 	}
    370 
    371 	wd->cur_buf = new_buf;
    372 
    373 	if (new_buf) {
    374 		elm_box_pack_end(wd->webkit_box, new_buf->view);
    375 		evas_object_show(new_buf->view);
    376 
    377 		//if (new_buf->inspector_enabled) {
    378 		//	ewk_view_web_inspector_show(new_buf->view);
    379 		//}
    380 
    381 		/* left side */
    382 		make_buffer_number(wd->status_buffer_num, new_buf);
    383 		make_favicon(wd->status_favicon, new_buf);
    384 		make_url(wd->status_url, new_buf);
    385 		make_bf_list(wd->status_back_forward, new_buf);
    386 
    387 		/* right side */
    388 		gui_count_update(wd);
    389 		gui_modkey_update(wd);
    390 		gui_zoom_update(wd, ewk_view_scale_get(new_buf->view));
    391 		gui_scroll_update(wd);
    392 	}
    393 }
    394 
    395 Window_Data*
    396 window_add(App_Data *ad, Session_Window *session_window)
    397 {
    398 	Window_Data *wd;
    399 	Evas_Modifier_Mask mask;
    400 	Evas *e;
    401 	unsigned int i;
    402 
    403 	wd = calloc(1, sizeof(Window_Data));
    404 	if (!wd) return NULL;
    405 
    406 	Evas_Object *win, *bg, *box, *status_bar, *url, *webkit_box, *status_url;
    407 	Evas_Object *event_box, *web_inspector, *progress, *downloads;
    408 	Evas_Object *status_back_forward, *status_buffer_num, *status_favicon;
    409 	Evas_Object *status_count, *status_modkey, *status_zoom, *status_scroll;
    410 
    411 	elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
    412 
    413 	win = elm_win_add(NULL, "viking", ELM_WIN_BASIC);
    414 	//elm_win_screen_constrain_set(win, EINA_TRUE);
    415 	//elm_win_keyboard_mode_set(win, ELM_WIN_KEYBOARD_ON);
    416 
    417 	e = evas_object_evas_get(win);
    418 	for (i = 0; i < LENGTH(keys); i++) {
    419 		mask = evas_key_modifier_mask_get(e, keys[i].mask);
    420 		if (keys[i].key && !evas_object_key_grab(win, keys[i].key, mask, 0, EINA_FALSE))
    421 		 	fprintf(stderr, "grab failed mask = %s, key = %s\n", keys[i].mask , keys[i].key);
    422 	}
    423 
    424 	/* program bacground */
    425 	bg = elm_bg_add(win);
    426 	evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    427 	elm_win_resize_object_add(win, bg);
    428 	// elm_bg_color_set(bg, 0, 0, 0);
    429 	evas_object_layer_set(bg, EVAS_LAYER_MIN);
    430 	evas_object_show(bg);
    431 
    432 	/* main box that everything goes into, resizes with window */
    433 	box = elm_box_add(win);
    434 	evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    435 	elm_win_resize_object_add(win, box);
    436 	evas_object_show(box);
    437 
    438 	/* box that shows the web view */
    439 	webkit_box = elm_box_add(win);
    440 	evas_object_size_hint_weight_set(webkit_box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    441 	evas_object_size_hint_align_set(webkit_box, EVAS_HINT_FILL, EVAS_HINT_FILL);
    442 	elm_box_pack_end(box, webkit_box);
    443 	evas_object_show(webkit_box);
    444 
    445 	/* status bar container */
    446 	status_bar = elm_box_add(win);
    447 	elm_box_horizontal_set(status_bar, EINA_TRUE);
    448 	evas_object_size_hint_align_set(status_bar, EVAS_HINT_FILL, EVAS_HINT_FILL);
    449 	elm_box_pack_end(box, status_bar);
    450 	evas_object_show(status_bar);
    451 
    452 	/* status buffer number */
    453 	status_buffer_num = elm_label_add(win);
    454 	elm_box_pack_end(status_bar, status_buffer_num);
    455 	evas_object_show(status_buffer_num);
    456 
    457 	/* status favicon */
    458 	status_favicon = elm_box_add(win);
    459 	elm_box_pack_end(status_bar, status_favicon);
    460 	evas_object_show(status_favicon);
    461 
    462 	/* status current url */
    463 	status_url = elm_label_add(win);
    464 	elm_box_pack_end(status_bar, status_url);
    465 	evas_object_show(status_url);
    466 
    467 	/* status able to go back/forward indicator */
    468 	status_back_forward = elm_label_add(win);
    469 	evas_object_size_hint_weight_set(status_back_forward, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
    470 	evas_object_size_hint_align_set(status_back_forward, 0.0, EVAS_HINT_FILL);
    471 	elm_box_pack_end(status_bar, status_back_forward);
    472 	evas_object_show(status_back_forward);
    473 
    474 	/* status number of downloads */
    475 	downloads = elm_label_add(win);
    476 	evas_object_size_hint_align_set(downloads, 1.0, EVAS_HINT_FILL);
    477 	elm_box_pack_end(status_bar, downloads);
    478 	evas_object_show(downloads);
    479 
    480 	/* current "count" */
    481 	status_count = elm_label_add(win);
    482 	evas_object_size_hint_align_set(status_count, 1.0, EVAS_HINT_FILL);
    483 	elm_box_pack_end(status_bar, status_count);
    484 	evas_object_show(status_count);
    485 
    486 	/* current modkey */
    487 	status_modkey = elm_label_add(win);
    488 	evas_object_size_hint_align_set(status_modkey, 1.0, EVAS_HINT_FILL);
    489 	elm_box_pack_end(status_bar, status_modkey);
    490 	evas_object_show(status_modkey);
    491 
    492 	/* current zoom level */
    493 	status_zoom = elm_label_add(win);
    494 	evas_object_size_hint_align_set(status_zoom, 1.0, EVAS_HINT_FILL);
    495 	elm_box_pack_end(status_bar, status_zoom);
    496 	evas_object_show(status_zoom);
    497 
    498 	/* status current progress bar */
    499 	progress = elm_progressbar_add(win);
    500 	elm_progressbar_horizontal_set(progress, EINA_TRUE);
    501 	evas_object_size_hint_align_set(progress, 0.0, 1.0);
    502 	elm_progressbar_unit_format_set(progress, NULL);
    503 	evas_object_size_hint_min_set(progress, 100, 11);
    504 	evas_object_size_hint_max_set(progress, 100, 11);
    505 	elm_box_pack_end(status_bar, progress);
    506 	evas_object_show(progress);
    507 
    508 	/* scroll position */
    509 	status_scroll = elm_label_add(win);
    510 	evas_object_size_hint_align_set(status_scroll, 1.0, EVAS_HINT_FILL);
    511 	elm_box_pack_end(status_bar, status_scroll);
    512 	evas_object_show(status_scroll);
    513 
    514 	/* invisible until activated web inspector */
    515 	web_inspector = elm_box_add(win);
    516 	evas_object_size_hint_align_set(web_inspector, EVAS_HINT_FILL, EVAS_HINT_FILL);
    517 	elm_box_pack_end(box, web_inspector);
    518 	evas_object_hide(web_inspector);
    519 
    520 	/* invisible event box, populated on tab completions and :ls */
    521 	event_box = elm_box_add(win);
    522 	evas_object_size_hint_align_set(event_box, EVAS_HINT_FILL, EVAS_HINT_FILL);
    523 	elm_box_pack_end(box, event_box);
    524 	evas_object_hide(event_box);
    525 
    526 	/* main entry widget */
    527 	url = elm_entry_add(win);
    528 	elm_entry_single_line_set(url, EINA_TRUE);
    529 	elm_entry_scrollable_set(url, EINA_TRUE);
    530 	evas_object_size_hint_weight_set(url, EVAS_HINT_EXPAND, 0.0);
    531 	evas_object_size_hint_align_set(url, EVAS_HINT_FILL, EVAS_HINT_FILL);
    532 	elm_box_pack_end(box, url);
    533 	elm_entry_text_style_user_push(url, "DEFAULT='font=Monospace font_size=12'");
    534 	evas_object_show(url);
    535 
    536 	wd->win = win;
    537 	wd->bg = bg;
    538 	wd->main_box = box;
    539 	wd->webkit_box = webkit_box;
    540 	wd->url = url;
    541 	wd->status_buffer_num = status_buffer_num;
    542 	wd->status_favicon = status_favicon;
    543 	wd->status_url = status_url;
    544 	wd->status_back_forward = status_back_forward;
    545 	wd->status_count = status_count;
    546 	wd->status_modkey = status_modkey;
    547 	wd->status_zoom = status_zoom;
    548 	wd->progress_bar = progress;
    549 	wd->status_scroll = status_scroll;
    550 	wd->event_box = event_box;
    551 	wd->web_inspector = web_inspector;
    552 	wd->downloads = downloads;
    553 	wd->app = ad;
    554 	wd->mode = ModeNormal;
    555 	wd->echo_active = EINA_FALSE;
    556 
    557 	if (session_window) {
    558 		wd->session_window = session_window;
    559 	}
    560 	else {
    561 		wd->session_window = session_window_new(NULL, EINA_FALSE);
    562 		session_windows_add(ad->session, wd->session_window);
    563 	}
    564 
    565 	evas_object_smart_callback_add(wd->win, "delete,request", delete_request_cb, wd);
    566 	evas_object_smart_callback_add(wd->win, "maximized", maximized_cb, wd);
    567 	evas_object_event_callback_add(wd->win, EVAS_CALLBACK_FREE, free_cb, wd);
    568 
    569 	evas_object_smart_callback_add(wd->url, "activated", inputbox_activate_cb, wd);
    570 	evas_object_smart_callback_add(wd->url, "changed", inputbox_changed_cb, wd);
    571 	evas_object_event_callback_add(wd->url, EVAS_CALLBACK_KEY_DOWN, inputbox_keypress_cb, wd);
    572 	evas_object_event_callback_add(wd->url, EVAS_CALLBACK_KEY_UP, inputbox_keyrelease_cb, wd);
    573 
    574 	ad->windows = eina_list_append(ad->windows, wd);
    575 
    576 	evas_object_resize(wd->win, 1024, 768);
    577 	evas_object_show(wd->win);
    578 
    579 	return wd;
    580 }
    581