1 /** HTML viewer (and much more)
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"
64 detach_formatted(struct document_view
*doc_view
)
67 if_assert_failed
return;
69 #ifdef CONFIG_ECMASCRIPT
70 if (doc_view
->session
) {
71 mem_free_set(&doc_view
->session
->status
.window_status
, NULL
);
74 if (doc_view
->document
) {
75 release_document(doc_view
->document
);
76 doc_view
->document
= NULL
;
79 doc_view
->vs
->doc_view
= NULL
;
82 mem_free_set(&doc_view
->name
, NULL
);
85 /*! @a type == 0 -> PAGE_DOWN;
86 * @a type == 1 -> DOWN */
88 move_down(struct session
*ses
, struct document_view
*doc_view
, int type
)
92 assert(ses
&& doc_view
&& doc_view
->vs
);
93 if_assert_failed
return;
95 assert(ses
->navigate_mode
== NAVIGATE_LINKWISE
); /* XXX: drop it at some time. --Zas */
97 newpos
= doc_view
->vs
->y
+ doc_view
->box
.height
;
98 if (newpos
< doc_view
->document
->height
)
99 doc_view
->vs
->y
= newpos
;
101 if (current_link_is_visible(doc_view
))
105 find_link_down(doc_view
);
107 find_link_page_down(doc_view
);
112 enum frame_event_status
113 move_page_down(struct session
*ses
, struct document_view
*doc_view
)
115 int oldy
= doc_view
->vs
->y
;
116 int count
= eat_kbd_repeat_count(ses
);
118 ses
->navigate_mode
= NAVIGATE_LINKWISE
;
120 do move_down(ses
, doc_view
, 0); while (--count
> 0);
122 return doc_view
->vs
->y
== oldy
? FRAME_EVENT_OK
: FRAME_EVENT_REFRESH
;
125 /*! @a type == 0 -> PAGE_UP;
126 * @a type == 1 -> UP */
128 move_up(struct session
*ses
, struct document_view
*doc_view
, int type
)
130 assert(ses
&& doc_view
&& doc_view
->vs
);
131 if_assert_failed
return;
133 assert(ses
->navigate_mode
== NAVIGATE_LINKWISE
); /* XXX: drop it at some time. --Zas */
135 if (doc_view
->vs
->y
== 0) return;
137 doc_view
->vs
->y
-= doc_view
->box
.height
;
138 int_lower_bound(&doc_view
->vs
->y
, 0);
140 if (current_link_is_visible(doc_view
))
144 find_link_up(doc_view
);
146 find_link_page_up(doc_view
);
151 enum frame_event_status
152 move_page_up(struct session
*ses
, struct document_view
*doc_view
)
154 int oldy
= doc_view
->vs
->y
;
155 int count
= eat_kbd_repeat_count(ses
);
157 ses
->navigate_mode
= NAVIGATE_LINKWISE
;
159 do move_up(ses
, doc_view
, 0); while (--count
> 0);
161 return doc_view
->vs
->y
== oldy
? FRAME_EVENT_OK
: FRAME_EVENT_REFRESH
;
165 enum frame_event_status
166 move_link(struct session
*ses
, struct document_view
*doc_view
, int direction
,
167 int wraparound_bound
, int wraparound_link
)
172 assert(ses
&& doc_view
&& doc_view
->vs
&& doc_view
->document
);
173 if_assert_failed
return FRAME_EVENT_OK
;
175 ses
->navigate_mode
= NAVIGATE_LINKWISE
;
177 if (doc_view
->document
->nlinks
< 2) {
178 /* Wraparound only makes sense with more than one link. */
179 wraparound_bound
= -1;
181 /* We only bother this option if there's some links
183 wraparound
= get_opt_bool("document.browse.links.wraparound");
186 count
= eat_kbd_repeat_count(ses
);
189 int current_link
= doc_view
->vs
->current_link
;
191 if (current_link
== wraparound_bound
) {
193 jump_to_link_number(ses
, doc_view
, wraparound_link
);
194 /* FIXME: This needs further work, we should call
195 * page_down() and set_textarea() under some conditions
196 * as well. --pasky */
201 if (next_link_in_view_y(doc_view
, current_link
+ direction
,
206 /* This is a work around for the case where the index of
207 * @wraparound_bound is not necessarily the index of the first
208 * or the last link in the view. It means that the link moving
209 * could end up calling next_link_in_view() in the condition
210 * above. This is bad because next_link_in_view() will then
211 * 'reset' doc_view->vs->current_link to -1 and the effect will
212 * be that the current link will 'wrap around'. By restoring
213 * the index of the @current_link nothing will be wrapped
214 * around and move_{up,down} will take care of finding the next
216 doc_view
->vs
->current_link
= current_link
;
219 move_down(ses
, doc_view
, 1);
221 move_up(ses
, doc_view
, 1);
224 if (current_link
!= wraparound_bound
225 && current_link
!= doc_view
->vs
->current_link
) {
226 set_textarea(doc_view
, -direction
);
228 } while (--count
> 0);
230 return FRAME_EVENT_REFRESH
;
233 enum frame_event_status
234 move_link_dir(struct session
*ses
, struct document_view
*doc_view
, int dir_x
, int dir_y
)
238 assert(ses
&& doc_view
&& doc_view
->vs
&& doc_view
->document
);
239 if_assert_failed
return FRAME_EVENT_OK
;
241 ses
->navigate_mode
= NAVIGATE_LINKWISE
;
243 count
= eat_kbd_repeat_count(ses
);
246 int current_link
= doc_view
->vs
->current_link
;
248 if (next_link_in_dir(doc_view
, dir_x
, dir_y
))
251 /* FIXME: This won't preserve the column! */
253 move_down(ses
, doc_view
, 1);
255 move_up(ses
, doc_view
, 1);
257 if (dir_y
&& current_link
!= doc_view
->vs
->current_link
) {
258 set_textarea(doc_view
, -dir_y
);
260 } while (--count
> 0);
262 return FRAME_EVENT_REFRESH
;
265 /*! @a steps > 0 -> down */
266 static enum frame_event_status
267 vertical_scroll(struct session
*ses
, struct document_view
*doc_view
, int steps
)
271 assert(ses
&& doc_view
&& doc_view
->vs
&& doc_view
->document
);
272 if_assert_failed
return FRAME_EVENT_OK
;
274 y
= doc_view
->vs
->y
+ steps
;
277 int max_height
= doc_view
->document
->height
- doc_view
->box
.height
;
279 if (doc_view
->vs
->y
>= max_height
) return FRAME_EVENT_OK
;
280 int_upper_bound(&y
, max_height
);
283 int_lower_bound(&y
, 0);
285 if (doc_view
->vs
->y
== y
) return FRAME_EVENT_OK
;
289 if (current_link_is_visible(doc_view
))
290 return FRAME_EVENT_REFRESH
;
293 find_link_page_down(doc_view
);
295 find_link_page_up(doc_view
);
297 return FRAME_EVENT_REFRESH
;
300 /*! @a steps > 0 -> right */
301 static enum frame_event_status
302 horizontal_scroll(struct session
*ses
, struct document_view
*doc_view
, int steps
)
306 assert(ses
&& doc_view
&& doc_view
->vs
&& doc_view
->document
);
307 if_assert_failed
return FRAME_EVENT_OK
;
309 x
= doc_view
->vs
->x
+ steps
;
311 if (get_opt_bool("document.browse.scrolling.horizontal_extended")) {
312 max
= doc_view
->document
->width
- 1;
314 max
= int_max(doc_view
->vs
->x
,
315 doc_view
->document
->width
- doc_view
->box
.width
);
318 int_bounds(&x
, 0, max
);
319 if (doc_view
->vs
->x
== x
) return FRAME_EVENT_OK
;
323 if (current_link_is_visible(doc_view
))
324 return FRAME_EVENT_REFRESH
;
326 find_link_page_down(doc_view
);
328 return FRAME_EVENT_REFRESH
;
331 enum frame_event_status
332 scroll_up(struct session
*ses
, struct document_view
*doc_view
)
334 int steps
= eat_kbd_repeat_count(ses
);
337 steps
= get_opt_int("document.browse.scrolling.vertical_step");
339 return vertical_scroll(ses
, doc_view
, -steps
);
342 enum frame_event_status
343 scroll_down(struct session
*ses
, struct document_view
*doc_view
)
345 int steps
= eat_kbd_repeat_count(ses
);
348 steps
= get_opt_int("document.browse.scrolling.vertical_step");
350 return vertical_scroll(ses
, doc_view
, steps
);
353 enum frame_event_status
354 scroll_left(struct session
*ses
, struct document_view
*doc_view
)
356 int steps
= eat_kbd_repeat_count(ses
);
359 steps
= get_opt_int("document.browse.scrolling.horizontal_step");
361 return horizontal_scroll(ses
, doc_view
, -steps
);
364 enum frame_event_status
365 scroll_right(struct session
*ses
, struct document_view
*doc_view
)
367 int steps
= eat_kbd_repeat_count(ses
);
370 steps
= get_opt_int("document.browse.scrolling.horizontal_step");
372 return horizontal_scroll(ses
, doc_view
, steps
);
376 static enum frame_event_status
377 scroll_mouse_up(struct session
*ses
, struct document_view
*doc_view
)
379 int steps
= get_opt_int("document.browse.scrolling.vertical_step");
381 return vertical_scroll(ses
, doc_view
, -steps
);
384 static enum frame_event_status
385 scroll_mouse_down(struct session
*ses
, struct document_view
*doc_view
)
387 int steps
= get_opt_int("document.browse.scrolling.vertical_step");
389 return vertical_scroll(ses
, doc_view
, steps
);
392 static enum frame_event_status
393 scroll_mouse_left(struct session
*ses
, struct document_view
*doc_view
)
395 int steps
= get_opt_int("document.browse.scrolling.horizontal_step");
397 return horizontal_scroll(ses
, doc_view
, -steps
);
400 static enum frame_event_status
401 scroll_mouse_right(struct session
*ses
, struct document_view
*doc_view
)
403 int steps
= get_opt_int("document.browse.scrolling.horizontal_step");
405 return horizontal_scroll(ses
, doc_view
, steps
);
407 #endif /* CONFIG_MOUSE */
409 enum frame_event_status
410 move_document_start(struct session
*ses
, struct document_view
*doc_view
)
412 assert(ses
&& doc_view
&& doc_view
->vs
);
413 if_assert_failed
return FRAME_EVENT_OK
;
415 doc_view
->vs
->y
= doc_view
->vs
->x
= 0;
417 if (ses
->navigate_mode
== NAVIGATE_CURSOR_ROUTING
) {
418 /* Move to the first line and the first column. */
419 move_cursor(ses
, doc_view
, doc_view
->box
.x
, doc_view
->box
.y
);
421 find_link_page_down(doc_view
);
424 return FRAME_EVENT_REFRESH
;
427 enum frame_event_status
428 move_document_end(struct session
*ses
, struct document_view
*doc_view
)
432 assert(ses
&& doc_view
&& doc_view
->vs
&& doc_view
->document
);
433 if_assert_failed
return FRAME_EVENT_OK
;
435 max_height
= doc_view
->document
->height
- doc_view
->box
.height
;
437 int_lower_bound(&doc_view
->vs
->y
, int_max(0, max_height
));
439 if (ses
->navigate_mode
== NAVIGATE_CURSOR_ROUTING
) {
440 /* Move to the last line of the document,
441 * but preserve the column. This is done to avoid
442 * moving the cursor backwards if it is already
443 * on the last line but is not on the first column. */
444 move_cursor(ses
, doc_view
, ses
->tab
->x
,
445 doc_view
->document
->height
- doc_view
->vs
->y
);
447 find_link_page_up(doc_view
);
450 return FRAME_EVENT_REFRESH
;
453 enum frame_event_status
454 set_frame(struct session
*ses
, struct document_view
*doc_view
, int xxxx
)
456 assert(ses
&& ses
->doc_view
&& doc_view
&& doc_view
->vs
);
457 if_assert_failed
return FRAME_EVENT_OK
;
459 if (doc_view
== ses
->doc_view
) return FRAME_EVENT_OK
;
460 goto_uri(ses
, doc_view
->vs
->uri
);
461 ses
->navigate_mode
= NAVIGATE_LINKWISE
;
463 return FRAME_EVENT_OK
;
468 toggle_plain_html(struct session
*ses
, struct document_view
*doc_view
, int xxxx
)
470 assert(ses
&& doc_view
&& ses
->tab
&& ses
->tab
->term
);
471 if_assert_failed
return;
474 nowhere_box(ses
->tab
->term
, NULL
);
478 doc_view
->vs
->plain
= !doc_view
->vs
->plain
;
479 draw_formatted(ses
, 1);
483 toggle_wrap_text(struct session
*ses
, struct document_view
*doc_view
, int xxxx
)
485 assert(ses
&& doc_view
&& ses
->tab
&& ses
->tab
->term
);
486 if_assert_failed
return;
489 nowhere_box(ses
->tab
->term
, NULL
);
493 doc_view
->vs
->wrap
= !doc_view
->vs
->wrap
;
494 draw_formatted(ses
, 1);
497 /** Move the cursor to the document view co-ordinates provided
498 * as @a x and @a y, scroll the document if necessary, put us in
499 * cursor-routing navigation mode if that is not the current mode,
500 * and select any link under the cursor. */
501 enum frame_event_status
502 move_cursor(struct session
*ses
, struct document_view
*doc_view
, int x
, int y
)
504 enum frame_event_status status
= FRAME_EVENT_REFRESH
;
505 struct terminal
*term
= ses
->tab
->term
;
506 struct box
*box
= &doc_view
->box
;
509 /* If cursor was moved outside the document view scroll it, but only
510 * within the document canvas */
511 if (!is_in_box(box
, x
, y
)) {
512 int max_height
= doc_view
->document
->height
- doc_view
->vs
->y
;
513 int max_width
= doc_view
->document
->width
- doc_view
->vs
->x
;
516 status
= vertical_scroll(ses
, doc_view
, y
- box
->y
);
518 } else if (y
>= box
->y
+ box
->height
&& y
<= max_height
) {
519 status
= vertical_scroll(ses
, doc_view
,
520 y
- (box
->y
+ box
->height
- 1));
522 } else if (x
< box
->x
) {
523 status
= horizontal_scroll(ses
, doc_view
, x
- box
->x
);
525 } else if (x
>= box
->x
+ box
->width
&& x
<= max_width
) {
526 status
= horizontal_scroll(ses
, doc_view
,
527 x
- (box
->x
+ box
->width
- 1));
530 /* If the view was not scrolled there's nothing more to do */
531 if (status
!= FRAME_EVENT_REFRESH
)
534 /* Restrict the cursor position within the current view */
535 int_bounds(&x
, box
->x
, box
->x
+ box
->width
- 1);
536 int_bounds(&y
, box
->y
, box
->y
+ box
->height
- 1);
539 /* Scrolling could have changed the navigation mode */
540 ses
->navigate_mode
= NAVIGATE_CURSOR_ROUTING
;
542 link
= get_link_at_coordinates(doc_view
, x
- box
->x
, y
- box
->y
);
544 doc_view
->vs
->current_link
= link
- doc_view
->document
->links
;
546 doc_view
->vs
->current_link
= -1;
549 /* Set the unblockable cursor position and update the window pointer so
550 * stuff like the link menu will be drawn relative to the cursor. */
551 set_cursor(term
, x
, y
, 0);
552 set_window_ptr(ses
->tab
, x
, y
);
557 static enum frame_event_status
558 move_cursor_rel_count(struct session
*ses
, struct document_view
*view
,
559 int rx
, int ry
, int count
)
563 x
= ses
->tab
->x
+ rx
*count
;
564 y
= ses
->tab
->y
+ ry
*count
;
565 return move_cursor(ses
, view
, x
, y
);
568 static enum frame_event_status
569 move_cursor_rel(struct session
*ses
, struct document_view
*view
,
572 int count
= eat_kbd_repeat_count(ses
);
574 int_lower_bound(&count
, 1);
576 return move_cursor_rel_count(ses
, view
, rx
, ry
, count
);
579 enum frame_event_status
580 move_cursor_left(struct session
*ses
, struct document_view
*view
)
582 return move_cursor_rel(ses
, view
, -1, 0);
585 enum frame_event_status
586 move_cursor_right(struct session
*ses
, struct document_view
*view
)
588 return move_cursor_rel(ses
, view
, 1, 0);
591 enum frame_event_status
592 move_cursor_up(struct session
*ses
, struct document_view
*view
)
594 return move_cursor_rel(ses
, view
, 0, -1);
597 enum frame_event_status
598 move_cursor_down(struct session
*ses
, struct document_view
*view
)
600 return move_cursor_rel(ses
, view
, 0, 1);
603 enum frame_event_status
604 move_link_up_line(struct session
*ses
, struct document_view
*doc_view
)
606 struct document
*document
;
607 struct view_state
*vs
;
611 assert(ses
&& doc_view
&& doc_view
->vs
&& doc_view
->document
);
612 if_assert_failed
return FRAME_EVENT_OK
;
614 document
= doc_view
->document
;
615 box
= &doc_view
->box
;
616 if (!document
->lines1
) {
618 vs
->y
-= box
->height
;
619 int_lower_bound(&vs
->y
, 0);
620 return FRAME_EVENT_REFRESH
;
622 return FRAME_EVENT_OK
;
624 min_y
= vs
->y
- box
->height
;
625 int_lower_bound(&min_y
, 0);
626 y1
= y
= vs
->y
+ ses
->tab
->y
- box
->y
;
627 int_upper_bound(&y
, document
->height
- 1);
628 for (y
--; y
>= min_y
; y
--) {
629 struct link
*link
= document
->lines1
[y
];
632 for (; link
<= document
->lines2
[y
]; link
++) {
633 enum frame_event_status status
;
635 if (link
->points
[0].y
!= y
) continue;
637 /* The line is above the visible part
638 * of the document. Scroll it by one
639 * page, but not at all past the
640 * beginning of the document. */
641 int mini
= int_min(box
->height
, vs
->y
);
643 /* Before this update, y is the line
644 * number in the document, and y - y1
645 * is the number of lines the cursor
646 * must move in the document.
647 * Afterwards, y does not make sense,
648 * but y - y1 is the number of lines
649 * the cursor must move on the screen. */
653 status
= move_cursor_rel_count(ses
, doc_view
, 0, y
- y1
, 1);
654 if (link
== get_current_link(doc_view
))
655 ses
->navigate_mode
= NAVIGATE_LINKWISE
;
660 vs
->y
-= box
->height
;
661 int_lower_bound(&vs
->y
, 0);
662 ses
->navigate_mode
= NAVIGATE_CURSOR_ROUTING
;
663 return FRAME_EVENT_REFRESH
;
665 return FRAME_EVENT_OK
;
668 enum frame_event_status
669 move_link_down_line(struct session
*ses
, struct document_view
*doc_view
)
671 struct document
*document
;
672 struct view_state
*vs
;
676 assert(ses
&& doc_view
&& doc_view
->vs
&& doc_view
->document
);
677 if_assert_failed
return FRAME_EVENT_OK
;
679 document
= doc_view
->document
;
680 box
= &doc_view
->box
;
681 if (!document
->lines1
) {
682 if (vs
->y
+ box
->height
< document
->height
) {
683 vs
->y
+= box
->height
;
684 return FRAME_EVENT_REFRESH
;
686 return FRAME_EVENT_OK
;
688 max_y
= vs
->y
+ box
->height
* 2 - 1;
689 int_upper_bound(&max_y
, document
->height
- 1);
690 y1
= y
= vs
->y
+ ses
->tab
->y
- box
->y
;
691 for (y
++; y
<= max_y
; y
++) {
692 struct link
*link
= document
->lines1
[y
];
695 for (; link
<= document
->lines2
[y
]; link
++) {
696 enum frame_event_status status
;
698 if (link
->points
[0].y
!= y
) continue;
699 if (y
>= vs
->y
+ box
->height
) {
700 /* The line is below the visible part
701 * of the document. Scroll it by one
702 * page, but keep at least one line of
703 * the document on the screen. */
704 int mini
= int_min(box
->height
, document
->height
- vs
->y
- 1);
706 /* Before this update, y is the line
707 * number in the document, and y - y1
708 * is the number of lines the cursor
709 * must move in the document.
710 * Afterwards, y does not make sense,
711 * but y - y1 is the number of lines
712 * the cursor must move on the screen. */
716 status
= move_cursor_rel_count(ses
, doc_view
, 0, y
- y1
, 1);
717 if (link
== get_current_link(doc_view
))
718 ses
->navigate_mode
= NAVIGATE_LINKWISE
;
722 if (vs
->y
+ box
->height
< document
->height
) {
723 vs
->y
+= box
->height
;
724 ses
->navigate_mode
= NAVIGATE_CURSOR_ROUTING
;
725 return FRAME_EVENT_REFRESH
;
727 return FRAME_EVENT_OK
;
730 enum frame_event_status
731 move_link_prev_line(struct session
*ses
, struct document_view
*doc_view
)
733 struct view_state
*vs
;
734 struct document
*document
;
736 struct link
*link
, *last
= NULL
;
737 int y1
, y
, min_y
, min_x
, max_x
, x1
;
739 assert(ses
&& doc_view
&& doc_view
->vs
&& doc_view
->document
);
740 if_assert_failed
return FRAME_EVENT_OK
;
743 document
= doc_view
->document
;
744 box
= &doc_view
->box
;
745 if (!document
->lines1
) {
747 vs
->y
-= box
->height
;
748 int_lower_bound(&vs
->y
, 0);
749 return FRAME_EVENT_REFRESH
;
751 return FRAME_EVENT_OK
;
753 y
= y1
= vs
->y
+ ses
->tab
->y
- box
->y
;
754 x1
= vs
->x
+ ses
->tab
->x
- box
->x
;
756 link
= get_current_link(doc_view
);
758 get_link_x_bounds(link
, y1
, &min_x
, &max_x
);
762 int_upper_bound(&y
, document
->height
- 1);
763 min_y
= int_max(0, vs
->y
- box
->height
);
765 for (; y
>= min_y
; y
--, min_x
= INT_MAX
) {
766 link
= document
->lines1
[y
];
768 for (; link
<= document
->lines2
[y
]; link
++) {
769 if (link
->points
[0].y
!= y
) continue;
770 if (link
->points
[0].x
>= min_x
) continue;
771 if (!last
) last
= link
;
772 else if (link
->points
[0].x
> last
->points
[0].x
) last
= link
;
775 enum frame_event_status status
;
777 y
= last
->points
[0].y
;
779 /* The line is above the visible part
780 * of the document. Scroll it by one
781 * page, but not at all past the
782 * beginning of the document. */
783 int mini
= int_min(box
->height
, vs
->y
);
785 /* Before this update, y is the line
786 * number in the document, and y - y1
787 * is the number of lines the cursor
788 * must move in the document.
789 * Afterwards, y does not make sense,
790 * but y - y1 is the number of lines
791 * the cursor must move on the screen. */
795 status
= move_cursor_rel_count(ses
, doc_view
, last
->points
[0].x
- x1
, y
- y1
, 1);
796 if (last
== get_current_link(doc_view
))
797 ses
->navigate_mode
= NAVIGATE_LINKWISE
;
802 vs
->y
-= box
->height
;
803 int_lower_bound(&vs
->y
, 0);
804 ses
->navigate_mode
= NAVIGATE_CURSOR_ROUTING
;
805 return FRAME_EVENT_REFRESH
;
807 return FRAME_EVENT_OK
;
810 enum frame_event_status
811 move_link_next_line(struct session
*ses
, struct document_view
*doc_view
)
813 struct view_state
*vs
;
814 struct document
*document
;
816 struct link
*link
, *last
= NULL
;
817 int y1
, y
, max_y
, min_x
, max_x
, x1
;
819 assert(ses
&& doc_view
&& doc_view
->vs
&& doc_view
->document
);
820 if_assert_failed
return FRAME_EVENT_OK
;
823 document
= doc_view
->document
;
824 box
= &doc_view
->box
;
825 if (!document
->lines1
) {
826 if (vs
->y
+ box
->height
< document
->height
) {
827 vs
->y
+= box
->height
;
828 return FRAME_EVENT_REFRESH
;
830 return FRAME_EVENT_OK
;
832 y
= y1
= vs
->y
+ ses
->tab
->y
- box
->y
;
833 x1
= vs
->x
+ ses
->tab
->x
- box
->x
;
835 link
= get_current_link(doc_view
);
837 get_link_x_bounds(link
, y1
, &min_x
, &max_x
);
841 int_upper_bound(&y
, document
->height
- 1);
842 max_y
= int_min(vs
->y
+ 2 * box
->height
- 1, document
->height
- 1);
844 for (; y
<= max_y
; y
++, min_x
= -1) {
845 link
= document
->lines1
[y
];
847 for (; link
<= document
->lines2
[y
]; link
++) {
848 if (link
->points
[0].y
!= y
) continue;
849 if (link
->points
[0].x
<= min_x
) continue;
850 if (!last
) last
= link
;
851 else if (link
->points
[0].x
< last
->points
[0].x
) last
= link
;
854 enum frame_event_status status
;
856 y
= last
->points
[0].y
;
857 if (y
>= vs
->y
+ box
->height
) {
858 /* The line is below the visible part
859 * of the document. Scroll it by one
860 * page, but keep at least one line of
861 * the document on the screen. */
862 int mini
= int_min(box
->height
, document
->height
- vs
->y
- 1);
864 /* Before this update, y is the line
865 * number in the document, and y - y1
866 * is the number of lines the cursor
867 * must move in the document.
868 * Afterwards, y does not make sense,
869 * but y - y1 is the number of lines
870 * the cursor must move on the screen. */
874 status
= move_cursor_rel_count(ses
, doc_view
, last
->points
[0].x
- x1
, y
- y1
, 1);
875 if (last
== get_current_link(doc_view
))
876 ses
->navigate_mode
= NAVIGATE_LINKWISE
;
880 if (vs
->y
+ box
->height
< document
->height
) {
881 vs
->y
+= box
->height
;
882 ses
->navigate_mode
= NAVIGATE_CURSOR_ROUTING
;
883 return FRAME_EVENT_REFRESH
;
885 return FRAME_EVENT_OK
;
888 enum frame_event_status
889 move_cursor_line_start(struct session
*ses
, struct document_view
*doc_view
)
891 struct view_state
*vs
;
895 assert(ses
&& doc_view
&& doc_view
->vs
);
896 if_assert_failed
return FRAME_EVENT_OK
;
899 box
= &doc_view
->box
;
900 x
= vs
->x
+ ses
->tab
->x
- box
->x
;
901 return move_cursor_rel(ses
, doc_view
, -x
, 0);
904 enum frame_event_status
905 copy_current_link_to_clipboard(struct session
*ses
,
906 struct document_view
*doc_view
,
911 unsigned char *uristring
;
913 link
= get_current_link(doc_view
);
914 if (!link
) return FRAME_EVENT_OK
;
916 uri
= get_link_uri(ses
, doc_view
, link
);
917 if (!uri
) return FRAME_EVENT_OK
;
919 uristring
= get_uri_string(uri
, URI_ORIGINAL
);
923 set_clipboard_text(uristring
);
927 return FRAME_EVENT_OK
;
932 try_jump_to_link_number(struct session
*ses
, struct document_view
*doc_view
)
934 int link_number
= eat_kbd_repeat_count(ses
) - 1;
936 if (link_number
< 0) return 1;
938 if (!doc_view
) return 0;
940 if (link_number
>= doc_view
->document
->nlinks
)
943 jump_to_link_number(ses
, doc_view
, link_number
);
944 refresh_view(ses
, doc_view
, 0);
950 enum frame_event_status
951 try_mark_key(struct session
*ses
, struct document_view
*doc_view
,
952 struct term_event
*ev
)
954 term_event_key_T key
= get_kbd_key(ev
);
957 /* set_mark and goto_mark allow only a subset of the ASCII
958 * character repertoire as mark characters. If get_kbd_key(ev)
959 * is something else (i.e. a special key or a non-ASCII
960 * character), map it to an ASCII character that the functions
961 * will not accept, so the results are consistent.
962 * When CONFIG_UTF8 is not defined, this assumes that codes
963 * 0 to 0x7F in all codepages match ASCII. */
964 if (key
>= 0 && key
<= 0x7F)
965 mark
= (unsigned char) key
;
969 switch (ses
->kbdprefix
.mark
) {
970 case KP_MARK_NOTHING
:
971 return FRAME_EVENT_IGNORED
;
974 /* It is intentional to set the mark
975 * to NULL if !doc_view->vs. */
976 set_mark(mark
, doc_view
->vs
);
980 goto_mark(mark
, doc_view
->vs
);
984 ses
->kbdprefix
.repeat_count
= 0;
985 ses
->kbdprefix
.mark
= KP_MARK_NOTHING
;
987 return FRAME_EVENT_REFRESH
;
991 static enum frame_event_status
992 try_prefix_key(struct session
*ses
, struct document_view
*doc_view
,
993 struct term_event
*ev
)
995 struct document
*document
= doc_view
->document
;
996 struct document_options
*doc_opts
= &document
->options
;
997 int digit
= get_kbd_key(ev
) - '0';
999 if (digit
< 0 || digit
> 9)
1000 return FRAME_EVENT_IGNORED
;
1002 if (get_kbd_modifier(ev
)
1003 || ses
->kbdprefix
.repeat_count
/* The user has already begun
1004 * entering a prefix. */
1005 || !doc_opts
->num_links_key
1006 || (doc_opts
->num_links_key
== 1 && !doc_opts
->links_numbering
)) {
1008 * ses->kbdprefix.repeat_count is initialized to zero
1009 * the first time by init_session() calloc() call.
1010 * When used, it has to be reset to zero. */
1012 /* Clear the highlighting for the previous partial prefix. */
1013 if (ses
->kbdprefix
.repeat_count
) draw_formatted(ses
, 0);
1015 ses
->kbdprefix
.repeat_count
*= 10;
1016 ses
->kbdprefix
.repeat_count
+= digit
;
1018 /* If too big, just restart from zero, so pressing
1019 * '0' six times or more will reset the count. */
1020 if (ses
->kbdprefix
.repeat_count
> 99999)
1021 ses
->kbdprefix
.repeat_count
= 0;
1022 else if (ses
->kbdprefix
.repeat_count
)
1023 highlight_links_with_prefixes_that_start_with_n(
1024 ses
->tab
->term
, doc_view
,
1025 ses
->kbdprefix
.repeat_count
);
1027 return FRAME_EVENT_OK
;
1030 if (digit
>= 1 && !get_kbd_modifier(ev
)) {
1031 int nlinks
= document
->nlinks
, length
;
1032 unsigned char d
[2] = { get_kbd_key(ev
), 0 };
1034 ses
->kbdprefix
.repeat_count
= 0;
1036 if (!nlinks
) return FRAME_EVENT_OK
;
1038 for (length
= 1; nlinks
; nlinks
/= 10)
1041 input_dialog(ses
->tab
->term
, NULL
,
1042 N_("Go to link"), N_("Enter link number"),
1044 length
, d
, 1, document
->nlinks
, check_number
,
1045 (void (*)(void *, unsigned char *)) goto_link_number
, NULL
);
1047 return FRAME_EVENT_OK
;
1050 return FRAME_EVENT_IGNORED
;
1053 static enum frame_event_status
1054 try_form_insert_mode(struct session
*ses
, struct document_view
*doc_view
,
1055 struct link
*link
, struct term_event
*ev
)
1057 enum frame_event_status status
= FRAME_EVENT_IGNORED
;
1058 enum edit_action action_id
;
1060 if (!link_is_textinput(link
))
1061 return FRAME_EVENT_IGNORED
;
1063 action_id
= kbd_action(KEYMAP_EDIT
, ev
, NULL
);
1065 if (ses
->insert_mode
== INSERT_MODE_OFF
) {
1066 if (action_id
== ACT_EDIT_ENTER
) {
1067 ses
->insert_mode
= INSERT_MODE_ON
;
1068 status
= FRAME_EVENT_REFRESH
;
1075 static enum frame_event_status
1076 try_form_action(struct session
*ses
, struct document_view
*doc_view
,
1077 struct link
*link
, struct term_event
*ev
)
1079 enum frame_event_status status
;
1083 if (!link_is_textinput(link
))
1084 return FRAME_EVENT_IGNORED
;
1086 status
= field_op(ses
, doc_view
, link
, ev
);
1088 if (status
!= FRAME_EVENT_IGNORED
1089 && ses
->insert_mode
== INSERT_MODE_ON
) {
1090 assert(link
== get_current_link(doc_view
));
1096 static enum frame_event_status
1097 frame_ev_kbd(struct session
*ses
, struct document_view
*doc_view
, struct term_event
*ev
)
1099 enum frame_event_status status
= FRAME_EVENT_IGNORED
;
1100 int accesskey_priority
;
1101 struct link
*link
= get_current_link(doc_view
);
1104 status
= try_form_insert_mode(ses
, doc_view
, link
, ev
);
1105 if (status
!= FRAME_EVENT_IGNORED
)
1108 status
= try_form_action(ses
, doc_view
, link
, ev
);
1109 if (status
!= FRAME_EVENT_IGNORED
)
1114 status
= try_mark_key(ses
, doc_view
, ev
);
1115 if (status
!= FRAME_EVENT_IGNORED
)
1118 accesskey_priority
= get_opt_int("document.browse.accesskey.priority");
1120 if (accesskey_priority
>= 2) {
1121 status
= try_document_key(ses
, doc_view
, ev
);
1123 if (status
!= FRAME_EVENT_IGNORED
) {
1124 /* The document ate the key! */
1129 status
= try_prefix_key(ses
, doc_view
, ev
);
1130 if (status
!= FRAME_EVENT_IGNORED
)
1133 if (accesskey_priority
== 1) {
1134 status
= try_document_key(ses
, doc_view
, ev
);
1136 if (status
!= FRAME_EVENT_IGNORED
) {
1137 /* The document ate the key! */
1142 return FRAME_EVENT_IGNORED
;
1146 static enum frame_event_status
1147 frame_ev_mouse(struct session
*ses
, struct document_view
*doc_view
, struct term_event
*ev
)
1149 int x
= ev
->info
.mouse
.x
;
1150 int y
= ev
->info
.mouse
.y
;
1153 if (check_mouse_wheel(ev
)) {
1154 if (!check_mouse_action(ev
, B_DOWN
)) {
1155 /* We handle only B_DOWN case... */
1156 } else if (check_mouse_button(ev
, B_WHEEL_UP
)) {
1157 return scroll_mouse_up(ses
, doc_view
);
1158 } else if (check_mouse_button(ev
, B_WHEEL_DOWN
)) {
1159 return scroll_mouse_down(ses
, doc_view
);
1162 return FRAME_EVENT_OK
;
1165 link
= get_link_at_coordinates(doc_view
, x
, y
);
1167 enum frame_event_status status
= FRAME_EVENT_REFRESH
;
1169 doc_view
->vs
->current_link
= link
- doc_view
->document
->links
;
1170 ses
->navigate_mode
= NAVIGATE_LINKWISE
;
1172 if (!link_is_textinput(link
)) {
1174 status
= FRAME_EVENT_OK
;
1176 refresh_view(ses
, doc_view
, 0);
1178 if (check_mouse_button(ev
, B_LEFT
)
1179 || check_mouse_button(ev
, B_MIDDLE
)) {
1180 if (check_mouse_action(ev
, B_DOWN
))
1181 do_not_ignore_next_mouse_event(ses
->tab
->term
);
1182 else if (check_mouse_button(ev
, B_LEFT
))
1183 status
= enter(ses
, doc_view
, 0);
1184 else if (check_mouse_button(ev
, B_MIDDLE
))
1185 open_current_link_in_new_tab(ses
, 1);
1187 link_menu(ses
->tab
->term
, NULL
, ses
);
1194 if (check_mouse_button(ev
, B_LEFT
)) {
1195 /* Clicking the edge of screen will scroll the document. */
1197 int scrollmargin
= get_opt_int("document.browse.scrolling.margin");
1199 /* XXX: This is code duplication with kbd handlers. But
1200 * repeatcount-free here. */
1202 if (y
< scrollmargin
) {
1203 return scroll_mouse_up(ses
, doc_view
);
1205 if (y
>= doc_view
->box
.height
- scrollmargin
) {
1206 return scroll_mouse_down(ses
, doc_view
);
1209 if (x
< scrollmargin
* 2) {
1210 return scroll_mouse_left(ses
, doc_view
);
1212 if (x
>= doc_view
->box
.width
- scrollmargin
* 2) {
1213 return scroll_mouse_right(ses
, doc_view
);
1216 return FRAME_EVENT_OK
;
1219 return FRAME_EVENT_IGNORED
;
1221 #endif /* CONFIG_MOUSE */
1223 static enum frame_event_status
1224 frame_ev(struct session
*ses
, struct document_view
*doc_view
, struct term_event
*ev
)
1226 assertm(doc_view
&& doc_view
->document
, "document not formatted");
1227 if_assert_failed
return FRAME_EVENT_IGNORED
;
1230 if_assert_failed
return FRAME_EVENT_IGNORED
;
1232 /* When changing frame, vs may be NULL. See bug 525. */
1233 if (!doc_view
->vs
) return FRAME_EVENT_IGNORED
;
1237 return frame_ev_kbd(ses
, doc_view
, ev
);
1240 return frame_ev_mouse(ses
, doc_view
, ev
);
1241 #endif /* CONFIG_MOUSE */
1243 return FRAME_EVENT_IGNORED
;
1247 struct document_view
*
1248 current_frame(struct session
*ses
)
1250 struct document_view
*doc_view
= NULL
;
1251 int current_frame_number
;
1254 if_assert_failed
return NULL
;
1256 if (!have_location(ses
)) return NULL
;
1258 current_frame_number
= cur_loc(ses
)->vs
.current_link
;
1259 if (current_frame_number
== -1) current_frame_number
= 0;
1261 foreach (doc_view
, ses
->scrn_frames
) {
1262 if (document_has_frames(doc_view
->document
)) continue;
1263 if (!current_frame_number
--) return doc_view
;
1266 doc_view
= ses
->doc_view
;
1268 assert(doc_view
&& doc_view
->document
);
1269 if_assert_failed
return NULL
;
1271 if (document_has_frames(doc_view
->document
)) return NULL
;
1275 static enum frame_event_status
1276 send_to_frame(struct session
*ses
, struct document_view
*doc_view
,
1277 struct term_event
*ev
)
1279 enum frame_event_status status
;
1281 assert(ses
&& ses
->tab
&& ses
->tab
->term
&& ev
);
1282 if_assert_failed
return FRAME_EVENT_IGNORED
;
1284 status
= frame_ev(ses
, doc_view
, ev
);
1286 if (status
== FRAME_EVENT_REFRESH
)
1287 refresh_view(ses
, doc_view
, 0);
1289 print_screen_status(ses
);
1296 do_mouse_event(struct session
*ses
, struct term_event
*ev
,
1297 struct document_view
*doc_view
)
1299 struct term_event evv
;
1300 struct document_view
*matched
= NULL
, *first
= doc_view
;
1303 if_assert_failed
return 0;
1305 if (!doc_view
) return 0;
1308 assert(doc_view
&& doc_view
->document
);
1309 if_assert_failed
return 0;
1311 assertm(doc_view
->document
->options
.box
.x
== doc_view
->box
.x
1312 && doc_view
->document
->options
.box
.y
== doc_view
->box
.y
,
1313 "Jonas' 1.565 -> 1.566 patch sucks");
1314 if_assert_failed
return 0;
1316 if (check_mouse_position(ev
, &doc_view
->box
)) {
1322 doc_view
= current_frame(ses
);
1324 } while (doc_view
!= first
);
1326 if (!matched
) return 0;
1328 if (doc_view
!= first
) draw_formatted(ses
, 0);
1330 set_mouse_term_event(&evv
,
1331 ev
->info
.mouse
.x
- doc_view
->box
.x
,
1332 ev
->info
.mouse
.y
- doc_view
->box
.y
,
1333 ev
->info
.mouse
.button
);
1335 return send_to_frame(ses
, doc_view
, &evv
);
1339 is_mouse_on_tab_bar(struct session
*ses
, struct term_event_mouse
*mouse
)
1341 struct terminal
*term
= ses
->tab
->term
;
1344 if (ses
->status
.show_tabs_bar_at_top
) y
= ses
->status
.show_title_bar
;
1345 else y
= term
->height
- 1 - !!ses
->status
.show_status_bar
;
1347 return mouse
->y
== y
;
1349 /** @returns the session if event cleanup should be done or NULL if no
1350 * cleanup is needed. */
1351 static struct session
*
1352 send_mouse_event(struct session
*ses
, struct document_view
*doc_view
,
1353 struct term_event
*ev
)
1355 struct terminal
*term
= ses
->tab
->term
;
1356 struct term_event_mouse
*mouse
= &ev
->info
.mouse
;
1359 && check_mouse_action(ev
, B_DOWN
)
1360 && !check_mouse_wheel(ev
)) {
1363 activate_bfu_technology(ses
, -1);
1364 m
= term
->windows
.next
;
1370 /* Handle tabs navigation if tabs bar is displayed. */
1371 if (ses
->status
.show_tabs_bar
&& is_mouse_on_tab_bar(ses
, mouse
)) {
1372 int tab_num
= get_tab_number_by_xpos(term
, mouse
->x
);
1373 struct window
*current_tab
= get_current_tab(term
);
1375 if (check_mouse_action(ev
, B_UP
)) {
1376 if (check_mouse_button(ev
, B_MIDDLE
)
1377 && term
->current_tab
== tab_num
1378 && mouse
->y
== term
->prev_mouse_event
.y
) {
1379 if (current_tab
->data
== ses
) ses
= NULL
;
1381 close_tab(term
, current_tab
->data
);
1387 if (check_mouse_button(ev
, B_WHEEL_UP
)) {
1388 switch_current_tab(ses
, -1);
1390 } else if (check_mouse_button(ev
, B_WHEEL_DOWN
)) {
1391 switch_current_tab(ses
, 1);
1393 } else if (tab_num
!= -1) {
1394 switch_to_tab(term
, tab_num
, -1);
1396 if (check_mouse_button(ev
, B_MIDDLE
)) {
1397 do_not_ignore_next_mouse_event(term
);
1398 } else if (check_mouse_button(ev
, B_RIGHT
)) {
1399 tab_menu(current_tab
->data
, mouse
->x
, mouse
->y
, 1);
1406 if (!do_mouse_event(ses
, ev
, doc_view
)
1407 && check_mouse_button(ev
, B_RIGHT
)) {
1408 tab_menu(ses
, mouse
->x
, mouse
->y
, 0);
1413 if (ses
->status
.show_leds
1414 && mouse
->y
== term
->height
- 1
1415 && mouse
->x
>= term
->width
- LEDS_COUNT
- 3) {
1416 menu_leds_info(term
, NULL
, NULL
);
1423 #endif /* CONFIG_MOUSE */
1426 try_typeahead(struct session
*ses
, struct document_view
*doc_view
,
1427 struct term_event
*ev
, enum main_action action_id
)
1429 switch (get_opt_int("document.browse.search.typeahead")) {
1433 action_id
= ACT_MAIN_SEARCH_TYPEAHEAD_LINK
;
1436 action_id
= ACT_MAIN_SEARCH_TYPEAHEAD_TEXT
;
1439 INTERNAL("invalid value for document.browse.search.typeahead");
1442 search_typeahead(ses
, doc_view
, action_id
);
1444 /* Cross your fingers -- I'm just asking
1445 * for an infinite loop! -- Miciah */
1446 term_send_event(ses
->tab
->term
, ev
);
1449 /** @returns the session if event cleanup should be done or NULL if no
1450 * cleanup is needed. */
1451 static struct session
*
1452 send_kbd_event(struct session
*ses
, struct document_view
*doc_view
,
1453 struct term_event
*ev
)
1456 enum main_action action_id
;
1458 if (doc_view
&& send_to_frame(ses
, doc_view
, ev
) != FRAME_EVENT_IGNORED
)
1461 action_id
= kbd_action(KEYMAP_MAIN
, ev
, &event
);
1463 if (action_id
== ACT_MAIN_QUIT
) {
1464 if (check_kbd_key(ev
, KBD_CTRL_C
))
1466 action_id
= ACT_MAIN_REALLY_QUIT
;
1469 switch (do_action(ses
, action_id
, 0)) {
1470 case FRAME_EVENT_SESSION_DESTROYED
:
1472 case FRAME_EVENT_IGNORED
:
1474 case FRAME_EVENT_OK
:
1475 case FRAME_EVENT_REFRESH
:
1479 if (action_id
== ACT_MAIN_SCRIPTING_FUNCTION
) {
1480 #ifdef CONFIG_SCRIPTING
1481 trigger_event(event
, ses
);
1486 if (check_kbd_key(ev
, KBD_CTRL_C
)) goto quit
;
1488 /* Ctrl-Alt-F should not open the File menu like Alt-f does. */
1489 if (check_kbd_modifier(ev
, KBD_MOD_ALT
)) {
1492 get_kbd_modifier(ev
) &= ~KBD_MOD_ALT
;
1493 activate_bfu_technology(ses
, -1);
1494 win
= ses
->tab
->term
->windows
.next
;
1495 win
->handler(win
, ev
);
1496 if (ses
->tab
->term
->windows
.next
== win
) {
1497 deselect_mainmenu(win
->term
, win
->data
);
1498 print_screen_status(ses
);
1500 if (ses
->tab
!= ses
->tab
->term
->windows
.next
)
1502 get_kbd_modifier(ev
) |= KBD_MOD_ALT
;
1505 && get_opt_int("document.browse.accesskey"
1507 && try_document_key(ses
, doc_view
, ev
)
1508 == FRAME_EVENT_REFRESH
) {
1509 /* The document ate the key! */
1510 refresh_view(ses
, doc_view
, 0);
1518 if (!(get_kbd_modifier(ev
) & KBD_MOD_CTRL
)) {
1519 if (doc_view
) try_typeahead(ses
, doc_view
, ev
, action_id
);
1526 send_event(struct session
*ses
, struct term_event
*ev
)
1529 if_assert_failed
return;
1531 if (ev
->ev
== EVENT_KBD
) {
1532 struct document_view
*doc_view
= current_frame(ses
);
1534 ses
= send_kbd_event(ses
, doc_view
, ev
);
1537 else if (ev
->ev
== EVENT_MOUSE
) {
1538 struct document_view
*doc_view
= current_frame(ses
);
1540 ses
= send_mouse_event(ses
, doc_view
, ev
);
1542 #endif /* CONFIG_MOUSE */
1544 /* @ses may disappear ie. in close_tab() */
1545 if (ses
) ses
->kbdprefix
.repeat_count
= 0;
1548 enum frame_event_status
1549 download_link(struct session
*ses
, struct document_view
*doc_view
,
1550 action_id_T action_id
)
1552 struct link
*link
= get_current_link(doc_view
);
1553 void (*download
)(void *ses
, unsigned char *file
) = start_download
;
1555 if (!link
) return FRAME_EVENT_OK
;
1557 if (ses
->download_uri
) {
1558 done_uri(ses
->download_uri
);
1559 ses
->download_uri
= NULL
;
1562 switch (action_id
) {
1563 case ACT_MAIN_LINK_DOWNLOAD_RESUME
:
1564 download
= resume_download
;
1565 case ACT_MAIN_LINK_DOWNLOAD
:
1566 ses
->download_uri
= get_link_uri(ses
, doc_view
, link
);
1569 case ACT_MAIN_LINK_DOWNLOAD_IMAGE
:
1570 if (!link
->where_img
) break;
1571 ses
->download_uri
= get_uri(link
->where_img
, 0);
1575 INTERNAL("I think you forgot to take your medication, mental boy!");
1576 return FRAME_EVENT_OK
;
1579 if (!ses
->download_uri
) return FRAME_EVENT_OK
;
1581 set_session_referrer(ses
, doc_view
->document
->uri
);
1582 query_file(ses
, ses
->download_uri
, ses
, download
, NULL
, 1);
1584 return FRAME_EVENT_OK
;
1587 enum frame_event_status
1588 view_image(struct session
*ses
, struct document_view
*doc_view
, int xxxx
)
1590 struct link
*link
= get_current_link(doc_view
);
1592 if (link
&& link
->where_img
)
1593 goto_url(ses
, link
->where_img
);
1595 return FRAME_EVENT_OK
;
1598 enum frame_event_status
1599 save_as(struct session
*ses
, struct document_view
*doc_view
, int magic
)
1602 if_assert_failed
return FRAME_EVENT_OK
;
1604 if (!have_location(ses
)) return FRAME_EVENT_OK
;
1606 if (ses
->download_uri
) done_uri(ses
->download_uri
);
1607 ses
->download_uri
= get_uri_reference(cur_loc(ses
)->vs
.uri
);
1609 assert(doc_view
&& doc_view
->document
&& doc_view
->document
->uri
);
1610 if_assert_failed
return FRAME_EVENT_OK
;
1612 set_session_referrer(ses
, doc_view
->document
->uri
);
1613 query_file(ses
, ses
->download_uri
, ses
, start_download
, NULL
, 1);
1615 return FRAME_EVENT_OK
;
1618 /*! save_formatted() passes this function as a ::cdf_callback_T to
1619 * create_download_finish(). */
1621 save_formatted_finish(struct terminal
*term
, int h
,
1622 void *data
, enum download_flags flags
)
1624 struct document
*document
= data
;
1626 assert(term
&& document
);
1627 if_assert_failed
return;
1629 if (h
== -1) return;
1630 if (dump_to_file(document
, h
)) {
1631 info_box(term
, 0, N_("Save error"), ALIGN_CENTER
,
1632 N_("Error writing to file"));
1638 save_formatted(void *data
, unsigned char *file
)
1640 struct session
*ses
= data
;
1641 struct document_view
*doc_view
;
1643 assert(ses
&& ses
->tab
&& ses
->tab
->term
&& file
);
1644 if_assert_failed
return;
1645 doc_view
= current_frame(ses
);
1646 assert(doc_view
&& doc_view
->document
);
1647 if_assert_failed
return;
1649 create_download_file(ses
->tab
->term
, file
, NULL
,
1650 DOWNLOAD_RESUME_DISABLED
,
1651 save_formatted_finish
, doc_view
->document
);
1654 enum frame_event_status
1655 save_formatted_dlg(struct session
*ses
, struct document_view
*doc_view
, int xxxx
)
1657 query_file(ses
, doc_view
->vs
->uri
, ses
, save_formatted
, NULL
, 1);
1658 return FRAME_EVENT_OK
;