1 /* HTML viewer (and much more) */
2 /* $Id: view.c,v 1.705 2005/09/08 13:42:13 zas Exp $ */
18 #include "bfu/dialog.h"
19 #include "config/kbdbind.h"
20 #include "config/options.h"
21 #include "dialogs/document.h"
22 #include "dialogs/menu.h"
23 #include "dialogs/options.h"
24 #include "dialogs/status.h"
25 #include "document/document.h"
26 #include "document/html/frames.h"
27 #include "document/options.h"
28 #include "document/renderer.h"
29 #include "document/view.h"
30 #include "intl/charsets.h"
31 #include "intl/gettext/libintl.h"
32 #include "main/event.h"
33 #include "osdep/osdep.h"
34 #include "protocol/uri.h"
35 #include "session/download.h"
36 #include "session/location.h"
37 #include "session/session.h"
38 #include "session/task.h"
39 #include "terminal/draw.h"
40 #include "terminal/event.h"
41 #include "terminal/kbd.h"
42 #include "terminal/mouse.h"
43 #include "terminal/tab.h"
44 #include "terminal/terminal.h"
45 #include "terminal/window.h"
46 #include "util/color.h"
47 #include "util/conv.h"
48 #include "util/error.h"
49 #include "util/memory.h"
50 #include "util/snprintf.h"
51 #include "util/string.h"
52 #include "viewer/action.h"
53 #include "viewer/dump/dump.h"
54 #include "viewer/text/draw.h"
55 #include "viewer/text/form.h"
56 #include "viewer/text/link.h"
57 #include "viewer/text/marks.h"
58 #include "viewer/text/search.h"
59 #include "viewer/text/textarea.h"
60 #include "viewer/text/view.h"
61 #include "viewer/text/vs.h"
66 detach_formatted(struct document_view
*doc_view
)
69 if_assert_failed
return;
71 if (doc_view
->document
) {
72 release_document(doc_view
->document
);
73 doc_view
->document
= NULL
;
76 doc_view
->vs
->doc_view
= NULL
;
79 if (doc_view
->link_bg
) free_link(doc_view
);
80 mem_free_set(&doc_view
->name
, NULL
);
83 /* type == 0 -> PAGE_DOWN
84 * type == 1 -> DOWN */
85 static enum frame_event_status
86 move_down(struct session
*ses
, struct document_view
*doc_view
, int type
)
90 assert(ses
&& doc_view
&& doc_view
->vs
);
91 if_assert_failed
return FRAME_EVENT_OK
;
93 assert(ses
->navigate_mode
== NAVIGATE_LINKWISE
); /* XXX: drop it at some time. --Zas */
95 newpos
= doc_view
->vs
->y
+ doc_view
->box
.height
;
96 if (newpos
< doc_view
->document
->height
)
97 doc_view
->vs
->y
= newpos
;
99 if (current_link_is_visible(doc_view
))
100 return FRAME_EVENT_REFRESH
;
103 find_link_down(doc_view
);
105 find_link_page_down(doc_view
);
107 return FRAME_EVENT_REFRESH
;
110 enum frame_event_status
111 move_page_down(struct session
*ses
, struct document_view
*doc_view
)
113 enum frame_event_status status
;
114 int count
= eat_kbd_repeat_count(ses
);
116 ses
->navigate_mode
= NAVIGATE_LINKWISE
;
119 status
= move_down(ses
, doc_view
, 0);
120 if (status
!= FRAME_EVENT_REFRESH
) break;
121 } while (--count
> 0);
126 /* type == 0 -> PAGE_UP
128 static enum frame_event_status
129 move_up(struct session
*ses
, struct document_view
*doc_view
, int type
)
131 assert(ses
&& doc_view
&& doc_view
->vs
);
132 if_assert_failed
return FRAME_EVENT_OK
;
134 assert(ses
->navigate_mode
== NAVIGATE_LINKWISE
); /* XXX: drop it at some time. --Zas */
136 if (doc_view
->vs
->y
== 0) return FRAME_EVENT_OK
;
138 doc_view
->vs
->y
-= doc_view
->box
.height
;
139 int_lower_bound(&doc_view
->vs
->y
, 0);
141 if (current_link_is_visible(doc_view
))
142 return FRAME_EVENT_REFRESH
;
145 find_link_up(doc_view
);
147 find_link_page_up(doc_view
);
149 return FRAME_EVENT_REFRESH
;
152 enum frame_event_status
153 move_page_up(struct session
*ses
, struct document_view
*doc_view
)
155 enum frame_event_status status
;
156 int count
= eat_kbd_repeat_count(ses
);
158 ses
->navigate_mode
= NAVIGATE_LINKWISE
;
161 status
= move_up(ses
, doc_view
, 0);
162 if (status
!= FRAME_EVENT_REFRESH
) break;
163 } while (--count
> 0);
168 enum frame_event_status
169 move_link(struct session
*ses
, struct document_view
*doc_view
, int direction
,
170 int wraparound_bound
, int wraparound_link
)
175 assert(ses
&& doc_view
&& doc_view
->vs
&& doc_view
->document
);
176 if_assert_failed
return FRAME_EVENT_OK
;
178 ses
->navigate_mode
= NAVIGATE_LINKWISE
;
180 if (doc_view
->document
->nlinks
< 2) {
181 /* Wraparound only makes sense with more than one link. */
182 wraparound_bound
= -1;
184 /* We only bother this option if there's some links
186 wraparound
= get_opt_bool("document.browse.links.wraparound");
189 count
= eat_kbd_repeat_count(ses
);
192 int current_link
= doc_view
->vs
->current_link
;
194 if (current_link
== wraparound_bound
) {
196 jump_to_link_number(ses
, doc_view
, wraparound_link
);
197 /* FIXME: This needs further work, we should call
198 * page_down() and set_textarea() under some conditions
199 * as well. --pasky */
204 if (next_link_in_view_y(doc_view
, current_link
+ direction
,
209 /* This is a work around for the case where the index of
210 * @wraparound_bound is not necessarily the index of the first
211 * or the last link in the view. It means that the link moving
212 * could end up calling next_link_in_view() in the condition
213 * above. This is bad because next_link_in_view() will then
214 * 'reset' doc_view->vs->current_link to -1 and the effect will
215 * be that the current link will 'wrap around'. By restoring
216 * the index of the @current_link nothing will be wrapped
217 * around and move_{up,down} will take care of finding the next
219 doc_view
->vs
->current_link
= current_link
;
222 move_down(ses
, doc_view
, 1);
224 move_up(ses
, doc_view
, 1);
227 if (current_link
!= wraparound_bound
228 && current_link
!= doc_view
->vs
->current_link
) {
229 set_textarea(doc_view
, -direction
);
231 } while (--count
> 0);
233 return FRAME_EVENT_REFRESH
;
236 enum frame_event_status
237 move_link_dir(struct session
*ses
, struct document_view
*doc_view
, int dir_x
, int dir_y
)
241 assert(ses
&& doc_view
&& doc_view
->vs
&& doc_view
->document
);
242 if_assert_failed
return FRAME_EVENT_OK
;
244 ses
->navigate_mode
= NAVIGATE_LINKWISE
;
246 count
= eat_kbd_repeat_count(ses
);
249 int current_link
= doc_view
->vs
->current_link
;
251 if (next_link_in_dir(doc_view
, dir_x
, dir_y
))
254 /* FIXME: This won't preserve the column! */
256 move_down(ses
, doc_view
, 1);
258 move_up(ses
, doc_view
, 1);
260 if (dir_y
&& current_link
!= doc_view
->vs
->current_link
) {
261 set_textarea(doc_view
, -dir_y
);
263 } while (--count
> 0);
265 return FRAME_EVENT_REFRESH
;
268 /* @steps > 0 -> down */
269 static enum frame_event_status
270 vertical_scroll(struct session
*ses
, struct document_view
*doc_view
, int steps
)
274 assert(ses
&& doc_view
&& doc_view
->vs
&& doc_view
->document
);
275 if_assert_failed
return FRAME_EVENT_OK
;
277 y
= doc_view
->vs
->y
+ steps
;
280 int max_height
= doc_view
->document
->height
- doc_view
->box
.height
;
282 if (doc_view
->vs
->y
>= max_height
) return FRAME_EVENT_OK
;
283 int_upper_bound(&y
, max_height
);
286 int_lower_bound(&y
, 0);
288 if (doc_view
->vs
->y
== y
) return FRAME_EVENT_OK
;
292 if (current_link_is_visible(doc_view
))
293 return FRAME_EVENT_REFRESH
;
296 find_link_page_down(doc_view
);
298 find_link_page_up(doc_view
);
300 return FRAME_EVENT_REFRESH
;
303 /* @steps > 0 -> right */
304 static enum frame_event_status
305 horizontal_scroll(struct session
*ses
, struct document_view
*doc_view
, int steps
)
309 assert(ses
&& doc_view
&& doc_view
->vs
&& doc_view
->document
);
310 if_assert_failed
return FRAME_EVENT_OK
;
312 x
= doc_view
->vs
->x
+ steps
;
314 if (get_opt_bool("document.browse.scrolling.horizontal_extended")) {
315 max
= doc_view
->document
->width
- 1;
317 max
= int_max(doc_view
->vs
->x
,
318 doc_view
->document
->width
- doc_view
->box
.width
);
321 int_bounds(&x
, 0, max
);
322 if (doc_view
->vs
->x
== x
) return FRAME_EVENT_OK
;
326 if (current_link_is_visible(doc_view
))
327 return FRAME_EVENT_REFRESH
;
329 find_link_page_down(doc_view
);
331 return FRAME_EVENT_REFRESH
;
334 enum frame_event_status
335 scroll_up(struct session
*ses
, struct document_view
*doc_view
)
337 int steps
= eat_kbd_repeat_count(ses
);
340 steps
= get_opt_int("document.browse.scrolling.vertical_step");
342 return vertical_scroll(ses
, doc_view
, -steps
);
345 enum frame_event_status
346 scroll_down(struct session
*ses
, struct document_view
*doc_view
)
348 int steps
= eat_kbd_repeat_count(ses
);
351 steps
= get_opt_int("document.browse.scrolling.vertical_step");
353 return vertical_scroll(ses
, doc_view
, steps
);
356 enum frame_event_status
357 scroll_left(struct session
*ses
, struct document_view
*doc_view
)
359 int steps
= eat_kbd_repeat_count(ses
);
362 steps
= get_opt_int("document.browse.scrolling.horizontal_step");
364 return horizontal_scroll(ses
, doc_view
, -steps
);
367 enum frame_event_status
368 scroll_right(struct session
*ses
, struct document_view
*doc_view
)
370 int steps
= eat_kbd_repeat_count(ses
);
373 steps
= get_opt_int("document.browse.scrolling.horizontal_step");
375 return horizontal_scroll(ses
, doc_view
, steps
);
379 static enum frame_event_status
380 scroll_mouse_up(struct session
*ses
, struct document_view
*doc_view
)
382 int steps
= get_opt_int("document.browse.scrolling.vertical_step");
384 return vertical_scroll(ses
, doc_view
, -steps
);
387 static enum frame_event_status
388 scroll_mouse_down(struct session
*ses
, struct document_view
*doc_view
)
390 int steps
= get_opt_int("document.browse.scrolling.vertical_step");
392 return vertical_scroll(ses
, doc_view
, steps
);
395 static enum frame_event_status
396 scroll_mouse_left(struct session
*ses
, struct document_view
*doc_view
)
398 int steps
= get_opt_int("document.browse.scrolling.horizontal_step");
400 return horizontal_scroll(ses
, doc_view
, -steps
);
403 static enum frame_event_status
404 scroll_mouse_right(struct session
*ses
, struct document_view
*doc_view
)
406 int steps
= get_opt_int("document.browse.scrolling.horizontal_step");
408 return horizontal_scroll(ses
, doc_view
, steps
);
410 #endif /* CONFIG_MOUSE */
412 enum frame_event_status
413 move_document_start(struct session
*ses
, struct document_view
*doc_view
)
415 assert(ses
&& doc_view
&& doc_view
->vs
);
416 if_assert_failed
return FRAME_EVENT_OK
;
418 doc_view
->vs
->y
= doc_view
->vs
->x
= 0;
420 if (ses
->navigate_mode
== NAVIGATE_CURSOR_ROUTING
) {
421 /* Move to the first line and the first column. */
422 move_cursor(ses
, doc_view
, doc_view
->box
.x
, doc_view
->box
.y
);
424 find_link_page_down(doc_view
);
427 return FRAME_EVENT_REFRESH
;
430 enum frame_event_status
431 move_document_end(struct session
*ses
, struct document_view
*doc_view
)
435 assert(ses
&& doc_view
&& doc_view
->vs
&& doc_view
->document
);
436 if_assert_failed
return FRAME_EVENT_OK
;
438 max_height
= doc_view
->document
->height
- doc_view
->box
.height
;
440 int_lower_bound(&doc_view
->vs
->y
, int_max(0, max_height
));
442 if (ses
->navigate_mode
== NAVIGATE_CURSOR_ROUTING
) {
443 /* Move to the last line of the document,
444 * but preserve the column. This is done to avoid
445 * moving the cursor backwards if it is already
446 * on the last line but is not on the first column. */
447 move_cursor(ses
, doc_view
, ses
->tab
->x
,
448 doc_view
->document
->height
- doc_view
->vs
->y
);
450 find_link_page_up(doc_view
);
453 return FRAME_EVENT_REFRESH
;
456 enum frame_event_status
457 set_frame(struct session
*ses
, struct document_view
*doc_view
, int xxxx
)
459 assert(ses
&& ses
->doc_view
&& doc_view
&& doc_view
->vs
);
460 if_assert_failed
return FRAME_EVENT_OK
;
462 if (doc_view
== ses
->doc_view
) return FRAME_EVENT_OK
;
463 goto_uri(ses
, doc_view
->vs
->uri
);
464 ses
->navigate_mode
= NAVIGATE_LINKWISE
;
466 return FRAME_EVENT_OK
;
471 toggle_plain_html(struct session
*ses
, struct document_view
*doc_view
, int xxxx
)
473 assert(ses
&& doc_view
&& ses
->tab
&& ses
->tab
->term
);
474 if_assert_failed
return;
477 nowhere_box(ses
->tab
->term
, NULL
);
481 doc_view
->vs
->plain
= !doc_view
->vs
->plain
;
482 draw_formatted(ses
, 1);
486 toggle_wrap_text(struct session
*ses
, struct document_view
*doc_view
, int xxxx
)
488 assert(ses
&& doc_view
&& ses
->tab
&& ses
->tab
->term
);
489 if_assert_failed
return;
492 nowhere_box(ses
->tab
->term
, NULL
);
496 doc_view
->vs
->wrap
= !doc_view
->vs
->wrap
;
497 draw_formatted(ses
, 1);
500 /* Move the cursor to the document view co-ordinates provided as @x and @y,
501 * scroll the document if necessary, put us in cursor-routing navigation mode if
502 * that is not the current mode, and select any link under the cursor. */
503 enum frame_event_status
504 move_cursor(struct session
*ses
, struct document_view
*doc_view
, int x
, int y
)
506 enum frame_event_status status
= FRAME_EVENT_REFRESH
;
507 struct terminal
*term
= ses
->tab
->term
;
508 struct box
*box
= &doc_view
->box
;
511 /* If cursor was moved outside the document view scroll it, but only
512 * within the document canvas */
513 if (!is_in_box(box
, x
, y
)) {
514 int max_height
= doc_view
->document
->height
- doc_view
->vs
->y
;
515 int max_width
= doc_view
->document
->width
- doc_view
->vs
->x
;
518 status
= vertical_scroll(ses
, doc_view
, y
- box
->y
);
520 } else if (y
>= box
->y
+ box
->height
&& y
<= max_height
) {
521 status
= vertical_scroll(ses
, doc_view
,
522 y
- (box
->y
+ box
->height
- 1));
524 } else if (x
< box
->x
) {
525 status
= horizontal_scroll(ses
, doc_view
, x
- box
->x
);
527 } else if (x
>= box
->x
+ box
->width
&& x
<= max_width
) {
528 status
= horizontal_scroll(ses
, doc_view
,
529 x
- (box
->x
+ box
->width
- 1));
532 /* If the view was not scrolled there's nothing more to do */
533 if (status
!= FRAME_EVENT_REFRESH
)
536 /* Restrict the cursor position within the current view */
537 int_bounds(&x
, box
->x
, box
->x
+ box
->width
- 1);
538 int_bounds(&y
, box
->y
, box
->y
+ box
->height
- 1);
541 /* Scrolling could have changed the navigation mode */
542 ses
->navigate_mode
= NAVIGATE_CURSOR_ROUTING
;
544 link
= get_link_at_coordinates(doc_view
, x
- box
->x
, y
- box
->y
);
546 doc_view
->vs
->current_link
= link
- doc_view
->document
->links
;
548 doc_view
->vs
->current_link
= -1;
551 /* Set the unblockable cursor position and update the window pointer so
552 * stuff like the link menu will be drawn relative to the cursor. */
553 set_cursor(term
, x
, y
, 0);
554 set_window_ptr(ses
->tab
, x
, y
);
559 enum frame_event_status
560 move_cursor_rel(struct session
*ses
, struct document_view
*view
,
563 int count
= eat_kbd_repeat_count(ses
);
566 int_lower_bound(&count
, 1);
568 x
= ses
->tab
->x
+ rx
*count
;
569 y
= ses
->tab
->y
+ ry
*count
;
570 return move_cursor(ses
, view
, x
, y
);
573 enum frame_event_status
574 move_cursor_left(struct session
*ses
, struct document_view
*view
)
576 return move_cursor_rel(ses
, view
, -1, 0);
579 enum frame_event_status
580 move_cursor_right(struct session
*ses
, struct document_view
*view
)
582 return move_cursor_rel(ses
, view
, 1, 0);
585 enum frame_event_status
586 move_cursor_up(struct session
*ses
, struct document_view
*view
)
588 return move_cursor_rel(ses
, view
, 0, -1);
591 enum frame_event_status
592 move_cursor_down(struct session
*ses
, struct document_view
*view
)
594 return move_cursor_rel(ses
, view
, 0, 1);
598 enum frame_event_status
599 copy_current_link_to_clipboard(struct session
*ses
,
600 struct document_view
*doc_view
,
605 unsigned char *uristring
;
607 link
= get_current_link(doc_view
);
608 if (!link
) return FRAME_EVENT_OK
;
610 uri
= get_link_uri(ses
, doc_view
, link
);
611 if (!uri
) return FRAME_EVENT_OK
;
613 uristring
= get_uri_string(uri
, URI_ORIGINAL
);
617 set_clipboard_text(uristring
);
621 return FRAME_EVENT_OK
;
626 try_jump_to_link_number(struct session
*ses
, struct document_view
*doc_view
)
628 int link_number
= eat_kbd_repeat_count(ses
) - 1;
630 if (link_number
< 0) return 1;
632 if (!doc_view
) return 0;
634 if (link_number
>= doc_view
->document
->nlinks
)
637 jump_to_link_number(ses
, doc_view
, link_number
);
638 refresh_view(ses
, doc_view
, 0);
644 enum frame_event_status
645 try_mark_key(struct session
*ses
, struct document_view
*doc_view
,
646 struct term_event
*ev
)
648 unsigned char mark
= get_kbd_key(ev
);
650 switch (ses
->kbdprefix
.mark
) {
651 case KP_MARK_NOTHING
:
652 return FRAME_EVENT_IGNORED
;
655 /* It is intentional to set the mark
656 * to NULL if !doc_view->vs. */
657 set_mark(mark
, doc_view
->vs
);
661 goto_mark(mark
, doc_view
->vs
);
665 ses
->kbdprefix
.repeat_count
= 0;
666 ses
->kbdprefix
.mark
= KP_MARK_NOTHING
;
668 return FRAME_EVENT_REFRESH
;
672 static enum frame_event_status
673 try_prefix_key(struct session
*ses
, struct document_view
*doc_view
,
674 struct term_event
*ev
)
676 struct document
*document
= doc_view
->document
;
677 struct document_options
*doc_opts
= &document
->options
;
678 int digit
= get_kbd_key(ev
) - '0';
680 if (digit
< 0 || digit
> 9)
681 return FRAME_EVENT_IGNORED
;
683 if (get_kbd_modifier(ev
)
684 || ses
->kbdprefix
.repeat_count
/* The user has already begun
685 * entering a prefix. */
686 || !doc_opts
->num_links_key
687 || (doc_opts
->num_links_key
== 1 && !doc_opts
->links_numbering
)) {
689 * ses->kbdprefix.repeat_count is initialized to zero
690 * the first time by init_session() calloc() call.
691 * When used, it has to be reset to zero. */
693 ses
->kbdprefix
.repeat_count
*= 10;
694 ses
->kbdprefix
.repeat_count
+= digit
;
696 /* If too big, just restart from zero, so pressing
697 * '0' six times or more will reset the count. */
698 if (ses
->kbdprefix
.repeat_count
> 99999)
699 ses
->kbdprefix
.repeat_count
= 0;
701 return FRAME_EVENT_OK
;
704 if (digit
>= 1 && !get_kbd_modifier(ev
)) {
705 int nlinks
= document
->nlinks
, length
;
706 unsigned char d
[2] = { get_kbd_key(ev
), 0 };
708 ses
->kbdprefix
.repeat_count
= 0;
710 if (!nlinks
) return FRAME_EVENT_OK
;
712 for (length
= 1; nlinks
; nlinks
/= 10)
715 input_dialog(ses
->tab
->term
, NULL
,
716 N_("Go to link"), N_("Enter link number"),
718 length
, d
, 1, document
->nlinks
, check_number
,
719 (void (*)(void *, unsigned char *)) goto_link_number
, NULL
);
721 return FRAME_EVENT_OK
;
724 return FRAME_EVENT_IGNORED
;
727 static enum frame_event_status
728 try_form_insert_mode(struct session
*ses
, struct document_view
*doc_view
,
729 struct link
*link
, struct term_event
*ev
)
731 enum frame_event_status status
= FRAME_EVENT_IGNORED
;
732 enum edit_action action_id
;
734 if (!link_is_textinput(link
))
735 return FRAME_EVENT_IGNORED
;
737 action_id
= kbd_action(KEYMAP_EDIT
, ev
, NULL
);
739 if (ses
->insert_mode
== INSERT_MODE_OFF
) {
740 if (action_id
== ACT_EDIT_ENTER
) {
741 ses
->insert_mode
= INSERT_MODE_ON
;
742 status
= FRAME_EVENT_REFRESH
;
749 static enum frame_event_status
750 try_form_action(struct session
*ses
, struct document_view
*doc_view
,
751 struct link
*link
, struct term_event
*ev
)
753 enum frame_event_status status
;
757 if (!link_is_textinput(link
))
758 return FRAME_EVENT_IGNORED
;
760 status
= field_op(ses
, doc_view
, link
, ev
);
762 if (status
!= FRAME_EVENT_IGNORED
763 && ses
->insert_mode
== INSERT_MODE_ON
) {
764 assert(link
== get_current_link(doc_view
));
770 static enum frame_event_status
771 frame_ev_kbd(struct session
*ses
, struct document_view
*doc_view
, struct term_event
*ev
)
773 enum frame_event_status status
= FRAME_EVENT_IGNORED
;
774 int accesskey_priority
;
775 struct link
*link
= get_current_link(doc_view
);
778 status
= try_form_insert_mode(ses
, doc_view
, link
, ev
);
779 if (status
!= FRAME_EVENT_IGNORED
)
782 status
= try_form_action(ses
, doc_view
, link
, ev
);
783 if (status
!= FRAME_EVENT_IGNORED
)
788 status
= try_mark_key(ses
, doc_view
, ev
);
789 if (status
!= FRAME_EVENT_IGNORED
)
792 accesskey_priority
= get_opt_int("document.browse.accesskey.priority");
794 if (accesskey_priority
>= 2) {
795 status
= try_document_key(ses
, doc_view
, ev
);
797 if (status
!= FRAME_EVENT_IGNORED
) {
798 /* The document ate the key! */
803 status
= try_prefix_key(ses
, doc_view
, ev
);
804 if (status
!= FRAME_EVENT_IGNORED
)
807 if (accesskey_priority
== 1) {
808 status
= try_document_key(ses
, doc_view
, ev
);
810 if (status
!= FRAME_EVENT_IGNORED
) {
811 /* The document ate the key! */
816 return FRAME_EVENT_IGNORED
;
820 static enum frame_event_status
821 frame_ev_mouse(struct session
*ses
, struct document_view
*doc_view
, struct term_event
*ev
)
823 int x
= ev
->info
.mouse
.x
;
824 int y
= ev
->info
.mouse
.y
;
827 if (check_mouse_wheel(ev
)) {
828 if (!check_mouse_action(ev
, B_DOWN
)) {
829 /* We handle only B_DOWN case... */
830 } else if (check_mouse_button(ev
, B_WHEEL_UP
)) {
831 return scroll_mouse_up(ses
, doc_view
);
832 } else if (check_mouse_button(ev
, B_WHEEL_DOWN
)) {
833 return scroll_mouse_down(ses
, doc_view
);
836 return FRAME_EVENT_OK
;
839 link
= get_link_at_coordinates(doc_view
, x
, y
);
841 enum frame_event_status status
= FRAME_EVENT_REFRESH
;
843 doc_view
->vs
->current_link
= link
- doc_view
->document
->links
;
845 if (!link_is_textinput(link
)) {
847 status
= FRAME_EVENT_OK
;
849 refresh_view(ses
, doc_view
, 0);
851 if (check_mouse_button(ev
, B_LEFT
)
852 || check_mouse_button(ev
, B_MIDDLE
)) {
853 if (check_mouse_action(ev
, B_DOWN
))
854 do_not_ignore_next_mouse_event(ses
->tab
->term
);
855 else if (check_mouse_button(ev
, B_LEFT
))
856 status
= enter(ses
, doc_view
, 0);
857 else if (check_mouse_button(ev
, B_MIDDLE
))
858 open_current_link_in_new_tab(ses
, 1);
860 link_menu(ses
->tab
->term
, NULL
, ses
);
867 if (check_mouse_button(ev
, B_LEFT
)) {
868 /* Clicking the edge of screen will scroll the document. */
870 int scrollmargin
= get_opt_int("document.browse.scrolling.margin");
872 /* XXX: This is code duplication with kbd handlers. But
873 * repeatcount-free here. */
875 if (y
< scrollmargin
) {
876 return scroll_mouse_up(ses
, doc_view
);
878 if (y
>= doc_view
->box
.height
- scrollmargin
) {
879 return scroll_mouse_down(ses
, doc_view
);
882 if (x
< scrollmargin
* 2) {
883 return scroll_mouse_left(ses
, doc_view
);
885 if (x
>= doc_view
->box
.width
- scrollmargin
* 2) {
886 return scroll_mouse_right(ses
, doc_view
);
889 return FRAME_EVENT_OK
;
892 return FRAME_EVENT_IGNORED
;
894 #endif /* CONFIG_MOUSE */
896 static enum frame_event_status
897 frame_ev(struct session
*ses
, struct document_view
*doc_view
, struct term_event
*ev
)
899 assertm(doc_view
&& doc_view
->document
, "document not formatted");
900 if_assert_failed
return FRAME_EVENT_IGNORED
;
903 if_assert_failed
return FRAME_EVENT_IGNORED
;
905 /* When changing frame, vs may be NULL. See bug 525. */
906 if (!doc_view
->vs
) return FRAME_EVENT_IGNORED
;
910 return frame_ev_kbd(ses
, doc_view
, ev
);
913 return frame_ev_mouse(ses
, doc_view
, ev
);
914 #endif /* CONFIG_MOUSE */
916 return FRAME_EVENT_IGNORED
;
920 struct document_view
*
921 current_frame(struct session
*ses
)
923 struct document_view
*doc_view
= NULL
;
924 int current_frame_number
;
927 if_assert_failed
return NULL
;
929 if (!have_location(ses
)) return NULL
;
931 current_frame_number
= cur_loc(ses
)->vs
.current_link
;
932 if (current_frame_number
== -1) current_frame_number
= 0;
934 foreach (doc_view
, ses
->scrn_frames
) {
935 if (document_has_frames(doc_view
->document
)) continue;
936 if (!current_frame_number
--) return doc_view
;
939 doc_view
= ses
->doc_view
;
941 assert(doc_view
&& doc_view
->document
);
942 if_assert_failed
return NULL
;
944 if (document_has_frames(doc_view
->document
)) return NULL
;
948 static enum frame_event_status
949 send_to_frame(struct session
*ses
, struct document_view
*doc_view
,
950 struct term_event
*ev
)
952 enum frame_event_status status
;
954 assert(ses
&& ses
->tab
&& ses
->tab
->term
&& ev
);
955 if_assert_failed
return FRAME_EVENT_IGNORED
;
957 status
= frame_ev(ses
, doc_view
, ev
);
959 if (status
== FRAME_EVENT_REFRESH
)
960 refresh_view(ses
, doc_view
, 0);
962 print_screen_status(ses
);
969 do_mouse_event(struct session
*ses
, struct term_event
*ev
,
970 struct document_view
*doc_view
)
972 struct term_event evv
;
973 struct document_view
*matched
= NULL
, *first
= doc_view
;
976 if_assert_failed
return 0;
978 if (!doc_view
) return 0;
981 assert(doc_view
&& doc_view
->document
);
982 if_assert_failed
return 0;
984 assertm(doc_view
->document
->options
.box
.x
== doc_view
->box
.x
985 && doc_view
->document
->options
.box
.y
== doc_view
->box
.y
,
986 "Jonas' 1.565 -> 1.566 patch sucks");
987 if_assert_failed
return 0;
989 if (check_mouse_position(ev
, &doc_view
->box
)) {
995 doc_view
= current_frame(ses
);
997 } while (doc_view
!= first
);
999 if (!matched
) return 0;
1001 if (doc_view
!= first
) draw_formatted(ses
, 0);
1003 set_mouse_term_event(&evv
,
1004 ev
->info
.mouse
.x
- doc_view
->box
.x
,
1005 ev
->info
.mouse
.y
- doc_view
->box
.y
,
1006 ev
->info
.mouse
.button
);
1008 return send_to_frame(ses
, doc_view
, &evv
);
1011 /* Returns the session if event cleanup should be done or NULL if no cleanup is
1013 static struct session
*
1014 send_mouse_event(struct session
*ses
, struct document_view
*doc_view
,
1015 struct term_event
*ev
)
1017 struct terminal
*term
= ses
->tab
->term
;
1018 struct term_event_mouse
*mouse
= &ev
->info
.mouse
;
1021 && check_mouse_action(ev
, B_DOWN
)
1022 && !check_mouse_wheel(ev
)) {
1025 activate_bfu_technology(ses
, -1);
1026 m
= term
->windows
.next
;
1032 /* Handle tabs navigation if tabs bar is displayed. */
1033 if (ses
->status
.show_tabs_bar
1034 && mouse
->y
== term
->height
- 1 - !!ses
->status
.show_status_bar
) {
1035 int tab_num
= get_tab_number_by_xpos(term
, mouse
->x
);
1036 struct window
*tab
= get_current_tab(term
);
1038 if (check_mouse_action(ev
, B_UP
)) {
1039 if (check_mouse_button(ev
, B_MIDDLE
)
1040 && term
->current_tab
== tab_num
1041 && mouse
->y
== term
->prev_mouse_event
.y
) {
1042 if (tab
->data
== ses
) ses
= NULL
;
1044 close_tab(term
, tab
->data
);
1050 if (check_mouse_button(ev
, B_WHEEL_UP
)) {
1051 switch_current_tab(ses
, -1);
1053 } else if (check_mouse_button(ev
, B_WHEEL_DOWN
)) {
1054 switch_current_tab(ses
, 1);
1056 } else if (tab_num
!= -1) {
1057 switch_to_tab(term
, tab_num
, -1);
1059 if (check_mouse_button(ev
, B_MIDDLE
)) {
1060 do_not_ignore_next_mouse_event(term
);
1061 } else if (check_mouse_button(ev
, B_RIGHT
)) {
1062 tab_menu(tab
->data
, mouse
->x
, mouse
->y
, 1);
1069 if (!do_mouse_event(ses
, ev
, doc_view
)
1070 && check_mouse_button(ev
, B_RIGHT
)) {
1071 tab_menu(ses
, mouse
->x
, mouse
->y
, 0);
1076 if (ses
->status
.show_leds
1077 && mouse
->y
== term
->height
- 1
1078 && mouse
->x
>= term
->width
- LEDS_COUNT
- 3) {
1079 menu_leds_info(term
, NULL
, NULL
);
1086 #endif /* CONFIG_MOUSE */
1089 try_typeahead(struct session
*ses
, struct document_view
*doc_view
,
1090 struct term_event
*ev
, enum main_action action_id
)
1092 switch (get_opt_int("document.browse.search.typeahead")) {
1096 action_id
= ACT_MAIN_SEARCH_TYPEAHEAD_LINK
;
1099 action_id
= ACT_MAIN_SEARCH_TYPEAHEAD_TEXT
;
1102 INTERNAL("invalid value for document.browse.search.typeahead");
1105 search_typeahead(ses
, doc_view
, action_id
);
1107 /* Cross your fingers -- I'm just asking
1108 * for an infinite loop! -- Miciah */
1109 term_send_event(ses
->tab
->term
, ev
);
1112 /* Returns the session if event cleanup should be done or NULL if no cleanup is
1114 static struct session
*
1115 send_kbd_event(struct session
*ses
, struct document_view
*doc_view
,
1116 struct term_event
*ev
)
1119 enum main_action action_id
;
1121 if (doc_view
&& send_to_frame(ses
, doc_view
, ev
) != FRAME_EVENT_IGNORED
)
1124 action_id
= kbd_action(KEYMAP_MAIN
, ev
, &event
);
1126 if (action_id
== ACT_MAIN_QUIT
) {
1127 if (check_kbd_key(ev
, KBD_CTRL_C
))
1129 action_id
= ACT_MAIN_REALLY_QUIT
;
1132 switch (do_action(ses
, action_id
, 0)) {
1133 case FRAME_EVENT_SESSION_DESTROYED
:
1135 case FRAME_EVENT_IGNORED
:
1137 case FRAME_EVENT_OK
:
1138 case FRAME_EVENT_REFRESH
:
1142 if (action_id
== ACT_MAIN_SCRIPTING_FUNCTION
) {
1143 #ifdef CONFIG_SCRIPTING
1144 trigger_event(event
, ses
);
1149 if (check_kbd_key(ev
, KBD_CTRL_C
)) goto quit
;
1151 if (get_kbd_modifier(ev
) & KBD_MOD_ALT
) {
1154 get_kbd_modifier(ev
) &= ~KBD_MOD_ALT
;
1155 activate_bfu_technology(ses
, -1);
1156 win
= ses
->tab
->term
->windows
.next
;
1157 win
->handler(win
, ev
);
1158 if (ses
->tab
->term
->windows
.next
== win
) {
1160 get_kbd_modifier(ev
) |= KBD_MOD_ALT
;
1166 && get_opt_int("document.browse.accesskey"
1168 && try_document_key(ses
, doc_view
, ev
)
1169 == FRAME_EVENT_REFRESH
) {
1170 /* The document ate the key! */
1171 refresh_view(ses
, doc_view
, 0);
1179 if (!(get_kbd_modifier(ev
) & KBD_MOD_CTRL
)) {
1180 if (doc_view
) try_typeahead(ses
, doc_view
, ev
, action_id
);
1187 send_event(struct session
*ses
, struct term_event
*ev
)
1189 struct document_view
*doc_view
;
1192 if_assert_failed
return;
1193 doc_view
= current_frame(ses
);
1195 if (ev
->ev
== EVENT_KBD
) {
1196 ses
= send_kbd_event(ses
, doc_view
, ev
);
1199 if (ev
->ev
== EVENT_MOUSE
) {
1200 ses
= send_mouse_event(ses
, doc_view
, ev
);
1202 #endif /* CONFIG_MOUSE */
1204 /* ses may disappear ie. in close_tab() */
1205 if (ses
) ses
->kbdprefix
.repeat_count
= 0;
1208 enum frame_event_status
1209 download_link(struct session
*ses
, struct document_view
*doc_view
,
1210 action_id_T action_id
)
1212 struct link
*link
= get_current_link(doc_view
);
1213 void (*download
)(void *ses
, unsigned char *file
) = start_download
;
1215 if (!link
) return FRAME_EVENT_OK
;
1217 if (ses
->download_uri
) {
1218 done_uri(ses
->download_uri
);
1219 ses
->download_uri
= NULL
;
1222 switch (action_id
) {
1223 case ACT_MAIN_LINK_DOWNLOAD_RESUME
:
1224 download
= resume_download
;
1225 case ACT_MAIN_LINK_DOWNLOAD
:
1226 ses
->download_uri
= get_link_uri(ses
, doc_view
, link
);
1229 case ACT_MAIN_LINK_DOWNLOAD_IMAGE
:
1230 if (!link
->where_img
) break;
1231 ses
->download_uri
= get_uri(link
->where_img
, 0);
1235 INTERNAL("I think you forgot to take your medication, mental boy!");
1236 return FRAME_EVENT_OK
;
1239 if (!ses
->download_uri
) return FRAME_EVENT_OK
;
1241 set_session_referrer(ses
, doc_view
->document
->uri
);
1242 query_file(ses
, ses
->download_uri
, ses
, download
, NULL
, 1);
1244 return FRAME_EVENT_OK
;
1247 enum frame_event_status
1248 view_image(struct session
*ses
, struct document_view
*doc_view
, int xxxx
)
1250 struct link
*link
= get_current_link(doc_view
);
1252 if (link
&& link
->where_img
)
1253 goto_url(ses
, link
->where_img
);
1255 return FRAME_EVENT_OK
;
1258 enum frame_event_status
1259 save_as(struct session
*ses
, struct document_view
*doc_view
, int magic
)
1262 if_assert_failed
return FRAME_EVENT_OK
;
1264 if (!have_location(ses
)) return FRAME_EVENT_OK
;
1266 if (ses
->download_uri
) done_uri(ses
->download_uri
);
1267 ses
->download_uri
= get_uri_reference(cur_loc(ses
)->vs
.uri
);
1269 assert(doc_view
&& doc_view
->document
&& doc_view
->document
->uri
);
1270 if_assert_failed
return FRAME_EVENT_OK
;
1272 set_session_referrer(ses
, doc_view
->document
->uri
);
1273 query_file(ses
, ses
->download_uri
, ses
, start_download
, NULL
, 1);
1275 return FRAME_EVENT_OK
;
1279 save_formatted_finish(struct terminal
*term
, int h
, void *data
, int resume
)
1281 struct document
*document
= data
;
1283 assert(term
&& document
);
1284 if_assert_failed
return;
1286 if (h
== -1) return;
1287 if (dump_to_file(document
, h
)) {
1288 info_box(term
, 0, N_("Save error"), ALIGN_CENTER
,
1289 N_("Error writing to file"));
1295 save_formatted(void *data
, unsigned char *file
)
1297 struct session
*ses
= data
;
1298 struct document_view
*doc_view
;
1300 assert(ses
&& ses
->tab
&& ses
->tab
->term
&& file
);
1301 if_assert_failed
return;
1302 doc_view
= current_frame(ses
);
1303 assert(doc_view
&& doc_view
->document
);
1304 if_assert_failed
return;
1306 create_download_file(ses
->tab
->term
, file
, NULL
, 0, 0,
1307 save_formatted_finish
, doc_view
->document
);
1310 enum frame_event_status
1311 save_formatted_dlg(struct session
*ses
, struct document_view
*doc_view
, int xxxx
)
1313 query_file(ses
, doc_view
->vs
->uri
, ses
, save_formatted
, NULL
, 1);
1314 return FRAME_EVENT_OK
;