6 external init
: Unix.file_descr
-> params
-> unit = "ml_init";;
7 external seltext
: opaque
-> (int * int * int * int) -> unit = "ml_seltext";;
8 external hassel
: opaque
-> bool = "ml_hassel";;
9 external copysel
: Unix.file_descr
-> opaque
-> unit = "ml_copysel";;
10 external getpdimrect
: int -> float array
= "ml_getpdimrect";;
11 external whatsunder
: opaque
-> int -> int -> under
= "ml_whatsunder";;
12 external markunder
: opaque
-> int -> int -> mark
-> bool = "ml_markunder";;
13 external clearmark
: opaque
-> unit = "ml_clearmark";;
14 external zoomforh
: int -> int -> int -> int -> float = "ml_zoom_for_height";;
15 external getmaxw
: unit -> float = "ml_getmaxw";;
16 external drawstr
: int -> int -> int -> string -> float = "ml_draw_string";;
17 external measurestr
: int -> string -> float = "ml_measure_string";;
18 external postprocess
:
19 opaque
-> int -> int -> int -> (int * string * int) -> int
21 external pagebbox
: opaque
-> (int * int * int * int) = "ml_getpagebox";;
22 external setaalevel
: int -> unit = "ml_setaalevel";;
23 external realloctexts
: int -> bool = "ml_realloctexts";;
24 external findlink
: opaque
-> linkdir
-> link
= "ml_findlink";;
25 external getlink
: opaque
-> int -> under
= "ml_getlink";;
26 external getlinkrect
: opaque
-> int -> irect
= "ml_getlinkrect";;
27 external getlinkcount
: opaque
-> int = "ml_getlinkcount";;
28 external findpwl
: int -> int -> pagewithlinks
= "ml_find_page_with_links";;
29 external getpbo
: width
-> height
-> colorspace
-> opaque
= "ml_getpbo";;
30 external freepbo
: opaque
-> unit = "ml_freepbo";;
31 external unmappbo
: opaque
-> unit = "ml_unmappbo";;
32 external bousable
: unit -> bool = "ml_bo_usable";;
33 external unproject
: opaque
-> int -> int -> (int * int) option
35 external project
: opaque
-> int -> int -> float -> float -> (float * float)
37 external drawtile
: tileparams
-> opaque
-> unit = "ml_drawtile";;
38 external rectofblock
: opaque
-> int -> int -> float array
option
40 external begintiles
: unit -> unit = "ml_begintiles";;
41 external endtiles
: unit -> unit = "ml_endtiles";;
42 external addannot
: opaque
-> int -> int -> string -> unit = "ml_addannot";;
43 external modannot
: opaque
-> slinkindex
-> string -> unit = "ml_modannot";;
44 external delannot
: opaque
-> slinkindex
-> unit = "ml_delannot";;
45 external hasunsavedchanges
: unit -> bool = "ml_hasunsavedchanges";;
46 external savedoc
: string -> unit = "ml_savedoc";;
47 external getannotcontents
: opaque
-> slinkindex
-> string
48 = "ml_getannotcontents";;
49 external drawprect
: opaque
-> int -> int -> float array
-> unit =
51 external wcmd
: Unix.file_descr
-> bytes
-> int -> unit = "ml_wcmd";;
52 external rcmd
: Unix.file_descr
-> string = "ml_rcmd";;
54 let selfexec = ref E.s
;;
55 let opengl_has_pbo = ref false;;
57 let drawstring size x y s
=
59 Gl.enable `texture_2d
;
60 GlFunc.blend_func ~src
:`src_alpha ~dst
:`one_minus_src_alpha
;
61 ignore
(drawstr size x y s
);
63 Gl.disable `texture_2d
;
66 let drawstring1 size x y s
=
70 let drawstring2 size x y fmt
=
71 Printf.kprintf
(drawstring size
(x
+1) (y
+size
+1)) fmt
75 dolog
"l %d dim=%d {" l
.pageno l
.pagedimno
;
76 dolog
" WxH %dx%d" l
.pagew l
.pageh
;
77 dolog
" vWxH %dx%d" l
.pagevw l
.pagevh
;
78 dolog
" pagex,y %d,%d" l
.pagex l
.pagey
;
79 dolog
" dispx,y %d,%d" l
.pagedispx l
.pagedispy
;
80 dolog
" column %d" l
.pagecol
;
84 let debugrect (x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
) =
86 dolog
" x0,y0=(% f, % f)" x0 y0
;
87 dolog
" x1,y1=(% f, % f)" x1 y1
;
88 dolog
" x2,y2=(% f, % f)" x2 y2
;
89 dolog
" x3,y3=(% f, % f)" x3 y3
;
93 let isbirdseye = function
100 let istextentry = function
101 | Textentry _
-> true
107 let wtmode = ref false;;
108 let cxack = ref false;;
110 let pgscale h
= truncate
(float h
*. conf
.pgscale);;
113 if not state
.uioh#alwaysscrolly
&& (conf
.scrollb
land scrollbhv
= 0)
114 || (state
.x
= 0 && state
.w
<= state
.winw
- conf
.scrollbw
)
120 if not state
.uioh#alwaysscrolly
&& (conf
.scrollb
land scrollbvv
= 0)
128 else x
> state
.winw
- vscrollw ()
131 let wadjsb () = -vscrollw ();;
132 let xadjsb () = if conf
.leftscroll
then vscrollw () else 0;;
135 fstate
.fontsize
<- n
;
136 fstate
.wwidth
<- measurestr fstate
.fontsize
"w";
137 fstate
.maxrows
<- (state
.winh
- fstate
.fontsize
- 1) / (fstate
.fontsize
+ 1);
143 else Printf.kprintf ignore fmt
147 if emptystr conf
.pathlauncher
148 then dolog
"%s" state
.path
150 let command = Str.global_replace percentsre state
.path conf
.pathlauncher
in
151 match spawn
command [] with
154 dolog
"failed to execute `%s': %s" command @@ exntos exn
160 let postRedisplay who
=
161 vlog "redisplay for [%S]" who
;
162 state
.redisplay
<- true;
166 let getopaque pageno
=
167 try Some
(Hashtbl.find state
.pagemap
(pageno
, state
.gen
))
168 with Not_found
-> None
171 let pagetranslatepoint l x y
=
172 let dy = y
- l
.pagedispy
in
173 let y = dy + l
.pagey
in
174 let dx = x
- l
.pagedispx
in
175 let x = dx + l
.pagex
in
179 let onppundermouse g
x y d
=
182 begin match getopaque l
.pageno
with
184 let x0 = l
.pagedispx
in
185 let x1 = x0 + l
.pagevw
in
186 let y0 = l
.pagedispy
in
187 let y1 = y0 + l
.pagevh
in
188 if y >= y0 && y <= y1 && x >= x0 && x <= x1
190 let px, py
= pagetranslatepoint l
x y in
191 match g opaque l
px py
with
204 let g opaque l
px py
=
207 match rectofblock opaque
px py
with
208 | Some
[|x0;x1;y0;y1|] ->
209 let ox = xadjsb () |> float in
210 let rect = (x0+.ox, y0, x1+.ox, y0, x1+.ox, y1, x0+.ox, y1) in
211 let color = (0.0, 0.0, 1.0 /. (l
.pageno
mod 3 |> float), 0.5) in
212 state
.rects
<- [l
.pageno
, color, rect];
213 G.postRedisplay "getunder";
216 let under = whatsunder opaque
px py
in
217 if under = Unone
then None
else Some
under
219 onppundermouse g x y Unone
224 match unproject opaque
x y with
225 | Some
(x, y) -> Some
(Some
(opaque
, l
.pageno
, x, y))
228 onppundermouse g x y None
;
232 state
.text
<- Printf.sprintf
"%c%s" c s
;
233 G.postRedisplay "showtext";
237 Format.ksprintf
(fun s
-> showtext '
!' s
) fmt
;
240 let pipesel opaque cmd
=
243 match Unix.pipe
() with
244 | (exception exn
) -> dolog
"pipesel cannot create pipe: %S" @@ exntos exn
;
246 let doclose what fd
=
247 Ne.clo fd
(fun msg
-> dolog
"%s close failed: %s" what msg
)
250 try spawn cmd
[r
, 0; w
, -1]
252 dolog
"cannot execute %S: %s" cmd
@@ exntos exn
;
258 G.postRedisplay "pipesel";
260 else doclose "pipesel pipe/w" w
;
261 doclose "pipesel pipe/r" r
;
265 let g opaque l
px py
=
266 if markunder opaque
px py conf
.paxmark
269 match getopaque l
.pageno
with
271 | Some opaque
-> pipesel opaque conf
.paxcmd
276 G.postRedisplay "paxunder";
277 if conf
.paxmark
= Mark_page
280 match getopaque l
.pageno
with
282 | Some opaque
-> clearmark opaque
) state
.layout
;
283 state
.roam
<- onppundermouse g x y (fun () -> impmsg "whoopsie daisy");
287 match Unix.pipe
() with
288 | (exception exn
) -> impmsg "pipe failed: %s" @@ exntos exn
291 Ne.clo fd
(fun msg
-> impmsg "failed to close %s: %s" cap msg
)
294 try spawn conf
.selcmd
[r
, 0; w
, -1]
296 impmsg "failed to execute %s: %s" conf
.selcmd
@@ exntos exn
;
302 let l = String.length s
in
303 let bytes = Bytes.unsafe_of_string s
in
304 let n = tempfailureretry
(Unix.write w
bytes 0) l in
306 then impmsg "failed to write %d characters to sel pipe, wrote %d"
309 impmsg "failed to write to sel pipe: %s" @@ exntos exn
312 clo "selstring pipe/r" r
;
313 clo "selstring pipe/w" w
;
316 let undertext ?
(nopath
=false) = function
319 | Ulinkgoto
(pageno
, _
) ->
321 then "page " ^ string_of_int
(pageno
+1)
322 else Printf.sprintf
"%s: page %d" state
.path
(pageno
+1)
323 | Utext s
-> "font: " ^ s
324 | Uunexpected s
-> "unexpected: " ^ s
325 | Ulaunch s
-> "launch: " ^ s
326 | Unamed s
-> "named: " ^ s
327 | Uremote
(filename
, pageno
) ->
328 Printf.sprintf
"%s: page %d" filename
(pageno
+1)
329 | Uremotedest
(filename
, destname
) ->
330 Printf.sprintf
"%s: destination %S" filename destname
331 | Uannotation
(opaque
, slinkindex
) ->
332 "annotation: " ^ getannotcontents opaque slinkindex
335 let updateunder x y =
336 match getunder x y with
337 | Unone
-> Wsi.setcursor
Wsi.CURSOR_INHERIT
339 if conf
.underinfo
then showtext 'u'
("ri: " ^ uri
);
340 Wsi.setcursor
Wsi.CURSOR_INFO
341 | Ulinkgoto
(pageno
, _
) ->
343 then showtext 'p'
("age: " ^ string_of_int
(pageno
+1));
344 Wsi.setcursor
Wsi.CURSOR_INFO
346 if conf
.underinfo
then showtext '
f'
("ont: " ^ s
);
347 Wsi.setcursor
Wsi.CURSOR_TEXT
349 if conf
.underinfo
then showtext 'u'
("nexpected: " ^ s
);
350 Wsi.setcursor
Wsi.CURSOR_INHERIT
352 if conf
.underinfo
then showtext '
l'
("aunch: " ^ s
);
353 Wsi.setcursor
Wsi.CURSOR_INHERIT
355 if conf
.underinfo
then showtext '
n'
("amed: " ^ s
);
356 Wsi.setcursor
Wsi.CURSOR_INHERIT
357 | Uremote
(filename
, pageno
) ->
358 if conf
.underinfo
then showtext 'r'
359 (Printf.sprintf
"emote: %s (%d)" filename
(pageno
+1));
360 Wsi.setcursor
Wsi.CURSOR_INFO
361 | Uremotedest
(filename
, destname
) ->
362 if conf
.underinfo
then showtext 'r'
363 (Printf.sprintf
"emote destination: %s (%S)" filename destname
);
364 Wsi.setcursor
Wsi.CURSOR_INFO
366 if conf
.underinfo
then showtext 'a'
"nnotation";
367 Wsi.setcursor
Wsi.CURSOR_INFO
370 let showlinktype under =
371 if conf
.underinfo
&& under != Unone
372 then showtext ' '
@@ undertext under
375 let intentry_with_suffix text key
=
377 if key
>= 32 && key
< 127
381 match Char.lowercase
c with
383 let text = addchar
text c in
387 let text = addchar
text c in
391 state
.text <- Printf.sprintf
"invalid char (%d, `%c')" key
c;
396 let b = Buffer.create
16 in
397 Buffer.add_string
b "llll";
400 let b = Buffer.to_bytes
b in
401 wcmd state
.ss
b @@ Bytes.length
b
405 let nogeomcmds cmds
=
407 | s
, [] -> emptystr s
411 let layoutN ((columns
, coverA
, coverB
), b) x y sw sh
=
412 let sh = sh - (hscrollh ()) in
413 let wadj = wadjsb () in
414 let rec fold accu
n =
415 if n = Array.length
b
418 let pdimno, dx, vy
, (_
, w
, h
, xoff
) = b.(n) in
421 || n = state
.pagecount
- coverB
422 || (n - coverA
) mod columns
= columns
- 1)
428 let pagey = max
0 (y - vy
) in
429 let pagedispy = if pagey > 0 then 0 else vy
- y in
430 let pagedispx, pagex
=
432 if n = coverA
- 1 || n = state
.pagecount
- coverB
433 then x + (wadj + sw
- w
) / 2
441 let vw = wadj + sw
- pagedispx in
442 let pw = w
- pagex
in
445 let pagevh = min
(h
- pagey) (sh - pagedispy) in
446 if pagevw > 0 && pagevh > 0
457 ; pagedispx = pagedispx
458 ; pagedispy = pagedispy
470 if Array.length
b = 0
472 else List.rev
(fold [] (page_of_y
y))
475 let layoutS (columns
, b) x y sw
sh =
476 let sh = sh - hscrollh () in
477 let wadj = wadjsb () in
478 let rec fold accu n =
479 if n = Array.length
b
482 let pdimno, px, vy
, (_
, pagew
, pageh
, xoff
) = b.(n) in
490 let pagey = max
0 (y - vy
) in
491 let pagedispy = if pagey > 0 then 0 else vy
- y in
492 let pagedispx, pagex
=
506 let pagecolw = pagew
/columns
in
509 then pagedispx + ((wadj + sw
- pagecolw) / 2)
513 let vw = wadj + sw
- pagedispx in
514 let pw = pagew
- pagex
in
517 let pagevw = min
pagevw pagecolw in
518 let pagevh = min
(pageh
- pagey) (sh - pagedispy) in
519 if pagevw > 0 && pagevh > 0
530 ; pagedispx = pagedispx
531 ; pagedispy = pagedispy
532 ; pagecol
= n mod columns
546 let layout x y sw
sh =
547 if nogeomcmds state
.geomcmds
549 match conf
.columns
with
550 | Csingle
b -> layoutN ((1, 0, 0), b) x y sw
sh
551 | Cmulti
c -> layoutN c x y sw
sh
552 | Csplit s
-> layoutS s
x y sw
sh
557 let y = state
.y + incr
in
559 let y = min
y (state
.maxy
- (if conf
.maxhfit
then state
.winh
else 0)) in
564 let tilex = l.pagex
mod conf
.tilew
in
565 let tiley = l.pagey mod conf
.tileh
in
567 let col = l.pagex
/ conf
.tilew
in
568 let row = l.pagey / conf
.tileh
in
570 let xadj = xadjsb () in
571 let rec rowloop row y0 dispy h
=
575 let dh = conf
.tileh
- y0 in
577 let rec colloop col x0 dispx w
=
581 let dw = conf
.tilew
- x0 in
583 let dispx'
= xadj + dispx in
584 f col row dispx' dispy
x0 y0 dw dh;
585 colloop (col+1) 0 (dispx+dw) (w
-dw)
588 colloop col tilex l.pagedispx l.pagevw;
589 rowloop (row+1) 0 (dispy
+dh) (h
-dh)
592 if l.pagevw > 0 && l.pagevh > 0
593 then rowloop row tiley l.pagedispy l.pagevh;
596 let gettileopaque l col row =
598 l.pageno
, state
.gen
, conf
.colorspace
, conf
.angle
, l.pagew
, l.pageh
, col, row
600 try Some
(Hashtbl.find state
.tilemap
key)
601 with Not_found
-> None
604 let puttileopaque l col row gen colorspace angle opaque size elapsed
=
605 let key = l.pageno
, gen
, colorspace
, angle
, l.pagew
, l.pageh
, col, row in
606 Hashtbl.add state
.tilemap
key (opaque
, size
, elapsed
)
609 let filledrect2 x0 y0 x1 y1 x2 y2 x3 y3
=
610 Raw.sets_float state
.vraw ~pos
:0 [| x0; y0; x1; y1; x2
; y2
; x3
; y3
|];
611 GlArray.vertex `two state
.vraw
;
612 GlArray.draw_arrays `triangle_strip ~first
:0 ~count
:4;
615 let filledrect1 x0 y0 x1 y1 = filledrect2 x0 y0 x0 y1 x1 y0 x1 y1;;
617 let filledrect x0 y0 x1 y1 =
618 GlArray.disable `texture_coord
;
619 filledrect1 x0 y0 x1 y1;
620 GlArray.enable `texture_coord
;
623 let linerect x0 y0 x1 y1 =
624 GlArray.disable `texture_coord
;
625 Raw.sets_float state
.vraw ~pos
:0 [| x0; y0; x0; y1; x1; y1; x1; y0 |];
626 GlArray.vertex `two state
.vraw
;
627 GlArray.draw_arrays `line_loop ~first
:0 ~count
:4;
628 GlArray.enable `texture_coord
;
631 let drawtiles l color =
633 let wadj = wadjsb () in
635 let f col row x y tilex tiley w h
=
636 match gettileopaque l col row with
637 | Some
(opaque
, _
, t
) ->
638 let params = x, y, w
, h
, tilex, tiley in
640 then GlTex.env
(`mode `blend
);
641 drawtile
params opaque
;
643 then GlTex.env
(`mode `modulate
);
647 let s = Printf.sprintf
651 let w = measurestr fstate
.fontsize
s in
652 GlDraw.color (0.0, 0.0, 0.0);
653 filledrect (float (x-2))
656 (float (y + fstate
.fontsize
+ 2));
658 drawstring fstate
.fontsize
x (y + fstate
.fontsize
- 1) s;
668 let lw = wadj + state
.winw
- x in
671 let lh = state
.winh
- y in
675 then GlTex.env
(`mode `blend
);
676 begin match state
.checkerstexid
with
678 Gl.enable `texture_2d
;
679 GlTex.bind_texture ~target
:`texture_2d id
;
683 and y1 = float (y+h
) in
685 let tw = float w /. 16.0
686 and th
= float h
/. 16.0 in
687 let tx0 = float tilex /. 16.0
688 and ty0
= float tiley /. 16.0 in
690 and ty1
= ty0
+. th
in
691 Raw.sets_float state
.vraw ~pos
:0
692 [| x0; y0; x0; y1; x1; y0; x1; y1 |];
693 Raw.sets_float state
.traw ~pos
:0
694 [| tx0; ty0
; tx0; ty1
; tx1; ty0
; tx1; ty1
|];
695 GlArray.vertex `two state
.vraw
;
696 GlArray.tex_coord `two state
.traw
;
697 GlArray.draw_arrays `triangle_strip ~first
:0 ~count
:4;
698 Gl.disable `texture_2d
;
701 GlDraw.color (1.0, 1.0, 1.0);
702 filledrect (float x) (float y) (float (x+w)) (float (y+h
));
705 then GlTex.env
(`mode `modulate
);
706 if w > 128 && h
> fstate
.fontsize
+ 10
708 let c = if conf
.invert
then 1.0 else 0.0 in
709 GlDraw.color (c, c, c);
712 then (col*conf
.tilew
, row*conf
.tileh
)
715 drawstring2 fstate
.fontsize
x y "Loading %d [%d,%d]" l.pageno
c r
;
724 let pagevisible layout n = List.exists
(fun l -> l.pageno
= n) layout;;
726 let tilevisible1 l x y =
728 and ax1
= l.pagex
+ l.pagevw
730 and ay1
= l.pagey + l.pagevh in
734 let bx1 = min
(bx0 + conf
.tilew
) l.pagew
735 and by1
= min
(by0
+ conf
.tileh
) l.pageh
in
737 let rx0 = max
ax0 bx0
738 and ry0
= max ay0 by0
739 and rx1
= min ax1
bx1
740 and ry1
= min ay1 by1
in
742 let nonemptyintersection = rx1
> rx0 && ry1
> ry0
in
746 let tilevisible layout n x y =
747 let rec findpageinlayout m
= function
748 | l :: rest
when l.pageno
= n ->
749 tilevisible1 l x y || (
750 match conf
.columns
with
751 | Csplit
(c, _
) when c > m
-> findpageinlayout (m
+1) rest
756 | _
:: rest
-> findpageinlayout 0 rest
759 findpageinlayout 0 layout;
762 let tileready l x y =
763 tilevisible1 l x y &&
764 gettileopaque l (x/conf
.tilew
) (y/conf
.tileh
) != None
767 let tilepage n p
layout =
768 let rec loop = function
772 let f col row _ _ _ _ _ _
=
773 if state
.currently
= Idle
775 match gettileopaque l col row with
778 let x = col*conf
.tilew
779 and y = row*conf
.tileh
in
781 let w = l.pagew
- x in
785 let h = l.pageh
- y in
790 then getpbo
w h conf
.colorspace
793 wcmd "tile %s %d %d %d %d %s"
794 (~
> p
) x y w h (~
> pbo);
797 l, p
, conf
.colorspace
, conf
.angle
,
798 state
.gen
, col, row, conf
.tilew
, conf
.tileh
807 if nogeomcmds state
.geomcmds
811 let preloadlayout x y sw
sh =
812 let y = if y < sh then 0 else y - sh in
813 let x = min
0 (x + sw
) in
821 if state
.currently
!= Idle
826 begin match getopaque l.pageno
with
828 wcmd "page %d %d" l.pageno
l.pagedimno
;
829 state
.currently
<- Loading
(l, state
.gen
);
831 tilepage l.pageno opaque pages
;
836 if nogeomcmds state
.geomcmds
842 if conf
.preload && state
.currently
= Idle
843 then load (preloadlayout state
.x state
.y state
.winw state
.winh
);
846 let layoutready layout =
847 let rec fold all ls
=
850 let seen = ref false in
851 let allvisible = ref true in
852 let foo col row _ _ _ _ _ _
=
854 allvisible := !allvisible &&
855 begin match gettileopaque l col row with
861 fold (!seen && !allvisible) rest
864 let alltilesvisible = fold true layout in
869 let y = bound
y 0 state
.maxy
in
870 let y, layout, proceed
=
871 match conf
.maxwait
with
872 | Some time
when state
.ghyll
== noghyll
->
873 begin match state
.throttle
with
875 let layout = layout state
.x y state
.winw state
.winh
in
876 let ready = layoutready layout in
880 state
.throttle
<- Some
(layout, y, now
());
882 else G.postRedisplay "gotoy showall (None)";
884 | Some
(_
, _
, started
) ->
885 let dt = now
() -. started
in
888 state
.throttle
<- None
;
889 let layout = layout state
.x y state
.winw state
.winh
in
891 G.postRedisplay "maxwait";
898 let layout = layout state
.x y state
.winw state
.winh
in
899 if not
!wtmode || layoutready layout
900 then G.postRedisplay "gotoy ready";
906 state
.layout <- layout;
907 begin match state
.mode
with
910 | Ltexact
(pageno
, linkno
) ->
911 let rec loop = function
913 state
.mode
<- LinkNav
(Ltgendir
0)
914 | l :: _
when l.pageno
= pageno
->
915 begin match getopaque pageno
with
916 | None
-> state
.mode
<- LinkNav
(Ltnotready
(pageno
, 0))
918 let x0, y0, x1, y1 = getlinkrect opaque linkno
in
919 if not
(x0 >= l.pagex
&& x1 <= l.pagex
+ l.pagevw
920 && y0 >= l.pagey && y1 <= l.pagey + l.pagevh)
921 then state
.mode
<- LinkNav
(Ltgendir
0)
923 | _
:: rest
-> loop rest
926 | Ltnotready _
| Ltgendir _
-> ()
932 begin match state
.mode
with
933 | Birdseye
(conf
, leftx
, pageno
, hooverpageno
, anchor
) ->
934 if not
(pagevisible layout pageno
)
936 match state
.layout with
939 state
.mode
<- Birdseye
(
940 conf
, leftx
, l.pageno
, hooverpageno
, anchor
945 | Ltnotready
(_
, dir
)
948 let rec loop = function
951 match getopaque l.pageno
with
952 | None
-> Ltnotready
(l.pageno
, dir
)
957 then LDfirstvisible
(l.pagex
, l.pagey, dir
)
959 if dir
> 0 then LDfirst
else LDlast
965 | Lnotfound
-> loop rest
967 showlinktype (getlink opaque
n);
968 Ltexact
(l.pageno
, n)
972 state
.mode
<- LinkNav
linknav
980 state
.ghyll
<- noghyll
;
983 let mx, my
= state
.mpos
in
988 let conttiling pageno opaque
=
989 tilepage pageno opaque
991 then preloadlayout state
.x state
.y state
.winw state
.winh
995 let gotoy_and_clear_text y =
996 if not conf
.verbose
then state
.text <- E.s;
1000 let getanchory (n, top
, dtop
) =
1001 let y, h = getpageyh
n in
1002 if conf
.presentation
1004 let ips = calcips
h in
1005 y + truncate
(top
*.float h -. dtop
*.float ips) + ips;
1007 y + truncate
(top
*.float h -. dtop
*.float conf
.interpagespace
)
1010 let gotoanchor anchor
=
1011 gotoy (getanchory anchor
);
1015 cbput state
.hists
.nav
(getanchor
());
1019 let anchor = cbgetc state
.hists
.nav dir
in
1023 let gotoghyll1 single
y =
1024 let scroll f n a
b =
1025 (* http://devmaster.net/forums/topic/9796-ease-in-ease-out-algorithm/ *)
1027 let s x = 3.0*.x**2.0 -. 2.0*.x**3.0 in
1029 then s (float f /. float a
)
1032 then 1.0 -. s ((float (f-b) /. float (n-b)))
1038 let ins = float a
*. 0.5
1039 and outs
= float (n-b) *. 0.5 in
1041 ins +. outs
+. float ones
1043 let rec set nab
y sy
=
1044 let (_N
, _A
, _B
), y =
1047 let scl = if y > sy
then 2 else -2 in
1048 let _N, _
, _
= nab
in
1049 (_N,0,_N), y+conf
.scrollstep
*scl
1051 let sum = summa
_N _A _B
in
1052 let dy = float (y - sy
) in
1056 then state
.ghyll
<- noghyll
1059 let s = scroll n _N _A _B
in
1060 let y1 = y1 +. ((s *. dy) /. sum) in
1061 gotoy_and_clear_text (truncate
y1);
1062 state
.ghyll
<- gf (n+1) y1;
1066 | Some
y'
when single
-> set nab
y' state
.y
1067 | Some
y'
-> set (_N/2, 1, 1) y' state
.y
1069 gf 0 (float state
.y)
1072 match conf
.ghyllscroll
with
1073 | Some nab
when not conf
.presentation
->
1074 if state
.ghyll
== noghyll
1075 then set nab
y state
.y
1076 else state
.ghyll
(Some
y)
1078 gotoy_and_clear_text y
1081 let gotoghyll = gotoghyll1 false;;
1083 let gotopage n top
=
1084 let y, h = getpageyh
n in
1085 let y = y + (truncate
(top
*. float h)) in
1089 let gotopage1 n top
=
1090 let y = getpagey
n in
1095 let invalidate s f =
1100 match state
.geomcmds
with
1101 | ps
, [] when emptystr ps
->
1103 state
.geomcmds
<- s, [];
1106 state
.geomcmds
<- ps
, [s, f];
1108 | ps
, (s'
, _
) :: rest
when s'
= s ->
1109 state
.geomcmds
<- ps
, ((s, f) :: rest
);
1112 state
.geomcmds
<- ps
, ((s, f) :: cmds
);
1116 Hashtbl.iter
(fun _ opaque
->
1117 wcmd "freepage %s" (~
> opaque
);
1119 Hashtbl.clear state
.pagemap
;
1123 if not
(Queue.is_empty state
.tilelru
)
1125 Queue.iter
(fun (k
, p
, s) ->
1126 wcmd "freetile %s" (~
> p
);
1127 state
.memused
<- state
.memused
- s;
1128 Hashtbl.remove state
.tilemap k
;
1130 state
.uioh#infochanged Memused
;
1131 Queue.clear state
.tilelru
;
1137 let h = truncate
(float h*.conf
.zoom
) in
1138 let d = conf
.interpagespace
lsl (if conf
.presentation
then 1 else 0) in
1142 let opendoc path password
=
1144 state
.password
<- password
;
1145 state
.gen
<- state
.gen
+ 1;
1146 state
.docinfo
<- [];
1147 state
.outlines
<- [||];
1150 setaalevel conf
.aalevel
;
1152 if emptystr state
.origin
1156 Wsi.settitle
("llpp " ^
(mbtoutf8
(Filename.basename
titlepath)));
1157 wcmd "open %d %d %s\000%s\000" (btod
!wtmode) (btod
!cxack) path password
;
1158 invalidate "reqlayout"
1160 wcmd "reqlayout %d %d %d %s\000"
1161 conf
.angle
(FMTE.to_int conf
.fitmodel
)
1162 (stateh state
.winh
) state
.nameddest
1167 state
.anchor <- getanchor
();
1168 opendoc state
.path state
.password
;
1172 let c = c *. conf
.colorscale
in
1176 let scalecolor2 (r
, g, b) =
1177 (r
*. conf
.colorscale
, g *. conf
.colorscale
, b *. conf
.colorscale
);
1180 let docolumns columns
=
1181 let wadj = wadjsb () in
1184 let a = Array.make state
.pagecount
(-1, -1, -1, (-1, -1, -1, -1)) in
1185 let wadj = wadjsb () in
1186 let rec loop pageno
pdimno pdim
y ph pdims
=
1187 if pageno
= state
.pagecount
1190 let pdimno, ((_
, w, h, xoff
) as pdim
), pdims
=
1192 | ((pageno'
, _
, _
, _
) as pdim
) :: rest
when pageno'
= pageno
->
1193 pdimno+1, pdim
, rest
1197 let x = max
0 (((wadj + state
.winw
- w) / 2) - xoff
) in
1199 (if conf
.presentation
1200 then (if pageno
= 0 then calcips
h else calcips ph
+ calcips
h)
1201 else (if pageno
= 0 then 0 else conf
.interpagespace
)
1204 a.(pageno
) <- (pdimno, x, y, pdim
);
1205 loop (pageno
+1) pdimno pdim
(y + h) h pdims
1207 loop 0 ~
-1 (-1,-1,-1,-1) 0 0 state
.pdims
;
1208 conf
.columns
<- Csingle
a;
1210 | Cmulti
((columns
, coverA
, coverB
), _
) ->
1211 let a = Array.make state
.pagecount
(-1, -1, -1, (-1, -1, -1, -1)) in
1212 let rec loop pageno
pdimno pdim
x y rowh pdims
=
1213 let rec fixrow m
= if m
= pageno
then () else
1214 let (pdimno, x, y, ((_
, _
, h, _
) as pdim
)) = a.(m
) in
1217 let y = y + (rowh
- h) / 2 in
1218 a.(m
) <- (pdimno, x, y, pdim
);
1222 if pageno
= state
.pagecount
1223 then fixrow (((pageno
- 1) / columns
) * columns
)
1225 let pdimno, ((_
, w, h, xoff
) as pdim
), pdims
=
1227 | ((pageno'
, _
, _
, _
) as pdim
) :: rest
when pageno'
= pageno
->
1228 pdimno+1, pdim
, rest
1233 if pageno
= coverA
- 1 || pageno
= state
.pagecount
- coverB
1235 let x = (wadj + state
.winw
- w) / 2 in
1237 if conf
.presentation
then calcips
h else conf
.interpagespace
in
1238 x, y + ips + rowh
, h
1241 if (pageno
- coverA
) mod columns
= 0
1243 let x = max
0 (wadj + state
.winw
- state
.w) / 2 in
1245 if conf
.presentation
1247 let ips = calcips
h in
1248 y + (if pageno
= 0 then 0 else calcips rowh
+ ips)
1250 y + (if pageno
= 0 then 0 else conf
.interpagespace
)
1254 else x, y, max rowh
h
1258 if pageno
> 1 && (pageno
- coverA
) mod columns
= 0
1261 if pageno
= columns
&& conf
.presentation
1263 let ips = calcips rowh
in
1264 for i
= 0 to pred columns
1266 let (pdimno, x, y, pdim
) = a.(i
) in
1267 a.(i
) <- (pdimno, x, y+ips, pdim
)
1273 fixrow (pageno
- columns
);
1278 a.(pageno
) <- (pdimno, x, y, pdim
);
1279 let x = x + w + xoff
*2 + conf
.interpagespace
in
1280 loop (pageno
+1) pdimno pdim
x y rowh' pdims
1282 loop 0 ~
-1 (-1,-1,-1,-1) 0 0 0 state
.pdims
;
1283 conf
.columns
<- Cmulti
((columns
, coverA
, coverB
), a);
1286 let a = Array.make
(state
.pagecount
*c) (-1, -1, -1, (-1, -1, -1, -1)) in
1287 let rec loop pageno
pdimno pdim
y pdims
=
1288 if pageno
= state
.pagecount
1291 let pdimno, ((_
, w, h, _
) as pdim
), pdims
=
1293 | ((pageno'
, _
, _
, _
) as pdim
) :: rest
when pageno'
= pageno
->
1294 pdimno+1, pdim
, rest
1299 let rec loop1 n x y =
1300 if n = c then y else (
1301 a.(pageno
*c + n) <- (pdimno, x, y, pdim
);
1302 loop1 (n+1) (x+cw) (y + h + conf
.interpagespace
)
1305 let y = loop1 0 0 y in
1306 loop (pageno
+1) pdimno pdim
y pdims
1308 loop 0 ~
-1 (-1,-1,-1,-1) 0 state
.pdims
;
1309 conf
.columns
<- Csplit
(c, a);
1313 docolumns conf
.columns
;
1314 state
.maxy
<- calcheight
();
1315 if state
.reprf
== noreprf
1317 match state
.mode
with
1318 | Birdseye
(_
, _
, pageno
, _
, _
) ->
1319 let y, h = getpageyh pageno
in
1320 let top = (state
.winh
- h) / 2 in
1321 gotoy (max
0 (y - top))
1325 let y = getanchory state
.anchor in
1326 let y = min
y (state
.maxy
- state
.winw
- hscrollh ()) in
1331 state
.reprf
<- noreprf
;
1335 let reshape ?
(firsttime
=false) w h =
1336 GlDraw.viewport ~
x:0 ~
y:0 ~
w:w ~
h:h;
1337 if not firsttime
&& nogeomcmds state
.geomcmds
1338 then state
.anchor <- getanchor
();
1341 let w = wadjsb () + (truncate
(float w *. conf
.zoom
)) in
1344 setfontsize fstate
.fontsize
;
1345 GlMat.mode `modelview
;
1346 GlMat.load_identity
();
1348 GlMat.mode `projection
;
1349 GlMat.load_identity
();
1350 GlMat.rotate ~
x:1.0 ~angle
:180.0 ();
1351 GlMat.translate ~
x:~
-.1.0 ~
y:~
-.1.0 ();
1352 GlMat.scale3
(2.0 /. float state
.winw
, 2.0 /. float state
.winh
, 1.0);
1357 else float state
.x /. float state
.w
1359 invalidate "geometry"
1363 then state
.x <- truncate
(relx *. float w);
1365 match conf
.columns
with
1367 | Cmulti
((c, _
, _
), _
) -> (w - (c-1)*conf
.interpagespace
) / c
1368 | Csplit
(c, _
) -> w * c
1370 wcmd "geometry %d %d %d"
1371 w (stateh h) (FMTE.to_int conf
.fitmodel
)
1376 let len = String.length state
.text in
1377 let x0 = xadjsb () in
1380 match state
.mode
with
1381 | Textentry _
| View
| LinkNav _
->
1382 let h, _
, _
= state
.uioh#scrollpw
in
1387 filledrect x (float (state
.winh
- (fstate
.fontsize
+ 4) - hscrollh))
1388 (x+.w) (float (state
.winh
- hscrollh))
1391 let w = float (wadjsb () + state
.winw
- 1) in
1392 if state
.progress
>= 0.0 && state
.progress
< 1.0
1394 GlDraw.color (0.3, 0.3, 0.3);
1395 let w1 = w *. state
.progress
in
1397 GlDraw.color (0.0, 0.0, 0.0);
1398 rect (float x0+.w1) (float x0+.w-.w1)
1401 GlDraw.color (0.0, 0.0, 0.0);
1405 GlDraw.color (1.0, 1.0, 1.0);
1406 drawstring fstate
.fontsize
1407 (if conf
.leftscroll
then x0 + 2 else x0 + if len > 0 then 8 else 2)
1408 (state
.winh
- hscrollh - 5) s;
1411 match state
.mode
with
1412 | Textentry
((prefix
, text, _
, _
, _
, _
), _
) ->
1416 Printf.sprintf
"%s%s_ [%s]" prefix
text state
.text
1418 Printf.sprintf
"%s%s_" prefix
text
1424 | LinkNav _
-> state
.text
1429 if not
(istextentry state
.mode
) && state
.uioh#eformsgs
1431 let s1 = "(press 'e' to review error messasges)" in
1432 if nonemptystr
s then s ^
" " ^
s1 else s1
1442 let len = Queue.length state
.tilelru
in
1444 match state
.throttle
with
1447 then preloadlayout state
.x state
.y state
.winw state
.winh
1449 | Some
(layout, _
, _
) ->
1453 if state
.memused
<= conf
.memlimit
1458 let (k
, p
, s) as lruitem
= Queue.pop state
.tilelru
in
1459 let n, gen
, colorspace
, angle
, pagew
, pageh
, col, row = k
in
1460 let (_
, pw, ph
, _
) = getpagedim
n in
1463 && colorspace
= conf
.colorspace
1464 && angle
= conf
.angle
1468 let x = col*conf
.tilew
1469 and y = row*conf
.tileh
in
1470 tilevisible (Lazy.force_val
layout) n x y
1472 then Queue.push lruitem state
.tilelru
1475 wcmd "freetile %s" (~
> p
);
1476 state
.memused
<- state
.memused
- s;
1477 state
.uioh#infochanged Memused
;
1478 Hashtbl.remove state
.tilemap k
;
1486 let onpagerect pageno
f =
1488 match conf
.columns
with
1489 | Cmulti
(_
, b) -> b
1491 | Csplit
(_
, b) -> b
1493 if pageno
>= 0 && pageno
< Array.length
b
1495 let (_
, _
, _
, (_
, w, h, _
)) = b.(pageno
) in
1499 let gotopagexy1 wtmode pageno
x y =
1500 let _,w1,h1
,leftx
= getpagedim pageno
in
1501 let top = y /. (float h1
) in
1502 let left = x /. (float w1) in
1503 let py, w, h = getpageywh pageno
in
1504 let wh = state
.winh
- hscrollh () in
1505 let x = left *. (float w) in
1506 let x = leftx
+ state
.x + truncate
x in
1507 let wadj = wadjsb () in
1509 if x < 0 || x >= wadj + state
.winw
1513 let pdy = truncate
(top *. float h) in
1514 let y'
= py + pdy in
1515 let dy = y'
- state
.y in
1517 if x != state
.x || not
(dy > 0 && dy < wh)
1519 if conf
.presentation
1521 if abs
(py - y'
) > wh
1528 if state
.x != sx || state
.y != sy
1533 let ww = wadj + state
.winw
in
1535 and qy
= pdy / wh in
1537 and y = py + qy
* wh in
1538 let x = if -x + ww > w1 then -(w1-ww) else x
1539 and y'
= if y + wh > state
.maxy
then state
.maxy
- wh else y in
1541 if conf
.presentation
1543 if abs
(py - y'
) > wh
1553 gotoy_and_clear_text y;
1555 else gotoy_and_clear_text state
.y;
1558 let gotopagexy wtmode pageno
x y =
1559 match state
.mode
with
1560 | Birdseye
_ -> gotopage pageno
0.0
1563 | LinkNav
_ -> gotopagexy1 wtmode pageno
x y
1566 let getpassword () =
1567 let passcmd = getenvwithdef
"LLPP_ASKPASS" conf
.passcmd in
1572 impmsg "error getting password: %s" s;
1573 dolog
"%s" s) passcmd;
1576 let pgoto opaque pageno
x y =
1577 let pdimno = getpdimno pageno
in
1578 let x, y = project opaque pageno
pdimno x y in
1579 gotopagexy false pageno
x y;
1583 (* dolog "%S" cmds; *)
1584 let cl = splitatspace cmds
in
1586 try Scanf.sscanf
s fmt
f
1588 dolog
"error processing '%S': %s" cmds
@@ exntos exn
;
1591 let addoutline outline
=
1592 match state
.currently
with
1593 | Outlining outlines
->
1594 state
.currently
<- Outlining
(outline
:: outlines
)
1595 | Idle
-> state
.currently
<- Outlining
[outline
]
1598 dolog
"invalid outlining state";
1599 logcurrently state
.currently
1603 state
.uioh#infochanged Pdim
;
1606 | "clearrects" :: [] ->
1607 state
.rects
<- state
.rects1
;
1608 G.postRedisplay "clearrects";
1610 | "continue" :: args
:: [] ->
1611 let n = scan args
"%u" (fun n -> n) in
1612 state
.pagecount
<- n;
1613 begin match state
.currently
with
1615 state
.currently
<- Idle
;
1616 state
.outlines
<- Array.of_list
(List.rev
l)
1622 let cur, cmds
= state
.geomcmds
in
1624 then failwith
"umpossible";
1626 begin match List.rev cmds
with
1628 state
.geomcmds
<- E.s, [];
1629 state
.throttle
<- None
;
1633 state
.geomcmds
<- s, List.rev rest
;
1635 if conf
.maxwait
= None
&& not
!wtmode
1636 then G.postRedisplay "continue";
1638 | "msg" :: args
:: [] ->
1641 | "vmsg" :: args
:: [] ->
1643 then showtext ' ' args
1645 | "emsg" :: args
:: [] ->
1646 Buffer.add_string state
.errmsgs args
;
1647 state
.newerrmsgs
<- true;
1648 G.postRedisplay "error message"
1650 | "progress" :: args
:: [] ->
1651 let progress, text =
1654 f, String.sub args pos
(String.length args
- pos
))
1657 state
.progress <- progress;
1658 G.postRedisplay "progress"
1660 | "firstmatch" :: args
:: [] ->
1661 let pageno, c, x0, y0, x1, y1, x2
, y2
, x3
, y3
=
1662 scan args
"%u %d %f %f %f %f %f %f %f %f"
1663 (fun p
c x0 y0 x1 y1 x2 y2 x3 y3
->
1664 (p
, c, x0, y0, x1, y1, x2
, y2
, x3
, y3
))
1666 let xoff = float (xadjsb ()) in
1670 and x3
= x3
+. xoff in
1671 let y = (getpagey
pageno) + truncate
y0 in
1673 then state
.x <- truncate
(xoff -. x0) + state
.winw
/2;
1676 let color = (0.0, 0.0, 1.0 /. float c, 0.5) in
1677 state
.rects1
<- [pageno, color, (x0, y0, x1, y1, x2
, y2
, x3
, y3
)]
1679 | "match" :: args
:: [] ->
1680 let pageno, c, x0, y0, x1, y1, x2
, y2
, x3
, y3
=
1681 scan args
"%u %d %f %f %f %f %f %f %f %f"
1682 (fun p
c x0 y0 x1 y1 x2 y2 x3 y3
->
1683 (p
, c, x0, y0, x1, y1, x2
, y2
, x3
, y3
))
1685 let xoff = float (xadjsb ()) in
1689 and x3
= x3
+. xoff in
1690 let color = (0.0, 0.0, 1.0 /. float c, 0.5) in
1692 (pageno, color, (x0, y0, x1, y1, x2
, y2
, x3
, y3
)) :: state
.rects1
1694 | "page" :: args
:: [] ->
1695 let pageopaques, t
= scan args
"%s %f" (fun p t
-> p
, t
) in
1696 let pageopaque = ~
< pageopaques in
1697 begin match state
.currently
with
1698 | Loading
(l, gen
) ->
1699 vlog "page %d took %f sec" l.pageno t
;
1700 Hashtbl.replace state
.pagemap
(l.pageno, gen
) pageopaque;
1701 begin match state
.throttle
with
1703 let preloadedpages =
1705 then preloadlayout state
.x state
.y state
.winw state
.winh
1710 List.fold_left
(fun s l -> IntSet.add
l.pageno s)
1711 IntSet.empty
preloadedpages
1714 Hashtbl.fold (fun ((pageno, _) as key) opaque
accu ->
1715 if not
(IntSet.mem
pageno set)
1717 wcmd "freepage %s" (~
> opaque
);
1723 List.iter
(Hashtbl.remove state
.pagemap
) evictedpages;
1726 state
.currently
<- Idle
;
1729 tilepage l.pageno pageopaque state
.layout;
1731 load preloadedpages;
1732 let visible = pagevisible state
.layout l.pageno in
1735 match state
.mode
with
1736 | LinkNav
(Ltnotready
(pageno, dir
)) ->
1737 if pageno = l.pageno
1742 then LDfirstvisible
(l.pagex
, l.pagey, dir
)
1744 if dir
> 0 then LDfirst
else LDlast
1747 findlink
pageopaque ld
1752 showlinktype (getlink
pageopaque n);
1753 state
.mode
<- LinkNav
(Ltexact
(l.pageno, n))
1755 | LinkNav
(Ltgendir
_)
1756 | LinkNav
(Ltexact
_)
1762 if visible && layoutready state
.layout
1764 G.postRedisplay "page";
1768 | Some
(layout, _, _) ->
1769 state
.currently
<- Idle
;
1770 tilepage l.pageno pageopaque layout;
1777 dolog
"Inconsistent loading state";
1778 logcurrently state
.currently
;
1782 | "tile" :: args
:: [] ->
1783 let (x, y, opaques
, size
, t
) =
1784 scan args
"%u %u %s %u %f"
1785 (fun x y p size t
-> (x, y, p
, size
, t
))
1787 let opaque = ~
< opaques
in
1788 begin match state
.currently
with
1789 | Tiling
(l, pageopaque, cs
, angle
, gen
, col, row, tilew
, tileh
) ->
1790 vlog "tile %d [%d,%d] took %f sec" l.pageno col row t
;
1793 if tilew
!= conf
.tilew
|| tileh
!= conf
.tileh
1795 wcmd "freetile %s" (~
> opaque);
1796 state
.currently
<- Idle
;
1800 puttileopaque l col row gen cs angle
opaque size t
;
1801 state
.memused
<- state
.memused
+ size
;
1802 state
.uioh#infochanged Memused
;
1804 Queue.push
((l.pageno, gen
, cs
, angle
, l.pagew
, l.pageh
, col, row),
1805 opaque, size
) state
.tilelru
;
1808 match state
.throttle
with
1809 | None
-> state
.layout
1810 | Some
(layout, _, _) -> layout
1813 state
.currently
<- Idle
;
1815 && conf
.colorspace
= cs
1816 && conf
.angle
= angle
1817 && tilevisible layout l.pageno x y
1818 then conttiling l.pageno pageopaque;
1820 begin match state
.throttle
with
1822 preload state
.layout;
1824 && conf
.colorspace
= cs
1825 && conf
.angle
= angle
1826 && tilevisible state
.layout l.pageno x y
1827 && (not
!wtmode || layoutready state
.layout)
1828 then G.postRedisplay "tile nothrottle";
1830 | Some
(layout, y, _) ->
1831 let ready = layoutready layout in
1835 state
.layout <- layout;
1836 state
.throttle
<- None
;
1837 G.postRedisplay "throttle";
1846 dolog
"Inconsistent tiling state";
1847 logcurrently state
.currently
;
1851 | "pdim" :: args
:: [] ->
1852 let (n, w, h, _) as pdim
=
1853 scan args
"%u %u %u %u" (fun n w h x -> n, w, h, x)
1856 match conf
.fitmodel
with
1858 | FitPage
| FitProportional
->
1859 match conf
.columns
with
1860 | Csplit
_ -> (n, w, h, 0)
1861 | Csingle
_ | Cmulti
_ -> pdim
1863 state
.uioh#infochanged Pdim
;
1864 state
.pdims
<- pdim :: state
.pdims
1866 | "o" :: args
:: [] ->
1867 let (l, n, t
, h, pos
) =
1868 scan args
"%u %u %d %u %n"
1869 (fun l n t
h pos
-> l, n, t
, h, pos
)
1871 let s = String.sub args pos
(String.length args
- pos
) in
1872 addoutline (s, l, Oanchor
(n, float t
/. float h, 0.0))
1874 | "ou" :: args
:: [] ->
1875 let (l, len, pos
) = scan args
"%u %u %n" (fun l len pos
-> l, len, pos
) in
1876 let s = String.sub args pos
len in
1877 let pos2 = pos
+ len + 1 in
1878 let uri = String.sub args
pos2 (String.length args
- pos2) in
1879 addoutline (s, l, Ouri
uri)
1881 | "on" :: args
:: [] ->
1882 let (l, pos
) = scan args
"%u %n" (fun l pos
-> l, pos
) in
1883 let s = String.sub args pos
(String.length args
- pos
) in
1884 addoutline (s, l, Onone
)
1886 | "a" :: args
:: [] ->
1888 scan args
"%u %d %d" (fun n l t
-> n, l, t
)
1890 state
.reprf
<- (fun () -> gotopagexy !wtmode n (float l) (float t
))
1892 | "info" :: args
:: [] ->
1893 let pos = nindex args '
\t'
in
1894 if pos >= 0 && String.sub args
0 pos = "Title"
1896 let s = String.sub args
(pos+1) @@ String.length args
- pos - 1 in
1900 state
.docinfo
<- (1, args
) :: state
.docinfo
1902 | "infoend" :: [] ->
1903 state
.uioh#infochanged Docinfo
;
1904 state
.docinfo
<- List.rev state
.docinfo
1908 then Wsi.settitle
"Wrong password";
1909 let password = getpassword () in
1910 if emptystr
password
1911 then error
"document is password protected"
1912 else opendoc state
.path
password
1914 error
"unknown cmd `%S'" cmds
1919 let action = function
1920 | HCprev
-> cbget cb ~
-1
1921 | HCnext
-> cbget cb
1
1922 | HCfirst
-> cbget cb ~
-(cb
.rc)
1923 | HClast
-> cbget cb
(cb
.len - 1 - cb
.rc)
1924 and cancel
() = cb
.rc <- rc
1928 let search pattern forward
=
1929 match conf
.columns
with
1930 | Csplit
_ -> impmsg "searching does not work properly in split columns mode"
1933 if nonemptystr pattern
1936 match state
.layout with
1939 l.pageno, (l.pagey + if forward
then 0 else 0*l.pagevh)
1941 wcmd "search %d %d %d %d,%s\000"
1942 (btod conf
.icase
) pn py (btod forward
) pattern
;
1945 let intentry text key =
1947 if key >= 32 && key < 127
1953 let text = addchar
text c in
1957 state
.text <- Printf.sprintf
"invalid char (%d, `%c')" key c;
1965 let l = String.length
s in
1966 let rec loop pos n = if pos = l then n else
1967 let m = Char.code
s.[pos] - (if pos = 0 && l > 1 then 96 else 97) in
1968 loop (pos+1) (n*26 + m)
1971 let rec loop n = function
1974 match getopaque l.pageno with
1975 | None
-> loop n rest
1977 let m = getlinkcount
opaque in
1980 let under = getlink
opaque n in
1983 else loop (n-m) rest
1985 loop n state
.layout;
1989 let linknentry text key =
1991 if key >= 32 && key < 127
1997 let text = addchar
text c in
1998 linknact (fun under -> state
.text <- undertext ~nopath
:true under) text;
2002 state
.text <- Printf.sprintf
"invalid char (%d, `%c')" key c;
2006 let textentry text key =
2007 if key land 0xff00 = 0xff00
2009 else TEcont
(text ^ toutf8
key)
2012 let reqlayout angle fitmodel
=
2013 match state
.throttle
with
2015 if nogeomcmds state
.geomcmds
2016 then state
.anchor <- getanchor
();
2017 conf
.angle
<- angle
mod 360;
2020 match state
.mode
with
2021 | LinkNav
_ -> state
.mode
<- View
2026 conf
.fitmodel
<- fitmodel
;
2027 invalidate "reqlayout"
2029 wcmd "reqlayout %d %d %d"
2030 conf
.angle
(FMTE.to_int conf
.fitmodel
) (stateh state
.winh
)
2035 let settrim trimmargins trimfuzz
=
2036 if nogeomcmds state
.geomcmds
2037 then state
.anchor <- getanchor
();
2038 conf
.trimmargins
<- trimmargins
;
2039 conf
.trimfuzz
<- trimfuzz
;
2040 let x0, y0, x1, y1 = trimfuzz
in
2041 invalidate "settrim"
2043 wcmd "settrim %d %d %d %d %d" (btod conf
.trimmargins
) x0 y0 x1 y1);
2048 match state
.throttle
with
2050 let zoom = max
0.0001 zoom in
2051 if zoom <> conf
.zoom
2053 state
.prevzoom
<- (conf
.zoom, state
.x);
2055 reshape state
.winw state
.winh
;
2056 state
.text <- Printf.sprintf
"zoom is now %-5.2f" (zoom *. 100.0);
2059 | Some
(layout, y, started
) ->
2061 match conf
.maxwait
with
2065 let dt = now
() -. started
in
2073 let setcolumns mode columns coverA coverB
=
2074 state
.prevcolumns
<- Some
(conf
.columns
, conf
.zoom);
2078 then impmsg "split mode doesn't work in bird's eye"
2080 conf
.columns
<- Csplit
(-columns
, E.a);
2088 conf
.columns
<- Csingle
E.a;
2093 conf
.columns
<- Cmulti
((columns
, coverA
, coverB
), E.a);
2097 reshape state
.winw state
.winh
;
2100 let resetmstate () =
2101 state
.mstate
<- Mnone
;
2102 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
2105 let enterbirdseye () =
2106 let zoom = float conf
.thumbw
/. float state
.winw
in
2107 let birdseyepageno =
2108 let cy = state
.winh
/ 2 in
2112 let rec fold best
= function
2115 let d = cy - (l.pagedispy + l.pagevh/2)
2116 and dbest
= cy - (best
.pagedispy + best
.pagevh/2) in
2117 if abs
d < abs dbest
2124 state
.mode
<- Birdseye
(
2125 { conf
with zoom = conf
.zoom }, state
.x, birdseyepageno, -1, getanchor
()
2129 conf
.presentation
<- false;
2130 conf
.interpagespace
<- 10;
2131 conf
.hlinks
<- false;
2132 conf
.fitmodel
<- FitPage
;
2134 conf
.maxwait
<- None
;
2136 match conf
.beyecolumns
with
2139 Cmulti
((c, 0, 0), E.a)
2140 | None
-> Csingle
E.a
2144 state
.text <- Printf.sprintf
"birds eye mode on (zoom %3.1f%%)"
2149 reshape state
.winw state
.winh
;
2152 let leavebirdseye (c, leftx
, pageno, _, anchor) goback
=
2154 conf
.zoom <- c.zoom;
2155 conf
.presentation
<- c.presentation
;
2156 conf
.interpagespace
<- c.interpagespace
;
2157 conf
.maxwait
<- c.maxwait
;
2158 conf
.hlinks
<- c.hlinks
;
2159 conf
.fitmodel
<- c.fitmodel
;
2160 conf
.beyecolumns
<- (
2161 match conf
.columns
with
2162 | Cmulti
((c, _, _), _) -> Some
c
2164 | Csplit
_ -> failwith
"leaving bird's eye split mode"
2167 match c.columns
with
2168 | Cmulti
(c, _) -> Cmulti
(c, E.a)
2169 | Csingle
_ -> Csingle
E.a
2170 | Csplit
(c, _) -> Csplit
(c, E.a)
2174 state
.text <- Printf.sprintf
"birds eye mode off (zoom %3.1f%%)"
2177 reshape state
.winw state
.winh
;
2178 state
.anchor <- if goback
then anchor else (pageno, 0.0, 1.0);
2182 let togglebirdseye () =
2183 match state
.mode
with
2184 | Birdseye vals
-> leavebirdseye vals
true
2185 | View
-> enterbirdseye ()
2190 let upbirdseye incr
(conf
, leftx
, pageno, hooverpageno
, anchor) =
2191 let pageno = max
0 (pageno - incr
) in
2192 let rec loop = function
2193 | [] -> gotopage1 pageno 0
2194 | l :: _ when l.pageno = pageno ->
2195 if l.pagedispy >= 0 && l.pagey = 0
2196 then G.postRedisplay "upbirdseye"
2197 else gotopage1 pageno 0
2198 | _ :: rest
-> loop rest
2202 state
.mode
<- Birdseye
(conf
, leftx
, pageno, hooverpageno
, anchor)
2205 let downbirdseye incr
(conf
, leftx
, pageno, hooverpageno
, anchor) =
2206 let pageno = min
(state
.pagecount
- 1) (pageno + incr
) in
2207 state
.mode
<- Birdseye
(conf
, leftx
, pageno, hooverpageno
, anchor);
2208 let rec loop = function
2210 let y, h = getpageyh
pageno in
2211 let dy = (y - state
.y) - (state
.winh
- h - conf
.interpagespace
) in
2213 | l :: _ when l.pageno = pageno ->
2214 if l.pagevh != l.pageh
2215 then gotoy (clamp (l.pageh
- l.pagevh + conf
.interpagespace
))
2216 else G.postRedisplay "downbirdseye"
2217 | _ :: rest
-> loop rest
2223 let optentry mode
_ key =
2224 let btos b = if b then "on" else "off" in
2225 if key >= 32 && key < 127
2227 let c = Char.chr
key in
2231 try conf
.scrollstep
<- int_of_string
s with exc
->
2232 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exc
2234 TEswitch
("scroll step: ", E.s, None
, intentry, ondone, true)
2239 conf
.autoscrollstep
<- boundastep state
.winh
(int_of_string
s);
2240 if state
.autoscroll
<> None
2241 then state
.autoscroll
<- Some conf
.autoscrollstep
2243 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exc
2245 TEswitch
("auto scroll step: ", E.s, None
, intentry, ondone, true)
2250 let n, a, b = multicolumns_of_string
s in
2251 setcolumns mode
n a b;
2253 state
.text <- Printf.sprintf
"bad columns `%s': %s" s @@ exntos exc
2255 TEswitch
("columns: ", E.s, None
, textentry, ondone, true)
2260 let zoom = float (int_of_string
s) /. 100.0 in
2263 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exc
2265 TEswitch
("zoom: ", E.s, None
, intentry, ondone, true)
2270 conf
.thumbw
<- bound
(int_of_string
s) 2 4096;
2272 Printf.sprintf
"thumbnail width is set to %d" conf
.thumbw
;
2273 begin match mode
with
2275 leavebirdseye beye
false;
2282 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exc
2284 TEswitch
("thumbnail width: ", E.s, None
, intentry, ondone, true)
2289 Some
(int_of_string
s)
2292 Printf.sprintf
"bad integer `%s': %s" s @@ exntos exc
;
2295 | Some angle
-> reqlayout angle conf
.fitmodel
2298 TEswitch
("rotation: ", E.s, None
, intentry, ondone, true)
2301 conf
.icase
<- not conf
.icase
;
2302 TEdone
("case insensitive search " ^
(btos conf
.icase
))
2305 conf
.preload <- not conf
.preload;
2307 TEdone
("preload " ^
(btos conf
.preload))
2310 conf
.verbose
<- not conf
.verbose
;
2311 TEdone
("verbose " ^
(btos conf
.verbose
))
2314 conf
.debug
<- not conf
.debug
;
2315 TEdone
("debug " ^
(btos conf
.debug
))
2318 conf
.maxhfit
<- not conf
.maxhfit
;
2319 state
.maxy
<- calcheight
();
2320 TEdone
("maxhfit " ^
(btos conf
.maxhfit
))
2323 conf
.crophack
<- not conf
.crophack
;
2324 TEdone
("crophack " ^
btos conf
.crophack
)
2328 match conf
.maxwait
with
2330 conf
.maxwait
<- Some infinity
;
2331 "always wait for page to complete"
2333 conf
.maxwait
<- None
;
2334 "show placeholder if page is not ready"
2339 conf
.underinfo
<- not conf
.underinfo
;
2340 TEdone
("underinfo " ^
btos conf
.underinfo
)
2343 conf
.savebmarks
<- not conf
.savebmarks
;
2344 TEdone
("persistent bookmarks " ^
btos conf
.savebmarks
)
2350 match state
.layout with
2355 conf
.interpagespace
<- int_of_string
s;
2356 docolumns conf
.columns
;
2357 state
.maxy
<- calcheight
();
2358 let y = getpagey
pageno in
2361 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exc
2363 TEswitch
("vertical margin: ", E.s, None
, intentry, ondone, true)
2367 match conf
.fitmodel
with
2368 | FitProportional
-> FitWidth
2369 | FitWidth
| FitPage
-> FitProportional
2371 reqlayout conf
.angle
fm;
2372 TEdone
("proportional display " ^
btos (fm == FitProportional
))
2375 settrim (not conf
.trimmargins
) conf
.trimfuzz
;
2376 TEdone
("trim margins " ^
btos conf
.trimmargins
)
2379 conf
.invert
<- not conf
.invert
;
2380 TEdone
("invert colors " ^
btos conf
.invert
)
2384 cbput state
.hists
.sel
s;
2387 TEswitch
("selection command: ", E.s, Some
(onhist state
.hists
.sel
),
2388 textentry, ondone, true)
2392 then conf
.pax
<- Some
(ref (0.0, 0, 0))
2393 else conf
.pax
<- None
;
2394 TEdone
("PAX " ^
btos (conf
.pax
!= None
))
2397 state
.text <- Printf.sprintf
"bad option %d `%c'" key c;
2403 class type lvsource
= object
2404 method getitemcount
: int
2405 method getitem
: int -> (string * int)
2406 method hasaction
: int -> bool
2414 method getactive
: int
2415 method getfirst
: int
2417 method getminfo
: (int * int) array
2420 class virtual lvsourcebase
= object
2421 val mutable m_active
= 0
2422 val mutable m_first
= 0
2423 val mutable m_pan
= 0
2424 method getactive
= m_active
2425 method getfirst
= m_first
2426 method getpan
= m_pan
2427 method getminfo
: (int * int) array
= E.a
2430 let textentrykeyboard
2431 key _mask
((c, text, opthist
, onkey
, ondone, cancelonempty
), onleave
) =
2434 if key >= 0xffb0 && key <= 0xffb9
2435 then key - 0xffb0 + 48 else key
2438 state
.mode
<- Textentry
(te
, onleave
);
2440 G.postRedisplay "textentrykeyboard enttext";
2442 let histaction cmd
=
2445 | Some
(action, _) ->
2446 state
.mode
<- Textentry
(
2447 (c, action cmd
, opthist
, onkey
, ondone, cancelonempty
), onleave
2449 G.postRedisplay "textentry histaction"
2453 if emptystr
text && cancelonempty
2456 G.postRedisplay "textentrykeyboard after cancel";
2459 let s = withoutlastutf8
text in
2460 enttext (c, s, opthist
, onkey
, ondone, cancelonempty
)
2462 | @enter
| @kpenter
->
2465 G.postRedisplay "textentrykeyboard after confirm"
2467 | @up
| @kpup
-> histaction HCprev
2468 | @down
| @kpdown
-> histaction HCnext
2469 | @home
| @kphome
-> histaction HCfirst
2470 | @jend
| @kpend
-> histaction HClast
2475 begin match opthist
with
2477 | Some
(_, onhistcancel
) -> onhistcancel
()
2481 G.postRedisplay "textentrykeyboard after cancel2"
2484 enttext (c, E.s, opthist
, onkey
, ondone, cancelonempty
)
2487 | @delete
| @kpdelete
-> ()
2490 && key land 0xff00 != 0xff00 (* keyboard *)
2491 && key land 0xfe00 != 0xfe00 (* xkb *)
2492 && key land 0xfd00 != 0xfd00 (* 3270 *)
2494 begin match onkey
text key with
2498 G.postRedisplay "textentrykeyboard after confirm2";
2501 enttext (c, text, opthist
, onkey
, ondone, cancelonempty
);
2505 G.postRedisplay "textentrykeyboard after cancel3"
2508 state
.mode
<- Textentry
(te
, onleave
);
2509 G.postRedisplay "textentrykeyboard switch";
2513 vlog "unhandled key %s" (Wsi.keyname
key)
2516 let firstof first active
=
2517 if first
> active
|| abs
(first
- active
) > fstate
.maxrows
- 1
2518 then max
0 (active
- (fstate
.maxrows
/2))
2522 let calcfirst first active
=
2525 let rows = active
- first
in
2526 if rows > fstate
.maxrows
then active
- fstate
.maxrows
else first
2530 let scrollph y maxy
=
2531 let sh = float (maxy
+ state
.winh
) /. float state
.winh
in
2532 let sh = float state
.winh
/. sh in
2533 let sh = max
sh (float conf
.scrollh
) in
2535 let percent = float y /. float maxy
in
2536 let position = (float state
.winh
-. sh) *. percent in
2539 if position +. sh > float state
.winh
2540 then float state
.winh
-. sh
2546 let adderrmsg src msg
=
2547 Buffer.add_string state
.errmsgs msg
;
2548 state
.newerrmsgs
<- true;
2552 let adderrfmt src fmt
=
2553 Format.ksprintf
(fun s -> adderrmsg src
s) fmt
;
2556 let coe s = (s :> uioh
);;
2558 class listview ~zebra ~helpmode ~
(source
:lvsource
) ~trusted ~modehash
=
2560 val m_pan
= source#getpan
2561 val m_first
= source#getfirst
2562 val m_active
= source#getactive
2564 val m_prev_uioh
= state
.uioh
2566 method private elemunder
y =
2570 let n = y / (fstate
.fontsize
+1) in
2571 if m_first
+ n < source#getitemcount
2573 if source#hasaction
(m_first
+ n)
2574 then Some
(m_first
+ n)
2581 GlFunc.blend_func ~src
:`src_alpha ~dst
:`one_minus_src_alpha
;
2582 GlDraw.color (0., 0., 0.) ~alpha
:0.85;
2583 filledrect 0. 0. (float state
.winw
) (float state
.winh
);
2584 GlDraw.color (1., 1., 1.);
2585 Gl.enable `texture_2d
;
2586 let fs = fstate
.fontsize
in
2588 let hw = (wadjsb () + xadjsb () + state
.winw
)/3 in
2589 let ww = fstate
.wwidth
in
2590 let tabw = 17.0*.ww in
2591 let itemcount = source#getitemcount
in
2592 let minfo = source#getminfo
in
2595 then float (xadjsb ()), float (state
.winw
- 1)
2596 else 0.0, float (state
.winw
- conf
.scrollbw
- 1)
2598 let xadj = xadjsb () in
2600 if (row - m_first
) > fstate
.maxrows
2603 if row >= 0 && row < itemcount
2605 let (s, level
) = source#getitem
row in
2606 let y = (row - m_first
) * nfs in
2608 (if conf
.leftscroll
then float xadj else 5.0)
2609 +. (float (level
+ m_pan
)) *. ww in
2612 (let c = if row land 1 = 0 then 1.0 else 0.92 in (c,c,c));
2616 Gl.disable `texture_2d
;
2617 let alpha = if source#hasaction
row then 0.9 else 0.3 in
2618 GlDraw.color (1., 1., 1.) ~
alpha;
2619 linerect (x0 +. 1.) (float (y + 1)) (x1) (float (y + fs + 3));
2620 Gl.enable `texture_2d
;
2623 if zebra
&& row land 1 = 1
2627 GlDraw.color (c,c,c);
2628 let drawtabularstring s =
2630 let x'
= truncate
(x0 +. x) in
2631 let pos = nindex
s '
\000'
in
2633 then drawstring1 fs x'
(y+nfs) s
2635 let s1 = String.sub
s 0 pos
2636 and s2
= String.sub
s (pos+1) (String.length
s - pos - 1) in
2641 let s'
= withoutlastutf8
s in
2642 let s = s' ^
"@Uellipsis" in
2643 let w = measurestr
fs s in
2644 if float x'
+. w +. ww < float (hw + x'
)
2649 if float x'
+. ww +. measurestr
fs s1 > float (hw + x'
)
2653 ignore
(drawstring1 fs x'
(y+nfs) s1);
2654 drawstring1 fs (hw + x'
) (y+nfs) s2
2658 let x = if helpmode
&& row > 0 then x +. ww else x in
2659 let tabpos = nindex
s '
\t'
in
2662 let len = String.length
s - tabpos - 1 in
2663 let s1 = String.sub
s 0 tabpos
2664 and s2
= String.sub
s (tabpos + 1) len in
2665 let nx = drawstr x s1 in
2667 let x = x +. (max
tabw sw) in
2670 let len = String.length
s - 2 in
2671 if len > 0 && s.[0] = '
\xc2'
&& s.[1] = '
\xb7'
2673 let s = String.sub
s 2 len in
2674 let x = if not helpmode
then x +. ww else x in
2675 GlDraw.color (1.2, 1.2, 1.2);
2676 let vinc = drawstring1 (fs+fs/4)
2677 (truncate
(x -. ww)) (y+nfs) s in
2678 GlDraw.color (1., 1., 1.);
2679 vinc +. (float fs *. 0.8)
2685 ignore
(drawtabularstring s);
2691 GlDraw.color (1.0, 1.0, 1.0) ~
alpha:0.5;
2692 let xadj = float (xadjsb () + 5) in
2694 if (row - m_first
) > fstate
.maxrows
2697 if row >= 0 && row < itemcount
2699 let (s, level
) = source#getitem
row in
2700 let pos0 = nindex
s '
\000'
in
2701 let y = (row - m_first
) * nfs in
2702 let x = float (level
+ m_pan
) *. ww in
2703 let (first
, last
) = minfo.(row) in
2705 if pos0 > 0 && first
> pos0
2706 then String.sub
s (pos0+1) (first
-pos0-1)
2707 else String.sub
s 0 first
2709 let suffix = String.sub
s first
(last
- first
) in
2710 let w1 = measurestr fstate
.fontsize
prefix in
2711 let w2 = measurestr fstate
.fontsize
suffix in
2712 let x = x +. if conf
.leftscroll
then xadj else 5.0 in
2713 let x = if pos0 > 0 && first
> pos0 then x +. float hw else x in
2715 and y0 = float (y+2) in
2717 and y1 = float (y+fs+3) in
2718 filledrect x0 y0 x1 y1;
2723 Gl.disable `texture_2d
;
2724 if Array.length
minfo > 0 then loop m_first
;
2727 method updownlevel incr
=
2728 let len = source#getitemcount
in
2730 if m_active
>= 0 && m_active
< len
2731 then snd
(source#getitem m_active
)
2735 if i
= len then i
-1 else if i
= -1 then 0 else
2736 let _, l = source#getitem i
in
2737 if l != curlevel then i
else flow (i
+incr
)
2739 let active = flow m_active
in
2740 let first = calcfirst m_first
active in
2741 G.postRedisplay "outline updownlevel";
2742 {< m_active
= active; m_first
= first >}
2744 method private key1
key mask
=
2745 let set1 active first qsearch
=
2746 coe {< m_active
= active; m_first
= first; m_qsearch
= qsearch
>}
2748 let search active pattern incr
=
2749 let active = if active = -1 then m_first
else active in
2752 if n >= 0 && n < source#getitemcount
2754 let s, _ = source#getitem
n in
2755 match Str.search_forward re
s 0 with
2756 | (exception Not_found
) -> loop (n + incr
)
2763 let qpat = Str.quote pattern
in
2764 match Str.regexp_case_fold
qpat with
2767 adderrfmt "listview key1" "regexp_case_fold for `%S' failed: %S\n"
2768 qpat @@ Printexc.to_string exn
;
2771 let itemcount = source#getitemcount
in
2772 let find start incr
=
2774 if i
= -1 || i
= itemcount
2777 if source#hasaction i
2779 else find (i
+ incr
)
2784 let set active first =
2785 let first = bound
first 0 (itemcount - fstate
.maxrows
) in
2787 coe {< m_active
= active; m_first
= first; m_qsearch
= E.s >}
2790 let isvisible first n = n >= first && n - first <= fstate
.maxrows
in
2792 let incr1 = if incr
> 0 then 1 else -1 in
2793 if isvisible m_first m_active
2796 let next = m_active
+ incr
in
2798 if next < 0 || next >= itemcount
2800 else find next incr1
2802 if abs
(m_active
- next) > fstate
.maxrows
2808 let first = m_first
+ incr
in
2809 let first = bound
first 0 (itemcount - fstate
.maxrows
) in
2811 let next = m_active
+ incr
in
2812 let next = bound
next 0 (itemcount - 1) in
2819 if isvisible first next
2826 let first = min
next m_first
in
2828 if abs
(next - first) > fstate
.maxrows
2834 let first = m_first
+ incr
in
2835 let first = bound
first 0 (itemcount - 1) in
2837 let next = m_active
+ incr
in
2838 let next = bound
next 0 (itemcount - 1) in
2839 let next = find next incr1 in
2841 if next = -1 || abs
(m_active
- first) > fstate
.maxrows
2843 let active = if m_active
= -1 then next else m_active
in
2848 if isvisible first active
2854 G.postRedisplay "listview navigate";
2858 | (@r
|@s) when Wsi.withctrl mask
->
2859 let incr = if key = @r
then -1 else 1 in
2861 match search (m_active
+ incr) m_qsearch
incr with
2863 state
.text <- m_qsearch ^
" [not found]";
2866 state
.text <- m_qsearch
;
2867 active, firstof m_first
active
2869 G.postRedisplay "listview ctrl-r/s";
2870 set1 active first m_qsearch
;
2872 | @insert
when Wsi.withctrl mask
->
2873 if m_active
>= 0 && m_active
< source#getitemcount
2875 let s, _ = source#getitem m_active
in
2881 if emptystr m_qsearch
2884 let qsearch = withoutlastutf8 m_qsearch
in
2888 G.postRedisplay "listview empty qsearch";
2889 set1 m_active m_first
E.s;
2893 match search m_active
qsearch ~
-1 with
2895 state
.text <- qsearch ^
" [not found]";
2898 state
.text <- qsearch;
2899 active, firstof m_first
active
2901 G.postRedisplay "listview backspace qsearch";
2902 set1 active first qsearch
2905 | key when (key != 0 && key land 0xff00 != 0xff00) ->
2906 let pattern = m_qsearch ^ toutf8
key in
2908 match search m_active
pattern 1 with
2910 state
.text <- pattern ^
" [not found]";
2913 state
.text <- pattern;
2914 active, firstof m_first
active
2916 G.postRedisplay "listview qsearch add";
2917 set1 active first pattern;
2921 if emptystr m_qsearch
2923 G.postRedisplay "list view escape";
2924 let mx, my
= state
.mpos
in
2928 source#exit ~uioh
:(coe self
)
2929 ~cancel
:true ~
active:m_active ~
first:m_first ~pan
:m_pan
2931 | None
-> m_prev_uioh
2936 G.postRedisplay "list view kill qsearch";
2937 coe {< m_qsearch
= E.s >}
2940 | @enter
| @kpenter
->
2942 let self = {< m_qsearch
= E.s >} in
2944 G.postRedisplay "listview enter";
2945 if m_active
>= 0 && m_active
< source#getitemcount
2947 source#exit ~uioh
:(coe self) ~cancel
:false
2948 ~
active:m_active ~
first:m_first ~pan
:m_pan
;
2951 source#exit ~uioh
:(coe self) ~cancel
:true
2952 ~
active:m_active ~
first:m_first ~pan
:m_pan
;
2955 begin match opt with
2956 | None
-> m_prev_uioh
2960 | @delete
| @kpdelete
->
2963 | @up
| @kpup
-> navigate ~
-1
2964 | @down
| @kpdown
-> navigate 1
2965 | @prior
| @kpprior
-> navigate ~
-(fstate
.maxrows
)
2966 | @next | @kpnext
-> navigate fstate
.maxrows
2968 | @right
| @kpright
->
2970 G.postRedisplay "listview right";
2971 coe {< m_pan
= m_pan
- 1 >}
2973 | @left | @kpleft
->
2975 G.postRedisplay "listview left";
2976 coe {< m_pan
= m_pan
+ 1 >}
2978 | @home
| @kphome
->
2979 let active = find 0 1 in
2980 G.postRedisplay "listview home";
2984 let first = max
0 (itemcount - fstate
.maxrows
) in
2985 let active = find (itemcount - 1) ~
-1 in
2986 G.postRedisplay "listview end";
2989 | key when (key = 0 || key land 0xff00 = 0xff00) ->
2993 dolog
"listview unknown key %#x" key; coe self
2995 method key key mask
=
2996 match state
.mode
with
2997 | Textentry te
-> textentrykeyboard key mask te
; coe self
3000 | LinkNav
_ -> self#key1
key mask
3002 method button button down
x y _ =
3005 | 1 when vscrollhit x ->
3006 G.postRedisplay "listview scroll";
3009 let _, position, sh = self#
scrollph in
3010 if y > truncate
position && y < truncate
(position +. sh)
3012 state
.mstate
<- Mscrolly
;
3016 let s = float (max
0 (y - conf
.scrollh
)) /. float state
.winh
in
3017 let first = truncate
(s *. float source#getitemcount
) in
3018 let first = min source#getitemcount
first in
3019 Some
(coe {< m_first
= first; m_active
= first >})
3021 state
.mstate
<- Mnone
;
3025 begin match self#elemunder
y with
3027 G.postRedisplay "listview click";
3028 source#exit ~uioh
:(coe {< m_active
= n >})
3029 ~cancel
:false ~
active:n ~
first:m_first ~pan
:m_pan
3033 | n when (n == 4 || n == 5) && not down
->
3034 let len = source#getitemcount
in
3036 if n = 5 && m_first
+ fstate
.maxrows
>= len
3040 let first = m_first
+ (if n == 4 then -1 else 1) in
3041 bound
first 0 (len - 1)
3043 G.postRedisplay "listview wheel";
3044 Some
(coe {< m_first
= first >})
3045 | n when (n = 6 || n = 7) && not down
->
3046 let inc = if n = 7 then -1 else 1 in
3047 G.postRedisplay "listview hwheel";
3048 Some
(coe {< m_pan
= m_pan
+ inc >})
3053 | None
-> m_prev_uioh
3056 method multiclick
_ x y = self#button
1 true x y
3059 match state
.mstate
with
3061 let s = float (max
0 (y - conf
.scrollh
)) /. float state
.winh
in
3062 let first = truncate
(s *. float source#getitemcount
) in
3063 let first = min source#getitemcount
first in
3064 G.postRedisplay "listview motion";
3065 coe {< m_first
= first; m_active
= first >}
3073 method pmotion
x y =
3074 if x < state
.winw
- conf
.scrollbw
3077 match self#elemunder
y with
3078 | None
-> Wsi.setcursor
Wsi.CURSOR_INHERIT
; m_active
3079 | Some
n -> Wsi.setcursor
Wsi.CURSOR_INFO
; n
3083 then (G.postRedisplay "listview pmotion"; {< m_active
= n >})
3088 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
3092 method infochanged
_ = ()
3094 method scrollpw
= (0, 0.0, 0.0)
3096 let nfs = fstate
.fontsize
+ 1 in
3097 let y = m_first
* nfs in
3098 let itemcount = source#getitemcount
in
3099 let maxi = max
0 (itemcount - fstate
.maxrows
) in
3100 let maxy = maxi * nfs in
3101 let p, h = scrollph y maxy in
3104 method modehash
= modehash
3105 method eformsgs
= false
3106 method alwaysscrolly
= true
3109 class outlinelistview ~zebra ~source
=
3110 let settext autonarrow
s =
3113 let ss = source#statestr
in
3117 else "{" ^
ss ^
"} [" ^
s ^
"]"
3118 else state
.text <- s
3124 ~source
:(source
:> lvsource
)
3126 ~modehash
:(findkeyhash conf
"outline")
3129 val m_autonarrow
= false
3131 method! key key mask
=
3133 if emptystr state
.text
3135 else fstate
.maxrows - 2
3137 let calcfirst first active =
3140 let rows = active - first in
3141 if rows > maxrows then active - maxrows else first
3145 let active = m_active
+ incr in
3146 let active = bound
active 0 (source#getitemcount
- 1) in
3147 let first = calcfirst m_first
active in
3148 G.postRedisplay "outline navigate";
3149 coe {< m_active
= active; m_first
= first >}
3151 let navscroll first =
3153 let dist = m_active
- first in
3159 else first + maxrows
3162 G.postRedisplay "outline navscroll";
3163 coe {< m_first
= first; m_active
= active >}
3165 let ctrl = Wsi.withctrl mask
in
3170 then (source#denarrow
; E.s)
3172 let pattern = source#renarrow
in
3173 if nonemptystr m_qsearch
3174 then (source#narrow m_qsearch
; m_qsearch
)
3178 settext (not m_autonarrow
) text;
3179 G.postRedisplay "toggle auto narrowing";
3180 coe {< m_first
= 0; m_active
= 0; m_autonarrow
= not m_autonarrow
>}
3182 | @slash
when emptystr m_qsearch
&& not m_autonarrow
->
3184 G.postRedisplay "toggle auto narrowing";
3185 coe {< m_first
= 0; m_active
= 0; m_autonarrow
= true >}
3188 source#narrow m_qsearch
;
3190 then source#add_narrow_pattern m_qsearch
;
3191 G.postRedisplay "outline ctrl-n";
3192 coe {< m_first
= 0; m_active
= 0 >}
3195 let active = source#calcactive
(getanchor
()) in
3196 let first = firstof m_first
active in
3197 G.postRedisplay "outline ctrl-s";
3198 coe {< m_first
= first; m_active
= active >}
3201 G.postRedisplay "outline ctrl-u";
3202 if m_autonarrow
&& nonemptystr m_qsearch
3204 ignore
(source#renarrow
);
3205 settext m_autonarrow
E.s;
3206 coe {< m_first
= 0; m_active
= 0; m_qsearch
= E.s >}
3209 source#del_narrow_pattern
;
3210 let pattern = source#renarrow
in
3212 if emptystr
pattern then E.s else "Narrowed to " ^
pattern
3214 settext m_autonarrow
text;
3215 coe {< m_first
= 0; m_active
= 0; m_qsearch
= E.s >}
3219 let first = max
0 (m_active
- (fstate
.maxrows / 2)) in
3220 G.postRedisplay "outline ctrl-l";
3221 coe {< m_first
= first >}
3223 | @tab
when m_autonarrow
->
3224 if nonemptystr m_qsearch
3226 G.postRedisplay "outline list view tab";
3227 source#add_narrow_pattern m_qsearch
;
3229 coe {< m_qsearch
= E.s >}
3233 | @escape
when m_autonarrow
->
3234 if nonemptystr m_qsearch
3235 then source#add_narrow_pattern m_qsearch
;
3238 | @enter
| @kpenter
when m_autonarrow
->
3239 if nonemptystr m_qsearch
3240 then source#add_narrow_pattern m_qsearch
;
3243 | key when m_autonarrow
&& (key != 0 && key land 0xff00 != 0xff00) ->
3244 let pattern = m_qsearch ^ toutf8
key in
3245 G.postRedisplay "outlinelistview autonarrow add";
3246 source#narrow
pattern;
3247 settext true pattern;
3248 coe {< m_first
= 0; m_active
= 0; m_qsearch
= pattern >}
3250 | key when m_autonarrow
&& key = @backspace
->
3251 if emptystr m_qsearch
3254 let pattern = withoutlastutf8 m_qsearch
in
3255 G.postRedisplay "outlinelistview autonarrow backspace";
3256 ignore
(source#renarrow
);
3257 source#narrow
pattern;
3258 settext true pattern;
3259 coe {< m_first
= 0; m_active
= 0; m_qsearch
= pattern >}
3261 | @up
| @kpup
when ctrl ->
3262 navscroll (max
0 (m_first
- 1))
3264 | @down
| @kpdown
when ctrl ->
3265 navscroll (min
(source#getitemcount
- 1) (m_first
+ 1))
3267 | @up
| @kpup
-> navigate ~
-1
3268 | @down
| @kpdown
-> navigate 1
3269 | @prior
| @kpprior
-> navigate ~
-(fstate
.maxrows)
3270 | @next | @kpnext
-> navigate fstate
.maxrows
3272 | @right
| @kpright
->
3276 G.postRedisplay "outline ctrl right";
3277 {< m_pan
= m_pan
+ 1 >}
3279 else self#updownlevel
1
3283 | @left | @kpleft
->
3287 G.postRedisplay "outline ctrl left";
3288 {< m_pan
= m_pan
- 1 >}
3290 else self#updownlevel ~
-1
3294 | @home
| @kphome
->
3295 G.postRedisplay "outline home";
3296 coe {< m_first
= 0; m_active
= 0 >}
3299 let active = source#getitemcount
- 1 in
3300 let first = max
0 (active - fstate
.maxrows) in
3301 G.postRedisplay "outline end";
3302 coe {< m_active
= active; m_first
= first >}
3304 | _ -> super#
key key mask
3307 let genhistoutlines () =
3309 |> List.sort
(fun (_, c1
, _, _, _, _) (_, c2
, _, _, _, _) ->
3310 compare c2
.lastvisit c1
.lastvisit
)
3312 (fun ((path
, c, _, _, _, origin
) as hist
) ->
3313 let path = if nonemptystr origin
then origin
else path in
3314 let base = mbtoutf8
@@ Filename.basename
path in
3315 (base ^
"\000" ^
c.title
, 1, Ohistory hist
)
3320 let gotohist (path, c, bookmarks
, x, anchor, origin
) =
3321 Config.save
leavebirdseye;
3322 state
.anchor <- anchor;
3323 state
.bookmarks
<- bookmarks
;
3324 state
.origin
<- origin
;
3327 let x0, y0, x1, y1 = conf
.trimfuzz
in
3328 wcmd "trimset %d %d %d %d %d" (btod conf
.trimmargins
) x0 y0 x1 y1;
3329 reshape ~firsttime
:true state
.winw state
.winh
;
3330 opendoc path origin
;
3334 let makecheckers () =
3335 (* Based on lablGL-1.04/LablGlut/examples/lablGL/checker.ml which had
3337 converted by Issac Trotts. July 25, 2002 *)
3338 let image = GlPix.create `ubyte ~format
:`luminance ~width
:2 ~height
:2 in
3339 Raw.sets_string
(GlPix.to_raw
image) ~
pos:0 "\255\200\200\255";
3340 let id = GlTex.gen_texture
() in
3341 GlTex.bind_texture ~target
:`texture_2d
id;
3342 GlPix.store
(`unpack_alignment
1);
3343 GlTex.image2d
image;
3344 List.iter
(GlTex.parameter ~target
:`texture_2d
)
3345 [ `mag_filter `nearest
; `min_filter `nearest
];
3349 let setcheckers enabled
=
3350 match state
.checkerstexid
with
3352 if enabled
then state
.checkerstexid
<- Some
(makecheckers ())
3354 | Some checkerstexid
->
3357 GlTex.delete_texture checkerstexid
;
3358 state
.checkerstexid
<- None
;
3362 let describe_location () =
3363 let fn = page_of_y state
.y in
3364 let ln = page_of_y
(state
.y + state
.winh
- hscrollh () - 1) in
3365 let maxy = state
.maxy - (if conf
.maxhfit
then state
.winh
else 0) in
3369 else (100. *. (float state
.y /. float maxy))
3373 Printf.sprintf
"page %d of %d [%.2f%%]"
3374 (fn+1) state
.pagecount
percent
3377 "pages %d-%d of %d [%.2f%%]"
3378 (fn+1) (ln+1) state
.pagecount
percent
3381 let setpresentationmode v
=
3382 let n = page_of_y state
.y in
3383 state
.anchor <- (n, 0.0, 1.0);
3384 conf
.presentation
<- v
;
3385 if conf
.fitmodel
= FitPage
3386 then reqlayout conf
.angle conf
.fitmodel
;
3390 let setbgcol (r
, g, b) =
3392 let r = r *. 255.0 |> truncate
3393 and g = g *. 255.0 |> truncate
3394 and b = b *. 255.0 |> truncate
in
3395 r lsl 16 |> (lor) (g lsl 8) |> (lor) b
3397 Wsi.setwinbgcol
col;
3401 let btos b = if b then "@Uradical" else E.s in
3402 let showextended = ref false in
3403 let leave mode
_ = state
.mode
<- mode
in
3406 val mutable m_l
= []
3407 val mutable m_a
= E.a
3408 val mutable m_prev_uioh
= nouioh
3409 val mutable m_prev_mode
= View
3411 inherit lvsourcebase
3413 method reset prev_mode prev_uioh
=
3414 m_a
<- Array.of_list
(List.rev m_l
);
3416 m_prev_mode
<- prev_mode
;
3417 m_prev_uioh
<- prev_uioh
;
3419 method int name get
set =
3421 (name
, `
int get
, 1, Action
(
3424 try set (int_of_string
s)
3426 state
.text <- Printf.sprintf
"bad integer `%s': %s"
3430 let te = name ^
": ", E.s, None
, intentry, ondone, true in
3431 state
.mode
<- Textentry
(te, leave m_prev_mode
);
3435 method int_with_suffix name get
set =
3437 (name
, `intws get
, 1, Action
(
3440 try set (int_of_string_with_suffix
s)
3442 state
.text <- Printf.sprintf
"bad integer `%s': %s"
3447 name ^
": ", E.s, None
, intentry_with_suffix, ondone, true
3449 state
.mode
<- Textentry
(te, leave m_prev_mode
);
3453 method bool ?
(offset
=1) ?
(btos=btos) name get
set =
3455 (name
, `
bool (btos, get
), offset
, Action
(
3462 method color name get
set =
3464 (name
, `
color get
, 1, Action
(
3466 let invalid = (nan
, nan
, nan
) in
3469 try color_of_string
s
3471 state
.text <- Printf.sprintf
"bad color `%s': %s"
3478 let te = name ^
": ", E.s, None
, textentry, ondone, true in
3479 state
.text <- color_to_string
(get
());
3480 state
.mode
<- Textentry
(te, leave m_prev_mode
);
3484 method string name get
set =
3486 (name
, `
string get
, 1, Action
(
3488 let ondone s = set s in
3489 let te = name ^
": ", E.s, None
, textentry, ondone, true in
3490 state
.mode
<- Textentry
(te, leave m_prev_mode
);
3494 method colorspace name get
set =
3496 (name
, `
string get
, 1, Action
(
3500 inherit lvsourcebase
3503 m_active
<- CSTE.to_int conf
.colorspace
;
3506 method getitemcount
=
3507 Array.length
CSTE.names
3510 method exit ~uioh ~cancel ~
active ~
first ~pan
=
3511 ignore
(uioh
, first, pan
);
3512 if not cancel
then set active;
3514 method hasaction
_ = true
3518 let modehash = findkeyhash conf
"info" in
3519 coe (new listview ~zebra
:false ~helpmode
:false
3520 ~
source ~trusted
:true ~
modehash)
3523 method paxmark name get
set =
3525 (name
, `
string get
, 1, Action
(
3529 inherit lvsourcebase
3532 m_active
<- MTE.to_int conf
.paxmark
;
3535 method getitemcount
= Array.length
MTE.names
3536 method getitem
n = (MTE.names
.(n), 0)
3537 method exit ~uioh ~cancel ~
active ~
first ~pan
=
3538 ignore
(uioh
, first, pan
);
3539 if not cancel
then set active;
3541 method hasaction
_ = true
3545 let modehash = findkeyhash conf
"info" in
3546 coe (new listview ~zebra
:false ~helpmode
:false
3547 ~
source ~trusted
:true ~
modehash)
3550 method fitmodel name get
set =
3552 (name
, `
string get
, 1, Action
(
3556 inherit lvsourcebase
3559 m_active
<- FMTE.to_int conf
.fitmodel
;
3562 method getitemcount
= Array.length
FMTE.names
3563 method getitem
n = (FMTE.names
.(n), 0)
3564 method exit ~uioh ~cancel ~
active ~
first ~pan
=
3565 ignore
(uioh
, first, pan
);
3566 if not cancel
then set active;
3568 method hasaction
_ = true
3572 let modehash = findkeyhash conf
"info" in
3573 coe (new listview ~zebra
:false ~helpmode
:false
3574 ~
source ~trusted
:true ~
modehash)
3577 method caption
s offset
=
3578 m_l
<- (s, `empty
, offset
, Noaction
) :: m_l
3580 method caption2
s f offset
=
3581 m_l
<- (s, `
string f, offset
, Noaction
) :: m_l
3583 method getitemcount
= Array.length m_a
3586 let tostr = function
3587 | `
int f -> string_of_int
(f ())
3588 | `intws
f -> string_with_suffix_of_int
(f ())
3590 | `
color f -> color_to_string
(f ())
3591 | `
bool (btos, f) -> btos (f ())
3594 let name, t
, offset
, _ = m_a
.(n) in
3595 ((let s = tostr t
in
3597 then Printf.sprintf
"%s\t%s" name s
3601 method exit ~uioh ~cancel ~
active ~
first ~pan
=
3606 match m_a
.(active) with
3607 | _, _, _, Action
f -> f uioh
3608 | _, _, _, Noaction
-> uioh
3619 method hasaction
n =
3621 | _, _, _, Action
_ -> true
3622 | _, _, _, Noaction
-> false
3624 initializer m_active
<- 1
3627 let rec fillsrc prevmode prevuioh
=
3628 let sep () = src#caption
E.s 0 in
3629 let colorp name get
set =
3631 (fun () -> color_to_string
(get
()))
3634 let c = color_of_string
v in
3637 state
.text <- Printf.sprintf
"bad color `%s': %s" v @@ exntos exn
3640 let oldmode = state
.mode
in
3641 let birdseye = isbirdseye state
.mode
in
3643 src#caption
(if birdseye then "Setup (Bird's eye)" else "Setup") 0;
3645 src#
bool "presentation mode"
3646 (fun () -> conf
.presentation
)
3647 (fun v -> setpresentationmode v);
3649 src#
bool "ignore case in searches"
3650 (fun () -> conf
.icase
)
3651 (fun v -> conf
.icase
<- v);
3654 (fun () -> conf
.preload)
3655 (fun v -> conf
.preload <- v);
3657 src#
bool "highlight links"
3658 (fun () -> conf
.hlinks
)
3659 (fun v -> conf
.hlinks
<- v);
3661 src#
bool "under info"
3662 (fun () -> conf
.underinfo
)
3663 (fun v -> conf
.underinfo
<- v);
3665 src#
bool "persistent bookmarks"
3666 (fun () -> conf
.savebmarks
)
3667 (fun v -> conf
.savebmarks
<- v);
3669 src#fitmodel
"fit model"
3670 (fun () -> FMTE.to_string conf
.fitmodel
)
3671 (fun v -> reqlayout conf
.angle
(FMTE.of_int
v));
3673 src#
bool "trim margins"
3674 (fun () -> conf
.trimmargins
)
3675 (fun v -> settrim v conf
.trimfuzz
; fillsrc prevmode prevuioh
);
3677 src#
bool "persistent location"
3678 (fun () -> conf
.jumpback
)
3679 (fun v -> conf
.jumpback
<- v);
3682 src#
int "inter-page space"
3683 (fun () -> conf
.interpagespace
)
3685 conf
.interpagespace
<- n;
3686 docolumns conf
.columns
;
3688 match state
.layout with
3693 state
.maxy <- calcheight
();
3694 let y = getpagey
pageno in
3699 (fun () -> conf
.pagebias
)
3700 (fun v -> conf
.pagebias
<- v);
3702 src#
int "scroll step"
3703 (fun () -> conf
.scrollstep
)
3704 (fun n -> conf
.scrollstep
<- n);
3706 src#
int "horizontal scroll step"
3707 (fun () -> conf
.hscrollstep
)
3708 (fun v -> conf
.hscrollstep
<- v);
3710 src#
int "auto scroll step"
3712 match state
.autoscroll
with
3714 | _ -> conf
.autoscrollstep
)
3716 let n = boundastep state
.winh
n in
3717 if state
.autoscroll
<> None
3718 then state
.autoscroll
<- Some
n;
3719 conf
.autoscrollstep
<- n);
3722 (fun () -> truncate
(conf
.zoom *. 100.))
3723 (fun v -> setzoom ((float v) /. 100.));
3726 (fun () -> conf
.angle
)
3727 (fun v -> reqlayout v conf
.fitmodel
);
3729 src#
int "scroll bar width"
3730 (fun () -> conf
.scrollbw
)
3733 reshape state
.winw state
.winh
;
3736 src#
int "scroll handle height"
3737 (fun () -> conf
.scrollh
)
3738 (fun v -> conf
.scrollh
<- v;);
3740 src#
int "thumbnail width"
3741 (fun () -> conf
.thumbw
)
3743 conf
.thumbw
<- min
4096 v;
3746 leavebirdseye beye
false;
3753 let mode = state
.mode in
3754 src#
string "columns"
3756 match conf
.columns
with
3758 | Cmulti
(multi
, _) -> multicolumns_to_string multi
3759 | Csplit
(count
, _) -> "-" ^ string_of_int count
3762 let n, a, b = multicolumns_of_string
v in
3763 setcolumns mode n a b);
3766 src#caption
"Pixmap cache" 0;
3767 src#int_with_suffix
"size (advisory)"
3768 (fun () -> conf
.memlimit
)
3769 (fun v -> conf
.memlimit
<- v);
3772 (fun () -> Printf.sprintf
"%s bytes, %d tiles"
3773 (string_with_suffix_of_int state
.memused
)
3774 (Hashtbl.length state
.tilemap
)) 1;
3777 src#caption
"Layout" 0;
3778 src#caption2
"Dimension"
3780 Printf.sprintf
"%dx%d (virtual %dx%d)"
3781 state
.winw state
.winh
3786 src#caption2
"Position" (fun () ->
3787 Printf.sprintf
"%dx%d" state
.x state
.y
3790 src#caption2
"Position" (fun () -> describe_location ()) 1
3794 src#
bool ~offset
:0 ~
btos:(fun v -> if v then "(on)" else "(off)")
3795 "Save these parameters as global defaults at exit"
3796 (fun () -> conf
.bedefault
)
3797 (fun v -> conf
.bedefault
<- v)
3801 let btos b = if b then "@Ulguillemet" else "@Urguillemet" in
3802 src#
bool ~offset
:0 ~
btos "Extended parameters"
3803 (fun () -> !showextended)
3804 (fun v -> showextended := v; fillsrc prevmode prevuioh
);
3808 (fun () -> conf
.checkers
)
3809 (fun v -> conf
.checkers
<- v; setcheckers v);
3810 src#
bool "update cursor"
3811 (fun () -> conf
.updatecurs
)
3812 (fun v -> conf
.updatecurs
<- v);
3813 src#
bool "scroll-bar on the left"
3814 (fun () -> conf
.leftscroll
)
3815 (fun v -> conf
.leftscroll
<- v);
3817 (fun () -> conf
.verbose
)
3818 (fun v -> conf
.verbose
<- v);
3819 src#
bool "invert colors"
3820 (fun () -> conf
.invert
)
3821 (fun v -> conf
.invert
<- v);
3823 (fun () -> conf
.maxhfit
)
3824 (fun v -> conf
.maxhfit
<- v);
3826 (fun () -> conf
.pax
!= None
)
3829 then conf
.pax
<- Some
(ref (now
(), 0, 0))
3830 else conf
.pax
<- None
);
3831 src#
string "uri launcher"
3832 (fun () -> conf
.urilauncher
)
3833 (fun v -> conf
.urilauncher
<- v);
3834 src#
string "path launcher"
3835 (fun () -> conf
.pathlauncher
)
3836 (fun v -> conf
.pathlauncher
<- v);
3837 src#
string "tile size"
3838 (fun () -> Printf.sprintf
"%dx%d" conf
.tilew conf
.tileh
)
3841 let w, h = Scanf.sscanf
v "%dx%d" (fun w h -> w, h) in
3842 conf
.tilew
<- max
64 w;
3843 conf
.tileh
<- max
64 h;
3846 state
.text <- Printf.sprintf
"bad tile size `%s': %s"
3849 src#
int "texture count"
3850 (fun () -> conf
.texcount
)
3853 then conf
.texcount
<- v
3854 else impmsg "failed to set texture count please retry later"
3856 src#
int "slice height"
3857 (fun () -> conf
.sliceheight
)
3859 conf
.sliceheight
<- v;
3860 wcmd "sliceh %d" conf
.sliceheight
;
3862 src#
int "anti-aliasing level"
3863 (fun () -> conf
.aalevel
)
3865 conf
.aalevel
<- bound
v 0 8;
3866 state
.anchor <- getanchor
();
3867 opendoc state
.path state
.password;
3869 src#
string "page scroll scaling factor"
3870 (fun () -> string_of_float conf
.pgscale)
3873 let s = float_of_string
v in
3876 state
.text <- Printf.sprintf
3877 "bad page scroll scaling factor `%s': %s" v @@ exntos exn
3880 src#
int "ui font size"
3881 (fun () -> fstate
.fontsize
)
3882 (fun v -> setfontsize (bound
v 5 100));
3883 src#
int "hint font size"
3884 (fun () -> conf
.hfsize
)
3885 (fun v -> conf
.hfsize
<- bound
v 5 100);
3886 colorp "background color"
3887 (fun () -> conf
.bgcolor
)
3888 (fun v -> conf
.bgcolor
<- v; setbgcol v);
3889 src#
bool "crop hack"
3890 (fun () -> conf
.crophack
)
3891 (fun v -> conf
.crophack
<- v);
3892 src#
string "trim fuzz"
3893 (fun () -> irect_to_string conf
.trimfuzz
)
3896 conf
.trimfuzz
<- irect_of_string
v;
3898 then settrim true conf
.trimfuzz
;
3900 state
.text <- Printf.sprintf
"bad irect `%s': %s" v @@ exntos exn
3902 src#
string "throttle"
3904 match conf
.maxwait
with
3905 | None
-> "show place holder if page is not ready"
3908 then "wait for page to fully render"
3910 "wait " ^ string_of_float
time
3911 ^
" seconds before showing placeholder"
3915 let f = float_of_string
v in
3917 then conf
.maxwait
<- None
3918 else conf
.maxwait
<- Some
f
3920 state
.text <- Printf.sprintf
"bad time `%s': %s" v @@ exntos exn
3922 src#
string "ghyll scroll"
3924 match conf
.ghyllscroll
with
3926 | Some nab
-> ghyllscroll_to_string nab
3929 try conf
.ghyllscroll
<- ghyllscroll_of_string
v
3932 state
.text <- Printf.sprintf
"bad ghyll `%s': %s" v msg
3934 state
.text <- Printf.sprintf
"bad ghyll `%s': %s" v @@ exntos exn
3936 src#
string "selection command"
3937 (fun () -> conf
.selcmd
)
3938 (fun v -> conf
.selcmd
<- v);
3939 src#
string "synctex command"
3940 (fun () -> conf
.stcmd
)
3941 (fun v -> conf
.stcmd
<- v);
3942 src#
string "pax command"
3943 (fun () -> conf
.paxcmd
)
3944 (fun v -> conf
.paxcmd
<- v);
3945 src#
string "ask password command"
3946 (fun () -> conf
.passcmd)
3947 (fun v -> conf
.passcmd <- v);
3948 src#
string "save path command"
3949 (fun () -> conf
.savecmd
)
3950 (fun v -> conf
.savecmd
<- v);
3951 src#colorspace
"color space"
3952 (fun () -> CSTE.to_string conf
.colorspace
)
3954 conf
.colorspace
<- CSTE.of_int
v;
3958 src#paxmark
"pax mark method"
3959 (fun () -> MTE.to_string conf
.paxmark
)
3960 (fun v -> conf
.paxmark
<- MTE.of_int
v);
3961 if bousable
() && !opengl_has_pbo
3964 (fun () -> conf
.usepbo
)
3965 (fun v -> conf
.usepbo
<- v);
3966 src#
bool "mouse wheel scrolls pages"
3967 (fun () -> conf
.wheelbypage
)
3968 (fun v -> conf
.wheelbypage
<- v);
3969 src#
bool "open remote links in a new instance"
3970 (fun () -> conf
.riani
)
3971 (fun v -> conf
.riani
<- v);
3972 src#
bool "edit annotations inline"
3973 (fun () -> conf
.annotinline
)
3974 (fun v -> conf
.annotinline
<- v);
3975 src#
bool "coarse positioning in presentation mode"
3976 (fun () -> conf
.coarseprespos
)
3977 (fun v -> conf
.coarseprespos
<- v);
3981 src#caption
"Document" 0;
3982 List.iter
(fun (_, s) -> src#caption
s 1) state
.docinfo
;
3983 src#caption2
"Pages"
3984 (fun () -> string_of_int state
.pagecount
) 1;
3985 src#caption2
"Dimensions"
3986 (fun () -> string_of_int
(List.length state
.pdims
)) 1;
3990 src#caption
"Trimmed margins" 0;
3991 src#caption2
"Dimensions"
3992 (fun () -> string_of_int
(List.length state
.pdims
)) 1;
3996 src#caption
"OpenGL" 0;
3997 src#caption
(Printf.sprintf
"Vendor\t%s" (GlMisc.get_string `vendor
)) 1;
3998 src#caption
(Printf.sprintf
"Renderer\t%s" (GlMisc.get_string `renderer
)) 1;
4001 src#caption
"Location" 0;
4002 if nonemptystr state
.origin
4003 then src#caption
("Orign\t" ^ mbtoutf8 state
.origin
) 1;
4004 src#caption
("Path\t" ^ mbtoutf8 state
.path) 1;
4006 src#reset prevmode prevuioh
;
4011 let prevmode = state
.mode
4012 and prevuioh
= state
.uioh in
4013 fillsrc prevmode prevuioh
;
4014 let source = (src :> lvsource
) in
4015 let modehash = findkeyhash conf
"info" in
4016 state
.uioh <- coe (object (self)
4017 inherit listview ~zebra
:false ~helpmode
:false
4018 ~
source ~trusted
:true ~
modehash as super
4019 val mutable m_prevmemused
= 0
4020 method! infochanged
= function
4022 if m_prevmemused
!= state
.memused
4024 m_prevmemused
<- state
.memused
;
4025 G.postRedisplay "memusedchanged";
4027 | Pdim
-> G.postRedisplay "pdimchanged"
4028 | Docinfo
-> fillsrc prevmode prevuioh
4030 method! key key mask
=
4031 if not
(Wsi.withctrl mask
)
4034 | @left | @kpleft
-> coe (self#updownlevel ~
-1)
4035 | @right
| @kpright
-> coe (self#updownlevel
1)
4036 | _ -> super#
key key mask
4037 else super#
key key mask
4039 G.postRedisplay "info";
4045 inherit lvsourcebase
4046 method getitemcount
= Array.length state
.help
4048 let s, l, _ = state
.help
.(n) in
4051 method exit ~
uioh ~cancel ~
active ~
first ~pan
=
4055 match state
.help
.(active) with
4056 | _, _, Action
f -> Some
(f uioh)
4057 | _, _, Noaction
-> Some
uioh
4066 method hasaction
n =
4067 match state
.help
.(n) with
4068 | _, _, Action
_ -> true
4069 | _, _, Noaction
-> false
4075 let modehash = findkeyhash conf
"help" in
4077 state
.uioh <- coe (new listview
4078 ~zebra
:false ~helpmode
:true
4079 ~
source ~trusted
:true ~
modehash);
4080 G.postRedisplay "help";
4086 inherit lvsourcebase
4087 val mutable m_items
= E.a
4089 method getitemcount
= 1 + Array.length m_items
4094 else m_items
.(n-1), 0
4096 method exit ~
uioh ~cancel ~
active ~
first ~pan
=
4101 then Buffer.clear state
.errmsgs
;
4108 method hasaction
n =
4112 state
.newerrmsgs
<- false;
4113 let l = Str.split newlinere
(Buffer.contents state
.errmsgs
) in
4114 m_items
<- Array.of_list
l
4123 let source = (msgsource :> lvsource
) in
4124 let modehash = findkeyhash conf
"listview" in
4125 state
.uioh <- coe (object
4126 inherit listview ~zebra
:false ~helpmode
:false
4127 ~
source ~trusted
:false ~
modehash as super
4130 then msgsource#reset
;
4133 G.postRedisplay "msgs";
4137 let editor = getenvwithdef
"EDITOR" E.s in
4141 let tmppath = Filename.temp_file
"llpp" "note" in
4144 let oc = open_out
tmppath in
4148 let execstr = editor ^
" " ^
tmppath in
4150 match spawn
execstr [] with
4151 | (exception exn
) ->
4152 impmsg "spawn(%S) failed: %s" execstr @@ exntos exn
;
4155 match Unix.waitpid
[] pid with
4156 | (exception exn
) ->
4157 impmsg "waitpid(%d) failed: %s" pid @@ exntos exn
;
4161 | Unix.WEXITED
0 -> filecontents
tmppath
4163 impmsg "editor process(%s) exited abnormally: %d" execstr n;
4165 | Unix.WSIGNALED
n ->
4166 impmsg "editor process(%s) was killed by signal %d" execstr n;
4168 | Unix.WSTOPPED
n ->
4169 impmsg "editor(%s) process was stopped by signal %d" execstr n;
4172 match Unix.unlink
tmppath with
4173 | (exception exn
) ->
4174 impmsg "failed to ulink %S: %s" tmppath @@ exntos exn
;
4179 let enterannotmode opaque slinkindex
=
4182 inherit lvsourcebase
4183 val mutable m_text
= E.s
4184 val mutable m_items
= E.a
4186 method getitemcount
= Array.length m_items
4189 let label, _func
= m_items
.(n) in
4192 method exit ~
uioh ~cancel ~
active ~
first ~pan
=
4193 ignore
(uioh, first, pan
);
4196 let _label, func
= m_items
.(active) in
4201 method hasaction
n = nonemptystr
@@ fst m_items
.(n)
4204 let rec split accu b i
=
4206 if p = String.length
s
4207 then (String.sub
s b (p-b), unit) :: accu
4209 if (i
> 70 && s.[p] = ' '
) || s.[p] = '
\r'
|| s.[p] = '
\n'
4211 let ss = if i
= 0 then E.s else String.sub
s b i
in
4212 split ((ss, unit)::accu) (p+1) 0
4217 wcmd "freepage %s" (~
> opaque);
4219 Hashtbl.fold (fun key opaque'
accu ->
4220 if opaque'
= opaque'
4221 then key :: accu else accu) state
.pagemap
[]
4223 List.iter
(Hashtbl.remove state
.pagemap
) keys;
4228 delannot
opaque slinkindex
;
4231 let edit inline
() =
4236 modannot
opaque slinkindex
s;
4242 let mode = state
.mode in
4245 ("annotation: ", m_text
, None
, textentry, update, true),
4246 fun _ -> state
.mode <- mode);
4250 let s = getusertext m_text
in
4255 ( "[Copy]", fun () -> selstring m_text
)
4256 :: ("[Delete]", dele)
4257 :: ("[Edit]", edit conf
.annotinline
)
4259 :: split [] 0 0 |> List.rev
|> Array.of_list
4266 let s = getannotcontents
opaque slinkindex
in
4269 let source = (msgsource :> lvsource
) in
4270 let modehash = findkeyhash conf
"listview" in
4271 state
.uioh <- coe (object
4272 inherit listview ~zebra
:false ~helpmode
:false
4273 ~
source ~trusted
:false ~
modehash
4275 G.postRedisplay "enterannotmode";
4278 let gotounder under =
4279 let getpath filename
=
4281 if nonemptystr filename
4283 if Filename.is_relative filename
4285 let dir = Filename.dirname state
.path in
4287 if Filename.is_implicit
dir
4288 then Filename.concat
(Sys.getcwd
()) dir
4291 Filename.concat
dir filename
4295 if Sys.file_exists
path
4300 | Ulinkgoto
(pageno, top) ->
4305 if conf
.presentation
&& conf
.coarseprespos
4309 gotopage1 pageno top;
4312 | Ulinkuri
s -> gotouri
s
4314 | Uremote
(filename
, pageno) ->
4315 let path = getpath filename
in
4320 let command = Printf.sprintf
"%s -page %d %S" !selfexec pageno path in
4321 match spawn
command [] with
4323 | (exception exn
) ->
4324 dolog
"failed to execute `%s': %s" command @@ exntos exn
4326 let anchor = getanchor
() in
4327 let ranchor = state
.path, state
.password, anchor, state
.origin
in
4328 state
.origin
<- E.s;
4329 state
.anchor <- (pageno, 0.0, 0.0);
4330 state
.ranchors
<- ranchor :: state
.ranchors
;
4333 else impmsg "cannot find %s" filename
4335 | Uremotedest
(filename
, destname
) ->
4336 let path = getpath filename
in
4341 let command = !selfexec ^
" " ^
path ^
" -dest " ^ destname
in
4342 match spawn
command [] with
4343 | (exception exn
) ->
4344 dolog
"failed to execute `%s': %s" command @@ exntos exn
4347 let anchor = getanchor
() in
4348 let ranchor = state
.path, state
.password, anchor, state
.origin
in
4349 state
.origin
<- E.s;
4350 state
.nameddest
<- destname
;
4351 state
.ranchors
<- ranchor :: state
.ranchors
;
4354 else impmsg "cannot find %s" filename
4356 | Uunexpected
_ | Ulaunch
_ | Unamed
_ | Utext
_ | Unone
-> ()
4357 | Uannotation
(opaque, slinkindex
) -> enterannotmode opaque slinkindex
4360 let gotooutline (_, _, kind
) =
4364 let (pageno, y, _) = anchor in
4366 (if conf
.presentation
then (pageno, y, 1.0) else anchor)
4370 | Ouri
uri -> gotounder (Ulinkuri
uri)
4371 | Olaunch cmd
-> gotounder (Ulaunch cmd
)
4372 | Oremote remote
-> gotounder (Uremote remote
)
4373 | Ohistory hist
-> gotohist hist
4374 | Oremotedest remotedest
-> gotounder (Uremotedest remotedest
)
4377 class outlinesoucebase fetchoutlines
= object (self)
4378 inherit lvsourcebase
4379 val mutable m_items
= E.a
4380 val mutable m_minfo
= E.a
4381 val mutable m_orig_items
= E.a
4382 val mutable m_orig_minfo
= E.a
4383 val mutable m_narrow_patterns
= []
4384 val mutable m_gen
= -1
4386 method getitemcount
= Array.length m_items
4389 let s, n, _ = m_items
.(n) in
4392 method exit ~
(uioh:uioh) ~cancel ~
active ~
(first:int) ~pan
:
4394 ignore
(uioh, first);
4396 if m_narrow_patterns
= []
4397 then m_orig_items
, m_orig_minfo
4398 else m_items
, m_minfo
4405 gotooutline m_items
.(active);
4413 method hasaction
(_:int) = true
4416 if Array.length m_items
!= Array.length m_orig_items
4419 match m_narrow_patterns
with
4421 | many
-> String.concat
"@Uellipsis" (List.rev many
)
4423 "Narrowed to " ^
s ^
" (ctrl-u to restore)"
4427 match m_narrow_patterns
with
4430 | head
:: _ -> "@Uellipsis" ^ head
4432 method narrow
pattern =
4433 match Str.regexp_case_fold
pattern with
4434 | (exception _) -> ()
4436 let rec loop accu minfo n =
4439 m_items
<- Array.of_list
accu;
4440 m_minfo
<- Array.of_list
minfo;
4443 let (s, _, _) as o = m_items
.(n) in
4445 match Str.search_forward re
s 0 with
4446 | (exception Not_found
) -> accu, minfo
4447 | first -> o :: accu, (first, Str.match_end
()) :: minfo
4449 loop accu minfo (n-1)
4451 loop [] [] (Array.length m_items
- 1)
4453 method! getminfo
= m_minfo
4456 m_orig_items
<- fetchoutlines
();
4457 m_minfo
<- m_orig_minfo
;
4458 m_items
<- m_orig_items
4460 method add_narrow_pattern
pattern =
4461 m_narrow_patterns
<- pattern :: m_narrow_patterns
4463 method del_narrow_pattern
=
4464 match m_narrow_patterns
with
4465 | _ :: rest
-> m_narrow_patterns
<- rest
4470 match m_narrow_patterns
with
4471 | pattern :: [] -> self#narrow
pattern; pattern
4473 List.fold_left
(fun accu pattern ->
4474 self#narrow
pattern;
4475 pattern ^
"@Uellipsis" ^
accu) E.s list
4477 method calcactive
(_:anchor) = 0
4479 method reset
anchor items =
4480 if state
.gen
!= m_gen
4482 m_orig_items
<- items;
4484 m_narrow_patterns
<- [];
4486 m_orig_minfo
<- E.a;
4490 if items != m_orig_items
4492 m_orig_items
<- items;
4493 if m_narrow_patterns
== []
4494 then m_items
<- items;
4497 let active = self#calcactive
anchor in
4499 m_first
<- firstof m_first
active
4503 let outlinesource fetchoutlines
=
4505 inherit outlinesoucebase fetchoutlines
4506 method! calcactive
anchor =
4507 let rely = getanchory anchor in
4508 let rec loop n best bestd
=
4509 if n = Array.length m_items
4512 let _, _, kind
= m_items
.(n) in
4515 let orely = getanchory anchor in
4516 let d = abs
(orely - rely) in
4519 else loop (n+1) best bestd
4520 | Onone
| Oremote
_ | Olaunch
_
4521 | Oremotedest
_ | Ouri
_ | Ohistory
_ ->
4522 loop (n+1) best bestd
4528 let enteroutlinemode, enterbookmarkmode
, enterhistmode
=
4529 let mkselector sourcetype
=
4530 let fetchoutlines () =
4531 match sourcetype
with
4532 | `bookmarks
-> Array.of_list state
.bookmarks
4533 | `outlines
-> state
.outlines
4534 | `history
-> genhistoutlines ()
4537 if sourcetype
= `history
4538 then new outlinesoucebase
fetchoutlines
4539 else outlinesource fetchoutlines
4542 let outlines = fetchoutlines () in
4543 if Array.length
outlines = 0
4545 showtext ' ' errmsg
;
4549 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
4550 let anchor = getanchor
() in
4551 source#reset
anchor outlines;
4552 state
.text <- source#greetmsg
;
4554 coe (new outlinelistview ~zebra
:(sourcetype
=`history
) ~
source);
4555 G.postRedisplay "enter selector";
4558 let mkenter sourcetype errmsg
=
4559 let enter = mkselector sourcetype
in
4560 fun () -> enter errmsg
4562 (**)mkenter `
outlines "document has no outline"
4563 , mkenter `bookmarks
"document has no bookmarks (yet)"
4564 , mkenter `history
"history is empty"
4567 let quickbookmark ?title
() =
4568 match state
.layout with
4574 let tm = Unix.localtime
(now
()) in
4576 "Quick (page %d) (bookmarked at %02d/%02d/%d %02d:%02d)"
4580 (tm.Unix.tm_year
+ 1900)
4583 | Some
title -> title
4585 state
.bookmarks
<- (title, 0, Oanchor
(getanchor1
l)) :: state
.bookmarks
4588 let setautoscrollspeed step goingdown
=
4589 let incr = max
1 ((abs step
) / 2) in
4590 let incr = if goingdown
then incr else -incr in
4591 let astep = boundastep state
.winh
(step
+ incr) in
4592 state
.autoscroll
<- Some
astep;
4596 match conf
.columns
with
4598 | Csingle
_ | Cmulti
_ -> state
.x != 0 || conf
.zoom > 1.0
4601 let panbound x = bound
x (-state
.w) (wadjsb () + state
.winw
);;
4603 let existsinrow pageno (columns
, coverA
, coverB
) p =
4604 let last = ((pageno - coverA
) mod columns
) + columns
in
4605 let rec any = function
4608 if l.pageno = coverA
- 1 || l.pageno = state
.pagecount
- coverB
4612 then (if l.pageno = last then false else any rest
)
4620 match state
.layout with
4622 let pageno = page_of_y state
.y in
4623 gotoghyll (getpagey
(pageno+1))
4625 match conf
.columns
with
4627 if conf
.presentation
&& rest
== [] && l.pageh
> l.pagey + l.pagevh
4629 let y = clamp (pgscale state
.winh
) in
4632 let pageno = min
(l.pageno+1) (state
.pagecount
-1) in
4633 gotoghyll (getpagey
pageno)
4634 | Cmulti
((c, _, _) as cl, _) ->
4635 if conf
.presentation
4636 && (existsinrow l.pageno cl
4637 (fun l -> l.pageh
> l.pagey + l.pagevh))
4639 let y = clamp (pgscale state
.winh
) in
4642 let pageno = min
(l.pageno+c) (state
.pagecount
-1) in
4643 gotoghyll (getpagey
pageno)
4645 if l.pageno < state
.pagecount
- 1 || l.pagecol
< n - 1
4647 let pagey, pageh
= getpageyh
l.pageno in
4648 let pagey = pagey + pageh
* l.pagecol
in
4649 let ips = if l.pagecol
= 0 then 0 else conf
.interpagespace
in
4650 gotoghyll (pagey + pageh
+ ips)
4654 match state
.layout with
4656 let pageno = page_of_y state
.y in
4657 gotoghyll (getpagey
(pageno-1))
4659 match conf
.columns
with
4661 if conf
.presentation
&& l.pagey != 0
4663 gotoghyll (clamp (pgscale ~
-(state
.winh
)))
4665 let pageno = max
0 (l.pageno-1) in
4666 gotoghyll (getpagey
pageno)
4667 | Cmulti
((c, _, coverB
) as cl, _) ->
4668 if conf
.presentation
&&
4669 (existsinrow l.pageno cl (fun l -> l.pagey != 0))
4671 gotoghyll (clamp (pgscale ~
-(state
.winh
)))
4674 if l.pageno = state
.pagecount
- coverB
4678 let pageno = max
0 (l.pageno-decr) in
4679 gotoghyll (getpagey
pageno)
4687 let pageno = max
0 (l.pageno-1) in
4688 let pagey, pageh
= getpageyh
pageno in
4691 let pagey, pageh
= getpageyh
l.pageno in
4692 pagey + pageh
* (l.pagecol
-1) - conf
.interpagespace
4698 if emptystr conf
.savecmd
4699 then error
"don't know where to save modified document"
4701 let savecmd = Str.global_replace percentsre state
.path conf
.savecmd in
4704 (fun s -> error
"failed to obtain path to the saved copy: %s" s)
4709 let tmp = path ^
".tmp" in
4711 Unix.rename
tmp path;
4714 let viewkeyboard key mask
=
4716 let mode = state
.mode in
4717 state
.mode <- Textentry
(te, fun _ -> state
.mode <- mode);
4720 G.postRedisplay "view:enttext"
4722 let ctrl = Wsi.withctrl mask
in
4724 if key >= 0xffb0 && key < 0xffb9 then key - 0xffb0 + 48 else key
4730 if hasunsavedchanges
()
4734 if conf
.angle
mod 360 = 0 && not
(isbirdseye state
.mode)
4736 state
.mode <- LinkNav
(Ltgendir
0);
4739 else impmsg "keyboard link navigation does not work under rotation"
4742 begin match state
.mstate
with
4745 G.postRedisplay "kill rect";
4748 | Mscrolly
| Mscrollx
4751 begin match state
.mode with
4754 G.postRedisplay "esc leave linknav"
4758 match state
.ranchors
with
4760 | (path, password, anchor, origin
) :: rest
->
4761 state
.ranchors
<- rest
;
4762 state
.anchor <- anchor;
4763 state
.origin
<- origin
;
4764 state
.nameddest
<- E.s;
4765 opendoc path password
4770 gotoghyll (getnav ~
-1)
4781 Hashtbl.iter
(fun _ opaque ->
4783 Hashtbl.clear state
.prects
) state
.pagemap
;
4784 G.postRedisplay "dehighlight";
4786 | @slash
| @question
->
4787 let ondone isforw
s =
4788 cbput state
.hists
.pat
s;
4789 state
.searchpattern
<- s;
4792 let s = String.make
1 (Char.chr
key) in
4793 enttext (s, E.s, Some
(onhist state
.hists
.pat
),
4794 textentry, ondone (key = @slash
), true)
4796 | @plus
| @kpplus
| @equals
when ctrl ->
4797 let incr = if conf
.zoom +. 0.01 > 0.1 then 0.1 else 0.01 in
4798 setzoom (conf
.zoom +. incr)
4800 | @plus
| @kpplus
->
4803 try int_of_string
s with exc
->
4804 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exc
;
4810 state
.text <- "page bias is now " ^ string_of_int
n;
4813 enttext ("page bias: ", E.s, None
, intentry, ondone, true)
4815 | @minus
| @kpminus
when ctrl ->
4816 let decr = if conf
.zoom -. 0.1 < 0.1 then 0.01 else 0.1 in
4817 setzoom (max
0.01 (conf
.zoom -. decr))
4819 | @minus
| @kpminus
->
4820 let ondone msg
= state
.text <- msg
in
4822 "option [acfhilpstvxACFPRSZTISM]: ", E.s, None
,
4823 optentry state
.mode, ondone, true
4834 | (@1 | @2) when ctrl && conf
.fitmodel
!= FitPage
-> (* ctrl-1/2 *)
4836 match conf
.columns
with
4837 | Csingle
_ | Cmulti
_ -> 1
4838 | Csplit
(n, _) -> n
4840 let h = state
.winh
-
4841 conf
.interpagespace
lsl (if conf
.presentation
then 1 else 0)
4843 let zoom = zoomforh state
.winw
h (vscrollw ()) cols in
4844 if zoom > 0.0 && (key = @2 || zoom < 1.0)
4849 match conf
.fitmodel
with
4850 | FitWidth
-> FitProportional
4851 | FitProportional
-> FitPage
4852 | FitPage
-> FitWidth
4854 state
.text <- "fit model: " ^
FMTE.to_string
fm;
4855 reqlayout conf
.angle
fm
4857 | @4 when ctrl -> (* ctrl-4 *)
4858 let zoom = getmaxw
() /. float state
.winw
in
4859 if zoom > 0.0 then setzoom zoom
4867 | (48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57)
4868 when not
ctrl -> (* 0..9 *)
4871 try int_of_string
s with exc
->
4872 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exc
;
4878 cbput state
.hists
.pag
(string_of_int
n);
4879 gotopage1 (n + conf
.pagebias
- 1) 0;
4882 let pageentry text key =
4883 match Char.unsafe_chr
key with
4884 | '
g'
-> TEdone
text
4885 | _ -> intentry text key
4887 let text = String.make
1 (Char.chr
key) in
4888 enttext (":", text, Some
(onhist state
.hists
.pag
),
4889 pageentry, ondone, true)
4892 conf
.scrollb
<- if conf
.scrollb
= 0 then (scrollbvv
lor scrollbhv
) else 0;
4893 reshape state
.winw state
.winh
;
4896 state
.bzoom
<- not state
.bzoom
;
4898 showtext ' '
("block zoom " ^
if state
.bzoom
then "on" else "off")
4901 conf
.hlinks
<- not conf
.hlinks
;
4902 state
.text <- "highlightlinks " ^
if conf
.hlinks
then "on" else "off";
4903 G.postRedisplay "toggle highlightlinks";
4906 if conf
.angle
mod 360 = 0
4908 state
.glinks
<- true;
4909 let mode = state
.mode in
4912 (":", E.s, None
, linknentry, linknact gotounder, false),
4914 state
.glinks
<- false;
4918 G.postRedisplay "view:linkent(F)"
4920 else impmsg "hint mode does not work under rotation"
4923 state
.glinks
<- true;
4924 let mode = state
.mode in
4925 state
.mode <- Textentry
(
4927 ":", E.s, None
, linknentry, linknact (fun under ->
4928 selstring (undertext under);
4932 state
.glinks
<- false;
4936 G.postRedisplay "view:linkent"
4939 begin match state
.autoscroll
with
4941 conf
.autoscrollstep
<- step
;
4942 state
.autoscroll
<- None
4944 if conf
.autoscrollstep
= 0
4945 then state
.autoscroll
<- Some
1
4946 else state
.autoscroll
<- Some conf
.autoscrollstep
4950 launchpath () (* XXX where do error messages go? *)
4953 setpresentationmode (not conf
.presentation
);
4954 showtext ' '
("presentation mode " ^
4955 if conf
.presentation
then "on" else "off");
4958 if List.mem
Wsi.Fullscreen state
.winstate
4959 then Wsi.reshape conf
.cwinw conf
.cwinh
4960 else Wsi.fullscreen
()
4963 search state
.searchpattern
false
4966 search state
.searchpattern
true
4969 begin match state
.layout with
4972 gotoghyll (getpagey
l.pageno)
4978 | @delete
| @kpdelete
-> (* delete *)
4982 showtext ' '
(describe_location ());
4985 begin match state
.layout with
4988 Wsi.reshape (l.pagew
+ vscrollw ()) l.pageh
;
4993 enterbookmarkmode
()
5001 | @e when Buffer.length state
.errmsgs
> 0 ->
5006 match state
.layout with
5011 (s, 0, Oanchor
(getanchor1
l)) :: state
.bookmarks
5014 enttext ("bookmark: ", E.s, None
, textentry, ondone, true)
5018 showtext ' '
"Quick bookmark added";
5021 begin match state
.layout with
5023 let rect = getpdimrect
l.pagedimno
in
5027 (truncate
(1.8 *. (rect.(1) -. rect.(0))),
5028 truncate
(1.2 *. (rect.(3) -. rect.(0))))
5030 (truncate
(rect.(1) -. rect.(0)),
5031 truncate
(rect.(3) -. rect.(0)))
5033 let w = truncate
((float w)*.conf
.zoom)
5034 and h = truncate
((float h)*.conf
.zoom) in
5037 state
.anchor <- getanchor
();
5038 Wsi.reshape (w + vscrollw ()) (h + conf
.interpagespace
)
5040 G.postRedisplay "z";
5045 | @x -> state
.roam
()
5048 reqlayout (conf
.angle
+
5049 (if key = @Gt
then 30 else -30)) conf
.fitmodel
5053 bound
(conf
.colorscale
+. (if key = 93 then 0.1 else -0.1)) 0.0 1.0
5055 G.postRedisplay "brightness";
5057 | @c when state
.mode = View
->
5062 let m = (wadjsb () + state
.winw
- state
.w) / 2 in
5064 gotoy_and_clear_text state
.y
5068 match state
.prevcolumns
with
5069 | None
-> (1, 0, 0), 1.0
5070 | Some
(columns
, z
) ->
5073 | Csplit
(c, _) -> -c, 0, 0
5074 | Cmulti
((c, a, b), _) -> c, a, b
5075 | Csingle
_ -> 1, 0, 0
5079 setcolumns View
c a b;
5082 | @down
| @up
when ctrl && Wsi.withshift mask
->
5083 let zoom, x = state
.prevzoom
in
5087 | @k
| @up
| @kpup
->
5088 begin match state
.autoscroll
with
5090 begin match state
.mode with
5091 | Birdseye beye
-> upbirdseye 1 beye
5096 then gotoy_and_clear_text (clamp ~
-(state
.winh
/2))
5098 if not
(Wsi.withshift mask
) && conf
.presentation
5100 else gotoghyll1 true (clamp (-conf
.scrollstep
))
5104 setautoscrollspeed n false
5107 | @j
| @down
| @kpdown
->
5108 begin match state
.autoscroll
with
5110 begin match state
.mode with
5111 | Birdseye beye
-> downbirdseye 1 beye
5116 then gotoy_and_clear_text (clamp (state
.winh
/2))
5118 if not
(Wsi.withshift mask
) && conf
.presentation
5120 else gotoghyll1 true (clamp (conf
.scrollstep
))
5124 setautoscrollspeed n true
5127 | @left | @right
| @kpleft
| @kpright
when not
(Wsi.withalt mask
) ->
5133 else conf
.hscrollstep
5135 let dx = if key = @left || key = @kpleft
then dx else -dx in
5136 state
.x <- panbound (state
.x + dx);
5137 gotoy_and_clear_text state
.y
5140 G.postRedisplay "left/right"
5143 | @prior
| @kpprior
->
5147 match state
.layout with
5149 | l :: _ -> state
.y - l.pagey
5151 clamp (pgscale (-state
.winh
))
5155 | @next | @kpnext
->
5159 match List.rev state
.layout with
5161 | l :: _ -> getpagey
l.pageno
5163 clamp (pgscale state
.winh
)
5167 | @g | @home
| @kphome
->
5170 | @G
| @jend
| @kpend
->
5172 gotoghyll (clamp state
.maxy)
5174 | @right
| @kpright
when Wsi.withalt mask
->
5175 gotoghyll (getnav 1)
5176 | @left | @kpleft
when Wsi.withalt mask
->
5177 gotoghyll (getnav ~
-1)
5182 | @v when conf
.debug
->
5185 match getopaque l.pageno with
5188 let x0, y0, x1, y1 = pagebbox
opaque in
5189 let a,b = float x0, float y0 in
5190 let c,d = float x1, float y0 in
5191 let e,f = float x1, float y1 in
5192 let h,j
= float x0, float y1 in
5193 let rect = (a,b,c,d,e,f,h,j
) in
5195 let color = (0.0, 0.0, 1.0 /. (l.pageno mod 3 |> float), 0.5) in
5196 state
.rects
<- (l.pageno, color, rect) :: state
.rects
;
5198 G.postRedisplay "v";
5201 let mode = state
.mode in
5202 let cmd = ref E.s in
5203 let onleave = function
5204 | Cancel
-> state
.mode <- mode
5207 match getopaque l.pageno with
5208 | Some
opaque -> pipesel opaque !cmd
5209 | None
-> ()) state
.layout;
5213 cbput state
.hists
.sel
s;
5217 "| ", !cmd, Some
(onhist state
.hists
.sel
), textentry, ondone, true
5219 G.postRedisplay "|";
5220 state
.mode <- Textentry
(te, onleave);
5223 vlog "huh? %s" (Wsi.keyname
key)
5226 let linknavkeyboard key mask
linknav =
5227 let getpage pageno =
5228 let rec loop = function
5230 | l :: _ when l.pageno = pageno -> Some
l
5231 | _ :: rest
-> loop rest
5232 in loop state
.layout
5234 let doexact (pageno, n) =
5235 match getopaque pageno, getpage pageno with
5236 | Some
opaque, Some
l ->
5237 if key = @enter || key = @kpenter
5239 let under = getlink
opaque n in
5240 G.postRedisplay "link gotounder";
5247 Some
(findlink
opaque LDfirst
), -1
5250 Some
(findlink
opaque LDlast
), 1
5253 Some
(findlink
opaque (LDleft
n)), -1
5256 Some
(findlink
opaque (LDright
n)), 1
5259 Some
(findlink
opaque (LDup
n)), -1
5262 Some
(findlink
opaque (LDdown
n)), 1
5267 begin match findpwl
l.pageno dir with
5271 state
.mode <- LinkNav
(Ltgendir
dir);
5272 let y, h = getpageyh
pageno in
5275 then y + h - state
.winh
5280 begin match getopaque pageno, getpage pageno with
5281 | Some
opaque, Some
_ ->
5283 let ld = if dir > 0 then LDfirst
else LDlast
in
5286 begin match link with
5288 showlinktype (getlink
opaque m);
5289 state
.mode <- LinkNav
(Ltexact
(pageno, m));
5290 G.postRedisplay "linknav jpage";
5291 | Lnotfound
-> notfound dir
5297 begin match opt with
5298 | Some Lnotfound
-> pwl l dir;
5299 | Some
(Lfound
m) ->
5303 let _, y0, _, y1 = getlinkrect
opaque m in
5305 then gotopage1 l.pageno y0
5307 let d = fstate
.fontsize
+ 1 in
5308 if y1 - l.pagey > l.pagevh - d
5309 then gotopage1 l.pageno (y1 - state
.winh
- hscrollh () + d)
5310 else G.postRedisplay "linknav";
5312 showlinktype (getlink
opaque m);
5313 state
.mode <- LinkNav
(Ltexact
(l.pageno, m));
5316 | None
-> viewkeyboard key mask
5318 | _ -> viewkeyboard key mask
5323 G.postRedisplay "leave linknav"
5327 | Ltgendir
_ | Ltnotready
_ -> viewkeyboard key mask
5328 | Ltexact exact
-> doexact exact
5331 let keyboard key mask
=
5332 if (key = @g && Wsi.withctrl mask
) && not
(istextentry state
.mode)
5333 then wcmd "interrupt"
5334 else state
.uioh <- state
.uioh#
key key mask
5337 let birdseyekeyboard key mask
5338 ((oconf
, leftx
, pageno, hooverpageno
, anchor) as beye
) =
5340 match conf
.columns
with
5342 | Cmulti
((c, _, _), _) -> c
5343 | Csplit
_ -> failwith
"bird's eye split mode"
5345 let pgh layout = List.fold_left
5346 (fun m l -> max
l.pageh
m) state
.winh
layout in
5348 | @l when Wsi.withctrl mask
->
5349 let y, h = getpageyh
pageno in
5350 let top = (state
.winh
- h) / 2 in
5351 gotoy (max
0 (y - top))
5352 | @enter | @kpenter
-> leavebirdseye beye
false
5353 | @escape
-> leavebirdseye beye
true
5354 | @up
-> upbirdseye incr beye
5355 | @down
-> downbirdseye incr beye
5356 | @left -> upbirdseye 1 beye
5357 | @right
-> downbirdseye 1 beye
5360 begin match state
.layout with
5364 state
.mode <- Birdseye
(
5365 oconf
, leftx
, l.pageno, hooverpageno
, anchor
5367 gotopage1 l.pageno 0;
5370 let layout = layout state
.x (state
.y-state
.winh
)
5372 (pgh state
.layout) in
5374 | [] -> gotoy (clamp (-state
.winh
))
5376 state
.mode <- Birdseye
(
5377 oconf
, leftx
, l.pageno, hooverpageno
, anchor
5379 gotopage1 l.pageno 0
5382 | [] -> gotoy (clamp (-state
.winh
))
5386 begin match List.rev state
.layout with
5388 let layout = layout state
.x
5389 (state
.y + (pgh state
.layout))
5390 state
.winw state
.winh
in
5391 begin match layout with
5393 let incr = l.pageh
- l.pagevh in
5398 oconf
, leftx
, state
.pagecount
- 1, hooverpageno
, anchor
5400 G.postRedisplay "birdseye pagedown";
5402 else gotoy (clamp (incr + conf
.interpagespace
*2));
5406 Birdseye
(oconf
, leftx
, l.pageno, hooverpageno
, anchor);
5407 gotopage1 l.pageno 0;
5410 | [] -> gotoy (clamp state
.winh
)
5414 state
.mode <- Birdseye
(oconf
, leftx
, 0, hooverpageno
, anchor);
5418 let pageno = state
.pagecount
- 1 in
5419 state
.mode <- Birdseye
(oconf
, leftx
, pageno, hooverpageno
, anchor);
5420 if not
(pagevisible state
.layout pageno)
5423 match List.rev state
.pdims
with
5425 | (_, _, h, _) :: _ -> h
5427 gotoy (max
0 (getpagey
pageno - (state
.winh
- h - conf
.interpagespace
)))
5428 else G.postRedisplay "birdseye end";
5430 | _ -> viewkeyboard key mask
5435 match state
.mode with
5436 | Textentry
_ -> scalecolor 0.4
5438 | View
-> scalecolor 1.0
5439 | Birdseye
(_, _, pageno, hooverpageno
, _) ->
5440 if l.pageno = hooverpageno
5443 if l.pageno = pageno
5445 let c = scalecolor 1.0 in
5447 GlDraw.line_width
3.0;
5448 let dispx = xadjsb () + l.pagedispx in
5450 (float (dispx-1)) (float (l.pagedispy-1))
5451 (float (dispx+l.pagevw+1))
5452 (float (l.pagedispy+l.pagevh+1))
5454 GlDraw.line_width
1.0;
5463 let postdrawpage l linkindexbase
=
5464 match getopaque l.pageno with
5466 if tileready l l.pagex
l.pagey
5468 let x = l.pagedispx - l.pagex
+ xadjsb ()
5469 and y = l.pagedispy - l.pagey in
5471 match conf
.columns
with
5472 | Csingle
_ | Cmulti
_ ->
5473 (if conf
.hlinks
then 1 else 0)
5475 && not
(isbirdseye state
.mode) then 2 else 0)
5479 match state
.mode with
5480 | Textentry
((_, s, _, _, _, _), _) when state
.glinks
-> s
5486 Hashtbl.find_all state
.prects
l.pageno |>
5487 List.iter
(fun vals
-> drawprect
opaque x y vals
);
5488 postprocess
opaque hlmask x y (linkindexbase
, s, conf
.hfsize
);
5493 let scrollindicator () =
5494 let sbw, ph
, sh = state
.uioh#
scrollph in
5495 let sbh, pw, sw = state
.uioh#scrollpw
in
5500 else ((state
.winw
- sbw), state
.winw
, 0)
5503 GlDraw.color (0.64, 0.64, 0.64);
5504 filledrect (float x0) 0. (float x1) (float state
.winh
);
5506 (float hx0
) (float (state
.winh
- sbh))
5507 (float (hx0
+ wadjsb () + state
.winw
)) (float state
.winh
)
5509 GlDraw.color (0.0, 0.0, 0.0);
5511 filledrect (float x0) ph
(float x1) (ph
+. sh);
5512 let pw = pw +. float hx0
in
5513 filledrect pw (float (state
.winh
- sbh)) (pw +. sw) (float state
.winh
);
5517 match state
.mstate
with
5518 | Mnone
| Mscrolly
| Mscrollx
| Mpan
_ | Mzoom
_ | Mzoomrect
_ ->
5521 | Msel
((x0, y0), (x1, y1)) ->
5522 let identify opaque l px py = Some
(opaque, l.pageno, px, py) in
5523 let o0,n0
,px0
,py0
= onppundermouse identify x0 y0 (~
< E.s, -1, 0, 0) in
5524 let _o1,n1
,px1
,py1
= onppundermouse identify x1 y1 (~
< E.s, -1, 0, 0) in
5525 if n0
!= -1 && n0
= n1
then seltext
o0 (px0
, py0
, px1
, py1
);
5528 let showrects = function [] -> () | rects
->
5530 GlDraw.color (0.0, 0.0, 1.0) ~
alpha:0.5;
5531 GlFunc.blend_func ~
src:`src_alpha ~dst
:`one_minus_src_alpha
;
5533 (fun (pageno, c, (x0, y0, x1, y1, x2
, y2
, x3
, y3
)) ->
5535 if l.pageno = pageno
5537 let dx = float (l.pagedispx - l.pagex
) in
5538 let dy = float (l.pagedispy - l.pagey) in
5539 let r, g, b, alpha = c in
5540 GlDraw.color (r, g, b) ~
alpha;
5541 filledrect2 (x0+.dx) (y0+.dy)
5553 begin match conf
.columns
, state
.layout with
5554 | Csingle
_, _ :: _ ->
5555 GlDraw.color (scalecolor2 conf
.bgcolor
);
5557 List.fold_left
(fun y l ->
5560 let x1 = l.pagedispx + xadjsb () in
5561 let y1 = (l.pagedispy + l.pagevh) in
5562 filledrect (float x0) (float y0) (float x1) (float y1);
5563 let x0 = x1 + l.pagevw in
5564 let x1 = state
.winw
in
5565 filledrect1 (float x0) (float y0) (float x1) (float y1);
5569 and x1 = state
.winw
in
5571 and y1 = l.pagedispy in
5572 filledrect1 (float x0) (float y0) (float x1) (float y1);
5574 l.pagedispy + l.pagevh) 0 state
.layout
5577 and x1 = state
.winw
in
5579 and y1 = state
.winh
in
5580 filledrect1 (float x0) (float y0) (float x1) (float y1)
5581 | (Cmulti
_ | Csplit
_), _ | Csingle
_, [] ->
5582 GlClear.color (scalecolor2 conf
.bgcolor
);
5583 GlClear.clear
[`
color];
5585 List.iter
drawpage state
.layout;
5587 match state
.mode with
5588 | LinkNav
(Ltexact
(pageno, linkno
)) ->
5589 begin match getopaque pageno with
5591 let dx = xadjsb () in
5592 let x0, y0, x1, y1 = getlinkrect
opaque linkno
in
5593 let x0 = x0 + dx and x1 = x1 + dx in
5594 let color = (0.0, 0.0, 0.5, 0.5) in
5601 | None
-> state
.rects
5603 | LinkNav
(Ltgendir
_) | LinkNav
(Ltnotready
_)
5606 | View
-> state
.rects
5609 let rec postloop linkindexbase
= function
5611 let linkindexbase = linkindexbase + postdrawpage l linkindexbase in
5612 postloop linkindexbase rest
5616 postloop 0 state
.layout;
5618 begin match state
.mstate
with
5619 | Mzoomrect
((x0, y0), (x1, y1)) ->
5621 GlDraw.color (0.3, 0.3, 0.3) ~
alpha:0.5;
5622 GlFunc.blend_func ~
src:`src_alpha ~dst
:`one_minus_src_alpha
;
5623 filledrect (float x0) (float y0) (float x1) (float y1);
5627 | Mscrolly
| Mscrollx
5636 let zoomrect x y x1 y1 =
5639 and y0 = min
y y1 in
5640 gotoy (state
.y + y0);
5641 state
.anchor <- getanchor
();
5642 let zoom = (float state
.w) /. float (x1 - x0) in
5645 let adjw = wadjsb () + state
.winw
in
5647 then (adjw - state
.w) / 2
5650 match conf
.fitmodel
with
5651 | FitWidth
| FitProportional
-> simple ()
5653 match conf
.columns
with
5655 onppundermouse (fun _ l _ _ -> Some
l.pagedispx) x0 y0 x0
5656 | Cmulti
_ | Csingle
_ -> simple ()
5658 state
.x <- (state
.x + margin) - x0;
5663 let annot inline
x y =
5664 match unproject x y with
5665 | Some
(opaque, n, ux
, uy
) ->
5667 addannot
opaque ux uy
text;
5668 wcmd "freepage %s" (~
> opaque);
5669 Hashtbl.remove state
.pagemap
(n, state
.gen
);
5675 let ondone s = add s in
5676 let mode = state
.mode in
5677 state
.mode <- Textentry
(
5678 ("annotation: ", E.s, None
, textentry, ondone, true),
5679 fun _ -> state
.mode <- mode);
5682 G.postRedisplay "annot"
5684 add @@ getusertext E.s
5689 let g opaque l px py =
5690 match rectofblock
opaque px py with
5692 let x0 = a.(0) -. 20. in
5693 let x1 = a.(1) +. 20. in
5694 let y0 = a.(2) -. 20. in
5695 let zoom = (float state
.w) /. (x1 -. x0) in
5696 let pagey = getpagey
l.pageno in
5697 gotoy_and_clear_text (pagey + truncate
y0);
5698 state
.anchor <- getanchor
();
5699 let margin = (state
.w - l.pagew
)/2 in
5700 state
.x <- -truncate
x0 - margin;
5705 match conf
.columns
with
5707 impmsg "block zooming does not work properly in split columns mode"
5708 | Cmulti
_ | Csingle
_ -> onppundermouse g x y ()
5712 let winw = wadjsb () + state
.winw - 1 in
5713 let s = float x /. float winw in
5714 let destx = truncate
(float (state
.w + winw) *. s) in
5715 state
.x <- winw - destx;
5716 gotoy_and_clear_text state
.y;
5717 state
.mstate
<- Mscrollx
;
5721 let s = float y /. float state
.winh
in
5722 let desty = truncate
(float (state
.maxy - state
.winh
) *. s) in
5723 gotoy_and_clear_text desty;
5724 state
.mstate
<- Mscrolly
;
5727 let viewmulticlick clicks
x y mask
=
5728 let g opaque l px py =
5736 if markunder
opaque px py mark
5740 match getopaque l.pageno with
5742 | Some
opaque -> pipesel opaque cmd
5744 state
.roam
<- (fun () -> dopipe conf
.paxcmd
);
5745 if not
(Wsi.withctrl mask
) then dopipe conf
.selcmd
;
5750 G.postRedisplay "viewmulticlick";
5751 onppundermouse g x y (fun () -> impmsg "nothing to select") ();
5755 match conf
.columns
with
5757 | Csingle
_ | Cmulti
_ -> conf
.angle
mod 360 = 0
5760 let viewmouse button down
x y mask
=
5762 | n when (n == 4 || n == 5) && not down
->
5763 if Wsi.withctrl mask
5765 match state
.mstate
with
5766 | Mzoom
(oldn
, i
) ->
5774 if conf
.zoom +. 0.01 > 0.1 then 0.1 else 0.01
5776 if conf
.zoom -. 0.1 < 0.1 then -0.01 else -0.1
5778 let zoom = conf
.zoom -. incr in
5780 state
.mstate
<- Mzoom
(n, 0);
5782 state
.mstate
<- Mzoom
(n, i
+1);
5784 else state
.mstate
<- Mzoom
(n, 0)
5788 | Mscrolly
| Mscrollx
5790 | Mnone
-> state
.mstate
<- Mzoom
(n, 0)
5793 match state
.autoscroll
with
5794 | Some step
-> setautoscrollspeed step
(n=4)
5796 if conf
.wheelbypage
|| conf
.presentation
5805 then -conf
.scrollstep
5806 else conf
.scrollstep
5808 let incr = incr * 2 in
5809 let y = clamp incr in
5810 gotoy_and_clear_text y
5813 | n when (n = 6 || n = 7) && not down
&& canpan () ->
5815 panbound (state
.x + (if n = 7 then -2 else 2) * conf
.hscrollstep
);
5816 gotoy_and_clear_text state
.y
5818 | 1 when Wsi.withshift mask
->
5819 state
.mstate
<- Mnone
;
5822 match unproject x y with
5824 | Some
(_, pageno, ux
, uy
) ->
5825 let cmd = Printf.sprintf
5827 conf
.stcmd state
.path pageno ux uy
5829 match spawn
cmd [] with
5830 | (exception exn
) ->
5831 impmsg "execution of synctex command(%S) failed: %S"
5832 conf
.stcmd
@@ exntos exn
5836 | 1 when Wsi.withctrl mask
->
5839 Wsi.setcursor
Wsi.CURSOR_FLEUR
;
5840 state
.mstate
<- Mpan
(x, y)
5843 state
.mstate
<- Mnone
5848 if Wsi.withshift mask
5850 annot conf
.annotinline
x y;
5851 G.postRedisplay "addannot"
5855 Wsi.setcursor
Wsi.CURSOR_CYCLE
;
5856 state
.mstate
<- Mzoomrect
(p, p)
5859 match state
.mstate
with
5860 | Mzoomrect
((x0, y0), _) ->
5861 if abs
(x-x0) > 10 && abs
(y - y0) > 10
5862 then zoomrect x0 y0 x y
5865 G.postRedisplay "kill accidental zoom rect";
5869 | Mscrolly
| Mscrollx
5875 | 1 when vscrollhit x ->
5878 let _, position, sh = state
.uioh#
scrollph in
5879 if y > truncate
position && y < truncate
(position +. sh)
5880 then state
.mstate
<- Mscrolly
5883 state
.mstate
<- Mnone
5885 | 1 when y > state
.winh
- hscrollh () ->
5888 let _, position, sw = state
.uioh#scrollpw
in
5889 if x > truncate
position && x < truncate
(position +. sw)
5890 then state
.mstate
<- Mscrollx
5893 state
.mstate
<- Mnone
5895 | 1 when state
.bzoom
-> if not down
then zoomblock x y
5898 let dest = if down
then getunder x y else Unone
in
5899 begin match dest with
5902 | Uremote
_ | Uremotedest
_
5903 | Uunexpected
_ | Ulaunch
_ | Unamed
_ ->
5906 | Unone
when down
->
5907 Wsi.setcursor
Wsi.CURSOR_FLEUR
;
5908 state
.mstate
<- Mpan
(x, y);
5910 | Uannotation
(opaque, slinkindex
) -> enterannotmode opaque slinkindex
5912 | Unone
| Utext
_ ->
5917 state
.mstate
<- Msel
((x, y), (x, y));
5918 G.postRedisplay "mouse select";
5922 match state
.mstate
with
5925 | Mzoom
_ | Mscrollx
| Mscrolly
->
5926 state
.mstate
<- Mnone
5928 | Mzoomrect
((x0, y0), _) ->
5932 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
5933 state
.mstate
<- Mnone
5935 | Msel
((x0, y0), (x1, y1)) ->
5936 let rec loop = function
5940 let a0 = l.pagedispy in
5941 let a1 = a0 + l.pagevh in
5942 let b0 = l.pagedispx in
5943 let b1 = b0 + l.pagevw in
5944 ((y0 >= a0 && y0 <= a1) || (y1 >= a0 && y1 <= a1))
5945 && ((x0 >= b0 && x0 <= b1) || (x1 >= b0 && x1 <= b1))
5949 match getopaque l.pageno with
5952 match Unix.pipe
() with
5953 | (exception exn
) ->
5954 impmsg "cannot create sel pipe: %s" @@
5958 Ne.clo fd
(fun msg
->
5959 dolog
"%s close failed: %s" what msg
)
5962 try spawn
cmd [r, 0; w, -1]
5964 dolog
"cannot execute %S: %s"
5971 G.postRedisplay "copysel";
5973 else clo "Msel pipe/w" w;
5974 clo "Msel pipe/r" r;
5976 dosel conf
.selcmd
();
5977 state
.roam
<- dosel conf
.paxcmd
;
5989 let birdseyemouse button down
x y mask
5990 (conf
, leftx
, _, hooverpageno
, anchor) =
5993 let rec loop = function
5996 if y > l.pagedispy && y < l.pagedispy + l.pagevh
5997 && x > l.pagedispx && x < l.pagedispx + l.pagevw
5999 leavebirdseye (conf
, leftx
, l.pageno, hooverpageno
, anchor) false;
6005 | _ -> viewmouse button down
x y mask
6011 method key key mask
=
6012 begin match state
.mode with
6013 | Textentry
textentry -> textentrykeyboard key mask
textentry
6014 | Birdseye
birdseye -> birdseyekeyboard key mask
birdseye
6015 | View
-> viewkeyboard key mask
6016 | LinkNav
linknav -> linknavkeyboard key mask
linknav
6020 method button button bstate
x y mask
=
6021 begin match state
.mode with
6023 | View
-> viewmouse button bstate
x y mask
6024 | Birdseye beye
-> birdseyemouse button bstate
x y mask beye
6029 method multiclick clicks
x y mask
=
6030 begin match state
.mode with
6032 | View
-> viewmulticlick clicks
x y mask
6039 begin match state
.mode with
6041 | View
| Birdseye
_ | LinkNav
_ ->
6042 match state
.mstate
with
6043 | Mzoom
_ | Mnone
-> ()
6048 state
.mstate
<- Mpan
(x, y);
6050 then state
.x <- panbound (state
.x + dx);
6052 gotoy_and_clear_text y
6055 state
.mstate
<- Msel
(a, (x, y));
6056 G.postRedisplay "motion select";
6059 let y = min state
.winh
(max
0 y) in
6063 let x = min state
.winw (max
0 x) in
6066 | Mzoomrect
(p0
, _) ->
6067 state
.mstate
<- Mzoomrect
(p0
, (x, y));
6068 G.postRedisplay "motion zoomrect";
6072 method pmotion
x y =
6073 begin match state
.mode with
6074 | Birdseye
(conf
, leftx
, pageno, hooverpageno
, anchor) ->
6075 let rec loop = function
6077 if hooverpageno
!= -1
6079 state
.mode <- Birdseye
(conf
, leftx
, pageno, -1, anchor);
6080 G.postRedisplay "pmotion birdseye no hoover";
6083 if y > l.pagedispy && y < l.pagedispy + l.pagevh
6084 && x > l.pagedispx && x < l.pagedispx + l.pagevw
6086 state
.mode <- Birdseye
(conf
, leftx
, pageno, l.pageno, anchor);
6087 G.postRedisplay "pmotion birdseye hoover";
6097 match state
.mstate
with
6098 | Mpan
_ | Msel
_ | Mzoom
_ | Mscrolly
| Mscrollx
| Mzoomrect
_ -> ()
6106 let past, _, _ = !r in
6108 let delta = now -. past in
6111 else r := (now, x, y)
6115 method infochanged
_ = ()
6118 let maxy = state
.maxy - (if conf
.maxhfit
then state
.winh
else 0) in
6121 then 0.0, float state
.winh
6122 else scrollph state
.y maxy
6127 let winw = wadjsb () + state
.winw in
6128 let fwinw = float winw in
6130 let sw = fwinw /. float state
.w in
6131 let sw = fwinw *. sw in
6132 max
sw (float conf
.scrollh
)
6135 let maxx = state
.w + winw in
6136 let x = winw - state
.x in
6137 let percent = float x /. float maxx in
6138 (fwinw -. sw) *. percent
6140 hscrollh (), position, sw
6144 match state
.mode with
6145 | LinkNav
_ -> "links"
6146 | Textentry
_ -> "textentry"
6147 | Birdseye
_ -> "birdseye"
6150 findkeyhash conf
modename
6152 method eformsgs
= true
6153 method alwaysscrolly
= false
6156 let addrect pageno r g b a x0 y0 x1 y1 =
6157 Hashtbl.add state
.prects
pageno [|r; g; b; a; x0; y0; x1; y1|];
6161 let cl = splitatspace cmds
in
6163 try Scanf.sscanf
s fmt
f
6165 adderrfmt "remote exec"
6166 "error processing '%S': %s\n" cmds
@@ exntos exn
6168 let rectx s pageno (r, g, b, a) x0 y0 x1 y1 =
6169 vlog "%s page %d color (%f %f %f %f) x0,y0,x1,y1 = %f %f %f %f"
6170 s pageno r g b a x0 y0 x1 y1;
6174 let _,w1,h1
,_ = getpagedim
pageno in
6175 let sw = float w1 /. float w
6176 and sh = float h1
/. float h in
6180 and y1s
= y1 *. sh in
6181 let rect = (x0s,y0s
,x1s
,y0s
,x1s
,y1s
,x0s,y1s
) in
6182 let color = (r, g, b, a) in
6183 if conf
.verbose
then debugrect rect;
6184 state
.rects <- (pageno, color, rect) :: state
.rects;
6189 | "reload" :: [] -> reload ()
6190 | "goto" :: args
:: [] ->
6191 scan args
"%u %f %f"
6193 let cmd, _ = state
.geomcmds
in
6195 then gotopagexy !wtmode pageno x y
6198 gotopagexy !wtmode pageno x y;
6201 state
.reprf
<- f state
.reprf
6203 | "goto1" :: args
:: [] -> scan args
"%u %f" gotopage
6204 | "gotor" :: args
:: [] ->
6206 (fun filename
pageno -> gotounder (Uremote
(filename
, pageno)))
6207 | "gotord" :: args
:: [] ->
6209 (fun filename
dest -> gotounder (Uremotedest
(filename
, dest)))
6210 | "rect" :: args
:: [] ->
6211 scan args
"%u %u %f %f %f %f"
6212 (fun pageno c x0 y0 x1 y1 ->
6213 let color = (0.0, 0.0, 1.0 /. float c, 0.5) in
6214 rectx "rect" pageno color x0 y0 x1 y1;
6216 | "prect" :: args
:: [] ->
6217 scan args
"%u %f %f %f %f %f %f %f %f"
6218 (fun pageno r g b alpha x0 y0 x1 y1 ->
6219 addrect pageno r g b alpha x0 y0 x1 y1;
6220 G.postRedisplay "prect"
6222 | "pgoto" :: args
:: [] ->
6223 scan args
"%u %f %f"
6226 match getopaque pageno with
6227 | Some
opaque -> opaque
6230 pgoto optopaque pageno x y;
6231 let rec fixx = function
6234 if l.pageno = pageno
6236 state
.x <- state
.x - l.pagedispx;
6243 match conf
.columns
with
6244 | Csingle
_ | Csplit
_ -> 1
6245 | Cmulti
((n, _, _), _) -> n
6247 layout 0 state
.y (state
.winw * mult) state
.winh
6251 | "activatewin" :: [] -> Wsi.activatewin
()
6252 | "quit" :: [] -> raise Quit
6253 | "clearrects" :: [] ->
6254 Hashtbl.clear state
.prects
;
6255 G.postRedisplay "clearrects"
6257 adderrfmt "remote command"
6258 "error processing remote command: %S\n" cmds
;
6262 let scratch = Bytes.create
80 in
6263 let buf = Buffer.create
80 in
6265 match tempfailureretry
(Unix.read fd
scratch 0) 80 with
6266 | (exception Unix.Unix_error
(Unix.EAGAIN
, _, _)) -> None
6269 if Buffer.length
buf > 0
6271 let s = Buffer.contents
buf in
6279 match Bytes.index_from
scratch ppos '
\n'
with
6280 | pos -> if pos >= n then -1 else pos
6281 | (exception Not_found
) -> -1
6285 Buffer.add_subbytes
buf scratch ppos
(nlpos-ppos
);
6286 let s = Buffer.contents
buf in
6292 Buffer.add_subbytes
buf scratch ppos
(n-ppos
);
6298 let remoteopen path =
6299 try Some
(Unix.openfile
path [Unix.O_NONBLOCK
; Unix.O_RDONLY
] 0o0)
6301 adderrfmt "remoteopen" "error opening %S: %s" path @@ exntos exn
;
6306 let gcconfig = ref E.s in
6307 let trimcachepath = ref E.s in
6308 let rcmdpath = ref E.s in
6309 let pageno = ref None
in
6310 let rootwid = ref 0 in
6311 let openlast = ref false in
6312 let nofc = ref false in
6313 let doreap = ref false in
6314 selfexec := Sys.executable_name
;
6317 [("-p", Arg.String
(fun s -> state
.password <- s),
6318 "<password> Set password");
6322 Config.fontpath
:= s;
6323 selfexec := !selfexec ^
" -f " ^
Filename.quote
s;
6325 "<path> Set path to the user interface font");
6329 selfexec := !selfexec ^
" -c " ^
Filename.quote
s;
6330 Config.confpath
:= s),
6331 "<path> Set path to the configuration file");
6333 ("-last", Arg.Set
openlast, " Open last document");
6335 ("-page", Arg.Int
(fun pageno1
-> pageno := Some
(pageno1
-1)),
6336 "<page-number> Jump to page");
6338 ("-tcf", Arg.String
(fun s -> trimcachepath := s),
6339 "<path> Set path to the trim cache file");
6341 ("-dest", Arg.String
(fun s -> state
.nameddest
<- s),
6342 "<named-destination> Set named destination");
6344 ("-wtmode", Arg.Set
wtmode, " Operate in wt mode");
6345 ("-cxack", Arg.Set
cxack, " Cut corners");
6347 ("-remote", Arg.String
(fun s -> rcmdpath := s),
6348 "<path> Set path to the remote commands source");
6350 ("-origin", Arg.String
(fun s -> state
.origin
<- s),
6351 "<original-path> Set original path");
6353 ("-gc", Arg.Set_string
gcconfig,
6354 "<script-path> Collect garbage with the help of a script");
6356 ("-nofc", Arg.Set
nofc, " Do not use fontconfig");
6358 ("-v", Arg.Unit
(fun () ->
6360 "%s\nconfiguration path: %s\n"
6364 exit
0), " Print version and exit");
6366 ("-embed", Arg.Set_int
rootwid,
6367 "<window-id> Embed into window")
6370 (fun s -> state
.path <- s)
6371 ("Usage: " ^
Sys.argv
.(0) ^
" [options] some.pdf\nOptions:")
6374 then selfexec := !selfexec ^
" -wtmode";
6376 let histmode = emptystr state
.path && not
!openlast in
6378 if not
(Config.load !openlast)
6379 then dolog
"failed to load configuration";
6380 begin match !pageno with
6381 | Some
pageno -> state
.anchor <- (pageno, 0.0, 0.0)
6385 if nonemptystr
!gcconfig
6388 match Unix.socketpair
Unix.PF_UNIX
Unix.SOCK_STREAM
0 with
6389 | (exception exn
) -> error
"socketpair for gc failed: %s" @@ exntos exn
6392 match spawn
!gcconfig [(c, 0); (c, 1); (s, -1)] with
6393 | (exception exn
) -> error
"failed to execute gc script: %s" @@ exntos exn
6395 Ne.clo c @@ (fun s -> error
"failed to close gc fd %s" s);
6400 let wsfd, winw, winh
= Wsi.init
(object (self)
6401 val mutable m_clicks
= 0
6402 val mutable m_click_x
= 0
6403 val mutable m_click_y
= 0
6404 val mutable m_lastclicktime
= infinity
6406 method private cleanup =
6407 state
.roam
<- noroam
;
6408 Hashtbl.iter
(fun _ opaque -> clearmark
opaque) state
.pagemap
6409 method expose
= G.postRedisplay "expose"
6413 | Wsi.Unobscured
-> "unobscured"
6414 | Wsi.PartiallyObscured
-> "partiallyobscured"
6415 | Wsi.FullyObscured
-> "fullyobscured"
6417 vlog "visibility change %s" name
6418 method display = display ()
6419 method map mapped
= vlog "mapped %b" mapped
6420 method reshape w h =
6423 method mouse
b d x y m =
6424 if d && canselect ()
6426 (* http://blogs.msdn.com/b/oldnewthing/archive/2004/10/18/243925.aspx *)
6432 if abs
x - m_click_x
> 10
6433 || abs
y - m_click_y
> 10
6434 || abs_float
(t -. m_lastclicktime
) > 0.3
6436 m_clicks
<- m_clicks
+ 1;
6437 m_lastclicktime
<- t;
6441 G.postRedisplay "cleanup";
6442 state
.uioh <- state
.uioh#button
b d x y m;
6444 else state
.uioh <- state
.uioh#multiclick m_clicks
x y m
6449 m_lastclicktime
<- infinity
;
6450 state
.uioh <- state
.uioh#button
b d x y m
6454 state
.uioh <- state
.uioh#button
b d x y m
6457 state
.mpos
<- (x, y);
6458 state
.uioh <- state
.uioh#motion
x y
6459 method pmotion
x y =
6460 state
.mpos
<- (x, y);
6461 state
.uioh <- state
.uioh#pmotion
x y
6463 let mascm = m land (
6464 Wsi.altmask
+ Wsi.shiftmask
+ Wsi.ctrlmask
+ Wsi.metamask
6467 let x = state
.x and y = state
.y in
6469 if x != state
.x || y != state
.y then self#
cleanup
6471 match state
.keystate
with
6473 let km = k
, mascm in
6476 let modehash = state
.uioh#
modehash in
6477 try Hashtbl.find modehash km
6479 try Hashtbl.find (findkeyhash conf
"global") km
6480 with Not_found
-> KMinsrt
(k
, m)
6482 | KMinsrt
(k
, m) -> keyboard k
m
6483 | KMinsrl
l -> List.iter
(fun (k
, m) -> keyboard k
m) l
6484 | KMmulti
(l, r) -> state
.keystate
<- KSinto
(l, r)
6486 | KSinto
((k'
, m'
) :: [], insrt
) when k'
=k
&& m'
land mascm = m'
->
6487 List.iter
(fun (k
, m) -> keyboard k
m) insrt
;
6488 state
.keystate
<- KSnone
6489 | KSinto
((k'
, m'
) :: keys, insrt
) when k'
=k
&& m'
land mascm = m'
->
6490 state
.keystate
<- KSinto
(keys, insrt
)
6491 | KSinto
_ -> state
.keystate
<- KSnone
6494 state
.mpos
<- (x, y);
6495 state
.uioh <- state
.uioh#pmotion
x y
6496 method leave = state
.mpos
<- (-1, -1)
6497 method winstate wsl
= state
.winstate
<- wsl
6498 method quit
= raise Quit
6499 end) !rootwid conf
.cwinw conf
.cwinh platform
in
6501 setbgcol conf
.bgcolor
;
6505 List.exists
GlMisc.check_extension
6506 [ "GL_ARB_texture_rectangle"
6507 ; "GL_EXT_texture_recangle"
6508 ; "GL_NV_texture_rectangle" ]
6510 then (dolog
"OpenGL does not suppport rectangular textures"; exit
1);
6513 let r = GlMisc.get_string `renderer
in
6514 let p = "Mesa DRI Intel(" in
6515 let l = String.length
p in
6516 String.length
r > l && String.sub
r 0 l = p
6519 defconf
.sliceheight
<- 1024;
6520 defconf
.texcount
<- 32;
6521 defconf
.usepbo
<- true;
6525 match Unix.socketpair
Unix.PF_UNIX
Unix.SOCK_STREAM
0 with
6526 | (exception exn
) ->
6527 dolog
"socketpair failed: %s" @@ exntos exn
;
6535 setcheckers conf
.checkers
;
6537 opengl_has_pbo := GlMisc.check_extension
"GL_ARB_pixel_buffer_object";
6540 conf
.angle
, conf
.fitmodel
, (conf
.trimmargins
, conf
.trimfuzz
),
6541 conf
.texcount
, conf
.sliceheight
, conf
.mustoresize
, conf
.colorspace
,
6542 !Config.fontpath
, !trimcachepath,
6546 List.iter
GlArray.enable
[`texture_coord
; `vertex
];
6548 reshape ~firsttime
:true winw winh
;
6552 Wsi.settitle
"llpp (history)";
6556 state
.text <- "Opening " ^
(mbtoutf8 state
.path);
6557 opendoc state
.path state
.password;
6561 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
6562 Sys.set_signal
Sys.sighup
(Sys.Signal_handle
(fun _ -> reload ()));
6565 match Unix.waitpid
[Unix.WNOHANG
] ~
-1 with
6566 | (exception (Unix.Unix_error
(Unix.ECHILD
, _, _))) -> ()
6567 | (exception exn
) -> dolog
"Unix.waitpid: %s" @@ exntos exn
6569 | _pid
, _status
-> reap ()
6571 Sys.set_signal
Sys.sigchld
(Sys.Signal_handle
(fun _ -> doreap := true));
6575 if nonemptystr
!rcmdpath
6576 then remoteopen !rcmdpath
6581 let rec loop deadline
=
6587 let r = [state
.ss; state
.wsfd] in
6591 | Some fd
-> fd
:: r
6595 state
.redisplay
<- false;
6602 if deadline
= infinity
6604 else max
0.0 (deadline
-. now)
6609 try Unix.select
r [] [] timeout
6610 with Unix.Unix_error
(Unix.EINTR
, _, _) -> [], [], []
6616 if state
.ghyll
== noghyll
6618 match state
.autoscroll
with
6619 | Some step
when step
!= 0 ->
6620 let y = state
.y + step
in
6621 let fy = if conf
.maxhfit
then state
.winh
else 0 in
6624 then state
.maxy - fy
6625 else if y >= state
.maxy - fy then 0 else y
6627 if state
.mode = View
6628 then gotoy_and_clear_text y
6632 else deadline
+. 0.01
6637 let rec checkfds = function
6639 | fd
:: rest
when fd
= state
.ss ->
6640 let cmd = rcmd state
.ss in
6644 | fd
:: rest
when fd
= state
.wsfd ->
6648 | fd
:: rest
when Some fd
= !optrfd ->
6649 begin match remote fd
with
6650 | None
-> optrfd := remoteopen !rcmdpath;
6651 | opt -> optrfd := opt
6656 dolog
"select returned unknown descriptor";
6662 if deadline
= infinity
6666 match state
.autoscroll
with
6667 | Some step
when step
!= 0 -> deadline1
6668 | _ -> if state
.ghyll
== noghyll
then infinity
else deadline1
6676 Config.save leavebirdseye;
6677 if hasunsavedchanges
()