Bug 997: Fix unlikely stack corruption in get_pasv_socket.
[elinks/elinks-j605.git] / src / terminal / tab.c
blob02b8409f55546bfc1a474c865827160cf3416481
1 /* Tab-style (those containing real documents) windows infrastructure. */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include "elinks.h"
9 #include "bfu/dialog.h"
10 #include "config/options.h"
11 #include "dialogs/menu.h"
12 #include "document/document.h"
13 #include "document/view.h"
14 #include "intl/gettext/libintl.h"
15 #include "main/select.h"
16 #include "protocol/uri.h"
17 #include "session/session.h"
18 #include "terminal/screen.h"
19 #include "terminal/tab.h"
20 #include "terminal/terminal.h"
21 #include "terminal/window.h"
22 #include "util/error.h"
23 #include "util/memory.h"
24 #include "util/lists.h"
25 #include "viewer/text/link.h"
26 #include "viewer/text/view.h"
29 struct window *
30 init_tab(struct terminal *term, void *data, window_handler_T handler)
32 struct window *win = mem_calloc(1, sizeof(*win));
34 if (!win) return NULL;
36 win->handler = handler;
37 win->term = term;
38 win->data = data;
39 win->type = WINDOW_TAB;
40 win->resize = 1;
42 add_to_list(term->windows, win);
44 return win;
47 /* Number of tabs at the terminal (in term->windows) */
48 inline int
49 number_of_tabs(struct terminal *term)
51 int result = 0;
52 struct window *win;
54 foreach_tab (win, term->windows)
55 result++;
57 return result;
60 /* Number of tab */
61 int
62 get_tab_number(struct window *window)
64 struct terminal *term = window->term;
65 struct window *win;
66 int current = 0;
67 int num = 0;
69 foreachback_tab (win, term->windows) {
70 if (win == window) {
71 num = current;
72 break;
74 current++;
77 return num;
80 /* Get tab of an according index */
81 struct window *
82 get_tab_by_number(struct terminal *term, int num)
84 struct window *win = NULL;
86 foreachback_tab (win, term->windows) {
87 if (!num) break;
88 num--;
91 return win;
94 /* Returns number of the tab at @xpos, or -1 if none. */
95 int
96 get_tab_number_by_xpos(struct terminal *term, int xpos)
98 int num = 0;
99 struct window *win = NULL;
101 foreachback_tab (win, term->windows) {
102 if (xpos >= win->xpos
103 && xpos < win->xpos + win->width)
104 return num;
105 num++;
108 return -1;
111 /* if @tabs > 0, then it is taken as the result of a recent
112 * call to number_of_tabs() so it just uses this value. */
113 void
114 switch_to_tab(struct terminal *term, int tab, int tabs)
116 if (tabs < 0) tabs = number_of_tabs(term);
118 if (tabs > 1) {
119 if (tab >= tabs) {
120 if (get_opt_bool("ui.tabs.wraparound"))
121 tab = 0;
122 else
123 tab = tabs - 1;
126 if (tab < 0) {
127 if (get_opt_bool("ui.tabs.wraparound"))
128 tab = tabs - 1;
129 else
130 tab = 0;
132 } else tab = 0;
134 if (tab != term->current_tab) {
135 term->current_tab = tab;
136 set_screen_dirty(term->screen, 0, term->height);
137 redraw_terminal(term);
141 void
142 switch_current_tab(struct session *ses, int direction)
144 struct terminal *term = ses->tab->term;
145 int num_tabs = number_of_tabs(term);
146 int count;
148 if (num_tabs < 2)
149 return;
151 count = eat_kbd_repeat_count(ses);
152 if (count) direction *= count;
154 switch_to_tab(term, term->current_tab + direction, num_tabs);
157 static void
158 really_close_tab(struct session *ses)
160 struct terminal *term = ses->tab->term;
161 struct window *current_tab = get_current_tab(term);
163 if (ses->tab == current_tab) {
164 int num_tabs = number_of_tabs(term);
166 switch_to_tab(term, term->current_tab - 1, num_tabs - 1);
169 delete_window(ses->tab);
172 void
173 close_tab(struct terminal *term, struct session *ses)
175 int num_tabs = number_of_tabs(term);
177 if (num_tabs < 2) {
178 query_exit(ses);
179 return;
182 if (!get_opt_bool("ui.tabs.confirm_close")) {
183 really_close_tab(ses);
184 return;
187 msg_box(term, NULL, 0,
188 N_("Close tab"), ALIGN_CENTER,
189 N_("Do you really want to close the current tab?"),
190 ses, 2,
191 N_("~Yes"), (void (*)(void *)) really_close_tab, B_ENTER,
192 N_("~No"), NULL, B_ESC);
195 static void
196 really_close_tabs(struct session *ses)
198 struct terminal *term = ses->tab->term;
199 struct window *current = get_current_tab(term);
200 struct window *tab;
202 foreach_tab (tab, term->windows) {
203 if (tab == current) continue;
204 tab = tab->prev;
205 delete_window(tab->next);
208 term->current_tab = 0;
209 redraw_terminal(term);
212 void
213 close_all_tabs_but_current(struct session *ses)
215 assert(ses);
216 if_assert_failed return;
218 if (!get_opt_bool("ui.tabs.confirm_close")) {
219 really_close_tabs(ses);
220 return;
223 msg_box(ses->tab->term, NULL, 0,
224 N_("Close tab"), ALIGN_CENTER,
225 N_("Do you really want to close all except the current tab?"),
226 ses, 2,
227 N_("~Yes"), (void (*)(void *)) really_close_tabs, B_ENTER,
228 N_("~No"), NULL, B_ESC);
232 void
233 open_uri_in_new_tab(struct session *ses, struct uri *uri, int in_background,
234 int based)
236 assert(ses);
237 /* @based means whether the current @ses location will be preloaded
238 * in the tab. */
239 init_session(based ? ses : NULL, ses->tab->term, uri, in_background);
242 void
243 open_current_link_in_new_tab(struct session *ses, int in_background)
245 struct document_view *doc_view = current_frame(ses);
246 struct uri *uri = NULL;
247 struct link *link;
249 if (doc_view) assert(doc_view->vs && doc_view->document);
250 if_assert_failed return;
252 link = get_current_link(doc_view);
253 if (link) uri = get_link_uri(ses, doc_view, link);
255 open_uri_in_new_tab(ses, uri, in_background, 1);
256 if (uri) done_uri(uri);
259 void
260 move_current_tab(struct session *ses, int direction)
262 struct terminal *term = ses->tab->term;
263 int tabs = number_of_tabs(term);
264 struct window *current_tab = get_current_tab(term);
265 struct window *tab;
266 int new_pos;
267 int count;
269 assert(ses && direction);
271 count = eat_kbd_repeat_count(ses);
272 if (count) direction *= count;
274 new_pos = term->current_tab + direction;
276 while (new_pos < 1 || new_pos > tabs)
277 new_pos += new_pos < 1 ? tabs : -tabs;
279 assert(0 < new_pos && new_pos <= tabs);
281 if (new_pos == term->current_tab) return;
283 tab = get_tab_by_number(term, new_pos);
285 del_from_list(current_tab);
287 if (new_pos < term->current_tab) {
288 add_at_pos(tab, current_tab);
289 } else {
290 add_to_list_end(*tab, current_tab);
293 switch_to_tab(term, new_pos, tabs);