Commit: 64086d8b058ef5111d45dd264fc22636a0dc0054
Parent: 10505f867460a6ed9c482de61dc23f62e943468a
Author: opask
Date:   Thu,  4 Oct 2018 08:55:45 -0600
merge remaining relevant changes from links 2.17
some changes have been adapted to fit our tree
Diffstat:
| M | ChangeLog | | | 102 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| M | bfu.c | | | 104 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------- | 
| M | default.c | | | 58 | +++++++++++++++++++++++++--------------------------------- | 
| M | dip.c | | | 63 | ++++++++++++++++++++++++++++++++++++++------------------------- | 
| M | dither.c | | | 498 | +++++++++++++++++++++++++++++++++++++++++++------------------------------------ | 
| M | drivers.c | | | 181 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- | 
| M | entity.inc | | | 2 | +- | 
| M | html.c | | | 32 | +++++++++++++++++--------------- | 
| M | html_gr.c | | | 45 | ++++++++++++++++++++++++++++++++------------- | 
| M | html_tbl.c | | | 6 | +++--- | 
| M | http.c | | | 6 | +++--- | 
| M | https.c | | | 2 | +- | 
| M | img.c | | | 160 | +++++++++++++++++++++++++++++++++++-------------------------------------------- | 
| M | kbd.c | | | 2 | +- | 
| M | language.h | | | 1366 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- | 
| M | language.inc | | | 1367 | +++++++++++++++++++++++++++++++++++++++---------------------------------------- | 
| M | links.h | | | 221 | +++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------- | 
| M | listedit.c | | | 310 | +++++++++++++++++++++++++++++++++++++------------------------------------------ | 
| M | main.c | | | 1 | - | 
| M | menu.c | | | 154 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------- | 
| M | sched.c | | | 2 | +- | 
| M | select.c | | | 27 | ++++++++++++++------------- | 
| M | string.c | | | 21 | +++++++++++++++++++-- | 
| M | terminal.c | | | 209 | +++++++++++++++++++------------------------------------------------------------ | 
| M | types.c | | | 3 | ++- | 
| M | url.c | | | 16 | +++++++++++++--- | 
| M | view.c | | | 679 | +++++++++++++++++++++++++++++++++++++++++++++---------------------------------- | 
| M | view_gr.c | | | 310 | ++++++++++++++++++++++++++++++++----------------------------------------------- | 
| M | x.c | | | 1135 | +++++++++++++++++++++++++++++++++++++++---------------------------------------- | 
29 files changed, 3738 insertions(+), 3344 deletions(-)
diff --git a/ChangeLog b/ChangeLog
@@ -1,3 +1,105 @@
+=== RELEASE 2.17 ===
+
+Fri Sep  7 00:04:41 CEST 2018 mikulas:
+
+	Fix verifying SSL certificates for numeric IPv6 addresses
+
+Thu Sep  6 22:07:03 CEST 2018 mikulas:
+
+	Delete the option -ftp.fast - it doesn't always work and ftp performance
+	is not an issue anymore
+
+	Passive ftp enabled by default because it will more likely work than
+	the port command
+
+Wed Sep  5 22:39:11 CEST 2018 mikulas:
+
+	Add bold and monospaced Turkish letter 'i' without a dot
+
+Wed Sep  5 01:28:31 cet 2018 mikulas:
+
+	On OS/2 allocate OpenSSL memory from the lower heap
+	It fixes SSL on systems with old 16-bit TCP/IP stack
+
+Fri Aug 31 18:06:26 CEST 2018 mikulas:
+
+	Fix IPv6 on OpenVMS Alpha
+
+Thu Jul 26 07:34:24 CEST 2018 mikulas:
+
+	Support mouse scroll wheel in textarea
+
+Thu Jul 26 05:24:17 CEST 2018 mikulas:
+
+	Delete the option -http-bugs.bug-302-redirect - RFC7231 allows the
+	"buggy" behavior and defines new codes 307 and 308 that retain the
+	post data
+
+Wed Jul 18 21:00:23 CEST 2018 mikulas:
+
+	X11 - fixed colormap leak when creating a new window
+
+Mon Jul 16 02:33:26 CEST 2018 mikulas:
+
+	Fixed an infinite loop that happened in graphics mode if the user
+	clicked on OK in "Miscellaneous options" dialog and more than one
+	windows were open.
+	This bug was introduced in Links 2.15.
+
+Sun Jul 15 21:36:04 CEST 2018 mikulas:
+
+	Support 6x6x6 RGB palette in 256-bit color mode on framebuffer
+	The palette may be switched in the "video options" menu
+	The 8x8x4 palette has better image quality
+	The 6x6x6 palette preserves gray
+
+Sat Jul 14 04:49:45 cet 2018 mikulas:
+
+	Implement dithering properly on OS/2 in 15-bit and 16-bit color mode
+
+	In 8-bit mode, Links may optionally use a private palette - it
+	improves visual quality of Links images, but degrades visual
+	quality of other concurrently running programs.
+
+Thu Jul 12 23:06:48 CEST 2018 mikulas:
+
+	Improve scrolling smoothness when the user drags the whole document
+
+Thu Jul 12 06:48:00 cet 2018 mikulas:
+
+	On OS/2, allocate large memory blocks directly (not with malloc)
+	- it reduces memory waste
+
+Thu Jul 12 00:56:57 cet 2018 mikulas:
+
+	Fixed a bug that setting terminal title and resizing a terminal didn't
+	work on OS/2 and Windows. The bug was introduced in Links 2.16 when
+	shutting up coverity warnings.
+
+Sun Jun 17 15:31:28 CEST 2018 mikulas:
+
+	Set link color to yellow by default
+
+Sun Jun 17 14:04:07 CEST 2018 mikulas:
+
+	Delete the option -http-bugs.bug-post-no-keepalive
+	It was needed in 1999 to avoid some bug in some http server and it is
+	not needed anymore
+
+Tue Jun  5 20:24:42 CEST 2018 mikulas:
+
+	Trust Content-Length on HTTP/1.0 redirect requests
+
+	This fixes hangs with misbehaving servers that honor Connection:
+	keep-alive but send out HTTP/1.0 reply without Connection: keep-alive.
+	Links thought that they don't support keep-alive and waited for the
+	connection to close (for example http://www.raspberrypi.org/)
+
+Tue May 22 00:51:35 CEST 2018 mikulas:
+
+	Use keys 'H' and 'L' to select the top and bottom link on the current
+	page
+
 === RELEASE 2.16 ===
 
 Sun Apr 29 17:12:24 CEST 2018 mikulas:
diff --git a/bfu.c b/bfu.c
@@ -416,7 +416,7 @@ static void display_menu_item_gfx(struct terminal *term, struct menu *menu, int 
 			g_print_text(dev, p, y, bfu_style_bw, menu->hktxt3[it], &p);
 		}
 		if (!*rtext) {
-			drv->set_clip_area(dev, &r);
+			set_clip_area(dev, &r);
 			if (p > menu->x + menu->xw - G_MENU_LEFT_BORDER - G_MENU_LEFT_INNER_BORDER) p = menu->x + menu->xw - G_MENU_LEFT_BORDER - G_MENU_LEFT_INNER_BORDER;
 			if (it != menu->selected)
 				drv->fill_area(dev, p, y, menu->x + menu->xw - (G_MENU_LEFT_BORDER + 1) / 2, y + G_BFU_FONT_SIZE, bfu_bg_color);
@@ -427,7 +427,7 @@ static void display_menu_item_gfx(struct terminal *term, struct menu *menu, int 
 			if (s < p) s = p;
 			drv->fill_area(dev, p, y, s, y + G_BFU_FONT_SIZE, it != menu->selected ? bfu_bg_color : bfu_fg_color);
 			g_print_text(dev, s, y, it != menu->selected ? bfu_style_bw : bfu_style_wb, rtext, NULL);
-			drv->set_clip_area(dev, &r);
+			set_clip_area(dev, &r);
 			if (it != menu->selected)
 				drv->fill_area(dev, menu->x + menu->xw - G_MENU_LEFT_BORDER - G_MENU_LEFT_INNER_BORDER, y, menu->x + menu->xw - (G_MENU_LEFT_BORDER + 1) / 2, y + G_BFU_FONT_SIZE, bfu_bg_color);
 			else
@@ -494,6 +494,14 @@ static void menu_func(struct window *win, struct links_event *ev, int fwd)
 			break;
 		case EV_MOUSE:
 			if ((ev->b & BM_ACT) == B_MOVE) break;
+			if ((ev->b & BM_BUTT) == B_FOURTH ||
+			    (ev->b & BM_BUTT) == B_FIFTH) {
+				if ((ev->b & BM_ACT) == B_DOWN) goto go_lr;
+				break;
+			}
+			if ((ev->b & BM_BUTT) == B_SIXTH) {
+				break;
+			}
 			if (ev->x < menu->x || ev->x >= menu->x+menu->xw || ev->y < menu->y || ev->y >= menu->y+menu->yw) {
 				int f = 1;
 				struct window *w1;
@@ -537,21 +545,18 @@ static void menu_func(struct window *win, struct links_event *ev, int fwd)
 			}
 			break;
 		case EV_KBD:
-			if (ev->y & KBD_PASTE) break;
+			if (ev->y & KBD_PASTING) break;
 			if (ev->x == KBD_LEFT || ev->x == KBD_RIGHT) {
+go_lr:
 				if (win->list_entry.next == &win->term->windows)
 					goto mm;
 				if (list_struct(win->list_entry.next, struct window)->handler == mainmenu_func)
 					goto mm;
-				if (ev->x == KBD_RIGHT) goto enter;
+				if (ev->ev == EV_MOUSE && (ev->b & BM_BUTT) == B_FIFTH) goto mm;
+				if (ev->ev == EV_KBD && ev->x == KBD_RIGHT) goto enter;
 				delete_window(win);
 				break;
 			}
-			if ((ev->x <= KBD_F1 && ev->x >= KBD_F12) || ev->y & KBD_ALT) {
-				mm:
-				delete_window_ev(win, ev);
-				break;
-			}
 			if (ev->x == KBD_ESC) {
 				if (win->list_entry.next == &win->term->windows)
 					ev = NULL;
@@ -560,6 +565,11 @@ static void menu_func(struct window *win, struct links_event *ev, int fwd)
 				delete_window_ev(win, ev);
 				break;
 			}
+			if (KBD_ESCAPE_MENU(ev->x) || ev->y & KBD_ALT) {
+				mm:
+				delete_window_ev(win, ev);
+				break;
+			}
 			menu_oldview = menu->view;
 			menu_oldsel = menu->selected;
 			if (ev->x == KBD_UP) scroll_menu(menu, -1);
@@ -754,6 +764,17 @@ static void mainmenu_func(struct window *win, struct links_event *ev, int fwd)
 		case EV_MOUSE:
 			in_menu = ev->x >= 0 && ev->x < win->term->x && ev->y >= 0 && ev->y < gf_val(1, G_BFU_FONT_SIZE);
 			if ((ev->b & BM_ACT) == B_MOVE) break;
+			if ((ev->b & BM_BUTT) == B_FOURTH) {
+				if ((ev->b & BM_ACT) == B_DOWN) goto go_left;
+				break;
+			}
+			if ((ev->b & BM_BUTT) == B_FIFTH) {
+				if ((ev->b & BM_ACT) == B_DOWN) goto go_right;
+				break;
+			}
+			if ((ev->b & BM_BUTT) == B_SIXTH) {
+				break;
+			}
 			if ((ev->b & BM_ACT) == B_DOWN && !in_menu) delete_window_ev(win, ev);
 			else if (in_menu) {
 				int i;
@@ -774,15 +795,17 @@ static void mainmenu_func(struct window *win, struct links_event *ev, int fwd)
 			}
 			break;
 		case EV_KBD:
-			if (ev->y & KBD_PASTE) break;
+			if (ev->y & KBD_PASTING) break;
 			if (ev->x == ' ' || ev->x == KBD_ENTER || ev->x == KBD_DOWN || ev->x == KBD_UP || ev->x == KBD_PAGE_DOWN || (upcase(ev->x) == 'F' && ev->y & KBD_CTRL) || ev->x == KBD_PAGE_UP || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL)) {
 				select_mainmenu(win->term, menu);
 				break;
 			} else if (ev->x == KBD_LEFT) {
+go_left:
 				if (!menu->selected--) menu->selected = menu->ni - 1;
 				s = 1;
 				if (fwd) s = 2;
 			} else if (ev->x == KBD_RIGHT) {
+go_right:
 				if (++menu->selected >= menu->ni) menu->selected = 0;
 				s = 1;
 				if (fwd) s = 2;
@@ -803,7 +826,7 @@ static void mainmenu_func(struct window *win, struct links_event *ev, int fwd)
 				}
 			}
 			if (!s) {
-				delete_window_ev(win, (ev->x <= KBD_F1 && ev->x >= KBD_F12) || ev->y & KBD_ALT ? ev : NULL);
+				delete_window_ev(win, KBD_ESCAPE_MENU(ev->x) || ev->y & KBD_ALT ? ev : NULL);
 				break;
 			}
 			draw_to_window(win, display_mainmenu, menu);
@@ -955,7 +978,7 @@ void display_dlg_item(struct dialog_data *dlg, struct dialog_item_data *di, int 
 						restrict_clip_area(dev, &r, p, di->y, p + s, di->y + G_BFU_FONT_SIZE);
 						g_print_text(dev, p, di->y, bfu_style_bw_u, cast_uchar "          ", NULL);
 						p += s;
-						drv->set_clip_area(dev, &r);
+						set_clip_area(dev, &r);
 					}
 					g_print_text(dev, p, di->y, bfu_style_bw, di->item->gid?cast_uchar G_DIALOG_RADIO_R:cast_uchar G_DIALOG_CHECKBOX_R, &p);
 				}
@@ -1014,7 +1037,7 @@ void display_dlg_item(struct dialog_data *dlg, struct dialog_item_data *di, int 
 				g_print_text(dev, p, di->y, sel ? bfu_style_wb_mono_u : bfu_style_wb_mono, text2, &p);
 				g_print_text(dev, p, di->y, bfu_style_wb_mono, text3, &p);
 				drv->fill_area(dev, p, di->y, di->x + di->l, di->y + G_BFU_FONT_SIZE, bfu_fg_color);
-				drv->set_clip_area(dev, &r);
+				set_clip_area(dev, &r);
 				free(text);
 				free(text2);
 				free(text3);
@@ -1039,7 +1062,7 @@ void display_dlg_item(struct dialog_data *dlg, struct dialog_item_data *di, int 
 			default:
 				internal("display_dlg_item: unknown item: %d", di->item->type);
 		}
-		if (!dlg->s) drv->set_clip_area(dev, &rr);
+		if (!dlg->s) set_clip_area(dev, &rr);
 #endif
 	}
 }
@@ -1188,7 +1211,7 @@ static void redraw_dialog(struct terminal *term, void *dlg_)
 	redraw_dialog_items(term, dlg);
 #ifdef G
 	if (F) {
-		drv->set_clip_area(term->dev, &dlg->r);
+		set_clip_area(term->dev, &dlg->r);
 		for (i = 0; i < dlg->s->m; i++) if (is_rect_valid(&dlg->s->r[i]))
 			drv->fill_area(term->dev, dlg->s->r[i].x1, dlg->s->r[i].y1, dlg->s->r[i].x2, dlg->s->r[i].y2, bfu_bg_color);
 		free(dlg->s);
@@ -1312,6 +1335,18 @@ void dialog_func(struct window *win, struct links_event *ev, int fwd)
 			break;
 		case EV_MOUSE:
 			if ((ev->b & BM_ACT) == B_MOVE) break;
+			if ((ev->b & BM_BUTT) == B_FOURTH) {
+				if ((ev->b & BM_ACT) == B_DOWN) goto go_prev;
+				break;
+			}
+			if ((ev->b & BM_BUTT) == B_FIFTH) {
+				if ((ev->b & BM_ACT) == B_DOWN) goto go_next;
+				break;
+			}
+			if ((ev->b & BM_BUTT) == B_SIXTH) {
+				if ((ev->b & BM_ACT) == B_DOWN) goto go_enter;
+				break;
+			}
 			for (i = 0; i < dlg->n; i++) if (dlg_mouse(dlg, &dlg->items[i], ev)) break;
 			if ((ev->b & BM_ACT) == B_DOWN && (ev->b & BM_BUTT) == B_MIDDLE) {
 				di = &dlg->items[dlg->selected];  /* don't delete this!!! it's here because of jump from mouse event */
@@ -1320,7 +1355,7 @@ void dialog_func(struct window *win, struct links_event *ev, int fwd)
 			break;
 		case EV_KBD:
 			di = &dlg->items[dlg->selected];
-			if (ev->y & KBD_PASTE) {
+			if (ev->y & KBD_PASTING) {
 				if (!((di->item->type == D_FIELD || di->item->type == D_FIELD_PASS) &&
 				      (ev->x >= ' ' && !(ev->y & (KBD_CTRL | KBD_ALT)))))
 					break;
@@ -1432,20 +1467,20 @@ void dialog_func(struct window *win, struct links_event *ev, int fwd)
 					goto dsp_f;
 				}
 				/* Copy to clipboard */
-				if ((ev->x == KBD_INS && ev->y & KBD_CTRL) || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL)) {
+				if ((ev->x == KBD_INS && ev->y & KBD_CTRL) || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL) || ev->x == KBD_COPY) {
 					set_clipboard_text(term, di->cdata);
 					break;	/* We don't need to redraw */
 				}
 				/* FIXME -- why keyboard shortcuts with shift don't works??? */
 				/* Cut to clipboard */
-				if ((ev->x == KBD_DEL && ev->y & KBD_SHIFT) || (upcase(ev->x) == 'X' && ev->y & KBD_CTRL)) {
+				if ((ev->x == KBD_DEL && ev->y & KBD_SHIFT) || (upcase(ev->x) == 'X' && ev->y & KBD_CTRL) || ev->x == KBD_CUT) {
 					set_clipboard_text(term, di->cdata);
 					di->cdata[0] = 0;
 					di->cpos = 0;
 					goto dsp_f;
 				}
 				/* Paste from clipboard */
-				if ((ev->x == KBD_INS && ev->y & KBD_SHIFT) || (upcase(ev->x) == 'V' && ev->y & KBD_CTRL)) {
+				if ((ev->x == KBD_INS && ev->y & KBD_SHIFT) || (upcase(ev->x) == 'V' && ev->y & KBD_CTRL) || ev->x == KBD_PASTE) {
 					unsigned char *clipboard;
 clipbd_paste:
 					clipboard = get_clipboard_text(term);
@@ -1462,7 +1497,7 @@ clipbd_paste:
 					}
 					goto dsp_f;
 				}
-				if (upcase(ev->x) == 'W' && ev->y & KBD_CTRL) {
+				if ((upcase(ev->x) == 'W' && ev->y & KBD_CTRL) || ev->x == KBD_FIND) {
 					do_tab_compl(term, &di->history, win);
 					goto dsp_f;
 				}
@@ -1480,10 +1515,17 @@ clipbd_paste:
 				unsigned char *tx = get_text_translation(dlg->dlg->items[i].text, term);
 				if (dlg->dlg->items[i].type == D_BUTTON && charset_upcase(GET_TERM_CHAR(term, &tx), term_charset(term)) == charset_upcase(ev->x, term_charset(term))) goto sel;
 			}
-			if (ev->x == KBD_ENTER) for (i = 0; i < dlg->n; i++)
-				if (dlg->dlg->items[i].type == D_BUTTON && dlg->dlg->items[i].gid & B_ENTER) goto sel;
-			if (ev->x == KBD_ESC) for (i = 0; i < dlg->n; i++)
-				if (dlg->dlg->items[i].type == D_BUTTON && dlg->dlg->items[i].gid & B_ESC) goto sel;
+			if (ev->x == KBD_ENTER) {
+go_enter:
+				for (i = 0; i < dlg->n; i++)
+					if (dlg->dlg->items[i].type == D_BUTTON && dlg->dlg->items[i].gid & B_ENTER) goto sel;
+				break;
+			}
+			if (ev->x == KBD_ESC) {
+				for (i = 0; i < dlg->n; i++)
+					if (dlg->dlg->items[i].type == D_BUTTON && dlg->dlg->items[i].gid & B_ESC) goto sel;
+				break;
+			}
 			if (0) {
 				sel:
 				if (dlg->selected != i) {
@@ -1492,10 +1534,11 @@ clipbd_paste:
 					dlg->selected = i;
 				}
 				dlg_select_item(dlg, &dlg->items[i]);
-				goto bla;
+				break;
 			}
 			if (((ev->x == KBD_TAB && !ev->y) || ev->x == KBD_DOWN
 			|| ev->x == KBD_RIGHT) && dlg->n > 1) {
+ go_next:
 				x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
 				if ((++dlg->selected) >= dlg->n) dlg->selected = 0;
 				x_display_dlg_item(dlg, &dlg->items[dlg->selected], 1);
@@ -1503,6 +1546,7 @@ clipbd_paste:
 			}
 			if (((ev->x == KBD_TAB && ev->y) || ev->x == KBD_UP
 			|| ev->x == KBD_LEFT) && dlg->n > 1) {
+ go_prev:
 				x_display_dlg_item(dlg, &dlg->items[dlg->selected], 0);
 				if ((--dlg->selected) < 0) dlg->selected = dlg->n - 1;
 				x_display_dlg_item(dlg, &dlg->items[dlg->selected], 1);
@@ -1520,7 +1564,6 @@ clipbd_paste:
 			}
 			freeml(dlg->ml);
 	}
-	bla:;
 }
 
 /* gid and gnum are 100 times greater than boundaries (e.g. if gid==1 boundary is 0.01) */
@@ -1528,7 +1571,7 @@ int check_float(struct dialog_data *dlg, struct dialog_item_data *di)
 {
 	unsigned char *end;
 	double d = strtod(cast_const_char di->cdata, (char **)(void *)&end);
-	if (!*di->cdata || *end || strspn(cast_const_char di->cdata, "0123456789.") != strlen(cast_const_char di->cdata) || *di->cdata == (unsigned char)'.') {
+	if (!*di->cdata || *end || di->cdata[strspn(cast_const_char di->cdata, "0123456789.")] || *di->cdata == (unsigned char)'.') {
 		msg_box(dlg->win->term, NULL, TEXT_(T_BAD_NUMBER), AL_CENTER, TEXT_(T_NUMBER_EXPECTED), MSG_BOX_END, NULL, 1, TEXT_(T_CANCEL), msg_box_null, B_ENTER | B_ESC);
 		return 1;
 	}
@@ -1716,7 +1759,7 @@ void draw_dlg(struct dialog_data *dlg)
 			g_print_text(dev, TXT_X + (tl - xtl) / 2, TXT_Y, bfu_style_wb, text, NULL);
 			drv->fill_area(dev, TXT_X + (tl - xtl) / 2 + xtl, TXT_Y, TXT_X + tl, TXT_Y + G_BFU_FONT_SIZE, bfu_fg_color);
 		}
-		drv->set_clip_area(dev, &r);
+		set_clip_area(dev, &r);
 
 		drv->draw_hline(dev, dlg->x + G_DIALOG_LEFT_BORDER, dlg->y + G_DIALOG_TOP_BORDER, TXT_X, bfu_fg_color);
 		drv->draw_hline(dev, dlg->x + G_DIALOG_LEFT_BORDER + G_DIALOG_VLINE_SPACE, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE, TXT_X, bfu_fg_color);
@@ -1743,14 +1786,9 @@ void draw_dlg(struct dialog_data *dlg)
 		drv->fill_area(dev, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - G_DIALOG_VLINE_SPACE, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - 1, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - G_DIALOG_HLINE_SPACE, bfu_bg_color);
 		drv->fill_area(dev, dlg->x + G_DIALOG_LEFT_BORDER + 1, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - G_DIALOG_HLINE_SPACE, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - 1, dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - 1, bfu_bg_color);
 
-		/*
-		drv->fill_area(dev, dlg->x + G_DIALOG_LEFT_BORDER + G_DIALOG_VLINE_SPACE + 1, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE + 1, TXT_X, TXT_Y + G_BFU_FONT_SIZE, bfu_bg_color);
-		drv->fill_area(dev, TXT_X + tl, dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE + 1, dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - G_DIALOG_VLINE_SPACE - 1, TXT_Y + G_BFU_FONT_SIZE, bfu_bg_color);
-		*/
 		dlg->s = init_rect_set();
 		dlg->rr.x1 = dlg->x + G_DIALOG_LEFT_BORDER + G_DIALOG_VLINE_SPACE + 1;
 		dlg->rr.x2 = dlg->x + dlg->xw - G_DIALOG_LEFT_BORDER - G_DIALOG_VLINE_SPACE - 1;
-		/*dlg->rr.y1 = TXT_Y + G_BFU_FONT_SIZE;*/
 		dlg->rr.y1 = dlg->y + G_DIALOG_TOP_BORDER + G_DIALOG_HLINE_SPACE + 1;
 		dlg->rr.y2 = dlg->y + dlg->yw - G_DIALOG_TOP_BORDER - G_DIALOG_HLINE_SPACE - 1;
 		add_to_rect_set(&dlg->s, &dlg->rr);
diff --git a/default.c b/default.c
@@ -150,7 +150,7 @@ static void parse_config_file(unsigned char *name, unsigned char *file, struct o
 		for (op = opt; (options = *op); op++)
 			for (i = 0; options[i].p; i++) if (options[i].cfg_name && (size_t)nl == strlen(cast_const_char options[i].cfg_name) && !casecmp(tok, cast_uchar options[i].cfg_name, nl)) {
 				unsigned char *o = memacpy(p, pl);
-				if ((e = options[i].rd_cfg(&options[i], o))) {
+				if (options[i].rd_cfg && (e = options[i].rd_cfg(&options[i], o))) {
 					if (e[0]) {
 						fprintf(stderr,
 							"Error parsing config file %s, line %d: %s\n",
@@ -761,9 +761,9 @@ struct driver_param *get_driver_param(unsigned char *n)
 	sl = strlen(cast_const_char n);
 	if (sl > INT_MAX - sizeof(struct driver_param)) overalloc();
 	dp = mem_calloc(sizeof(struct driver_param) + sl);
-	dp->kbd_codepage = -1;
 	strcpy(cast_char dp->name, cast_const_char n);
-	dp->shell = mem_calloc(1);
+	dp->kbd_codepage = -1;
+	dp->palette_mode = 0;
 	dp->nosave = 1;
 	add_to_list(driver_params, dp);
 	return dp;
@@ -772,44 +772,33 @@ struct driver_param *get_driver_param(unsigned char *n)
 static unsigned char *dp_rd(struct option *o, unsigned char *c)
 {
 	int cc;
-	unsigned char *n, *param, *cp, *shell;
+	unsigned char *n, *param, *cp;
 	struct driver_param *dp;
-	if (!(n = get_token(&c))) goto err;
-	if (!(param = get_token(&c))) {
-		free(n);
+	if (!(n = get_token(&c)))
 		goto err;
-	}
-	if (!(shell = get_token(&c))){
-		free(n);
-		free(param);
+	dp = get_driver_param(n);
+	free(n);
+	if (!(param = get_token(&c)))
 		goto err;
-	}
-	if (!(cp = get_token(&c))) {
-		free(n);
-		free(param);
-		free(shell);
+	free(dp->param);
+	dp->param = param;
+	if (!(param = get_token(&c)))
+		goto err;
+	safe_strncpy(dp->shell_term, param, MAX_STR_LEN);
+	free(param);
+	if (!(cp = get_token(&c)))
 		goto err;
-	}
 	if (!casestrcmp(cp, cast_uchar "default"))
 		cc = -1;
 	else if ((cc = get_cp_index(cp)) == -1) {
-		free(n);
-		free(param);
-		free(shell);
 		free(cp);
 		goto err;
 	}
-	dp = get_driver_param(n);
+	free(cp);
 	dp->kbd_codepage = cc;
-	free(dp->param);
-	dp->param = param;
-	free(dp->shell);
-	dp->shell = shell;
 	dp->nosave = 0;
-	free(cp);
-	free(n);
 	return NULL;
-	err:
+ err:
 	return cast_uchar "Error reading driver mode specification";
 }
 
@@ -818,17 +807,21 @@ static void dp_wr(struct option *o, unsigned char **s, int *l)
 	struct driver_param *dp;
 	struct list_head *ldp;
 	foreachback(struct driver_param, dp, ldp, driver_params) {
-		if ((!dp->param || !*dp->param) && dp->kbd_codepage == -1 && !*dp->shell) continue;
+		if ((!dp->param || !*dp->param) && !*dp->shell_term && dp->kbd_codepage < 0 && !dp->palette_mode)
+			continue;
 		if (dp->nosave) continue;
 		add_nm(o, s, l);
 		add_quoted_to_str(s, l, dp->name);
 		add_to_str(s, l, cast_uchar " ");
 		add_quoted_to_str(s, l, dp->param ? dp->param : (unsigned char*)"");
 		add_to_str(s, l, cast_uchar " ");
-		add_quoted_to_str(s, l, dp->shell);
+		add_quoted_to_str(s, l, dp->shell_term);
 		add_to_str(s, l, cast_uchar " ");
 		if (dp->kbd_codepage == -1) add_to_str(s, l, cast_uchar "default");
 		else add_to_str(s, l, get_cp_mime_name(dp->kbd_codepage));
+		add_to_str(s, l, cast_uchar " ");
+		add_num_to_str(s, l, dp->palette_mode);
+		/* pokud se sem neco prida, opravit podminku na zacatku cyklu */
 	}
 }
 
@@ -859,7 +852,7 @@ static unsigned char *gen_cmd(struct option *o, unsigned char ***argv, int *argc
 	e = init_str();
 	l = 0;
 	add_quoted_to_str(&e, &l, **argv);
-	r = o->rd_cfg(o, e);
+	r = o->rd_cfg ? o->rd_cfg(o, e) : 0;
 	free(e);
 	if (r) return r;
 	(*argv)++; (*argc)--;
@@ -967,7 +960,6 @@ void end_config(void)
 	struct list_head *ldp;
 	foreach(struct driver_param, dp, ldp, driver_params) {
 		free(dp->param);
-		free(dp->shell);
 	}
 	free_list(struct driver_param, driver_params);
 	free(links_home);
@@ -1141,7 +1133,7 @@ static struct option links_options[] = {
 	{1, gen_cmd, dbl_rd, dbl_wr, 1, 10000, &display_blue_gamma, "display_blue_gamma", "display-blue-gamma"},
 	{1, gen_cmd, dbl_rd, dbl_wr, 1, 10000, &user_gamma, "user_gamma", "user-gamma"},
 	{1, gen_cmd, dbl_rd, dbl_wr, 25, 400, &bfu_aspect, "bfu_aspect", "bfu-aspect"},
-	{1, gen_cmd, num_rd, NULL, 0, 1, NULL, "aspect_on", NULL},
+	{1, gen_cmd, NULL, NULL, 0, 1, NULL, "aspect_on", NULL},
 	{1, gen_cmd, num_rd, num_wr, 0, 1, &dither_letters, "dither_letters", "dither-letters"},
 	{1, gen_cmd, num_rd, num_wr, 0, 1, &dither_images, "dither_images", "dither-images"},
 	{1, gen_cmd, num_rd, num_wr, 0, 2, &gamma_bits, "gamma_correction", "gamma-correction"},
diff --git a/dip.c b/dip.c
@@ -1160,9 +1160,9 @@ void agx_24_to_48(unsigned short *restrict dest, const unsigned char *restrict s
  * We assume unsigned short holds at least 16 bits. */
 void make_gamma_table(struct cached_image *cimg)
 {
-	float rg=(float)((float)user_gamma/cimg->red_gamma);
-	float gg=(float)((float)user_gamma/cimg->green_gamma);
-	float bg=(float)((float)user_gamma/cimg->blue_gamma);
+	float rg = (float)(user_gamma / cimg->red_gamma);
+	float gg = (float)(user_gamma / cimg->green_gamma);
+	float bg = (float)(user_gamma / cimg->blue_gamma);
 	int a;
 	unsigned short *ptr_16;
 	unsigned short last_val;
@@ -1568,9 +1568,9 @@ static struct font_cache_entry *supply_color_cache_entry(struct style *style, st
 	mix_two_colors(primary_data, found->bitmap.data,
 		found->bitmap.x*found->bitmap.y,
 		red,green,blue,
-		ags_8_to_16(style->r1,(float)((float)user_gamma/(float)sRGB_gamma)),
-		ags_8_to_16(style->g1,(float)((float)user_gamma/(float)sRGB_gamma)),
-		ags_8_to_16(style->b1,(float)((float)user_gamma/(float)sRGB_gamma))
+		ags_8_to_16(style->r1, (float)(user_gamma / sRGB_gamma)),
+		ags_8_to_16(style->g1, (float)(user_gamma / sRGB_gamma)),
+		ags_8_to_16(style->b1, (float)(user_gamma / sRGB_gamma))
 	);
 	/* We have a buffer with photons */
 	if (drv->get_empty_bitmap(&(neww->bitmap)))
@@ -1633,24 +1633,24 @@ static inline int print_letter(struct graphics_device *device, int x, int y, str
 	struct letter *letter;
 
 	/* Find a suitable letter */
-	letter=find_stored_letter(style->table,char_number);
+	letter = find_stored_letter(style->table, char_number);
 #ifdef DEBUG
 	if (!letter) internal("print_letter could not find a letter - even not the blotch!");
 #endif /* #ifdef DEBUG */
-	templat.r0=style->r0;
-	templat.r1=style->r1;
-	templat.g0=style->g0;
-	templat.g1=style->g1;
-	templat.b0=style->b0;
-	templat.b1=style->b1;
-	templat.bitmap.y=style->height;
-	templat.mono_space=style->mono_space;
-	templat.mono_height=style->mono_height;
-
-	found=lru_lookup(&font_cache, &templat, &letter->color_list);
-	if (!found) found=supply_color_cache_entry(style, letter);
+	templat.r0 = style->r0;
+	templat.r1 = style->r1;
+	templat.g0 = style->g0;
+	templat.g1 = style->g1;
+	templat.b0 = style->b0;
+	templat.b1 = style->b1;
+	templat.bitmap.y = style->height;
+	templat.mono_space = style->mono_space;
+	templat.mono_height = style->mono_height;
+
+	found = lru_lookup(&font_cache, &templat, &letter->color_list);
+	if (!found) found = supply_color_cache_entry(style, letter);
 	else locked_color_entry = found;
-	drv->draw_bitmap(device, &(found->bitmap), x, y);
+	drv->draw_bitmap(device, &found->bitmap, x, y);
 	xw = found->bitmap.x;
 	if (locked_color_entry != found) internal("bad letter lock");
 	locked_color_entry = NULL;
@@ -1696,7 +1696,7 @@ void g_print_text(struct graphics_device *device, int x, int y, struct style *st
 		restrict_clip_area(device, &saved_clip, 0, 0, device->size.x2, y+
 			top_underline);
 		g_print_text(device, x, y, style, text, width);
-		drv->set_clip_area(device, &saved_clip);
+		set_clip_area(device, &saved_clip);
 		if (bottom_underline-top_underline==1){
 			/* Line */
 			drv->draw_hline(device, x, y+top_underline,
@@ -1718,7 +1718,7 @@ void g_print_text(struct graphics_device *device, int x, int y, struct style *st
 				y+bottom_underline, device->size.x2,
 				device->size.y2);
 			g_print_text(device, x, y, style, text, width);
-			drv->set_clip_area(device, &saved_clip);
+			set_clip_area(device, &saved_clip);
 		}
 		style->flags=original_flags;
 		return;
@@ -2104,6 +2104,8 @@ void g_free_style(struct style *st)
 	free(st);
 }
 
+tcount gamma_stamp = 1; /* stamp counter for gamma changes */
+
 long gamma_cache_color;
 int gamma_cache_rgb = -2;
 
@@ -2120,9 +2122,9 @@ long real_dip_get_color_sRGB(int rgb)
 	rgb = hack_rgb(rgb);
 
 	round_color_sRGB_to_48(&r,&g,&b,rgb);
-	r=ags_16_to_8(r,(float)(1/(float)display_red_gamma));
-	g=ags_16_to_8(g,(float)(1/(float)display_green_gamma));
-	b=ags_16_to_8(b,(float)(1/(float)display_blue_gamma));
+	r = ags_16_to_8(r, (float)(1 / display_red_gamma));
+	g = ags_16_to_8(g, (float)(1 / display_green_gamma));
+	b = ags_16_to_8(b, (float)(1 / display_blue_gamma));
 	new_rgb=b|(g<<8)|(r<<16);
 	gamma_cache_rgb = rgb;
 	/* The get_color takes values with gamma of display_*_gamma */
@@ -2152,10 +2154,21 @@ static inline void qb_palette(unsigned r_max, unsigned g_max, unsigned b_max, un
 
 void q_palette(unsigned size, unsigned color, unsigned scale, unsigned rgb[3])
 {
+	if (color >= size) {
+		rgb[0] = rgb[1] = rgb[2] = 0;
+		return;
+	}
+
 	switch (size) {
+		case 8:
+			qb_palette(1, 1, 1, color >> 2, (color >> 1) & 1, color & 1, scale, rgb);
+			break;
 		case 16:
 			qb_palette(1, 3, 1, color >> 3, (color >> 1) & 3, color & 1, scale, rgb);
 			break;
+		case 216:
+			qb_palette(5, 5, 5, color / 36, color / 6 % 6, color % 6, scale, rgb);
+			break;
 		case 256:
 			qb_palette(7, 7, 3, color >> 5, (color >> 2) & 7, color & 3, scale, rgb);
 			break;
diff --git a/dither.c b/dither.c
@@ -88,42 +88,6 @@ void (*round_fn)(unsigned short *restrict in, struct bitmap *out);
 /* When you finish the stuff with dither_start, dither_restart, just do "if (dregs) mem_free(dregs);" */
 static void (*dither_fn_internal)(unsigned short *restrict in, struct bitmap *out, int *dregs);
 
-
-     /* prototypes */
-static void dither_1byte(unsigned short *restrict, struct bitmap *, int *);   /* DITHER_TEMPLATE */
-static void round_1byte(unsigned short *restrict, struct bitmap *);           /* ROUND_TEMPLATE */
-static void dither_2byte(unsigned short *restrict, struct bitmap *, int *);   /* DITHER_TEMPLATE */
-static void round_2byte(unsigned short *restrict, struct bitmap *);           /* ROUND_TEMPLATE */
-static void dither_195(unsigned short *restrict, struct bitmap *, int *);   /* DITHER_TEMPLATE */
-static void round_195(unsigned short *restrict, struct bitmap *);           /* ROUND_TEMPLATE */
-static void dither_451(unsigned short *restrict, struct bitmap *, int *);   /* DITHER_TEMPLATE */
-static void round_451(unsigned short *restrict, struct bitmap *);           /* ROUND_TEMPLATE */
-static void dither_196(unsigned short *restrict, struct bitmap *, int *);   /* DITHER_TEMPLATE */
-static void round_196(unsigned short *restrict, struct bitmap *);           /* ROUND_TEMPLATE */
-static void dither_452(unsigned short *restrict, struct bitmap *, int *);   /* DITHER_TEMPLATE */
-static void round_452(unsigned short *restrict, struct bitmap *);           /* ROUND_TEMPLATE */
-static void dither_708(unsigned short *restrict, struct bitmap *, int *);   /* DITHER_TEMPLATE */
-static void round_708(unsigned short *restrict, struct bitmap *);           /* ROUND_TEMPLATE */
-static long color_332(int);
-static long color_121(int);
-static long color_pass_rgb(int);
-static long color_888_bgr(int);
-/*static void pass_bgr(unsigned short *, struct bitmap *);*/
-static long color_8888_bgr0(int);
-static long color_8888_0bgr(int);
-static long color_8888_0rgb(int);
-/*static void pass_0bgr(unsigned short *, struct bitmap *);*/
-static long color_555be(int);
-static long color_555(int);
-static long color_565be(int);
-static long color_565(int);
-/*static void make_8_table(int *, double);*/
-static void make_16_table(int *, int, int, float, int, int);
-static void make_red_table(int, int, int, int);
-static void make_green_table(int, int, int, int);
-static void make_blue_table(int, int, int, int);
-static void make_round_tables(void);
-
 int slow_fpu = -1;
 
 #define LIN \
@@ -139,15 +103,9 @@ int slow_fpu = -1;
 		if ((unsigned)rc>65535) rc=rc<0?0:65535;\
 		if ((unsigned)gc>65535) gc=gc<0?0:65535;\
 		if ((unsigned)bc>65535) bc=bc<0?0:65535;\
-		if (table_16) {\
-			rt=red_table[rc];\
-			gt=green_table[gc];\
-			bt=blue_table[bc];\
-		} else {\
-			rt=red_table[rc >> 8];\
-			gt=green_table[gc >> 8];\
-			bt=blue_table[bc >> 8];\
-		}\
+		rt=red_table[rc >> shift];\
+		gt=green_table[gc >> shift];\
+		bt=blue_table[bc >> shift];\
 	}\
 	SAVE_CODE\
 	rt=r-(rt&65535);\
@@ -224,6 +182,7 @@ int slow_fpu = -1;
 #define DITHER_TEMPLATE(template_name) \
 	static void template_name(unsigned short *restrict in, struct bitmap *out, int *dregs)\
 		{\
+		int shift = 8 - table_16 * 8;\
 		int r,g,b,o,rt,gt,bt,y,x;\
 		unsigned char *restrict outp=out->data;\
 		int *restrict bptr;\
@@ -297,8 +256,8 @@ int slow_fpu = -1;
  * as a scratchpad.
  */
 #define SAVE_CODE \
-	o=rt|gt|bt;\
-	*outp++=(o>>16);
+	o = (rt >> 16) + (gt >> 16) + (bt >> 16);\
+	*outp++ = (unsigned char)o;
 
 DITHER_TEMPLATE(dither_1byte)
 ROUND_TEMPLATE(round_1byte)
@@ -318,8 +277,9 @@ ROUND_TEMPLATE(round_2byte)
 #undef SKIP_CODE
 
 /* B G R */
-#define SKIP_CODE out->x*3;
-#define SAVE_CODE outp[0]=bt>>16;\
+#define SKIP_CODE out->x*3
+#define SAVE_CODE \
+	outp[0]=bt>>16;\
 	outp[1]=gt>>16;\
 	outp[2]=rt>>16;\
 	outp+=3;
@@ -329,8 +289,9 @@ ROUND_TEMPLATE(round_195)
 #undef SKIP_CODE
 
 /* R G B */
-#define SKIP_CODE out->x*3;
-#define SAVE_CODE *outp=rt>>16;\
+#define SKIP_CODE out->x*3
+#define SAVE_CODE \
+	outp[0]=rt>>16;\
 	outp[1]=gt>>16;\
 	outp[2]=bt>>16;\
 	outp+=3;
@@ -340,8 +301,9 @@ ROUND_TEMPLATE(round_451)
 #undef SKIP_CODE
 
 /* B G R 0 */
-#define SKIP_CODE out->x*4;
-#define SAVE_CODE *outp=bt>>16;\
+#define SKIP_CODE out->x*4
+#define SAVE_CODE \
+	outp[0]=bt>>16;\
 	outp[1]=gt>>16;\
 	outp[2]=rt>>16;\
 	outp[3]=0;\
@@ -352,8 +314,9 @@ ROUND_TEMPLATE(round_196)
 #undef SKIP_CODE
 
 /* 0 B G R */
-#define SKIP_CODE out->x*4;
-#define SAVE_CODE *outp=0;\
+#define SKIP_CODE out->x*4
+#define SAVE_CODE \
+	outp[0]=0;\
 	outp[1]=bt>>16;\
 	outp[2]=gt>>16;\
 	outp[3]=rt>>16;\
@@ -364,8 +327,9 @@ ROUND_TEMPLATE(round_452)
 #undef SKIP_CODE
 
 /* 0 R G B */
-#define SKIP_CODE out->x*4;
-#define SAVE_CODE *outp=0;\
+#define SKIP_CODE out->x*4
+#define SAVE_CODE \
+	outp[0]=0;\
 	outp[1]=rt>>16;\
 	outp[2]=gt>>16;\
 	outp[3]=bt>>16;\
@@ -395,23 +359,65 @@ static long color_332(int rgb)
 
 }
 
+/* For 216-color cube */
+static long color_666(int rgb)
+{
+	int r, g, b;
+	unsigned char i;
+	long ret = 0;
+
+	r = (rgb >> 16) & 255;
+	g = (rgb >> 8) & 255;
+	b = rgb & 255;
+
+	r = (r * 5 + 127) / 255;
+	g = (g * 5 + 127) / 255;
+	b = (b * 5 + 127) / 255;
+
+	i = (unsigned char)r;
+	i *= 6;
+	i += g;
+	i *= 6;
+	i += b;
+
+	*(unsigned char *)&ret = i;
+	return ret;
+
+}
+
 static long color_121(int rgb)
 {
-	int r,g,b;
+	int r, g, b;
 	long ret = 0;
 
-	r=(rgb>>16)&255;
-	g=(rgb>>8)&255;
-	b=rgb&255;
-	r=(r+127)/255;
-	g=(3*g+127)/255;
-	b=(b+127)/255;
-	*(unsigned char *)&ret=(r<<3)|(g<<1)|b;
+	r = (rgb >> 16) & 255;
+	g = (rgb >> 8) & 255;
+	b = rgb & 255;
+	r = (r + 127) / 255;
+	g = (3 * g + 127) / 255;
+	b = (b + 127) / 255;
+	*(unsigned char *)&ret = (r << 3) | (g << 1) | b;
+	return ret;
+
+}
+
+static long color_111(int rgb)
+{
+	int r, g, b;
+	long ret = 0;
+
+	r = (rgb >> 16) & 255;
+	g = (rgb >> 8) & 255;
+	b = rgb & 255;
+	r = (r + 127) / 255;
+	g = (g + 127) / 255;
+	b = (b + 127) / 255;
+	*(unsigned char *)&ret = (r << 2) | (g << 1) | b;
 	return ret;
 
 }
 
-static long color_pass_rgb(int rgb)
+static long color_888_rgb(int rgb)
 {
 	long ret = 0;
 
@@ -434,26 +440,6 @@ static long color_888_bgr(int rgb)
 	return ret;
 }
 
-#if 0
-/* Long live the Manchester Modulation! */
-static void pass_bgr(unsigned short *in, struct bitmap *out)
-{
-	int skip=out->skip-3*out->x,y,x;
-	unsigned char *outp=out->data;
-
-	for (y=out->y;y;y--){
-		for (x=out->x;x;x--){
-			outp[0]=in[2];
-			outp[1]=in[1];
-			outp[2]=in[0];
-			outp+=3;
-			in+=3;
-		}
-		outp+=skip;
-	}
-}
-#endif
-
 static long color_8888_bgr0(int rgb)
 {
 	long ret = 0;
@@ -496,27 +482,6 @@ static long color_8888_0rgb(int rgb)
 	return ret;
 }
 
-#if 0
-/* We assume unsgned short holds at least 16 bits. */
-static void pass_0bgr(unsigned short *in, struct bitmap *out)
-{
-	int skip=out->skip-4*out->x,y,x;
-	unsigned char *outp=out->data;
-
-	for (y=out->y;y;y--){
-		for (x=out->x;x;x--){
-			outp[0]=0;
-			outp[1]=in[2]>>8;
-			outp[2]=in[1]>>8;
-			outp[3]=in[0]>>8;
-			outp+=4;
-			in+=3;
-		}
-		outp+=skip;
-	}
-}
-#endif
-
 /* We assume long holds at least 32 bits */
 static long color_555be(int rgb)
 {
@@ -593,6 +558,50 @@ static long color_565(int rgb)
 	return ret;
 }
 
+static long color_888_bgr_15bit(int rgb)
+{
+	int r,g,b;
+	long ret = 0;
+
+	r=(rgb>>16)&255;
+	g=(rgb>>8)&255;
+	/* Long live the PIN photodiode */
+	b=rgb&255;
+
+	r=(r*31+127)/255;
+	g=(g*31+127)/255;
+	b=(b*31+127)/255;
+
+	((unsigned char *)&ret)[0]=(unsigned char)(r<<3);
+	((unsigned char *)&ret)[1]=(unsigned char)(g<<3);
+	((unsigned char *)&ret)[2]=(unsigned char)(b<<3);
+
+	return ret;
+}
+
+static long color_888_bgr_16bit(int rgb)
+{
+	int r,g,b;
+	long ret = 0;
+
+	r=(rgb>>16)&255;
+	g=(rgb>>8)&255;
+	/* Long live the PIN photodiode */
+	b=rgb&255;
+
+	r=(r*31+127)/255;
+	g=(g*63+127)/255;
+	b=(b*31+127)/255;
+
+	((unsigned char *)&ret)[0]=(unsigned char)(r<<3);
+	((unsigned char *)&ret)[1]=(unsigned char)(g<<2);
+	((unsigned char *)&ret)[2]=(unsigned char)(b<<3);
+
+	return ret;
+}
+
+
+
 /* rgb = r*65536+g*256+b */
 /* The selected color_fn returns a long.
  * When we have for example 2 bytes per pixel, we make them in the memory,
@@ -601,16 +610,22 @@ static long color_565(int rgb)
  */
 long (*get_color_fn(int depth))(int rgb)
 {
-	switch(depth)
-	{
+	switch (depth) {
 		case 33:
 			return color_121;
 			break;
 
+		case 801:
+			return color_111;
+			break;
+
 		case 65:
 			return color_332;
 			break;
 
+		case 833:
+			return color_666;
+
 		case 122:
 			return color_555;
 			break;
@@ -628,7 +643,7 @@ long (*get_color_fn(int depth))(int rgb)
 			break;
 
 		case 451:
-			return color_pass_rgb;
+			return color_888_rgb;
 			break;
 
 		case 195:
@@ -647,6 +662,14 @@ long (*get_color_fn(int depth))(int rgb)
 			return color_8888_0rgb;
 			break;
 
+		case 15555:
+			return color_888_bgr_15bit;
+			break;
+
+		case 16579:
+			return color_888_bgr_16bit;
+			break;
+
 		default:
 			return NULL;
 			break;
@@ -654,44 +677,25 @@ long (*get_color_fn(int depth))(int rgb)
 	}
 }
 
-#if 0
-static void make_8_table(int *table, double gamma)
-{
-	int i,light0;
-	float light;
-	const float inv_255=1/255.;
-
-	for (i=0;i<256;i++){
-		light=powf((float)i*inv_255,gamma);
-		/* Long live the Nipkow Disk */
-		light0=65535*light;
-		if (light0<0) light0=0;
-		if (light0>65535) light0=65535;
-		table[i]=light0;
-	}
-}
-#endif
-
 /* Gamma says that light=electricity raised to gamma */
-/* dump_t2c means memory organization defined in comment for
- * red_table on the top of dither.c */
-/* dump_t2c is taken into account only if t2c is defined. */
-static void make_16_table(int *table, int bits, int pos, float gamma, int dump_t2c,
-	int bigendian)
+static void make_16_table(int *table, int values, int mult, float gamma, int bigendian)
 {
-	int j,light_val,grades=(1<<bits)-1,grade;
+	int grades = values - 1;
+	int j, light_val, grade;
 	float voltage;
-	float rev_gamma=1/gamma;
-	const float inv_65535=(float)(1/65535.);
+	float rev_gamma = 1 / gamma;
+	const float inv_65535 = (float)(1 / 65535.);
 	int last_grade, last_content;
+	unsigned int val;
 	uttime start_time = get_time();
 	int sample_state = 0;
 	int x_slow_fpu = slow_fpu;
+
 	if (gamma_bits != 2) x_slow_fpu = !gamma_bits;
 
-	repeat_loop:
-	last_grade=-1;
-	last_content=0;
+ repeat_loop:
+	last_grade = -1;
+	last_content = 0;
 
 	for (j=0;j<65536;j++){
 		if (x_slow_fpu) {
@@ -717,18 +721,18 @@ static void make_16_table(int *table, int bits, int pos, float gamma, int dump_t
 				}
 			}
 		}
-		voltage=powf(j*inv_65535,rev_gamma);
+		voltage = powf(j * inv_65535, rev_gamma);
 		/* Determine which monitor input voltage is equivalent
 		 * to said photon flux level
 		 */
 
-		grade=(int)(voltage*grades+(float)0.5);
-		if (grade==last_grade){
-			table[j]=last_content;
+		grade = (int)(voltage * grades + (float)0.5);
+		if (grade == last_grade) {
+			table[j] = last_content;
 			continue;
 		}
-		last_grade=grade;
-		voltage=(float)grade/grades;
+		last_grade = grade;
+		voltage = (float)grade / grades;
 		/* Find nearest voltage to this voltage. Finding nearest voltage, not
 		 * nearest photon flux ensures the dithered pixels will be perceived to be
 		 * near. The voltage input into the monitor was intentionally chosen by
@@ -738,23 +742,19 @@ static void make_16_table(int *table, int bits, int pos, float gamma, int dump_t
 		 * kool ;-) (and is kool)
 		 */
 
-		light_val=(int)(powf(voltage,gamma)*65535+(float)0.5);
+		light_val = (int)(powf(voltage, gamma) * 65535 + (float)0.5);
 		/* Find out what photon flux this index represents */
 
-		if (light_val<0) light_val=0;
-		if (light_val>65535) light_val=65535;
+		if (light_val < 0) light_val = 0;
+		if (light_val > 65535) light_val = 65535;
 		/* Clip photon flux for safety */
 
-		if (bigendian) {
-			unsigned val, val2;
-			val = grade<<pos;
-			val2 = (val>>8) | ((val&0xff)<<8);
-			last_content=light_val|((unsigned)val2<<16U);
-		}else{
-			last_content=light_val|((unsigned)grade<<(pos+16U));
-		}
+		val = grade * mult;
+		if (bigendian)
+			val = (val >> 8) | ((val & 0xff) << 8);
+		last_content = light_val | (val << 16);
 
-		table[j]=last_content;
+		table[j] = last_content;
 		/* Save index and photon flux. */
 	}
 	if (x_slow_fpu == -1) slow_fpu = 0;	/* if loop passed once without
@@ -762,22 +762,22 @@ static void make_16_table(int *table, int bits, int pos, float gamma, int dump_t
 	if (gamma_bits == 2 && x_slow_fpu == 1) slow_fpu = 1;
 }
 
-static void make_red_table(int bits, int pos, int dump_t2c, int be)
+static void make_red_table(int values, int mult, int be)
 {
 	red_table = xrealloc(red_table, 65536 * sizeof(*red_table));
-	make_16_table(red_table,bits,pos,(float)display_red_gamma,dump_t2c, be);
+	make_16_table(red_table, values, mult, (float)display_red_gamma, be);
 }
 
-static void make_green_table(int bits, int pos, int dump_t2c, int be)
+static void make_green_table(int values, int mult, int be)
 {
 	green_table = xrealloc(green_table, 65536 * sizeof(*green_table));
-	make_16_table(green_table,bits,pos,(float)display_green_gamma,dump_t2c, be);
+	make_16_table(green_table, values, mult, (float)display_green_gamma, be);
 }
 
-static void make_blue_table(int bits, int pos,int dump_t2c, int be)
+static void make_blue_table(int values, int mult, int be)
 {
 	blue_table = xrealloc(blue_table, 65536 * sizeof(*blue_table));
-	make_16_table(blue_table,bits,pos,(float)display_blue_gamma, dump_t2c, be);
+	make_16_table(blue_table, values, mult, (float)display_blue_gamma, be);
 }
 
 void dither(unsigned short *in, struct bitmap *out)
@@ -812,12 +812,12 @@ static void make_round_tables(void)
 	int a;
 	unsigned short v;
 
-	for (a=0;a<256;a++){
+	for (a = 0; a < 256; a++) {
 		/* a is sRGB coordinate */
-		v=ags_8_to_16((unsigned char)a,(float)((float)user_gamma/(float)sRGB_gamma));
-		round_red_table[a]=red_table[v >> (8 - 8 * table_16)] & 0xffff;
-		round_green_table[a]=green_table[v >> (8 - 8 * table_16)] & 0xffff;
-		round_blue_table[a]=blue_table[v >> (8 - 8 * table_16)] & 0xffff;
+		v = ags_8_to_16((unsigned char)a, (float)(user_gamma / sRGB_gamma));
+		round_red_table[a] = red_table[v >> (8 - 8 * table_16)] & 0xffff;
+		round_green_table[a] = green_table[v >> (8 - 8 * table_16)] & 0xffff;
+		round_blue_table[a] = blue_table[v >> (8 - 8 * table_16)] & 0xffff;
 	}
 }
 
@@ -858,59 +858,77 @@ static void compress_tables(void)
 void init_dither(int depth)
 {
 	table_16 = 1;
-	switch(depth){
+	switch (depth) {
 		case 33:
 		/* 4bpp, 1Bpp */
-		make_red_table(1,3,0,0);
-		make_green_table(2,1,0,0);
-		make_blue_table(1,0,0,0);
-		dither_fn_internal=dither_1byte;
-		round_fn=round_1byte;
+		make_red_table(1 << 1, 1 << 3, 0);
+		make_green_table(1 << 2, 1 << 1, 0);
+		make_blue_table(1 << 1, 1 << 0, 0);
+		dither_fn_internal = dither_1byte;
+		round_fn = round_1byte;
+		break;
+
+		case 801:
+		/* 8bpp, 1Bpp, 1x1x1 */
+		make_red_table(1 << 1, 1 << 2, 0);
+		make_green_table(1 << 1, 1 << 1, 0);
+		make_blue_table(1 << 1, 1 << 0, 0);
+		dither_fn_internal = dither_1byte;
+		round_fn = round_1byte;
 		break;
 
 		case 65:
-		/* 8 bpp, 1 Bpp */
-		make_red_table(3,5,0,0);
-		make_green_table(3,2,0,0);
-		make_blue_table(2,0,0,0);
-		dither_fn_internal=dither_1byte;
-		round_fn=round_1byte;
+		/* 8 bpp, 1Bpp */
+		make_red_table(1 << 3, 1 << 5, 0);
+		make_green_table(1 << 3, 1 << 2, 0);
+		make_blue_table(1 << 2, 1 << 0, 0);
+		dither_fn_internal = dither_1byte;
+		round_fn = round_1byte;
+		break;
+
+		case 833:
+		/* 8bpp, 1Bpp, 6x6x6 */
+		make_red_table(6, 36, 0);
+		make_green_table(6, 6, 0);
+		make_blue_table(6, 1, 0);
+		dither_fn_internal = dither_1byte;
+		round_fn = round_1byte;
 		break;
 
 		case 122:
 		/* 15bpp, 2Bpp */
-		make_red_table(5,10,1,0);
-		make_green_table(5,5,1,0);
-		make_blue_table(5,0,1,0);
-		dither_fn_internal=dither_2byte;
-		round_fn=round_2byte;
+		make_red_table(1 << 5, 1 << 10, 0);
+		make_green_table(1 << 5, 1 << 5, 0);
+		make_blue_table(1 << 5, 1 << 0, 0);
+		dither_fn_internal = dither_2byte;
+		round_fn = round_2byte;
 		break;
 
 		case 378:
-		/* 15bpp, 2Bpp, disordered (I have a mental disorder) */
-		make_red_table(5,10,1,1);
-		make_green_table(5,5,1,1);
-		make_blue_table(5,0,1,1);
-		dither_fn_internal=dither_2byte;
-		round_fn=round_2byte;
+		/* 15bpp, 2Bpp, disordered (1 << I have a mental disorder) */
+		make_red_table(1 << 5, 1 << 10, 1);
+		make_green_table(1 << 5, 1 << 5, 1);
+		make_blue_table(1 << 5, 1 << 0, 1);
+		dither_fn_internal = dither_2byte;
+		round_fn = round_2byte;
 		break;
 
 		case 130:
 		/* 16bpp, 2Bpp */
-		make_red_table(5,11,1,0);
-		make_green_table(6,5,1,0);
-		make_blue_table(5,0,1,0);
-		dither_fn_internal=dither_2byte;
-		round_fn=round_2byte;
+		make_red_table(1 << 5, 1 << 11, 0);
+		make_green_table(1 << 6, 1 << 5, 0);
+		make_blue_table(1 << 5, 1 << 0, 0);
+		dither_fn_internal = dither_2byte;
+		round_fn = round_2byte;
 		break;
 
 		case 386:
 		/* 16bpp, 2Bpp, disordered */
-		make_red_table(5,11,1,1);
-		make_green_table(6,5,1,1);
-		make_blue_table(5,0,1,1);
-		dither_fn_internal=dither_2byte;
-		round_fn=round_2byte;
+		make_red_table(1 << 5, 1 << 11, 1);
+		make_green_table(1 << 6, 1 << 5, 1);
+		make_blue_table(1 << 5, 1 << 0, 1);
+		dither_fn_internal = dither_2byte;
+		round_fn = round_2byte;
 		break;
 
 		case 451:
@@ -918,11 +936,11 @@ void init_dither(int depth)
 		 * Even this is dithered!
 		 * R G B
 		 */
-		make_red_table(8,0,0,0);
-		make_green_table(8,0,0,0);
-		make_blue_table(8,0,0,0);
-		dither_fn_internal=dither_451;
-		round_fn=round_451;
+		make_red_table(1 << 8, 1 << 0, 0);
+		make_green_table(1 << 8, 1 << 0, 0);
+		make_blue_table(1 << 8, 1 << 0, 0);
+		dither_fn_internal = dither_451;
+		round_fn = round_451;
 		break;
 
 		case 195:
@@ -930,11 +948,11 @@ void init_dither(int depth)
 		 * Even this is dithered!
 		 * B G R
 		 */
-		make_red_table(8,0,0,0);
-		make_green_table(8,0,0,0);
-		make_blue_table(8,0,0,0);
-		dither_fn_internal=dither_195;
-		round_fn=round_195;
+		make_red_table(1 << 8, 1 << 0, 0);
+		make_green_table(1 << 8, 1 << 0, 0);
+		make_blue_table(1 << 8, 1 << 0, 0);
+		dither_fn_internal = dither_195;
+		round_fn = round_195;
 		break;
 
 		case 452:
@@ -942,11 +960,11 @@ void init_dither(int depth)
 		 * Even this is dithered!
 		 * 0 B G R
 		 */
-		make_red_table(8,0,0,0);
-		make_green_table(8,0,0,0);
-		make_blue_table(8,0,0,0);
-		dither_fn_internal=dither_452;
-		round_fn=round_452;
+		make_red_table(1 << 8, 1 << 0, 0);
+		make_green_table(1 << 8, 1 << 0, 0);
+		make_blue_table(1 << 8, 1 << 0, 0);
+		dither_fn_internal = dither_452;
+		round_fn = round_452;
 		break;
 
 		case 196:
@@ -954,11 +972,11 @@ void init_dither(int depth)
 		 * Even this is dithered!
 		 * B G R 0
 		 */
-		make_red_table(8,0,0,0);
-		make_green_table(8,0,0,0);
-		make_blue_table(8,0,0,0);
-		dither_fn_internal=dither_196;
-		round_fn=round_196;
+		make_red_table(1 << 8, 1 << 0, 0);
+		make_green_table(1 << 8, 1 << 0, 0);
+		make_blue_table(1 << 8, 1 << 0, 0);
+		dither_fn_internal = dither_196;
+		round_fn = round_196;
 		break;
 
 		case 708:
@@ -966,19 +984,43 @@ void init_dither(int depth)
 		 * Even this is dithered!
 		 * 0 R G B
 		 */
-		make_red_table(8,0,0,0);
-		make_green_table(8,0,0,0);
-		make_blue_table(8,0,0,0);
-		dither_fn_internal=dither_708;
-		round_fn=round_708;
+		make_red_table(1 << 8, 1 << 0, 0);
+		make_green_table(1 << 8, 1 << 0, 0);
+		make_blue_table(1 << 8, 1 << 0, 0);
+		dither_fn_internal = dither_708;
+		round_fn = round_708;
+		break;
+
+		case 15555:
+		/* 24bpp, 3Bpp, downsampled to 15bit
+		 * B G R
+		 */
+		make_red_table(1 << 5, 1 << 3, 0);
+		make_green_table(1 << 5, 1 << 3, 0);
+		make_blue_table(1 << 5, 1 << 3, 0);
+		dither_fn_internal = dither_195;
+		round_fn = round_195;
+		break;
+
+		case 16579:
+		/* 24bpp, 3Bpp, downsampled to 16bit
+		 * B G R
+		 */
+		make_red_table(1 << 5, 1 << 3, 0);
+		make_green_table(1 << 6, 1 << 2, 0);
+		make_blue_table(1 << 5, 1 << 3, 0);
+		dither_fn_internal = dither_195;
+		round_fn = round_195;
 		break;
 
 		default:
-		internal("Graphics driver returned unsupported \
-pixel memory organisation %d",depth);
+		internal("Graphics driver returned unsupported pixel memory organisation %d",depth);
 	}
 	compress_tables();
 	make_round_tables();
+
+	gamma_cache_rgb = -2;
+	gamma_stamp++;
 }
 
 /* Input is in sRGB space (unrounded, i. e. directly from HTML)
diff --git a/drivers.c b/drivers.c
@@ -24,16 +24,10 @@ static unsigned char *init_graphics_driver(unsigned char *p, unsigned char *disp
 	struct driver_param *dp = get_driver_param(x_driver.name);
 	if (!p || !*p)
 		p = dp->param;
-	x_driver.kbd_codepage = dp->kbd_codepage;
-	x_driver.shell = mem_calloc(MAX_STR_LEN);
-	if (dp->shell)
-		safe_strncpy(x_driver.shell, dp->shell, MAX_STR_LEN);
 	drv = &x_driver;
-	if ((r = x_driver.init_driver(p, display))) {
-		free(x_driver.shell);
-		x_driver.shell = NULL;
+	if ((r = x_driver.init_driver(p, display)))
 		drv = NULL;
-	} else
+	else
 		F = 1;
 	return r;
 }
@@ -76,7 +70,6 @@ unsigned char *init_graphics(unsigned char *driver, unsigned char *param, unsign
 void shutdown_graphics(void)
 {
 	if (drv) {
-		free(drv->shell);
 		drv->shutdown_driver();
 		drv = NULL;
 		F = 0;
@@ -86,34 +79,184 @@ void shutdown_graphics(void)
 void update_driver_param(void)
 {
 	if (drv) {
-		struct driver_param *dp = get_driver_param(drv->name);
-		dp->kbd_codepage = drv->kbd_codepage;
+		struct driver_param *dp = drv->param;
 		free(dp->param);
-		dp->param = stracpy(drv->get_driver_param());
-		free(dp->shell);
-		dp->shell = stracpy(drv->shell);
+		dp->param = NULL;
+		if (drv->get_driver_param)
+			dp->param = stracpy(drv->get_driver_param());
 		dp->nosave = 0;
 	}
 }
 
 int g_kbd_codepage(struct graphics_driver *drv)
 {
-	if (drv->kbd_codepage >= 0)
-		return drv->kbd_codepage;
+	if (drv->param->kbd_codepage > 0)
+		return drv->param->kbd_codepage;
 	return 0;
 }
 
-void generic_set_clip_area(struct graphics_device *dev, struct rect *r)
+/* FIXME */
+int do_rects_intersect(struct rect *r1, struct rect *r2)
 {
-	memcpy(&dev->clip, r, sizeof(struct rect));
+	return (r1->x1 > r2->x1 ? r1->x1 : r2->x1) < (r1->x2 > r2->x2 ? r2->x2 : r1->x2) && (r1->y1 > r2->y1 ? r1->y1 : r2->y1) < (r1->y2 > r2->y2 ? r2->y2 : r1->y2);
+}
+
+void intersect_rect(struct rect *v, struct rect *r1, struct rect *r2)
+{
+	v->x1 = r1->x1 > r2->x1 ? r1->x1 : r2->x1;
+	v->x2 = r1->x2 > r2->x2 ? r2->x2 : r1->x2;
+	v->y1 = r1->y1 > r2->y1 ? r1->y1 : r2->y1;
+	v->y2 = r1->y2 > r2->y2 ? r2->y2 : r1->y2;
+}
+
+void unite_rect(struct rect *v, struct rect *r1, struct rect *r2)
+{
+	if (!is_rect_valid(r1)) {
+		if (v != r2) memcpy(v, r2, sizeof(struct rect));
+		return;
+	}
+	if (!is_rect_valid(r2)) {
+		if (v != r1) memcpy(v, r1, sizeof(struct rect));
+		return;
+	}
+	v->x1 = r1->x1 < r2->x1 ? r1->x1 : r2->x1;
+	v->x2 = r1->x2 < r2->x2 ? r2->x2 : r1->x2;
+	v->y1 = r1->y1 < r2->y1 ? r1->y1 : r2->y1;
+	v->y2 = r1->y2 < r2->y2 ? r2->y2 : r1->y2;
+}
+
+#define R_GR   8
+
+struct rect_set *init_rect_set(void)
+{
+	struct rect_set *s;
+	s = mem_calloc(sizeof(struct rect_set) + sizeof(struct rect) * R_GR);
+	s->rl = R_GR;
+	s->m = 0;
+	return s;
+}
+
+void add_to_rect_set(struct rect_set **s, struct rect *r)
+{
+	struct rect_set *ss = *s;
+	int i;
+	if (!is_rect_valid(r)) return;
+	for (i = 0; i < ss->rl; i++) if (!ss->r[i].x1 && !ss->r[i].x2 && !ss->r[i].y1 && !ss->r[i].y2) {
+ x:
+		memcpy(&ss->r[i], r, sizeof(struct rect));
+		if (i >= ss->m) ss->m = i + 1;
+		return;
+	}
+	if ((unsigned)ss->rl > (INT_MAX - sizeof(struct rect_set)) / sizeof(struct rect) - R_GR) overalloc();
+	ss = xrealloc(ss, sizeof(struct rect_set) + sizeof(struct rect) * (ss->rl + R_GR));
+	memset(&(*s = ss)->r[i = (ss->rl += R_GR) - R_GR], 0, sizeof(struct rect) * R_GR);
+	goto x;
+}
+
+void exclude_rect_from_set(struct rect_set **s, struct rect *r)
+{
+	int i, a;
+	struct rect *rr;
+	do {
+		a = 0;
+		for (i = 0; i < (*s)->m; i++) if (do_rects_intersect(rr = &(*s)->r[i], r)) {
+			struct rect r1, r2, r3, r4;
+			r1.x1 = rr->x1;
+			r1.x2 = rr->x2;
+			r1.y1 = rr->y1;
+			r1.y2 = r->y1;
+
+			r2.x1 = rr->x1;
+			r2.x2 = r->x1;
+			r2.y1 = r->y1;
+			r2.y2 = r->y2;
+
+			r3.x1 = r->x2;
+			r3.x2 = rr->x2;
+			r3.y1 = r->y1;
+			r3.y2 = r->y2;
+
+			r4.x1 = rr->x1;
+			r4.x2 = rr->x2;
+			r4.y1 = r->y2;
+			r4.y2 = rr->y2;
+
+			intersect_rect(&r2, &r2, rr);
+			intersect_rect(&r3, &r3, rr);
+			rr->x1 = rr->x2 = rr->y1 = rr->y2 = 0;
+			add_to_rect_set(s, &r1);
+			add_to_rect_set(s, &r2);
+			add_to_rect_set(s, &r3);
+			add_to_rect_set(s, &r4);
+			a = 1;
+		}
+	} while (a);
+}
+
+void set_clip_area(struct graphics_device *dev, struct rect *r)
+{
+	dev->clip = *r;
 	if (dev->clip.x1 < 0) dev->clip.x1 = 0;
 	if (dev->clip.x2 > dev->size.x2) dev->clip.x2 = dev->size.x2;
 	if (dev->clip.y1 < 0) dev->clip.y1 = 0;
 	if (dev->clip.y2 > dev->size.y2) dev->clip.y2 = dev->size.y2;
-	if (dev->clip.x1 >= dev->clip.x2 || dev->clip.y1 >= dev->clip.y2) {
+	if (!is_rect_valid(&dev->clip)) {
 		/* Empty region */
 		dev->clip.x1 = dev->clip.x2 = dev->clip.y1 = dev->clip.y2 = 0;
 	}
+	if (drv->set_clip_area)
+		drv->set_clip_area(dev);
+}
+
+/* memory address r must contain one struct rect
+ * x1 is leftmost pixel that is still valid
+ * x2 is leftmost pixel that isn't valid any more
+ * y1, y2 analogically
+ */
+int restrict_clip_area(struct graphics_device *dev, struct rect *r, int x1, int y1, int x2, int y2)
+{
+	struct rect v, rr;
+	rr.x1 = x1, rr.x2 = x2, rr.y1 = y1, rr.y2 = y2;
+	if (r) memcpy(r, &dev->clip, sizeof(struct rect));
+	intersect_rect(&v, &dev->clip, &rr);
+	set_clip_area(dev, &v);
+	return is_rect_valid(&v);
+}
+
+struct rect_set *g_scroll(struct graphics_device *dev, int scx, int scy)
+{
+	struct rect_set *rs = init_rect_set();
+
+	if (!scx && !scy)
+		return rs;
+
+	if (abs(scx) >= dev->clip.x2 - dev->clip.x1
+	|| abs(scy) >= dev->clip.y2 - dev->clip.y1) {
+		add_to_rect_set(&rs, &dev->clip);
+		return rs;
+	}
+
+	if (drv->scroll(dev, &rs, scx, scy)) {
+		struct rect q = dev->clip;
+		if (scy >= 0)
+			q.y2 = q.y1 + scy;
+		else
+			q.y1 = q.y2 + scy;
+		add_to_rect_set(&rs, &q);
+
+		q = dev->clip;
+		if (scy >= 0)
+			q.y1 += scy;
+		else
+			q.y2 += scy;
+		if (scx >= 0)
+			q.x2 = q.x1 + scx;
+		else
+			q.x1 = q.x2 + scx;
+		add_to_rect_set(&rs, &q);
+	}
+
+	return rs;
 }
 
 #endif
diff --git a/entity.inc b/entity.inc
@@ -238,7 +238,7 @@ static const struct { const char *s; int c; } entities [1010] = {
   {"aogon",	0x0105},  /* LATIN SMALL LETTER A WITH OGONEK		   */
   {"ap",	0x2248},  /* ALMOST EQUAL TO				   */
   {"ape",	0x224A},  /* ALMOST EQUAL OR EQUAL TO			   */
-  {"apos",	0x02BC},  /* MODIFIER LETTER APOSTROPHE 		   */
+  {"apos",	0x0027},  /* APOSTROPHE 		   		   */
   {"aring",	0x00E5},  /* LATIN SMALL LETTER A WITH RING ABOVE	   */
   {"ast",	0x002A},  /* ASTERISK					   */
   {"asymp",	0x2248},  /* ALMOST EQUAL TO				   */
diff --git a/html.c b/html.c
@@ -453,7 +453,7 @@ static const struct color_spec color_specs[] = {
 	{"yellowgreen",		0x9ACD32},
 };
 
-#define endof(T) ((T)+sizeof(T)/sizeof(*(T)))
+#define endof(T) ((T) + array_elements(T))
 
 int decode_color(unsigned char *str, struct rgb *col)
 {
@@ -1009,10 +1009,10 @@ static void html_font(unsigned char *a)
 	get_color(a, cast_uchar "color", &format_.fg);
 }
 
-static unsigned char *get_url_val_nonempty(unsigned char *a, unsigned char *name)
+static unsigned char *get_url_val_img(unsigned char *a, unsigned char *name)
 {
 	unsigned char *v = get_url_val(a, name);
-	if (v && !*v) {
+	if (v && !v[strcspn(cast_const_char v, "./")]) {
 		free(v);
 		v = NULL;
 	}
@@ -1042,18 +1042,19 @@ static void html_img(unsigned char *a)
 	ismap = format_.link && (F || !has_attr(a, cast_uchar "usemap")) && has_attr(a, cast_uchar "ismap");
 	free(format_.image);
 	format_.image = NULL;
-	if ((s = get_url_val_nonempty(a, cast_uchar "data-full"))
-	|| (s = get_url_val_nonempty(a, cast_uchar "data-normal"))
-	|| (s = get_url_val_nonempty(a, cast_uchar "data-src"))
-	|| (s = get_url_val_nonempty(a, cast_uchar "data-defer-src"))
-	|| (s = get_url_val_nonempty(a, cast_uchar "data-li-src"))
-	|| (s = get_url_val_nonempty(a, cast_uchar "data-original"))
-	|| (s = get_url_val_nonempty(a, cast_uchar "data-small"))
-	|| (s = get_url_val_nonempty(a, cast_uchar "data-lazy"))
-	|| (s = get_url_val_nonempty(a, cast_uchar "src"))
-	|| (s = get_url_val_nonempty(a, cast_uchar "dynsrc"))
-	|| (s = get_url_val_nonempty(a, cast_uchar "data"))
-	|| (s = get_url_val_nonempty(a, cast_uchar "content"))) {
+	if ((s = get_url_val_img(a, cast_uchar "data-full"))
+	|| (s = get_url_val_img(a, cast_uchar "data-normal"))
+	|| (s = get_url_val_img(a, cast_uchar "data-src"))
+	|| (s = get_url_val_img(a, cast_uchar "data-defer-src"))
+	|| (s = get_url_val_img(a, cast_uchar "data-li-src"))
+	|| (s = get_url_val_img(a, cast_uchar "data-original"))
+	|| (s = get_url_val_img(a, cast_uchar "data-small"))
+	|| (s = get_url_val_img(a, cast_uchar "data-lazy"))
+	|| (s = get_url_val_img(a, cast_uchar "src"))
+	|| (s = get_url_val_img(a, cast_uchar "dynsrc"))
+	|| (s = get_url_val_img(a, cast_uchar "data"))
+	|| (s = get_url_val_img(a, cast_uchar "content"))
+	|| (s = get_url_val(a, cast_uchar "src"))) {
 		 format_.image = join_urls(format_.href_base, s);
 		 orig_link = s;
 	}
@@ -2720,6 +2721,7 @@ static void html_link(unsigned char *a)
 	}
 	if (
 	    !casecmp(name, cast_uchar "schema", 6) ||
+	    !casecmp(name, cast_uchar "mw-", 3) ||
 	    !casestrcmp(name, cast_uchar "Edit-Time-Data") ||
 	    !casestrcmp(name, cast_uchar "File-List") ||
 	    !casestrcmp(name, cast_uchar "alternate stylesheet") ||
diff --git a/html_gr.c b/html_gr.c
@@ -37,20 +37,41 @@ static int get_real_font_size(int size)
 	return 0;
 }
 
-struct background *get_background(unsigned char *bg, unsigned char *bgcolor)
+struct background *g_get_background(unsigned char *bg, unsigned char *bgcolor)
 {
 	struct background *b;
 	struct rgb r;
 	b = xmalloc(sizeof(struct background));
-	{
-		if (bgcolor && !decode_color(bgcolor, &r))
-			b->u.sRGB=(r.r << 16) + (r.g << 8) + r.b;
-		else
-			b->u.sRGB=(d_opt->default_bg.r << 16) + (d_opt->default_bg.g << 8) + d_opt->default_bg.b;
-	}
+	b->color = 0;
+	b->gamma_stamp = gamma_stamp - 1;
+	if (bgcolor && !decode_color(bgcolor, &r))
+		b->sRGB = (r.r << 16) + (r.g << 8) + r.b;
+	else
+		b->sRGB = (d_opt->default_bg.r << 16) + (d_opt->default_bg.g << 8) + d_opt->default_bg.b;
 	return b;
 }
 
+/* FIXME */
+void g_release_background(struct background *bg)
+{
+	free(bg);
+}
+
+void g_draw_background(struct graphics_device *dev, struct background *bg, int x, int y, int xw, int yw)
+{
+	int x2, y2;
+	long color;
+	if (bg->gamma_stamp == gamma_stamp)
+		color = bg->color;
+	else {
+		bg->gamma_stamp = gamma_stamp;
+		color = bg->color = dip_get_color_sRGB(bg->sRGB);
+	}
+	if (test_int_overflow(x, xw, &x2)) x2 = INT_MAX;
+	if (test_int_overflow(y, yw, &y2)) y2 = INT_MAX;
+	drv->fill_area(dev, x, y, x2, y2, color);
+}
+
 static void g_put_chars(void *, unsigned char *, int);
 
 /* Returns 0 to 2550 */
@@ -275,11 +296,9 @@ static void split_line_object(struct g_part *p, struct g_object *text_go, unsign
 		goto nt2;
 	}
 	text_t = get_struct(text_go, struct g_object_text, goti.go);
-	if (par_format.align == AL_NO_BREAKABLE
-	&& text_t == p->text
-	&& strspn(cast_const_char ptr, cast_const_char " ") == strlen(cast_const_char ptr)) {
+	if (par_format.align == AL_NO_BREAKABLE && text_t == p->text
+	&& !ptr[strspn(cast_const_char ptr, cast_const_char " ")])
 		return;
-	}
 	sl = strlen(cast_const_char ptr);
 	if (sl > INT_MAX - sizeof(struct g_object_text))
 		overalloc();
@@ -634,7 +653,7 @@ static void g_hr(struct g_part *gp, struct hr_param *hr)
 	o->go.xw = hr->width;
 	o->go.yw = hr->size;
 	table_bg(&format_, bgstr);
-	o->bg = get_background(NULL, bgstr);
+	o->bg = g_get_background(NULL, bgstr);
 	o->n_entries = 0;
 	flush_pending_text_to_line(gp);
 	add_object_to_line(gp, &gp->line, &o->go);
@@ -986,7 +1005,7 @@ struct g_part *g_format_html_part(unsigned char *start, unsigned char *end, int 
 	{
 		struct g_object_area *a;
 		a = mem_calloc(sizeof(struct g_object_area));
-		a->bg = get_background(bg, bgcolor);
+		a->bg = g_get_background(bg, bgcolor);
 		if (bgcolor)
 			decode_color(bgcolor, &format_.bg);
 		if (bgcolor)
diff --git a/html_tbl.c b/html_tbl.c
@@ -1765,7 +1765,7 @@ static void table_draw(struct f_data_c *fd, struct g_object *o_, int x, int y)
 			draw_rect_set(dev, c->root->bg, c->brd, x, y);
 			restrict_clip_area(dev, &clip, x + c->root->go.x, y + c->root->go.y, x + c->root->go.x + c->root->go.xw /*c->g_width*/, y + c->root->go.y + c->root->go.yw);
 			c->root->go.draw(fd, &c->root->go, x + c->root->go.x, y + c->root->go.y);
-			drv->set_clip_area(dev, &clip);
+			set_clip_area(dev, &clip);
 		}
 	}
 	draw_rect_sets(dev, t->bg, t->r_bg, t->nr_bg, x, y);
@@ -1847,13 +1847,13 @@ static void process_g_table(struct g_part *gp, struct table *t)
 	else ta = &format_;
 
 	if (t->bordercolor && !decode_color(t->bordercolor, &dummy)) {
-		if (!(t->frame_bg = get_background(NULL, t->bordercolor))) {
+		if (!(t->frame_bg = g_get_background(NULL, t->bordercolor))) {
 			free_table(t);
 			return;
 		}
 	} else {
 		table_bg(ta, bgstr);
-		if (!(t->frame_bg = get_background(NULL, bgstr))) {
+		if (!(t->frame_bg = g_get_background(NULL, bgstr))) {
 			free_table(t);
 			return;
 		}
diff --git a/http.c b/http.c
@@ -172,6 +172,7 @@ static int check_http_server_bugs(unsigned char *url, struct http_connection_inf
 
 static void http_end_request(struct connection *c, int notrunc, int nokeepalive, int state)
 {
+	struct http_connection_info *info = c->info;
 	if (state == S__OK && c->cache) {
 		if (!notrunc)
 			truncate_entry(c->cache, c->from, 1);
@@ -179,8 +180,8 @@ static void http_end_request(struct connection *c, int notrunc, int nokeepalive,
 	}
 	setcstate(c, state);
 	if (c->info
-	&& !((struct http_connection_info *)c->info)->close
-	&& !((struct http_connection_info *)c->info)->send_close
+	&& !info->close
+	&& !info->send_close
 	&& !nokeepalive) {
 		add_keepalive_socket(c, HTTP_KEEPALIVE_TIMEOUT, 0);
 	} else
@@ -902,7 +903,6 @@ again:
 		unsigned char *cookie;
 		unsigned char *ch = head;
 		while ((cookie = parse_http_header(ch, cast_uchar "Set-Cookie", &ch))) {
-			unsigned char *host = remove_proxy_prefix(c->url);
 			set_cookie(NULL, host, cookie);
 			free(cookie);
 		}
diff --git a/https.c b/https.c
@@ -222,7 +222,7 @@ static void set_session_cache_entry(SSL_CTX *ctx, char *host, int port, SSL_SESS
 	if (!s)
 		return;
 	sl = strlen(host);
-	if (sl > INT_MAX - sizeof(sizeof(struct session_cache_entry))) return;
+	if (sl > INT_MAX - sizeof(struct session_cache_entry)) return;
 	sce = xmalloc(sizeof(struct session_cache_entry) + sl);
 	sce->absolute_time = get_absolute_time();
 	sce->ctx = ctx;
diff --git a/img.c b/img.c
@@ -173,14 +173,10 @@ void compute_background_8(unsigned char *rgb, struct cached_image *cimg)
 {
 	unsigned short red, green, blue;
 
-	round_color_sRGB_to_48(&red, &green, &blue
-		, cimg->background_color);
-	rgb[0]=ags_16_to_8(red
-		,(float)(cimg->red_gamma/(float)user_gamma));
-	rgb[1]=ags_16_to_8(green
-		,(float)(cimg->green_gamma/(float)user_gamma));
-	rgb[2]=ags_16_to_8(blue
-		,(float)(cimg->blue_gamma/(float)user_gamma));
+	round_color_sRGB_to_48(&red, &green, &blue, cimg->background_color);
+	rgb[0] = ags_16_to_8(red, (float)(cimg->red_gamma / user_gamma));
+	rgb[1] = ags_16_to_8(green, (float)(cimg->green_gamma / user_gamma));
+	rgb[2] = ags_16_to_8(blue, (float)(cimg->blue_gamma / user_gamma));
 }
 
 /* updates cimg state when header dimensions are know. Only allowed to be called
@@ -337,30 +333,26 @@ int header_dimensions_known(struct cached_image *cimg)
 			memset(cimg->buffer, 0, (size_t)cimg->width * (size_t)cimg->height * (size_t)cimg->buffer_bytes_per_pixel);
 		}else{
 			/* Fill the buffer with background color */
-			if (cimg->buffer_bytes_per_pixel>4){
+			if (cimg->buffer_bytes_per_pixel > 4) {
 				/* 16-bit */
 				unsigned short red, green, blue;
 
-				round_color_sRGB_to_48(&red, &green, &blue
-					, cimg->background_color);
-
-				red=ags_16_to_16(red
-					,(float)(cimg->red_gamma/(float)user_gamma));
-				green=ags_16_to_16(green
-					,(float)(cimg->green_gamma/(float)user_gamma));
-				blue=ags_16_to_16(blue
-					,(float)(cimg->blue_gamma/(float)user_gamma));
-				mix_one_color_48((unsigned short *)cimg->buffer
-					,cimg->width*cimg->height,red
-					,green, blue);
-			}else{
+				round_color_sRGB_to_48(&red, &green, &blue, cimg->background_color);
+
+				red = ags_16_to_16(red, (float)(cimg->red_gamma / user_gamma));
+				green = ags_16_to_16(green, (float)(cimg->green_gamma / user_gamma));
+				blue = ags_16_to_16(blue, (float)(cimg->blue_gamma / user_gamma));
+
+				mix_one_color_48((unsigned short *)cimg->buffer,
+					cimg->width * cimg->height, red ,green, blue);
+			} else {
 				unsigned char rgb[3];
 
 				/* 8-bit */
-				compute_background_8(rgb,cimg);
-				mix_one_color_24(cimg->buffer
-					,cimg->width*cimg->height
-					,rgb[0],rgb[1],rgb[2]);
+				compute_background_8(rgb, cimg);
+				mix_one_color_24(cimg->buffer,
+					cimg->width * cimg->height, rgb[0],
+					rgb[1], rgb[2]);
 			}
 		}
 	}
@@ -376,89 +368,79 @@ int header_dimensions_known(struct cached_image *cimg)
 /* Fills "tmp" buffer with the resulting data and does not free the input
  * buffer. May be called only in states 12 and 14 of cimg
  */
-static unsigned short *buffer_to_16(unsigned short *tmp, struct cached_image *cimg
-	,unsigned char *buffer, int height)
+static unsigned short *buffer_to_16(unsigned short *tmp, struct cached_image *cimg, unsigned char *buffer, int height)
 {
-	unsigned short red, green,blue;
+	unsigned short red, green, blue;
 
 #ifdef DEBUG
-	if (cimg->state!=12&&cimg->state!=14){
-		fprintf(stderr,"cimg->state=%d\n",cimg->state);
+	if (cimg->state != 12 && cimg->state != 14) {
+		fprintf(stderr, "cimg->state=%d\n", cimg->state);
 		internal("invalid state in buffer_to_16");
 	}
 #endif /* #ifdef DEBUG */
-	switch (cimg->buffer_bytes_per_pixel){
+	switch (cimg->buffer_bytes_per_pixel) {
 		case 3:
-			if (cimg->gamma_table){
+			if (cimg->gamma_table)
 				agx_24_to_48_table(tmp, buffer,
-					cimg->width*height
-					,cimg->gamma_table);
-			}
-			else{
-				agx_24_to_48(tmp,buffer,cimg->width
-					*height
-					,(float)((float)user_gamma/cimg->red_gamma)
-					,(float)((float)user_gamma/cimg->green_gamma)
-					,(float)((float)user_gamma/cimg->blue_gamma));
-			}
+					cimg->width * height,
+					cimg->gamma_table);
+			else
+				agx_24_to_48(tmp, buffer, cimg->width * height,
+					(float)(user_gamma / cimg->red_gamma),
+					(float)(user_gamma / cimg->green_gamma),
+					(float)(user_gamma / cimg->blue_gamma));
 		break;
 
-		case 3*sizeof(unsigned short):
-			if (cimg->gamma_table){
-				agx_48_to_48_table(tmp
-					,(unsigned short *)buffer
-					,cimg->width*height, cimg->gamma_table);
-			}else{
-				agx_48_to_48(tmp,(unsigned short *)buffer
-					,cimg->width*height
-					,(float)((float)user_gamma/cimg->red_gamma)
-					,(float)((float)user_gamma/cimg->green_gamma)
-					,(float)((float)user_gamma/cimg->blue_gamma));
-			}
+		case 3 * sizeof(unsigned short):
+			if (cimg->gamma_table)
+				agx_48_to_48_table(tmp, (unsigned short *)buffer,
+					cimg->width * height, cimg->gamma_table);
+			else
+				agx_48_to_48(tmp ,(unsigned short *)buffer,
+					cimg->width * height,
+					(float)(user_gamma / cimg->red_gamma),
+					(float)(user_gamma / cimg->green_gamma),
+					(float)(user_gamma / cimg->blue_gamma));
 		break;
 
 		/* Alpha's: */
 		case 4:
-		{
-
 			round_color_sRGB_to_48(&red,&green,&blue,cimg->background_color);
-			if (cimg->gamma_table){
-				agx_and_uc_32_to_48_table(
-						tmp, buffer, cimg->width *height,
-						cimg->gamma_table, red, green, blue);
-			}else{
-				agx_and_uc_32_to_48(tmp,buffer
-					,cimg->width*height
-					,(float)((float)user_gamma/cimg->red_gamma)
-					,(float)((float)user_gamma/cimg->green_gamma)
-					,(float)((float)user_gamma/cimg->blue_gamma)
-					,red, green, blue);
-			}
-		}
+			if (cimg->gamma_table)
+				agx_and_uc_32_to_48_table(tmp, buffer,
+						cimg->width * height,
+						cimg->gamma_table, red, green,
+						blue);
+			else
+				agx_and_uc_32_to_48(tmp, buffer,
+					cimg->width * height,
+					(float)(user_gamma / cimg->red_gamma),
+					(float)(user_gamma / cimg->green_gamma),
+					(float)(user_gamma / cimg->blue_gamma),
+					red, green, blue);
 		break;
 
-		case 4*sizeof(unsigned short):
-		{
+		case 4 * sizeof(unsigned short):
 			round_color_sRGB_to_48(&red, &green, &blue,
 				cimg->background_color);
-			if (cimg->gamma_table){
-				agx_and_uc_64_to_48_table
-					(tmp, (unsigned short *)buffer, cimg->width*height
-					,cimg->gamma_table, red, green, blue);
-			}else{
-				agx_and_uc_64_to_48(tmp
-					,(unsigned short*)buffer,cimg->width*height
-					,(float)((float)user_gamma/cimg->red_gamma)
-					,(float)((float)user_gamma/cimg->green_gamma)
-					,(float)((float)user_gamma/cimg->blue_gamma)
-					,red,green,blue);
-			}
-		}
+			if (cimg->gamma_table)
+				agx_and_uc_64_to_48_table(tmp,
+					(unsigned short *)buffer,
+					cimg->width * height, cimg->gamma_table,
+					red, green, blue);
+			else
+				agx_and_uc_64_to_48(tmp,
+					(unsigned short *)buffer,
+					cimg->width * height,
+					(float)(user_gamma / cimg->red_gamma),
+					(float)(user_gamma / cimg->green_gamma),
+					(float)(user_gamma / cimg->blue_gamma),
+					red, green, blue);
 		break;
 
 #ifdef DEBUG
 		default:
-		internal("buffer_to_16: unknown mem organization");
+			internal("buffer_to_16: unknown mem organization");
 #endif /* #ifdef DEBUG */
 
 	}
@@ -1015,7 +997,7 @@ static void draw_picture(struct f_data_c *fdatac, struct g_object_image *goi,
 	drv->draw_bitmap(dev, &cimg->bmp,x,y);
 	drv->fill_area(dev, x + cimg->bmp.x, y, x + goi->goti.go.xw, y + cimg->bmp.y, bg);
 	drv->fill_area(dev, x, y + cimg->bmp.y, x + goi->goti.go.xw, y + goi->goti.go.yw,bg);
-	drv->set_clip_area(dev, &saved);
+	set_clip_area(dev, &saved);
 }
 
 /* Ensures in buffer there is not newer picture than in bitmap. Allowed to be
@@ -1088,7 +1070,7 @@ static void img_draw_image(struct f_data_c *fdatac, struct g_object *goi_, int x
 	}
 #endif /* #ifdef DEBUG */
 	ret:
-	drv->set_clip_area(fdatac->ses->term->dev, &r);
+	set_clip_area(fdatac->ses->term->dev, &r);
 #ifdef LINKS_TESTMODE_IMAGE_AUTO_EXIT
 	if (cimg->state & 1)
 		terminate_loop = 1;
@@ -1218,7 +1200,7 @@ struct g_object_image *insert_image(struct g_part *p, struct image_description *
 	image->af = request_additional_file(current_f_data, im->url);
 	if (image->goti.go.xw < 0 || image->goti.go.yw < 0)
 		image->af->unknown_image_size = 1;
-	image->background = hack_rgb(p->root->bg->u.sRGB);
+	image->background = hack_rgb(p->root->bg->sRGB);
 
 	/* This supplies the result into image->cimg and global_cimg */
 	find_or_make_cached_image(image, im->url, d_opt->image_scale);
diff --git a/kbd.c b/kbd.c
@@ -1074,7 +1074,7 @@ do_alt:
 	}
 	if (ev.x != -1) {
 		if (itrm->flags & BRACKETED_PASTE && ev.ev == EV_KBD)
-			ev.y |= KBD_PASTE;
+			ev.y |= KBD_PASTING;
 		itrm->queue_event(itrm, (unsigned char *)&ev, sizeof(struct links_event));
 	}
 	memmove(itrm->kqueue, itrm->kqueue + el, itrm->qlen -= el);
diff --git a/language.h b/language.h
@@ -1,684 +1,686 @@
 /* Automatically generated by gen-intl */
 
-#define T__CHAR_SET      1
-#define T__LANGUAGE      2
-#define T__ACCEPT_LANGUAGE      3
-#define T__DEFAULT_CHAR_SET      4
-#define T_OK      5
-#define T_CANCEL      6
-#define T_BAD_NUMBER      7
-#define T_NUMBER_EXPECTED      8
-#define T_NUMBER_OUT_OF_RANGE      9
-#define T_BAD_STRING     10
-#define T_EMPTY_STRING_NOT_ALLOWED     11
-#define T_BAD_IP_ADDRESS     12
-#define T_INVALID_IP_ADDRESS_SYNTAX     13
-#define T_UNABLE_TO_USE_LOCAL_IP_ADDRESS     14
-#define T_CONFIG_ERROR     15
-#define T_UNABLE_TO_WRITE_TO_CONFIG_FILE     16
-#define T_HOME_DIRECTORY_INACCESSIBLE     17
-#define T_BOOKMARK_ERROR     18
-#define T_UNABLE_TO_WRITE_TO_BOOKMARK_FILE     19
-#define T_ABOUT     20
-#define T_LINKS__LYNX_LIKE     21
-#define T_VERSION     22
-#define T_VERSION_INFORMATION     23
-#define T_LINKS_VERSION     24
-#define T_OPERATING_SYSTEM_TYPE     25
-#define T_OPERATING_SYSTEM_VERSION     26
-#define T_COMPILER     27
-#define T_WORD_SIZE     28
-#define T_MEMORY     29
-#define T_FILE_SIZE     30
-#define T_DEBUGGING_LEVEL     31
-#define T_EVENT_HANDLER     32
-#define T_SELECT_SYSCALL     33
-#define T_dISABLED     34
-#define T_IPV6     35
-#define T_NOT_ENABLED_IN_SYSTEM     36
-#define T_LOCAL_NETWORK_ONLY     37
-#define T_UTF8_TERMINAL     38
-#define T_COMPRESSION_METHODS     39
-#define T_ENCRYPTION     40
-#define T_NO_CERTIFICATE_VERIFICATION     41
-#define T_GPM_MOUSE_DRIVER     42
-#define T_XTERM_FOR_OS2     43
-#define T_GRAPHICS_MODE     44
-#define T_IMAGE_LIBRARIES     45
-#define T_OPENMP     46
-#define T_NOT_USED_IN_TEXT_MODE     47
-#define T_DISABLED     48
-#define T_THREAD     49
-#define T_THREADS     50
-#define T_THREADS5     51
-#define T_CONFIGURATION_DIRECTORY     52
-#define T_NONE     53
-#define T_KEYS     54
-#define T_KEYS_DESC     55
-#define T_KEYS_BRAILLE_DESC     56
-#define T_COPYING     57
-#define T_COPYING_DESC     58
-#define T_RESOURCES     59
-#define T_MEMORY_CACHE     60
-#define T_DECOMPRESSED_CACHE     61
-#define T_FONT_CACHE     62
-#define T_IMAGE_CACHE     63
-#define T_FORMATTED_DOCUMENT_CACHE     64
-#define T_DNS_CACHE     65
-#define T_TLS_SESSION_CACHE     66
-#define T_HANDLES     67
-#define T_TIMERS     68
-#define T_WAITING     69
-#define T_CONNECTING     70
-#define T_tRANSFERRING     71
-#define T_KEEPALIVE     72
-#define T_BYTES     73
-#define T_LETTERS     74
-#define T_FILES     75
-#define T_LOCKED     76
-#define T_LOADING     77
-#define T_IMAGES     78
-#define T_DOCUMENTS     79
-#define T_SERVERS     80
-#define T_MEMORY_ALLOCATED     81
-#define T_BLOCKS_ALLOCATED     82
-#define T_MEMORY_REQUESTED     83
-#define T_BLOCKS_REQUESTED     84
-#define T_JS_MEMORY_ALLOCATED     85
-#define T_MEMORY_INFO     86
-#define T_NO_HISTORY     87
-#define T_NO_DOWNLOADS     88
-#define T_NO_FRAMES     89
-#define T_VT_100_FRAMES     90
-#define T_LINUX_OR_OS2_FRAMES     91
-#define T_KOI8R_FRAMES     92
-#define T_FREEBSD_FRAMES     93
-#define T_USE_11M     94
-#define T_RESTRICT_FRAMES_IN_CP850_852     95
-#define T_BLOCK_CURSOR     96
-#define T_COLOR     97
-#define T_BRAILLE_TERMINAL     98
-#define T_TERMINAL_OPTIONS     99
-#define T_SCREEN_MARGINS    100
-#define T_LEFT_MARGIN    101
-#define T_RIGHT_MARGIN    102
-#define T_TOP_MARGIN    103
-#define T_BOTTOM_MARGIN    104
-#define T_MARGINS_TOO_LARGE    105
-#define T_THE_ENTERED_VALUES_ARE_TOO_LARGE_FOR_THE_CURRENT_SCREEN    106
-#define T_NETWORK_OPTIONS    107
-#define T_IPV6_OPTIONS    108
-#define T_IPV6_DEFAULT    109
-#define T_IPV6_PREFER_IPV4    110
-#define T_IPV6_PREFER_IPV6    111
-#define T_IPV6_USE_ONLY_IPV4    112
-#define T_IPV6_USE_ONLY_IPV6    113
-#define T_PROXIES    114
-#define T_HTTP_PROXY__HOST_PORT    115
-#define T_FTP_PROXY__HOST_PORT    116
-#define T_HTTPS_PROXY__HOST_PORT    117
-#define T_SOCKS_4A_PROXY__USER_HOST_PORT    118
-#define T_APPEND_TEXT_TO_SOCKS_LOOKUPS    119
-#define T_ONLY_PROXIES    120
-#define T_NOPROXY_LIST    121
-#define T_SSL_OPTIONS    122
-#define T_ACCEPT_INVALID_CERTIFICATES    123
-#define T_WARN_ON_INVALID_CERTIFICATES    124
-#define T_REJECT_INVALID_CERTIFICATES    125
-#define T_USE_BUILT_IN_CERTIFICATES    126
-#define T_CLIENT_CERTIFICATE_KEY_FILE    127
-#define T_CLIENT_CERTIFICATE_FILE    128
-#define T_CLIENT_CERTIFICATE_KEY_PASSWORD    129
-#define T_BAD_FILE    130
-#define T_THE_FILE_DOES_NOT_EXIST    131
-#define T_THE_FILE_HAS_INVALID_FORMAT    132
-#define T_ERROR_INITIALIZING_BUILT_IN_CERTIFICATES    133
-#define T_FAILED    134
-#define T_CONNECTIONS    135
-#define T_MAX_CONNECTIONS    136
-#define T_MAX_CONNECTIONS_TO_ONE_HOST    137
-#define T_RETRIES    138
-#define T_RECEIVE_TIMEOUT_SEC    139
-#define T_TIMEOUT_WHEN_UNRESTARTABLE    140
-#define T_TIMEOUT_WHEN_TRYING_MULTIPLE_ADDRESSES    141
-#define T_BIND_TO_LOCAL_IP_ADDRESS    142
-#define T_BIND_TO_LOCAL_IPV6_ADDRESS    143
-#define T_ASYNC_DNS_LOOKUP    144
-#define T_SET_TIME_OF_DOWNLOADED_FILES    145
-#define T_CACHE_OPTIONS    146
-#define T_MEMORY_CACHE_SIZE__KB    147
-#define T_IMAGE_CACHE_SIZE__KB    148
-#define T_FONT_CACHE_SIZE__KB    149
-#define T_NUMBER_OF_FORMATTED_DOCUMENTS    150
-#define T_AGGRESSIVE_CACHE    151
-#define T_HTML_OPTIONS    152
-#define T_DISPLAY_TABLES    153
-#define T_DISPLAY_FRAMES    154
-#define T_BREAK_LONG_LINES    155
-#define T_DISPLAY_IMAGES    156
-#define T_DISPLAY_IMAGE_FILENAMES    157
-#define T_DISPLAY_LINKS_TO_IMAGES    158
-#define T_LINK_ORDER_BY_COLUMNS    159
-#define T_NUMBERED_LINKS    160
-#define T_AUTO_REFRESH    161
-#define T_TARGET_IN_NEW_WINDOW    162
-#define T_TEXT_MARGIN    163
-#define T_DEFAULT_CODEPAGE    164
-#define T_IGNORE_CHARSET_INFO_SENT_BY_SERVER    165
-#define T_TEXT_COLOR    166
-#define T_LINK_COLOR    167
-#define T_BACKGROUND_COLOR    168
-#define T_IGNORE_DOCUMENT_COLOR    169
-#define T_COLOR_0    170
-#define T_COLOR_1    171
-#define T_COLOR_2    172
-#define T_COLOR_3    173
-#define T_COLOR_4    174
-#define T_COLOR_5    175
-#define T_COLOR_6    176
-#define T_COLOR_7    177
-#define T_COLOR_8    178
-#define T_COLOR_9    179
-#define T_COLOR_10    180
-#define T_COLOR_11    181
-#define T_COLOR_12    182
-#define T_COLOR_13    183
-#define T_COLOR_14    184
-#define T_COLOR_15    185
-#define T_GOTO_URL    186
-#define T_GO_BACK    187
-#define T_GO_FORWARD    188
-#define T_HISTORY    189
-#define T_RELOAD    190
-#define T_NEW_WINDOW    191
-#define T_SAVE_AS    192
-#define T_SAVE_URL_AS    193
-#define T_SAVE_FORMATTED_DOCUMENT    194
-#define T_COPY_URL_LOCATION    195
-#define T_KILL_BACKGROUND_CONNECTIONS    196
-#define T_KILL_ALL_CONNECTIONS    197
-#define T_FLUSH_ALL_CACHES    198
-#define T_RESOURCE_INFO    199
-#define T_OS_SHELL    200
-#define T_EXIT    201
-#define T_SEARCH    202
-#define T_SEARCH_BACK    203
-#define T_FIND_NEXT    204
-#define T_FIND_PREVIOUS    205
-#define T_TOGGLE_HTML_PLAIN    206
-#define T_DOCUMENT_INFO    207
-#define T_FRAME_AT_FULL_SCREEN    208
-#define T_SAVE_HTML_OPTIONS    209
-#define T_CHARACTER_SET    210
-#define T_DEFAULT_CHARSET    211
-#define T_CACHE    212
-#define T_MAIL_AND_TELNEL    213
-#define T_MAIL_TELNET_AND_SHELL    214
-#define T_ASSOCIATIONS    215
-#define T_FILE_EXTENSIONS    216
-#define T_SAVE_OPTIONS    217
-#define T_FILE    218
-#define T_VIEW    219
-#define T_LINK    220
-#define T_DOWNLOADS    221
-#define T_WINDOWS    222
-#define T_SETUP    223
-#define T_HELP    224
-#define T_ENTER_URL    225
-#define T_SAVE_URL    226
-#define T_DOWNLOAD    227
-#define T_SAVE_TO_FILE    228
-#define T_SEARCH_FOR_TEXT    229
-#define T_PAGE_P    230
-#define T_PAGE_OF    231
-#define T_PAGE_CL    232
-#define T_FORMATTING_DOCUMENT    233
-#define T_SEARCHING    234
-#define T_WAITING_IN_QUEUE    235
-#define T_LOOKING_UP_HOST    236
-#define T_MAKING_CONNECTION    237
-#define T_MAKING_CONNECTION_TO_ANOTHER_ADDRESS    238
-#define T_SOCKS_NEGOTIATION    239
-#define T_SSL_NEGOTIATION    240
-#define T_REQUEST_SENT    241
-#define T_LOGGING_IN    242
-#define T_GETTING_HEADERS    243
-#define T_SERVER_IS_PROCESSING_REQUEST    244
-#define T_TRANSFERRING    245
-#define T_INTERRUPTED    246
-#define T_SOCKET_EXCEPTION    247
-#define T_INTERNAL_ERROR    248
-#define T_OUT_OF_MEMORY    249
-#define T_HOST_NOT_FOUND    250
-#define T_PROXY_NOT_FOUND    251
-#define T_ERROR_WRITING_TO_SOCKET    252
-#define T_ERROR_READING_FROM_SOCKET    253
-#define T_DATA_MODIFIED    254
-#define T_BAD_URL_SYNTAX    255
-#define T_BAD_PROXY_SYNTAX    256
-#define T_RECEIVE_TIMEOUT    257
-#define T_REQUEST_MUST_BE_RESTARTED    258
-#define T_CANT_GET_SOCKET_STATE    259
-#define T_CYCLIC_REDIRECT    260
-#define T_TOO_LARGE_FILE    261
-#define T_BAD_HTTP_RESPONSE    262
-#define T_HTTP_100    263
-#define T_NO_CONTENT    264
-#define T_HTTPS_FWD_ERROR    265
-#define T_INVALID_CERTIFICATE    266
-#define T_DOWNGRADED_METHOD    267
-#define T_INSECURE_CIPHER    268
-#define T_UNKNOWN_FILE_TYPE    269
-#define T_ERROR_OPENING_FILE    270
-#define T_BAD_FTP_RESPONSE    271
-#define T_FTP_SERVICE_UNAVAILABLE    272
-#define T_BAD_FTP_LOGIN    273
-#define T_FTP_PORT_COMMAND_FAILED    274
-#define T_FILE_NOT_FOUND    275
-#define T_FTP_FILE_ERROR    276
-#define T_SSL_ERROR    277
-#define T_NO_SSL    278
-#define T_BAD_SOCKS_VERSION    279
-#define T_SOCKS_REJECTED_OR_FAILED    280
-#define T_SOCKS_NO_IDENTD    281
-#define T_SOCKS_BAD_USERID    282
-#define T_SOCKS_UNKNOWN_ERROR    283
-#define T_NO_SMB_CLIENT    284
-#define T_BLOCKED_URL    285
-#define T_SMB_NOT_ALLOWED    286
-#define T_FILE_NOT_ALLOWED    287
-#define T_NO_PROXY    288
-#define T_UNKNOWN_ERROR    289
-#define T_RECEIVED    290
-#define T_OF    291
-#define T_AVG    292
-#define T_CUR    293
-#define T_AVERAGE_SPEED    294
-#define T_SPEED    295
-#define T_CURRENT_SPEED    296
-#define T_ELAPSED_TIME    297
-#define T_ESTIMATED_TIME    298
-#define T_BACKGROUND    299
-#define T_ABORT    300
-#define T_ABORT_AND_DELETE_FILE    301
-#define T_YES    302
-#define T_NO    303
-#define T_DIRECTORY    304
-#define T_FILE_ALREADY_EXISTS    305
-#define T_ALREADY_EXISTS_AS_DOWNLOAD    306
-#define T_ALREADY_EXISTS    307
-#define T_DO_YOU_WISH_TO_CONTINUE    308
-#define T_DO_YOU_WISH_TO_OVERWRITE    309
-#define T_CONTINUE    310
-#define T_OVERWRITE    311
-#define T_RENAME    312
-#define T_DOWNLOAD_ERROR    313
-#define T_COULD_NOT_WRITE_TO_FILE    314
-#define T_ERROR_DOWNLOADING    315
-#define T_ERROR_LOADING    316
-#define T_COULD_NOT_CREATE_FILE    317
-#define T_COULD_NOT_CREATE_TEMPORARY_FILE    318
-#define T_ERROR_CALLING_LSEEK_ON_FILE    319
-#define T_TOO_LARGE_FILE_SEQUENCE    320
-#define T_UNKNOWN_TYPE    321
-#define T_CONTENT_TYPE_IS    322
-#define T_DO_YOU_WANT_TO_OPEN_SAVE_OR_DISPLAY_THIS_FILE    323
-#define T_DO_YOU_WANT_TO_OPEN_OR_DISPLAY_THIS_FILE    324
-#define T_DO_YOU_WANT_TO_SAVE_OR_DISLPAY_THIS_FILE    325
-#define T_SAVE    326
-#define T_DISPLAY    327
-#define T_WHAT_TO_DO    328
-#define T_DO_YOU_WANT_TO_OPEN_FILE_WITH    329
-#define T_SAVE_IT_OR_DISPLAY_IT    330
-#define T_OPEN    331
-#define T_OPEN_WITH    332
-#define T_DO_YOU_WANT_TO_FOLLOW_REDIRECT_AND_POST_FORM_DATA_TO_URL    333
-#define T_DO_YOU_WANT_TO_POST_FORM_DATA_TO_URL    334
-#define T_DO_YOU_WANT_TO_REPOST_FORM_DATA_TO_URL    335
-#define T_WARNING    336
-#define T_ERROR    337
-#define T_WELCOME    338
-#define T_WELCOME_TO_LINKS    339
-#define T_BASIC_HELP    340
-#define T_LABEL    341
-#define T_CONTENT_TYPES    342
-#define T_PROGRAM__IS_REPLACED_WITH_FILE_NAME    343
-#define T_BLOCK_TERMINAL_WHILE_PROGRAM_RUNNING    344
-#define T_RUN_ON_TERMINAL    345
-#define T_RUN_IN_XWINDOW    346
-#define T_ASK_BEFORE_OPENING    347
-#define T_ACCEPT_HTTP    348
-#define T_ACCEPT_FTP    349
-#define T_DELETE_ASSOCIATION    350
-#define T_ASSOCIATION    351
-#define T_EXTENSION_S    352
-#define T_CONTENT_TYPE    353
-#define T_DELETE_EXTENSION    354
-#define T_EXTENSION    355
-#define T_eXTENSION    356
-#define T_ERROR_WHILE_POSTING_FORM    357
-#define T_COULD_NOT_GET_FILE    358
-#define T_READING_FILES_IS_NOT_ALLOWED    359
-#define T_NO_PREVIOUS_SEARCH    360
-#define T_SEARCH_STRING_NOT_FOUND    361
-#define T_SAVE_ERROR    362
-#define T_ERROR_WRITING_TO_FILE    363
-#define T_DISPLAY_USEMAP    364
-#define T_FOLLOW_LINK    365
-#define T_OPEN_IN_NEW_WINDOW    366
-#define T_DOWNLOAD_LINK    367
-#define T_RESET_FORM    368
-#define T_SUBMIT_FORM    369
-#define T_SUBMIT_FORM_AND_OPEN_IN_NEW_WINDOW    370
-#define T_SUBMIT_FORM_AND_DOWNLOAD    371
-#define T_VIEW_IMAGE    372
-#define T_DOWNLOAD_IMAGE    373
-#define T_SCALE_IMAGE_TO_FULL_SCREEN    374
-#define T_NO_LINK_SELECTED    375
-#define T_IMAGE    376
-#define T_USEMAP    377
-#define T_XTERM    378
-#define T_TWTERM    379
-#define T_SCREEN    380
-#define T_WINDOW    381
-#define T_FULL_SCREEN    382
-#define T_BEOS_TERMINAL    383
-#define T_UNABLE_TO_OPEN_NEW_WINDOW    384
-#define T_JAVASCRIPT    385
-#define T_SUBMIT_FORM_TO    386
-#define T_POST_FORM_TO    387
-#define T_RADIO_BUTTON    388
-#define T_CHECKBOX    389
-#define T_SELECT_FIELD    390
-#define T_TEXT_FIELD    391
-#define T_TEXT_AREA    392
-#define T_FILE_UPLOAD    393
-#define T_PASSWORD_FIELD    394
-#define T_BUTTON    395
-#define T_NAME    396
-#define T_VALUE    397
-#define T_HIT_ENTER_TO    398
-#define T_SUBMIT_TO    399
-#define T_POST_TO    400
-#define T_INFO    401
-#define T_HEADER_INFO    402
-#define T_YOU_ARE_NOWHERE    403
-#define T_NO_HEADER    404
-#define T_URL    405
-#define T_IP_ADDRESS    406
-#define T_IP_ADDRESSES    407
-#define T_SIZE    408
-#define T_COMPRESSED_WITH    409
-#define T_INCOMPLETE    410
-#define T_CODEPAGE    411
-#define T_ASSUMED    412
-#define T_IGNORING_SERVER_SETTING    413
-#define T_SERVER    414
-#define T_DATE    415
-#define T_LAST_MODIFIED    416
-#define T_SSL_CIPHER    417
-#define T_LANGUAGE    418
-#define T_DEFAULT_LANG    419
-#define T_GO_TO_LINK    420
-#define T_ENTER_LINK_NUMBER    421
-#define T_RESIZE_TERMINAL    422
-#define T_COLUMNS    423
-#define T_ROWS    424
-#define T_GOTO    425
-#define T_CLOSE    426
-#define T_FOLDER    427
-#define T_fOLDER    428
-#define T_ADD    429
-#define T_DELETE    430
-#define T_EDIT    431
-#define T_MOVE    432
-#define T_NO_ITEMS_SELECTED    433
-#define T_UNSELECT_ALL    434
-#define T_BOOKMARKS    435
-#define T_BOOKMARK    436
-#define T_ADD_BOOKMARK    437
-#define T_ADD_ASSOCIATION    438
-#define T_ADD_EXTENSION    439
-#define T_ADD_FOLDER    440
-#define T_BOOKMARK_TITLE    441
-#define T_EDIT_BOOKMARK    442
-#define T_EDIT_ASSOCIATION    443
-#define T_EDIT_EXTENSION    444
-#define T_DELETE_BOOKMARK    445
-#define T_EDIT_FOLDER    446
-#define T_DELETE_FOLDER    447
-#define T_NOT_EMPTY_SURE_DELETE    448
-#define T_BOOKMARK_MANAGER    449
-#define T_ASSOCIATIONS_MANAGER    450
-#define T_EXTENSIONS_MANAGER    451
-#define T_url    452
-#define T_NNAME    453
-#define T_EXIT_LINKS    454
-#define T_DO_YOU_REALLY_WANT_TO_CLOSE_WINDOW    455
-#define T_DO_YOU_REALLY_WANT_TO_EXIT_LINKS    456
-#define T_DO_YOU_REALLY_WANT_TO_EXIT_LINKS_AND_TERMINATE_ALL_DOWNLOADS    457
-#define T_HTTP_OPTIONS    458
-#define T_FTP_OPTIONS    459
-#define T_SMB_OPTIONS    460
-#define T_HTTP_BUG_WORKAROUNDS    461
-#define T_USE_HTTP_10    462
-#define T_ALLOW_SERVER_BLACKLIST    463
-#define T_BROKEN_302_REDIRECT    464
-#define T_NO_KEEPALIVE_AFTER_POST_REQUEST    465
-#define T_DO_NOT_SEND_ACCEPT_CHARSET    466
-#define T_DO_NOT_ADVERTISE_COMPRESSION_SUPPORT    467
-#define T_RETRY_ON_INTERNAL_ERRORS    468
-#define T_HEADER_OPTIONS    469
-#define T_HTTP_HEADER_OPTIONS    470
-#define T_FAKE_FIREFOX    471
-#define T_DO_NOT_TRACK    472
-#define T_REFERER_NONE    473
-#define T_REFERER_SAME_URL    474
-#define T_REFERER_FAKE    475
-#define T_REFERER_REAL_SAME_SERVER    476
-#define T_REFERER_REAL    477
-#define T_FAKE_REFERER    478
-#define T_FAKE_USERAGENT    479
-#define T_EXTRA_HEADER    480
-#define T_PASSWORD_FOR_ANONYMOUS_LOGIN    481
-#define T_USE_PASSIVE_FTP    482
-#define T_USE_EPRT_EPSV    483
-#define T_USE_FAST_FTP    484
-#define T_SET_TYPE_OF_SERVICE    485
-#define T_ALLOW_HYPERLINKS_TO_SMB    486
-#define T_MANUAL    487
-#define T_HOMEPAGE    488
-#define T_CALIBRATION    489
-#define T_MAILTO_PROG    490
-#define T_SHELL_PROG    491
-#define T_TELNET_PROG    492
-#define T_MAGNET_PROG    493
-#define T_TN3270_PROG    494
-#define T_MMS_PROG    495
-#define T_MAIL_AND_TELNET_PROGRAMS    496
-#define T_MAIL_TELNET_AND_SHELL_PROGRAMS    497
-#define T_NO_PROGRAM    498
-#define T_NO_PROGRAM_SPECIFIED_FOR    499
-#define T_MAIL    500
-#define T_TELNET    501
-#define T_MAGNET    502
-#define T_TN3270    503
-#define T_MMS    504
-#define T_BAD_MAILTO_URL    505
-#define T_BAD_TELNET_URL    506
-#define T_BAD_TN3270_URL    507
-#define T_MMS_URL_CONTAINS_INACCEPTABLE_CHARACTERS    508
-#define T_AUTHORIZATION_REQUIRED    509
-#define T_PROXY_AUTHORIZATION_REQUIRED    510
-#define T_USERID    511
-#define T_PASSWORD    512
-#define T_ENTER_USERNAME    513
-#define T_AT    514
-#define T_THE_SERVER_    515
-#define T_DOESNT_HAVE_A_VALID_CERTIFICATE    516
-#define T_USES_DOWNGRADED_METHOD    517
-#define T_USES_INSECURE_CIPHER    518
-#define T_WAITING_FOR_REDIRECT_CONFIRMATION    519
-#define T_DECOMPRESSION_ERROR    520
-#define T_ERROR_DECOMPRESSING_    521
-#define T__wITH_    522
-#define T_COMPRESSED_ERROR    523
-#define T_UNKNOWN_COMPRESSION_METHOD    524
-#define T_SURE_DELETE    525
-#define T_BOOKMARKS_ALREADY_IN_USE    526
-#define T_ASSOCIATIONS_ALREADY_IN_USE    527
-#define T_EXTENSIONS_ALREADY_IN_USE    528
-#define T_VIDEO_OPTIONS    529
-#define T_VIDEO_OPTIONS_TEXT    530
-#define T_RED_DISPLAY_GAMMA    531
-#define T_GREEN_DISPLAY_GAMMA    532
-#define T_BLUE_DISPLAY_GAMMA    533
-#define T_USER_GAMMA    534
-#define T_ASPECT_RATIO    535
-#define T_DITHER_LETTERS    536
-#define T_DITHER_IMAGES    537
-#define T_8_BIT_GAMMA_CORRECTION    538
-#define T_16_BIT_GAMMA_CORRECTION    539
-#define T_AUTO_GAMMA_CORRECTION    540
-#define T_OVERWRITE_SCREEN_INSTEAD_OF_SCROLLING_IT    541
-#define T_ALERT    542
-#define T_QUESTION    543
-#define T_KILL_SCRIPT    544
-#define T_KILL_ALL_SCRIPTS    545
-#define T_SCRIPT_KILLED_BY_USER    546
-#define T_SCRIPT_TRYING_TO_CLOSE_WINDOW    547
-#define T_ENTER_STRING    548
-#define T_JAVASCRIPT_OPTIONS    549
-#define T_ENABLE_JAVASCRIPT    550
-#define T_VERBOSE_JS_ERRORS    551
-#define T_VERBOSE_JS_WARNINGS    552
-#define T_MISCELANEOUS_OPTIONS    553
-#define T_JAVASCRIPT_ERROR    554
-#define T_JAVASCRIPT_WARNING    555
-#define T_DISMISS    556
-#define T_MENU_FONT_SIZE    557
-#define T_USER_FONT_SIZE    558
-#define T_TURN_OFF_WARNINGS    559
-#define T_BOOKMARKS_ENCODING    560
-#define T_JS_IS_ATTEMPTING_TO_GO_TO_URL    561
-#define T_JS_IS_ATTEMPTING_TO_OPEN_NEW_WINDOW_WITH_URL    562
-#define T_JS_IS_ATTEMPTING_TO_GO_INTO_HISTORY    563
-#define T_TO_URL    564
-#define T_GOTO_HISTORY    565
-#define T_ALLOW    566
-#define T_REJECT    567
-#define T_ENABLE_ALL_CONVERSIONS    568
-#define T_ENABLE_GLOBAL_NAME_RESOLUTION    569
-#define T_MANUAL_JS_CONTROL    570
-#define T_JS_RECURSION_DEPTH    571
-#define T_MENU_BACKGROUND_COLOR    572
-#define T_MENU_FOREGROUND_COLOR    573
-#define T_SCROLL_BAR_BAR_COLOR    574
-#define T_SCROLL_BAR_AREA_COLOR    575
-#define T_SCROLL_BAR_FRAME_COLOR    576
-#define T_BOOKMARKS_FILE    577
-#define T_SAVE_URL_HISTORY_ON_EXIT    578
-#define T_ENTER_COLORS_AS_RGB_TRIPLETS    579
-#define T_JS_MEMORY_LIMIT_KB    580
-#define T_SCALE_ALL_IMAGES_BY    581
-#define T_PORN_ENABLE    582
-#define T_DISPLAY_OPTIMIZATION_CRT    583
-#define T_DISPLAY_OPTIMIZATION_LCD_RGB    584
-#define T_DISPLAY_OPTIMIZATION_LCD_BGR    585
-#define T_KEYBOARD_CODEPAGE    586
-#define T_COPY_LINK_LOCATION    587
-#define T_BLOCK_URL    588
-#define T_BLOCK_LIST    589
-#define T_BLOCKED_IMAGE    590
-#define T_BLOCK_LIST_IN_USE    591
-#define T_BLOCK_LIST_MANAGER    592
-#define T_BLOCK_ADD    593
-#define T_BLOCK_EDIT    594
-#define T_BLOCK_DELETE    595
-#define T_HK_GOTO_URL    596
-#define T_HK_GO_BACK    597
-#define T_HK_GO_FORWARD    598
-#define T_HK_HISTORY    599
-#define T_HK_RELOAD    600
-#define T_HK_BOOKMARKS    601
-#define T_HK_NEW_WINDOW    602
-#define T_HK_SAVE_AS    603
-#define T_HK_SAVE_URL_AS    604
-#define T_HK_SAVE_FORMATTED_DOCUMENT    605
-#define T_HK_COPY_URL_LOCATION    606
-#define T_HK_KILL_BACKGROUND_CONNECTIONS    607
-#define T_HK_KILL_ALL_CONNECTIONS    608
-#define T_HK_FLUSH_ALL_CACHES    609
-#define T_HK_RESOURCE_INFO    610
-#define T_HK_MEMORY_INFO    611
-#define T_HK_OS_SHELL    612
-#define T_HK_RESIZE_TERMINAL    613
-#define T_HK_EXIT    614
-#define T_HK_SEARCH    615
-#define T_HK_SEARCH_BACK    616
-#define T_HK_FIND_NEXT    617
-#define T_HK_FIND_PREVIOUS    618
-#define T_HK_TOGGLE_HTML_PLAIN    619
-#define T_HK_DOCUMENT_INFO    620
-#define T_HK_HEADER_INFO    621
-#define T_HK_FRAME_AT_FULL_SCREEN    622
-#define T_HK_HTML_OPTIONS    623
-#define T_HK_COLOR    624
-#define T_HK_SAVE_HTML_OPTIONS    625
-#define T_HK_LANGUAGE    626
-#define T_HK_CHARACTER_SET    627
-#define T_HK_TERMINAL_OPTIONS    628
-#define T_HK_SCREEN_MARGINS    629
-#define T_HK_VIDEO_OPTIONS    630
-#define T_HK_NETWORK_OPTIONS    631
-#define T_HK_CONNECTIONS    632
-#define T_HK_IPV6_OPTIONS    633
-#define T_HK_PROXIES    634
-#define T_HK_SSL_OPTIONS    635
-#define T_HK_HTTP_OPTIONS    636
-#define T_HK_FTP_OPTIONS    637
-#define T_HK_SMB_OPTIONS    638
-#define T_HK_JAVASCRIPT_OPTIONS    639
-#define T_HK_MISCELANEOUS_OPTIONS    640
-#define T_HK_CACHE    641
-#define T_HK_MAIL_AND_TELNEL    642
-#define T_HK_ASSOCIATIONS    643
-#define T_HK_FILE_EXTENSIONS    644
-#define T_HK_BLOCK_LIST    645
-#define T_HK_SAVE_OPTIONS    646
-#define T_HK_ABOUT    647
-#define T_HK_KEYS    648
-#define T_HK_COPYING    649
-#define T_HK_MANUAL    650
-#define T_HK_HOMEPAGE    651
-#define T_HK_CALIBRATION    652
-#define T_HK_FILE    653
-#define T_HK_VIEW    654
-#define T_HK_LINK    655
-#define T_HK_DOWNLOADS    656
-#define T_HK_WINDOWS    657
-#define T_HK_SETUP    658
-#define T_HK_HELP    659
-#define T_HK_DISPLAY_USEMAP    660
-#define T_HK_FOLLOW_LINK    661
-#define T_HK_OPEN_IN_NEW_WINDOW    662
-#define T_HK_DOWNLOAD_LINK    663
-#define T_HK_RESET_FORM    664
-#define T_HK_SUBMIT_FORM    665
-#define T_HK_SUBMIT_FORM_AND_OPEN_IN_NEW_WINDOW    666
-#define T_HK_SUBMIT_FORM_AND_DOWNLOAD    667
-#define T_HK_VIEW_IMAGE    668
-#define T_HK_DOWNLOAD_IMAGE    669
-#define T_HK_SCALE_IMAGE_TO_FULL_SCREEN    670
-#define T_HK_COPY_LINK_LOCATION    671
-#define T_HK_BLOCK_URL    672
-#define T_HK_XTERM    673
-#define T_HK_TWTERM    674
-#define T_HK_SCREEN    675
-#define T_HK_WINDOW    676
-#define T_HK_FULL_SCREEN    677
-#define T_HK_BEOS_TERMINAL    678
-#define T_URL_MANUAL    679
-#define T_URL_HOMEPAGE    680
-#define T_URL_CALIBRATION    681
-#define T__N_TEXTS    682
+#define T__CHAR_SET      0
+#define T__LANGUAGE      1
+#define T__ACCEPT_LANGUAGE      2
+#define T__DEFAULT_CHAR_SET      3
+#define T_OK      4
+#define T_CANCEL      5
+#define T_BAD_NUMBER      6
+#define T_NUMBER_EXPECTED      7
+#define T_NUMBER_OUT_OF_RANGE      8
+#define T_BAD_STRING      9
+#define T_EMPTY_STRING_NOT_ALLOWED     10
+#define T_BAD_IP_ADDRESS     11
+#define T_INVALID_IP_ADDRESS_SYNTAX     12
+#define T_UNABLE_TO_USE_LOCAL_IP_ADDRESS     13
+#define T_CONFIG_ERROR     14
+#define T_UNABLE_TO_WRITE_TO_CONFIG_FILE     15
+#define T_HOME_DIRECTORY_INACCESSIBLE     16
+#define T_BOOKMARK_ERROR     17
+#define T_UNABLE_TO_WRITE_TO_BOOKMARK_FILE     18
+#define T_ABOUT     19
+#define T_LINKS__LYNX_LIKE     20
+#define T_VERSION     21
+#define T_VERSION_INFORMATION     22
+#define T_LINKS_VERSION     23
+#define T_OPERATING_SYSTEM_TYPE     24
+#define T_OPERATING_SYSTEM_VERSION     25
+#define T_COMPILER     26
+#define T_WORD_SIZE     27
+#define T_MEMORY     28
+#define T_FILE_SIZE     29
+#define T_DEBUGGING_LEVEL     30
+#define T_EVENT_HANDLER     31
+#define T_SELECT_SYSCALL     32
+#define T_dISABLED     33
+#define T_IPV6     34
+#define T_NOT_ENABLED_IN_SYSTEM     35
+#define T_LOCAL_NETWORK_ONLY     36
+#define T_UTF8_TERMINAL     37
+#define T_COMPRESSION_METHODS     38
+#define T_ENCRYPTION     39
+#define T_NO_CERTIFICATE_VERIFICATION     40
+#define T_GPM_MOUSE_DRIVER     41
+#define T_XTERM_FOR_OS2     42
+#define T_GRAPHICS_MODE     43
+#define T_IMAGE_LIBRARIES     44
+#define T_OPENMP     45
+#define T_NOT_USED_IN_TEXT_MODE     46
+#define T_DISABLED     47
+#define T_THREAD     48
+#define T_THREADS     49
+#define T_THREADS5     50
+#define T_CONFIGURATION_DIRECTORY     51
+#define T_NONE     52
+#define T_KEYS     53
+#define T_KEYS_DESC     54
+#define T_KEYS_BRAILLE_DESC     55
+#define T_COPYING     56
+#define T_COPYING_DESC     57
+#define T_RESOURCES     58
+#define T_MEMORY_CACHE     59
+#define T_DECOMPRESSED_CACHE     60
+#define T_FONT_CACHE     61
+#define T_IMAGE_CACHE     62
+#define T_FORMATTED_DOCUMENT_CACHE     63
+#define T_DNS_CACHE     64
+#define T_TLS_SESSION_CACHE     65
+#define T_HANDLES     66
+#define T_TIMERS     67
+#define T_WAITING     68
+#define T_CONNECTING     69
+#define T_tRANSFERRING     70
+#define T_KEEPALIVE     71
+#define T_BYTES     72
+#define T_LETTERS     73
+#define T_FILES     74
+#define T_LOCKED     75
+#define T_LOADING     76
+#define T_IMAGES     77
+#define T_DOCUMENTS     78
+#define T_SERVERS     79
+#define T_MEMORY_ALLOCATED     80
+#define T_BLOCKS_ALLOCATED     81
+#define T_MEMORY_LARGE_BLOCKS     82
+#define T_BLOCKS_LARGE_BLOCKS     83
+#define T_MEMORY_REQUESTED     84
+#define T_BLOCKS_REQUESTED     85
+#define T_JS_MEMORY_ALLOCATED     86
+#define T_MEMORY_INFO     87
+#define T_NO_HISTORY     88
+#define T_NO_DOWNLOADS     89
+#define T_NO_FRAMES     90
+#define T_VT_100_FRAMES     91
+#define T_LINUX_OR_OS2_FRAMES     92
+#define T_KOI8R_FRAMES     93
+#define T_FREEBSD_FRAMES     94
+#define T_USE_11M     95
+#define T_RESTRICT_FRAMES_IN_CP850_852     96
+#define T_BLOCK_CURSOR     97
+#define T_COLOR     98
+#define T_BRAILLE_TERMINAL     99
+#define T_TERMINAL_OPTIONS    100
+#define T_SCREEN_MARGINS    101
+#define T_LEFT_MARGIN    102
+#define T_RIGHT_MARGIN    103
+#define T_TOP_MARGIN    104
+#define T_BOTTOM_MARGIN    105
+#define T_MARGINS_TOO_LARGE    106
+#define T_THE_ENTERED_VALUES_ARE_TOO_LARGE_FOR_THE_CURRENT_SCREEN    107
+#define T_NETWORK_OPTIONS    108
+#define T_IPV6_OPTIONS    109
+#define T_IPV6_DEFAULT    110
+#define T_IPV6_PREFER_IPV4    111
+#define T_IPV6_PREFER_IPV6    112
+#define T_IPV6_USE_ONLY_IPV4    113
+#define T_IPV6_USE_ONLY_IPV6    114
+#define T_PROXIES    115
+#define T_HTTP_PROXY__HOST_PORT    116
+#define T_FTP_PROXY__HOST_PORT    117
+#define T_HTTPS_PROXY__HOST_PORT    118
+#define T_SOCKS_4A_PROXY__USER_HOST_PORT    119
+#define T_APPEND_TEXT_TO_SOCKS_LOOKUPS    120
+#define T_ONLY_PROXIES    121
+#define T_NOPROXY_LIST    122
+#define T_SSL_OPTIONS    123
+#define T_ACCEPT_INVALID_CERTIFICATES    124
+#define T_WARN_ON_INVALID_CERTIFICATES    125
+#define T_REJECT_INVALID_CERTIFICATES    126
+#define T_USE_BUILT_IN_CERTIFICATES    127
+#define T_CLIENT_CERTIFICATE_KEY_FILE    128
+#define T_CLIENT_CERTIFICATE_FILE    129
+#define T_CLIENT_CERTIFICATE_KEY_PASSWORD    130
+#define T_BAD_FILE    131
+#define T_THE_FILE_DOES_NOT_EXIST    132
+#define T_THE_FILE_HAS_INVALID_FORMAT    133
+#define T_ERROR_INITIALIZING_BUILT_IN_CERTIFICATES    134
+#define T_FAILED    135
+#define T_CONNECTIONS    136
+#define T_MAX_CONNECTIONS    137
+#define T_MAX_CONNECTIONS_TO_ONE_HOST    138
+#define T_RETRIES    139
+#define T_RECEIVE_TIMEOUT_SEC    140
+#define T_TIMEOUT_WHEN_UNRESTARTABLE    141
+#define T_TIMEOUT_WHEN_TRYING_MULTIPLE_ADDRESSES    142
+#define T_BIND_TO_LOCAL_IP_ADDRESS    143
+#define T_BIND_TO_LOCAL_IPV6_ADDRESS    144
+#define T_ASYNC_DNS_LOOKUP    145
+#define T_SET_TIME_OF_DOWNLOADED_FILES    146
+#define T_CACHE_OPTIONS    147
+#define T_MEMORY_CACHE_SIZE__KB    148
+#define T_IMAGE_CACHE_SIZE__KB    149
+#define T_FONT_CACHE_SIZE__KB    150
+#define T_NUMBER_OF_FORMATTED_DOCUMENTS    151
+#define T_AGGRESSIVE_CACHE    152
+#define T_HTML_OPTIONS    153
+#define T_DISPLAY_TABLES    154
+#define T_DISPLAY_FRAMES    155
+#define T_BREAK_LONG_LINES    156
+#define T_DISPLAY_IMAGES    157
+#define T_DISPLAY_IMAGE_FILENAMES    158
+#define T_DISPLAY_LINKS_TO_IMAGES    159
+#define T_LINK_ORDER_BY_COLUMNS    160
+#define T_NUMBERED_LINKS    161
+#define T_AUTO_REFRESH    162
+#define T_TARGET_IN_NEW_WINDOW    163
+#define T_TEXT_MARGIN    164
+#define T_DEFAULT_CODEPAGE    165
+#define T_IGNORE_CHARSET_INFO_SENT_BY_SERVER    166
+#define T_TEXT_COLOR    167
+#define T_LINK_COLOR    168
+#define T_BACKGROUND_COLOR    169
+#define T_IGNORE_DOCUMENT_COLOR    170
+#define T_COLOR_0    171
+#define T_COLOR_1    172
+#define T_COLOR_2    173
+#define T_COLOR_3    174
+#define T_COLOR_4    175
+#define T_COLOR_5    176
+#define T_COLOR_6    177
+#define T_COLOR_7    178
+#define T_COLOR_8    179
+#define T_COLOR_9    180
+#define T_COLOR_10    181
+#define T_COLOR_11    182
+#define T_COLOR_12    183
+#define T_COLOR_13    184
+#define T_COLOR_14    185
+#define T_COLOR_15    186
+#define T_GOTO_URL    187
+#define T_GO_BACK    188
+#define T_GO_FORWARD    189
+#define T_HISTORY    190
+#define T_RELOAD    191
+#define T_NEW_WINDOW    192
+#define T_SAVE_AS    193
+#define T_SAVE_URL_AS    194
+#define T_SAVE_FORMATTED_DOCUMENT    195
+#define T_COPY_URL_LOCATION    196
+#define T_KILL_BACKGROUND_CONNECTIONS    197
+#define T_KILL_ALL_CONNECTIONS    198
+#define T_FLUSH_ALL_CACHES    199
+#define T_RESOURCE_INFO    200
+#define T_OS_SHELL    201
+#define T_EXIT    202
+#define T_SEARCH    203
+#define T_SEARCH_BACK    204
+#define T_FIND_NEXT    205
+#define T_FIND_PREVIOUS    206
+#define T_TOGGLE_HTML_PLAIN    207
+#define T_DOCUMENT_INFO    208
+#define T_FRAME_AT_FULL_SCREEN    209
+#define T_SAVE_HTML_OPTIONS    210
+#define T_CHARACTER_SET    211
+#define T_DEFAULT_CHARSET    212
+#define T_CACHE    213
+#define T_MAIL_AND_TELNEL    214
+#define T_MAIL_TELNET_AND_SHELL    215
+#define T_ASSOCIATIONS    216
+#define T_FILE_EXTENSIONS    217
+#define T_SAVE_OPTIONS    218
+#define T_FILE    219
+#define T_VIEW    220
+#define T_LINK    221
+#define T_DOWNLOADS    222
+#define T_WINDOWS    223
+#define T_SETUP    224
+#define T_HELP    225
+#define T_ENTER_URL    226
+#define T_SAVE_URL    227
+#define T_DOWNLOAD    228
+#define T_SAVE_TO_FILE    229
+#define T_SEARCH_FOR_TEXT    230
+#define T_PAGE_P    231
+#define T_PAGE_OF    232
+#define T_PAGE_CL    233
+#define T_FORMATTING_DOCUMENT    234
+#define T_SEARCHING    235
+#define T_WAITING_IN_QUEUE    236
+#define T_LOOKING_UP_HOST    237
+#define T_MAKING_CONNECTION    238
+#define T_MAKING_CONNECTION_TO_ANOTHER_ADDRESS    239
+#define T_SOCKS_NEGOTIATION    240
+#define T_SSL_NEGOTIATION    241
+#define T_REQUEST_SENT    242
+#define T_LOGGING_IN    243
+#define T_GETTING_HEADERS    244
+#define T_SERVER_IS_PROCESSING_REQUEST    245
+#define T_TRANSFERRING    246
+#define T_INTERRUPTED    247
+#define T_SOCKET_EXCEPTION    248
+#define T_INTERNAL_ERROR    249
+#define T_OUT_OF_MEMORY    250
+#define T_HOST_NOT_FOUND    251
+#define T_PROXY_NOT_FOUND    252
+#define T_ERROR_WRITING_TO_SOCKET    253
+#define T_ERROR_READING_FROM_SOCKET    254
+#define T_DATA_MODIFIED    255
+#define T_BAD_URL_SYNTAX    256
+#define T_BAD_PROXY_SYNTAX    257
+#define T_RECEIVE_TIMEOUT    258
+#define T_REQUEST_MUST_BE_RESTARTED    259
+#define T_CANT_GET_SOCKET_STATE    260
+#define T_CYCLIC_REDIRECT    261
+#define T_TOO_LARGE_FILE    262
+#define T_BAD_HTTP_RESPONSE    263
+#define T_HTTP_100    264
+#define T_NO_CONTENT    265
+#define T_HTTPS_FWD_ERROR    266
+#define T_INVALID_CERTIFICATE    267
+#define T_DOWNGRADED_METHOD    268
+#define T_INSECURE_CIPHER    269
+#define T_UNKNOWN_FILE_TYPE    270
+#define T_ERROR_OPENING_FILE    271
+#define T_BAD_FTP_RESPONSE    272
+#define T_FTP_SERVICE_UNAVAILABLE    273
+#define T_BAD_FTP_LOGIN    274
+#define T_FTP_PORT_COMMAND_FAILED    275
+#define T_FILE_NOT_FOUND    276
+#define T_FTP_FILE_ERROR    277
+#define T_SSL_ERROR    278
+#define T_NO_SSL    279
+#define T_BAD_SOCKS_VERSION    280
+#define T_SOCKS_REJECTED_OR_FAILED    281
+#define T_SOCKS_NO_IDENTD    282
+#define T_SOCKS_BAD_USERID    283
+#define T_SOCKS_UNKNOWN_ERROR    284
+#define T_NO_SMB_CLIENT    285
+#define T_BLOCKED_URL    286
+#define T_SMB_NOT_ALLOWED    287
+#define T_FILE_NOT_ALLOWED    288
+#define T_NO_PROXY    289
+#define T_UNKNOWN_ERROR    290
+#define T_RECEIVED    291
+#define T_OF    292
+#define T_AVG    293
+#define T_CUR    294
+#define T_AVERAGE_SPEED    295
+#define T_SPEED    296
+#define T_CURRENT_SPEED    297
+#define T_ELAPSED_TIME    298
+#define T_ESTIMATED_TIME    299
+#define T_BACKGROUND    300
+#define T_ABORT    301
+#define T_ABORT_AND_DELETE_FILE    302
+#define T_YES    303
+#define T_NO    304
+#define T_DIRECTORY    305
+#define T_FILE_ALREADY_EXISTS    306
+#define T_ALREADY_EXISTS_AS_DOWNLOAD    307
+#define T_ALREADY_EXISTS    308
+#define T_DO_YOU_WISH_TO_CONTINUE    309
+#define T_DO_YOU_WISH_TO_OVERWRITE    310
+#define T_CONTINUE    311
+#define T_OVERWRITE    312
+#define T_RENAME    313
+#define T_DOWNLOAD_ERROR    314
+#define T_COULD_NOT_WRITE_TO_FILE    315
+#define T_ERROR_DOWNLOADING    316
+#define T_ERROR_LOADING    317
+#define T_COULD_NOT_CREATE_FILE    318
+#define T_COULD_NOT_CREATE_TEMPORARY_FILE    319
+#define T_ERROR_CALLING_LSEEK_ON_FILE    320
+#define T_TOO_LARGE_FILE_SEQUENCE    321
+#define T_UNKNOWN_TYPE    322
+#define T_CONTENT_TYPE_IS    323
+#define T_DO_YOU_WANT_TO_OPEN_SAVE_OR_DISPLAY_THIS_FILE    324
+#define T_DO_YOU_WANT_TO_OPEN_OR_DISPLAY_THIS_FILE    325
+#define T_DO_YOU_WANT_TO_SAVE_OR_DISLPAY_THIS_FILE    326
+#define T_SAVE    327
+#define T_DISPLAY    328
+#define T_WHAT_TO_DO    329
+#define T_DO_YOU_WANT_TO_OPEN_FILE_WITH    330
+#define T_SAVE_IT_OR_DISPLAY_IT    331
+#define T_OPEN    332
+#define T_OPEN_WITH    333
+#define T_DO_YOU_WANT_TO_FOLLOW_REDIRECT_AND_POST_FORM_DATA_TO_URL    334
+#define T_DO_YOU_WANT_TO_POST_FORM_DATA_TO_URL    335
+#define T_DO_YOU_WANT_TO_REPOST_FORM_DATA_TO_URL    336
+#define T_WARNING    337
+#define T_ERROR    338
+#define T_WELCOME    339
+#define T_WELCOME_TO_LINKS    340
+#define T_BASIC_HELP    341
+#define T_LABEL    342
+#define T_CONTENT_TYPES    343
+#define T_PROGRAM__IS_REPLACED_WITH_FILE_NAME    344
+#define T_BLOCK_TERMINAL_WHILE_PROGRAM_RUNNING    345
+#define T_RUN_ON_TERMINAL    346
+#define T_RUN_IN_XWINDOW    347
+#define T_ASK_BEFORE_OPENING    348
+#define T_ACCEPT_HTTP    349
+#define T_ACCEPT_FTP    350
+#define T_DELETE_ASSOCIATION    351
+#define T_ASSOCIATION    352
+#define T_EXTENSION_S    353
+#define T_CONTENT_TYPE    354
+#define T_DELETE_EXTENSION    355
+#define T_EXTENSION    356
+#define T_eXTENSION    357
+#define T_ERROR_WHILE_POSTING_FORM    358
+#define T_COULD_NOT_GET_FILE    359
+#define T_READING_FILES_IS_NOT_ALLOWED    360
+#define T_NO_PREVIOUS_SEARCH    361
+#define T_SEARCH_STRING_NOT_FOUND    362
+#define T_SAVE_ERROR    363
+#define T_ERROR_WRITING_TO_FILE    364
+#define T_DISPLAY_USEMAP    365
+#define T_FOLLOW_LINK    366
+#define T_OPEN_IN_NEW_WINDOW    367
+#define T_DOWNLOAD_LINK    368
+#define T_RESET_FORM    369
+#define T_SUBMIT_FORM    370
+#define T_SUBMIT_FORM_AND_OPEN_IN_NEW_WINDOW    371
+#define T_SUBMIT_FORM_AND_DOWNLOAD    372
+#define T_VIEW_IMAGE    373
+#define T_DOWNLOAD_IMAGE    374
+#define T_SCALE_IMAGE_TO_FULL_SCREEN    375
+#define T_NO_LINK_SELECTED    376
+#define T_IMAGE    377
+#define T_USEMAP    378
+#define T_XTERM    379
+#define T_TWTERM    380
+#define T_SCREEN    381
+#define T_WINDOW    382
+#define T_FULL_SCREEN    383
+#define T_BEOS_TERMINAL    384
+#define T_UNABLE_TO_OPEN_NEW_WINDOW    385
+#define T_JAVASCRIPT    386
+#define T_SUBMIT_FORM_TO    387
+#define T_POST_FORM_TO    388
+#define T_RADIO_BUTTON    389
+#define T_CHECKBOX    390
+#define T_SELECT_FIELD    391
+#define T_TEXT_FIELD    392
+#define T_TEXT_AREA    393
+#define T_FILE_UPLOAD    394
+#define T_PASSWORD_FIELD    395
+#define T_BUTTON    396
+#define T_NAME    397
+#define T_VALUE    398
+#define T_HIT_ENTER_TO    399
+#define T_SUBMIT_TO    400
+#define T_POST_TO    401
+#define T_INFO    402
+#define T_HEADER_INFO    403
+#define T_YOU_ARE_NOWHERE    404
+#define T_NO_HEADER    405
+#define T_URL    406
+#define T_IP_ADDRESS    407
+#define T_IP_ADDRESSES    408
+#define T_SIZE    409
+#define T_COMPRESSED_WITH    410
+#define T_INCOMPLETE    411
+#define T_CODEPAGE    412
+#define T_ASSUMED    413
+#define T_IGNORING_SERVER_SETTING    414
+#define T_SERVER    415
+#define T_DATE    416
+#define T_LAST_MODIFIED    417
+#define T_SSL_CIPHER    418
+#define T_LANGUAGE    419
+#define T_DEFAULT_LANG    420
+#define T_GO_TO_LINK    421
+#define T_ENTER_LINK_NUMBER    422
+#define T_RESIZE_TERMINAL    423
+#define T_COLUMNS    424
+#define T_ROWS    425
+#define T_GOTO    426
+#define T_CLOSE    427
+#define T_FOLDER    428
+#define T_fOLDER    429
+#define T_ADD    430
+#define T_DELETE    431
+#define T_EDIT    432
+#define T_MOVE    433
+#define T_NO_ITEMS_SELECTED    434
+#define T_UNSELECT_ALL    435
+#define T_BOOKMARKS    436
+#define T_BOOKMARK    437
+#define T_ADD_BOOKMARK    438
+#define T_ADD_ASSOCIATION    439
+#define T_ADD_EXTENSION    440
+#define T_ADD_FOLDER    441
+#define T_BOOKMARK_TITLE    442
+#define T_EDIT_BOOKMARK    443
+#define T_EDIT_ASSOCIATION    444
+#define T_EDIT_EXTENSION    445
+#define T_DELETE_BOOKMARK    446
+#define T_EDIT_FOLDER    447
+#define T_DELETE_FOLDER    448
+#define T_NOT_EMPTY_SURE_DELETE    449
+#define T_BOOKMARK_MANAGER    450
+#define T_ASSOCIATIONS_MANAGER    451
+#define T_EXTENSIONS_MANAGER    452
+#define T_url    453
+#define T_NNAME    454
+#define T_EXIT_LINKS    455
+#define T_DO_YOU_REALLY_WANT_TO_CLOSE_WINDOW    456
+#define T_DO_YOU_REALLY_WANT_TO_EXIT_LINKS    457
+#define T_DO_YOU_REALLY_WANT_TO_EXIT_LINKS_AND_TERMINATE_ALL_DOWNLOADS    458
+#define T_HTTP_OPTIONS    459
+#define T_FTP_OPTIONS    460
+#define T_SMB_OPTIONS    461
+#define T_HTTP_BUG_WORKAROUNDS    462
+#define T_USE_HTTP_10    463
+#define T_ALLOW_SERVER_BLACKLIST    464
+#define T_DO_NOT_SEND_ACCEPT_CHARSET    465
+#define T_DO_NOT_ADVERTISE_COMPRESSION_SUPPORT    466
+#define T_RETRY_ON_INTERNAL_ERRORS    467
+#define T_HEADER_OPTIONS    468
+#define T_HTTP_HEADER_OPTIONS    469
+#define T_FAKE_FIREFOX    470
+#define T_DO_NOT_TRACK    471
+#define T_REFERER_NONE    472
+#define T_REFERER_SAME_URL    473
+#define T_REFERER_FAKE    474
+#define T_REFERER_REAL_SAME_SERVER    475
+#define T_REFERER_REAL    476
+#define T_FAKE_REFERER    477
+#define T_FAKE_USERAGENT    478
+#define T_EXTRA_HEADER    479
+#define T_PASSWORD_FOR_ANONYMOUS_LOGIN    480
+#define T_USE_PASSIVE_FTP    481
+#define T_USE_EPRT_EPSV    482
+#define T_SET_TYPE_OF_SERVICE    483
+#define T_ALLOW_HYPERLINKS_TO_SMB    484
+#define T_MANUAL    485
+#define T_HOMEPAGE    486
+#define T_CALIBRATION    487
+#define T_MAILTO_PROG    488
+#define T_SHELL_PROG    489
+#define T_TELNET_PROG    490
+#define T_MAGNET_PROG    491
+#define T_TN3270_PROG    492
+#define T_MMS_PROG    493
+#define T_MAIL_AND_TELNET_PROGRAMS    494
+#define T_MAIL_TELNET_AND_SHELL_PROGRAMS    495
+#define T_NO_PROGRAM    496
+#define T_NO_PROGRAM_SPECIFIED_FOR    497
+#define T_MAIL    498
+#define T_TELNET    499
+#define T_MAGNET    500
+#define T_TN3270    501
+#define T_MMS    502
+#define T_BAD_MAILTO_URL    503
+#define T_BAD_TELNET_URL    504
+#define T_BAD_TN3270_URL    505
+#define T_MMS_URL_CONTAINS_INACCEPTABLE_CHARACTERS    506
+#define T_AUTHORIZATION_REQUIRED    507
+#define T_PROXY_AUTHORIZATION_REQUIRED    508
+#define T_USERID    509
+#define T_PASSWORD    510
+#define T_ENTER_USERNAME    511
+#define T_AT    512
+#define T_THE_SERVER_    513
+#define T_DOESNT_HAVE_A_VALID_CERTIFICATE    514
+#define T_USES_DOWNGRADED_METHOD    515
+#define T_USES_INSECURE_CIPHER    516
+#define T_WAITING_FOR_REDIRECT_CONFIRMATION    517
+#define T_DECOMPRESSION_ERROR    518
+#define T_ERROR_DECOMPRESSING_    519
+#define T__wITH_    520
+#define T_COMPRESSED_ERROR    521
+#define T_UNKNOWN_COMPRESSION_METHOD    522
+#define T_SURE_DELETE    523
+#define T_BOOKMARKS_ALREADY_IN_USE    524
+#define T_ASSOCIATIONS_ALREADY_IN_USE    525
+#define T_EXTENSIONS_ALREADY_IN_USE    526
+#define T_VIDEO_OPTIONS    527
+#define T_VIDEO_OPTIONS_TEXT    528
+#define T_RED_DISPLAY_GAMMA    529
+#define T_GREEN_DISPLAY_GAMMA    530
+#define T_BLUE_DISPLAY_GAMMA    531
+#define T_USER_GAMMA    532
+#define T_ASPECT_RATIO    533
+#define T_DITHER_LETTERS    534
+#define T_DITHER_IMAGES    535
+#define T_8_BIT_GAMMA_CORRECTION    536
+#define T_16_BIT_GAMMA_CORRECTION    537
+#define T_AUTO_GAMMA_CORRECTION    538
+#define T_RGB_PALETTE_8x8x4    539
+#define T_RGB_PALETTE_6x6x6    540
+#define T_SWITCH_PALETTE    541
+#define T_OVERWRITE_SCREEN_INSTEAD_OF_SCROLLING_IT    542
+#define T_ALERT    543
+#define T_QUESTION    544
+#define T_KILL_SCRIPT    545
+#define T_KILL_ALL_SCRIPTS    546
+#define T_SCRIPT_KILLED_BY_USER    547
+#define T_SCRIPT_TRYING_TO_CLOSE_WINDOW    548
+#define T_ENTER_STRING    549
+#define T_JAVASCRIPT_OPTIONS    550
+#define T_ENABLE_JAVASCRIPT    551
+#define T_VERBOSE_JS_ERRORS    552
+#define T_VERBOSE_JS_WARNINGS    553
+#define T_MISCELANEOUS_OPTIONS    554
+#define T_JAVASCRIPT_ERROR    555
+#define T_JAVASCRIPT_WARNING    556
+#define T_DISMISS    557
+#define T_MENU_FONT_SIZE    558
+#define T_USER_FONT_SIZE    559
+#define T_TURN_OFF_WARNINGS    560
+#define T_BOOKMARKS_ENCODING    561
+#define T_JS_IS_ATTEMPTING_TO_GO_TO_URL    562
+#define T_JS_IS_ATTEMPTING_TO_OPEN_NEW_WINDOW_WITH_URL    563
+#define T_JS_IS_ATTEMPTING_TO_GO_INTO_HISTORY    564
+#define T_TO_URL    565
+#define T_GOTO_HISTORY    566
+#define T_ALLOW    567
+#define T_REJECT    568
+#define T_ENABLE_ALL_CONVERSIONS    569
+#define T_ENABLE_GLOBAL_NAME_RESOLUTION    570
+#define T_MANUAL_JS_CONTROL    571
+#define T_JS_RECURSION_DEPTH    572
+#define T_MENU_BACKGROUND_COLOR    573
+#define T_MENU_FOREGROUND_COLOR    574
+#define T_SCROLL_BAR_BAR_COLOR    575
+#define T_SCROLL_BAR_AREA_COLOR    576
+#define T_SCROLL_BAR_FRAME_COLOR    577
+#define T_BOOKMARKS_FILE    578
+#define T_SAVE_URL_HISTORY_ON_EXIT    579
+#define T_ENTER_COLORS_AS_RGB_TRIPLETS    580
+#define T_JS_MEMORY_LIMIT_KB    581
+#define T_SCALE_ALL_IMAGES_BY    582
+#define T_PORN_ENABLE    583
+#define T_DISPLAY_OPTIMIZATION_CRT    584
+#define T_DISPLAY_OPTIMIZATION_LCD_RGB    585
+#define T_DISPLAY_OPTIMIZATION_LCD_BGR    586
+#define T_KEYBOARD_CODEPAGE    587
+#define T_COPY_LINK_LOCATION    588
+#define T_BLOCK_URL    589
+#define T_BLOCK_LIST    590
+#define T_BLOCKED_IMAGE    591
+#define T_BLOCK_LIST_IN_USE    592
+#define T_BLOCK_LIST_MANAGER    593
+#define T_BLOCK_ADD    594
+#define T_BLOCK_EDIT    595
+#define T_BLOCK_DELETE    596
+#define T_HK_GOTO_URL    597
+#define T_HK_GO_BACK    598
+#define T_HK_GO_FORWARD    599
+#define T_HK_HISTORY    600
+#define T_HK_RELOAD    601
+#define T_HK_BOOKMARKS    602
+#define T_HK_NEW_WINDOW    603
+#define T_HK_SAVE_AS    604
+#define T_HK_SAVE_URL_AS    605
+#define T_HK_SAVE_FORMATTED_DOCUMENT    606
+#define T_HK_COPY_URL_LOCATION    607
+#define T_HK_KILL_BACKGROUND_CONNECTIONS    608
+#define T_HK_KILL_ALL_CONNECTIONS    609
+#define T_HK_FLUSH_ALL_CACHES    610
+#define T_HK_RESOURCE_INFO    611
+#define T_HK_MEMORY_INFO    612
+#define T_HK_OS_SHELL    613
+#define T_HK_RESIZE_TERMINAL    614
+#define T_HK_EXIT    615
+#define T_HK_SEARCH    616
+#define T_HK_SEARCH_BACK    617
+#define T_HK_FIND_NEXT    618
+#define T_HK_FIND_PREVIOUS    619
+#define T_HK_TOGGLE_HTML_PLAIN    620
+#define T_HK_DOCUMENT_INFO    621
+#define T_HK_HEADER_INFO    622
+#define T_HK_FRAME_AT_FULL_SCREEN    623
+#define T_HK_HTML_OPTIONS    624
+#define T_HK_COLOR    625
+#define T_HK_SAVE_HTML_OPTIONS    626
+#define T_HK_LANGUAGE    627
+#define T_HK_CHARACTER_SET    628
+#define T_HK_TERMINAL_OPTIONS    629
+#define T_HK_SCREEN_MARGINS    630
+#define T_HK_VIDEO_OPTIONS    631
+#define T_HK_NETWORK_OPTIONS    632
+#define T_HK_CONNECTIONS    633
+#define T_HK_IPV6_OPTIONS    634
+#define T_HK_PROXIES    635
+#define T_HK_SSL_OPTIONS    636
+#define T_HK_HTTP_OPTIONS    637
+#define T_HK_FTP_OPTIONS    638
+#define T_HK_SMB_OPTIONS    639
+#define T_HK_JAVASCRIPT_OPTIONS    640
+#define T_HK_MISCELANEOUS_OPTIONS    641
+#define T_HK_CACHE    642
+#define T_HK_MAIL_AND_TELNEL    643
+#define T_HK_ASSOCIATIONS    644
+#define T_HK_FILE_EXTENSIONS    645
+#define T_HK_BLOCK_LIST    646
+#define T_HK_SAVE_OPTIONS    647
+#define T_HK_ABOUT    648
+#define T_HK_KEYS    649
+#define T_HK_COPYING    650
+#define T_HK_MANUAL    651
+#define T_HK_HOMEPAGE    652
+#define T_HK_CALIBRATION    653
+#define T_HK_FILE    654
+#define T_HK_VIEW    655
+#define T_HK_LINK    656
+#define T_HK_DOWNLOADS    657
+#define T_HK_WINDOWS    658
+#define T_HK_SETUP    659
+#define T_HK_HELP    660
+#define T_HK_DISPLAY_USEMAP    661
+#define T_HK_FOLLOW_LINK    662
+#define T_HK_OPEN_IN_NEW_WINDOW    663
+#define T_HK_DOWNLOAD_LINK    664
+#define T_HK_RESET_FORM    665
+#define T_HK_SUBMIT_FORM    666
+#define T_HK_SUBMIT_FORM_AND_OPEN_IN_NEW_WINDOW    667
+#define T_HK_SUBMIT_FORM_AND_DOWNLOAD    668
+#define T_HK_VIEW_IMAGE    669
+#define T_HK_DOWNLOAD_IMAGE    670
+#define T_HK_SCALE_IMAGE_TO_FULL_SCREEN    671
+#define T_HK_COPY_LINK_LOCATION    672
+#define T_HK_BLOCK_URL    673
+#define T_HK_XTERM    674
+#define T_HK_TWTERM    675
+#define T_HK_SCREEN    676
+#define T_HK_WINDOW    677
+#define T_HK_FULL_SCREEN    678
+#define T_HK_BEOS_TERMINAL    679
+#define T_URL_MANUAL    680
+#define T_URL_HOMEPAGE    681
+#define T_URL_CALIBRATION    682
+#define T__N_TEXTS    683
diff --git a/language.inc b/language.inc
@@ -1,690 +1,689 @@
 /* Automatically generated by gen-intl */
 
 static const struct {
-	int code;
 	const char *name;
 } translation[] = {
-  { 0, NULL },
-  {T__CHAR_SET, "us-ascii" },
-  {T__LANGUAGE, "English" },
-  {T__ACCEPT_LANGUAGE, "en" },
-  {T__DEFAULT_CHAR_SET, "ISO-8859-1" },
-  {T_OK, "OK" },
-  {T_CANCEL, "Cancel" },
-  {T_BAD_NUMBER, "Bad number" },
-  {T_NUMBER_EXPECTED, "Number expected in field" },
-  {T_NUMBER_OUT_OF_RANGE, "Number out of range" },
-  {T_BAD_STRING, "Bad string" },
-  {T_EMPTY_STRING_NOT_ALLOWED, "Empty string not allowed" },
-  {T_BAD_IP_ADDRESS, "Bad IP address" },
-  {T_INVALID_IP_ADDRESS_SYNTAX, "Invalid IP address syntax" },
-  {T_UNABLE_TO_USE_LOCAL_IP_ADDRESS, "Unable to use local IP address" },
-  {T_CONFIG_ERROR, "Config error" },
-  {T_UNABLE_TO_WRITE_TO_CONFIG_FILE, "Unable to write to config file" },
-  {T_HOME_DIRECTORY_INACCESSIBLE, "Home directory inaccessible" },
-  {T_BOOKMARK_ERROR, "Bookmark error" },
-  {T_UNABLE_TO_WRITE_TO_BOOKMARK_FILE, "Unable to write to bookmark file" },
-  {T_ABOUT, "About" },
-  {T_LINKS__LYNX_LIKE, "Links " VERSION "\n\nText and graphics WWW browser" },
-  {T_VERSION, "Version" },
-  {T_VERSION_INFORMATION, "Version information" },
-  {T_LINKS_VERSION, "Links version" },
-  {T_OPERATING_SYSTEM_TYPE, "Operating system type" },
-  {T_OPERATING_SYSTEM_VERSION, "Operating system version" },
-  {T_COMPILER, "Compiler" },
-  {T_WORD_SIZE, "Word size" },
-  {T_MEMORY, "Memory" },
-  {T_FILE_SIZE, "file size" },
-  {T_DEBUGGING_LEVEL, "Debugging level" },
-  {T_EVENT_HANDLER, "Event handler" },
-  {T_SELECT_SYSCALL, "Select syscall" },
-  {T_dISABLED, "disabled" },
-  {T_IPV6, "IPv6" },
-  {T_NOT_ENABLED_IN_SYSTEM, "Not enabled in system" },
-  {T_LOCAL_NETWORK_ONLY, "Local network only" },
-  {T_UTF8_TERMINAL, "UTF-8 terminal" },
-  {T_COMPRESSION_METHODS, "Compression methods" },
-  {T_ENCRYPTION, "Encryption" },
-  {T_NO_CERTIFICATE_VERIFICATION, "no certificate verification" },
-  {T_GPM_MOUSE_DRIVER, "GPM mouse driver" },
-  {T_XTERM_FOR_OS2, "Xterm for OS/2" },
-  {T_GRAPHICS_MODE, "Graphics mode" },
-  {T_IMAGE_LIBRARIES, "Image libraries" },
-  {T_OPENMP, "OpenMP" },
-  {T_NOT_USED_IN_TEXT_MODE, "Not used in text mode" },
-  {T_DISABLED, "Disabled" },
-  {T_THREAD, "thread" },
-  {T_THREADS, "threads" },
-  {T_THREADS5, "threads" },
-  {T_CONFIGURATION_DIRECTORY, "Configuration directory" },
-  {T_NONE, "None" },
-  {T_KEYS, "Keys" },
-  {T_KEYS_DESC, "ESC       display menu\n^C, q, Q  quit\np, l      scroll up, down\n[, ]      scroll left, right\nup, down  select link\n->        follow link\n<-, z     go back\n', x      go forward\nTAB       switch frames\ng         go to url\nG         go to url based on current url\n^G        go to url based on current link\n*         toggle image displaying\n^W        complete URL or search string\n^B,^X,^V,^K copy, cut, paste, cut line to/from clipboard\nAlt-1 .. Alt-9 switch virtual screens (svgalib and fb)" },
-  {T_KEYS_BRAILLE_DESC, "a, w      cursor to status line or title\n{, }      cursor to start/end of a line\n^Y,^T,y,t,^O go to next/previous link/word/form entry" },
-  {T_COPYING, "Copying" },
-  {T_COPYING_DESC, "Links " VERSION "\n\n" LINKS_COPYRIGHT "\n\nThis program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version." },
-  {T_RESOURCES, "Resources" },
-  {T_MEMORY_CACHE, "Memory cache" },
-  {T_DECOMPRESSED_CACHE, "Decompressed cache" },
-  {T_FONT_CACHE, "Font cache" },
-  {T_IMAGE_CACHE, "Image cache" },
-  {T_FORMATTED_DOCUMENT_CACHE, "Formatted document cache" },
-  {T_DNS_CACHE, "DNS cache" },
-  {T_TLS_SESSION_CACHE, "TLS session cache" },
-  {T_HANDLES, "handles" },
-  {T_TIMERS, "timers" },
-  {T_WAITING, "waiting" },
-  {T_CONNECTING, "connecting" },
-  {T_tRANSFERRING, "transferring" },
-  {T_KEEPALIVE, "keepalive" },
-  {T_BYTES, "bytes" },
-  {T_LETTERS, "letters" },
-  {T_FILES, "files" },
-  {T_LOCKED, "locked" },
-  {T_LOADING, "loading" },
-  {T_IMAGES, "images" },
-  {T_DOCUMENTS, "documents" },
-  {T_SERVERS, "servers" },
-  {T_MEMORY_ALLOCATED, "bytes of memory allocated" },
-  {T_BLOCKS_ALLOCATED, "blocks" },
-  {T_MEMORY_REQUESTED, "bytes requested from system" },
-  {T_BLOCKS_REQUESTED, "blocks" },
-  {T_JS_MEMORY_ALLOCATED, "bytes of javascript memory allocated" },
-  {T_MEMORY_INFO, "Memory info" },
-  {T_NO_HISTORY, "No history" },
-  {T_NO_DOWNLOADS, "No downloads" },
-  {T_NO_FRAMES, "No frames" },
-  {T_VT_100_FRAMES, "VT 100 frames" },
-  {T_LINUX_OR_OS2_FRAMES, "Linux or OS/2 frames" },
-  {T_KOI8R_FRAMES, "KOI8-R frames" },
-  {T_FREEBSD_FRAMES, "FreeBSD frames" },
-  {T_USE_11M, "Use ^[[11m" },
-  {T_RESTRICT_FRAMES_IN_CP850_852, "Restrict frames in cp850/852" },
-  {T_BLOCK_CURSOR, "Block cursor" },
-  {T_COLOR, "Color" },
-  {T_BRAILLE_TERMINAL, "Braille terminal" },
-  {T_TERMINAL_OPTIONS, "Terminal options" },
-  {T_SCREEN_MARGINS, "Screen margins" },
-  {T_LEFT_MARGIN, "Left margin" },
-  {T_RIGHT_MARGIN, "Right margin" },
-  {T_TOP_MARGIN, "Top margin" },
-  {T_BOTTOM_MARGIN, "Bottom margin" },
-  {T_MARGINS_TOO_LARGE, "Margins too large" },
-  {T_THE_ENTERED_VALUES_ARE_TOO_LARGE_FOR_THE_CURRENT_SCREEN, "The entered values are too large for the current screen" },
-  {T_NETWORK_OPTIONS, "Network options" },
-  {T_IPV6_OPTIONS, "IPv6 options" },
-  {T_IPV6_DEFAULT, "Default system preference" },
-  {T_IPV6_PREFER_IPV4, "Prefer IPv4" },
-  {T_IPV6_PREFER_IPV6, "Prefer IPv6" },
-  {T_IPV6_USE_ONLY_IPV4, "Use only IPv4" },
-  {T_IPV6_USE_ONLY_IPV6, "Use only IPv6" },
-  {T_PROXIES, "Proxies" },
-  {T_HTTP_PROXY__HOST_PORT, "HTTP proxy (host:port)" },
-  {T_FTP_PROXY__HOST_PORT, "FTP proxy (host:port)" },
-  {T_HTTPS_PROXY__HOST_PORT, "HTTPS proxy (host:port)" },
-  {T_SOCKS_4A_PROXY__USER_HOST_PORT, "Socks4A proxy (user@host:port)" },
-  {T_APPEND_TEXT_TO_SOCKS_LOOKUPS, "Append text to hostname (for specifying tor exit node)" },
-  {T_ONLY_PROXIES, "Connect only via proxies or Socks (useful for tor)" },
-  {T_NOPROXY_LIST, "Direct access (w/o proxy) domains (comma separated)" },
-  {T_SSL_OPTIONS, "SSL options" },
-  {T_ACCEPT_INVALID_CERTIFICATES, "Accept invalid certificates and weak ciphers" },
-  {T_WARN_ON_INVALID_CERTIFICATES, "Warn on invalid certificate or weak cipher" },
-  {T_REJECT_INVALID_CERTIFICATES, "Reject invalid certificates and weak ciphers" },
-  {T_USE_BUILT_IN_CERTIFICATES, "Use built-in certificates" },
-  {T_CLIENT_CERTIFICATE_KEY_FILE, "Client certificate key file" },
-  {T_CLIENT_CERTIFICATE_FILE, "Client certificate file" },
-  {T_CLIENT_CERTIFICATE_KEY_PASSWORD, "Client certificate password (won't be saved in config file)" },
-  {T_BAD_FILE, "Bad file" },
-  {T_THE_FILE_DOES_NOT_EXIST, "The file does not exist" },
-  {T_THE_FILE_HAS_INVALID_FORMAT, "The file has invalid format" },
-  {T_ERROR_INITIALIZING_BUILT_IN_CERTIFICATES, "Error initializing built-in certificates" },
-  {T_FAILED, "failed" },
-  {T_CONNECTIONS, "Connections" },
-  {T_MAX_CONNECTIONS, "Max connections" },
-  {T_MAX_CONNECTIONS_TO_ONE_HOST, "Max connections to one host" },
-  {T_RETRIES, "Retries (0 - unlimited)" },
-  {T_RECEIVE_TIMEOUT_SEC, "Receive timeout (sec)" },
-  {T_TIMEOUT_WHEN_UNRESTARTABLE, "Timeout when unrestartable" },
-  {T_TIMEOUT_WHEN_TRYING_MULTIPLE_ADDRESSES, "Timeout when trying multiple addresses" },
-  {T_BIND_TO_LOCAL_IP_ADDRESS, "Bind to local IP address" },
-  {T_BIND_TO_LOCAL_IPV6_ADDRESS, "... IPv6 address" },
-  {T_ASYNC_DNS_LOOKUP, "Async DNS lookup" },
-  {T_SET_TIME_OF_DOWNLOADED_FILES, "Set time of downloaded files" },
-  {T_CACHE_OPTIONS, "Cache options" },
-  {T_MEMORY_CACHE_SIZE__KB, "Memory cache size (KiB)" },
-  {T_IMAGE_CACHE_SIZE__KB, "Image cache size (KiB)" },
-  {T_FONT_CACHE_SIZE__KB, "Font cache size (KiB)" },
-  {T_NUMBER_OF_FORMATTED_DOCUMENTS, "Number of formatted documents" },
-  {T_AGGRESSIVE_CACHE, "Aggressive cache" },
-  {T_HTML_OPTIONS, "Html options" },
-  {T_DISPLAY_TABLES, "Display tables" },
-  {T_DISPLAY_FRAMES, "Display frames" },
-  {T_BREAK_LONG_LINES, "Break long lines" },
-  {T_DISPLAY_IMAGES, "Display images" },
-  {T_DISPLAY_IMAGE_FILENAMES, "Display image filenames" },
-  {T_DISPLAY_LINKS_TO_IMAGES, "Display links to images" },
-  {T_LINK_ORDER_BY_COLUMNS, "Move by columns in table" },
-  {T_NUMBERED_LINKS, "Links are numbered" },
-  {T_AUTO_REFRESH, "Auto refresh" },
-  {T_TARGET_IN_NEW_WINDOW, "Allow opening links in new window (target=\"_blank\")" },
-  {T_TEXT_MARGIN, "Text margin" },
-  {T_DEFAULT_CODEPAGE, "Default codepage" },
-  {T_IGNORE_CHARSET_INFO_SENT_BY_SERVER, "Ignore charset info sent by server" },
-  {T_TEXT_COLOR, "Text" },
-  {T_LINK_COLOR, "Link" },
-  {T_BACKGROUND_COLOR, "Background" },
-  {T_IGNORE_DOCUMENT_COLOR, "Ignore document color" },
-  {T_COLOR_0, "Black" },
-  {T_COLOR_1, "Red" },
-  {T_COLOR_2, "Green" },
-  {T_COLOR_3, "Yellow" },
-  {T_COLOR_4, "Dark blue" },
-  {T_COLOR_5, "Magenta" },
-  {T_COLOR_6, "Cyan" },
-  {T_COLOR_7, "White" },
-  {T_COLOR_8, "Dark grey" },
-  {T_COLOR_9, "Bright red" },
-  {T_COLOR_10, "Bright green" },
-  {T_COLOR_11, "Bright yellow" },
-  {T_COLOR_12, "Bright blue" },
-  {T_COLOR_13, "Bright magenta" },
-  {T_COLOR_14, "Bright cyan" },
-  {T_COLOR_15, "Bright white" },
-  {T_GOTO_URL, "Go to URL" },
-  {T_GO_BACK, "Go back" },
-  {T_GO_FORWARD, "Go forward" },
-  {T_HISTORY, "History" },
-  {T_RELOAD, "Reload" },
-  {T_NEW_WINDOW, "New window" },
-  {T_SAVE_AS, "Save as" },
-  {T_SAVE_URL_AS, "Save URL as" },
-  {T_SAVE_FORMATTED_DOCUMENT, "Save formatted document" },
-  {T_COPY_URL_LOCATION, "Copy current URL location" },
-  {T_KILL_BACKGROUND_CONNECTIONS, "Kill background connections" },
-  {T_KILL_ALL_CONNECTIONS, "Kill all connections" },
-  {T_FLUSH_ALL_CACHES, "Flush all caches" },
-  {T_RESOURCE_INFO, "Resource info" },
-  {T_OS_SHELL, "OS shell" },
-  {T_EXIT, "Exit" },
-  {T_SEARCH, "Search" },
-  {T_SEARCH_BACK, "Search backward" },
-  {T_FIND_NEXT, "Find next" },
-  {T_FIND_PREVIOUS, "Find previous" },
-  {T_TOGGLE_HTML_PLAIN, "Toggle html/plain" },
-  {T_DOCUMENT_INFO, "Document info" },
-  {T_FRAME_AT_FULL_SCREEN, "Frame at full-screen" },
-  {T_SAVE_HTML_OPTIONS, "Save html options" },
-  {T_CHARACTER_SET, "Character set" },
-  {T_DEFAULT_CHARSET, "Default" },
-  {T_CACHE, "Cache" },
-  {T_MAIL_AND_TELNEL, "Mail and telnet" },
-  {T_MAIL_TELNET_AND_SHELL, "Mail, telnet and shell" },
-  {T_ASSOCIATIONS, "Associations" },
-  {T_FILE_EXTENSIONS, "File extensions" },
-  {T_SAVE_OPTIONS, "Save options" },
-  {T_FILE, "File" },
-  {T_VIEW, "View" },
-  {T_LINK, "Link" },
-  {T_DOWNLOADS, "Downloads" },
-  {T_WINDOWS, "Windows" },
-  {T_SETUP, "Setup" },
-  {T_HELP, "Help" },
-  {T_ENTER_URL, "Enter URL" },
-  {T_SAVE_URL, "Save URL" },
-  {T_DOWNLOAD, "Download" },
-  {T_SAVE_TO_FILE, "Save to file" },
-  {T_SEARCH_FOR_TEXT, "Search for text" },
-  {T_PAGE_P, "(p" },
-  {T_PAGE_OF, " of " },
-  {T_PAGE_CL, ")" },
-  {T_FORMATTING_DOCUMENT, "Formatting document" },
-  {T_SEARCHING, "Searching" },
-  {T_WAITING_IN_QUEUE, "Waiting in queue" },
-  {T_LOOKING_UP_HOST, "Looking up host" },
-  {T_MAKING_CONNECTION, "Making connection" },
-  {T_MAKING_CONNECTION_TO_ANOTHER_ADDRESS, "Making connection to another address" },
-  {T_SOCKS_NEGOTIATION, "Making Socks connection" },
-  {T_SSL_NEGOTIATION, "SSL negotiation" },
-  {T_REQUEST_SENT, "Request sent" },
-  {T_LOGGING_IN, "Logging in" },
-  {T_GETTING_HEADERS, "Getting headers" },
-  {T_SERVER_IS_PROCESSING_REQUEST, "Server is processing request" },
-  {T_TRANSFERRING, "Transferring" },
-  {T_INTERRUPTED, "Interrupted" },
-  {T_SOCKET_EXCEPTION, "Socket exception" },
-  {T_INTERNAL_ERROR, "Internal error" },
-  {T_OUT_OF_MEMORY, "Out of memory" },
-  {T_HOST_NOT_FOUND, "Host not found" },
-  {T_PROXY_NOT_FOUND, "Proxy not found" },
-  {T_ERROR_WRITING_TO_SOCKET, "Error writing to socket" },
-  {T_ERROR_READING_FROM_SOCKET, "Error reading from socket" },
-  {T_DATA_MODIFIED, "Data modified" },
-  {T_BAD_URL_SYNTAX, "Bad URL syntax" },
-  {T_BAD_PROXY_SYNTAX, "Bad proxy syntax" },
-  {T_RECEIVE_TIMEOUT, "Receive timeout" },
-  {T_REQUEST_MUST_BE_RESTARTED, "Request must be restarted" },
-  {T_CANT_GET_SOCKET_STATE, "Can't get socket state" },
-  {T_CYCLIC_REDIRECT, "Cyclic redirect" },
-  {T_TOO_LARGE_FILE, "Too large file" },
-  {T_BAD_HTTP_RESPONSE, "Bad HTTP response" },
-  {T_HTTP_100, "HTTP 100 (\?\?\?)" },
-  {T_NO_CONTENT, "No content" },
-  {T_HTTPS_FWD_ERROR, "HTTPS forwarding failed" },
-  {T_INVALID_CERTIFICATE, "Invalid certificate" },
-  {T_DOWNGRADED_METHOD, "Downgraded SSL/TLS method" },
-  {T_INSECURE_CIPHER, "Insecure cipher" },
-  {T_UNKNOWN_FILE_TYPE, "Unknown file type" },
-  {T_ERROR_OPENING_FILE, "Error opening file" },
-  {T_BAD_FTP_RESPONSE, "Bad FTP response" },
-  {T_FTP_SERVICE_UNAVAILABLE, "FTP service unavailable" },
-  {T_BAD_FTP_LOGIN, "Bad FTP login" },
-  {T_FTP_PORT_COMMAND_FAILED, "FTP PORT command failed" },
-  {T_FILE_NOT_FOUND, "File not found" },
-  {T_FTP_FILE_ERROR, "FTP file error" },
-  {T_SSL_ERROR, "SSL error" },
-  {T_NO_SSL, "This version of Links does not contain SSL/TLS support" },
-  {T_BAD_SOCKS_VERSION, "Bad Socks version (4a is required)" },
-  {T_SOCKS_REJECTED_OR_FAILED, "Socks connection rejected or failed" },
-  {T_SOCKS_NO_IDENTD, "Socks proxy can't connect to identd server" },
-  {T_SOCKS_BAD_USERID, "Bad Socks userid" },
-  {T_SOCKS_UNKNOWN_ERROR, "Unknown Socks error" },
-  {T_NO_SMB_CLIENT, "No smb client program installed (supported is smbclient or smbc)" },
-  {T_BLOCKED_URL, "This URL is in your blocklist" },
-  {T_SMB_NOT_ALLOWED, "Hyperlinks to the SMB protocol are not allowed" },
-  {T_FILE_NOT_ALLOWED, "Hyperlinks to local files are not allowed" },
-  {T_NO_PROXY, "No proxy for this connection and connections without proxies are disabled" },
-  {T_UNKNOWN_ERROR, "Unknown error" },
-  {T_RECEIVED, "Received" },
-  {T_OF, "of" },
-  {T_AVG, "avg" },
-  {T_CUR, "cur" },
-  {T_AVERAGE_SPEED, "Average speed" },
-  {T_SPEED, "Speed" },
-  {T_CURRENT_SPEED, "current speed" },
-  {T_ELAPSED_TIME, "Elapsed time" },
-  {T_ESTIMATED_TIME, "estimated time" },
-  {T_BACKGROUND, "Background" },
-  {T_ABORT, "Abort" },
-  {T_ABORT_AND_DELETE_FILE, "Abort and delete file" },
-  {T_YES, "Yes" },
-  {T_NO, "No" },
-  {T_DIRECTORY, "Directory" },
-  {T_FILE_ALREADY_EXISTS, "File already exists" },
-  {T_ALREADY_EXISTS_AS_DOWNLOAD, "already exists as an active download." },
-  {T_ALREADY_EXISTS, "already exists." },
-  {T_DO_YOU_WISH_TO_CONTINUE, "Do you wish to continue download or overwrite file?" },
-  {T_DO_YOU_WISH_TO_OVERWRITE, "Do you wish to overwrite it?" },
-  {T_CONTINUE, "Continue" },
-  {T_OVERWRITE, "Overwrite" },
-  {T_RENAME, "Rename" },
-  {T_DOWNLOAD_ERROR, "Download error" },
-  {T_COULD_NOT_WRITE_TO_FILE, "Could not create file" },
-  {T_ERROR_DOWNLOADING, "Error downloading" },
-  {T_ERROR_LOADING, "Error loading" },
-  {T_COULD_NOT_CREATE_FILE, "Could not create file" },
-  {T_COULD_NOT_CREATE_TEMPORARY_FILE, "Could not create temporary file" },
-  {T_ERROR_CALLING_LSEEK_ON_FILE, "Error calling lseek on file" },
-  {T_TOO_LARGE_FILE_SEQUENCE, "Too large file sequence" },
-  {T_UNKNOWN_TYPE, "Unknown type" },
-  {T_CONTENT_TYPE_IS, "Content type is" },
-  {T_DO_YOU_WANT_TO_OPEN_SAVE_OR_DISPLAY_THIS_FILE, "Do you want to open, save or display this file?" },
-  {T_DO_YOU_WANT_TO_OPEN_OR_DISPLAY_THIS_FILE, "Do you want to open or display this file?" },
-  {T_DO_YOU_WANT_TO_SAVE_OR_DISLPAY_THIS_FILE, "Do you want to save or display this file?" },
-  {T_SAVE, "Save" },
-  {T_DISPLAY, "Display" },
-  {T_WHAT_TO_DO, "What to do?" },
-  {T_DO_YOU_WANT_TO_OPEN_FILE_WITH, "Do you want to open file with" },
-  {T_SAVE_IT_OR_DISPLAY_IT, "save it or display it?" },
-  {T_OPEN, "Open" },
-  {T_OPEN_WITH, "Open with" },
-  {T_DO_YOU_WANT_TO_FOLLOW_REDIRECT_AND_POST_FORM_DATA_TO_URL, "Do you want to follow redirect and post form data to url" },
-  {T_DO_YOU_WANT_TO_POST_FORM_DATA_TO_URL, "Do you want to post form data to url" },
-  {T_DO_YOU_WANT_TO_REPOST_FORM_DATA_TO_URL, "Do you want to repost form data to url" },
-  {T_WARNING, "Warning" },
-  {T_ERROR, "Error" },
-  {T_WELCOME, "Welcome" },
-  {T_WELCOME_TO_LINKS, "Welcome to links!" },
-  {T_BASIC_HELP, "To display menu, press ESC or click on the top line in window. Select Help->Manual in menu for user's manual." },
-  {T_LABEL, "Label" },
-  {T_CONTENT_TYPES, "Content-Type(s) (comma-separated)" },
-  {T_PROGRAM__IS_REPLACED_WITH_FILE_NAME, "Program ('%' is replaced with file name)" },
-  {T_BLOCK_TERMINAL_WHILE_PROGRAM_RUNNING, "Block terminal while program running" },
-  {T_RUN_ON_TERMINAL, "Run on terminal" },
-  {T_RUN_IN_XWINDOW, "Run in X-Window" },
-  {T_ASK_BEFORE_OPENING, "Ask before opening" },
-  {T_ACCEPT_HTTP, "Accepts HTTP URLs" },
-  {T_ACCEPT_FTP, "Accepts FTP URLs" },
-  {T_DELETE_ASSOCIATION, "Delete association" },
-  {T_ASSOCIATION, "association" },
-  {T_EXTENSION_S, "Extension(s) (comma-separated)" },
-  {T_CONTENT_TYPE, "Content-Type" },
-  {T_DELETE_EXTENSION, "Delete extension" },
-  {T_EXTENSION, "Extension" },
-  {T_eXTENSION, "extension" },
-  {T_ERROR_WHILE_POSTING_FORM, "Error while posting form" },
-  {T_COULD_NOT_GET_FILE, "Could not get file" },
-  {T_READING_FILES_IS_NOT_ALLOWED, "Reading files is not allowed" },
-  {T_NO_PREVIOUS_SEARCH, "No previous search" },
-  {T_SEARCH_STRING_NOT_FOUND, "Search string not found" },
-  {T_SAVE_ERROR, "Save error" },
-  {T_ERROR_WRITING_TO_FILE, "Error writing to file" },
-  {T_DISPLAY_USEMAP, "Display usemap" },
-  {T_FOLLOW_LINK, "Follow link" },
-  {T_OPEN_IN_NEW_WINDOW, "Open in new window" },
-  {T_DOWNLOAD_LINK, "Download link" },
-  {T_RESET_FORM, "Reset form" },
-  {T_SUBMIT_FORM, "Submit form" },
-  {T_SUBMIT_FORM_AND_OPEN_IN_NEW_WINDOW, "Submit form and open in new window" },
-  {T_SUBMIT_FORM_AND_DOWNLOAD, "Submit form and download" },
-  {T_VIEW_IMAGE, "View image" },
-  {T_DOWNLOAD_IMAGE, "Download image" },
-  {T_SCALE_IMAGE_TO_FULL_SCREEN, "Scale image to full screen" },
-  {T_NO_LINK_SELECTED, "No link selected" },
-  {T_IMAGE, "Image" },
-  {T_USEMAP, "Usemap" },
-  {T_XTERM, "Xterm" },
-  {T_TWTERM, "Twterm" },
-  {T_SCREEN, "Screen" },
-  {T_WINDOW, "Window" },
-  {T_FULL_SCREEN, "Full screen" },
-  {T_BEOS_TERMINAL, "BeOS terminal" },
-  {T_UNABLE_TO_OPEN_NEW_WINDOW, "Unable to open new window" },
-  {T_JAVASCRIPT, "Javascript" },
-  {T_SUBMIT_FORM_TO, "Submit form to" },
-  {T_POST_FORM_TO, "Post form to" },
-  {T_RADIO_BUTTON, "Radio button" },
-  {T_CHECKBOX, "Checkbox" },
-  {T_SELECT_FIELD, "Select field" },
-  {T_TEXT_FIELD, "Text field" },
-  {T_TEXT_AREA, "Text area" },
-  {T_FILE_UPLOAD, "File upload" },
-  {T_PASSWORD_FIELD, "Password field" },
-  {T_BUTTON, "Button" },
-  {T_NAME, "name" },
-  {T_VALUE, "value" },
-  {T_HIT_ENTER_TO, "hit ENTER to" },
-  {T_SUBMIT_TO, "submit to" },
-  {T_POST_TO, "post to" },
-  {T_INFO, "Info" },
-  {T_HEADER_INFO, "Header info" },
-  {T_YOU_ARE_NOWHERE, "No page is displayed" },
-  {T_NO_HEADER, "The document doesn't have a header" },
-  {T_URL, "URL" },
-  {T_IP_ADDRESS, "IP address" },
-  {T_IP_ADDRESSES, "IP addresses" },
-  {T_SIZE, "Size" },
-  {T_COMPRESSED_WITH, "compressed with" },
-  {T_INCOMPLETE, "incomplete" },
-  {T_CODEPAGE, "Codepage" },
-  {T_ASSUMED, "assumed" },
-  {T_IGNORING_SERVER_SETTING, "ignoring server setting" },
-  {T_SERVER, "Server" },
-  {T_DATE, "Date" },
-  {T_LAST_MODIFIED, "Last modified" },
-  {T_SSL_CIPHER, "SSL cipher" },
-  {T_LANGUAGE, "Language" },
-  {T_DEFAULT_LANG, "Default" },
-  {T_GO_TO_LINK, "Go to link" },
-  {T_ENTER_LINK_NUMBER, "Enter link number" },
-  {T_RESIZE_TERMINAL, "Resize terminal" },
-  {T_COLUMNS, "Columns" },
-  {T_ROWS, "Rows" },
-  {T_GOTO, "Goto" },
-  {T_CLOSE, "Close" },
-  {T_FOLDER, "Folder" },
-  {T_fOLDER, "folder" },
-  {T_ADD, "Add" },
-  {T_DELETE, "Delete" },
-  {T_EDIT, "Edit" },
-  {T_MOVE, "Move" },
-  {T_NO_ITEMS_SELECTED, "No items selected. Nothing to move." },
-  {T_UNSELECT_ALL, "Unselect all" },
-  {T_BOOKMARKS, "Bookmarks" },
-  {T_BOOKMARK, "bookmark" },
-  {T_ADD_BOOKMARK, "Add bookmark" },
-  {T_ADD_ASSOCIATION, "Add association" },
-  {T_ADD_EXTENSION, "Add extension" },
-  {T_ADD_FOLDER, "Add folder" },
-  {T_BOOKMARK_TITLE, "Bookmark title" },
-  {T_EDIT_BOOKMARK, "Edit bookmark" },
-  {T_EDIT_ASSOCIATION, "Edit association" },
-  {T_EDIT_EXTENSION, "Edit extension" },
-  {T_DELETE_BOOKMARK, "Delete bookmark" },
-  {T_EDIT_FOLDER, "Edit folder" },
-  {T_DELETE_FOLDER, "Delete folder" },
-  {T_NOT_EMPTY_SURE_DELETE, "is not empty. Do you really want to delete it?" },
-  {T_BOOKMARK_MANAGER, "Bookmark manager" },
-  {T_ASSOCIATIONS_MANAGER, "Associations manager" },
-  {T_EXTENSIONS_MANAGER, "Extensions manager" },
-  {T_url, "url" },
-  {T_NNAME, "Name" },
-  {T_EXIT_LINKS, "Exit Links" },
-  {T_DO_YOU_REALLY_WANT_TO_CLOSE_WINDOW, "Do you really want to close window?" },
-  {T_DO_YOU_REALLY_WANT_TO_EXIT_LINKS, "Do you really want to exit Links?" },
-  {T_DO_YOU_REALLY_WANT_TO_EXIT_LINKS_AND_TERMINATE_ALL_DOWNLOADS, "Do you really want to exit Links (and terminate all downloads)?" },
-  {T_HTTP_OPTIONS, "HTTP options" },
-  {T_FTP_OPTIONS, "FTP options" },
-  {T_SMB_OPTIONS, "SMB options" },
-  {T_HTTP_BUG_WORKAROUNDS, "HTTP bug workarounds" },
-  {T_USE_HTTP_10, "Use HTTP/1.0" },
-  {T_ALLOW_SERVER_BLACKLIST, "Allow blacklist of buggy servers" },
-  {T_BROKEN_302_REDIRECT, "Broken redirect 302 (it violates RFC, but it's compatible with Netscape)" },
-  {T_NO_KEEPALIVE_AFTER_POST_REQUEST, "No keepalive connection after POST request (some buggy PHP databases need it)" },
-  {T_DO_NOT_SEND_ACCEPT_CHARSET, "Do not send Accept-Charset" },
-  {T_DO_NOT_ADVERTISE_COMPRESSION_SUPPORT, "Do not advertise compression support" },
-  {T_RETRY_ON_INTERNAL_ERRORS, "Retry on internal server errors (50x)" },
-  {T_HEADER_OPTIONS, "Header options" },
-  {T_HTTP_HEADER_OPTIONS, "HTTP header options" },
-  {T_FAKE_FIREFOX, "Fake Firefox (improves privacy)" },
-  {T_DO_NOT_TRACK, "Send \"do not track\" request" },
-  {T_REFERER_NONE, "No referer" },
-  {T_REFERER_SAME_URL, "Send requested URL as referer" },
-  {T_REFERER_FAKE, "Fixed referer" },
-  {T_REFERER_REAL_SAME_SERVER, "Send real referer only to the same server" },
-  {T_REFERER_REAL, "Send real referer (normal operation, INSECURE!!!)" },
-  {T_FAKE_REFERER, "Fixed HTTP Referer" },
-  {T_FAKE_USERAGENT, "Fake User-Agent" },
-  {T_EXTRA_HEADER, "Extra header string ('\\' means newline)" },
-  {T_PASSWORD_FOR_ANONYMOUS_LOGIN, "Password for anonymous login" },
-  {T_USE_PASSIVE_FTP, "Use passive FTP" },
-  {T_USE_EPRT_EPSV, "Use EPRT/EPSV commands on IPv4" },
-  {T_USE_FAST_FTP, "Command queuing (fast but incompatible with RFC)" },
-  {T_SET_TYPE_OF_SERVICE, "Set IP Type Of Service" },
-  {T_ALLOW_HYPERLINKS_TO_SMB, "Allow hyperlinks to SMB protocol. Disabling this improves security, because internet sites cannot exploit possible bugs in the SMB client." },
-  {T_MANUAL, "User's manual" },
-  {T_HOMEPAGE, "Home page" },
-  {T_CALIBRATION, "Calibration" },
-  {T_MAILTO_PROG, "Mail program (% is replaced with address)" },
-  {T_SHELL_PROG, "Shell for executing external commands (% is replaced with command)" },
-  {T_TELNET_PROG, "Telnet program (% is replaced with \"host\" or \"host port\")" },
-  {T_MAGNET_PROG, "Magnet program (% is replaced with URL)" },
-  {T_TN3270_PROG, "Tn3270 program (% is replaced with \"host\" or \"host port\")" },
-  {T_MMS_PROG, "MMS program (% is replaced with URL)" },
-  {T_MAIL_AND_TELNET_PROGRAMS, "Mail and telnet programs" },
-  {T_MAIL_TELNET_AND_SHELL_PROGRAMS, "Mail, telnet and shell programs" },
-  {T_NO_PROGRAM, "No program" },
-  {T_NO_PROGRAM_SPECIFIED_FOR, "No program specified for" },
-  {T_MAIL, "mail" },
-  {T_TELNET, "telnet" },
-  {T_MAGNET, "magnet" },
-  {T_TN3270, "tn3270" },
-  {T_MMS, "mms" },
-  {T_BAD_MAILTO_URL, "Bad mailto url" },
-  {T_BAD_TELNET_URL, "Bad telnet url" },
-  {T_BAD_TN3270_URL, "Bad tn3270 url" },
-  {T_MMS_URL_CONTAINS_INACCEPTABLE_CHARACTERS, "MMS url contains inacceptable characters" },
-  {T_AUTHORIZATION_REQUIRED, "Authorization required" },
-  {T_PROXY_AUTHORIZATION_REQUIRED, "Proxy authorization required" },
-  {T_USERID, "User ID" },
-  {T_PASSWORD, "Password" },
-  {T_ENTER_USERNAME, "Enter username for " },
-  {T_AT, "at " },
-  {T_THE_SERVER_, "The server " },
-  {T_DOESNT_HAVE_A_VALID_CERTIFICATE, " doesn't have a valid certificate. Do you want to connect to it anyway?" },
-  {T_USES_DOWNGRADED_METHOD, " uses downgraded SSL/TLS method. Do you want to connect to it anyway?" },
-  {T_USES_INSECURE_CIPHER, " uses insecure cipher. Do you want to connect to it anyway?" },
-  {T_WAITING_FOR_REDIRECT_CONFIRMATION, "Waiting for redirect confirmation" },
-  {T_DECOMPRESSION_ERROR, "Decompression error" },
-  {T_ERROR_DECOMPRESSING_, "Error decompressing " },
-  {T__wITH_, " with " },
-  {T_COMPRESSED_ERROR, "Error in compressed data" },
-  {T_UNKNOWN_COMPRESSION_METHOD, "Unknown compression method" },
-  {T_SURE_DELETE, "Are you sure to delete" },
-  {T_BOOKMARKS_ALREADY_IN_USE, "Bookmarks are already in use!" },
-  {T_ASSOCIATIONS_ALREADY_IN_USE, "Associations are already in use!" },
-  {T_EXTENSIONS_ALREADY_IN_USE, "Extensions are already in use!" },
-  {T_VIDEO_OPTIONS, "Video options" },
-  {T_VIDEO_OPTIONS_TEXT, "Recommended user gamma setting:\n1.33 for dark room, 1.11 for very dim room, 1 for usual computer workspace lighting, 0.88 for bright environment lighting." },
-  {T_RED_DISPLAY_GAMMA, "Red display gamma" },
-  {T_GREEN_DISPLAY_GAMMA, "Green display gamma" },
-  {T_BLUE_DISPLAY_GAMMA, "Blue display gamma" },
-  {T_USER_GAMMA, "User gamma" },
-  {T_ASPECT_RATIO, "Aspect ratio" },
-  {T_DITHER_LETTERS, "Dither letters" },
-  {T_DITHER_IMAGES, "Dither images" },
-  {T_8_BIT_GAMMA_CORRECTION, "8-bit gamma correction" },
-  {T_16_BIT_GAMMA_CORRECTION, "16-bit gamma correction" },
-  {T_AUTO_GAMMA_CORRECTION, "Auto gamma correction (according to FPU speed)" },
-  {T_OVERWRITE_SCREEN_INSTEAD_OF_SCROLLING_IT, "Overwrite screen instead of scrolling it" },
-  {T_ALERT, "Alert" },
-  {T_QUESTION, "Question" },
-  {T_KILL_SCRIPT, "Kill script" },
-  {T_KILL_ALL_SCRIPTS, "Kill all scripts" },
-  {T_SCRIPT_KILLED_BY_USER, "Javascript killed by user." },
-  {T_SCRIPT_TRYING_TO_CLOSE_WINDOW, "Javascript is trying to close the browser window. Do you really want to close the window?" },
-  {T_ENTER_STRING, "Enter string" },
-  {T_JAVASCRIPT_OPTIONS, "Javascript options" },
-  {T_ENABLE_JAVASCRIPT, "Enable javascript" },
-  {T_VERBOSE_JS_ERRORS, "Verbose javascript errors" },
-  {T_VERBOSE_JS_WARNINGS, "Verbose javascript warnings" },
-  {T_MISCELANEOUS_OPTIONS, "Miscellaneous options" },
-  {T_JAVASCRIPT_ERROR, "Javascript error" },
-  {T_JAVASCRIPT_WARNING, "Javascript warning" },
-  {T_DISMISS, "Dismiss" },
-  {T_MENU_FONT_SIZE, "Menu font size" },
-  {T_USER_FONT_SIZE, "User font size" },
-  {T_TURN_OFF_WARNINGS, "Turn off warnings" },
-  {T_BOOKMARKS_ENCODING, "Bookmarks encoding" },
-  {T_JS_IS_ATTEMPTING_TO_GO_TO_URL, "Javascript is attempting to go to URL" },
-  {T_JS_IS_ATTEMPTING_TO_OPEN_NEW_WINDOW_WITH_URL, "Javascript is attempting open a new window with URL" },
-  {T_JS_IS_ATTEMPTING_TO_GO_INTO_HISTORY, "Javascript is attempting to go into history" },
-  {T_TO_URL, "to url" },
-  {T_GOTO_HISTORY, "Goto history" },
-  {T_ALLOW, "Allow" },
-  {T_REJECT, "Reject" },
-  {T_ENABLE_ALL_CONVERSIONS, "Enable all conversions" },
-  {T_ENABLE_GLOBAL_NAME_RESOLUTION, "Enable global name resolution" },
-  {T_MANUAL_JS_CONTROL, "Manual javascript operations confirmation" },
-  {T_JS_RECURSION_DEPTH, "Recursion depth" },
-  {T_MENU_BACKGROUND_COLOR, "Background color" },
-  {T_MENU_FOREGROUND_COLOR, "Foreground color" },
-  {T_SCROLL_BAR_BAR_COLOR, "Scroll-bar bar color" },
-  {T_SCROLL_BAR_AREA_COLOR, "Scroll-bar area color" },
-  {T_SCROLL_BAR_FRAME_COLOR, "Scroll-bar frame color" },
-  {T_BOOKMARKS_FILE, "Bookmarks file" },
-  {T_SAVE_URL_HISTORY_ON_EXIT, "Save URL history on exit" },
-  {T_ENTER_COLORS_AS_RGB_TRIPLETS, "Enter colors as sRGB hexadecimal RRGGBB triplets." },
-  {T_JS_MEMORY_LIMIT_KB, "Memory dedicated to javascript (KiB)" },
-  {T_SCALE_ALL_IMAGES_BY, "Scale all images by (%)" },
-  {T_PORN_ENABLE, "Autoscale single images" },
-  {T_DISPLAY_OPTIMIZATION_CRT,"Display optimization for CRT" },
-  {T_DISPLAY_OPTIMIZATION_LCD_RGB,"Display optimization for LCD (RGB)" },
-  {T_DISPLAY_OPTIMIZATION_LCD_BGR,"Display optimization for LCD (BGR)" },
-  {T_KEYBOARD_CODEPAGE, "Keyboard codepage" },
-  {T_COPY_LINK_LOCATION, "Copy link location" },
-  {T_BLOCK_URL, "Block image" },
-  {T_BLOCK_LIST, "Blocked images" },
-  {T_BLOCKED_IMAGE, "Blocked images" },
-  {T_BLOCK_LIST_IN_USE, "Blocked images is already open" },
-  {T_BLOCK_LIST_MANAGER, "Image blocking manager" },
-  {T_BLOCK_ADD, "Add Image URL to block" },
-  {T_BLOCK_EDIT, "Edit Image URL" },
-  {T_BLOCK_DELETE, "Remove" },
-  {T_HK_GOTO_URL, "G" },
-  {T_HK_GO_BACK, "B" },
-  {T_HK_GO_FORWARD, "F" },
-  {T_HK_HISTORY, "H" },
-  {T_HK_RELOAD, "R" },
-  {T_HK_BOOKMARKS, "S" },
-  {T_HK_NEW_WINDOW, "N" },
-  {T_HK_SAVE_AS, "V" },
-  {T_HK_SAVE_URL_AS, "U" },
-  {T_HK_SAVE_FORMATTED_DOCUMENT, "D" },
-  {T_HK_COPY_URL_LOCATION, "C" },
-  {T_HK_KILL_BACKGROUND_CONNECTIONS, "K" },
-  {T_HK_KILL_ALL_CONNECTIONS, "T" },
-  {T_HK_FLUSH_ALL_CACHES, "C" },
-  {T_HK_RESOURCE_INFO, "I" },
-  {T_HK_MEMORY_INFO, "M" },
-  {T_HK_OS_SHELL, "O" },
-  {T_HK_RESIZE_TERMINAL, "Z" },
-  {T_HK_EXIT, "X" },
-  {T_HK_SEARCH, "S" },
-  {T_HK_SEARCH_BACK, "B" },
-  {T_HK_FIND_NEXT, "N" },
-  {T_HK_FIND_PREVIOUS, "P" },
-  {T_HK_TOGGLE_HTML_PLAIN, "H" },
-  {T_HK_DOCUMENT_INFO, "I" },
-  {T_HK_HEADER_INFO, "E" },
-  {T_HK_FRAME_AT_FULL_SCREEN, "F" },
-  {T_HK_HTML_OPTIONS, "O" },
-  {T_HK_COLOR, "C" },
-  {T_HK_SAVE_HTML_OPTIONS, "A" },
-  {T_HK_LANGUAGE, "L" },
-  {T_HK_CHARACTER_SET, "H" },
-  {T_HK_TERMINAL_OPTIONS, "T" },
-  {T_HK_SCREEN_MARGINS, "M" },
-  {T_HK_VIDEO_OPTIONS, "V" },
-  {T_HK_NETWORK_OPTIONS, "N" },
-  {T_HK_CONNECTIONS, "C" },
-  {T_HK_IPV6_OPTIONS, "I" },
-  {T_HK_PROXIES, "P" },
-  {T_HK_SSL_OPTIONS, "L" },
-  {T_HK_HTTP_OPTIONS, "H" },
-  {T_HK_FTP_OPTIONS, "F" },
-  {T_HK_SMB_OPTIONS, "S" },
-  {T_HK_JAVASCRIPT_OPTIONS, "J" },
-  {T_HK_MISCELANEOUS_OPTIONS, "O" },
-  {T_HK_CACHE, "C" },
-  {T_HK_MAIL_AND_TELNEL, "M" },
-  {T_HK_ASSOCIATIONS, "A" },
-  {T_HK_FILE_EXTENSIONS, "E" },
-  {T_HK_BLOCK_LIST, "B" },
-  {T_HK_SAVE_OPTIONS, "S" },
-  {T_HK_ABOUT, "A" },
-  {T_HK_KEYS, "K" },
-  {T_HK_COPYING, "C" },
-  {T_HK_MANUAL, "M" },
-  {T_HK_HOMEPAGE, "H" },
-  {T_HK_CALIBRATION, "L" },
-  {T_HK_FILE, "F" },
-  {T_HK_VIEW, "V" },
-  {T_HK_LINK, "L" },
-  {T_HK_DOWNLOADS, "D" },
-  {T_HK_WINDOWS, "W" },
-  {T_HK_SETUP, "S" },
-  {T_HK_HELP, "H" },
-  {T_HK_DISPLAY_USEMAP, "U" },
-  {T_HK_FOLLOW_LINK, "F" },
-  {T_HK_OPEN_IN_NEW_WINDOW, "W" },
-  {T_HK_DOWNLOAD_LINK, "D" },
-  {T_HK_RESET_FORM, "R" },
-  {T_HK_SUBMIT_FORM, "S" },
-  {T_HK_SUBMIT_FORM_AND_OPEN_IN_NEW_WINDOW, "W" },
-  {T_HK_SUBMIT_FORM_AND_DOWNLOAD, "D" },
-  {T_HK_VIEW_IMAGE, "I" },
-  {T_HK_DOWNLOAD_IMAGE, "G" },
-  {T_HK_SCALE_IMAGE_TO_FULL_SCREEN, "S" },
-  {T_HK_COPY_LINK_LOCATION, "C" },
-  {T_HK_BLOCK_URL, "B" },
-  {T_HK_XTERM, "X" },
-  {T_HK_TWTERM, "T" },
-  {T_HK_SCREEN, "S" },
-  {T_HK_WINDOW, "W" },
-  {T_HK_FULL_SCREEN, "F" },
-  {T_HK_BEOS_TERMINAL, "B" },
-  {T_URL_MANUAL, "http://links.twibright.com/user_en.html" },
-  {T_URL_HOMEPAGE, "http://links.twibright.com/" },
-  {T_URL_CALIBRATION, "http://links.twibright.com/calibration.html" },
-  { 0, NULL }
+  { "us-ascii" },
+  { "English" },
+  { "en" },
+  { "ISO-8859-1" },
+  { "OK" },
+  { "Cancel" },
+  { "Bad number" },
+  { "Number expected in field" },
+  { "Number out of range" },
+  { "Bad string" },
+  { "Empty string not allowed" },
+  { "Bad IP address" },
+  { "Invalid IP address syntax" },
+  { "Unable to use local IP address" },
+  { "Config error" },
+  { "Unable to write to config file" },
+  { "Home directory inaccessible" },
+  { "Bookmark error" },
+  { "Unable to write to bookmark file" },
+  { "About" },
+  { "Links " VERSION "\n\nText and graphics WWW browser" },
+  { "Version" },
+  { "Version information" },
+  { "Links version" },
+  { "Operating system type" },
+  { "Operating system version" },
+  { "Compiler" },
+  { "Word size" },
+  { "Memory" },
+  { "file size" },
+  { "Debugging level" },
+  { "Event handler" },
+  { "Select syscall" },
+  { "disabled" },
+  { "IPv6" },
+  { "Not enabled in system" },
+  { "Local network only" },
+  { "UTF-8 terminal" },
+  { "Compression methods" },
+  { "Encryption" },
+  { "no certificate verification" },
+  { "GPM mouse driver" },
+  { "Xterm for OS/2" },
+  { "Graphics mode" },
+  { "Image libraries" },
+  { "OpenMP" },
+  { "Not used in text mode" },
+  { "Disabled" },
+  { "thread" },
+  { "threads" },
+  { "threads" },
+  { "Configuration directory" },
+  { "None" },
+  { "Keys" },
+  { "ESC       display menu\n^C, q, Q  quit\np, l      scroll up, down\n[, ]      scroll left, right\nup, down  select link\nH, L      select top/bottom link\n->        follow link\n<-, z     go back\n', x      go forward\nTAB       switch frames\ng         go to url\nG         go to url based on current url\n^G        go to url based on current link\n*         toggle image displaying\n^W        complete URL or search string\n^B,^X,^V,^K copy, cut, paste, cut line to/from clipboard\nAlt-1 .. Alt-9 switch virtual screens (svgalib and fb)" },
+  { "a, w      cursor to status line or title\n{, }      cursor to start/end of a line\n^Y,^T,y,t,^O go to next/previous link/word/form entry" },
+  { "Copying" },
+  { "Links " VERSION "\n\n" LINKS_COPYRIGHT "\n\nThis program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version." },
+  { "Resources" },
+  { "Memory cache" },
+  { "Decompressed cache" },
+  { "Font cache" },
+  { "Image cache" },
+  { "Formatted document cache" },
+  { "DNS cache" },
+  { "TLS session cache" },
+  { "handles" },
+  { "timers" },
+  { "waiting" },
+  { "connecting" },
+  { "transferring" },
+  { "keepalive" },
+  { "bytes" },
+  { "letters" },
+  { "files" },
+  { "locked" },
+  { "loading" },
+  { "images" },
+  { "documents" },
+  { "servers" },
+  { "bytes of memory allocated" },
+  { "blocks" },
+  { "bytes allocated as large blocks" },
+  { "large blocks" },
+  { "bytes requested from system" },
+  { "blocks" },
+  { "bytes of javascript memory allocated" },
+  { "Memory info" },
+  { "No history" },
+  { "No downloads" },
+  { "No frames" },
+  { "VT 100 frames" },
+  { "Linux or OS/2 frames" },
+  { "KOI8-R frames" },
+  { "FreeBSD frames" },
+  { "Use ^[[11m" },
+  { "Restrict frames in cp850/852" },
+  { "Block cursor" },
+  { "Color" },
+  { "Braille terminal" },
+  { "Terminal options" },
+  { "Screen margins" },
+  { "Left margin" },
+  { "Right margin" },
+  { "Top margin" },
+  { "Bottom margin" },
+  { "Margins too large" },
+  { "The entered values are too large for the current screen" },
+  { "Network options" },
+  { "IPv6 options" },
+  { "Default system preference" },
+  { "Prefer IPv4" },
+  { "Prefer IPv6" },
+  { "Use only IPv4" },
+  { "Use only IPv6" },
+  { "Proxies" },
+  { "HTTP proxy (host:port)" },
+  { "FTP proxy (host:port)" },
+  { "HTTPS proxy (host:port)" },
+  { "Socks4A proxy (user@host:port)" },
+  { "Append text to hostname (for specifying tor exit node)" },
+  { "Connect only via proxies or Socks (useful for tor)" },
+  { "Direct access (w/o proxy) domains (comma separated)" },
+  { "SSL options" },
+  { "Accept invalid certificates and weak ciphers" },
+  { "Warn on invalid certificate or weak cipher" },
+  { "Reject invalid certificates and weak ciphers" },
+  { "Use built-in certificates" },
+  { "Client certificate key file" },
+  { "Client certificate file" },
+  { "Client certificate password (won't be saved in config file)" },
+  { "Bad file" },
+  { "The file does not exist" },
+  { "The file has invalid format" },
+  { "Error initializing built-in certificates" },
+  { "failed" },
+  { "Connections" },
+  { "Max connections" },
+  { "Max connections to one host" },
+  { "Retries (0 - unlimited)" },
+  { "Receive timeout (sec)" },
+  { "Timeout when unrestartable" },
+  { "Timeout when trying multiple addresses" },
+  { "Bind to local IP address" },
+  { "... IPv6 address" },
+  { "Async DNS lookup" },
+  { "Set time of downloaded files" },
+  { "Cache options" },
+  { "Memory cache size (KiB)" },
+  { "Image cache size (KiB)" },
+  { "Font cache size (KiB)" },
+  { "Number of formatted documents" },
+  { "Aggressive cache" },
+  { "Html options" },
+  { "Display tables" },
+  { "Display frames" },
+  { "Break long lines" },
+  { "Display images" },
+  { "Display image filenames" },
+  { "Display links to images" },
+  { "Move by columns in table" },
+  { "Links are numbered" },
+  { "Auto refresh" },
+  { "Allow opening links in new window (target=\"_blank\")" },
+  { "Text margin" },
+  { "Default codepage" },
+  { "Ignore charset info sent by server" },
+  { "Text" },
+  { "Link" },
+  { "Background" },
+  { "Ignore document color" },
+  { "Black" },
+  { "Red" },
+  { "Green" },
+  { "Yellow" },
+  { "Dark blue" },
+  { "Magenta" },
+  { "Cyan" },
+  { "White" },
+  { "Dark grey" },
+  { "Bright red" },
+  { "Bright green" },
+  { "Bright yellow" },
+  { "Bright blue" },
+  { "Bright magenta" },
+  { "Bright cyan" },
+  { "Bright white" },
+  { "Go to URL" },
+  { "Go back" },
+  { "Go forward" },
+  { "History" },
+  { "Reload" },
+  { "New window" },
+  { "Save as" },
+  { "Save URL as" },
+  { "Save formatted document" },
+  { "Copy current URL location" },
+  { "Kill background connections" },
+  { "Kill all connections" },
+  { "Flush all caches" },
+  { "Resource info" },
+  { "OS shell" },
+  { "Exit" },
+  { "Search" },
+  { "Search backward" },
+  { "Find next" },
+  { "Find previous" },
+  { "Toggle html/plain" },
+  { "Document info" },
+  { "Frame at full-screen" },
+  { "Save html options" },
+  { "Character set" },
+  { "Default" },
+  { "Cache" },
+  { "Mail and telnet" },
+  { "Mail, telnet and shell" },
+  { "Associations" },
+  { "File extensions" },
+  { "Save options" },
+  { "File" },
+  { "View" },
+  { "Link" },
+  { "Downloads" },
+  { "Windows" },
+  { "Setup" },
+  { "Help" },
+  { "Enter URL" },
+  { "Save URL" },
+  { "Download" },
+  { "Save to file" },
+  { "Search for text" },
+  { "(p" },
+  { " of " },
+  { ")" },
+  { "Formatting document" },
+  { "Searching" },
+  { "Waiting in queue" },
+  { "Looking up host" },
+  { "Making connection" },
+  { "Making connection to another address" },
+  { "Making Socks connection" },
+  { "SSL negotiation" },
+  { "Request sent" },
+  { "Logging in" },
+  { "Getting headers" },
+  { "Server is processing request" },
+  { "Transferring" },
+  { "Interrupted" },
+  { "Socket exception" },
+  { "Internal error" },
+  { "Out of memory" },
+  { "Host not found" },
+  { "Proxy not found" },
+  { "Error writing to socket" },
+  { "Error reading from socket" },
+  { "Data modified" },
+  { "Bad URL syntax" },
+  { "Bad proxy syntax" },
+  { "Receive timeout" },
+  { "Request must be restarted" },
+  { "Can't get socket state" },
+  { "Cyclic redirect" },
+  { "Too large file" },
+  { "Bad HTTP response" },
+  { "HTTP 100 (\?\?\?)" },
+  { "No content" },
+  { "HTTPS forwarding failed" },
+  { "Invalid certificate" },
+  { "Downgraded SSL/TLS method" },
+  { "Insecure cipher" },
+  { "Unknown file type" },
+  { "Error opening file" },
+  { "Bad FTP response" },
+  { "FTP service unavailable" },
+  { "Bad FTP login" },
+  { "FTP PORT command failed" },
+  { "File not found" },
+  { "FTP file error" },
+  { "SSL error" },
+  { "This version of Links does not contain SSL/TLS support" },
+  { "Bad Socks version (4a is required)" },
+  { "Socks connection rejected or failed" },
+  { "Socks proxy can't connect to identd server" },
+  { "Bad Socks userid" },
+  { "Unknown Socks error" },
+  { "No smb client program installed (supported is smbclient or smbc)" },
+  { "This URL is in your blocklist" },
+  { "Hyperlinks to the SMB protocol are not allowed" },
+  { "Hyperlinks to local files are not allowed" },
+  { "No proxy for this connection and connections without proxies are disabled" },
+  { "Unknown error" },
+  { "Received" },
+  { "of" },
+  { "avg" },
+  { "cur" },
+  { "Average speed" },
+  { "Speed" },
+  { "current speed" },
+  { "Elapsed time" },
+  { "estimated time" },
+  { "Background" },
+  { "Abort" },
+  { "Abort and delete file" },
+  { "Yes" },
+  { "No" },
+  { "Directory" },
+  { "File already exists" },
+  { "already exists as an active download." },
+  { "already exists." },
+  { "Do you wish to continue download or overwrite file?" },
+  { "Do you wish to overwrite it?" },
+  { "Continue" },
+  { "Overwrite" },
+  { "Rename" },
+  { "Download error" },
+  { "Could not create file" },
+  { "Error downloading" },
+  { "Error loading" },
+  { "Could not create file" },
+  { "Could not create temporary file" },
+  { "Error calling lseek on file" },
+  { "Too large file sequence" },
+  { "Unknown type" },
+  { "Content type is" },
+  { "Do you want to open, save or display this file?" },
+  { "Do you want to open or display this file?" },
+  { "Do you want to save or display this file?" },
+  { "Save" },
+  { "Display" },
+  { "What to do?" },
+  { "Do you want to open file with" },
+  { "save it or display it?" },
+  { "Open" },
+  { "Open with" },
+  { "Do you want to follow redirect and post form data to url" },
+  { "Do you want to post form data to url" },
+  { "Do you want to repost form data to url" },
+  { "Warning" },
+  { "Error" },
+  { "Welcome" },
+  { "Welcome to links!" },
+  { "To display menu, press ESC or click on the top line in window. Select Help->Manual in menu for user's manual." },
+  { "Label" },
+  { "Content-Type(s) (comma-separated)" },
+  { "Program ('%' is replaced with file name)" },
+  { "Block terminal while program running" },
+  { "Run on terminal" },
+  { "Run in X-Window" },
+  { "Ask before opening" },
+  { "Accepts HTTP URLs" },
+  { "Accepts FTP URLs" },
+  { "Delete association" },
+  { "association" },
+  { "Extension(s) (comma-separated)" },
+  { "Content-Type" },
+  { "Delete extension" },
+  { "Extension" },
+  { "extension" },
+  { "Error while posting form" },
+  { "Could not get file" },
+  { "Reading files is not allowed" },
+  { "No previous search" },
+  { "Search string not found" },
+  { "Save error" },
+  { "Error writing to file" },
+  { "Display usemap" },
+  { "Follow link" },
+  { "Open in new window" },
+  { "Download link" },
+  { "Reset form" },
+  { "Submit form" },
+  { "Submit form and open in new window" },
+  { "Submit form and download" },
+  { "View image" },
+  { "Download image" },
+  { "Scale image to full screen" },
+  { "No link selected" },
+  { "Image" },
+  { "Usemap" },
+  { "Xterm" },
+  { "Twterm" },
+  { "Screen" },
+  { "Window" },
+  { "Full screen" },
+  { "BeOS terminal" },
+  { "Unable to open new window" },
+  { "Javascript" },
+  { "Submit form to" },
+  { "Post form to" },
+  { "Radio button" },
+  { "Checkbox" },
+  { "Select field" },
+  { "Text field" },
+  { "Text area" },
+  { "File upload" },
+  { "Password field" },
+  { "Button" },
+  { "name" },
+  { "value" },
+  { "hit ENTER to" },
+  { "submit to" },
+  { "post to" },
+  { "Info" },
+  { "Header info" },
+  { "No page is displayed" },
+  { "The document doesn't have a header" },
+  { "URL" },
+  { "IP address" },
+  { "IP addresses" },
+  { "Size" },
+  { "compressed with" },
+  { "incomplete" },
+  { "Codepage" },
+  { "assumed" },
+  { "ignoring server setting" },
+  { "Server" },
+  { "Date" },
+  { "Last modified" },
+  { "SSL cipher" },
+  { "Language" },
+  { "Default" },
+  { "Go to link" },
+  { "Enter link number" },
+  { "Resize terminal" },
+  { "Columns" },
+  { "Rows" },
+  { "Goto" },
+  { "Close" },
+  { "Folder" },
+  { "folder" },
+  { "Add" },
+  { "Delete" },
+  { "Edit" },
+  { "Move" },
+  { "No items selected. Use the key \"*\" to select items to move." },
+  { "Unselect all" },
+  { "Bookmarks" },
+  { "bookmark" },
+  { "Add bookmark" },
+  { "Add association" },
+  { "Add extension" },
+  { "Add folder" },
+  { "Bookmark title" },
+  { "Edit bookmark" },
+  { "Edit association" },
+  { "Edit extension" },
+  { "Delete bookmark" },
+  { "Edit folder" },
+  { "Delete folder" },
+  { "is not empty. Do you really want to delete it?" },
+  { "Bookmark manager" },
+  { "Associations manager" },
+  { "Extensions manager" },
+  { "url" },
+  { "Name" },
+  { "Exit Links" },
+  { "Do you really want to close window?" },
+  { "Do you really want to exit Links?" },
+  { "Do you really want to exit Links (and terminate all downloads)?" },
+  { "HTTP options" },
+  { "FTP options" },
+  { "SMB options" },
+  { "HTTP bug workarounds" },
+  { "Use HTTP/1.0" },
+  { "Allow blacklist of buggy servers" },
+  { "Do not send Accept-Charset" },
+  { "Do not advertise compression support" },
+  { "Retry on internal server errors (50x)" },
+  { "Header options" },
+  { "HTTP header options" },
+  { "Fake Firefox (improves privacy)" },
+  { "Send \"do not track\" request" },
+  { "No referer" },
+  { "Send requested URL as referer" },
+  { "Fixed referer" },
+  { "Send real referer only to the same server" },
+  { "Send real referer (normal operation, INSECURE!!!)" },
+  { "Fixed HTTP Referer" },
+  { "Fake User-Agent" },
+  { "Extra header string ('\\' means newline)" },
+  { "Password for anonymous login" },
+  { "Use passive FTP" },
+  { "Use EPRT/EPSV commands on IPv4" },
+  { "Set IP Type Of Service" },
+  { "Allow hyperlinks to SMB protocol. Disabling this improves security, because internet sites cannot exploit possible bugs in the SMB client." },
+  { "User's manual" },
+  { "Home page" },
+  { "Calibration" },
+  { "Mail program (% is replaced with address)" },
+  { "Shell for executing external commands (% is replaced with command)" },
+  { "Telnet program (% is replaced with \"host\" or \"host port\")" },
+  { "Magnet program (% is replaced with URL)" },
+  { "Tn3270 program (% is replaced with \"host\" or \"host port\")" },
+  { "MMS program (% is replaced with URL)" },
+  { "Mail and telnet programs" },
+  { "Mail, telnet and shell programs" },
+  { "No program" },
+  { "No program specified for" },
+  { "mail" },
+  { "telnet" },
+  { "magnet" },
+  { "tn3270" },
+  { "mms" },
+  { "Bad mailto url" },
+  { "Bad telnet url" },
+  { "Bad tn3270 url" },
+  { "MMS url contains inacceptable characters" },
+  { "Authorization required" },
+  { "Proxy authorization required" },
+  { "User ID" },
+  { "Password" },
+  { "Enter username for " },
+  { "at " },
+  { "The server " },
+  { " doesn't have a valid certificate. Do you want to connect to it anyway?" },
+  { " uses downgraded SSL/TLS method. Do you want to connect to it anyway?" },
+  { " uses insecure cipher. Do you want to connect to it anyway?" },
+  { "Waiting for redirect confirmation" },
+  { "Decompression error" },
+  { "Error decompressing " },
+  { " with " },
+  { "Error in compressed data" },
+  { "Unknown compression method" },
+  { "Are you sure to delete" },
+  { "Bookmarks are already in use!" },
+  { "Associations are already in use!" },
+  { "Extensions are already in use!" },
+  { "Video options" },
+  { "Recommended user gamma setting:\n1.33 for dark room, 1.11 for very dim room, 1 for usual computer workspace lighting, 0.88 for bright environment lighting." },
+  { "Red display gamma" },
+  { "Green display gamma" },
+  { "Blue display gamma" },
+  { "User gamma" },
+  { "Aspect ratio" },
+  { "Dither letters" },
+  { "Dither images" },
+  { "8-bit gamma correction" },
+  { "16-bit gamma correction" },
+  { "Auto gamma correction (according to FPU speed)" },
+  { "RGB palette 8x8x4" },
+  { "RGB palette 6x6x6" },
+  { "Switch palette" },
+  { "Overwrite screen instead of scrolling it" },
+  { "Alert" },
+  { "Question" },
+  { "Kill script" },
+  { "Kill all scripts" },
+  { "Javascript killed by user." },
+  { "Javascript is trying to close the browser window. Do you really want to close the window?" },
+  { "Enter string" },
+  { "Javascript options" },
+  { "Enable javascript" },
+  { "Verbose javascript errors" },
+  { "Verbose javascript warnings" },
+  { "Miscellaneous options" },
+  { "Javascript error" },
+  { "Javascript warning" },
+  { "Dismiss" },
+  { "Menu font size" },
+  { "User font size" },
+  { "Turn off warnings" },
+  { "Bookmarks encoding" },
+  { "Javascript is attempting to go to URL" },
+  { "Javascript is attempting open a new window with URL" },
+  { "Javascript is attempting to go into history" },
+  { "to url" },
+  { "Goto history" },
+  { "Allow" },
+  { "Reject" },
+  { "Enable all conversions" },
+  { "Enable global name resolution" },
+  { "Manual javascript operations confirmation" },
+  { "Recursion depth" },
+  { "Background color" },
+  { "Foreground color" },
+  { "Scroll-bar bar color" },
+  { "Scroll-bar area color" },
+  { "Scroll-bar frame color" },
+  { "Bookmarks file" },
+  { "Save URL history on exit" },
+  { "Enter colors as sRGB hexadecimal RRGGBB triplets." },
+  { "Memory dedicated to javascript (KiB)" },
+  { "Scale all images by (%)" },
+  { "Autoscale single images" },
+  { "Display optimization for CRT" },
+  { "Display optimization for LCD (RGB)" },
+  { "Display optimization for LCD (BGR)" },
+  { "Keyboard codepage" },
+  { "Copy link location" },
+  { "Block image" },
+  { "Blocked images" },
+  { "Blocked images" },
+  { "Blocked images is already open" },
+  { "Image blocking manager" },
+  { "Add Image URL to block" },
+  { "Edit Image URL" },
+  { "Remove" },
+  { "G" },
+  { "B" },
+  { "F" },
+  { "H" },
+  { "R" },
+  { "S" },
+  { "N" },
+  { "V" },
+  { "U" },
+  { "D" },
+  { "C" },
+  { "K" },
+  { "T" },
+  { "C" },
+  { "I" },
+  { "M" },
+  { "O" },
+  { "Z" },
+  { "X" },
+  { "S" },
+  { "B" },
+  { "N" },
+  { "P" },
+  { "H" },
+  { "I" },
+  { "E" },
+  { "F" },
+  { "O" },
+  { "C" },
+  { "A" },
+  { "L" },
+  { "H" },
+  { "T" },
+  { "M" },
+  { "V" },
+  { "N" },
+  { "C" },
+  { "I" },
+  { "P" },
+  { "L" },
+  { "H" },
+  { "F" },
+  { "S" },
+  { "J" },
+  { "O" },
+  { "C" },
+  { "M" },
+  { "A" },
+  { "E" },
+  { "B" },
+  { "S" },
+  { "A" },
+  { "K" },
+  { "C" },
+  { "M" },
+  { "H" },
+  { "L" },
+  { "F" },
+  { "V" },
+  { "L" },
+  { "D" },
+  { "W" },
+  { "S" },
+  { "H" },
+  { "U" },
+  { "F" },
+  { "W" },
+  { "D" },
+  { "R" },
+  { "S" },
+  { "W" },
+  { "D" },
+  { "I" },
+  { "G" },
+  { "S" },
+  { "C" },
+  { "B" },
+  { "X" },
+  { "T" },
+  { "S" },
+  { "W" },
+  { "F" },
+  { "B" },
+  { "http://links.twibright.com/user_en.html" },
+  { "http://links.twibright.com/" },
+  { "http://links.twibright.com/calibration.html" },
 };
diff --git a/links.h b/links.h
@@ -158,14 +158,18 @@ do {									\
 	fatal_exit("ERROR: arithmetic overflow at %s:%d", __FILE__, __LINE__);\
 } while (1)
 
-#define test_int_overflow(x, y)						\
-	(~((unsigned)(x) ^ (unsigned)(y)) & ((unsigned)(x) ^ ((unsigned)(x) + (unsigned)(y))) & (1U << (sizeof(unsigned) * 8 - 1)))
+static inline int test_int_overflow(int x, int y, int *result)
+{
+	int z = *result = (int)((unsigned)(x) + (unsigned)(y));
+	return ~((unsigned)(x) ^ (unsigned)(y)) & ((unsigned)(x) ^ ((unsigned)(z))) & (1U << (sizeof(unsigned) * 8 - 1));
+}
 
 static inline int safe_add_function(int x, int y, unsigned char *file, int line)
 {
-	if (test_int_overflow(x, y))
+	int ret;
+	if (test_int_overflow(x, y, &ret))
 		fatal_exit("ERROR: arithmetic overflow at %s:%d: %d + %d", file, line, (x), (y));
-	return (int)((unsigned)x + (unsigned)y);
+	return ret;
 }
 
 #define safe_add(x, y)	safe_add_function(x, y, (unsigned char *)__FILE__, __LINE__)
@@ -733,7 +737,6 @@ void change_connection(struct status *, struct status *, int);
 void detach_connection(struct status *, off_t, int, int);
 void abort_all_connections(void);
 void abort_background_connections(void);
-void abort_all_keepalive_connections(void);
 int is_entry_used(struct cache_entry *);
 void clear_connection_timeout(struct connection *);
 void set_connection_timeout(struct connection *);
@@ -932,6 +935,8 @@ void mailto_func(struct session *, unsigned char *);
 #define KBD_END		-0x10b
 #define KBD_PAGE_UP	-0x10c
 #define KBD_PAGE_DOWN	-0x10d
+#define KBD_MENU	-0x10e
+#define KBD_STOP	-0x10f
 
 #define KBD_F1		-0x120
 #define KBD_F2		-0x121
@@ -946,13 +951,30 @@ void mailto_func(struct session *, unsigned char *);
 #define KBD_F11		-0x12a
 #define KBD_F12		-0x12b
 
+#define KBD_UNDO	-0x140
+#define KBD_REDO	-0x141
+#define KBD_FIND	-0x142
+#define KBD_HELP	-0x143
+#define KBD_COPY	-0x144
+#define KBD_PASTE	-0x145
+#define KBD_CUT		-0x146
+#define KBD_PROPS	-0x147
+#define KBD_FRONT	-0x148
+#define KBD_OPEN	-0x149
+#define KBD_BACK	-0x14a
+#define KBD_FORWARD	-0x14b
+#define KBD_RELOAD	-0x14c
+#define KBD_BOOKMARKS	-0x14d
+
+#define KBD_ESCAPE_MENU(x)	((x) <= KBD_F1 && (x) > KBD_CTRL_C)
+
 #define KBD_CTRL_C	-0x200
 #define KBD_CLOSE	-0x201
 
 #define KBD_SHIFT	1
 #define KBD_CTRL	2
 #define KBD_ALT		4
-#define KBD_PASTE	8
+#define KBD_PASTING	8
 
 void handle_trm(int, void *, int);
 void free_all_itrms(void);
@@ -1006,16 +1028,12 @@ void *lru_lookup(struct lru *cache, void *templ, struct lru_entry **row);
 
 /* drivers.c */
 
-struct irgb {
-	int r,g,b; /* 0xffff=full white, 0x0000=full black */
-};
-
 /* Bitmap is allowed to pass only to that driver from which was obtained.
  * It is forbidden to get bitmap from svga driver and pass it to X driver.
  * It is impossible to get an error when registering a bitmap
  */
-struct bitmap{
-	int x,y; /* Dimensions */
+struct bitmap {
+	int x, y; /* Dimensions */
 	int skip; /* Byte distance between vertically consecutive pixels */
 	void *data; /* Pointer to room for topleft pixel */
 	void *flags; /* Allocation flags for the driver */
@@ -1049,6 +1067,8 @@ struct graphics_device {
 	void (*mouse_handler)(struct graphics_device *dev, int x, int y, int buttons);
 };
 
+struct driver_param;
+
 struct graphics_driver {
 	unsigned char *name;
 	unsigned char *(*init_driver)(unsigned char *param, unsigned char *display);	/* param is get from get_driver_param and saved into configure file */
@@ -1086,16 +1106,18 @@ struct graphics_driver {
 	void (*fill_area)(struct graphics_device *dev, int x1, int y1, int x2, int y2, long color);
 	void (*draw_hline)(struct graphics_device *dev, int left, int y, int right, long color);
 	void (*draw_vline)(struct graphics_device *dev, int x, int top, int bottom, long color);
-	int (*scroll)(struct graphics_device *dev, struct rect_set **set, int sc, const int h);
+	int (*scroll)(struct graphics_device *dev, struct rect_set **set, int scx, int scy);
 	 /* When scrolling, the empty spaces will have undefined contents. */
 	 /* returns:
 	    0 - the caller should not care about redrawing, redraw will be sent
 	    1 - the caller should redraw uncovered area */
 	 /* when set is not NULL rectangles in the set (uncovered area) should be redrawn */
-	void (*set_clip_area)(struct graphics_device *dev, struct rect *r);
+	void (*set_clip_area)(struct graphics_device *dev);
 
 	void (*flush)(struct graphics_device *dev);
 
+	void (*set_palette)(void);
+
 	void (*set_title)(struct graphics_device *dev, unsigned char *title);
 		/* set window title. title is in utf-8 encoding -- you should recode it to device charset */
 		/* if device doesn't support titles (svgalib, framebuffer), this should be NULL, not empty function ! */
@@ -1114,14 +1136,16 @@ struct graphics_driver {
 
 	int depth; /* Data layout
 		    * depth
-		    *  8 7 6 5 4 3 2 1 0
-		    * +-+---------+-----+
-		    * | |         |     |
-		    * +-+---------+-----+
+		    *  4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+		    * +---------+-+-+---------+-----+
+		    * +         | | |         |     |
+		    * +---------+-+-+---------+-----+
 		    *
-		    * 0 - 2 Number of bytes per pixel in passed bitmaps
-		    * 3 - 7 Number of significant bits per pixel -- 1, 4, 8, 15, 16, 24
-		    * 8   0-- normal order, 1-- misordered.Has the same value as vga_misordered from the VGA mode.
+		    *  0 - 2  Number of bytes per pixel in passed bitmaps
+		    *  3 - 7  Number of significant bits per pixel -- 1, 4, 8, 15, 16, 24
+		    *  8      0 -- normal order, 1 -- misordered.Has the same value as vga_misordered from the VGA mode.
+		    *  9      1 -- misordered (0rgb)
+		    * 10 - 14 1 -- dither to the requested number of bits
 		    *
 		    * This number is to be used by the layer that generates images.
 		    * Memory layout for 1 bytes per pixel is:
@@ -1145,15 +1169,7 @@ struct graphics_driver {
 		    */
 	int x, y;	/* size of screen. only for drivers that use virtual devices */
 	int flags;	/* GD_xxx flags */
-	int kbd_codepage;
-	unsigned char *shell;
-		/* -if exec is NULL string is unused
-		   -otherwise this string describes shell to be executed by the
-		    exec function, the '%' char means string to be executed
-		   -shell cannot be NULL
-		   -if exec is !NULL and shell is empty, exec should use some
-		    default shell (e.g. "xterm -e %")
-		*/
+	struct driver_param *param;
 };
 
 #define GD_DONT_USE_SCROLL	1
@@ -1163,9 +1179,40 @@ struct graphics_driver {
 #define GD_NOAUTO		16
 #define GD_NO_OS_SHELL		32
 #define GD_NO_LIBEVENT		64
+#define GD_SELECT_PALETTE	128
+#define GD_SWITCH_PALETTE	256
 
 extern struct graphics_driver *drv;
 
+#define CLIP_DRAW_BITMAP				\
+	if (!is_rect_valid(&dev->clip)) return;		\
+	if (!bmp->x || !bmp->y) return;			\
+	if (x >= dev->clip.x2) return;			\
+	if (x + bmp->x <= dev->clip.x1) return;		\
+	if (y >= dev->clip.y2) return;			\
+	if (y + bmp->y <= dev->clip.y1) return;		\
+
+#define CLIP_FILL_AREA					\
+	if (x1 < dev->clip.x1) x1 = dev->clip.x1;	\
+	if (x2 > dev->clip.x2) x2 = dev->clip.x2;	\
+	if (y1 < dev->clip.y1) y1 = dev->clip.y1;	\
+	if (y2 > dev->clip.y2) y2 = dev->clip.y2;	\
+	if (x1 >= x2 || y1 >= y2) return;		\
+
+#define CLIP_DRAW_HLINE					\
+	if (y < dev->clip.y1) return;			\
+	if (y >= dev->clip.y2) return;			\
+	if (x1 < dev->clip.x1) x1 = dev->clip.x1;	\
+	if (x2 > dev->clip.x2) x2 = dev->clip.x2;	\
+	if (x1 >= x2) return;				\
+
+#define CLIP_DRAW_VLINE					\
+	if (x < dev->clip.x1) return;			\
+	if (x >= dev->clip.x2) return;			\
+	if (y1 < dev->clip.y1) y1 = dev->clip.y1;	\
+	if (y2 > dev->clip.y2) y2 = dev->clip.y2;	\
+	if (y1 >= y2) return;				\
+
 void add_graphics_drivers(unsigned char **s, int *l);
 unsigned char *init_graphics(unsigned char *, unsigned char *, unsigned char *);
 void shutdown_graphics(void);
@@ -1176,7 +1223,27 @@ extern struct graphics_device **virtual_devices;
 extern int n_virtual_devices;
 extern struct graphics_device *current_virtual_device;
 
-void generic_set_clip_area(struct graphics_device *dev, struct rect *r);
+static inline int is_rect_valid(struct rect *r)
+{
+	return r->x1 < r->x2 && r->y1 < r->y2;
+}
+int do_rects_intersect(struct rect *, struct rect *);
+void intersect_rect(struct rect *, struct rect *, struct rect *);
+void unite_rect(struct rect *, struct rect *, struct rect *);
+struct rect_set *init_rect_set(void);
+void add_to_rect_set(struct rect_set **, struct rect *);
+void exclude_rect_from_set(struct rect_set **, struct rect *);
+static inline void exclude_from_set(struct rect_set **s, int x1, int y1, int x2, int y2)
+{
+	struct rect r;
+	r.x1 = x1, r.x2 = x2, r.y1 = y1, r.y2 = y2;
+	exclude_rect_from_set(s, &r);
+}
+
+void set_clip_area(struct graphics_device *dev, struct rect *r);
+int restrict_clip_area(struct graphics_device *dev, struct rect *r, int x1, int y1, int x2, int y2);
+
+struct rect_set *g_scroll(struct graphics_device *dev, int scx, int scy);
 
 /* dip.c */
 
@@ -1238,9 +1305,6 @@ struct style {
 	int mono_height; /* Height of the space if mono_space is >=0
 			  * undefined otherwise
 			  */
-	/*
-	unsigned char font[1];
-	*/
 };
 
 struct font_cache_entry {
@@ -1318,6 +1382,8 @@ struct style *g_invert_style(struct style *);
 void g_free_style(struct style *style0);
 struct style *g_clone_style(struct style *);
 
+extern tcount gamma_stamp;
+
 extern long gamma_cache_color;
 extern int gamma_cache_rgb;
 
@@ -1506,7 +1572,6 @@ unsigned char get_attribute(int, int);
 struct terminal *init_term(int, int, void (*)(struct window *, struct links_event *, int));
 #ifdef G
 struct terminal *init_gfx_term(void (*)(struct window *, struct links_event *, int), unsigned char *, void *, int);
-int restrict_clip_area(struct graphics_device *, struct rect *, int, int, int, int);
 #endif
 struct term_spec *new_term_spec(unsigned char *);
 void free_term_specs(void);
@@ -1526,24 +1591,6 @@ void flush_terminal(struct terminal *);
 #ifdef G
 
 void set_window_pos(struct window *, int, int, int, int);
-int do_rects_intersect(struct rect *, struct rect *);
-void intersect_rect(struct rect *, struct rect *, struct rect *);
-void unite_rect(struct rect *, struct rect *, struct rect *);
-int is_rect_valid(struct rect *);
-
-struct rect_set *init_rect_set(void);
-void add_to_rect_set(struct rect_set **, struct rect *);
-void exclude_rect_from_set(struct rect_set **, struct rect *);
-static inline void exclude_from_set(struct rect_set **s, int x1, int y1, int x2, int y2)
-{
-	struct rect r;
-	r.x1 = x1;
-	r.x2 = x2;
-	r.y1 = y1;
-	r.y2 = y2;
-	exclude_rect_from_set(s, &r);
-}
-
 void t_redraw(struct graphics_device *, struct rect *);
 void t_resize(struct graphics_device *);
 void t_kbd(struct graphics_device *, int, int);
@@ -1553,7 +1600,7 @@ void t_mouse(struct graphics_device *, int, int, int);
 
 /* text only */
 void set_char(struct terminal *, int, int, unsigned, unsigned char);
-chr *get_char(struct terminal *, int, int);
+const chr *get_char(struct terminal *, int, int);
 void set_color(struct terminal *, int, int, unsigned char);
 void set_only_char(struct terminal *, int, int, unsigned, unsigned char);
 void set_line(struct terminal *, int, int, int, chr *);
@@ -1750,16 +1797,35 @@ struct form_control {
 	list_entry_last
 };
 
+struct line_info {
+	int st_offs;
+	int en_offs;
+	int chars;
+};
+
+struct format_text_cache_entry {
+	int width;
+	int wrap;
+	int cp;
+	int last_state;
+	int last_vpos;
+	int last_vypos;
+	int last_cursor;
+	int n_lines;
+	struct line_info ln[1];
+};
+
 struct form_state {
 	int form_num;	/* cislo formulare */
 	int ctrl_num;	/* identifikace polozky v ramci formulare */
 	int g_ctrl_num;	/* identifikace polozky mezi vsemi polozkami (poradi v poli form_info) */
 	int position;
 	int type;
-	unsigned char *value; /* selected value of a select item */
+	unsigned char *string; /* selected value of a select item */
 	int state; /* index of selected item of a select item */
 	int vpos;
 	int vypos;
+	struct format_text_cache_entry *ftce;
 };
 
 struct link {
@@ -1961,10 +2027,10 @@ struct image_map {
 };
 
 struct background {
-	union {
-		int sRGB; /* This is 3*8 bytes with sRGB_gamma (in sRGB space).
-			     This is not rounded. */
-	} u;
+	int sRGB; /* This is 3*8 bytes with sRGB_gamma (in sRGB space).
+		     This is not rounded. */
+	long color;
+	tcount gamma_stamp;
 };
 
 struct f_data_c;
@@ -2155,7 +2221,7 @@ struct g_object_image {
 	unsigned char *orig_src;
 	unsigned char *src;
 	int background; /* Remembered background from insert_image
-			 * (g_part->root->bg->u.sRGB)
+			 * (g_part->root->bg->sRGB)
 			 */
 	int xyw_meaning;
 
@@ -2741,6 +2807,7 @@ void activate_keys(struct session *ses);
 void reset_settings_for_tor(void);
 int save_proxy(int charset, unsigned char *result, unsigned char *proxy);
 int save_noproxy_list(int charset, unsigned char *result, unsigned char *noproxy_list);
+void dialog_html_options(struct session *ses);
 void activate_bfu_technology(struct session *, int);
 void dialog_goto_url(struct session *ses, unsigned char *url);
 void dialog_save_url(struct session *ses);
@@ -2755,10 +2822,6 @@ void exit_prog(struct terminal *, void *, void *);
 void really_exit_prog(void *ses_);
 void query_exit(struct session *ses);
 
-#ifdef G
-extern tcount gamma_stamp;
-#endif
-
 /* charsets.c */
 
 struct conv_table {
@@ -2842,21 +2905,15 @@ int textptr_diff(unsigned char *t2, unsigned char *t1, int cp);
 
 extern int ismap_link, ismap_x, ismap_y;
 
-struct line_info {
-	unsigned char *st;
-	unsigned char *en;
-};
-
-struct line_info *format_text(unsigned char *text, int width, int wrap, int cp);
-
 void frm_download(struct session *, struct f_data_c *);
 void frm_download_image(struct session *, struct f_data_c *);
 void frm_view_image(struct session *, struct f_data_c *);
+struct format_text_cache_entry *format_text(struct f_data_c *fd, struct form_control *fc, struct form_state *fs);
+int area_cursor(struct f_data_c *f, struct form_control *fc, struct form_state *fs);
 struct form_state *find_form_state(struct f_data_c *, struct form_control *);
 void fixup_select_state(struct form_control *fc, struct form_state *fs);
 int enter(struct session *ses, struct f_data_c *f, int a);
-int field_op(struct session *ses, struct f_data_c *f, struct link *l, struct links_event *ev, int rep);
-int area_cursor(struct f_data_c *f, struct form_control *form, struct form_state *fs);
+int field_op(struct session *ses, struct f_data_c *f, struct link *l, struct links_event *ev);
 
 int can_open_in_new(struct terminal *);
 void open_in_new_window(struct terminal *, void *fn_, void *ses_);
@@ -2894,7 +2951,6 @@ void set_frame(struct session *, struct f_data_c *, int);
 struct f_data_c *current_frame(struct session *);
 void reset_form(struct f_data_c *f, int form_num);
 void set_textarea(struct session *, struct f_data_c *, int);
-void free_format_text_cache(void);
 
 /* font_inc.c */
 
@@ -3041,7 +3097,6 @@ static inline void intersect(int s1, int l1, int s2, int l2, int *s3, int *l3)
 }
 
 
-void g_draw_background(struct graphics_device *dev, struct background *bg, int x, int y, int xw, int yw);
 int g_forward_mouse(struct f_data_c *fd, struct g_object *a, int x, int y, int b);
 
 void draw_vscroll_bar(struct graphics_device *dev, int x, int y, int yw, int total, int view, int pos);
@@ -3073,7 +3128,7 @@ void g_area_get_list(struct g_object *, void (*)(struct g_object *parent, struct
 void draw_one_object(struct f_data_c *fd, struct g_object *o);
 void draw_title(struct f_data_c *f);
 void draw_graphical_doc(struct terminal *t, struct f_data_c *scr, int active);
-int g_next_link(struct f_data_c *fd, int dir);
+int g_next_link(struct f_data_c *fd, int dir, int do_scroll);
 int g_frame_ev(struct session *ses, struct f_data_c *fd, struct links_event *ev);
 void g_find_next(struct f_data_c *f, int);
 
@@ -3366,7 +3421,9 @@ void create_frame(struct frame_param *fp);
 void release_image_map(struct image_map *map);
 int is_in_area(struct map_area *a, int x, int y);
 
-struct background *get_background(unsigned char *bg, unsigned char *bgcolor);
+struct background *g_get_background(unsigned char *bg, unsigned char *bgcolor);
+void g_release_background(struct background *bg);
+void g_draw_background(struct graphics_device *dev, struct background *bg, int x, int y, int xw, int yw);
 
 void g_x_extend_area(struct g_object_area *a, int width, int height, int align);
 struct g_part *g_format_html_part(unsigned char *, unsigned char *, int, int, int, unsigned char *, int, unsigned char *, unsigned char *, struct f_data *);
@@ -3414,12 +3471,20 @@ void save_url_history(void);
 struct driver_param {
 	list_entry_1st
 	int kbd_codepage;
+	int palette_mode;
 	unsigned char *param;
-	unsigned char *shell;
+	unsigned char shell_term[MAX_STR_LEN];
 	int nosave;
 	list_entry_last
 	unsigned char name[1];
 };
+		/* -if exec is NULL, shell_term is unused
+		   -otherwise this string describes shell to be executed by the
+		    exec function, the '%' char means string to be executed
+		   -shell cannot be NULL
+		   -if exec is !NULL and shell is empty, exec should use some
+		    default shell (e.g. "xterm -e %")
+		*/
 
 struct driver_param *get_driver_param(unsigned char *);
 
diff --git a/listedit.c b/listedit.c
@@ -396,7 +396,7 @@ static int draw_bfu_element(struct terminal * term, int x, int y, unsigned char 
 			drv->fill_area(dev,x+(int)(4.75*BFU_GRX_WIDTH),y,x+5*BFU_GRX_WIDTH,y+BFU_GRX_HEIGHT,b);
 		}
 
-		drv->set_clip_area(dev, &r);
+		set_clip_area(dev, &r);
 		return BFU_ELEMENT_WIDTH;
 	}
 #endif
@@ -428,7 +428,7 @@ static struct list *next_in_tree(struct list_description *ld, struct list *item)
 	if (!(item->type & 1) || (item->type & 2))  /* item or opened folder */
 		return list_next(item);
 	/* skip content of this folder */
-	do item=list_next(item); while (item->depth > depth);   /* must stop on head 'cause it's depth is -1 */
+	do item = list_next(item); while (item->depth > depth);   /* must stop on head 'cause it's depth is -1 */
 	return item;
 }
 
@@ -470,13 +470,13 @@ static struct list *prev_in_tree(struct list_description *ld, struct list *item)
 #ifdef G
 static int get_total_items(struct list_description *ld)
 {
-	struct list*l=ld->list;
-	int count=0;
+	struct list *l = ld->list;
+	int count = 0;
 
 	do{
-		l=next_in_tree(ld,l);
+		l = next_in_tree(ld, l);
 		count++;
-	}while(l!=ld->list);
+	} while (l != ld->list);
 
 	return count;
 }
@@ -484,11 +484,11 @@ static int get_total_items(struct list_description *ld)
 
 static int get_scroll_pos(struct list_description *ld)
 {
-	struct list*l;
-	int count;
+	struct list *l;
+	int count = 0;
 
-	for (l=ld->list,count=0;l!=ld->win_offset;l=next_in_tree(ld,l),count++)
-		;
+	for (l = ld->list; l != ld->win_offset; l = next_in_tree(ld,l))
+		count++;
 
 	return count;
 }
@@ -496,13 +496,13 @@ static int get_scroll_pos(struct list_description *ld)
 
 static int get_visible_items(struct list_description *ld)
 {
-	struct list*l=ld->win_offset;
-	int count=0;
+	struct list *l = ld->win_offset;
+	int count = 0;
 
 	do{
-		l=next_in_tree(ld,l);
+		l = next_in_tree(ld,l);
 		count++;
-	}while(count<ld->n_items&&l!=ld->list);
+	} while (count < ld->n_items && l != ld->list);
 
 	return count;
 }
@@ -510,15 +510,16 @@ static int get_visible_items(struct list_description *ld)
 
 static struct list *find_last_in_window(struct list_description *ld)
 {
-	struct list*l=ld->win_offset;
-	struct list *x=l;
-	int count=0;
+	struct list *l = ld->win_offset;
+	struct list *x = l;
+	int count = 0;
 
 	do{
-		l=next_in_tree(ld,l);
+		l = next_in_tree(ld, l);
 		count++;
-		if (l!=ld->list&&count!=ld->n_items)x=l;
-	}while(count<ld->n_items&&l!=ld->list);
+		if (l != ld->list && count != ld->n_items)
+			x = l;
+	} while (count < ld->n_items && l != ld->list);
 
 	return x;
 }
@@ -528,11 +529,11 @@ static struct list *find_last_in_window(struct list_description *ld)
 
 static int get_win_pos(struct list_description *ld)
 {
-	struct list*l;
-	int count;
+	struct list *l;
+	int count = 0;
 
-	for (l=ld->win_offset,count=0;l!=ld->current_pos;l=next_in_tree(ld,l),count++)
-		;
+	for (l = ld->win_offset; l != ld->current_pos; l = next_in_tree(ld, l))
+		count++;
 
 	return count;
 }
@@ -686,13 +687,13 @@ static int list_item_move(struct dialog_data *dlg, struct dialog_item_data *usel
 		struct list *behind_next = next_in_tree(ld, behind);	/* to se musi pocitat pokazdy, protoze by se nam mohlo stat, ze to je taky oznaceny */
 		struct list *item_last = list_prev(next); /* last item of moved block */
 
+		if (!(i->type & 4)) { i = next; continue; }
 		if (is_parent(ld, ld->current_pos, i)) { /* we're moving directory into itself - let's behave like item was not selected */
 			i->type &= ~4;
 			i = next;
 			count++;
 			continue;
 		}
-		if (!(i->type & 4)) { i = next; continue; }
 
 		if ((i->type & 3) == 3) { /* dirty trick */
 			i->type &= ~2;
@@ -918,7 +919,6 @@ static int list_item_delete(struct dialog_data *dlg,struct dialog_item_data *use
 	struct terminal *term=dlg->win->term;
 	struct list_description *ld=(struct list_description*)(dlg->dlg->udata2);
 	struct list *item=ld->current_pos;
-	/*struct session *ses=(struct session *)(dlg->dlg->udata);*/
 	unsigned char *txt;
 	struct ve_skodarne_je_jeste_vetsi_narez *narez;
 
@@ -975,34 +975,38 @@ static int list_item_delete(struct dialog_data *dlg,struct dialog_item_data *use
 	return 0;
 }
 
-static int redraw_list_element(struct terminal *term, struct dialog_data *dlg, int y, int w, struct list_description *ld, struct list *l)
+static void redraw_list_element(struct terminal *term, struct dialog_data *dlg, int y, int w, struct list_description *ld, struct list *l)
 {
 	struct list *lx;
 	unsigned char *xp;
 	int xd;
 	unsigned char *txt;
 	int x=0;
-	int text_position;
 	unsigned char color = 0;
 	long bgcolor = 0, fgcolor = 0;
 	int b;
 	unsigned char element;
 
 	if (!F) {
-		color=(l==ld->current_pos)?COLOR_MENU_SELECTED:COLOR_MENU_TEXT;
+		color = l == ld->current_pos ? COLOR_MENU_SELECTED : COLOR_MENU_TEXT;
+	}
 #ifdef G
-	} else {
-		int bgc=(l==ld->current_pos)?G_BFU_FG_COLOR:G_BFU_BG_COLOR;
-		int fgc=(l==ld->current_pos)?G_BFU_BG_COLOR:G_BFU_FG_COLOR;
-
-		bgcolor=dip_get_color_sRGB(bgc);
-		fgcolor=dip_get_color_sRGB(fgc);
-#endif
+	else {
+		struct rect r;
+		r.x1 = dlg->x + DIALOG_LB;
+		r.x2 = dlg->x + DIALOG_LB + w;
+		r.y1 = y;
+		r.y2 = y + G_BFU_FONT_SIZE;
+		if (dlg->s) exclude_rect_from_set(&dlg->s, &r);
+		if (!do_rects_intersect(&r, &term->dev->clip))
+			return;
+		bgcolor = l == ld->current_pos ? bfu_fg_color : bfu_bg_color;
+		fgcolor = l == ld->current_pos ? bfu_bg_color : bfu_fg_color;
 	}
+#endif
 
-	txt=ld->type_item(term, l,1);
-	if (!txt)
-	{
+	txt = ld->type_item(term, l, 1);
+	if (!txt) {
 		txt = stracpy(cast_uchar "");
 	}
 
@@ -1014,7 +1018,7 @@ static int redraw_list_element(struct terminal *term, struct dialog_data *dlg, i
 			element = BFU_ELEMENT_TEE;
 			if (list_next(l) == ld->list)
 				element = BFU_ELEMENT_L;
-			x+=draw_bfu_element(term,dlg->x+DIALOG_LB,y,color,bgcolor,fgcolor,element,(l->type)&4);
+			x += draw_bfu_element(term, dlg->x + DIALOG_LB, y, color, bgcolor, fgcolor, element, l->type & 4);
 			break;
 		case 1:
 			xp = xmalloc(l->depth + 1);
@@ -1027,31 +1031,29 @@ static int redraw_list_element(struct terminal *term, struct dialog_data *dlg, i
 					if (!xd) break;
 				}
 			}
-			for (b=0;b<l->depth;b++)
-				x+=draw_bfu_element(term,dlg->x+DIALOG_LB+x,y,color,bgcolor,fgcolor,xp[b] ? BFU_ELEMENT_PIPE : BFU_ELEMENT_EMPTY,0);
-			if (l->depth>=0)  /* everything except head */
-			{
+			for (b = 0; b < l->depth; b++)
+				x += draw_bfu_element(term, dlg->x + DIALOG_LB+x, y, color, bgcolor, fgcolor, xp[b] ? BFU_ELEMENT_PIPE : BFU_ELEMENT_EMPTY, 0);
+			if (l->depth >= 0) {  /* everything except head */
 				int o = xp[l->depth];
-				switch((l->type)&1)
-				{
+				switch (l->type & 1) {
 					case 0:  /* item */
-					element=o ? BFU_ELEMENT_TEE : BFU_ELEMENT_L;
-					break;
+						element = o ? BFU_ELEMENT_TEE : BFU_ELEMENT_L;
+						break;
 
 					case 1:  /* directory */
-					if (l->type & 2) {
-						element = o ? BFU_ELEMENT_OPEN_DOWN : BFU_ELEMENT_OPEN;
-					} else {
-						element = o ? BFU_ELEMENT_CLOSED_DOWN : BFU_ELEMENT_CLOSED;
-					}
-					break;
+						if (l->type & 2) {
+							element = o ? BFU_ELEMENT_OPEN_DOWN : BFU_ELEMENT_OPEN;
+						} else {
+							element = o ? BFU_ELEMENT_CLOSED_DOWN : BFU_ELEMENT_CLOSED;
+						}
+						break;
 
 					default:  /* this should never happen */
-					internal("=8-Q  lunacy level too high! Call "BOHNICE".\n");
-					element=BFU_ELEMENT_EMPTY;
+						internal("=8-Q  lunacy level too high! Call "BOHNICE".\n");
+						element = BFU_ELEMENT_EMPTY;
 
 				}
-				x+=draw_bfu_element(term,dlg->x+DIALOG_LB+x,y,color,bgcolor,fgcolor,element,(l->type)&4);
+				x += draw_bfu_element(term, dlg->x + DIALOG_LB + x, y, color, bgcolor, fgcolor, element, l->type & 4);
 			}
 			free(xp);
 			break;
@@ -1065,71 +1067,60 @@ static int redraw_list_element(struct terminal *term, struct dialog_data *dlg, i
 		}
 	}
 
-	text_position = x;
-	if (!F)
-	{
-		print_text(term,dlg->x+x+DIALOG_LB,y,w-x,txt,color);
+	if (!F) {
+		print_text(term, dlg->x + x + DIALOG_LB, y, w-x, txt, color);
 		x += strlen((char *)txt);
-		fill_area(term,dlg->x+DIALOG_LB+x,y,w-x,1,' ',0);
-		set_line_color(term,dlg->x+DIALOG_LB+x,y,w-x,color);
+		fill_area(term, dlg->x+DIALOG_LB+x, y, w-x, 1, ' ', 0);
+		set_line_color(term, dlg->x + DIALOG_LB + x, y, w-x, color);
 	}
 #ifdef G
-	else
-	{
+	else {
 		struct rect old_area;
-		struct style* stl=(l==ld->current_pos)?bfu_style_wb:bfu_style_bw;
-
-		restrict_clip_area(term->dev,&old_area,dlg->x+x+DIALOG_LB,y,dlg->x+DIALOG_LB+w,y+G_BFU_FONT_SIZE);
-		g_print_text(term->dev,dlg->x+x+DIALOG_LB,y,stl,txt,0);
-		x+=g_text_width(stl,txt);
-		drv->fill_area(term->dev,dlg->x+DIALOG_LB+x,y,dlg->x+DIALOG_LB+w,y+G_BFU_FONT_SIZE,bgcolor);
-		drv->set_clip_area(term->dev,&old_area);
-		if (dlg->s)exclude_from_set(&(dlg->s),dlg->x+DIALOG_LB,y,dlg->x+DIALOG_LB+w,y+G_BFU_FONT_SIZE);
+		struct style *stl = l == ld->current_pos ? bfu_style_wb : bfu_style_bw;
+
+		restrict_clip_area(term->dev, &old_area, dlg->x + x + DIALOG_LB, y, dlg->x + DIALOG_LB + w, y + G_BFU_FONT_SIZE);
+		g_print_text(term->dev, dlg->x + x + DIALOG_LB, y, stl, txt, NULL);
+		x += g_text_width(stl, txt);
+		drv->fill_area(term->dev, dlg->x + DIALOG_LB + x, y, dlg->x + DIALOG_LB + w, y + G_BFU_FONT_SIZE, bgcolor);
+		set_clip_area(term->dev, &old_area);
 	}
 #endif
 	free(txt);
-	return text_position;
 }
 
 /* redraws list */
 static void redraw_list(struct terminal *term, void *bla)
 {
-	struct redraw_data* rd=(struct redraw_data *)bla;
-	struct list_description *ld=rd->ld;
-	struct dialog_data *dlg=rd->dlg;
-	/*struct session *ses=(struct session*)(dlg->dlg->udata);*/
-	int y,a;
+	struct redraw_data* rd = (struct redraw_data *)bla;
+	struct list_description *ld = rd->ld;
+	struct dialog_data *dlg = rd->dlg;
+	int y, a;
 	struct list *l;
-	int w=dlg->xw-2*DIALOG_LB-(F?sirka_scrollovadla:0);
-	y=dlg->y+DIALOG_TB;
+	int w = dlg->xw - 2 * DIALOG_LB - (F ? sirka_scrollovadla : 0);
+	y = dlg->y + DIALOG_TB;
 
 #ifdef G
-	if (F)
-	{
-		int total=get_total_items(ld);
-		int visible=get_visible_items(ld);
-		int pos=get_scroll_pos(ld);
-		struct rect old_area;
-
-		restrict_clip_area(term->dev,&old_area,dlg->x+w+DIALOG_LB+G_SCROLL_BAR_WIDTH,y,dlg->x+DIALOG_LB+w+sirka_scrollovadla,y+G_BFU_FONT_SIZE*ld->n_items);
-		drv->set_clip_area(term->dev,&old_area);
-		draw_vscroll_bar(term->dev,dlg->x+DIALOG_LB+w+G_SCROLL_BAR_WIDTH,y,G_BFU_FONT_SIZE*ld->n_items,total,visible,pos);
-		if (dlg->s)exclude_from_set(&(dlg->s),dlg->x+DIALOG_LB+w+G_SCROLL_BAR_WIDTH,y,dlg->x+DIALOG_LB+w+sirka_scrollovadla,y+G_BFU_FONT_SIZE*ld->n_items);
+	if (F) {
+		int total = get_total_items(ld);
+		int visible = get_visible_items(ld);
+		int pos = get_scroll_pos(ld);
+		draw_vscroll_bar(term->dev, dlg->x + DIALOG_LB + w + G_SCROLL_BAR_WIDTH, y, G_BFU_FONT_SIZE * ld->n_items, total, visible, pos);
+		if (dlg->s) exclude_from_set(&dlg->s, dlg->x + DIALOG_LB + w + G_SCROLL_BAR_WIDTH, y, dlg->x + DIALOG_LB + w + sirka_scrollovadla, y + G_BFU_FONT_SIZE * ld->n_items);
 	}
 #endif
 
-	for (a=0,l=ld->win_offset;a<ld->n_items;) {
+	for (a = 0, l = ld->win_offset; a < ld->n_items; ) {
 		redraw_list_element(term, dlg, y, w, ld, l);
-		l=next_in_tree(ld, l);
+		l = next_in_tree(ld, l);
 		a++;
-		y+=gf_val(1,G_BFU_FONT_SIZE);
-		if (l==ld->list) break;
+		y += gf_val(1, G_BFU_FONT_SIZE);
+		if (l == ld->list) break;
 	}
-	if (!F) fill_area(term,dlg->x+DIALOG_LB,y,w,ld->n_items-a,' ',COLOR_MENU_TEXT);
+	if (!F) fill_area(term, dlg->x + DIALOG_LB, y, w, ld->n_items-a, ' ', COLOR_MENU_TEXT);
 #ifdef G
 	else {
-		drv->fill_area(term->dev,dlg->x+DIALOG_LB,y,dlg->x+DIALOG_LB+w,dlg->y+DIALOG_TB+(ld->n_items)*G_BFU_FONT_SIZE,dip_get_color_sRGB(G_BFU_BG_COLOR));
-		if (dlg->s) exclude_from_set(&(dlg->s),dlg->x+DIALOG_LB,y,dlg->x+DIALOG_LB+w,dlg->y+DIALOG_TB+(ld->n_items)*G_BFU_FONT_SIZE);
+		drv->fill_area(term->dev, dlg->x + DIALOG_LB, y, dlg->x + DIALOG_LB + w, dlg->y + DIALOG_TB + ld->n_items * G_BFU_FONT_SIZE, dip_get_color_sRGB(G_BFU_BG_COLOR));
+		if (dlg->s) exclude_from_set(&dlg->s, dlg->x + DIALOG_LB, y, dlg->x + DIALOG_LB + w, dlg->y + DIALOG_TB + ld->n_items * G_BFU_FONT_SIZE);
 	}
 #endif
 }
@@ -1139,20 +1130,19 @@ static void redraw_list(struct terminal *term, void *bla)
 /* direction: -1=old is previous, +1=old is next */
 static void redraw_list_line(struct terminal *term, void *bla)
 {
-	struct redraw_data *rd=(struct redraw_data *)bla;
-	struct list_description *ld=rd->ld;
-	struct dialog_data *dlg=rd->dlg;
-	/*struct session *ses=(struct session *)(dlg->dlg->udata);*/
-	int direction=rd->n;
-	int w=dlg->xw-2*DIALOG_LB-(F?sirka_scrollovadla:0);
-	int y=dlg->y+DIALOG_TB+gf_val(ld->win_pos,ld->win_pos*G_BFU_FONT_SIZE);
+	struct redraw_data *rd = (struct redraw_data *)bla;
+	struct list_description *ld = rd->ld;
+	struct dialog_data *dlg = rd->dlg;
+	int direction = rd->n;
+	int w = dlg->xw - 2 * DIALOG_LB - (F ? sirka_scrollovadla : 0);
+	int y = dlg->y + DIALOG_TB + gf_val(ld->win_pos, ld->win_pos * G_BFU_FONT_SIZE);
 	struct list *l;
 
 	redraw_list_element(term, dlg, y, w, ld, ld->current_pos);
 	if (!F && !term->spec->block_cursor) {
 		set_cursor(term, dlg->x + DIALOG_LB, y, dlg->x + DIALOG_LB, y);
 	}
-	y+=gf_val(direction, direction*G_BFU_FONT_SIZE);
+	y += gf_val(direction, direction * G_BFU_FONT_SIZE);
 	switch (direction) {
 		case 0:
 			l = NULL;
@@ -1178,69 +1168,63 @@ static void redraw_list_line(struct terminal *term, void *bla)
 static void scroll_list(struct terminal *term, void *bla)
 {
 #ifdef G
-	struct redraw_data *rd=(struct redraw_data *)bla;
-	struct list_description *ld=rd->ld;
-	struct dialog_data *dlg=rd->dlg;
-	int direction=rd->n;
-	struct rect_set *set;
+	struct redraw_data *rd = (struct redraw_data *)bla;
+	struct list_description *ld = rd->ld;
+	struct dialog_data *dlg = rd->dlg;
+	int direction = rd->n;
 #endif
 
-	if (!F)
-	{
+	if (!F) {
 		redraw_list(term, bla);
-#ifdef G
 	}
-	else
-	{
+#ifdef G
+	else {
 		struct rect old_area;
-		struct graphics_device *dev=term->dev;
-		int w=dlg->xw-2*DIALOG_LB-sirka_scrollovadla;
-		int y=dlg->y+DIALOG_TB;
-		int top=0,bottom=0;
+		struct graphics_device *dev = term->dev;
+		int w = dlg->xw-2 * DIALOG_LB - sirka_scrollovadla;
+		int y = dlg->y + DIALOG_TB;
+		int top = 0, bottom = 0;
 
-		switch(direction)
-		{
+		switch(direction) {
 			case 1:  /* down */
-			top=G_BFU_FONT_SIZE;
-			break;
+				top = G_BFU_FONT_SIZE;
+				break;
 
 			case -1:  /* up */
-			bottom=-G_BFU_FONT_SIZE;
-			break;
+				bottom = -G_BFU_FONT_SIZE;
+				break;
 
 			default:
-			internal("Wrong direction %d in function scroll_list.\n",direction);
+				internal("Wrong direction %d in function scroll_list.\n",direction);
 		}
 
-		restrict_clip_area(term->dev,&old_area,dlg->x+DIALOG_LB,y+top,dlg->x+DIALOG_LB+w,y+bottom+G_BFU_FONT_SIZE*(ld->n_items));
+		restrict_clip_area(term->dev, &old_area, dlg->x + DIALOG_LB, y + top, dlg->x + DIALOG_LB + w, y + bottom + G_BFU_FONT_SIZE * ld->n_items);
 		if (drv->flags & GD_DONT_USE_SCROLL && overwrite_instead_of_scroll)
-			goto redraw_all;
-		set=NULL;
-		drv->scroll(dev, &set, top + bottom, 0);
-
-		if (set)	/* redraw rectangles in the set - we cannot redraw particular rectangles, we are only able to redraw whole window */
-		{
-			free(set);
-redraw_all:
 			redraw_list(term, bla);
+		else {
+			int j;
+			struct rect_set *rs = g_scroll(dev, 0, top + bottom);
+			for (j = 0; j < rs->m; j++) {
+				struct rect *r = &rs->r[j];
+				struct rect clip1;
+				restrict_clip_area(term->dev, &clip1, r->x1, r->y1, r->x2, r->y2); 
+				redraw_list(term, bla);
+				set_clip_area(term->dev, &clip1);
+			}
+			free(rs);
 		}
-		drv->set_clip_area(term->dev,&old_area);
+		set_clip_area(term->dev, &old_area);
 
 		/* redraw scroll bar */
 		{
-			int total=get_total_items(ld);
-			int visible=get_visible_items(ld);
-			int pos=get_scroll_pos(ld);
-			struct rect old_area;
-
-			restrict_clip_area(term->dev,&old_area,dlg->x+w+DIALOG_LB+G_SCROLL_BAR_WIDTH,y,dlg->x+DIALOG_LB+w+sirka_scrollovadla,y+G_BFU_FONT_SIZE*ld->n_items);
-			drv->set_clip_area(term->dev,&old_area);
-			draw_vscroll_bar(term->dev,dlg->x+DIALOG_LB+w+G_SCROLL_BAR_WIDTH,y,G_BFU_FONT_SIZE*ld->n_items,total,visible,pos);
-			if (dlg->s)exclude_from_set(&(dlg->s),dlg->x+DIALOG_LB+w+G_SCROLL_BAR_WIDTH,y,dlg->x+DIALOG_LB+w+sirka_scrollovadla,y+G_BFU_FONT_SIZE*ld->n_items);
+			int total = get_total_items(ld);
+			int visible = get_visible_items(ld);
+			int pos = get_scroll_pos(ld);
+			draw_vscroll_bar(term->dev, dlg->x + DIALOG_LB + w + G_SCROLL_BAR_WIDTH, y, G_BFU_FONT_SIZE * ld->n_items, total, visible,pos);
+			if (dlg->s) exclude_from_set(&dlg->s, dlg->x + DIALOG_LB + w + G_SCROLL_BAR_WIDTH, y, dlg->x + DIALOG_LB + w + sirka_scrollovadla, y + G_BFU_FONT_SIZE * ld->n_items);
 		}
-
-#endif
 	}
+#endif
 }
 
 
@@ -1329,7 +1313,7 @@ static int list_event_handler(struct dialog_data *dlg, struct links_event *ev)
 	switch ((int)ev->ev)
 	{
 		case EV_KBD:
-		if (ev->y & KBD_PASTE) break;
+		if (ev->y & KBD_PASTING) break;
 		if (ld->type==1)  /* tree list */
 		{
 			if (ev->x==' ')  /* toggle folder */
@@ -1354,7 +1338,7 @@ static int list_event_handler(struct dialog_data *dlg, struct links_event *ev)
 				return EVENT_PROCESSED;
 			}
 		}
-		if (ev->x=='/') /* search forward */
+		if (ev->x == '/' || (ev->x == KBD_FIND && !(ev->y & (KBD_SHIFT | KBD_CTRL | KBD_ALT)))) /* search forward */
 		{
 			struct redraw_data *r;
 
@@ -1365,7 +1349,7 @@ static int list_event_handler(struct dialog_data *dlg, struct links_event *ev)
 			input_field(ses->term, getml(r,NULL), TEXT_(T_SEARCH), TEXT_(T_SEARCH_FOR_TEXT), r, ld->search_history, MAX_INPUT_URL_LEN, cast_uchar "", 0, 0, NULL, 2, TEXT_(T_OK), list_search_for, TEXT_(T_CANCEL), input_field_null);
 			return EVENT_PROCESSED;
 		}
-		if (ev->x=='?') /* search back */
+		if (ev->x == '?' || (ev->x == KBD_FIND && ev->y & (KBD_SHIFT | KBD_CTRL | KBD_ALT))) /* search back */
 		{
 			struct redraw_data *r;
 
@@ -1376,12 +1360,12 @@ static int list_event_handler(struct dialog_data *dlg, struct links_event *ev)
 			input_field(ses->term, getml(r,NULL), TEXT_(T_SEARCH_BACK), TEXT_(T_SEARCH_FOR_TEXT), r, ld->search_history, MAX_INPUT_URL_LEN, cast_uchar "", 0, 0, NULL, 2, TEXT_(T_OK), list_search_for_back, TEXT_(T_CANCEL), input_field_null);
 			return EVENT_PROCESSED;
 		}
-		if (ev->x=='n') /* find next */
+		if ((ev->x == 'n' && !(ev->y & KBD_ALT)) || ev->x == KBD_REDO) /* find next */
 		{
 			list_find_next(&rd, ld->search_direction);
 			return EVENT_PROCESSED;
 		}
-		if (ev->x=='N') /* find prev */
+		if ((ev->x == 'N' && !(ev->y & KBD_ALT)) || ev->x == KBD_UNDO) /* find prev */
 		{
 			list_find_next(&rd, - ld->search_direction);
 			return EVENT_PROCESSED;
@@ -1519,8 +1503,7 @@ static int list_event_handler(struct dialog_data *dlg, struct links_event *ev)
 
 		case EV_MOUSE:
 		/* toggle select item */
-		if ((ev->b&BM_ACT)==B_DOWN&&(ev->b&BM_BUTT)==B_RIGHT)
-		{
+		if ((ev->b & BM_ACT) == B_DOWN && (ev->b & BM_BUTT) == B_RIGHT) {
 			int n,a;
 			struct list *l=ld->win_offset;
 
@@ -1552,8 +1535,7 @@ static int list_event_handler(struct dialog_data *dlg, struct links_event *ev)
 			return EVENT_PROCESSED;
 		}
 		/* click on item */
-		if (((ev->b&BM_ACT)==B_DOWN || (ev->b&BM_ACT)==B_DRAG)&&(ev->b&BM_BUTT)==B_LEFT)
-		{
+		if (((ev->b & BM_ACT) == B_DOWN || (ev->b & BM_ACT) == B_DRAG) && (ev->b & BM_BUTT) == B_LEFT) {
 			int n,a;
 			struct list *l=ld->win_offset;
 
@@ -1582,8 +1564,7 @@ static int list_event_handler(struct dialog_data *dlg, struct links_event *ev)
 			ld->current_pos=l;
 
 			/* clicked on directory graphical stuff */
-			if ((ev->b&BM_ACT)==B_DOWN&&(ld->type)&&(ev->x)<(dlg->x+DIALOG_LB+a*BFU_ELEMENT_WIDTH)&&((l->type)&1))
-			{
+			if ((ev->b & BM_ACT) == B_DOWN && ld->type && ev->x < (dlg->x + DIALOG_LB + a * BFU_ELEMENT_WIDTH) && (l->type & 1)) {
 				l->type^=2;
 				if (!(l->type&2))unselect_in_folder(ld, ld->current_pos);
 			}
@@ -1596,8 +1577,7 @@ static int list_event_handler(struct dialog_data *dlg, struct links_event *ev)
 		/* scroll with the bar */
 		skip_item_click:
 #ifdef G
-		if (F&&(((ev->b&BM_ACT)==B_DRAG||(ev->b&BM_ACT)==B_DOWN||(ev->b&BM_ACT)==B_UP)&&(ev->b&BM_BUTT)==B_LEFT))
-		{
+		if (F && (((ev->b & BM_ACT) == B_DRAG || (ev->b & BM_ACT) == B_DOWN || (ev->b & BM_ACT) == B_UP) && (ev->b & BM_BUTT) == B_LEFT)) {
 			int total=get_total_items(ld);
 			int scroll_pos;
 			int redraw_all;
@@ -1658,8 +1638,7 @@ static int list_event_handler(struct dialog_data *dlg, struct links_event *ev)
 
 		}
 #endif
-		if ((ev->b&BM_ACT)==B_DRAG&&(ev->b&BM_BUTT)==B_MIDDLE)
-		{
+		if ((ev->b & BM_ACT) == B_DRAG && (ev->b & BM_BUTT) == B_MIDDLE) {
 			long delta=(ev->y-last_mouse_y)/MOUSE_SCROLL_DIVIDER;
 
 			last_mouse_y=ev->y;
@@ -1695,8 +1674,7 @@ static int list_event_handler(struct dialog_data *dlg, struct links_event *ev)
 
 		}
 		/* mouse wheel */
-		if ((ev->b&BM_ACT)==B_MOVE&&((ev->b&BM_BUTT)==B_WHEELUP||(ev->b&BM_BUTT)==B_WHEELDOWN||(ev->b&BM_BUTT)==B_WHEELDOWN1||(ev->b&BM_BUTT)==B_WHEELUP1))
-		{
+		if ((ev->b & BM_ACT) == B_MOVE && ((ev->b & BM_BUTT) == B_WHEELUP || (ev->b & BM_BUTT) == B_WHEELDOWN || (ev->b & BM_BUTT) == B_WHEELDOWN1 || (ev->b & BM_BUTT) == B_WHEELUP1)) {
 			int button=(int)ev->b&BM_BUTT;
 			last_mouse_y=ev->y;
 
diff --git a/main.c b/main.c
@@ -457,7 +457,6 @@ static void terminate_all_subsystems(void)
 	abort_all_connections();
 
 	free_all_caches();
-	free_format_text_cache();
 	ssl_finish();
 	if (init_b)
 		save_url_history();
diff --git a/menu.c b/menu.c
@@ -609,17 +609,18 @@ static unsigned char disp_green_g[VO_GAMMA_LEN];
 static unsigned char disp_blue_g[VO_GAMMA_LEN];
 static unsigned char user_g[VO_GAMMA_LEN];
 static unsigned char aspect_str[VO_GAMMA_LEN];
-tcount gamma_stamp; /* stamp counter for gamma changes */
 
 static void reinit_video(void);
 
 static void refresh_video(void *xxx)
 {
-	display_red_gamma=atof(cast_const_char disp_red_g);
-	display_green_gamma=atof(cast_const_char disp_green_g);
-	display_blue_gamma=atof(cast_const_char disp_blue_g);
-	user_gamma=atof(cast_const_char user_g);
-	bfu_aspect=atof(cast_const_char aspect_str);
+	display_red_gamma = atof(cast_const_char disp_red_g);
+	display_green_gamma = atof(cast_const_char disp_green_g);
+	display_blue_gamma = atof(cast_const_char disp_blue_g);
+	user_gamma = atof(cast_const_char user_g);
+	bfu_aspect = atof(cast_const_char aspect_str);
+	if (F && drv->flags & (GD_SELECT_PALETTE | GD_SWITCH_PALETTE) && drv->set_palette)
+		drv->set_palette();
 	reinit_video();
 }
 
@@ -630,10 +631,6 @@ static void reinit_video(void)
 
 	/* Flush font cache */
 	update_aspect();
-	gamma_stamp++;
-
-	/* Flush dip_get_color cache */
-	gamma_cache_rgb = -2;
 
 	/* Recompute dithering tables for the new gamma */
 	init_dither(drv->depth);
@@ -662,21 +659,50 @@ static unsigned char * const video_msg_2[] = {
 	TEXT_(T_8_BIT_GAMMA_CORRECTION),
 	TEXT_(T_16_BIT_GAMMA_CORRECTION),
 	TEXT_(T_AUTO_GAMMA_CORRECTION),
+};
+
+#define video_option_select_palette    (drv->flags & GD_SELECT_PALETTE)
+#define video_option_switch_palette    (drv->flags & GD_SWITCH_PALETTE)
+#define video_option_scrolling         (drv->flags & GD_DONT_USE_SCROLL)
+
+static unsigned char * const video_msg_select_palette[] = {
+	TEXT_(T_RGB_PALETTE_6x6x6),
+	TEXT_(T_RGB_PALETTE_8x8x4),
+};
+
+static unsigned char * const video_msg_switch_palette[] = {
+	TEXT_(T_SWITCH_PALETTE),
+};
+
+static unsigned char * const video_msg_scrolling[] = {
 	TEXT_(T_OVERWRITE_SCREEN_INSTEAD_OF_SCROLLING_IT),
 };
 
 static void videoopt_fn(struct dialog_data *dlg)
 {
 	struct terminal *term = dlg->win->term;
+	struct dialog_item_data *did;
 	int max = 0, min = 0;
 	int w, rw;
 	int y = gf_val(-1, -G_BFU_FONT_SIZE);
 	max_text_width(term, video_msg_0, &max, AL_LEFT);
 	min_text_width(term, video_msg_0, &min, AL_LEFT);
-	max_group_width(term, video_msg_1, dlg->items, 5, &max);
-	min_group_width(term, video_msg_1, dlg->items, 5, &min);
-	checkboxes_width(term, video_msg_2, dlg->n-2-5, &max, max_text_width);
-	checkboxes_width(term, video_msg_2, dlg->n-2-5, &min, min_text_width);
+	max_group_width(term, video_msg_1, dlg->items, array_elements(video_msg_1), &max);
+	min_group_width(term, video_msg_1, dlg->items, array_elements(video_msg_1), &min);
+	checkboxes_width(term, video_msg_2, array_elements(video_msg_2), &max, max_text_width);
+	checkboxes_width(term, video_msg_2, array_elements(video_msg_2), &min, min_text_width);
+	if (video_option_select_palette) {
+		checkboxes_width(term, video_msg_select_palette, array_elements(video_msg_select_palette), &max, max_text_width);
+		checkboxes_width(term, video_msg_select_palette, array_elements(video_msg_select_palette), &min, min_text_width);
+	}
+	if (video_option_switch_palette) {
+		checkboxes_width(term, video_msg_switch_palette, array_elements(video_msg_switch_palette), &max, max_text_width);
+		checkboxes_width(term, video_msg_switch_palette, array_elements(video_msg_switch_palette), &min, min_text_width);
+	}
+	if (video_option_scrolling) {
+		checkboxes_width(term, video_msg_scrolling, array_elements(video_msg_scrolling), &max, max_text_width);
+		checkboxes_width(term, video_msg_scrolling, array_elements(video_msg_scrolling), &min, min_text_width);
+	}
 	max_buttons_width(term, dlg->items + dlg->n-2, 2, &max);
 	min_buttons_width(term, dlg->items + dlg->n-2, 2, &min);
 	w = dlg->win->term->x * 9 / 10 - 2 * DIALOG_LB;
@@ -687,11 +713,26 @@ static void videoopt_fn(struct dialog_data *dlg)
 	rw = 0;
 	dlg_format_text(dlg, NULL, video_msg_0, 0, &y, w, &rw, COLOR_DIALOG_TEXT, AL_LEFT);
 	y += gf_val(1, G_BFU_FONT_SIZE);
-	dlg_format_group(dlg, NULL, video_msg_1, dlg->items, 5, 0, &y, w, &rw);
+	did = dlg->items;
+	dlg_format_group(dlg, NULL, video_msg_1, did, array_elements(video_msg_1), 0, &y, w, &rw);
+	did += array_elements(video_msg_1);
 	y += gf_val(1, G_BFU_FONT_SIZE);
-	dlg_format_checkboxes(dlg, NULL, dlg->items+5, dlg->n-2-5, dlg->x + DIALOG_LB, &y, w, &rw, video_msg_2);
+	dlg_format_checkboxes(dlg, NULL, did, array_elements(video_msg_2), dlg->x + DIALOG_LB, &y, w, &rw, video_msg_2);
+	did += array_elements(video_msg_2);
+	if (video_option_select_palette) {
+		dlg_format_checkboxes(dlg, NULL, did, array_elements(video_msg_select_palette), dlg->x + DIALOG_LB, &y, w, &rw, video_msg_select_palette);
+		did += array_elements(video_msg_select_palette);
+	}
+	if (video_option_switch_palette) {
+		dlg_format_checkboxes(dlg, NULL, did, array_elements(video_msg_switch_palette), dlg->x + DIALOG_LB, &y, w, &rw, video_msg_switch_palette);
+		did += array_elements(video_msg_switch_palette);
+	}
+	if (video_option_scrolling) {
+		dlg_format_checkboxes(dlg, NULL, did, array_elements(video_msg_scrolling), dlg->x + DIALOG_LB, &y, w, &rw, video_msg_scrolling);
+		did += array_elements(video_msg_scrolling);
+	}
 	y += gf_val(1, G_BFU_FONT_SIZE);
-	dlg_format_buttons(dlg, NULL, dlg->items+dlg->n-2, 2, 0, &y, w, &rw, AL_CENTER);
+	dlg_format_buttons(dlg, NULL, did, 2, 0, &y, w, &rw, AL_CENTER);
 	w = rw;
 	dlg->xw = w + 2 * DIALOG_LB;
 	dlg->yw = y + 2 * DIALOG_TB;
@@ -700,9 +741,24 @@ static void videoopt_fn(struct dialog_data *dlg)
 	y = dlg->y + DIALOG_TB;
 	dlg_format_text(dlg, term, video_msg_0, dlg->x + DIALOG_LB, &y, w, NULL, COLOR_DIALOG_TEXT, AL_LEFT);
 	y += gf_val(2, G_BFU_FONT_SIZE);
-	dlg_format_group(dlg, term, video_msg_1, dlg->items, 5, dlg->x + DIALOG_LB, &y, w, NULL);
+	did = dlg->items;
+	dlg_format_group(dlg, term, video_msg_1, did, array_elements(video_msg_1), dlg->x + DIALOG_LB, &y, w, NULL);
+	did += array_elements(video_msg_1);
 	y += gf_val(1, G_BFU_FONT_SIZE);
-	dlg_format_checkboxes(dlg, term, dlg->items+5, dlg->n-2-5, dlg->x + DIALOG_LB, &y, w, NULL, video_msg_2);
+	dlg_format_checkboxes(dlg, term, did, array_elements(video_msg_2), dlg->x + DIALOG_LB, &y, w, NULL, video_msg_2);
+	did += array_elements(video_msg_2);
+	if (video_option_select_palette) {
+		dlg_format_checkboxes(dlg, term, did, array_elements(video_msg_select_palette), dlg->x + DIALOG_LB, &y, w, NULL, video_msg_select_palette);
+		did += array_elements(video_msg_select_palette);
+	}
+	if (video_option_switch_palette) {
+		dlg_format_checkboxes(dlg, term, did, array_elements(video_msg_switch_palette), dlg->x + DIALOG_LB, &y, w, NULL, video_msg_switch_palette);
+		did += array_elements(video_msg_switch_palette);
+	}
+	if (video_option_scrolling) {
+		dlg_format_checkboxes(dlg, term, did, array_elements(video_msg_scrolling), dlg->x + DIALOG_LB, &y, w, NULL, video_msg_scrolling);
+		did += array_elements(video_msg_scrolling);
+	}
 	y += gf_val(1, G_BFU_FONT_SIZE);
 	dlg_format_buttons(dlg, term, dlg->items+dlg->n-2, 2, dlg->x + DIALOG_LB, &y, w, NULL, AL_CENTER);
 }
@@ -731,7 +787,7 @@ static void video_options(struct terminal *term, void *xxx, void *ses_)
 	remove_zeroes(user_g);
 	snprintf(cast_char aspect_str, VO_GAMMA_LEN, "%f", bfu_aspect);
 	remove_zeroes(aspect_str);
-	d = mem_calloc(sizeof(struct dialog) + 13 * sizeof(struct dialog_item));
+	d = mem_calloc(sizeof(struct dialog) + 15 * sizeof(struct dialog_item));
 	d->title = TEXT_(T_VIDEO_OPTIONS);
 	d->fn = videoopt_fn;
 	d->refresh = refresh_video;
@@ -793,7 +849,29 @@ static void video_options(struct terminal *term, void *xxx, void *ses_)
 	d->items[a].dlen = sizeof(int);
 	d->items[a++].data = (void *)&gamma_bits;
 
-	if (drv->flags & GD_DONT_USE_SCROLL) {
+	if (video_option_select_palette) {
+		int *palette_mode_p = &drv->param->palette_mode;
+		d->items[a].type = D_CHECKBOX;
+		d->items[a].gid = 3;
+		d->items[a].gnum = 0;
+		d->items[a].dlen = sizeof(int);
+		d->items[a++].data = (void *)palette_mode_p;
+		d->items[a].type = D_CHECKBOX;
+		d->items[a].gid = 3;
+		d->items[a].gnum = 1;
+		d->items[a].dlen = sizeof(int);
+		d->items[a++].data = (void *)palette_mode_p;
+	}
+
+	if (video_option_switch_palette) {
+		int *palette_mode_p = &drv->param->palette_mode;
+		d->items[a].type = D_CHECKBOX;
+		d->items[a].gid = 0;
+		d->items[a].dlen = sizeof(int);
+		d->items[a++].data = (void *)palette_mode_p;
+	}
+
+	if (video_option_scrolling) {
 		d->items[a].type = D_CHECKBOX;
 		d->items[a].gid = 0;
 		d->items[a].dlen = sizeof(int);
@@ -1660,7 +1738,7 @@ static void net_programs(struct terminal *term, void *xxx, void *yyy)
 	if (have_extra_exec()) {
 		d->items[a].type = D_FIELD;
 		d->items[a].dlen = MAX_STR_LEN;
-		d->items[a++].data = drv->shell;
+		d->items[a++].data = drv->param->shell_term;
 	}
 #endif
 	d->items[a].type = D_BUTTON;
@@ -1876,9 +1954,8 @@ static int dlg_kb_cp(struct dialog_data *dlg, struct dialog_item_data *di)
 }
 #endif
 
-static void menu_html_options(struct terminal *term, void *xxx, void *ses_)
+void dialog_html_options(struct session *ses)
 {
-	struct session *ses = (struct session *)ses_;
 	struct dialog *d;
 	int a;
 
@@ -1996,7 +2073,13 @@ static void menu_html_options(struct terminal *term, void *xxx, void *ses_)
 	d->items[a].text = TEXT_(T_CANCEL);
 	a++;
 	d->items[a].type = D_END;
-	do_dialog(term, d, getml(d, NULL));
+	do_dialog(ses->term, d, getml(d, NULL));
+}
+
+static void menu_html_options(struct terminal *term, void *xxx, void *ses_)
+{
+	struct session *ses = (struct session *)ses_;
+	dialog_html_options(ses);
 }
 
 static unsigned char * const color_texts[] = { cast_uchar "", cast_uchar "", cast_uchar "", TEXT_(T_IGNORE_DOCUMENT_COLOR) };
@@ -2150,21 +2233,16 @@ static void refresh_misc(void *ses_)
 	struct session *ses = (struct session *)ses_;
 #ifdef G
 	if (F) {
-		struct session *ses;
-		struct list_head *lses;
-
-		menu_font_size=(int)strtol(cast_const_char menu_font_str,NULL,10);
-		G_BFU_FG_COLOR=(int)strtol(cast_const_char fg_color_str,NULL,16);
-		G_BFU_BG_COLOR=(int)strtol(cast_const_char bg_color_str,NULL,16);
-		G_SCROLL_BAR_AREA_COLOR=(int)strtol(cast_const_char scroll_area_color_str,NULL,16);
-		G_SCROLL_BAR_BAR_COLOR=(int)strtol(cast_const_char scroll_bar_color_str,NULL,16);
-		G_SCROLL_BAR_FRAME_COLOR=(int)strtol(cast_const_char scroll_frame_color_str,NULL,16);
+		menu_font_size = (int)strtol(cast_const_char menu_font_str, NULL, 10);
+		G_BFU_FG_COLOR = (int)strtol(cast_const_char fg_color_str, NULL, 16);
+		G_BFU_BG_COLOR = (int)strtol(cast_const_char bg_color_str, NULL, 16);
+		G_SCROLL_BAR_AREA_COLOR = (int)strtol(cast_const_char scroll_area_color_str, NULL, 16);
+		G_SCROLL_BAR_BAR_COLOR = (int)strtol(cast_const_char scroll_bar_color_str, NULL, 16);
+		G_SCROLL_BAR_FRAME_COLOR = (int)strtol(cast_const_char scroll_frame_color_str, NULL, 16);
 		shutdown_bfu();
 		init_bfu();
 		init_grview();
-		foreach(struct session, ses, lses, sessions) {
-			ses->term->dev->resize_handler(ses->term->dev);
-		}
+		cls_redraw_all_terminals();
 	}
 #endif
 	if (strcmp((char *)new_bookmarks_file, (char *)bookmarks_file))
@@ -2385,7 +2463,7 @@ static void miscelaneous_options(struct terminal *term, void *xxx, void *ses_)
 		d->items[a].gid = 0;
 		d->items[a].fn = dlg_kb_cp;
 		d->items[a].text = TEXT_(T_KEYBOARD_CODEPAGE);
-		d->items[a].data = (unsigned char *) &(drv->kbd_codepage);
+		d->items[a].data = (unsigned char *)&drv->param->kbd_codepage;
 		d->items[a].dlen = sizeof(int);
 		a++;
 	}
diff --git a/sched.c b/sched.c
@@ -205,7 +205,7 @@ int get_keepalive_socket(struct connection *c, int *protocol_data)
 	return 0;
 }
 
-void abort_all_keepalive_connections(void)
+static void abort_all_keepalive_connections(void)
 {
 	while (!list_empty(keepalive_connections))
 		del_keepalive_socket(list_struct(keepalive_connections.next,
diff --git a/select.c b/select.c
@@ -67,32 +67,34 @@ void portable_sleep(unsigned msec)
 
 static int can_do_io(int fd, int wr, int sec)
 {
+	fd_set fds;
+	struct timeval tv, *tvp;
+	int rs;
+
+	if (fd < 0)
+		die("can_do_io: handle %d", fd);
+
 #if defined(USE_POLL)
 	struct pollfd p;
-	int rs;
 	p.fd = fd;
 	p.events = !wr ? POLLIN : POLLOUT;
 	EINTRLOOP(rs, poll(&p, 1, sec < 0 ? -1 : sec * 1000));
 	if (rs < 0)
-		die("poll for %s (%d) failed: %s\n", !wr ? "read" : "write", fd, strerror(errno));
-	if (!rs) return 0;
+		die("poll for %s (%d) failed: %s", !wr ? "read" : "write", fd, strerror(errno));
+	if (!rs)
+		return 0;
 	if (p.revents & POLLNVAL)
-		die("poll for %s (%d) failed: %s\n", !wr ? "read" : "write", fd, strerror(errno));
+		goto fallback;
 	return 1;
-#else
-	fd_set fds;
-	struct timeval tv, *tvp;
-	int rs;
+ fallback:
+#endif
 	if (sec >= 0) {
 		tv.tv_sec = sec;
 		tv.tv_usec = 0;
 		tvp = &tv;
-	} else {
+	} else
 		tvp = NULL;
-	}
 	FD_ZERO(&fds);
-	if (fd < 0)
-		die("can_do_io: handle %d\n", fd);
 	if (fd >= (int)FD_SETSIZE)
 		die("too big handle %d\n", fd);
 	FD_SET(fd, &fds);
@@ -103,7 +105,6 @@ static int can_do_io(int fd, int wr, int sec)
 	if (rs < 0)
 		die("select for %s (%d) failed: %s\n", !wr ? "read" : "write", fd, strerror(errno));
 	return rs;
-#endif
 }
 
 int can_write(int fd)
diff --git a/string.c b/string.c
@@ -108,8 +108,25 @@ void add_unsigned_long_num_to_str(unsigned char **s, int *l, unsigned long n)
 void add_num_to_str(unsigned char **s, int *l, off_t n)
 {
 	unsigned char a[64];
-	snzprint(a, 64, n);
-	add_to_str(s, l, a);
+	if (n >= 0 && n < 1000) {
+		unsigned sn = (unsigned)n;
+		unsigned char *p = a;
+		if (sn >= 100) {
+			*p++ = '0' + sn / 100;
+			sn %= 100;
+			goto d10;
+		}
+		if (sn >= 10) {
+			d10:
+			*p++ = '0' + sn / 10;
+			sn %= 10;
+		}
+		*p++ = '0' + sn;
+		add_bytes_to_str(s, l, a, p - a);
+	} else {
+		snzprint(a, 64, n);
+		add_to_str(s, l, a);
+	}
 }
 
 void add_knum_to_str(unsigned char **s, int *l, off_t n)
diff --git a/terminal.c b/terminal.c
@@ -175,145 +175,12 @@ void cls_redraw_all_terminals(void)
 	foreach(struct terminal, term, lterm, terminals) {
 		if (!F) redraw_terminal_cls(term);
 #ifdef G
-		else {
-			t_resize(term->dev);
-		}
+		else
+			term->dev->resize_handler(term->dev);
 #endif
 	}
 }
 
-#ifdef G
-
-int do_rects_intersect(struct rect *r1, struct rect *r2)
-{
-	return (r1->x1 > r2->x1 ? r1->x1 : r2->x1) < (r1->x2 > r2->x2 ? r2->x2 : r1->x2) && (r1->y1 > r2->y1 ? r1->y1 : r2->y1) < (r1->y2 > r2->y2 ? r2->y2 : r1->y2);
-}
-
-void intersect_rect(struct rect *v, struct rect *r1, struct rect *r2)
-{
-	v->x1 = r1->x1 > r2->x1 ? r1->x1 : r2->x1;
-	v->x2 = r1->x2 > r2->x2 ? r2->x2 : r1->x2;
-	v->y1 = r1->y1 > r2->y1 ? r1->y1 : r2->y1;
-	v->y2 = r1->y2 > r2->y2 ? r2->y2 : r1->y2;
-}
-
-void unite_rect(struct rect *v, struct rect *r1, struct rect *r2)
-{
-	if (!is_rect_valid(r1)) {
-		if (v != r2) memcpy(v, r2, sizeof(struct rect));
-		return;
-	}
-	if (!is_rect_valid(r2)) {
-		if (v != r1) memcpy(v, r1, sizeof(struct rect));
-		return;
-	}
-	v->x1 = r1->x1 < r2->x1 ? r1->x1 : r2->x1;
-	v->x2 = r1->x2 < r2->x2 ? r2->x2 : r1->x2;
-	v->y1 = r1->y1 < r2->y1 ? r1->y1 : r2->y1;
-	v->y2 = r1->y2 < r2->y2 ? r2->y2 : r1->y2;
-}
-
-int is_rect_valid(struct rect *r1)
-{
-	return r1->x1 < r1->x2 && r1->y1 < r1->y2;
-}
-
-#define R_GR	8
-
-struct rect_set *init_rect_set(void)
-{
-	struct rect_set *s;
-	s = mem_calloc(sizeof(struct rect_set) + sizeof(struct rect) * R_GR);
-	s->rl = R_GR;
-	s->m = 0;
-	return s;
-}
-
-void add_to_rect_set(struct rect_set **s, struct rect *r)
-{
-	struct rect_set *ss = *s;
-	int i;
-	if (!is_rect_valid(r)) return;
-	for (i = 0; i < ss->rl; i++) if (!ss->r[i].x1 && !ss->r[i].x2 && !ss->r[i].y1 && !ss->r[i].y2) {
-		x:
-		memcpy(&ss->r[i], r, sizeof(struct rect));
-		if (i >= ss->m) ss->m = i + 1;
-		return;
-	}
-	if ((unsigned)ss->rl > (INT_MAX - sizeof(struct rect_set)) / sizeof(struct rect) - R_GR)
-		overalloc();
-	ss = xrealloc(ss,
-		sizeof(struct rect_set) + sizeof(struct rect) * (ss->rl + R_GR));
-	memset(&(*s = ss)->r[i = (ss->rl += R_GR) - R_GR], 0, sizeof(struct rect) * R_GR);
-	goto x;
-}
-
-void exclude_rect_from_set(struct rect_set **s, struct rect *r)
-{
-	int i, a;
-	struct rect *rr;
-	do {
-		a = 0;
-		for (i = 0; i < (*s)->m; i++) if (do_rects_intersect(rr = &(*s)->r[i], r)) {
-			struct rect r1, r2, r3, r4;
-			r1.x1 = rr->x1;
-			r1.x2 = rr->x2;
-			r1.y1 = rr->y1;
-			r1.y2 = r->y1;
-
-			r2.x1 = rr->x1;
-			r2.x2 = r->x1;
-			r2.y1 = r->y1;
-			r2.y2 = r->y2;
-
-			r3.x1 = r->x2;
-			r3.x2 = rr->x2;
-			r3.y1 = r->y1;
-			r3.y2 = r->y2;
-
-			r4.x1 = rr->x1;
-			r4.x2 = rr->x2;
-			r4.y1 = r->y2;
-			r4.y2 = rr->y2;
-
-			intersect_rect(&r2, &r2, rr);
-			intersect_rect(&r3, &r3, rr);
-			rr->x1 = rr->x2 = rr->y1 = rr->y2 = 0;
-#ifdef DEBUG
-			if (is_rect_valid(&r1) && do_rects_intersect(&r1, r)) internal("bad intersection 1");
-			if (is_rect_valid(&r2) && do_rects_intersect(&r2, r)) internal("bad intersection 2");
-			if (is_rect_valid(&r3) && do_rects_intersect(&r3, r)) internal("bad intersection 3");
-			if (is_rect_valid(&r4) && do_rects_intersect(&r4, r)) internal("bad intersection 4");
-#endif
-			add_to_rect_set(s, &r1);
-			add_to_rect_set(s, &r2);
-			add_to_rect_set(s, &r3);
-			add_to_rect_set(s, &r4);
-			a = 1;
-		}
-	} while (a);
-}
-
-/* memory address r must contain one struct rect
- * x1 is leftmost pixel that is still valid
- * x2 is leftmost pixel that isn't valid any more
- * y1, y2 analogically
- */
-int restrict_clip_area(struct graphics_device *dev, struct rect *r, int x1, int y1, int x2, int y2)
-{
-	struct rect v, rr;
-	rr.x1 = x1;
-	rr.x2 = x2;
-	rr.y1 = y1;
-	rr.y2 = y2;
-	if (r) memcpy(r, &dev->clip, sizeof(struct rect));
-	intersect_rect(&v, &dev->clip, &rr);
-	drv->set_clip_area(dev, &v);
-	return is_rect_valid(&v);
-}
-
-#endif
-
 void draw_to_window(struct window *win, void (*fn)(struct terminal *term, void *), void *data)
 {
 	struct terminal *term = win->term;
@@ -349,17 +216,17 @@ void draw_to_window(struct window *win, void (*fn)(struct terminal *term, void *
 		a = 0;
 		memcpy(&r1, &term->dev->clip, sizeof(struct rect));
 		for (i = 0; i < s->m; i++) if (is_rect_valid(r = &s->r[i])) {
-			drv->set_clip_area(term->dev, r);
+			set_clip_area(term->dev, r);
 			pr(fn(term, data)) {
 			}
 			a = 1;
 		}
 		if (!a) {
 			struct rect empty = { 0, 0, 0, 0 };
-			drv->set_clip_area(term->dev, &empty);
+			set_clip_area(term->dev, &empty);
 			fn(term, data);
 		}
-		drv->set_clip_area(term->dev, &r1);
+		set_clip_area(term->dev, &r1);
 		free(s);
 #endif
 	}
@@ -381,11 +248,11 @@ ok:
 		struct links_event ev = { EV_REDRAW, 0, 0, 0 };
 		ev.x = term->x;
 		ev.y = term->y;
-		drv->set_clip_area(term->dev, &win->redr);
+		set_clip_area(term->dev, &win->redr);
 		memset(&win->redr, 0, sizeof(struct rect));
 		win->handler(win, &ev, 0);
 	}
-	drv->set_clip_area(term->dev, &term->dev->size);
+	set_clip_area(term->dev, &term->dev->size);
 }
 
 void set_window_pos(struct window *win, int x1, int y1, int x2, int y2)
@@ -623,8 +490,8 @@ static int process_utf_8(struct terminal *term, struct links_event *ev)
 			unsigned char *p;
 			unsigned c;
 			if (ev->x <= 0 || ev->x >= 0x100) goto direct;
-			if ((term->utf8_paste_mode ^ ev->y) & KBD_PASTE) {
-				term->utf8_paste_mode = ev->y & KBD_PASTE;
+			if ((term->utf8_paste_mode ^ ev->y) & KBD_PASTING) {
+				term->utf8_paste_mode = ev->y & KBD_PASTING;
 				term->utf8_buffer[0] = 0;
 			}
 			if ((l = strlen(cast_const_char term->utf8_buffer))
@@ -723,11 +590,11 @@ void t_resize(struct graphics_device *dev)
 	struct links_event ev = { EV_RESIZE, 0, 0, 0 };
 	term->x = ev.x = dev->size.x2;
 	term->y = ev.y = dev->size.y2;
-	drv->set_clip_area(dev, &dev->size);
+	set_clip_area(dev, &dev->size);
 	foreach(struct window, win, lwin, term->windows) {
 		win->handler(win, &ev, 0);
 	}
-	drv->set_clip_area(dev, &dev->size);
+	set_clip_area(dev, &dev->size);
 }
 
 void t_kbd(struct graphics_device *dev, int key, int flags)
@@ -739,11 +606,13 @@ void t_kbd(struct graphics_device *dev, int key, int flags)
 	r.y2 = dev->size.y2;
 	ev.x = key;
 	ev.y = flags;
-	if (upcase(key) == 'L' && flags == KBD_CTRL) {
+	if (upcase(ev.x) == 'L' && !(ev.y & KBD_PASTING) && ev.y & KBD_CTRL) {
 		t_redraw(dev, &r);
 		return;
 	} else {
-		drv->set_clip_area(dev, &r);
+		if (ev.x == KBD_STOP)
+			abort_background_connections();
+		set_clip_area(dev, &r);
 		if (list_empty(term->windows)) return;
 		if (ev.x == KBD_CTRL_C || ev.x == KBD_CLOSE) {
 			struct window *prev = list_struct(term->windows.prev, struct window);
@@ -782,7 +651,7 @@ void t_mouse(struct graphics_device *dev, int x, int y, int b)
 	ev.x = x;
 	ev.y = y;
 	ev.b = b;
-	drv->set_clip_area(dev, &r);
+	set_clip_area(dev, &r);
 	if (list_empty(term->windows)) return;
 	next = list_struct(term->windows.next, struct window);
 	next->handler(next, &ev, 0);
@@ -856,14 +725,17 @@ static void in_term(void *term_)
 		ev->y -= term->top_margin;
 	}
 	if (ev->ev == EV_KBD || ev->ev == EV_MOUSE) {
-		if (ev->ev == EV_KBD && upcase(ev->x) == 'L' && !(ev->y & KBD_PASTE) && ev->y & KBD_CTRL) {
+		if (ev->ev == EV_KBD && upcase(ev->x) == 'L' && !(ev->y & KBD_PASTING) && ev->y & KBD_CTRL) {
 			ev->ev = EV_REDRAW;
 			ev->x = term->x;
 			ev->y = term->y;
 			goto send_redraw;
 		}
+		if (ev->ev == EV_KBD && ev->x == KBD_STOP) {
+			abort_background_connections();
+		}
 		if (!list_empty(term->windows)) {
-			if (ev->ev == EV_KBD && ev->x == KBD_CTRL_C && !(ev->y & KBD_PASTE)) {
+			if (ev->ev == EV_KBD && ev->x == KBD_CTRL_C && !(ev->y & KBD_PASTING)) {
 				struct window *prev = list_struct(term->windows.prev, struct window);
 				prev->handler(prev, ev, 0);
 			} else {
@@ -955,6 +827,7 @@ static unsigned char frame_vt100[49] =	"aaaxuuukkuxkjjjkmvwtqnttmlvwtqnvvwwmmlln
 				SETPOS(cx, y);				\
 			add_to_str(&a, &l, encode_utf_8(c));		\
 			SETPOS(cx + 1, y);				\
+			print_next = 1;					\
 		}							\
 	}								\
 	else if (!c || c == 1) add_chr_to_str(&a, &l, ' ');		\
@@ -972,6 +845,7 @@ static void redraw_screen(struct terminal *term)
 	int attrib = -1;
 	int mode = -1;
 	int l = 0;
+	int print_next = 0;
 	struct term_spec *s;
 	if (!term->dirty || (term->master && is_blocked())) return;
 	a = init_str();
@@ -988,9 +862,14 @@ static void redraw_screen(struct terminal *term)
 				/* make sure that padding is identical */
 				if (chr_has_padding)
 					memcpy(&term->last_screen[p], &term->screen[p], sizeof(chr));
+				if (print_next) {
+					print_next = 0;
+					goto must_print_next;
+				}
 				continue;
 			}
 			memcpy(&term->last_screen[p], &term->screen[p], sizeof(chr));
+ must_print_next:
 			if (cx == x && cy == y)
 				goto pc;
 			else if (cy == y && x - cx < 10 && x - cx > 0) {
@@ -1006,6 +885,11 @@ static void redraw_screen(struct terminal *term)
 				goto ppc;
 			}
 		}
+		if (print_next && term->left_margin + term->x < term->real_x) {
+			add_to_str(&a, &l, cast_uchar "\033[0m ");
+			attrib = -1;
+			print_next = 0;
+		}
 	}
 	if (l) {
 		if (s->col) add_to_str(&a, &l, cast_uchar "\033[37;40m");
@@ -1117,18 +1001,23 @@ void set_char(struct terminal *t, int x, int y, unsigned ch, unsigned char at)
 	}
 }
 
-chr *get_char(struct terminal *t, int x, int y)
+const chr *get_char(struct terminal *t, int x, int y)
 {
-	if (!t->x || !t->y) {
-		static chr empty;
-		empty.ch = ' ';
-		empty.at = 070;
+	int lx, ly;
+	lx = t->x - 1;
+	ly = t->y - 1;
+	if((lx | ly) < 0) {
+		static const chr empty = { ' ', 070 };
 		return ∅
 	}
-	if (x >= t->x) x = t->x - 1;
-	if (x < 0) x = 0;
-	if (y >= t->y) y = t->y - 1;
-	if (y < 0) y = 0;
+	if (x > lx)
+		x = lx;
+	else if (x < 0)
+		x = 0;
+	if (y > ly)
+		y = ly;
+	else if (y < 0)
+		y = 0;
 	return &t->screen[x + t->x * y];
 }
 
@@ -1140,7 +1029,7 @@ void set_color(struct terminal *t, int x, int y, unsigned char c)
 
 void set_only_char(struct terminal *t, int x, int y, unsigned ch, unsigned char at)
 {
-	chr *cc;
+	const chr *cc;
 	t->dirty = 1;
 	cc = get_char(t, x, y);
 	at = (at & ATTR_FRAME) | (cc->at & ~ATTR_FRAME);
@@ -1359,7 +1248,7 @@ void do_terminal_function(struct terminal *term, unsigned char code, unsigned ch
 	int x_datal;
 	x_data = init_str();
 	x_datal = 0;
-	add_chr_to_str(&x_data, &x_datal, 0);
+	add_chr_to_str(&x_data, &x_datal, code);
 	add_to_str(&x_data, &x_datal, data);
 	exec_on_terminal(term, NULL, x_data, 0);
 	free(x_data);
diff --git a/types.c b/types.c
@@ -984,7 +984,8 @@ unsigned char *get_content_type_by_extension(unsigned char *url)
 		&& !end_of_dir(url, ext[extl]))
 			extl++;
 	if ((extl == 3 && !casecmp(ext, cast_uchar "htm", 3))
-	|| (extl == 4 && !casecmp(ext, cast_uchar "html", 4)))
+	|| (extl == 4 && !casecmp(ext, cast_uchar "html", 4))
+	|| (extl == 5 && !casecmp(ext, cast_uchar "xhtml", 5)))
 		return stracpy(cast_uchar "text/html");
 	foreach(struct list, l, ll, extensions.list_entry) {
 		struct extension *e = get_struct(l, struct extension, head);
diff --git a/url.c b/url.c
@@ -424,7 +424,7 @@ static unsigned char *translate_hashbang(unsigned char *up)
 static unsigned char *rewrite_url_google_docs(unsigned char *n)
 {
 	int i;
-	unsigned char *id, *id_end;
+	unsigned char *id, *id_end, *url_end;
 	unsigned char *res;
 	int l;
 	struct {
@@ -433,9 +433,13 @@ static unsigned char *rewrite_url_google_docs(unsigned char *n)
 		const char *result2;
 	} const patterns[] = {
 		{ "https://docs.google.com/document/d/", "https://docs.google.com/document/d/", "/export?format=pdf" },
+		{ "https://docs.google.com/document/u/", "https://docs.google.com/document/u/", "/export?format=pdf" },
 		{ "https://docs.google.com/spreadsheets/d/", "https://docs.google.com/spreadsheets/d/", "/export?format=pdf" },
+		{ "https://docs.google.com/spreadsheets/u/", "https://docs.google.com/spreadsheets/u/", "/export?format=pdf" },
 		{ "https://docs.google.com/presentation/d/", "https://docs.google.com/presentation/d/", "/export/pdf" },
-		{ "https://drive.google.com/file/d/", "https://drive.google.com/uc?export=download&id=", "" }
+		{ "https://docs.google.com/presentation/u/", "https://docs.google.com/presentation/u/", "/export/pdf" },
+		{ "https://drive.google.com/file/d/", "https://drive.google.com/uc?export=download&id=", "" },
+		{ "https://drive.google.com/file/u/", "https://drive.google.com/uc?export=download&id=", "" }
 	};
 	for (i = 0; i < (int)array_elements(patterns); i++)
 		if (!cmpbeg(n, cast_uchar patterns[i].beginning))
@@ -443,11 +447,17 @@ static unsigned char *rewrite_url_google_docs(unsigned char *n)
 	return n;
 match:
 	id = n + strlen((char *)patterns[i].beginning);
-	id_end = cast_uchar strchr((char *)id, '/');
+	url_end = id + strcspn(cast_const_char id, "#" POST_CHAR_STRING);
+	id_end = memchr(id, '/', url_end - id);
 	if (!id_end)
 		return n;
 	if (!cmpbeg(id_end, cast_uchar "/export"))
 		return n;
+	if (!patterns[i].result2[0]) {
+		id = id_end;
+		while (id[-1] != '/')
+			id--;
+	}
 	res = init_str();
 	l = 0;
 	add_to_str(&res, &l, cast_uchar patterns[i].result1);
diff --git a/view.c b/view.c
@@ -32,6 +32,24 @@ struct view_state *create_vs(void)
 	return vs;
 }
 
+/* FIXME: remove */
+static void free_format_text_cache_entry(struct form_state *fs)
+{
+	struct format_text_cache_entry *ftce = fs->ftce;
+	if (!ftce)
+		return;
+	fs->ftce = NULL;
+	free(ftce);
+}
+
+/* FIXME: remove */
+static void free_form_state(struct form_state *fs)
+{
+	free_format_text_cache_entry(fs);
+	if (fs->string)
+		free(fs->string);
+}
+
 void destroy_vs(struct view_state *vs)
 {
 	int i;
@@ -39,8 +57,11 @@ void destroy_vs(struct view_state *vs)
 		if (vs->refcount < 0) internal("destroy_vs: view_state refcount underflow");
 		return;
 	}
-	for (i = 0; i < vs->form_info_len; i++)
-		free(vs->form_info[i].value);
+	for (i = 0; i < vs->form_info_len; i++) {
+		free(vs->form_info[i].string);
+		free(vs->form_info[i].ftce);
+		vs->form_info[i].ftce = NULL;
+	}
 	free(vs->form_info);
 	free(vs);
 }
@@ -153,8 +174,8 @@ void sort_links(struct f_data *f)
 unsigned char *textptr_add(unsigned char *t, int i, int cp)
 {
 	if (cp) {
-		if ((size_t)i <= strlen(cast_const_char t)) return t + i;
-		else return t + strlen(cast_const_char t);
+		if (i) t += strnlen(cast_const_char t, i);
+		return t;
 	} else {
 		while (i-- && *t) FWD_UTF_8(t);
 		return t;
@@ -175,36 +196,58 @@ int textptr_diff(unsigned char *t2, unsigned char *t1, int cp)
 	}
 }
 
-static struct line_info *format_text_uncached(unsigned char *text, int width, int wrap, int cp)
+static struct format_text_cache_entry *format_text_uncached(unsigned char *text, int width, int wrap, int cp)
 {
-	struct line_info *ln = NULL;
+	unsigned char *text_start = text;
+	struct format_text_cache_entry *ftce;
+	int lnn_allocated = ALLOC_GR;
 	int lnn = 0;
 	unsigned char *b = text;
 	int sk, ps = 0;
+	int xpos = 0;
+	unsigned char *last_space = NULL;
+	int last_space_xpos = 0;
+
+	ftce = xmalloc(sizeof(struct format_text_cache_entry) - sizeof(struct line_info) + lnn_allocated * sizeof(struct line_info));
+
+	ftce->width = width;
+	ftce->wrap = wrap;
+	ftce->cp = cp;
+	ftce->last_state = -1;
+
 	while (*text) {
-		unsigned char *s;
 		if (*text == '\n') {
 			sk = 1;
 			put:
-			if (!(lnn & (ALLOC_GR-1))) {
-				if ((unsigned)lnn > INT_MAX / sizeof(struct line_info) - ALLOC_GR)
+			if (lnn == lnn_allocated) {
+				if ((unsigned)lnn_allocated > INT_MAX / sizeof(struct line_info) - ALLOC_GR)
 					overalloc();
-				ln = xrealloc(ln, (lnn + ALLOC_GR) * sizeof(struct line_info));
+				ftce = xrealloc(ftce, sizeof(struct format_text_cache_entry) - sizeof(struct line_info) + lnn_allocated * sizeof(struct line_info));
 			}
-			ln[lnn].st = b;
-			ln[lnn++].en = text;
+			ftce->ln[lnn].st_offs = (int)(b - text_start);
+			ftce->ln[lnn].en_offs = (int)(text - text_start);
+			ftce->ln[lnn++].chars = xpos;
 			b = text += sk;
+			xpos = 0;
+			last_space = NULL;
 			continue;
 		}
-		if (!wrap || textptr_diff(text, b, cp) < width) {
+		if (*text == ' ') {
+			last_space = text;
+			last_space_xpos = xpos;
+		}
+		if (!wrap || xpos < width) {
 			if (cp)
 				text++;
 			else FWD_UTF_8(text);
+			xpos++;
 			continue;
 		}
-		for (s = text; s >= b; s--) if (*s == ' ') {
-			text = s;
+		if (last_space) {
+			text = last_space;
+			xpos = last_space_xpos;
 			if (wrap == 2) {
+				unsigned char *s = last_space;
 				*s = '\n';
 				for (s++; *s; s++) if (*s == '\n') {
 					if (s[1] != '\n') *s = ' ';
@@ -217,96 +260,73 @@ static struct line_info *format_text_uncached(unsigned char *text, int width, in
 		sk = 0;
 		goto put;
 	}
-	if (ps < 2) {
+	if (ps < 1) {
 		ps++;
 		sk = 0;
 		goto put;
 	}
-	ln[lnn - 1].st = ln[lnn - 1].en = NULL;
-	return ln;
+	ftce->n_lines = lnn;
+	return ftce;
 }
 
-struct format_text_cache_entry {
-	list_entry_1st
-	unsigned char *text_ptr;
-	int text_len;
-	int width;
-	int wrap;
-	int cp;
-	struct line_info *ln;
-	list_entry_last
-	unsigned char copied_text[1];
-};
-
-#define MAX_FORMAT_TEXT_CACHE_ENTRIES		5
-
-static struct list_head format_text_cache = { &format_text_cache, &format_text_cache };
-static int format_text_cache_entries = 0;
-
-static void free_format_text_cache_entry(void)
+struct format_text_cache_entry *format_text(struct f_data_c *fd, struct form_control *fc, struct form_state *fs)
 {
-	struct format_text_cache_entry *ftce = list_struct(format_text_cache.prev, struct format_text_cache_entry);
-	del_from_list(ftce);
-	format_text_cache_entries--;
-	free(ftce->ln);
-	free(ftce);
-}
+	int width = fc->cols;
+	int wrap = fc->wrap;
+	int cp = fd->f_data->opt.cp;
+	struct format_text_cache_entry *ftce = fs->ftce;
 
-struct line_info *format_text(unsigned char *text, int width, int wrap, int cp)
-{
-	struct format_text_cache_entry *ftce;
-	struct list_head *lftce;
-	size_t text_len = strlen(cast_const_char text);
-	foreach(struct format_text_cache_entry, ftce, lftce, format_text_cache) {
-		if ((size_t)ftce->text_len == text_len &&
-		    ftce->text_ptr == text &&
-		    !memcmp(ftce->copied_text, text, text_len) &&
-		    ftce->width == width &&
-		    ftce->wrap == wrap &&
-		    ftce->cp == cp)
-			goto have_it;
-	}
-	if (text_len > INT_MAX - sizeof(struct format_text_cache_entry)) overalloc();
-	ftce = xmalloc(sizeof(struct format_text_cache_entry) + text_len);
-	memcpy(ftce->copied_text, text, text_len + 1);
-	ftce->text_ptr = text;
-	ftce->text_len = (int)text_len;
-	ftce->width = width;
-	ftce->wrap = wrap;
-	ftce->cp = cp;
-	ftce->ln = format_text_uncached(text, width, wrap, cp);
-	add_to_list(format_text_cache, ftce);
-	format_text_cache_entries++;
-	if (format_text_cache_entries > MAX_FORMAT_TEXT_CACHE_ENTRIES)
-		free_format_text_cache_entry();
-have_it:
-	return ftce->ln;
+	if (ftce && ftce->width == width && ftce->wrap == wrap && ftce->cp == cp)
+		return fs->ftce;
+	
+	free_format_text_cache_entry(fs);
+
+	ftce = format_text_uncached(fs->string, width, wrap, cp);
+	fs->ftce = ftce;
+	return ftce;
 }
 
-void free_format_text_cache(void)
+static int find_cursor_line(struct format_text_cache_entry *ftce, int state)
 {
-	while (format_text_cache_entries)
-		free_format_text_cache_entry();
+	int res;
+#define LINE_EQ(x, key) (key >= ftce->ln[x].st_offs && (x >= ftce->n_lines - 1 || key < ftce->ln[x + 1].st_offs))
+#define LINE_ABOVE(x, key) (key < ftce->ln[x].st_offs)
+	BIN_SEARCH(ftce->n_lines, LINE_EQ, LINE_ABOVE, state, res);
+#undef LINE_EQ
+#undef LINE_ABOVE
+	return res;
 }
 
-int area_cursor(struct f_data_c *f, struct form_control *form, struct form_state *fs)
+int area_cursor(struct f_data_c *f, struct form_control *fc, struct form_state *fs)
 {
-	struct line_info *ln;
+	struct format_text_cache_entry *ftce;
 	int q = 0;
 	int x, y;
-	ln = format_text(fs->value, form->cols, form->wrap, f->f_data->opt.cp);
-	for (y = 0; ln[y].st; y++) if (fs->value + fs->state >= ln[y].st && fs->value + fs->state < ln[y].en + (ln[y+1].st != ln[y].en)) {
-		x = textptr_diff(fs->value + fs->state, ln[y].st, f->f_data->opt.cp);
-		if (form->wrap && x == form->cols) x--;
-		if (x >= form->cols + fs->vpos) fs->vpos = x - form->cols + 1;
+	ftce = format_text(f, fc, fs);
+	if (ftce->last_state == fs->state && ftce->last_vpos == fs->vpos && ftce->last_vypos == fs->vypos)
+		return fs->ftce->last_cursor;
+	y = find_cursor_line(ftce, fs->state);
+	if (y >= 0) {
+		x = textptr_diff(fs->string + fs->state, fs->string + ftce->ln[y].st_offs, f->f_data->opt.cp);
+		if (fc->wrap && x == fc->cols) x--;
+
+		if (x >= fc->cols + fs->vpos) fs->vpos = x - fc->cols + 1;
 		if (x < fs->vpos) fs->vpos = x;
-		if (y >= form->rows + fs->vypos) fs->vypos = y - form->rows + 1;
+
+		if (fs->vypos > ftce->n_lines - fc->rows) {
+			fs->vypos = ftce->n_lines - fc->rows;
+			if (fs->vypos < 0) fs->vypos = 0;
+		}
+
 		if (y < fs->vypos) fs->vypos = y;
 		x -= fs->vpos;
 		y -= fs->vypos;
-		q = y * form->cols + x;
-		break;
+		q = y * fc->cols + x;
 	}
+	ftce->last_state = fs->state;
+	ftce->last_vpos = fs->vpos;
+	ftce->last_vypos = fs->vypos;
+	ftce->last_cursor = q;
 	return q;
 }
 
@@ -339,7 +359,7 @@ static void draw_link(struct terminal *t, struct f_data_c *scr, int l)
 			q = 0;
 			if (link->type == L_FIELD) {
 				struct form_state *fs = find_form_state(scr, link->form);
-				q = textptr_diff(fs->value + fs->state, fs->value + fs->vpos, scr->f_data->opt.cp);
+				q = textptr_diff(fs->string + fs->state, fs->string + fs->vpos, scr->f_data->opt.cp);
 			} else if (link->type == L_AREA) {
 				struct form_state *fs = find_form_state(scr, link->form);
 				q = area_cursor(scr, link->form, fs);
@@ -351,7 +371,7 @@ static void draw_link(struct terminal *t, struct f_data_c *scr, int l)
 				int x = link->pos[i].x + xp - vx;
 				int y = link->pos[i].y + yp - vy;
 				if (x >= xp && y >= yp && x < xp+xw && y < yp+yw) {
-					chr *co;
+					const chr *co;
 					co = get_char(t, x, y);
 					scr->link_bg[i].x = x;
 					scr->link_bg[i].y = y;
@@ -573,7 +593,7 @@ static void draw_searched(struct terminal *t, struct f_data_c *scr)
 	if (get_searched(scr, &pt, &len) < 0) return;
 	for (i = 0; i < len; i++) {
 		int x = pt[i].x + xp - vx, y = pt[i].y + yp - vy;
-		chr *co;
+		const chr *co;
 		unsigned char nco;
 		co = get_char(t, x, y);
 		nco = ((co->at >> 3) & 0x07) | ((co->at << 3) & 0x38);
@@ -614,9 +634,9 @@ void fixup_select_state(struct form_control *fc, struct form_state *fs)
 	int inited = 0;
 	int i;
 	retry:
-	if (fs->state >= 0 && fs->state < fc->nvalues && !strcmp(cast_const_char fc->values[fs->state], cast_const_char fs->value)) return;
+	if (fs->state >= 0 && fs->state < fc->nvalues && !strcmp(cast_const_char fc->values[fs->state], cast_const_char fs->string)) return;
 	for (i = 0; i < fc->nvalues; i++) {
-		if (!strcmp(cast_const_char fc->values[i], cast_const_char fs->value)) {
+		if (!strcmp(cast_const_char fc->values[i], cast_const_char fs->string)) {
 			fs->state = i;
 			return;
 		}
@@ -627,25 +647,25 @@ void fixup_select_state(struct form_control *fc, struct form_state *fs)
 		goto retry;
 	}
 	fs->state = 0;
-	free(fs->value);
-	if (fc->nvalues) fs->value = stracpy(fc->values[0]);
-	else fs->value = stracpy(cast_uchar "");
+	free(fs->string);
+	if (fc->nvalues) fs->string = stracpy(fc->values[0]);
+	else fs->string = stracpy(cast_uchar "");
 }
 
 static void init_ctrl(struct form_control *form, struct form_state *fs)
 {
-	free(fs->value);
-	fs->value = NULL;
+	free(fs->string);
+	fs->string = NULL;
 	switch (form->type) {
 		case FC_TEXT:
 		case FC_PASSWORD:
 		case FC_TEXTAREA:
-			fs->value = stracpy(form->default_value);
+			fs->string = stracpy(form->default_value);
 			fs->state = (int)strlen(cast_const_char form->default_value);
 			fs->vpos = 0;
 			break;
 		case FC_FILE:
-			fs->value = stracpy(cast_uchar "");
+			fs->string = stracpy(cast_uchar "");
 			fs->state = 0;
 			fs->vpos = 0;
 			break;
@@ -654,7 +674,7 @@ static void init_ctrl(struct form_control *form, struct form_state *fs)
 			fs->state = form->default_state;
 			break;
 		case FC_SELECT:
-			fs->value = stracpy(form->default_value);
+			fs->string = stracpy(form->default_value);
 			fs->state = form->default_state;
 			fixup_select_state(form, fs);
 			break;
@@ -678,7 +698,7 @@ struct form_state *find_form_state(struct f_data_c *f, struct form_control *form
 		fs = &vs->form_info[n];
 	}
 	if (fs->form_num == form->form_num && fs->ctrl_num == form->ctrl_num && fs->g_ctrl_num == form->g_ctrl_num && /*fs->position == form->position &&*/ fs->type == form->type) return fs;
-	free(fs->value);
+	free_form_state(fs);
 	memset(fs, 0, sizeof(struct form_state));
 	fs->form_num = form->form_num;
 	fs->ctrl_num = form->ctrl_num;
@@ -708,8 +728,9 @@ static void draw_form_entry(struct terminal *t, struct f_data_c *f, struct link 
 	fs = find_form_state(f, form);
 	switch (form->type) {
 		unsigned char *s;
-		struct line_info *ln, *lnx;
-		int sl;
+		struct format_text_cache_entry *ftce;
+		int lid;
+
 		case FC_TEXT:
 		case FC_PASSWORD:
 		case FC_FILE:
@@ -717,20 +738,20 @@ static void draw_form_entry(struct terminal *t, struct f_data_c *f, struct link 
 				if (fs->state >= fs->vpos + form->size) fs->vpos = fs->state - form->size + 1;
 				if (fs->state < fs->vpos) fs->vpos = fs->state;
 				*/
-			if ((size_t)fs->vpos > strlen(cast_const_char fs->value)) fs->vpos = (int)strlen(cast_const_char fs->value);
-			while ((size_t)fs->vpos < strlen(cast_const_char fs->value) && textptr_diff(fs->value + fs->state, fs->value + fs->vpos, f->f_data->opt.cp) >= form->size) {
-				unsigned char *p = fs->value + fs->vpos;
+			if ((size_t)fs->vpos > strlen(cast_const_char fs->string)) fs->vpos = (int)strlen(cast_const_char fs->string);
+			while ((size_t)fs->vpos < strlen(cast_const_char fs->string) && textptr_diff(fs->string + fs->state, fs->string + fs->vpos, f->f_data->opt.cp) >= form->size) {
+				unsigned char *p = fs->string + fs->vpos;
 				FWD_UTF_8(p);
-				fs->vpos = (int)(p - fs->value);
+				fs->vpos = (int)(p - fs->string);
 			}
 			while (fs->vpos > fs->state) {
-				unsigned char *p = fs->value + fs->vpos;
-				BACK_UTF_8(p, fs->value);
-				fs->vpos = (int)(p - fs->value);
+				unsigned char *p = fs->string + fs->vpos;
+				BACK_UTF_8(p, fs->string);
+				fs->vpos = (int)(p - fs->string);
 			}
 			if (!l->n) break;
 			x = l->pos[0].x + xp - vx; y = l->pos[0].y + yp - vy;
-			s = fs->value + fs->vpos;
+			s = fs->string + fs->vpos;
 			for (i = 0; i < form->size; i++, x++) {
 				unsigned ch;
 				if (!*s) {
@@ -754,18 +775,13 @@ static void draw_form_entry(struct terminal *t, struct f_data_c *f, struct link 
 			if (!l->n) break;
 			x = l->pos[0].x + xp - vx; y = l->pos[0].y + yp - vy;
 			area_cursor(f, form, fs);
-			lnx = format_text(fs->value, form->cols, form->wrap, f->f_data->opt.cp);
-			ln = lnx;
-			sl = fs->vypos;
-			while (ln->st && sl) {
-				sl--;
-				ln++;
-			}
-			for (; ln->st && y < l->pos[0].y + yp - vy + form->rows; ln++, y++) {
-				s = textptr_add(ln->st, fs->vpos, f->f_data->opt.cp);
+			ftce = format_text(f, form, fs);
+			lid = fs->vypos;
+			for (; lid < ftce->n_lines && y < l->pos[0].y + yp - vy + form->rows; lid++, y++) {
+				s = textptr_add(fs->string, ftce->ln[lid].st_offs, f->f_data->opt.cp);
 				for (i = 0; i < form->cols; i++) {
 					unsigned ch;
-					if (s >= ln->en) {
+					if (s >= fs->string + ftce->ln[lid].en_offs) {
 						ch = '_';
 					} else {
 						if (f->f_data->opt.cp) {
@@ -868,7 +884,7 @@ static unsigned char fr_trans[2][4] = {{0xb3, 0xc3, 0xb4, 0xc5}, {0xc4, 0xc2, 0x
 
 static void set_xchar(struct terminal *t, int x, int y, unsigned dir)
 {
-	chr *co;
+	const chr *co;
 	if (x < 0 || x >= t->x || y < 0 || y >= t->y) return;
 	co = get_char(t, x, y);
 	if (!(co->at & ATTR_FRAME)) return;
@@ -1305,14 +1321,14 @@ static void down(struct session *ses, struct f_data_c *f, int a)
 {
 	int l = f->vs->current_link;
 	if (f->vs->current_link == -1 || !next_in_view(f, f->vs->current_link+1, 1, in_viewy, set_pos_x)) page_down(ses, f, 1);
-	if (l != f->vs->current_link) set_textarea(ses, f, KBD_UP);
+	if (l != f->vs->current_link) set_textarea(ses, f, -1);
 }
 
 static void up(struct session *ses, struct f_data_c *f, int a)
 {
 	int l = f->vs->current_link;
 	if (f->vs->current_link == -1 || !next_in_view(f, f->vs->current_link-1, -1, in_viewy, set_pos_x)) page_up(ses, f, 1);
-	if (l != f->vs->current_link) set_textarea(ses, f, KBD_DOWN);
+	if (l != f->vs->current_link) set_textarea(ses, f, 1);
 }
 
 static void scroll(struct session *ses, struct f_data_c *f, int a)
@@ -1433,10 +1449,10 @@ static void get_succesful_controls(struct f_data_c *f, struct form_control *fc, 
 				case FC_TEXT:
 				case FC_PASSWORD:
 				case FC_FILE:
-					sub->value = stracpy(fs->value);
+					sub->value = stracpy(fs->string);
 					break;
 				case FC_TEXTAREA:
-					sub->value = encode_textarea(fs->value);
+					sub->value = encode_textarea(fs->string);
 					break;
 				case FC_CHECKBOX:
 				case FC_RADIO:
@@ -1446,7 +1462,7 @@ static void get_succesful_controls(struct f_data_c *f, struct form_control *fc, 
 					break;
 				case FC_SELECT:
 					fixup_select_state(form, fs);
-					sub->value = encode_textarea(fs->value);
+					sub->value = encode_textarea(fs->string);
 					break;
 				case FC_IMAGE:
 					if (fi == -1) {
@@ -1927,7 +1943,7 @@ int enter(struct session *ses, struct f_data_c *f, int a)
 			down(ses, f, 0);
 		}
 #ifdef G
-		else g_next_link(f, 1);
+		else g_next_link(f, 1, 1);
 #endif
 		return 1;
 	}
@@ -1961,9 +1977,10 @@ void selected_item(struct terminal *term, void *pitem, void *ses_)
 	form = l->form;
 	fs = find_form_state(f, form);
 	if (item >= 0 && item < form->nvalues) {
+		free_format_text_cache_entry(fs);
 		fs->state = item;
-		free(fs->value);
-		fs->value = stracpy(form->values[item]);
+		free(fs->string);
+		fs->string = stracpy(form->values[item]);
 	}
 	fixup_select_state(form, fs);
 	f->active = 1;
@@ -2003,29 +2020,31 @@ static void set_form_position(struct f_data_c *fd, struct link *l, struct links_
 		int xx = 0, yy = 0; /* against uninitialized warning */
 
 		if (l->type == L_AREA) {
-			struct line_info *ln;
+			struct format_text_cache_entry *ftce;
 
 			if (!find_pos_in_link(fd, l, ev, &xx, &yy)) {
-				int a;
 				xx += fs->vpos;
 				yy += fs->vypos;
-				ln = format_text(fs->value, l->form->cols, l->form->wrap, fd->f_data->opt.cp);
-				for (a = 0; ln[a].st; a++) if (a == yy) {
+				ftce = format_text(fd, l->form, fs);
+				if (yy >= ftce->n_lines)
+					yy = ftce->n_lines - 1;
+				if (yy >= 0) {
 					unsigned char *ptr;
-					fs->state = (int)(ln[a].st - fs->value);
-					ptr = textptr_add(fs->value + fs->state, xx, fd->f_data->opt.cp);
-					if (ptr > ln[a].en) ptr = ln[a].en;
-					fs->state = (int)(ptr - fs->value);
+					fs->state = ftce->ln[yy].st_offs;
+					ptr = textptr_add(fs->string + fs->state, xx, fd->f_data->opt.cp);
+					if (ptr > fs->string + ftce->ln[yy].en_offs)
+						ptr = fs->string + ftce->ln[yy].en_offs;
+					fs->state = (int)(ptr - fs->string);
 					goto br;
 				}
-				fs->state = (int)strlen(cast_const_char fs->value);
+				fs->state = (int)strlen(cast_const_char fs->string);
 				br:;
 			}
 		} else if (l->type == L_FIELD) {
 			if (!find_pos_in_link(fd, l, ev, &xx, &yy)) {
 				unsigned char *ptr;
-				ptr = textptr_add(fs->value + fs->vpos, xx, fd->f_data->opt.cp);
-				fs->state = (int)(ptr - fs->value);
+				ptr = textptr_add(fs->string + fs->vpos, xx, fd->f_data->opt.cp);
+				fs->state = (int)(ptr - fs->string);
 			}
 		}
 
@@ -2063,31 +2082,34 @@ static void set_br_pos(struct f_data_c *fd, struct link *l)
 {
 }
 
-int field_op(struct session *ses, struct f_data_c *f, struct link *l, struct links_event *ev, int rep)
+int field_op(struct session *ses, struct f_data_c *f, struct link *l, struct links_event *ev)
 {
 	struct form_control *form = l->form;
 	struct form_state *fs;
-	int x = 1;
+	int r = 1;
+	struct format_text_cache_entry *ftce;
+	int y;
 
 	if (!form) {
 		internal("link has no form control");
 		return 0;
 	}
-	if (l->form->ro == 2) return 0;
+	if (form->ro == 2) return 0;
 	fs = find_form_state(f, form);
-	if (!fs->value) return 0;
+	if (!fs->string) return 0;
 	if (ev->ev == EV_KBD) {
 		if (!(ev->y & (KBD_CTRL | KBD_ALT)) && ev->x >= ' ') {
 			if (cp2u(ev->x, term_charset(ses->term)) == -1)
 				goto done;
 			set_br_pos(f, l);
-			if (!form->ro && strlen((char *)fs->value) < form->maxlength) {
+			if (!form->ro && strlen((char *)fs->string) < form->maxlength) {
 				unsigned char *v;
 				unsigned char a_[2];
 				unsigned char *nw;
 				int ll;
-				v = fs->value = xrealloc(fs->value,
-							strlen(cast_const_char fs->value) + 12);
+				free_format_text_cache_entry(fs);
+				v = fs->string = xrealloc(fs->string,
+							strlen(cast_const_char fs->string) + 12);
 				if (f->f_data->opt.cp) {
 					nw = a_;
 					a_[0] = (unsigned char)ev->x;
@@ -2106,118 +2128,95 @@ int field_op(struct session *ses, struct f_data_c *f, struct link *l, struct lin
 		&& ev->x == KBD_ENTER
 		&& form->type == FC_TEXTAREA) {
 			if (!form->ro
-			&& strlen(cast_const_char fs->value) < (size_t)form->maxlength) {
+			&& strlen(cast_const_char fs->string) < (size_t)form->maxlength) {
 				unsigned char *v;
-				v = xrealloc(fs->value,
-					strlen(cast_const_char fs->value) + 2);
-				fs->value = v;
+				free_format_text_cache_entry(fs);
+				v = xrealloc(fs->string,
+					strlen(cast_const_char fs->string) + 2);
+				fs->string = v;
 				memmove(v + fs->state + 1, v + fs->state, strlen(cast_const_char(v + fs->state)) + 1);
 				v[fs->state++] = '\n';
 			}
 			goto done;
 		}
-		if (ev->y & KBD_PASTE) {
-			x = 0;
+		if (ev->y & KBD_PASTING) {
+			r = 0;
 			goto done;
 		}
 		if (ev->x == KBD_LEFT) {
 			if (f->f_data->opt.cp)
 				fs->state = fs->state ? fs->state - 1 : 0;
 			else {
-				unsigned char *p = fs->value + fs->state;
-				BACK_UTF_8(p, fs->value);
-				fs->state = (int)(p - fs->value);
+				unsigned char *p = fs->string + fs->state;
+				BACK_UTF_8(p, fs->string);
+				fs->state = (int)(p - fs->string);
 			}
 		} else if (ev->x == KBD_RIGHT) {
-			if ((size_t)fs->state < strlen(cast_const_char fs->value)) {
+			if ((size_t)fs->state < strlen(cast_const_char fs->string)) {
 				if (f->f_data->opt.cp)
 					fs->state = fs->state + 1;
 				else {
-					unsigned char *p = fs->value + fs->state;
+					unsigned char *p = fs->string + fs->state;
 					FWD_UTF_8(p);
-					fs->state = (int)(p - fs->value);
+					fs->state = (int)(p - fs->string);
 				}
-			} else fs->state = (int)strlen(cast_const_char fs->value);
+			} else fs->state = (int)strlen(cast_const_char fs->string);
 		} else if ((ev->x == KBD_HOME || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL))) {
 			if (form->type == FC_TEXTAREA) {
-				struct line_info *ln;
-				int y;
-				ln = format_text(fs->value, form->cols, form->wrap, f->f_data->opt.cp);
-				for (y = 0; ln[y].st; y++) if (fs->value + fs->state >= ln[y].st && fs->value + fs->state < ln[y].en + (ln[y+1].st != ln[y].en)) {
-					fs->state = (int)(ln[y].st - fs->value);
+				ftce = format_text(f, form, fs);
+				y = find_cursor_line(ftce, fs->state);
+				if (y >= 0) {
+					fs->state = ftce->ln[y].st_offs;
 					goto done;
 				}
 				fs->state = 0;
 			} else fs->state = 0;
-		} else if (ev->x == KBD_UP) {
+		} else if (ev->x == KBD_END || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) {
 			if (form->type == FC_TEXTAREA) {
-				struct line_info *ln;
-				int y;
-				ln = format_text(fs->value, form->cols, form->wrap, f->f_data->opt.cp);
-				rep1:
-				for (y = 0; ln[y].st; y++) if (fs->value + fs->state >= ln[y].st && fs->value + fs->state < ln[y].en + (ln[y+1].st != ln[y].en)) {
-					if (!y) {
-						/*if (F) goto xx;*/
-						goto b;
-					}
-					/*fs->state -= ln[y].st - ln[y-1].st;*/
-					fs->state = (int)(textptr_add(ln[y-1].st, textptr_diff(fs->value + fs->state, ln[y].st, f->f_data->opt.cp), f->f_data->opt.cp) - fs->value);
-					if (fs->value + fs->state > ln[y-1].en) fs->state = (int)(ln[y-1].en - fs->value);
-					goto xx;
+				ftce = format_text(f, form, fs);
+				y = find_cursor_line(ftce, fs->state);
+				if (y >= 0) {
+					fs->state = ftce->ln[y].en_offs;
+					if (fs->state && y < ftce->n_lines - 1 && ftce->ln[y + 1].st_offs == ftce->ln[y].en_offs)
+						fs->state--;
+					goto done;
 				}
-				goto b;
-				xx:
-				if (rep) goto rep1;
-			} else {
-				x = 0;
-				f->vs->brl_in_field = 0;
-			}
+				fs->state = (int)strlen(cast_const_char fs->string);
+			} else fs->state = (int)strlen(cast_const_char fs->string);
+		} else if (ev->x == KBD_UP) {
+			if (form->type == FC_TEXTAREA) {
+				ftce = format_text(f, form, fs);
+				y = find_cursor_line(ftce, fs->state);
+				if (y > 0) {
+					fs->state = (int)(textptr_add(fs->string + ftce->ln[y - 1].st_offs, textptr_diff(fs->string + fs->state, fs->string + ftce->ln[y].st_offs, f->f_data->opt.cp), f->f_data->opt.cp) - fs->string);
+					if (fs->state > ftce->ln[y - 1].en_offs) fs->state = ftce->ln[y - 1].en_offs;
+				} else
+					goto b;
+			} else r = 0, f->vs->brl_in_field = 0;
 		} else if (ev->x == KBD_DOWN) {
 			if (form->type == FC_TEXTAREA) {
-				struct line_info *ln;
-				int y;
-				ln = format_text(fs->value, form->cols, form->wrap, f->f_data->opt.cp);
-				rep2:
-				for (y = 0; ln[y].st; y++) if (fs->value + fs->state >= ln[y].st && fs->value + fs->state < ln[y].en + (ln[y+1].st != ln[y].en)) {
-					if (!ln[y+1].st) {
-						/*if (F) goto yy;*/
+				ftce = format_text(f, form, fs);
+				y = find_cursor_line(ftce, fs->state);
+				if (y >= 0) {
+					if (y >= ftce->n_lines - 1)
 						goto b;
-					}
-					/*fs->state += ln[y+1].st - ln[y].st;*/
-					fs->state = (int)(textptr_add(ln[y+1].st, textptr_diff(fs->value + fs->state, ln[y].st, f->f_data->opt.cp), f->f_data->opt.cp) - fs->value);
-					if (fs->value + fs->state > ln[y+1].en) fs->state = (int)(ln[y+1].en - fs->value);
-					goto yy;
-				}
-				goto b;
-				yy:
-				if (rep) goto rep2;
-
-			} else {
-				x = 0;
-				f->vs->brl_in_field = 0;
-			}
-		} else if (ev->x == KBD_END || (upcase(ev->x) == 'E' && ev->y & KBD_CTRL)) {
-			if (form->type == FC_TEXTAREA) {
-				struct line_info *ln;
-				int y;
-				ln = format_text(fs->value, form->cols, form->wrap, f->f_data->opt.cp);
-				for (y = 0; ln[y].st; y++) if (fs->value + fs->state >= ln[y].st && fs->value + fs->state < ln[y].en + (ln[y+1].st != ln[y].en)) {
-					fs->state = (int)(ln[y].en - fs->value);
-					if (fs->state && (size_t)fs->state < strlen(cast_const_char fs->value) && ln[y+1].st == ln[y].en) fs->state--;
-					goto yyyy;
-				}
-				fs->state = (int)strlen(cast_const_char fs->value);
-				yyyy:;
-			} else fs->state = (int)strlen(cast_const_char fs->value);
-		} else if ((ev->x == KBD_INS && ev->y & KBD_CTRL) || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL)) {
+					fs->state = (int)(textptr_add(fs->string + ftce->ln[y + 1].st_offs, textptr_diff(fs->string + fs->state, fs->string + ftce->ln[y].st_offs, f->f_data->opt.cp), f->f_data->opt.cp) - fs->string);
+					if (fs->state > ftce->ln[y + 1].en_offs) fs->state = ftce->ln[y + 1].en_offs;
+				} else 
+					goto b;
+			} else r = 0, f->vs->brl_in_field = 0;
+		} else if ((ev->x == KBD_INS && ev->y & KBD_CTRL) || (upcase(ev->x) == 'B' && ev->y & KBD_CTRL) || ev->x == KBD_COPY) {
 			set_br_pos(f, l);
-			set_clipboard_text(ses->term, fs->value);
-		} else if ((ev->x == KBD_DEL && ev->y & KBD_SHIFT) || (upcase(ev->x) == 'X' && ev->y & KBD_CTRL)) {
+			set_clipboard_text(ses->term, fs->string);
+		} else if ((ev->x == KBD_DEL && ev->y & KBD_SHIFT) || (upcase(ev->x) == 'X' && ev->y & KBD_CTRL) || ev->x == KBD_CUT) {
 			set_br_pos(f, l);
-			set_clipboard_text(ses->term, fs->value);
-			if (!form->ro) fs->value[0] = 0;
+			set_clipboard_text(ses->term, fs->string);
+			if (!form->ro) {
+				free_format_text_cache_entry(fs);
+				fs->string[0] = 0;
+			}
 			fs->state = 0;
-		} else if ((ev->x == KBD_INS && ev->y & KBD_SHIFT) || (upcase(ev->x) == 'V' && ev->y & KBD_CTRL)) {
+		} else if ((ev->x == KBD_INS && ev->y & KBD_SHIFT) || (upcase(ev->x) == 'V' && ev->y & KBD_CTRL) || ev->x == KBD_PASTE) {
 			unsigned char *clipboard;
 			set_br_pos(f, l);
 			clipboard = get_clipboard_text(ses->term);
@@ -2226,28 +2225,30 @@ int field_op(struct session *ses, struct f_data_c *f, struct link *l, struct lin
 				unsigned char *nl = clipboard;
 				while ((nl = cast_uchar strchr(cast_const_char nl, '\n'))) *nl = ' ';
 			}
-			if (!form->ro && strlen((char *)fs->value) + strlen((char *)clipboard) <= form->maxlength) {
+			if (!form->ro && strlen(cast_const_char fs->string) + strlen(cast_const_char clipboard) <= form->maxlength) {
 				unsigned char *v;
-				v = xrealloc(fs->value,
-					strlen(cast_const_char fs->value) + strlen(cast_const_char clipboard) +1);
-				fs->value = v;
+				free_format_text_cache_entry(fs);
+				v = xrealloc(fs->string,
+					strlen(cast_const_char fs->string) + strlen(cast_const_char clipboard) + 1);
+				fs->string = v;
 				memmove(v + fs->state + strlen(cast_const_char clipboard), v + fs->state, strlen(cast_const_char v) - fs->state + 1);
 				memcpy(v + fs->state, clipboard, strlen(cast_const_char clipboard));
 				fs->state += (int)strlen(cast_const_char clipboard);
 			}
 			free(clipboard);
 		} else if (ev->x == KBD_ENTER)
-			x = 0;
+			r = 0;
 		else if (ev->x == KBD_BS) {
 			set_br_pos(f, l);
 			if (!form->ro && fs->state) {
 				int ll = 1;
+				free_format_text_cache_entry(fs);
 				if (!f->f_data->opt.cp) {
-					unsigned char *p = fs->value + fs->state;
-					BACK_UTF_8(p, fs->value);
-					ll = (int)(fs->value + fs->state - p);
+					unsigned char *p = fs->string + fs->state;
+					BACK_UTF_8(p, fs->string);
+					ll = (int)(fs->string + fs->state - p);
 				}
-				memmove(fs->value + fs->state - ll, fs->value + fs->state, strlen(cast_const_char(fs->value + fs->state)) + 1);
+				memmove(fs->string + fs->state - ll, fs->string + fs->state, strlen(cast_const_char(fs->string + fs->state)) + 1);
 				fs->state -= ll;
 			}
 		} else if (ev->x == KBD_DEL || (upcase(ev->x) == 'D' && ev->y & KBD_CTRL)) {
@@ -2256,68 +2257,165 @@ int field_op(struct session *ses, struct f_data_c *f, struct link *l, struct lin
 				return 0;
 			set_br_pos(f, l);
 			if (!f->f_data->opt.cp) {
-				unsigned char *p = fs->value + fs->state;
+				unsigned char *p = fs->string+ fs->state;
 				FWD_UTF_8(p);
-				ll = (int)(p - (fs->value + fs->state));
+				ll = (int)(p - (fs->string+ fs->state));
 			}
-			if (!form->ro && (size_t)fs->state < strlen(cast_const_char fs->value)) {
-				memmove(fs->value + fs->state, fs->value + fs->state + ll, strlen(cast_const_char(fs->value + fs->state + ll)) + 1);
+			if (!form->ro && (size_t)fs->state < strlen(cast_const_char fs->string)) {
+				free_format_text_cache_entry(fs);
+				memmove(fs->string + fs->state, fs->string + fs->state + ll, strlen(cast_const_char(fs->string + fs->state + ll)) + 1);
 			}
 		} else if (upcase(ev->x) == 'U' && ev->y & KBD_CTRL) {
 			unsigned char *a;
 			set_br_pos(f, l);
-			a = memacpy(fs->value, fs->state);
+			a = memacpy(fs->string, fs->state);
 			set_clipboard_text(ses->term, a);
 			free(a);
 			if (!form->ro) {
-				memmove(fs->value, fs->value + fs->state, strlen(cast_const_char(fs->value + fs->state)) + 1);
+				free_format_text_cache_entry(fs);
+				memmove(fs->string, fs->string + fs->state, strlen(cast_const_char(fs->string + fs->state)) + 1);
 			}
 			fs->state = 0;
 		} else if (upcase(ev->x) == 'K' && ev->y & KBD_CTRL) {
 			set_br_pos(f, l);
 			if (!form->ro) {
 				if (form->type == FC_TEXTAREA) {
-					struct line_info *ln, *lnx;
-					lnx = format_text(fs->value, form->cols, form->wrap, f->f_data->opt.cp);
-					for (ln = lnx; ln->st; ln++) {
-						if (!(ln + 1)->st || (ln + 1)->st > fs->value + fs->state) {
-							unsigned l;
-							unsigned char *cp = memacpy(ln->st, ln->en - ln->st);
-							set_clipboard_text(ses->term, cp);
-							free(cp);
-							l = (int)(ln->en - ln->st + ((ln + 1)->st && (ln + 1)->st > ln->en));
-							memmove(ln->st, ln->st + l, strlen(cast_const_char(ln->st + l)) + 1);
-							fs->state = (int)(ln->st - fs->value);
-							break;
-						}
+					ftce = format_text(f, form, fs);
+					y = find_cursor_line(ftce, fs->state);
+					if (y >= 0) {
+						int l = ftce->ln[y].en_offs - ftce->ln[y].st_offs;
+						unsigned char *start_line = fs->string + ftce->ln[y].st_offs;
+						unsigned char *cp = memacpy(start_line, ftce->ln[y].en_offs - ftce->ln[y].st_offs);
+						set_clipboard_text(ses->term, cp);
+						free(cp);
+						l += y < ftce->n_lines - 1 && ftce->ln[y + 1].st_offs > ftce->ln[y].en_offs;
+						memmove(fs->string + ftce->ln[y].st_offs, fs->string + ftce->ln[y].st_offs + l, strlen(cast_const_char(fs->string + ftce->ln[y].st_offs + l)) + 1);
+						fs->state = ftce->ln[y].st_offs;
 					}
 				} else {
-					set_clipboard_text(ses->term, fs->state + fs->value);
-					fs->value[fs->state] = 0;
+					set_clipboard_text(ses->term, fs->state + fs->string);
+					fs->string[fs->state] = 0;
 				}
+				free_format_text_cache_entry(fs);
 			}
 		} else {
 			b:
 			f->vs->brl_in_field = 0;
+			r = 0;
+		}
+	} else if (ev->ev == EV_MOUSE && BM_IS_WHEEL(ev->b) && form->type == FC_TEXTAREA) {
+		int xdiff = 0, ydiff = 0;
+		int x;
+		unsigned char *ap;
+
+		ftce = format_text(f, form, fs);
+		y = find_cursor_line(ftce, fs->state);
+		if (y >= 0)
+			x = textptr_diff(fs->string + fs->state, fs->string + ftce->ln[y].st_offs, f->f_data->opt.cp);
+		else {
 			x = 0;
+			y = 0;
+		}
+			
+		if ((ev->b & BM_BUTT) == B_WHEELUP)
+			ydiff = form->rows >= 5 ? -5 : -form->rows;
+		else if ((ev->b & BM_BUTT) == B_WHEELUP1)
+			ydiff = -1;
+		else if ((ev->b & BM_BUTT) == B_WHEELDOWN)
+			ydiff = form->rows >= 5 ? 5 : form->rows;
+		else if ((ev->b & BM_BUTT) == B_WHEELDOWN1)
+			ydiff = 1;
+		else if ((ev->b & BM_BUTT) == B_WHEELLEFT)
+			xdiff = form->cols >= 5 ? -5 : -form->cols;
+		else if ((ev->b & BM_BUTT) == B_WHEELLEFT1)
+			xdiff = -1;
+		else if ((ev->b & BM_BUTT) == B_WHEELRIGHT)
+			xdiff = form->cols >= 5 ? 5 : form->cols;
+		else if ((ev->b & BM_BUTT) == B_WHEELRIGHT1)
+			xdiff = 1;
+
+		if (ydiff) {
+			int target_y = -1;
+			fs->vypos += ydiff;
+			if (fs->vypos > ftce->n_lines - form->rows) fs->vypos = ftce->n_lines - form->rows;
+			if (fs->vypos < 0) fs->vypos = 0;
+			if (y >= form->rows + fs->vypos) {
+				target_y = form->rows + fs->vypos - 1;
+				if (target_y < 0)
+					target_y = 0;
+			}
+			if (y < fs->vypos)
+				target_y = fs->vypos;
+
+			if (target_y >= 0) {
+				if (target_y >= ftce->n_lines)
+					target_y = ftce->n_lines - 1;
+				fs->state = ftce->ln[target_y].st_offs;
+				if (x > ftce->ln[target_y].chars)
+					x = ftce->ln[target_y].chars;
+				ap = textptr_add(fs->string + fs->state, x, f->f_data->opt.cp);
+				fs->state = (int)(ap - fs->string);
+			}
+		} else if (xdiff) {
+			int j;
+			int maxx = 0;
+			int longest = y;
+			for (j = fs->vypos; j < fs->vypos + form->rows && j < ftce->n_lines; j++) {
+				if (ftce->ln[j].chars > maxx) {
+					maxx = ftce->ln[j].chars;
+					longest = j;
+				}
+			}
+			maxx -= form->cols - 1;
+			if (maxx < 0) maxx = 0;
+			fs->vpos += xdiff;
+			if (fs->vpos < 0) fs->vpos = 0;
+			if (fs->vpos > maxx) fs->vpos = maxx;
+			if (x > fs->vpos + form->cols - 1) {
+				ap = textptr_add(fs->string + ftce->ln[y].st_offs, fs->vpos + form->cols - 1, f->f_data->opt.cp);
+				fs->state = (int)(ap - fs->string);
+			} else if (x < fs->vpos) {
+				ap = textptr_add(fs->string + ftce->ln[y].st_offs, fs->vpos, f->f_data->opt.cp);
+				if (y < ftce->n_lines - 1 && ap >= fs->string + ftce->ln[y + 1].st_offs)
+					ap = textptr_add(fs->string + ftce->ln[longest].st_offs, fs->vpos, f->f_data->opt.cp);
+				fs->state = (int)(ap - fs->string);
+			}
 		}
-	} else x = 0;
+		goto done;
+	} else
+		r = 0;
 done:
-	if (!F && x) {
-		if (ev->x == KBD_UP || ev->x == KBD_DOWN
+	if (!F && r) {
+		/* FIXME: test might be broken */
+		if ((ev->ev == EV_KBD && (ev->x == KBD_UP || ev->x == KBD_DOWN))
 		|| form->type != FC_TEXTAREA || textarea_adjust_viewport(f, l))
 			x_draw_form_entry(ses, f, l);
 	}
-	return x;
+	return r;
 }
 
-void set_textarea(struct session *ses, struct f_data_c *f, int kbd)
+void set_textarea(struct session *ses, struct f_data_c *f, int dir)
 {
 	struct link *l = get_current_link(f);
 	if (l && l->type == L_AREA) {
-		struct links_event ev = { EV_KBD, 0, 0, 0 };
-		ev.x = kbd;
-		field_op(ses, f, l, &ev, 1);
+		struct form_control *form = l->form;
+		struct form_state *fs;
+		struct format_text_cache_entry *ftce;
+		int y;
+
+		if (form->ro == 2) return;
+		fs = find_form_state(f, form);
+		if (!fs->string) return;
+
+		ftce = format_text(f, form, fs);
+		y = find_cursor_line(ftce, fs->state);
+		if (y >= 0) {
+			int ty = dir < 0 ? 0 : ftce->n_lines - 1;
+			if (ty < 0) return;
+
+			fs->state = (int)(textptr_add(fs->string + ftce->ln[ty].st_offs, textptr_diff(fs->string + fs->state, fs->string + ftce->ln[y].st_offs, f->f_data->opt.cp), f->f_data->opt.cp) - fs->string);
+			if (fs->state > ftce->ln[ty].en_offs) fs->state = ftce->ln[ty].en_offs;
+		}
 	}
 }
 
@@ -2523,14 +2621,14 @@ static int frame_ev(struct session *ses, struct f_data_c *fd, struct links_event
 
 	if (!fd || !fd->vs || !fd->f_data) return 0;
 	if (fd->vs->current_link >= 0 && (fd->f_data->links[fd->vs->current_link].type == L_FIELD || fd->f_data->links[fd->vs->current_link].type == L_AREA)) {
-		if (field_op(ses, fd, &fd->f_data->links[fd->vs->current_link], ev, 0)) {
+		if (field_op(ses, fd, &fd->f_data->links[fd->vs->current_link], ev)) {
 			fd->last_captured = 1;
 			fd->vs->brl_in_field = 1;
 			return 1;
 		}
 	}
 	fd->last_captured = 0;
-	if (ev->ev == EV_KBD && !(ev->y & KBD_PASTE)) {
+	if (ev->ev == EV_KBD && !(ev->y & KBD_PASTING)) {
 		if (ev->x >= '0'+!ses->kbdprefix.rep && ev->x <= '9' && (!fd->f_data->opt.num_links || (ev->y & (KBD_CTRL | KBD_ALT)))) {
 			if (!ses->kbdprefix.rep) ses->kbdprefix.rep_num = 0;
 			if ((ses->kbdprefix.rep_num = ses->kbdprefix.rep_num * 10 + ev->x - '0') > 65536) ses->kbdprefix.rep_num = 65536;
@@ -2549,8 +2647,8 @@ static int frame_ev(struct session *ses, struct f_data_c *fd, struct links_event
 				free(current_link);
 			}
 		}
-		else if (ev->x == KBD_INS || (upcase(ev->x) == 'P' && ev->y & KBD_CTRL) || (upcase(ev->x) == 'P' && !(ev->y & (KBD_CTRL | KBD_ALT)))) rep_ev(ses, fd, scroll, -1 - !ses->kbdprefix.rep);
-		else if (ev->x == KBD_DEL || (upcase(ev->x) == 'N' && ev->y & KBD_CTRL) || (upcase(ev->x) == 'L' && !(ev->y & (KBD_CTRL | KBD_ALT)))) rep_ev(ses, fd, scroll, 1 + !ses->kbdprefix.rep);
+		else if (ev->x == KBD_INS || (upcase(ev->x) == 'P' && ev->y & KBD_CTRL) || (ev->x == 'p' && !(ev->y & (KBD_CTRL | KBD_ALT)))) rep_ev(ses, fd, scroll, -1 - !ses->kbdprefix.rep);
+		else if (ev->x == KBD_DEL || (upcase(ev->x) == 'N' && ev->y & KBD_CTRL) || (ev->x == 'l' && !(ev->y & (KBD_CTRL | KBD_ALT)))) rep_ev(ses, fd, scroll, 1 + !ses->kbdprefix.rep);
 		else if (ev->x == '[') rep_ev(ses, fd, hscroll, -1 - 7 * !ses->kbdprefix.rep);
 		else if (ev->x == ']') rep_ev(ses, fd, hscroll, 1 + 7 * !ses->kbdprefix.rep);
 		else if (ev->x == KBD_HOME || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL)) rep_ev(ses, fd, home, 0);
@@ -2567,11 +2665,13 @@ static int frame_ev(struct session *ses, struct f_data_c *fd, struct links_event
 			if (!anonymous) frm_download_image(ses, fd);
 		} else if (upcase(ev->x) == 'D' && !(ev->y & KBD_ALT)) {
 			if (!anonymous) frm_download(ses, fd);
-		} else if (ev->x == '/') search_dlg(ses, fd, 0);
-		else if (ev->x == '?') search_back_dlg(ses, fd, 0);
-		else if (ev->x == 'n' && !(ev->y & KBD_ALT)) find_next(ses, fd, 0);
-		else if (ev->x == 'N' && !(ev->y & KBD_ALT)) find_next_back(ses, fd, 0);
-		else if (upcase(ev->x) == 'F' && !(ev->y & (KBD_ALT | KBD_CTRL))) set_frame(ses, fd, 0);
+		} else if (ev->x == '/' || (ev->x == KBD_FIND && !(ev->y & (KBD_SHIFT | KBD_CTRL | KBD_ALT)))) search_dlg(ses, fd, 0);
+		else if (ev->x == '?' || (ev->x == KBD_FIND && ev->y & (KBD_SHIFT | KBD_CTRL | KBD_ALT))) search_back_dlg(ses, fd, 0);
+		else if ((ev->x == 'n' && !(ev->y & KBD_ALT)) || ev->x == KBD_REDO) find_next(ses, fd, 0);
+		else if ((ev->x == 'N' && !(ev->y & KBD_ALT)) || ev->x == KBD_UNDO) find_next_back(ses, fd, 0);
+		else if ((upcase(ev->x) == 'F' && !(ev->y & (KBD_ALT | KBD_CTRL))) || ev->x == KBD_FRONT) set_frame(ses, fd, 0);
+		else if (ev->x == 'H' && !(ev->y & (KBD_CTRL | KBD_ALT))) find_link(fd, 1, 1);
+		else if (ev->x == 'L' && !(ev->y & (KBD_CTRL | KBD_ALT))) find_link(fd, -1, 1);
 		else if (ev->x >= '1' && ev->x <= '9' && !(ev->y & (KBD_CTRL | KBD_ALT))) {
 			struct f_data *f_data = fd->f_data;
 			int nl, lnl;
@@ -2772,8 +2872,8 @@ void send_event(struct session *ses, struct links_event *ev)
 	}
 	if (ev->ev == EV_KBD) {
 		if (send_to_frame(ses, ev)) return;
-		if (ev->y & KBD_PASTE) goto x;
-		if (ev->y & KBD_ALT && ev->x != KBD_TAB) {
+		if (ev->y & KBD_PASTING) goto x;
+		if (ev->y & KBD_ALT && ev->x != KBD_TAB && !KBD_ESCAPE_MENU(ev->x)) {
 			struct window *m;
 			ev->y &= ~KBD_ALT;
 			activate_bfu_technology(ses, -1);
@@ -2784,7 +2884,7 @@ void send_event(struct session *ses, struct links_event *ev)
 			} else goto x;
 			ev->y |= KBD_ALT;
 		}
-		if (ev->x == KBD_F1) {
+		if (ev->x == KBD_F1 || ev->x == KBD_HELP) {
 			activate_keys(ses);
 			goto x;
 		}
@@ -2804,32 +2904,24 @@ void send_event(struct session *ses, struct links_event *ev)
 			go_back(ses, 1);
 			goto x;
 		}
-		if (upcase(ev->x) == 'Z' && !(ev->y & (KBD_CTRL | KBD_ALT))) {
+		if ((upcase(ev->x) == 'Z' && !(ev->y & (KBD_CTRL | KBD_ALT))) || ev->x == KBD_BS || ev->x == KBD_BACK) {
 			go_back(ses, 1);
 			goto x;
 		}
-		if (ev->x == '\'') {
-			go_back(ses, -1);
-			goto x;
-		}
-		if (upcase(ev->x) == 'X' && !(ev->y & (KBD_CTRL | KBD_ALT))) {
+		if ((upcase(ev->x) == 'X' && !(ev->y & (KBD_CTRL | KBD_ALT))) || ev->x == '\'' || ev->x == KBD_FORWARD) {
 			go_back(ses, -1);
 			goto x;
 		}
-		if (ev->x == KBD_BS) {
-			go_back(ses, 1);
-			goto x;
-		}
-		if (upcase(ev->x) == 'R' && ev->y & KBD_CTRL) {
+		if ((upcase(ev->x) == 'R' && ev->y & KBD_CTRL) || ev->x == KBD_RELOAD) {
 			reload(ses, -1);
 			goto x;
 		}
-		if (ev->x == 'g' && !(ev->y & (KBD_CTRL | KBD_ALT))) {
+		if ((ev->x == 'g' && !(ev->y & (KBD_CTRL | KBD_ALT))) || (ev->x == KBD_OPEN && !(ev->y & (KBD_SHIFT | KBD_CTRL)))) {
 			quak:
 			dialog_goto_url(ses, cast_uchar "");
 			goto x;
 		}
-		if (ev->x == 'G' && !(ev->y & (KBD_CTRL | KBD_ALT))) {
+		if ((ev->x == 'G' && !(ev->y & (KBD_CTRL | KBD_ALT))) || (ev->x == KBD_OPEN && ev->y & KBD_SHIFT)) {
 			unsigned char *s;
 			if (list_empty(ses->history) || !ses->screen->rq->url) goto quak;
 			s = display_url(ses->term, ses->screen->rq->url, 0);
@@ -2837,7 +2929,7 @@ void send_event(struct session *ses, struct links_event *ev)
 			free(s);
 			goto x;
 		}
-		if (upcase(ev->x) == 'G' && ev->y & KBD_CTRL) {
+		if ((upcase(ev->x) == 'G' && ev->y & KBD_CTRL) || (ev->x == KBD_OPEN && ev->y & KBD_CTRL)) {
 			struct f_data_c *fd = current_frame(ses);
 			unsigned char *s;
 			if (!fd->vs || !fd->f_data || fd->vs->current_link < 0 || fd->vs->current_link >= fd->f_data->nlinks) goto quak;
@@ -2846,13 +2938,17 @@ void send_event(struct session *ses, struct links_event *ev)
 			free(s);
 			goto x;
 		}
+		if (ev->x == KBD_PROPS) {
+			dialog_html_options(ses);
+			goto x;
+		}
 		/*
 		if (upcase(ev->x) == 'A' && !(ev->y & (KBD_CTRL | KBD_ALT))) {
 			if (!anonymous) menu_bookmark_manager(ses->term, NULL, ses);
 			goto x;
 		}
 		*/
-		if (upcase(ev->x) == 'S' && !(ev->y & (KBD_CTRL | KBD_ALT))) {
+		if ((upcase(ev->x) == 'S' && !(ev->y & (KBD_CTRL | KBD_ALT))) || ev->x == KBD_BOOKMARKS) {
 			if (!anonymous) menu_bookmark_manager(ses->term, NULL, ses);
 			goto x;
 		}
@@ -2888,7 +2984,10 @@ void send_event(struct session *ses, struct links_event *ev)
 		}
 #ifdef G
 		if (ses->locked_link) {
-			if ((ev->b & BM_ACT) != B_MOVE) {
+			if (BM_IS_WHEEL(ev->b)) {
+				send_to_frame(ses, ev);
+				return;
+			} else if ((ev->b & BM_ACT) != B_MOVE) {
 				ses->locked_link = 0;
 				clr_xl(ses->screen);
 				draw_formatted(ses);
diff --git a/view_gr.c b/view_gr.c
@@ -20,23 +20,6 @@ static struct g_object_text * g_find_nearest_object(struct f_data *f, int x, int
 
 static int previous_link=-1;	/* for mouse event handlers */
 
-void g_draw_background(struct graphics_device *dev, struct background *bg, int x, int y, int xw, int yw)
-{
-	if (xw > 4096) {
-		int halfx = x + xw / 2;
-		if (dev->clip.x1 < halfx) g_draw_background(dev, bg, x, y, halfx - x, yw);
-		if (dev->clip.x2 > halfx) g_draw_background(dev, bg, halfx, y, x + xw - halfx, yw);
-		return;
-	}
-	if (yw > 4096) {
-		int halfy = y + yw / 2;
-		if (dev->clip.y1 < halfy) g_draw_background(dev, bg, x, y, xw, halfy - y);
-		if (dev->clip.y2 > halfy) g_draw_background(dev, bg, x, halfy, xw, y + yw - halfy);
-		return;
-	}
-	drv->fill_area(dev, x, y, x + xw, y + yw , dip_get_color_sRGB(bg->u.sRGB));
-}
-
 void g_dummy_draw(struct f_data_c *fd, struct g_object *t, int x, int y)
 {
 }
@@ -118,7 +101,7 @@ void g_text_draw(struct f_data_c *fd, struct g_object *t_, int x, int y)
 	int i, j;
 	int yy;
 	int cur;
-	struct line_info *ln, *lnx;
+	struct format_text_cache_entry *ftce;
 	struct graphics_device *dev = fd->ses->term->dev;
 
 	if (x + t->goti.go.xw <= fd->ses->term->dev->clip.x1)
@@ -137,7 +120,7 @@ void g_text_draw(struct f_data_c *fd, struct g_object *t_, int x, int y)
 		fs = find_form_state(fd, form);
 		switch (form->type) {
 			struct style *inv;
-			int in;
+			int in, lid;
 			case FC_RADIO:
 				if (link
 				&& fd->active
@@ -190,20 +173,20 @@ void g_text_draw(struct f_data_c *fd, struct g_object *t_, int x, int y)
 				if (fs->state >= fs->vpos + form->size) fs->vpos = fs->state - form->size + 1;
 				if (fs->state < fs->vpos) fs->vpos = fs->state;
 				*/
-				if ((size_t)fs->vpos > strlen(cast_const_char fs->value)) fs->vpos = (int)strlen(cast_const_char fs->value);
-				while ((size_t)fs->vpos < strlen(cast_const_char fs->value) && textptr_diff(fs->value + fs->state, fs->value + fs->vpos, fd->f_data->opt.cp) >= form->size) {
-					unsigned char *p = fs->value + fs->vpos;
+				if ((size_t)fs->vpos > strlen(cast_const_char fs->string)) fs->vpos = (int)strlen(cast_const_char fs->string);
+				while ((size_t)fs->vpos < strlen(cast_const_char fs->string) && textptr_diff(fs->string + fs->state, fs->string + fs->vpos, fd->f_data->opt.cp) >= form->size) {
+					unsigned char *p = fs->string + fs->vpos;
 					FWD_UTF_8(p);
-					fs->vpos = (int)(p - fs->value);
+					fs->vpos = (int)(p - fs->string);
 				}
 				while (fs->vpos > fs->state) {
-					unsigned char *p = fs->value + fs->vpos;
-					BACK_UTF_8(p, fs->value);
-					fs->vpos = (int)(p - fs->value);
+					unsigned char *p = fs->string + fs->vpos;
+					BACK_UTF_8(p, fs->string);
+					fs->vpos = (int)(p - fs->string);
 				}
 				l = 0;
 				i = 0;
-				ll = (int)strlen(cast_const_char fs->value);
+				ll = (int)strlen(cast_const_char fs->string);
 				while (l < t->goti.go.xw) {
 					struct style *st = t->style;
 					int sm = 0;
@@ -217,7 +200,7 @@ void g_text_draw(struct f_data_c *fd, struct g_object *t_, int x, int y)
 						tx[1] = 0;
 						i++;
 					} else {
-						i += prepare_input_field_char(fs->value + fs->vpos + i, tx);
+						i += prepare_input_field_char(fs->string + fs->vpos + i, tx);
 						if (form->type == FC_PASSWORD) {
 							tx[0] = '*';
 							tx[1] = 0;
@@ -230,16 +213,26 @@ void g_text_draw(struct f_data_c *fd, struct g_object *t_, int x, int y)
 				return;
 			case FC_TEXTAREA:
 				cur = area_cursor(fd, form, fs);
-				lnx = format_text(fs->value, form->cols, form->wrap, fd->f_data->opt.cp);
-				ln = lnx;
+				ftce = format_text(fd, form, fs);
+
 				yy = y - t->goti.link_order * t->style->height;
-				for (j = 0; j < fs->vypos; j++) if (ln->st) ln++;
+				lid = fs->vypos;
 				for (j = 0; j < form->rows; j++) {
-					unsigned char *pp = ln->st;
+					unsigned char *pp, *en;
+					int remaining_chars;
 					int xx = fs->vpos;
-					while (ln->st && pp < ln->en && xx > 0) {
+					if (lid < ftce->n_lines) {
+						pp = fs->string + ftce->ln[lid].st_offs;
+						en = fs->string + ftce->ln[lid].en_offs;
+						remaining_chars = ftce->ln[lid].chars;
+					} else {
+						pp = en = NULL;
+						remaining_chars = 0;
+					}
+					while(pp && pp < en && xx > 0) {
 						FWD_UTF_8(pp);
 						xx--;
+						remaining_chars--;
 					}
 					if (cur >= 0 && cur < form->cols
 					&& t->goti.link_num == fd->vs->current_link
@@ -249,7 +242,7 @@ void g_text_draw(struct f_data_c *fd, struct g_object *t_, int x, int y)
 
 						if (print_all_textarea || j == t->goti.link_order) while (xx < x + t->goti.go.xw) {
 							struct style *st = t->style;
-							if (ln->st && pp < ln->en) {
+							if (pp && pp < en) {
 								pp += prepare_input_field_char(pp, tx);
 							} else {
 								tx[0] = '_';
@@ -270,20 +263,26 @@ void g_text_draw(struct f_data_c *fd, struct g_object *t_, int x, int y)
 						} else cur -= form->cols;
 					} else {
 						if (print_all_textarea || j == t->goti.link_order) {
-							int aa;
 							unsigned char *a;
 							struct rect old;
-							if (ln->st && pp < ln->en) a = memacpy(pp, ln->en - pp);
-							else a = stracpy(cast_uchar "");
-							for (aa = 0; aa < form->cols; aa += 4) add_to_strn(&a, cast_uchar "____");
+							size_t text_size;
+							if (remaining_chars <= form->cols)
+								remaining_chars = form->cols - remaining_chars;
+							else
+								remaining_chars = 0;
+							text_size = pp ? en - pp : 0;
+							a = xmalloc(text_size + remaining_chars + 1);
+							if (text_size) memcpy(a, pp, text_size);
+							memset(a + text_size, '_', remaining_chars);
+							a[text_size + remaining_chars] = 0;
 							restrict_clip_area(dev, &old, x, 0, x + t->goti.go.xw, dev->size.y2);
 							g_print_text(dev, x, yy + j * t->style->height, t->style, a, NULL);
-							drv->set_clip_area(dev, &old);
+							set_clip_area(dev, &old);
 							free(a);
 						}
 						cur -= form->cols;
 					}
-					if (ln->st) ln++;
+					if (lid < ftce->n_lines) lid++;
 				}
 				return;
 		}
@@ -584,13 +583,13 @@ static void draw_root(struct f_data_c *scr, int x, int y)
 
 void draw_graphical_doc(struct terminal *t, struct f_data_c *scr, int active)
 {
-	int r = 0;
 	struct rect old;
 	struct view_state *vs = scr->vs;
 	struct rect_set *rs;
 	int xw = scr->xw;
 	int yw = scr->yw;
 	int vx, vy;
+	int j;
 
 	if (active) {
 		if (scr->ses->search_word && scr->ses->search_word[0]) {
@@ -639,97 +638,24 @@ void draw_graphical_doc(struct terminal *t, struct f_data_c *scr, int active)
 	|| (scr->xl - vx > xw || vx - scr->xl > xw || scr->yl - vy > yw
 	|| vy - scr->yl > yw))
 		goto rrr;
-	if (scr->xl != vx) {
-		rs = NULL;
-		r |= drv->scroll(t->dev, &rs, scr->xl - vx, 1);
-		if (rs) {
-			int j;
-			for (j = 0; j < rs->m; j++) {
-				struct rect *r = &rs->r[j];
-				struct rect clip1;
-				restrict_clip_area(t->dev, &clip1, r->x1, r->y1,
-					r->x2, r->y2);
-				draw_root(scr, scr->xp - vs->view_posx,
-					scr->yp - vs->view_pos - (scr->yl - vy));
-				drv->set_clip_area(t->dev, &clip1);
-			}
-			free(rs);
-		}
-	}
 
-	if (scr->yl != vy) {
-		rs = NULL;
-		r |= drv->scroll(t->dev, &rs, scr->yl - vy, 0);
-		if (rs) {
-			int j;
-			for (j = 0; j < rs->m; j++) {
-				struct rect *r = &rs->r[j];
-				struct rect clip1;
-				restrict_clip_area(t->dev, &clip1, r->x1, r->y1,
-					r->x2, r->y2);
-				draw_root(scr, scr->xp - vs->view_posx,
-					scr->yp - vs->view_pos);
-				drv->set_clip_area(t->dev, &clip1);
-			}
-			free(rs);
-		}
-	}
-
-	if (r) {
+	rs = g_scroll(t->dev, scr->xl - vx, scr->yl - vy);
+	for (j = 0; j < rs->m; j++) {
+		struct rect *r = &rs->r[j];
 		struct rect clip1;
-		if (scr->xl < vx)  {
-			if (scr->yl < vy)
-				restrict_clip_area(t->dev, &clip1,
-					scr->xp + xw - scr->vsb
-					* G_SCROLL_BAR_WIDTH - (vx - scr->xl),
-					scr->yp, scr->xp + xw - scr->vsb
-					* G_SCROLL_BAR_WIDTH,
-					scr->yp + yw - scr->hsb
-					* G_SCROLL_BAR_WIDTH - (vy - scr->yl));
-			else
-				restrict_clip_area(t->dev, &clip1,
-					scr->xp + xw - scr->vsb
-					* G_SCROLL_BAR_WIDTH - (vx - scr->xl),
-					scr->yp + (scr->yl - vy),
-					scr->xp + xw - scr->vsb
-					* G_SCROLL_BAR_WIDTH,
-					scr->yp + yw - scr->hsb
-					* G_SCROLL_BAR_WIDTH);
-		} else {
-			if (scr->yl < vy)
-				restrict_clip_area(t->dev, &clip1, scr->xp,
-					scr->yp, scr->xp + (scr->xl - vx),
-					scr->yp + yw - scr->hsb
-					* G_SCROLL_BAR_WIDTH - (vy - scr->yl));
-			else
-				restrict_clip_area(t->dev, &clip1, scr->xp,
-					scr->yp + (scr->yl - vy),
-					scr->xp + (scr->xl - vx),
-					scr->yp + yw - scr->hsb
-					* G_SCROLL_BAR_WIDTH);
-		}
-		draw_root(scr, scr->xp - vs->view_posx, scr->yp - vs->view_pos);
-		drv->set_clip_area(t->dev, &clip1);
-		if (scr->yl < vy)
-			restrict_clip_area(t->dev, NULL, scr->xp,
-				scr->yp + yw - scr->hsb * G_SCROLL_BAR_WIDTH
-				- (vy - scr->yl),
-				scr->xp + xw - scr->vsb * G_SCROLL_BAR_WIDTH,
-				scr->yp + yw - scr->hsb * G_SCROLL_BAR_WIDTH);
-		else
-			restrict_clip_area(t->dev, NULL, scr->xp, scr->yp,
-				scr->xp + xw - scr->vsb * G_SCROLL_BAR_WIDTH,
-				scr->yp + (scr->yl - vy));
+		restrict_clip_area(t->dev, &clip1, r->x1, r->y1, r->x2, r->y2);
 		draw_root(scr, scr->xp - vs->view_posx, scr->yp - vs->view_pos);
+		set_clip_area(t->dev, &clip1);
 	}
+	free(rs);
 
-	goto eee;
+	if (0) {
  rrr:
-	draw_root(scr, scr->xp - vs->view_posx, scr->yp - vs->view_pos);
- eee:
+		draw_root(scr, scr->xp - vs->view_posx, scr->yp - vs->view_pos);
+	}
 	scr->xl = vx;
 	scr->yl = vy;
-	drv->set_clip_area(t->dev, &old);
+	set_clip_area(t->dev, &old);
 
 	highlight_positions = NULL;
 	highlight_lengths = NULL;
@@ -754,7 +680,7 @@ static void draw_one_object_fn(struct terminal *t, void *d_)
 	get_object_pos(o, &x, &y);
 	o->draw(scr, o, scr->xp - scr->vs->view_posx + x,
 		scr->yp - scr->vs->view_pos + y);
-	drv->set_clip_area(t->dev, &clip);
+	set_clip_area(t->dev, &clip);
 }
 
 void draw_one_object(struct f_data_c *scr, struct g_object *o)
@@ -902,8 +828,7 @@ static void g_set_current_link(struct f_data_c *fd, struct g_object_text_image *
 			if (!l->form) return;
 			if (l->type == L_AREA) {
 				struct g_object_text *at = get_struct(a, struct g_object_text, goti);
-				struct line_info *ln;
-				int aa;
+				struct format_text_cache_entry *ftce;
 				fs = find_form_state(fd,l->form);
 
 				if (g_char_width(at->style, ' '))
@@ -911,16 +836,17 @@ static void g_set_current_link(struct f_data_c *fd, struct g_object_text_image *
 				else
 					xx = x;
 				xx += fs->vpos;
-				xx= xx < 0 ? 0 : xx;
+				xx = xx < 0 ? 0 : xx;
 				yy = a->link_order;
 				yy += fs->vypos;
-				ln = format_text(fs->value, l->form->cols, l->form->wrap, fd->f_data->opt.cp);
-				for (aa = 0; ln[aa].st; aa++) if (aa==yy){
-					int bla = textptr_diff(ln[aa].en, ln[aa].st, fd->f_data->opt.cp);
-
-					fs->state = (int)(ln[aa].st-fs->value);
-					fs->state = (int)(textptr_add(fs->value + fs->state, xx<bla?xx:bla, fd->f_data->opt.cp) - fs->value);
-					break;
+				ftce = format_text(fd, l->form, fs);
+				if (yy >= ftce->n_lines)
+					yy = ftce->n_lines - 1;
+				if (yy >= 0) {
+					int bla = textptr_diff(fs->string + ftce->ln[yy].en_offs, fs->string + ftce->ln[yy].st_offs, fd->f_data->opt.cp);
+
+					fs->state = ftce->ln[yy].st_offs;
+					fs->state = (int)(textptr_add(fs->string + fs->state, xx < bla ? xx : bla, fd->f_data->opt.cp) - fs->string);
 				}
 				return;
 			}
@@ -931,7 +857,7 @@ static void g_set_current_link(struct f_data_c *fd, struct g_object_text_image *
 					xx = x / g_char_width(at->style, ' ');
 				else
 					xx = x;
-				fs->state = (int)(textptr_add(fs->value + ((size_t)fs->vpos > strlen(cast_const_char fs->value) ? strlen(cast_const_char fs->value) : (size_t)fs->vpos), (xx<0?0:xx), fd->f_data->opt.cp) - fs->value);
+				fs->state = (int)(textptr_add(fs->string + ((size_t)fs->vpos > strlen(cast_const_char fs->string) ? strlen(cast_const_char fs->string) : (size_t)fs->vpos), (xx < 0 ? 0 : xx), fd->f_data->opt.cp) - fs->string);
 			}
 		}
 	}
@@ -1065,7 +991,7 @@ static int lr_link(struct f_data_c *fd, int nl)
 	return xx != fd->vs->view_posx;
 }
 
-int g_next_link(struct f_data_c *fd, int dir)
+int g_next_link(struct f_data_c *fd, int dir, int do_scroll)
 {
 	int orig_link = -1;
 	int r = 2;
@@ -1080,6 +1006,8 @@ retry:
 	}
 	again:
 	if (n < 0 || n >= fd->f_data->nlinks) {
+		if (!do_scroll)
+			return 0;
 		if (r == 1) {
 			fd->vs->current_link = -1;
 			if (fd->vs->view_pos > fd->f_data->y - fd->yw + fd->hsb * G_SCROLL_BAR_WIDTH) fd->vs->view_pos = fd->f_data->y - fd->yw + fd->hsb * G_SCROLL_BAR_WIDTH;
@@ -1119,7 +1047,7 @@ retry:
 	if (fd->f_data->links[fd->vs->current_link].type == L_FIELD || fd->f_data->links[fd->vs->current_link].type == L_AREA) {
 		if ((fd->f_data->locked_on = fd->f_data->links[fd->vs->current_link].obj)) fd->ses->locked_link = 1;
 	}
-	set_textarea(fd->ses, fd, dir < 0 ? KBD_DOWN : KBD_UP);
+	set_textarea(fd->ses, fd, -dir);
 	change_screen_status(fd->ses);
 	print_screen_status(fd->ses);
 	if (lr_link(fd, fd->vs->current_link)) r = 1;
@@ -1167,14 +1095,35 @@ int g_frame_ev(struct session *ses, struct f_data_c *fd, struct links_event *ev)
 	if (!fd->f_data) return 0;
 	switch ((int)ev->ev) {
 		case EV_MOUSE:
-			if ((ev->b & BM_BUTT) == B_WHEELUP) goto up;
-			if ((ev->b & BM_BUTT) == B_WHEELDOWN) goto down;
-			if ((ev->b & BM_BUTT) == B_WHEELUP1) goto up1;
-			if ((ev->b & BM_BUTT) == B_WHEELDOWN1) goto down1;
-			if ((ev->b & BM_BUTT) == B_WHEELLEFT) goto left;
-			if ((ev->b & BM_BUTT) == B_WHEELRIGHT) goto right;
-			if ((ev->b & BM_BUTT) == B_WHEELLEFT1) goto left1;
-			if ((ev->b & BM_BUTT) == B_WHEELRIGHT1) goto right1;
+			if (BM_IS_WHEEL(ev->b) && ses->locked_link) {
+				if (fd->vs->current_link >= 0 && fd->vs->current_link < fd->f_data->nlinks && fd->f_data->links[fd->vs->current_link].type == L_AREA) {
+					if (field_op(ses, fd, &fd->f_data->links[fd->vs->current_link], ev)) {
+						if (fd->f_data->locked_on) {
+							print_all_textarea = 1;
+							draw_one_object(fd, fd->f_data->locked_on);
+							print_all_textarea = 0;
+							return 2;
+						}
+					}
+				}
+				return 1;
+			}
+			if ((ev->b & BM_BUTT) == B_WHEELUP)
+				return scroll_v(fd, -64);
+			if ((ev->b & BM_BUTT) == B_WHEELDOWN)
+				return scroll_v(fd, 64);
+			if ((ev->b & BM_BUTT) == B_WHEELUP1)
+				return scroll_v(fd, -16);
+			if ((ev->b & BM_BUTT) == B_WHEELDOWN1)
+				return scroll_v(fd, 16);
+			if ((ev->b & BM_BUTT) == B_WHEELLEFT)
+				return scroll_h(fd, -64);
+			if ((ev->b & BM_BUTT) == B_WHEELRIGHT)
+				return scroll_h(fd, 64);
+			if ((ev->b & BM_BUTT) == B_WHEELLEFT1)
+				return scroll_h(fd, -16);
+			if ((ev->b & BM_BUTT) == B_WHEELRIGHT1)
+				return scroll_h(fd, 16);
 			if ((ev->b & BM_ACT) == B_MOVE) ses->scrolling = 0;
 			if (ses->scrolling == 1) process_sb_move(fd, ses->scrolltype ? ev->x : ev->y);
 			if (ses->scrolling == 2) {
@@ -1182,7 +1131,7 @@ int g_frame_ev(struct session *ses, struct f_data_c *fd, struct links_event *ev)
 				fd->vs->view_posx = -ev->x + ses->scrolltype;
 				fd->vs->orig_view_pos = fd->vs->view_pos;
 				fd->vs->orig_view_posx = fd->vs->view_posx;
-				draw_graphical_doc(fd->ses->term, fd, 1);
+				draw_graphical_doc(ses->term, fd, 1);
 				if ((ev->b & BM_ACT) == B_UP) {
 					ses->scrolling = 0;
 				}
@@ -1266,7 +1215,7 @@ int g_frame_ev(struct session *ses, struct f_data_c *fd, struct links_event *ev)
 							while ((p = cast_uchar strchr(cast_const_char p, 1))) *p++ = ' ';
 							p = m;
 							while ((p = cast_uchar strstr(cast_const_char p, "\302\255"))) memmove(p, p + 2, strlen(cast_const_char(p + 2)) + 1);
-							if (*m) set_clipboard_text(fd->ses->term, m);
+							if (*m) set_clipboard_text(ses->term, m);
 							free(m);
 						}
 					}
@@ -1283,7 +1232,7 @@ int g_frame_ev(struct session *ses, struct f_data_c *fd, struct links_event *ev)
 			break;
 		case EV_KBD:
 			if (ses->locked_link && fd->vs->current_link >= 0 && fd->vs->current_link < fd->f_data->nlinks && (fd->f_data->links[fd->vs->current_link].type == L_FIELD || fd->f_data->links[fd->vs->current_link].type == L_AREA)) {
-				if (field_op(ses, fd, &fd->f_data->links[fd->vs->current_link], ev, 0)) {
+				if (field_op(ses, fd, &fd->f_data->links[fd->vs->current_link], ev)) {
 					if (fd->f_data->locked_on) {
 						print_all_textarea = 1;
 						draw_one_object(fd, fd->f_data->locked_on);
@@ -1292,11 +1241,11 @@ int g_frame_ev(struct session *ses, struct f_data_c *fd, struct links_event *ev)
 					}
 					return 1;
 				}
-				if (ev->x == KBD_ENTER && !(ev->y & KBD_PASTE)) {
+				if (ev->x == KBD_ENTER && !(ev->y & KBD_PASTING)) {
 					return enter(ses, fd, 0);
 				}
 			}
-			if (ev->y & KBD_PASTE)
+			if (ev->y & KBD_PASTING)
 				return 0;
 			if (ev->x == KBD_ENTER && fd->f_data->opt.plain == 2) {
 				ses->ds.porn_enable ^= 1;
@@ -1326,50 +1275,32 @@ int g_frame_ev(struct session *ses, struct f_data_c *fd, struct links_event *ev)
 				unset_link(fd);
 				return scroll_v(fd, -vertical_page_jump(fd));
 			}
-			if (0) {
-				down:
-				return scroll_v(fd, 64);
-			}
-			if (0) {
-				up:
-				return scroll_v(fd, -64);
-			}
-			if (ev->x == KBD_DEL || (upcase(ev->x) == 'N' && ev->y & KBD_CTRL) || (upcase(ev->x) == 'L' && !(ev->y & (KBD_CTRL | KBD_ALT)))) {
+			if (ev->x == KBD_DEL || (upcase(ev->x) == 'N' && ev->y & KBD_CTRL) || (ev->x == 'l' && !(ev->y & (KBD_CTRL | KBD_ALT)))) {
 				return scroll_v(fd, 32);
 			}
-			if (ev->x == KBD_INS || (upcase(ev->x) == 'P' && ev->y & KBD_CTRL) || (upcase(ev->x) == 'P' && !(ev->y & (KBD_CTRL | KBD_ALT)))) {
+			if (ev->x == KBD_INS || (upcase(ev->x) == 'P' && ev->y & KBD_CTRL) || (ev->x == 'p' && !(ev->y & (KBD_CTRL | KBD_ALT)))) {
 				return scroll_v(fd, -32);
 			}
-			if (/*ev->x == KBD_DOWN*/ 0) {
-				down1:
-				return scroll_v(fd, 16);
-			}
-			if (/*ev->x == KBD_UP*/ 0) {
-				up1:
-				return scroll_v(fd, -16);
-			}
 			if (ev->x == KBD_DOWN) {
-				return g_next_link(fd, 1);
+				return g_next_link(fd, 1, 1);
 			}
 			if (ev->x == KBD_UP) {
-				return g_next_link(fd, -1);
+				return g_next_link(fd, -1, 1);
+			}
+			if (ev->x == 'H' && !(ev->y & (KBD_CTRL | KBD_ALT))) {
+				unset_link(fd);
+				return g_next_link(fd, 1, 0);
+			}
+			if (ev->x == 'L' && !(ev->y & (KBD_CTRL | KBD_ALT))) {
+				unset_link(fd);
+				return g_next_link(fd, -1, 0);
 			}
 			if (ev->x == '[') {
-				left:
 				return scroll_h(fd, -64);
 			}
 			if (ev->x == ']') {
-				right:
 				return scroll_h(fd, 64);
 			}
-			if (/*ev->x == KBD_LEFT*/ 0) {
-				left1:
-				return scroll_h(fd, -16);
-			}
-			if (/*ev->x == KBD_RIGHT*/ 0) {
-				right1:
-				return scroll_h(fd, 16);
-			}
 			if (ev->x == KBD_HOME || (upcase(ev->x) == 'A' && ev->y & KBD_CTRL)) {
 				fd->vs->view_pos = 0;
 				fd->vs->orig_view_pos = fd->vs->view_pos;
@@ -1382,7 +1313,7 @@ int g_frame_ev(struct session *ses, struct f_data_c *fd, struct links_event *ev)
 				unset_link(fd);
 				return 3;
 			}
-			if (upcase(ev->x) == 'F' && !(ev->y & (KBD_ALT | KBD_CTRL))) {
+			if ((upcase(ev->x) == 'F' && !(ev->y & (KBD_ALT | KBD_CTRL))) || ev->x == KBD_FRONT) {
 				set_frame(ses, fd, 0);
 				return 2;
 			}
@@ -1404,22 +1335,29 @@ int g_frame_ev(struct session *ses, struct f_data_c *fd, struct links_event *ev)
 				if (!anonymous) frm_download(ses, fd);
 				return 2;
 			}
-			if (ev->x == '/') {
+			if (ev->x == '/' || (ev->x == KBD_FIND && !(ev->y & (KBD_SHIFT | KBD_CTRL | KBD_ALT)))) {
 				search_dlg(ses, fd, 0);
 				return 2;
 			}
-			if (ev->x == '?') {
+			if (ev->x == '?' || (ev->x == KBD_FIND && ev->y & (KBD_SHIFT | KBD_CTRL | KBD_ALT))) {
 				search_back_dlg(ses, fd, 0);
 				return 2;
 			}
-			if (ev->x == 'n' && !(ev->y & KBD_ALT)) {
+			if ((ev->x == 'n' && !(ev->y & KBD_ALT)) || ev->x == KBD_REDO) {
 				find_next(ses, fd, 0);
 				return 2;
 			}
-			if (ev->x == 'N' && !(ev->y & KBD_ALT)) {
+			if ((ev->x == 'N' && !(ev->y & KBD_ALT)) || ev->x == KBD_UNDO) {
 				find_next_back(ses, fd, 0);
 				return 2;
 			}
+			if (ev->x == KBD_MENU) {
+				if (fd->vs->current_link >= 0 && fd->vs->current_link < fd->f_data->nlinks) {
+					ses->win->xp = fd->f_data->links[fd->vs->current_link].r.x1 + fd->xp - fd->vs->view_posx;
+					ses->win->yp = fd->f_data->links[fd->vs->current_link].r.y2 + fd->yp - fd->vs->view_pos;
+					link_menu(ses->term, NULL, ses);
+				}
+			}
 			break;
 	}
 	return 0;
diff --git a/x.c b/x.c
@@ -103,6 +103,8 @@ static int x_default_window_width;
 static int x_default_window_height;
 
 static long (*x_get_color_function)(int);
+static void x_translate_colors(unsigned char *data, int x, int y, int skip);
+static void x_convert_to_216(char *data, int x, int y, int skip);
 
 static void selection_request(XEvent *event);
 
@@ -110,22 +112,29 @@ static int x_fd;    /* x socket */
 static Display *x_display = NULL;   /* display */
 static unsigned char *x_display_string = NULL;
 static int x_screen;   /* screen */
-static int x_display_height,x_display_width;   /* screen dimensions */
+static int x_display_height, x_display_width;   /* screen dimensions */
 static unsigned long x_black_pixel;  /* black pixel */
 static int x_depth, x_bitmap_bpp;   /* bits per pixel and bytes per pixel */
 static int x_bitmap_scanline_pad; /* bitmap scanline_padding in bytes */
-static int x_colors;  /* colors in the palette (undefined when there's no palette) */
-static int x_have_palette;
 static int x_input_encoding;	/* locales encoding */
 static int x_bitmap_bit_order;
 
+static unsigned char x_have_palette;
+static unsigned char x_use_static_color_table;
+static unsigned char *static_color_table = NULL;
+static XColor *static_color_map = NULL;
+
+#define X_STATIC_COLORS                (x_depth < 8 ? 8 : 216)
+#define X_STATIC_CODE          (x_depth < 8 ? 801 : 833)
 
 static Window x_root_window, fake_window;
 static int fake_window_initialized = 0;
 static GC x_normal_gc = 0, x_copy_gc = 0, x_drawbitmap_gc = 0, x_scroll_gc = 0;
+static long x_normal_gc_color;
+static struct rect x_scroll_gc_rect;
 static Colormap x_colormap;
 static Atom x_delete_window_atom, x_wm_protocols_atom, x_sel_atom, x_targets_atom, x_utf8_string_atom;
-static Visual* x_default_visual;
+static Visual *x_default_visual;
 static Pixmap x_icon = 0;
 
 static XIM xim = NULL;
@@ -150,24 +159,22 @@ struct x_pixmapa
 };
 
 
-static struct
-{
+static struct {
 	unsigned char count;
 	struct graphics_device **pointer;
-}
-x_hash_table[X_HASH_TABLE_SIZE];
+} x_hash_table[X_HASH_TABLE_SIZE];
 
 /* string in clipboard is in UTF-8 */
-static unsigned char * x_my_clipboard=NULL;
+static unsigned char *x_my_clipboard = NULL;
 
 struct window_info {
 	XIC xic;
 	Window window;
 };
 
-static inline struct window_info *get_window_info(struct graphics_device *gd)
+static inline struct window_info *get_window_info(struct graphics_device *dev)
 {
-	return gd->driver_data;
+	return dev->driver_data;
 }
 
 /*----------------------------------------------------------------------*/
@@ -243,82 +250,84 @@ static int x_test_for_failure(void)
 /* suppose l<h */
 static void x_clip_number(int *n,int l,int h)
 {
-	if ((*n) < l)
-		*n=l;
-	if ((*n) > h)
-		*n=h;
+	if (*n < l)
+		*n = l;
+	if (*n > h)
+		*n = h;
 }
 
-
-static unsigned char *x_set_palette(void)
+static void x_set_palette(void)
 {
-	XColor color;
-	unsigned a;
-	unsigned limit = 1U << (x_depth <= 24 ? x_depth : 24);
-
-	x_colormap=XCreateColormap(x_display,x_root_window,x_default_visual,AllocAll);
-	XInstallColormap(x_display,x_colormap);
-
-	for (a = 0; a < limit; a++) {
-		unsigned rgb[3];
-		q_palette(limit, a, 65535, rgb);
-		color.red = rgb[0];
-		color.green = rgb[1];
-		color.blue = rgb[2];
-		color.pixel = a;
-		color.flags = DoRed | DoGreen | DoBlue;
-		XStoreColor(x_display, x_colormap, &color);
+	unsigned int a;
+	unsigned int limit = 1U << x_depth;
+
+	if (x_use_static_color_table)
+		XStoreColors(x_display, x_colormap, static_color_map, (int)limit);
+	else {
+		XColor colors[256];
+		for (a = 0; a < limit; a++) {
+			unsigned rgb[3];
+			q_palette(limit, a, 65535, rgb);
+			colors[a].red = rgb[0];
+			colors[a].green = rgb[1];
+			colors[a].blue = rgb[2];
+			colors[a].pixel = a;
+			colors[a].flags = DoRed | DoGreen | DoBlue;
+		}
+		XStoreColors(x_display, x_colormap, colors, (int)limit);
 	}
 
 	X_FLUSH();
-	return NULL;
 }
 
-static unsigned char *static_color_table = NULL;
+static unsigned char get_nearest_color(unsigned rgb[3])
+{
+	int j;
+	double best_distance = 0;
+	int best = -1;
+	for (j = 0; j < 1 << x_depth; j++) {
+		double distance;
+		if ((static_color_map[j].flags & (DoRed | DoGreen | DoBlue)) != (DoRed | DoGreen | DoBlue))
+			continue;
+		distance = rgb_distance(rgb[0], rgb[1], rgb[2], static_color_map[j].red, static_color_map[j].green, static_color_map[j].blue);
+		if (best < 0 || distance < best_distance) {
+			best = j;
+			best_distance = distance;
+		}
+	}
+	return (unsigned char)best;
+}
 
 static unsigned char *x_query_palette(void)
 {
-	int i, j;
-	XColor color[256];
-	unsigned char valid[256];
+	int i;
 	int some_valid = 0;
 	if (x_depth > 8)
 		return stracpy(cast_uchar "Static color supported for up to 8-bit depth\n");
-	memset(color, 0, sizeof color);
-	memset(valid, 0, sizeof valid);
+	if ((int)sizeof(XColor) > INT_MAX >> x_depth) overalloc();
+	static_color_map = mem_calloc(sizeof(XColor) << x_depth);
 	for (i = 0; i < 1 << x_depth; i++) {
-		color[i].pixel = i;
+		static_color_map[i].pixel = i;
 		x_prepare_for_failure();
-		XQueryColor(x_display,XDefaultColormap(x_display,x_screen), &color[i]);
-		if (!x_test_for_failure()) {
-			valid[i] = 1;
+		XQueryColor(x_display, XDefaultColormap(x_display, x_screen), &static_color_map[i]);
+		if (!x_test_for_failure() && (static_color_map[i].flags & (DoRed | DoGreen | DoBlue)) == (DoRed | DoGreen | DoBlue))
 			some_valid = 1;
-		}
+		else
+			memset(&static_color_map[i], 0, sizeof(XColor));
 	}
 	if (!some_valid)
 		return stracpy(cast_uchar "Could not query static colormap\n");
 	static_color_table = mem_calloc(256);
-	for (i = 0; i < 1 << x_depth; i++) {
-		double best_distance = 0;
-		int best = -1;
-		unsigned rgb[3];
-		q_palette(1U << x_depth, i, 65535, rgb);
-		for (j = 0; j < 1 << x_depth; j++) {
-			double distance;
-			if (!valid[j]) continue;
-			distance = rgb_distance(rgb[0], rgb[1], rgb[2], color[j].red, color[j].green, color[j].blue);
-			if (best == -1 || distance < best_distance) {
-				best = j;
-				best_distance = distance;
-			}
-		}
-		static_color_table[i] = (unsigned char)best;
+	for (i = 0; i < X_STATIC_COLORS; i++) {
+		unsigned int rgb[3];
+		q_palette(X_STATIC_COLORS, i, 65535, rgb);
+		static_color_table[i] = get_nearest_color(rgb);
 	}
 	return NULL;
 }
 
 
-static inline int trans_key(unsigned char * str, int table)
+static inline int trans_key(unsigned char *str, int table)
 {
 	if (!table) {
 		int a;
@@ -333,7 +342,7 @@ static inline int trans_key(unsigned char * str, int table)
 
 /* translates X keys to links representation */
 /* return value: 1=valid key, 0=nothing */
-static int x_translate_key(struct graphics_device *gd, XKeyEvent *e,int *key,int *flag)
+static int x_translate_key(struct graphics_device *dev, XKeyEvent *e,int *key,int *flag)
 {
 	KeySym ks = 0;
 	static XComposeStatus comp = { NULL, 0 };
@@ -342,9 +351,9 @@ static int x_translate_key(struct graphics_device *gd, XKeyEvent *e,int *key,int
 	int table = x_input_encoding < 0 ? g_kbd_codepage(&x_driver) : x_input_encoding;
 	int len;
 
-	if (get_window_info(gd)->xic) {
+	if (get_window_info(dev)->xic) {
 		Status status;
-		len = Xutf8LookupString(get_window_info(gd)->xic, e, cast_char str, str_size, &ks, &status);
+		len = Xutf8LookupString(get_window_info(dev)->xic, e, cast_char str, str_size, &ks, &status);
 		table = 0;
 		/*fprintf(stderr, "len: %d, ks %ld, status %d\n", len, ks, status);*/
 	} else
@@ -370,55 +379,55 @@ static int x_translate_key(struct graphics_device *gd, XKeyEvent *e,int *key,int
 	if (((*flag)&KBD_CTRL)&&(ks==XK_c||ks==XK_C)){*key=KBD_CTRL_C;*flag=0;return 1;}
 
 	if (ks == NoSymbol) { return 0;
-	} else if (ks == XK_Return) { *key=KBD_ENTER;
-	} else if (ks == XK_BackSpace) { *key=KBD_BS;
+	} else if (ks == XK_Return) { *key = KBD_ENTER;
+	} else if (ks == XK_BackSpace) { *key = KBD_BS;
 	} else if (ks == XK_Tab
 #ifdef XK_KP_Tab
 		|| ks == XK_KP_Tab
 #endif
-		) { *key=KBD_TAB;
+		) { *key = KBD_TAB;
 	} else if (ks == XK_Escape) {
-		*key=KBD_ESC;
+		*key = KBD_ESC;
 	} else if (ks == XK_Left
 #ifdef XK_KP_Left
 		|| ks == XK_KP_Left
 #endif
-		) { *key=KBD_LEFT;
+		) { *key = KBD_LEFT;
 	} else if (ks == XK_Right
 #ifdef XK_KP_Right
 		|| ks == XK_KP_Right
 #endif
-		) { *key=KBD_RIGHT;
+		) { *key = KBD_RIGHT;
 	} else if (ks == XK_Up
 #ifdef XK_KP_Up
 		|| ks == XK_KP_Up
 #endif
-		) { *key=KBD_UP;
+		) { *key = KBD_UP;
 	} else if (ks == XK_Down
 #ifdef XK_KP_Down
 		|| ks == XK_KP_Down
 #endif
-		) { *key=KBD_DOWN;
+		) { *key = KBD_DOWN;
 	} else if (ks == XK_Insert
 #ifdef XK_KP_Insert
 		|| ks == XK_KP_Insert
 #endif
-		) { *key=KBD_INS;
+		) { *key = KBD_INS;
 	} else if (ks == XK_Delete
 #ifdef XK_KP_Delete
 		|| ks == XK_KP_Delete
 #endif
-		) { *key=KBD_DEL;
+		) { *key = KBD_DEL;
 	} else if (ks == XK_Home
 #ifdef XK_KP_Home
 		|| ks == XK_KP_Home
 #endif
-		) { *key=KBD_HOME;
+		) { *key = KBD_HOME;
 	} else if (ks == XK_End
 #ifdef XK_KP_End
 		|| ks == XK_KP_End
 #endif
-		) { *key=KBD_END;
+		) { *key = KBD_END;
 	} else if (0
 #ifdef XK_KP_Page_Up
 		|| ks == XK_KP_Page_Up
@@ -426,7 +435,7 @@ static int x_translate_key(struct graphics_device *gd, XKeyEvent *e,int *key,int
 #ifdef XK_Page_Up
 		|| ks == XK_Page_Up
 #endif
-		) { *key=KBD_PAGE_UP;
+		) { *key = KBD_PAGE_UP;
 	} else if (0
 #ifdef XK_KP_Page_Down
 		|| ks == XK_KP_Page_Down
@@ -434,67 +443,102 @@ static int x_translate_key(struct graphics_device *gd, XKeyEvent *e,int *key,int
 #ifdef XK_Page_Down
 		|| ks == XK_Page_Down
 #endif
-		) { *key=KBD_PAGE_DOWN;
+		) { *key = KBD_PAGE_DOWN;
 	} else if (ks == XK_F1
 #ifdef XK_KP_F1
 		|| ks == XK_KP_F1
 #endif
-		) { *key=KBD_F1;
+		) { *key = KBD_F1;
 	} else if (ks == XK_F2
 #ifdef XK_KP_F2
 		|| ks == XK_KP_F2
 #endif
-		) { *key=KBD_F2;
+		) { *key = KBD_F2;
 	} else if (ks == XK_F3
 #ifdef XK_KP_F3
 		|| ks == XK_KP_F3
 #endif
-		) { *key=KBD_F3;
+		) { *key = KBD_F3;
 	} else if (ks == XK_F4
 #ifdef XK_KP_F4
 		|| ks == XK_KP_F4
 #endif
-		) { *key=KBD_F4;
-	} else if (ks == XK_F5) { *key=KBD_F5;
-	} else if (ks == XK_F6) { *key=KBD_F6;
-	} else if (ks == XK_F7) { *key=KBD_F7;
-	} else if (ks == XK_F8) { *key=KBD_F8;
-	} else if (ks == XK_F9) { *key=KBD_F9;
-	} else if (ks == XK_F10) { *key=KBD_F10;
-	} else if (ks == XK_F11) { *key=KBD_F11;
-	} else if (ks == XK_F12) { *key=KBD_F12;
-	} else if (ks == XK_KP_Subtract) { *key='-';
-	} else if (ks == XK_KP_Decimal) { *key='.';
-	} else if (ks == XK_KP_Divide) { *key='/';
-	} else if (ks == XK_KP_Space) { *key=' ';
-	} else if (ks == XK_KP_Enter) { *key=KBD_ENTER;
-	} else if (ks == XK_KP_Equal) { *key='=';
-	} else if (ks == XK_KP_Multiply) { *key='*';
-	} else if (ks == XK_KP_Add) { *key='+';
-	} else if (ks == XK_KP_0) { *key='0';
-	} else if (ks == XK_KP_1) { *key='1';
-	} else if (ks == XK_KP_2) { *key='2';
-	} else if (ks == XK_KP_3) { *key='3';
-	} else if (ks == XK_KP_4) { *key='4';
-	} else if (ks == XK_KP_5) { *key='5';
-	} else if (ks == XK_KP_6) { *key='6';
-	} else if (ks == XK_KP_7) { *key='7';
-	} else if (ks == XK_KP_8) { *key='8';
-	} else if (ks == XK_KP_9) { *key='9';
-	} else if (ks & 0x8000) { return 0;
-	} else { *key=((*flag)&KBD_CTRL)?(int)ks&255:trans_key(str,table);
+		) { *key = KBD_F4;
+	} else if (ks == XK_F5) { *key = KBD_F5;
+	} else if (ks == XK_F6) { *key = KBD_F6;
+	} else if (ks == XK_F7) { *key = KBD_F7;
+	} else if (ks == XK_F8) { *key = KBD_F8;
+	} else if (ks == XK_F9) { *key = KBD_F9;
+	} else if (ks == XK_F10) { *key = KBD_F10;
+	} else if (ks == XK_F11) { *key = KBD_F11;
+	} else if (ks == XK_F12) { *key = KBD_F12;
+	} else if (ks == XK_KP_Subtract) { *key = '-';
+	} else if (ks == XK_KP_Decimal) { *key = '.';
+	} else if (ks == XK_KP_Divide) { *key = '/';
+	} else if (ks == XK_KP_Space) { *key = ' ';
+	} else if (ks == XK_KP_Enter) { *key = KBD_ENTER;
+	} else if (ks == XK_KP_Equal) { *key = '=';
+	} else if (ks == XK_KP_Multiply) { *key = '*';
+	} else if (ks == XK_KP_Add) { *key = '+';
+	} else if (ks == XK_KP_0) { *key = '0';
+	} else if (ks == XK_KP_1) { *key = '1';
+	} else if (ks == XK_KP_2) { *key = '2';
+	} else if (ks == XK_KP_3) { *key = '3';
+	} else if (ks == XK_KP_4) { *key = '4';
+	} else if (ks == XK_KP_5) { *key = '5';
+	} else if (ks == XK_KP_6) { *key = '6';
+	} else if (ks == XK_KP_7) { *key = '7';
+	} else if (ks == XK_KP_8) { *key = '8';
+	} else if (ks == XK_KP_9) { *key = '9';
+#ifdef XK_Undo
+	} else if (ks == XK_Undo) { *key = KBD_UNDO;
+#endif
+#ifdef XK_Redo
+	} else if (ks == XK_Redo) { *key = KBD_REDO;
+#endif
+#ifdef XK_Menu
+	} else if (ks == XK_Menu) { *key = KBD_MENU;
+#endif
+#ifdef XK_Find
+	} else if (ks == XK_Find) { *key = KBD_FIND;
+#endif
+#ifdef XK_Cancel
+	} else if (ks == XK_Cancel) { *key = KBD_STOP;
+#endif
+#ifdef XK_Help
+	} else if (ks == XK_Help) { *key = KBD_HELP;
+#endif
+	} else if (ks & 0x8000) {
+		unsigned char *str = (unsigned char *)XKeysymToString(ks);
+		if (str) {
+			if (!casestrcmp(str, cast_uchar "XF86Copy")) { *key = KBD_COPY; return 1; }
+			if (!casestrcmp(str, cast_uchar "XF86Paste")) { *key = KBD_PASTE; return 1; }
+			if (!casestrcmp(str, cast_uchar "XF86Cut")) { *key = KBD_CUT; return 1; }
+			if (!casestrcmp(str, cast_uchar "SunProps")) { *key = KBD_PROPS; return 1; }
+			if (!casestrcmp(str, cast_uchar "SunFront")) { *key = KBD_FRONT; return 1; }
+			if (!casestrcmp(str, cast_uchar "SunOpen")) { *key = KBD_OPEN; return 1; }
+			if (!casestrcmp(str, cast_uchar "XF86Search")) { *key = KBD_FIND; return 1; }
+			if (!casestrcmp(str, cast_uchar "XF86Favorites")) { *key = KBD_BOOKMARKS; return 1; }
+			if (!casestrcmp(str, cast_uchar "XF86Reload")) { *key = KBD_RELOAD; return 1; }
+			if (!casestrcmp(str, cast_uchar "XF86Stop")) { *key = KBD_STOP; return 1; }
+			if (!casestrcmp(str, cast_uchar "XF86Forward")) { *key = KBD_FORWARD; return 1; }
+			if (!casestrcmp(str, cast_uchar "XF86Back")) { *key = KBD_BACK; return 1; }
+			if (!casestrcmp(str, cast_uchar "XF86Open")) { *key = KBD_OPEN; return 1; }
+			if (!casestrcmp(str, cast_uchar "XF86OpenURL")) { *key = KBD_OPEN; return 1; }
+		}
+		return 0;
+	} else { *key = ((*flag)&KBD_CTRL)?(int)ks&255:trans_key(str,table);
 	}
 	return 1;
 }
 
-static void x_hash_table_init(void)
+static void x_init_hash_table(void)
 {
 	int a;
 
-	for (a=0;a<X_HASH_TABLE_SIZE;a++)
-	{
-		x_hash_table[a].count=0;
-		x_hash_table[a].pointer=NULL;
+	for (a = 0; a < X_HASH_TABLE_SIZE; a++) {
+		x_hash_table[a].count = 0;
+		x_hash_table[a].pointer = NULL;
 	}
 }
 
@@ -502,21 +546,26 @@ static void x_clear_clipboard(void);
 
 static void x_free_hash_table(void)
 {
-	int a,b;
+	int a;
 
+	process_events_in_progress = 0;
+	flush_in_progress = 0;
 	unregister_bottom_half(x_process_events, NULL);
 	unregister_bottom_half(x_do_flush, NULL);
 
 	for (a = 0; a < X_HASH_TABLE_SIZE; a++) {
-		for (b = 0; b < x_hash_table[a].count; b++)
-			free(x_hash_table[a].pointer[b]);
+		if (x_hash_table[a].count)
+			internal("x_free_hash_table: the table is not empty");
 		free(x_hash_table[a].pointer);
 	}
 
 	x_clear_clipboard();
 
 	free(static_color_table);
+	free(static_color_map);
 	static_color_table = NULL;
+	static_color_map = NULL;
+
 
 	if (x_display) {
 		if (x_icon) {
@@ -557,75 +606,49 @@ static void x_free_hash_table(void)
 	x_display_string = NULL;
 }
 
-
-
 /* returns graphics device structure which belonging to the window */
-static struct graphics_device *x_find_gd(Window *win)
+static struct graphics_device *x_find_gd(Window win)
 {
-	int a,b;
+	int a, b;
 
-	a=(int)(*win)&(X_HASH_TABLE_SIZE-1);
-	if (!x_hash_table[a].count)return 0;
-	for (b=0;b<x_hash_table[a].count;b++)
-	{
-		if (get_window_info(x_hash_table[a].pointer[b])->window == *win)
+	a=(int)win & (X_HASH_TABLE_SIZE - 1);
+	for (b = 0; b < x_hash_table[a].count; b++) {
+		if (get_window_info(x_hash_table[a].pointer[b])->window == win)
 			return x_hash_table[a].pointer[b];
 	}
 	return NULL;
 }
 
-static void x_update_driver_param(int w, int h)
-{
-	int l=0;
-
-	if (n_wins!=1)return;
-
-	x_default_window_width=w;
-	x_default_window_height=h;
-
-	free(x_driver_param);
-	x_driver_param = init_str();
-	add_num_to_str(&x_driver_param,&l,x_default_window_width);
-	add_to_str(&x_driver_param,&l,cast_uchar "x");
-	add_num_to_str(&x_driver_param,&l,x_default_window_height);
-}
-
-
-
 /* adds graphics device to hash table */
-static void x_add_to_table(struct graphics_device* gd)
+static void x_add_to_table(struct graphics_device *dev)
 {
-	int a=(int)get_window_info(gd)->window & (X_HASH_TABLE_SIZE-1);
-	int c=x_hash_table[a].count;
+	int a = (int)get_window_info(dev)->window & (X_HASH_TABLE_SIZE - 1);
+	int c = x_hash_table[a].count;
 
-	if (!c)
-		x_hash_table[a].pointer = xmalloc(sizeof(struct graphics_device *));
-	else {
-		if ((unsigned)c > INT_MAX / sizeof(struct graphics_device *) - 1)
-			overalloc();
-		x_hash_table[a].pointer = xrealloc(x_hash_table[a].pointer,
-						(c + 1) * sizeof(struct graphics_device *));
-	}
+	if ((unsigned)c > INT_MAX / sizeof(struct graphics_device *) - 1)
+		overalloc();
+	x_hash_table[a].pointer = xrealloc(x_hash_table[a].pointer,
+				(c + 1) * sizeof(struct graphics_device *));
 
-	x_hash_table[a].pointer[c] = gd;
+	x_hash_table[a].pointer[c] = dev;
 	x_hash_table[a].count++;
 }
 
-
 /* removes graphics device from table */
-static void x_remove_from_table(Window *win)
+static void x_remove_from_table(Window win)
 {
-	int a=(int)(*win)&(X_HASH_TABLE_SIZE-1);
+	int a = (int)win & (X_HASH_TABLE_SIZE - 1);
 	int b;
 
-	for (b=0;b<x_hash_table[a].count;b++)
-		if (get_window_info(x_hash_table[a].pointer[b])->window == *win)
-		{
-			memmove(x_hash_table[a].pointer+b,x_hash_table[a].pointer+b+1,(x_hash_table[a].count-b-1)*sizeof(struct graphics_device *));
+	for (b = 0; b < x_hash_table[a].count; b++) {
+		if (get_window_info(x_hash_table[a].pointer[b])->window == win) {
+			memmove(x_hash_table[a].pointer + b, x_hash_table[a].pointer + b + 1, (x_hash_table[a].count - b - 1) * sizeof(struct graphics_device *));
 			x_hash_table[a].count--;
-			x_hash_table[a].pointer = xrealloc(x_hash_table[a].pointer,
-							x_hash_table[a].count * sizeof(struct graphics_device *));
+			x_hash_table[a].pointer = xrealloc(x_hash_table[a].pointer, x_hash_table[a].count * sizeof(struct graphics_device *));
+			return;
 		}
+	}
+	internal("x_remove_from_table: window not found");
 }
 
 
@@ -636,11 +659,46 @@ static void x_clear_clipboard(void)
 }
 
 
+static void x_update_driver_param(int w, int h)
+{
+	int l=0;
+
+	if (n_wins != 1) return;
+
+	x_default_window_width = w;
+	x_default_window_height = h;
+
+	free(x_driver_param);
+	x_driver_param = init_str();
+	add_num_to_str(&x_driver_param, &l, x_default_window_width);
+	add_to_str(&x_driver_param, &l ,cast_uchar "x");
+	add_num_to_str(&x_driver_param, &l, x_default_window_height);
+}
+
+
+static int x_decode_button(int b)
+{
+	switch (b) {
+		case 1: return B_LEFT;
+		case 3: return B_RIGHT;
+		case 2: return B_MIDDLE;
+		case 4: return B_WHEELUP;
+		case 5: return B_WHEELDOWN;
+		case 6: return B_WHEELLEFT;
+		case 7: return B_WHEELRIGHT;
+		case 8: return B_FOURTH;
+		case 9: return B_FIFTH;
+		case 10: return B_SIXTH;
+
+	}
+	return -1;
+}
+
 static void x_process_events(void *data)
 {
 	XEvent event;
 	XEvent last_event;
-	struct graphics_device *gd;
+	struct graphics_device *dev;
 	int last_was_mouse;
 	int replay_event = 0;
 
@@ -668,8 +726,8 @@ static void x_process_events(void *data)
 				MESSAGE(txt);
 			}
 #endif
-			gd=x_find_gd(&(last_event.xmotion.window));
-			if (!gd)break;
+			dev = x_find_gd(last_event.xmotion.window);
+			if (!dev) break;
 			a=B_LEFT;
 			b=B_MOVE;
 			if ((last_event.xmotion.state)&Button1Mask)
@@ -696,9 +754,9 @@ static void x_process_events(void *data)
 				MESSAGE("right button/drag\n");
 #endif
 			}
-			x_clip_number(&(last_event.xmotion.x),gd->size.x1,gd->size.x2);
-			x_clip_number(&(last_event.xmotion.y),gd->size.y1,gd->size.y2);
-			gd->mouse_handler(gd,last_event.xmotion.x,last_event.xmotion.y,a|b);
+			x_clip_number(&last_event.xmotion.x, dev->size.x1, dev->size.x2 - 1);
+			x_clip_number(&last_event.xmotion.y, dev->size.y1, dev->size.y2 - 1);
+			dev->mouse_handler(dev, last_event.xmotion.x, last_event.xmotion.y, a | b);
 		}
 
 		switch (event.type) {
@@ -707,14 +765,14 @@ static void x_process_events(void *data)
 		{
 			struct rect r;
 
-			gd = x_find_gd(&event.xgraphicsexpose.drawable);
-			if (!gd)
+			dev = x_find_gd(event.xgraphicsexpose.drawable);
+			if (!dev)
 				break;
 			r.x1 = event.xgraphicsexpose.x;
 			r.y1 = event.xgraphicsexpose.y;
 			r.x2 = event.xgraphicsexpose.x + event.xgraphicsexpose.width;
 			r.y2 = event.xgraphicsexpose.y + event.xgraphicsexpose.height;
-			gd->redraw_handler(gd, &r);
+			dev->redraw_handler(dev, &r);
 		}
 			break;
 
@@ -723,41 +781,41 @@ static void x_process_events(void *data)
 		{
 			struct rect r;
 
-			gd = x_find_gd(&event.xexpose.window);
-			if (!gd)
+			dev = x_find_gd(event.xexpose.window);
+			if (!dev)
 				break;
 			r.x1 = event.xexpose.x;
 			r.y1 = event.xexpose.y;
 			r.x2 = event.xexpose.x + event.xexpose.width;
 			r.y2 = event.xexpose.y + event.xexpose.height;
-			gd->redraw_handler(gd, &r);
+			dev->redraw_handler(dev, &r);
 		}
 			break;
 
 		/* resize window */
 		case ConfigureNotify:
-			gd = x_find_gd(&event.xconfigure.window);
-			if (!gd)
+			dev = x_find_gd(event.xconfigure.window);
+			if (!dev)
 				break;
 			/* when window only moved and size is the same, do nothing */
-			if (gd->size.x2 == event.xconfigure.width
-			&& gd->size.y2 == event.xconfigure.height)
+			if (dev->size.x2 == event.xconfigure.width
+			&& dev->size.y2 == event.xconfigure.height)
 				break;
-configure_notify_again:
-			gd->size.x2 = event.xconfigure.width;
-			gd->size.y2 = event.xconfigure.height;
+ configure_notify_again:
+			dev->size.x2 = event.xconfigure.width;
+			dev->size.y2 = event.xconfigure.height;
 			x_update_driver_param(event.xconfigure.width, event.xconfigure.height);
 			while (XCheckWindowEvent(x_display,
-					get_window_info(gd)->window,
+					get_window_info(dev)->window,
 					ExposureMask, &event) == True);
 			if (XCheckWindowEvent(x_display,
-					get_window_info(gd)->window,
+					get_window_info(dev)->window,
 					StructureNotifyMask, &event) == True) {
 				if (event.type == ConfigureNotify)
 					goto configure_notify_again;
 				replay_event = 1;
 			}
-			gd->resize_handler(gd);
+			dev->resize_handler(dev);
 			break;
 
 		case KeyPress:
@@ -765,11 +823,11 @@ configure_notify_again:
 			int f, k;
 			if (XFilterEvent(&event, None))
 				break;
-			gd = x_find_gd(&event.xkey.window);
-			if (!gd)
+			dev = x_find_gd(event.xkey.window);
+			if (!dev)
 				break;
-			if (x_translate_key(gd, (XKeyEvent*)(&event), &k, &f))
-				gd->keyboard_handler(gd, k, f);
+			if (x_translate_key(dev, (XKeyEvent*)(&event), &k, &f))
+				dev->keyboard_handler(dev, k, f);
 		}
 			break;
 
@@ -781,90 +839,40 @@ configure_notify_again:
 			/*else fallthrough*/
 
 		case DestroyNotify:
-			gd = x_find_gd(&event.xkey.window);
-			if (!gd)
+			dev = x_find_gd(event.xkey.window);
+			if (!dev)
 				break;
 
-			gd->keyboard_handler(gd, KBD_CLOSE, 0);
+			dev->keyboard_handler(dev, KBD_CLOSE, 0);
 			break;
 
 		case ButtonRelease:
 		{
 			int a;
-			gd = x_find_gd(&event.xbutton.window);
-			if (!gd)
+			dev = x_find_gd(event.xbutton.window);
+			if (!dev)
 				break;
 			last_was_mouse = 0;
-			switch (event.xbutton.button) {
-			case 1:
-				a = B_LEFT;
-				break;
-			case 2:
-				a = B_MIDDLE;
-				break;
-			case 3:
-				a = B_RIGHT;
-				break;
-			case 8:
-				a = B_FOURTH;
-				break;
-			case 9:
-				a = B_FIFTH;
-				break;
-			default:
-				goto r_xx;
+			if ((a = x_decode_button(event.xbutton.button)) >= 0 && !BM_IS_WHEEL(a)) {
+				x_clip_number(&event.xmotion.x, dev->size.x1, dev->size.x2 - 1);
+				x_clip_number(&event.xmotion.y, dev->size.y1, dev->size.y2 - 1);
+				dev->mouse_handler(dev, event.xbutton.x, event.xbutton.y, a | B_UP);
 			}
-			x_clip_number(&event.xmotion.x, gd->size.x1, gd->size.x2);
-			x_clip_number(&event.xmotion.y, gd->size.y1, gd->size.y2);
-			gd->mouse_handler(gd, event.xbutton.x, event.xbutton.y,
-					a|B_UP);
-r_xx:;
 		}
 			break;
 
 		case ButtonPress:
 		{
 			int a;
-			gd = x_find_gd(&event.xbutton.window);
-			if (!gd)
+			dev = x_find_gd(event.xbutton.window);
+			if (!dev)
 				break;
 			last_was_mouse = 0;
-			switch (event.xbutton.button) {
-			case 1:
-				a = B_LEFT;
-				break;
-			case 2:
-				a = B_MIDDLE;
-				break;
-			case 3:
-				a = B_RIGHT;
-				break;
-			case 4:
-				a = B_WHEELUP;
-				break;
-			case 5:
-				a = B_WHEELDOWN;
-				break;
-			case 6:
-				a = B_WHEELLEFT;
-				break;
-			case 7:
-				a = B_WHEELRIGHT;
-				break;
-			case 8:
-				a = B_FOURTH;
-				break;
-			case 9:
-				a = B_FIFTH;
-				break;
-			default:
-				goto p_xx;
+			if ((a = x_decode_button(event.xbutton.button)) >= 0) {
+				x_clip_number(&(event.xmotion.x), dev->size.x1, dev->size.x2 - 1);
+				x_clip_number(&(event.xmotion.y), dev->size.y1, dev->size.y2 - 1);
+				dev->mouse_handler(dev, event.xbutton.x, event.xbutton.y, a | (!BM_IS_WHEEL(a) ? B_DOWN : B_MOVE));
 			}
-			x_clip_number(&event.xmotion.x, gd->size.x1, gd->size.x2);
-			x_clip_number(&event.xmotion.y, gd->size.y1, gd->size.y2);
-			gd->mouse_handler(gd, event.xbutton.x, event.xbutton.y,
-				a | (!BM_IS_WHEEL(a) ? B_DOWN : B_MOVE));
-p_xx:;
 		}
 				break;
 
@@ -900,8 +908,8 @@ p_xx:;
 		int a, b;
 
 		last_was_mouse = 0;
-		gd = x_find_gd(&last_event.xmotion.window);
-		if (!gd)
+		dev = x_find_gd(last_event.xmotion.window);
+		if (!dev)
 			goto ret;
 		a = B_LEFT;
 		b = B_MOVE;
@@ -917,17 +925,17 @@ p_xx:;
 			a = B_RIGHT;
 			b = B_DRAG;
 		}
-		x_clip_number(&last_event.xmotion.x, gd->size.x1, gd->size.x2);
-		x_clip_number(&last_event.xmotion.y, gd->size.y1, gd->size.y2);
-		gd->mouse_handler(gd, last_event.xmotion.x, last_event.xmotion.y,
-				a | b);
+		x_clip_number(&last_event.xmotion.x, dev->size.x1, dev->size.x2 - 1);
+		x_clip_number(&last_event.xmotion.y, dev->size.y1, dev->size.y2 - 1);
+		dev->mouse_handler(dev, last_event.xmotion.x,
+			last_event.xmotion.y, a | b);
 	}
 ret:;
 }
 
 
 /* returns pointer to string with driver parameter or NULL */
-static unsigned char * x_get_driver_param(void)
+static unsigned char *x_get_driver_param(void)
 {
 	return x_driver_param;
 }
@@ -942,12 +950,15 @@ static XIC x_open_xic(Window w);
 /* initiate connection with X server */
 static unsigned char *x_init_driver(unsigned char *param, unsigned char *display)
 {
+	unsigned char *err;
+	int l;
+
 	XGCValues gcv;
 	XSetWindowAttributes win_attr;
 	XVisualInfo vinfo;
 	int misordered = -1;
 
-	x_hash_table_init();
+	x_init_hash_table();
 
 	n_wins = 0;
 
@@ -980,14 +991,14 @@ static unsigned char *x_init_driver(unsigned char *param, unsigned char *display
 
 	x_display = XOpenDisplay((char *)display);
 	if (!x_display) {
-		unsigned char *err = init_str();
-		int l = 0;
+		err = init_str();
+		l = 0;
 
 		add_to_str(&err, &l, cast_uchar "Can't open display \"");
 		add_to_str(&err, &l, display ? display : (unsigned char *)"(null)");
 		add_to_str(&err, &l, cast_uchar "\"\n");
 		x_free_hash_table();
-		return err;
+		goto ret_err;
 	}
 
 	x_bitmap_bit_order = BitmapBitOrder(x_display);
@@ -1013,8 +1024,8 @@ static unsigned char *x_init_driver(unsigned char *param, unsigned char *display
 
 		if (*x_driver_param < '0' || *x_driver_param > '9') {
 invalid_param:
-			x_free_hash_table();
-			return stracpy(cast_uchar "Invalid parameter\n");
+			err = stracpy(cast_uchar "Invalid parameter\n");
+			goto ret_err;
 		}
 		w = strtoul((char *)x_driver_param, (char **)&e, 10);
 		if (upcase(*e) != 'X')
@@ -1033,40 +1044,37 @@ invalid_param:
 
 	/* find best visual */
 	{
-#define DEPTHS 5
-#define CLASSES 3
-		int depths[DEPTHS] = { 24, 16, 15, 8, 4 };
-		int classes[CLASSES] = { TrueColor, PseudoColor, StaticColor }; /* FIXME: dodelat DirectColor */
-		int a,b;
-
-		for (a = 0; a < DEPTHS; a++)
-			for (b = 0; b < CLASSES; b++) {
-				if (XMatchVisualInfo(x_display, x_screen,
-						depths[a], classes[b], &vinfo)) {
+		static int depths[] = { 24, 16, 15, 8, 4 };
+		static int classes[] = { TrueColor, PseudoColor, StaticColor }; /* FIXME: dodelat DirectColor */
+		int a, b;
+
+		for (a = 0; a < array_elements(depths); a++)
+			for (b = 0; b < array_elements(classes); b++) {
+				if ((classes[b] == PseudoColor || classes[b] == StaticColor) && depths[a] > 8)
+					continue;
+				if (classes[b] == TrueColor && depths[a] <= 8)
+					continue;
+
+				if (XMatchVisualInfo(x_display, x_screen, depths[a], classes[b], &vinfo)) {
 					XPixmapFormatValues *pfm;
 					int n, i;
 
 					x_default_visual = vinfo.visual;
 					x_depth = vinfo.depth;
 
-					if (classes[b] == StaticColor
-					&& depths[a] > 8)
-						continue;
-
 					/* determine bytes per pixel */
 					pfm = XListPixmapFormats(x_display, &n);
 					for (i = 0; i < n; i++)
 						if (pfm[i].depth == x_depth) {
 							x_bitmap_bpp = pfm[i].bits_per_pixel < 8 ? 1 : ((pfm[i].bits_per_pixel) >> 3);
-							x_bitmap_scanline_pad = (pfm[i].scanline_pad) >> 3;
+							x_bitmap_scanline_pad = pfm[i].scanline_pad >> 3;
 							XFree(pfm);
 							goto bytes_per_pixel_found;
 						}
 					if (n)
 						XFree(pfm);
 					continue;
-bytes_per_pixel_found:
-
+ bytes_per_pixel_found:
 					/* test misordered flag */
 					switch(x_depth) {
 					case 4:
@@ -1124,9 +1132,27 @@ bytes_per_pixel_found:
 				}
 			}
 
-		x_free_hash_table();
-		return stracpy(cast_uchar "No supported color depth found.\n");
- visual_found:;
+		err = stracpy(cast_uchar "No supported color depth found.\n");
+		goto ret_err;
+	}
+
+ visual_found:
+
+	x_driver.flags &= ~GD_SWITCH_PALETTE;
+	x_have_palette = 0;
+	x_use_static_color_table = 0;
+	if (vinfo.class == StaticColor || vinfo.class == PseudoColor) {
+		if ((err = x_query_palette()))
+			goto ret_err;
+		x_use_static_color_table = 1;
+	}
+	if (vinfo.class == PseudoColor) {
+		if (x_driver.param->palette_mode)
+			x_use_static_color_table = 0;
+		x_have_palette = 1;
+		x_colormap = XCreateColormap(x_display, x_root_window, x_default_visual, AllocAll);
+		x_set_palette();
+		x_driver.flags |= GD_SWITCH_PALETTE;
 	}
 
 	x_driver.depth = 0;
@@ -1137,52 +1163,14 @@ bytes_per_pixel_found:
 	/* check if depth is sane */
 	if (x_driver.depth == 707)
 		x_driver.depth = 195;
-	switch (x_driver.depth) {
-	case 33:
-	case 65:
-	case 122:
-	case 130:
-	case 451:
-	case 195:
-	case 196:
-	case 378:
-	case 386:
-	case 452:
-	case 708:
-		break;
-	default: {
-			char err[MAX_STR_LEN];
-
-			snprintf(err, MAX_STR_LEN,
-				"Unsupported graphics mode: x_depth = %d, bits_per_pixel = %d, bytes_per_pixel = %d\n",
-				x_driver.depth, x_depth, x_bitmap_bpp);
-			x_free_hash_table();
-			return (unsigned char *)strdup(err);
-	}
-	}
-
+	if (x_use_static_color_table)
+		x_driver.depth = X_STATIC_CODE;
 	x_get_color_function = get_color_fn(x_driver.depth);
-	if (!x_get_color_function)
-		internal("Unknown bit depth: %d", x_driver.depth);
-
-	x_colors = 1 << x_depth;
-	x_have_palette = 0;
-
-	switch (vinfo.class) {
-		unsigned char *t;
-	case DirectColor:
-	case PseudoColor:
-		x_have_palette = 1;
-		if ((t = x_set_palette())) {
-			x_free_hash_table();
-			return t;
-		}
-	case StaticColor:
-		if ((t = x_query_palette())) {
-			x_free_hash_table();
-			return t;
-		}
-	default:;
+	if (!x_get_color_function) {
+		unsigned char nerr[MAX_STR_LEN];
+		snprintf(cast_char nerr, MAX_STR_LEN, "Unsupported graphics mode: x_depth=%d, bits_per_pixel=%d, bytes_per_pixel=%d\n",x_driver.depth, x_depth, x_bitmap_bpp);
+		err = stracpy(nerr);
+		goto ret_err;
 	}
 
 	x_black_pixel = BlackPixel(x_display, x_screen);
@@ -1202,45 +1190,43 @@ bytes_per_pixel_found:
 	if (x_have_palette)
 		win_attr.colormap = x_colormap;
 	else
-		win_attr.colormap = XCreateColormap(x_display, x_root_window,
-						x_default_visual, AllocNone);
-
-	win_attr.border_pixel = x_black_pixel;
+		win_attr.colormap = XDefaultColormap(x_display, x_screen);
 
 	fake_window = XCreateWindow(x_display, x_root_window, 0, 0, 10, 10, 0,
 				x_depth, CopyFromParent, x_default_visual,
-				CWColormap | CWBorderPixel, &win_attr);
+				CWColormap, &win_attr);
 
 	fake_window_initialized = 1;
 
 	x_normal_gc = XCreateGC(x_display, fake_window,
 			GCFillStyle | GCBackground, &gcv);
 	if (!x_normal_gc) {
-		x_free_hash_table();
-		return stracpy(cast_uchar "Cannot create graphic context.\n");
+		err = stracpy(cast_uchar "Cannot create graphic context.\n");
+		goto ret_err;
 	}
+	x_normal_gc_color = 0;
+	XSetForeground(x_display, x_normal_gc, x_normal_gc_color);
+	XSetLineAttributes(x_display, x_normal_gc, 1, LineSolid, CapRound, JoinRound);
 
 	x_copy_gc = XCreateGC(x_display, fake_window, GCFunction, &gcv);
 	if (!x_copy_gc) {
-		x_free_hash_table();
-		return stracpy(cast_uchar "Cannot create graphic context.\n");
+		err = stracpy(cast_uchar "Cannot create graphic context.\n");
+		goto ret_err;
 	}
 
 	x_drawbitmap_gc = XCreateGC(x_display, fake_window, GCFunction, &gcv);
 	if (!x_drawbitmap_gc) {
-		x_free_hash_table();
-		return stracpy(cast_uchar "Cannot create graphic context.\n");
+		err = stracpy(cast_uchar "Cannot create graphic context.\n");
+		goto ret_err;
 	}
 
 	x_scroll_gc = XCreateGC(x_display, fake_window,
 			GCGraphicsExposures | GCBackground, &gcv);
 	if (!x_scroll_gc) {
-		x_free_hash_table();
-		return stracpy(cast_uchar "Cannot create graphic context.\n");
+		err = stracpy(cast_uchar "Cannot create graphic context.\n");
+		goto ret_err;
 	}
-
-	XSetLineAttributes(x_display, x_normal_gc, 1, LineSolid, CapRound,
-			JoinRound);
+	x_scroll_gc_rect.x1 = x_scroll_gc_rect.x2 = x_scroll_gc_rect.y1 = x_scroll_gc_rect.y2 = -1;
 
 	{
 #if defined(LC_CTYPE)
@@ -1249,17 +1235,14 @@ bytes_per_pixel_found:
 		 * current locale, even if we use Xutf8LookupString.
 		 * So, try to set locale to utf8 for the input method.
 		 */
-		unsigned char *l, *m, *d;
+		unsigned char *l;
 		int len;
 		l = cast_uchar setlocale(LC_CTYPE, "");
 		len = l ? (int)strlen((char *)l) : 0;
 		if (l
 		&& !(len >= 5 && !casestrcmp(l + len - 5, cast_uchar ".utf8"))
 		&& !(len >= 6 && !casestrcmp(l + len - 6, cast_uchar ".utf-8"))) {
-			m = stracpy(l);
-			d = cast_uchar strchr(cast_const_char m, '.');
-			if (d)
-				*d = 0;
+			unsigned char *m = memacpy(l, strcspn(cast_const_char l, "."));
 			add_to_strn(&m, cast_uchar ".UTF-8");
 			l = cast_uchar setlocale(LC_CTYPE, (char *)m);
 			free(m);
@@ -1296,6 +1279,10 @@ bytes_per_pixel_found:
 	XSync(x_display, False);
 	X_SCHEDULE_PROCESS_EVENTS();
 	return NULL;
+
+ ret_err:
+	x_free_hash_table();
+	return err;
 }
 
 
@@ -1314,34 +1301,33 @@ static XIC x_open_xic(Window w)
 }
 
 /* create new window */
-static struct graphics_device* x_init_device(void)
+static struct graphics_device *x_init_device(void)
 {
-	struct graphics_device *gd;
+	struct graphics_device *dev;
 	XWMHints wm_hints;
 	XClassHint class_hints;
 	XTextProperty windowName;
-	unsigned char *links_name=cast_uchar "Links";
+	unsigned char *links_name = cast_uchar "Links";
 	XSetWindowAttributes win_attr;
 	struct window_info *wi;
 
-	gd = xmalloc(sizeof(struct graphics_device));
+	dev = xmalloc(sizeof(struct graphics_device));
 
 	wi = mem_calloc(sizeof(struct window_info));
 
-	gd->size.x1 = 0;
-	gd->size.y1 = 0;
-	gd->size.x2 = x_default_window_width;
-	gd->size.y2 = x_default_window_height;
+	dev->size.x1 = 0;
+	dev->size.y1 = 0;
+	dev->size.x2 = x_default_window_width;
+	dev->size.y2 = x_default_window_height;
 
 	if (x_have_palette)
 		win_attr.colormap = x_colormap;
 	else
-		win_attr.colormap = XCreateColormap(x_display, x_root_window,
-						x_default_visual, AllocNone);
+		win_attr.colormap = XDefaultColormap(x_display, x_screen);
 	win_attr.border_pixel = x_black_pixel;
 
-	wi->window = XCreateWindow(x_display, x_root_window, gd->size.x1,
-				gd->size.y1, gd->size.x2, gd->size.y2,
+	wi->window = XCreateWindow(x_display, x_root_window, dev->size.x1,
+				dev->size.y1, dev->size.x2, dev->size.y2,
 				X_BORDER_WIDTH, x_depth, InputOutput,
 				x_default_visual, CWColormap | CWBorderPixel,
 				&win_attr);
@@ -1349,11 +1335,12 @@ static struct graphics_device* x_init_device(void)
 		XImage *img;
 		char *data;
 		int w, h, skip;
+
 		get_links_icon(&data, &w, &h, &skip, x_bitmap_scanline_pad);
+		x_convert_to_216(data, w, h, skip);
 
-		img = XCreateImage(x_display, x_default_visual, x_depth, ZPixmap,
-				0, 0, w, h, x_bitmap_scanline_pad << 3,
-				w * ((x_driver.depth) & 7));
+		img = XCreateImage(x_display, x_default_visual, x_depth, ZPixmap, 0,
+			data, w, h, x_bitmap_scanline_pad << 3, skip);
 		if (!img) {
 			x_icon = 0;
 			goto nic_nebude_bobankove;
@@ -1390,17 +1377,15 @@ nic_nebude_bobankove:;
 
 	XMapWindow(x_display,wi->window);
 
-	gd->clip.x1 = gd->size.x1;
-	gd->clip.y1 = gd->size.y1;
-	gd->clip.x2 = gd->size.x2;
-	gd->clip.y2 = gd->size.y2;
-	gd->driver_data = wi;
-	gd->user_data = 0;
+	dev->clip.x1 = dev->size.x1;
+	dev->clip.y1 = dev->size.y1;
+	dev->clip.x2 = dev->size.x2;
+	dev->clip.y2 = dev->size.y2;
+	dev->driver_data = wi;
+	dev->user_data = 0;
 
 	XSetWindowBackgroundPixmap(x_display, wi->window, None);
-	if (x_have_palette)
-		XSetWindowColormap(x_display,wi->window,x_colormap);
-	x_add_to_table(gd);
+	x_add_to_table(dev);
 
 	XSetWMProtocols(x_display,wi->window,&x_delete_window_atom,1);
 
@@ -1420,13 +1405,13 @@ nic_nebude_bobankove:;
 	XSync(x_display, False);
 	X_SCHEDULE_PROCESS_EVENTS();
 	n_wins++;
-	return gd;
+	return dev;
 }
 
 
-static void x_shutdown_device(struct graphics_device *gd)
+static void x_shutdown_device(struct graphics_device *dev)
 {
-	struct window_info *wi = get_window_info(gd);
+	struct window_info *wi = get_window_info(dev);
 
 	n_wins--;
 	XDestroyWindow(x_display, wi->window);
@@ -1435,15 +1420,33 @@ static void x_shutdown_device(struct graphics_device *gd)
 	XSync(x_display, False);
 	X_SCHEDULE_PROCESS_EVENTS();
 
-	x_remove_from_table(&wi->window);
+	x_remove_from_table(wi->window);
 	free(wi);
-	free(gd);
+	free(dev);
+}
+
+static void x_update_palette(void)
+{
+	if (x_use_static_color_table == !x_driver.param->palette_mode)
+		return;
+
+	x_use_static_color_table = !x_driver.param->palette_mode;
+
+	if (x_use_static_color_table)
+		x_driver.depth = X_STATIC_CODE;
+	else
+		x_driver.depth = x_bitmap_bpp | (x_depth << 3);
+	x_get_color_function = get_color_fn(x_driver.depth);
+	if (!x_get_color_function)
+		internal("x: unsupported depth %d", x_driver.depth);
+
+	x_set_palette();
 }
 
 static void x_translate_colors(unsigned char *data, int x, int y, int skip)
 {
 	int i, j;
-	if (!static_color_table)
+	if (!x_use_static_color_table)
 		return;
 	for (j = 0; j < y; j++) {
 		for (i = 0; i < x; i++)
@@ -1452,6 +1455,38 @@ static void x_translate_colors(unsigned char *data, int x, int y, int skip)
 	}
 }
 
+static void x_convert_to_216(char *data, int x, int y, int skip)
+{
+	unsigned char color_table[256];
+	int i, j;
+
+	if (!static_color_table)
+		return;
+	if (x_use_static_color_table) {
+		x_translate_colors((unsigned char *)data, x, y, skip);
+		return;
+	}
+
+	memset(color_table, 255, sizeof color_table);
+
+	for (j = 0; j < y; j++) {
+		for (i = 0; i < x; i++) {
+			unsigned char a = (unsigned char)data[i];
+			unsigned char result;
+			if (color_table[a] != 255) {
+				result = color_table[a];
+			} else {
+				unsigned rgb[3];
+				q_palette(256, a, 65535, rgb);
+				result = get_nearest_color(rgb);
+				color_table[a] = result;
+			}
+			data[i] = result;
+		}
+		data += skip;
+	}
+}
+
 static int x_get_empty_bitmap(struct bitmap *bmp)
 {
 	int pad;
@@ -1483,15 +1518,14 @@ static void x_register_bitmap(struct bitmap *bmp)
 	/* alloc XImage in client's memory */
  retry:
 	image = XCreateImage(x_display, x_default_visual, x_depth, ZPixmap, 0,
-			0, bmp->x, bmp->y, x_bitmap_scanline_pad << 3, bmp->skip);
-	if (!image){
+			bmp->data, bmp->x, bmp->y, x_bitmap_scanline_pad << 3,
+			bmp->skip);
+	if (!image) {
 		if (out_of_memory())
 			goto retry;
 		free(p);
 		goto cant_create;
 	}
-	image->data = bmp->data;
-
 
 	/* try to alloc XPixmap in server's memory */
 	can_create_pixmap = 1;
@@ -1503,7 +1537,7 @@ static void x_register_bitmap(struct bitmap *bmp)
 
 	x_prepare_for_failure();
 	pixmap = xmalloc(sizeof(Pixmap));
-	(*pixmap) = XCreatePixmap(x_display,fake_window,bmp->x,bmp->y,x_depth);
+	*pixmap = XCreatePixmap(x_display, fake_window, bmp->x, bmp->y, x_depth);
 	if (x_test_for_failure()) {
 		if (*pixmap) {
 			x_prepare_for_failure();
@@ -1569,7 +1603,7 @@ static long x_get_color(int rgb)
 	/*fprintf(stderr, "bitmap bpp %d\n", x_bitmap_bpp);*/
 	switch (x_bitmap_bpp) {
 	case 1:
-		if (static_color_table)
+		if (x_use_static_color_table)
 			return static_color_table[b[0]];
 		return b[0];
 	case 2:
@@ -1585,114 +1619,80 @@ static long x_get_color(int rgb)
 	}
 }
 
+static inline void x_set_color(long color)
+{
+	if (color != x_normal_gc_color) {
+		x_normal_gc_color = color;
+		XSetForeground(x_display, x_normal_gc, color);
+	}
+}
 
-static void x_fill_area(struct graphics_device *gd, int x1, int y1, int x2, int y2, long color)
+static void x_fill_area(struct graphics_device *dev, int x1, int y1, int x2, int y2, long color)
 {
-	if (x1 < gd->clip.x1)
-		x1 = gd->clip.x1;
-	if (x2 > gd->clip.x2)
-		x2 = gd->clip.x2;
-	if (y1 < gd->clip.y1)
-		y1 = gd->clip.y1;
-	if (y2 > gd->clip.y2)
-		y2 = gd->clip.y2;
-	if (x1 >= x2)
-		return;
-	if (y1 >= y2)
-		return;
+	CLIP_FILL_AREA
 
-	XSetForeground(x_display, x_normal_gc, color);
-	XFillRectangle(x_display, get_window_info(gd)->window, x_normal_gc, x1,
+	x_set_color(color);
+	XFillRectangle(x_display, get_window_info(dev)->window, x_normal_gc, x1,
 		y1, x2 - x1, y2 - y1);
 	X_FLUSH();
 }
 
-
-static void x_draw_hline(struct graphics_device *gd, int left, int y, int right, long color)
+static void x_draw_hline(struct graphics_device *dev, int x1, int y, int x2, long color)
 {
-	if (left >= right)
-		return;
-	if (y >= gd->clip.y2 || y < gd->clip.y1)
-		return;
-	if (right <= gd->clip.x1 || left >= gd->clip.x2)
-		return;
-	XSetForeground(x_display, x_normal_gc, color);
-	XDrawLine(x_display, get_window_info(gd)->window, x_normal_gc, left, y,
-		right - 1, y);
-	X_FLUSH();
-}
-
+	CLIP_DRAW_HLINE
 
-static void x_draw_vline(struct graphics_device *gd, int x, int top, int bottom, long color)
-{
-	if (top >= bottom)
-		return;
-	if (x >= gd->clip.x2 || x < gd->clip.x1)
-		return;
-	if (bottom <= gd->clip.y1 || top >= gd->clip.y2)
-		return;
-	XSetForeground(x_display, x_normal_gc, color);
-	XDrawLine(x_display, get_window_info(gd)->window, x_normal_gc, x, top,
-		x, bottom - 1);
+	x_set_color(color);
+	XDrawLine(x_display, get_window_info(dev)->window, x_normal_gc, x1, y,
+		x2 - 1, y);
 	X_FLUSH();
 }
 
-
-static void x_set_clip_area(struct graphics_device *gd, struct rect *r)
+static void x_draw_vline(struct graphics_device *dev, int x, int y1, int y2, long color)
 {
-	XRectangle xr;
-
-	generic_set_clip_area(gd, r);
-
-	xr.x = gd->clip.x1;
-	xr.y = gd->clip.y1;
-	xr.width = gd->clip.x2 - gd->clip.x1;
-	xr.height = gd->clip.y2 - gd->clip.y1;
+	CLIP_DRAW_VLINE
 
-	XSetClipRectangles(x_display, x_normal_gc, 0, 0, &xr, 1, Unsorted);
-	XSetClipRectangles(x_display, x_scroll_gc ,0, 0, &xr, 1, Unsorted);
-	XSetClipRectangles(x_display, x_drawbitmap_gc, 0, 0, &xr, 1, Unsorted);
+	x_set_color(color);
+	XDrawLine(x_display, get_window_info(dev)->window, x_normal_gc, x, y1,
+		x, y2 - 1);
 	X_FLUSH();
 }
 
-
-static void x_draw_bitmap(struct graphics_device *gd, struct bitmap *bmp, int x, int y)
+static void x_draw_bitmap(struct graphics_device *dev, struct bitmap *bmp, int x, int y)
 {
 	int bmp_off_x, bmp_off_y, bmp_size_x, bmp_size_y;
-	if (!bmp->flags || !bmp->x || !bmp->y)
-		return;
-	if (x >= gd->clip.x2 || y >= gd->clip.y2)
-		return;
-	if (x + bmp->x <= gd->clip.x1 || y + bmp->y <= gd->clip.y1)
+	if (!bmp->flags)
 		return;
+
+	CLIP_DRAW_BITMAP
+
 	bmp_off_x = 0;
 	bmp_off_y = 0;
 	bmp_size_x = bmp->x;
 	bmp_size_y = bmp->y;
-	if (x < gd->clip.x1) {
-		bmp_off_x = gd->clip.x1 - x;
-		bmp_size_x -= gd->clip.x1 - x;
-		x = gd->clip.x1;
+	if (x < dev->clip.x1) {
+		bmp_off_x = dev->clip.x1 - x;
+		bmp_size_x -= dev->clip.x1 - x;
+		x = dev->clip.x1;
 	}
-	if (x + bmp_size_x > gd->clip.x2)
-		bmp_size_x = gd->clip.x2 - x;
-	if (y < gd->clip.y1) {
-		bmp_off_y = gd->clip.y1 - y;
-		bmp_size_y -= gd->clip.y1 - y;
-		y = gd->clip.y1;
+	if (x + bmp_size_x > dev->clip.x2)
+		bmp_size_x = dev->clip.x2 - x;
+	if (y < dev->clip.y1) {
+		bmp_off_y = dev->clip.y1 - y;
+		bmp_size_y -= dev->clip.y1 - y;
+		y = dev->clip.y1;
 	}
-	if (y + bmp_size_y > gd->clip.y2)
-		bmp_size_y = gd->clip.y2 - y;
+	if (y + bmp_size_y > dev->clip.y2)
+		bmp_size_y = dev->clip.y2 - y;
 
 	switch(XPIXMAPP(bmp->flags)->type) {
 	case X_TYPE_PIXMAP:
 		XCopyArea(x_display, *(XPIXMAPP(bmp->flags)->data.pixmap),
-			get_window_info(gd)->window, x_drawbitmap_gc, bmp_off_x,
+			get_window_info(dev)->window, x_drawbitmap_gc, bmp_off_x,
 			bmp_off_y, bmp_size_x, bmp_size_y, x, y);
 		break;
 
 	case X_TYPE_IMAGE:
-		XPutImage(x_display, get_window_info(gd)->window,
+		XPutImage(x_display, get_window_info(dev)->window,
 			x_drawbitmap_gc, XPIXMAPP(bmp->flags)->data.image,
 			bmp_off_x, bmp_off_y, x, y, bmp_size_x, bmp_size_y);
 		break;
@@ -1701,84 +1701,6 @@ static void x_draw_bitmap(struct graphics_device *gd, struct bitmap *bmp, int x,
 }
 
 
-static int x_scroll(struct graphics_device *gd, struct rect_set **set, int sc, const int h)
-{
-	XEvent ev;
-	struct rect r;
-
-	*set = NULL;
-	if (!sc)
-		return 0;
-	*set = init_rect_set();
-	if (!*set)
-		internal("Cannot allocate memory for rect set in scroll function.\n");
-
-	if (h)
-		XCopyArea(x_display, get_window_info(gd)->window,
-			get_window_info(gd)->window, x_scroll_gc, gd->clip.x1,
-			gd->clip.y1, gd->clip.x2 - gd->clip.x1,
-			gd->clip.y2 - gd->clip.y1, gd->clip.x1 + sc, gd->clip.y1);
-	else
-		XCopyArea(x_display, get_window_info(gd)->window,
-			get_window_info(gd)->window, x_scroll_gc, gd->clip.x1,
-			gd->clip.y1, gd->clip.x2 - gd->clip.x1,
-			gd->clip.y2 - gd->clip.y1, gd->clip.x1, gd->clip.y1 + sc);
-
-	XSync(x_display, False);
-	/* ten sync tady musi byt, protoze potrebuju zarucit, aby vsechny
-	 * graphics-expose vyvolane timto scrollem byly vraceny v rect-set */
-
-	/* take all graphics expose events for this window and put them into the rect set */
-	while (XCheckWindowEvent(x_display, get_window_info(gd)->window,
-			ExposureMask, &ev) == True) {
-		switch(ev.type) {
-		case GraphicsExpose:
-			r.x1 = ev.xgraphicsexpose.x;
-			r.y1 = ev.xgraphicsexpose.y;
-			r.x2 = ev.xgraphicsexpose.x + ev.xgraphicsexpose.width;
-			r.y2 = ev.xgraphicsexpose.y + ev.xgraphicsexpose.height;
-			break;
-
-		case Expose:
-			r.x1 = ev.xexpose.x;
-			r.y1 = ev.xexpose.y;
-			r.x2 = ev.xexpose.x + ev.xexpose.width;
-			r.y2 = ev.xexpose.y + ev.xexpose.height;
-			break;
-
-		default:
-			continue;
-		}
-		if (r.x1 < gd->clip.x1 || r.x2 > gd->clip.x2
-		|| r.y1 < gd->clip.y1 || r.y2 > gd->clip.y2) {
-			switch(ev.type) {
-			case GraphicsExpose:
-				ev.xgraphicsexpose.x = 0;
-				ev.xgraphicsexpose.y = 0;
-				ev.xgraphicsexpose.width = gd->size.x2;
-				ev.xgraphicsexpose.height = gd->size.y2;
-				break;
-
-			case Expose:
-				ev.xexpose.x = 0;
-				ev.xexpose.y = 0;
-				ev.xexpose.width = gd->size.x2;
-				ev.xexpose.height = gd->size.y2;
-				break;
-			}
-			XPutBackEvent(x_display, &ev);
-			free(*set);
-			*set = NULL;
-			break;
-		}
-		add_to_rect_set(set,&r);
-	}
-
-	X_SCHEDULE_PROCESS_EVENTS();
-
-	return 1;
-}
-
 static void *x_prepare_strip(struct bitmap *bmp, int top, int lines)
 {
 	struct x_pixmapa *p = (struct x_pixmapa *)bmp->flags;
@@ -1792,36 +1714,24 @@ static void *x_prepare_strip(struct bitmap *bmp, int top, int lines)
 
 	switch (p->type) {
 	case X_TYPE_PIXMAP:
- retry:
 		x_data = xmalloc(bmp->skip * lines);
-		if (!x_data) {
-			if (out_of_memory())
-				goto retry;
-			return NULL;
-		}
-
- retry2:
 		image = XCreateImage(x_display, x_default_visual, x_depth,
-				ZPixmap, 0, 0, bmp->x, lines,
+				ZPixmap, 0, x_data, bmp->x, lines,
 				x_bitmap_scanline_pad << 3, bmp->skip);
 		if (!image) {
-			if (out_of_memory())
-				goto retry2;
 			free(x_data);
 			return NULL;
 		}
-		image->data = x_data;
 		bmp->data = image;
 		return image->data;
 
 	case X_TYPE_IMAGE:
-		return p->data.image->data+(bmp->skip*top);
+		return p->data.image->data + (bmp->skip * top);
 	}
 	internal("Unknown pixmap type found in x_prepare_strip. SOMETHING IS REALLY STRANGE!!!!\n");
 	return NULL;
 }
 
-
 static void x_commit_strip(struct bitmap *bmp, int top, int lines)
 {
 	struct x_pixmapa *p = (struct x_pixmapa *)bmp->flags;
@@ -1829,36 +1739,111 @@ static void x_commit_strip(struct bitmap *bmp, int top, int lines)
 	if (!p)
 		return;
 
-	switch(p->type) {
+	bmp->data = NULL;
+
+	switch (p->type) {
 	/* send image to pixmap in xserver */
 	case X_TYPE_PIXMAP:
 		if (!bmp->data)
 			return;
 		x_translate_colors((unsigned char *)((XImage*)bmp->data)->data,
-				bmp->x, lines, bmp->skip);
+			bmp->x, lines, bmp->skip);
 		XPutImage(x_display, *(XPIXMAPP(bmp->flags)->data.pixmap),
 			x_copy_gc, (XImage*)bmp->data, 0, 0, 0, top, bmp->x,
 			lines);
 		XDestroyImage((XImage *)bmp->data);
 		return;
-
 	case X_TYPE_IMAGE:
-		x_translate_colors((unsigned char *)p->data.image->data + (bmp->skip * top),
-				bmp->x, lines, bmp->skip);
+		x_translate_colors((unsigned char *)p->data.image->data
+				+ (bmp->skip * top), bmp->x, lines, bmp->skip);
 		/* everything has been done by user */
 		return;
 	}
 }
 
+static int x_scroll(struct graphics_device *dev, struct rect_set **set, int scx, int scy)
+{
+	XEvent ev;
+	struct rect r;
+	if (memcmp(&dev->clip, &x_scroll_gc_rect, sizeof(struct rect))) {
+		XRectangle xr;
+
+		memcpy(&x_scroll_gc_rect, &dev->clip, sizeof(struct rect));
+
+		xr.x = dev->clip.x1;
+		xr.y = dev->clip.y1;
+		xr.width = dev->clip.x2 - dev->clip.x1;
+		xr.height = dev->clip.y2 - dev->clip.y1;
+
+		XSetClipRectangles(x_display, x_scroll_gc, 0, 0, &xr, 1, Unsorted);
+	}
+
+	XCopyArea(x_display, get_window_info(dev)->window,
+		get_window_info(dev)->window, x_scroll_gc, dev->clip.x1,
+		dev->clip.y1, dev->clip.x2 - dev->clip.x1,
+		dev->clip.y2 - dev->clip.y1, dev->clip.x1 + scx,
+		dev->clip.y1 + scy);
+	XSync(x_display, False);
+	/* ten sync tady musi byt, protoze potrebuju zarucit, aby vsechny
+	* graphics-expose vyvolane timto scrollem byly vraceny v rect-set */
+
+	/* take all graphics expose events for this window and put them into the rect set */
+	while (XCheckWindowEvent(x_display, get_window_info(dev)->window, ExposureMask, &ev) == True) {
+		switch(ev.type) {
+		case GraphicsExpose:
+			r.x1 = ev.xgraphicsexpose.x;
+			r.y1 = ev.xgraphicsexpose.y;
+			r.x2 = ev.xgraphicsexpose.x + ev.xgraphicsexpose.width;
+			r.y2 = ev.xgraphicsexpose.y + ev.xgraphicsexpose.height;
+			break;
+
+		case Expose:
+			r.x1 = ev.xexpose.x;
+			r.y1 = ev.xexpose.y;
+			r.x2 = ev.xexpose.x + ev.xexpose.width;
+			r.y2 = ev.xexpose.y + ev.xexpose.height;
+			break;
+
+		default:
+			continue;
+		}
+
+		if (r.x1 < dev->clip.x1 || r.x2 > dev->clip.x2
+		|| r.y1 < dev->clip.y1 || r.y2 > dev->clip.y2) {
+			switch(ev.type) {
+			case GraphicsExpose:
+				ev.xgraphicsexpose.x = 0;
+				ev.xgraphicsexpose.y = 0;
+				ev.xgraphicsexpose.width = dev->size.x2;
+				ev.xgraphicsexpose.height = dev->size.y2;
+				break;
+
+			case Expose:
+				ev.xexpose.x = 0;
+				ev.xexpose.y = 0;
+				ev.xexpose.width = dev->size.x2;
+				ev.xexpose.height = dev->size.y2;
+				break;
+			}
+			XPutBackEvent(x_display, &ev);
+			free(*set);
+			*set = init_rect_set();
+			break;
+		}
+		add_to_rect_set(set, &r);
+	}
+	X_SCHEDULE_PROCESS_EVENTS();
+	return 1;
+}
 
-static void x_flush(struct graphics_device *gd)
+static void x_flush(struct graphics_device *dev)
 {
 	unregister_bottom_half(x_do_flush, NULL);
 	x_do_flush(NULL);
 }
 
 
-static void x_set_window_title(struct graphics_device *gd, unsigned char *title)
+static void x_set_window_title(struct graphics_device *dev, unsigned char *title)
 {
 	unsigned char *t;
 	XTextProperty windowName;
@@ -1872,7 +1857,7 @@ retry_encode_ascii:
 		output_encoding = 0;
 	}
 
-	if (!gd)
+	if (!dev)
 		internal("x_set_window_title called with NULL graphics_device pointer.\n");
 	t = convert(0, output_encoding, title, NULL);
 	clr_white(t);
@@ -1909,21 +1894,21 @@ retry_encode_ascii:
 		}
 	}
 	free(t);
-	XSetWMName(x_display, get_window_info(gd)->window, &windowName);
-	XSetWMIconName(x_display, get_window_info(gd)->window, &windowName);
+	XSetWMName(x_display, get_window_info(dev)->window, &windowName);
+	XSetWMIconName(x_display, get_window_info(dev)->window, &windowName);
 	XFree(windowName.value);
 	X_FLUSH();
 }
 
 /* gets string in UTF8 */
-static void x_set_clipboard_text(struct graphics_device *gd, unsigned char *text)
+static void x_set_clipboard_text(struct graphics_device *dev, unsigned char *text)
 {
 	x_clear_clipboard();
 	if (text) {
 		x_my_clipboard = stracpy(text);
 
 		XSetSelectionOwner(x_display, XA_PRIMARY,
-			get_window_info(gd)->window, CurrentTime);
+			get_window_info(dev)->window, CurrentTime);
 		XFlush(x_display);
 		X_SCHEDULE_PROCESS_EVENTS();
 	}
@@ -2082,8 +2067,8 @@ static int x_exec(unsigned char *command, int fg)
 	}
 
 	l = 0;
-	if (*x_driver.shell)
-		pattern = strdup((char *)x_driver.shell);
+	if (*x_driver.param->shell_term)
+		pattern = strdup((char *)x_driver.param->shell_term);
 	else {
 		pattern = strdup((char *)links_xterm());
 		if (*command) {
@@ -2131,8 +2116,9 @@ struct graphics_driver x_driver = {
 	x_draw_hline,
 	x_draw_vline,
 	x_scroll,
-	x_set_clip_area,
+	NULL,
 	x_flush,
+	x_update_palette,
 	x_set_window_title,
 	x_exec,
 	x_set_clipboard_text,
@@ -2140,6 +2126,5 @@ struct graphics_driver x_driver = {
 	0,				/* depth (filled in x_init_driver function) */
 	0, 0,				/* size (in X is empty) */
 	GD_UNICODE_KEYS,		/* flags */
-	0,				/* codepage */
-	NULL,				/* shell */
+	NULL,				/* param */
 };