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 =
52 let selfexec = ref E.s
;;
53 let opengl_has_pbo = ref false;;
55 let drawstring size x y s
=
57 Gl.enable `texture_2d
;
58 GlFunc.blend_func ~src
:`src_alpha ~dst
:`one_minus_src_alpha
;
59 ignore
(drawstr size x y s
);
61 Gl.disable `texture_2d
;
64 let drawstring1 size x y s
=
68 let drawstring2 size x y fmt
=
69 Printf.kprintf
(drawstring size
(x
+1) (y
+size
+1)) fmt
73 dolog
"l %d dim=%d {" l
.pageno l
.pagedimno
;
74 dolog
" WxH %dx%d" l
.pagew l
.pageh
;
75 dolog
" vWxH %dx%d" l
.pagevw l
.pagevh
;
76 dolog
" pagex,y %d,%d" l
.pagex l
.pagey
;
77 dolog
" dispx,y %d,%d" l
.pagedispx l
.pagedispy
;
78 dolog
" column %d" l
.pagecol
;
82 let debugrect (x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
) =
84 dolog
" x0,y0=(% f, % f)" x0 y0
;
85 dolog
" x1,y1=(% f, % f)" x1 y1
;
86 dolog
" x2,y2=(% f, % f)" x2 y2
;
87 dolog
" x3,y3=(% f, % f)" x3 y3
;
91 let isbirdseye = function
98 let istextentry = function
105 let wtmode = ref false;;
106 let cxack = ref false;;
108 let pgscale h
= truncate
(float h
*. conf
.pgscale);;
111 if not state
.uioh#alwaysscrolly
&& (conf
.scrollb
land scrollbhv
= 0)
112 || (state
.x
= 0 && state
.w
<= state
.winw
- conf
.scrollbw
)
118 if not state
.uioh#alwaysscrolly
&& (conf
.scrollb
land scrollbvv
= 0)
126 else x
> state
.winw
- vscrollw ()
129 let wadjsb () = -vscrollw ();;
130 let xadjsb () = if conf
.leftscroll
then vscrollw () else 0;;
133 fstate
.fontsize
<- n
;
134 fstate
.wwidth
<- measurestr fstate
.fontsize
"w";
135 fstate
.maxrows
<- (state
.winh
- fstate
.fontsize
- 1) / (fstate
.fontsize
+ 1);
141 else Printf.kprintf ignore fmt
145 if emptystr conf
.pathlauncher
146 then dolog
"%s" state
.path
148 let command = Str.global_replace percentsre state
.path conf
.pathlauncher
in
149 match spawn
command [] with
152 dolog
"failed to execute `%s': %s" command @@ exntos exn
158 let postRedisplay who
=
159 vlog "redisplay for [%S]" who
;
160 state
.redisplay
<- true;
164 let getopaque pageno
=
165 try Some
(Hashtbl.find state
.pagemap
(pageno
, state
.gen
))
166 with Not_found
-> None
169 let pagetranslatepoint l x y
=
170 let dy = y
- l
.pagedispy
in
171 let y = dy + l
.pagey
in
172 let dx = x
- l
.pagedispx
in
173 let x = dx + l
.pagex
in
177 let onppundermouse g
x y d
=
180 begin match getopaque l
.pageno
with
182 let x0 = l
.pagedispx
in
183 let x1 = x0 + l
.pagevw
in
184 let y0 = l
.pagedispy
in
185 let y1 = y0 + l
.pagevh
in
186 if y >= y0 && y <= y1 && x >= x0 && x <= x1
188 let px, py
= pagetranslatepoint l
x y in
189 match g opaque l
px py
with
202 let g opaque l
px py
=
205 match rectofblock opaque
px py
with
206 | Some
[|x0;x1;y0;y1|] ->
207 let ox = xadjsb () |> float in
208 let rect = (x0+.ox, y0, x1+.ox, y0, x1+.ox, y1, x0+.ox, y1) in
209 let color = (0.0, 0.0, 1.0 /. (l
.pageno
mod 3 |> float), 0.5) in
210 state
.rects
<- [l
.pageno
, color, rect];
211 G.postRedisplay "getunder";
214 let under = whatsunder opaque
px py
in
215 if under = Unone
then None
else Some
under
217 onppundermouse g x y Unone
222 match unproject opaque
x y with
223 | Some
(x, y) -> Some
(Some
(opaque
, l
.pageno
, x, y))
226 onppundermouse g x y None
;
230 state
.text
<- Printf.sprintf
"%c%s" c s
;
231 G.postRedisplay "showtext";
235 Format.ksprintf
(fun s
-> showtext '
!' s
) fmt
;
238 let pipesel opaque cmd
=
241 match Unix.pipe
() with
242 | (exception exn
) -> dolog
"pipesel cannot create pipe: %S" @@ exntos exn
;
244 let doclose what fd
=
245 Ne.clo fd
(fun msg
-> dolog
"%s close failed: %s" what msg
)
248 try spawn cmd
[r
, 0; w
, -1]
250 dolog
"cannot execute %S: %s" cmd
@@ exntos exn
;
256 G.postRedisplay "pipesel";
258 else doclose "pipesel pipe/w" w
;
259 doclose "pipesel pipe/r" r
;
263 let g opaque l
px py
=
264 if markunder opaque
px py conf
.paxmark
267 match getopaque l
.pageno
with
269 | Some opaque
-> pipesel opaque conf
.paxcmd
274 G.postRedisplay "paxunder";
275 if conf
.paxmark
= Mark_page
278 match getopaque l
.pageno
with
280 | Some opaque
-> clearmark opaque
) state
.layout
;
281 state
.roam
<- onppundermouse g x y (fun () -> impmsg "whoopsie daisy");
285 match Unix.pipe
() with
286 | (exception exn
) -> impmsg "pipe failed: %s" @@ exntos exn
289 Ne.clo fd
(fun msg
-> impmsg "failed to close %s: %s" cap msg
)
292 try spawn conf
.selcmd
[r
, 0; w
, -1]
294 impmsg "failed to execute %s: %s" conf
.selcmd
@@ exntos exn
;
300 let l = String.length s
in
301 let bytes = Bytes.unsafe_of_string s
in
302 let n = tempfailureretry
(Unix.write w
bytes 0) l in
304 then impmsg "failed to write %d characters to sel pipe, wrote %d"
307 impmsg "failed to write to sel pipe: %s" @@ exntos exn
310 clo "selstring pipe/r" r
;
311 clo "selstring pipe/w" w
;
314 let undertext ?
(nopath
=false) = function
317 | Ulinkgoto
(pageno
, _
) ->
319 then "page " ^ string_of_int
(pageno
+1)
320 else Printf.sprintf
"%s: page %d" state
.path
(pageno
+1)
321 | Utext s
-> "font: " ^ s
322 | Uunexpected s
-> "unexpected: " ^ s
323 | Ulaunch s
-> "launch: " ^ s
324 | Unamed s
-> "named: " ^ s
325 | Uremote
(filename
, pageno
) ->
326 Printf.sprintf
"%s: page %d" filename
(pageno
+1)
327 | Uremotedest
(filename
, destname
) ->
328 Printf.sprintf
"%s: destination %S" filename destname
329 | Uannotation
(opaque
, slinkindex
) ->
330 "annotation: " ^ getannotcontents opaque slinkindex
333 let updateunder x y =
334 match getunder x y with
335 | Unone
-> Wsi.setcursor
Wsi.CURSOR_INHERIT
337 if conf
.underinfo
then showtext 'u'
("ri: " ^ uri
);
338 Wsi.setcursor
Wsi.CURSOR_INFO
339 | Ulinkgoto
(pageno
, _
) ->
341 then showtext 'p'
("age: " ^ string_of_int
(pageno
+1));
342 Wsi.setcursor
Wsi.CURSOR_INFO
344 if conf
.underinfo
then showtext '
f'
("ont: " ^ s
);
345 Wsi.setcursor
Wsi.CURSOR_TEXT
347 if conf
.underinfo
then showtext 'u'
("nexpected: " ^ s
);
348 Wsi.setcursor
Wsi.CURSOR_INHERIT
350 if conf
.underinfo
then showtext '
l'
("aunch: " ^ s
);
351 Wsi.setcursor
Wsi.CURSOR_INHERIT
353 if conf
.underinfo
then showtext '
n'
("amed: " ^ s
);
354 Wsi.setcursor
Wsi.CURSOR_INHERIT
355 | Uremote
(filename
, pageno
) ->
356 if conf
.underinfo
then showtext 'r'
357 (Printf.sprintf
"emote: %s (%d)" filename
(pageno
+1));
358 Wsi.setcursor
Wsi.CURSOR_INFO
359 | Uremotedest
(filename
, destname
) ->
360 if conf
.underinfo
then showtext 'r'
361 (Printf.sprintf
"emote destination: %s (%S)" filename destname
);
362 Wsi.setcursor
Wsi.CURSOR_INFO
364 if conf
.underinfo
then showtext 'a'
"nnotation";
365 Wsi.setcursor
Wsi.CURSOR_INFO
368 let showlinktype under =
369 if conf
.underinfo
&& under != Unone
370 then showtext ' '
@@ undertext under
373 let intentry_with_suffix text key
=
375 if key
>= 32 && key
< 127
379 match Char.lowercase
c with
381 let text = addchar
text c in
385 let text = addchar
text c in
389 state
.text <- Printf.sprintf
"invalid char (%d, `%c')" key
c;
394 let s = Bytes.create
4 in
395 let n = tempfailureretry
(Unix.read fd
s 0) 4 in
396 if n != 4 then error
"incomplete read(len) = %d" n;
397 let len = (Char.code
(Bytes.get
s 0) lsl 24)
398 lor (Char.code
(Bytes.get
s 1) lsl 16)
399 lor (Char.code
(Bytes.get
s 2) lsl 8)
400 lor (Char.code
(Bytes.get
s 3))
402 let s = Bytes.create
len in
403 let n = tempfailureretry
(Unix.read fd
s 0) len in
404 if n != len then error
"incomplete read(data) %d vs %d" n len;
409 let b = Buffer.create
16 in
410 Buffer.add_string
b "llll";
413 let s = Buffer.to_bytes
b in
414 let n = Bytes.length
s in
416 (* dolog "wcmd %S" (String.sub s 4 len); *)
417 Bytes.set
s 0 (Char.chr
((len lsr 24) land 0xff));
418 Bytes.set
s 1 (Char.chr
((len lsr 16) land 0xff));
419 Bytes.set
s 2 (Char.chr
((len lsr 8) land 0xff));
420 Bytes.set
s 3 (Char.chr
(len land 0xff));
421 let n'
= tempfailureretry
(Unix.write state
.ss
s 0) n in
422 if n'
!= n then error
"write failed %d vs %d" n'
n;
426 let nogeomcmds cmds
=
428 | s, [] -> emptystr
s
432 let layoutN ((columns
, coverA
, coverB
), b) x y sw sh
=
433 let sh = sh - (hscrollh ()) in
434 let wadj = wadjsb () in
435 let rec fold accu
n =
436 if n = Array.length
b
439 let pdimno, dx, vy
, (_
, w
, h
, xoff
) = b.(n) in
442 || n = state
.pagecount
- coverB
443 || (n - coverA
) mod columns
= columns
- 1)
449 let pagey = max
0 (y - vy
) in
450 let pagedispy = if pagey > 0 then 0 else vy
- y in
451 let pagedispx, pagex
=
453 if n = coverA
- 1 || n = state
.pagecount
- coverB
454 then x + (wadj + sw
- w
) / 2
462 let vw = wadj + sw
- pagedispx in
463 let pw = w
- pagex
in
466 let pagevh = min
(h
- pagey) (sh - pagedispy) in
467 if pagevw > 0 && pagevh > 0
478 ; pagedispx = pagedispx
479 ; pagedispy = pagedispy
491 if Array.length
b = 0
493 else List.rev
(fold [] (page_of_y
y))
496 let layoutS (columns
, b) x y sw
sh =
497 let sh = sh - hscrollh () in
498 let wadj = wadjsb () in
499 let rec fold accu n =
500 if n = Array.length
b
503 let pdimno, px, vy
, (_
, pagew
, pageh
, xoff
) = b.(n) in
511 let pagey = max
0 (y - vy
) in
512 let pagedispy = if pagey > 0 then 0 else vy
- y in
513 let pagedispx, pagex
=
527 let pagecolw = pagew
/columns
in
530 then pagedispx + ((wadj + sw
- pagecolw) / 2)
534 let vw = wadj + sw
- pagedispx in
535 let pw = pagew
- pagex
in
538 let pagevw = min
pagevw pagecolw in
539 let pagevh = min
(pageh
- pagey) (sh - pagedispy) in
540 if pagevw > 0 && pagevh > 0
551 ; pagedispx = pagedispx
552 ; pagedispy = pagedispy
553 ; pagecol
= n mod columns
567 let layout x y sw
sh =
568 if nogeomcmds state
.geomcmds
570 match conf
.columns
with
571 | Csingle
b -> layoutN ((1, 0, 0), b) x y sw
sh
572 | Cmulti
c -> layoutN c x y sw
sh
573 | Csplit
s -> layoutS s x y sw
sh
578 let y = state
.y + incr
in
580 let y = min
y (state
.maxy
- (if conf
.maxhfit
then state
.winh
else 0)) in
585 let tilex = l.pagex
mod conf
.tilew
in
586 let tiley = l.pagey mod conf
.tileh
in
588 let col = l.pagex
/ conf
.tilew
in
589 let row = l.pagey / conf
.tileh
in
591 let xadj = xadjsb () in
592 let rec rowloop row y0 dispy h
=
596 let dh = conf
.tileh
- y0 in
598 let rec colloop col x0 dispx w
=
602 let dw = conf
.tilew
- x0 in
604 let dispx'
= xadj + dispx in
605 f col row dispx' dispy
x0 y0 dw dh;
606 colloop (col+1) 0 (dispx+dw) (w
-dw)
609 colloop col tilex l.pagedispx l.pagevw;
610 rowloop (row+1) 0 (dispy
+dh) (h
-dh)
613 if l.pagevw > 0 && l.pagevh > 0
614 then rowloop row tiley l.pagedispy l.pagevh;
617 let gettileopaque l col row =
619 l.pageno
, state
.gen
, conf
.colorspace
, conf
.angle
, l.pagew
, l.pageh
, col, row
621 try Some
(Hashtbl.find state
.tilemap
key)
622 with Not_found
-> None
625 let puttileopaque l col row gen colorspace angle opaque size elapsed
=
626 let key = l.pageno
, gen
, colorspace
, angle
, l.pagew
, l.pageh
, col, row in
627 Hashtbl.add state
.tilemap
key (opaque
, size
, elapsed
)
630 let filledrect1 x0 y0 x1 y1 =
631 Raw.sets_float state
.vraw ~pos
:0 [| x0; y0; x0; y1; x1; y0; x1; y1 |];
632 GlArray.vertex `two state
.vraw
;
633 GlArray.draw_arrays `triangle_strip ~first
:0 ~count
:4;
636 let filledrect x0 y0 x1 y1 =
637 GlArray.disable `texture_coord
;
638 filledrect1 x0 y0 x1 y1;
639 GlArray.enable `texture_coord
;
642 let linerect x0 y0 x1 y1 =
643 GlArray.disable `texture_coord
;
644 Raw.sets_float state
.vraw ~pos
:0 [| x0; y0; x0; y1; x1; y1; x1; y0 |];
645 GlArray.vertex `two state
.vraw
;
646 GlArray.draw_arrays `line_loop ~first
:0 ~count
:4;
647 GlArray.enable `texture_coord
;
650 let drawtiles l color =
652 let wadj = wadjsb () in
654 let f col row x y tilex tiley w h
=
655 match gettileopaque l col row with
656 | Some
(opaque
, _
, t
) ->
657 let params = x, y, w
, h
, tilex, tiley in
659 then GlTex.env
(`mode `blend
);
660 drawtile
params opaque
;
662 then GlTex.env
(`mode `modulate
);
666 let s = Printf.sprintf
670 let w = measurestr fstate
.fontsize
s in
671 GlDraw.color (0.0, 0.0, 0.0);
672 filledrect (float (x-2))
675 (float (y + fstate
.fontsize
+ 2));
677 drawstring fstate
.fontsize
x (y + fstate
.fontsize
- 1) s;
687 let lw = wadj + state
.winw
- x in
690 let lh = state
.winh
- y in
694 then GlTex.env
(`mode `blend
);
695 begin match state
.checkerstexid
with
697 Gl.enable `texture_2d
;
698 GlTex.bind_texture ~target
:`texture_2d id
;
702 and y1 = float (y+h
) in
704 let tw = float w /. 16.0
705 and th
= float h
/. 16.0 in
706 let tx0 = float tilex /. 16.0
707 and ty0
= float tiley /. 16.0 in
709 and ty1
= ty0
+. th
in
710 Raw.sets_float state
.vraw ~pos
:0
711 [| x0; y0; x0; y1; x1; y0; x1; y1 |];
712 Raw.sets_float state
.traw ~pos
:0
713 [| tx0; ty0
; tx0; ty1
; tx1; ty0
; tx1; ty1
|];
714 GlArray.vertex `two state
.vraw
;
715 GlArray.tex_coord `two state
.traw
;
716 GlArray.draw_arrays `triangle_strip ~first
:0 ~count
:4;
717 Gl.disable `texture_2d
;
720 GlDraw.color (1.0, 1.0, 1.0);
721 filledrect (float x) (float y) (float (x+w)) (float (y+h
));
724 then GlTex.env
(`mode `modulate
);
725 if w > 128 && h
> fstate
.fontsize
+ 10
727 let c = if conf
.invert
then 1.0 else 0.0 in
728 GlDraw.color (c, c, c);
731 then (col*conf
.tilew
, row*conf
.tileh
)
734 drawstring2 fstate
.fontsize
x y "Loading %d [%d,%d]" l.pageno
c r
;
743 let pagevisible layout n = List.exists
(fun l -> l.pageno
= n) layout;;
745 let tilevisible1 l x y =
747 and ax1
= l.pagex
+ l.pagevw
749 and ay1
= l.pagey + l.pagevh in
753 let bx1 = min
(bx0 + conf
.tilew
) l.pagew
754 and by1
= min
(by0
+ conf
.tileh
) l.pageh
in
756 let rx0 = max
ax0 bx0
757 and ry0
= max ay0 by0
758 and rx1
= min ax1
bx1
759 and ry1
= min ay1 by1
in
761 let nonemptyintersection = rx1
> rx0 && ry1
> ry0
in
765 let tilevisible layout n x y =
766 let rec findpageinlayout m
= function
767 | l :: rest
when l.pageno
= n ->
768 tilevisible1 l x y || (
769 match conf
.columns
with
770 | Csplit
(c, _
) when c > m
-> findpageinlayout (m
+1) rest
775 | _
:: rest
-> findpageinlayout 0 rest
778 findpageinlayout 0 layout;
781 let tileready l x y =
782 tilevisible1 l x y &&
783 gettileopaque l (x/conf
.tilew
) (y/conf
.tileh
) != None
786 let tilepage n p
layout =
787 let rec loop = function
791 let f col row _ _ _ _ _ _
=
792 if state
.currently
= Idle
794 match gettileopaque l col row with
797 let x = col*conf
.tilew
798 and y = row*conf
.tileh
in
800 let w = l.pagew
- x in
804 let h = l.pageh
- y in
809 then getpbo
w h conf
.colorspace
812 wcmd "tile %s %d %d %d %d %s"
813 (~
> p
) x y w h (~
> pbo);
816 l, p
, conf
.colorspace
, conf
.angle
,
817 state
.gen
, col, row, conf
.tilew
, conf
.tileh
826 if nogeomcmds state
.geomcmds
830 let preloadlayout x y sw
sh =
831 let y = if y < sh then 0 else y - sh in
832 let x = min
0 (x + sw
) in
840 if state
.currently
!= Idle
845 begin match getopaque l.pageno
with
847 wcmd "page %d %d" l.pageno
l.pagedimno
;
848 state
.currently
<- Loading
(l, state
.gen
);
850 tilepage l.pageno opaque pages
;
855 if nogeomcmds state
.geomcmds
861 if conf
.preload && state
.currently
= Idle
862 then load (preloadlayout state
.x state
.y state
.winw state
.winh
);
865 let layoutready layout =
866 let rec fold all ls
=
869 let seen = ref false in
870 let allvisible = ref true in
871 let foo col row _ _ _ _ _ _
=
873 allvisible := !allvisible &&
874 begin match gettileopaque l col row with
880 fold (!seen && !allvisible) rest
883 let alltilesvisible = fold true layout in
888 let y = bound
y 0 state
.maxy
in
889 let y, layout, proceed
=
890 match conf
.maxwait
with
891 | Some time
when state
.ghyll
== noghyll
->
892 begin match state
.throttle
with
894 let layout = layout state
.x y state
.winw state
.winh
in
895 let ready = layoutready layout in
899 state
.throttle
<- Some
(layout, y, now
());
901 else G.postRedisplay "gotoy showall (None)";
903 | Some
(_
, _
, started
) ->
904 let dt = now
() -. started
in
907 state
.throttle
<- None
;
908 let layout = layout state
.x y state
.winw state
.winh
in
910 G.postRedisplay "maxwait";
917 let layout = layout state
.x y state
.winw state
.winh
in
918 if not
!wtmode || layoutready layout
919 then G.postRedisplay "gotoy ready";
925 state
.layout <- layout;
926 begin match state
.mode
with
929 | Ltexact
(pageno
, linkno
) ->
930 let rec loop = function
932 state
.mode
<- LinkNav
(Ltgendir
0)
933 | l :: _
when l.pageno
= pageno
->
934 begin match getopaque pageno
with
935 | None
-> state
.mode
<- LinkNav
(Ltnotready
(pageno
, 0))
937 let x0, y0, x1, y1 = getlinkrect opaque linkno
in
938 if not
(x0 >= l.pagex
&& x1 <= l.pagex
+ l.pagevw
939 && y0 >= l.pagey && y1 <= l.pagey + l.pagevh)
940 then state
.mode
<- LinkNav
(Ltgendir
0)
942 | _
:: rest
-> loop rest
945 | Ltnotready _
| Ltgendir _
-> ()
951 begin match state
.mode
with
952 | Birdseye
(conf
, leftx
, pageno
, hooverpageno
, anchor
) ->
953 if not
(pagevisible layout pageno
)
955 match state
.layout with
958 state
.mode
<- Birdseye
(
959 conf
, leftx
, l.pageno
, hooverpageno
, anchor
964 | Ltnotready
(_
, dir
)
967 let rec loop = function
970 match getopaque l.pageno
with
971 | None
-> Ltnotready
(l.pageno
, dir
)
976 then LDfirstvisible
(l.pagex
, l.pagey, dir
)
978 if dir
> 0 then LDfirst
else LDlast
984 | Lnotfound
-> loop rest
986 showlinktype (getlink opaque
n);
987 Ltexact
(l.pageno
, n)
991 state
.mode
<- LinkNav
linknav
999 state
.ghyll
<- noghyll
;
1002 let mx, my
= state
.mpos
in
1007 let conttiling pageno opaque
=
1008 tilepage pageno opaque
1010 then preloadlayout state
.x state
.y state
.winw state
.winh
1014 let gotoy_and_clear_text y =
1015 if not conf
.verbose
then state
.text <- E.s;
1019 let getanchory (n, top
, dtop
) =
1020 let y, h = getpageyh
n in
1021 if conf
.presentation
1023 let ips = calcips
h in
1024 y + truncate
(top
*.float h -. dtop
*.float ips) + ips;
1026 y + truncate
(top
*.float h -. dtop
*.float conf
.interpagespace
)
1029 let gotoanchor anchor
=
1030 gotoy (getanchory anchor
);
1034 cbput state
.hists
.nav
(getanchor
());
1038 let anchor = cbgetc state
.hists
.nav dir
in
1042 let gotoghyll1 single
y =
1043 let scroll f n a
b =
1044 (* http://devmaster.net/forums/topic/9796-ease-in-ease-out-algorithm/ *)
1046 let s x = 3.0*.x**2.0 -. 2.0*.x**3.0 in
1048 then s (float f /. float a
)
1051 then 1.0 -. s ((float (f-b) /. float (n-b)))
1057 let ins = float a
*. 0.5
1058 and outs
= float (n-b) *. 0.5 in
1060 ins +. outs
+. float ones
1062 let rec set nab
y sy
=
1063 let (_N
, _A
, _B
), y =
1066 let scl = if y > sy
then 2 else -2 in
1067 let _N, _
, _
= nab
in
1068 (_N,0,_N), y+conf
.scrollstep
*scl
1070 let sum = summa
_N _A _B
in
1071 let dy = float (y - sy
) in
1075 then state
.ghyll
<- noghyll
1078 let s = scroll n _N _A _B
in
1079 let y1 = y1 +. ((s *. dy) /. sum) in
1080 gotoy_and_clear_text (truncate
y1);
1081 state
.ghyll
<- gf (n+1) y1;
1085 | Some
y'
when single
-> set nab
y' state
.y
1086 | Some
y'
-> set (_N/2, 1, 1) y' state
.y
1088 gf 0 (float state
.y)
1091 match conf
.ghyllscroll
with
1092 | Some nab
when not conf
.presentation
->
1093 if state
.ghyll
== noghyll
1094 then set nab
y state
.y
1095 else state
.ghyll
(Some
y)
1097 gotoy_and_clear_text y
1100 let gotoghyll = gotoghyll1 false;;
1102 let gotopage n top
=
1103 let y, h = getpageyh
n in
1104 let y = y + (truncate
(top
*. float h)) in
1108 let gotopage1 n top
=
1109 let y = getpagey
n in
1114 let invalidate s f =
1119 match state
.geomcmds
with
1120 | ps
, [] when emptystr ps
->
1122 state
.geomcmds
<- s, [];
1125 state
.geomcmds
<- ps
, [s, f];
1127 | ps
, (s'
, _
) :: rest
when s'
= s ->
1128 state
.geomcmds
<- ps
, ((s, f) :: rest
);
1131 state
.geomcmds
<- ps
, ((s, f) :: cmds
);
1135 Hashtbl.iter
(fun _ opaque
->
1136 wcmd "freepage %s" (~
> opaque
);
1138 Hashtbl.clear state
.pagemap
;
1142 if not
(Queue.is_empty state
.tilelru
)
1144 Queue.iter
(fun (k
, p
, s) ->
1145 wcmd "freetile %s" (~
> p
);
1146 state
.memused
<- state
.memused
- s;
1147 Hashtbl.remove state
.tilemap k
;
1149 state
.uioh#infochanged Memused
;
1150 Queue.clear state
.tilelru
;
1156 let h = truncate
(float h*.conf
.zoom
) in
1157 let d = conf
.interpagespace
lsl (if conf
.presentation
then 1 else 0) in
1161 let opendoc path password
=
1163 state
.password
<- password
;
1164 state
.gen
<- state
.gen
+ 1;
1165 state
.docinfo
<- [];
1166 state
.outlines
<- [||];
1169 setaalevel conf
.aalevel
;
1171 if emptystr state
.origin
1175 Wsi.settitle
("llpp " ^
(mbtoutf8
(Filename.basename
titlepath)));
1176 wcmd "open %d %d %s\000%s\000" (btod
!wtmode) (btod
!cxack) path password
;
1177 invalidate "reqlayout"
1179 wcmd "reqlayout %d %d %d %s\000"
1180 conf
.angle
(FMTE.to_int conf
.fitmodel
)
1181 (stateh state
.winh
) state
.nameddest
1186 state
.anchor <- getanchor
();
1187 opendoc state
.path state
.password
;
1191 let c = c *. conf
.colorscale
in
1195 let scalecolor2 (r
, g, b) =
1196 (r
*. conf
.colorscale
, g *. conf
.colorscale
, b *. conf
.colorscale
);
1199 let docolumns columns
=
1200 let wadj = wadjsb () in
1203 let a = Array.make state
.pagecount
(-1, -1, -1, (-1, -1, -1, -1)) in
1204 let wadj = wadjsb () in
1205 let rec loop pageno
pdimno pdim
y ph pdims
=
1206 if pageno
= state
.pagecount
1209 let pdimno, ((_
, w, h, xoff
) as pdim
), pdims
=
1211 | ((pageno'
, _
, _
, _
) as pdim
) :: rest
when pageno'
= pageno
->
1212 pdimno+1, pdim
, rest
1216 let x = max
0 (((wadj + state
.winw
- w) / 2) - xoff
) in
1218 (if conf
.presentation
1219 then (if pageno
= 0 then calcips
h else calcips ph
+ calcips
h)
1220 else (if pageno
= 0 then 0 else conf
.interpagespace
)
1223 a.(pageno
) <- (pdimno, x, y, pdim
);
1224 loop (pageno
+1) pdimno pdim
(y + h) h pdims
1226 loop 0 ~
-1 (-1,-1,-1,-1) 0 0 state
.pdims
;
1227 conf
.columns
<- Csingle
a;
1229 | Cmulti
((columns
, coverA
, coverB
), _
) ->
1230 let a = Array.make state
.pagecount
(-1, -1, -1, (-1, -1, -1, -1)) in
1231 let rec loop pageno
pdimno pdim
x y rowh pdims
=
1232 let rec fixrow m
= if m
= pageno
then () else
1233 let (pdimno, x, y, ((_
, _
, h, _
) as pdim
)) = a.(m
) in
1236 let y = y + (rowh
- h) / 2 in
1237 a.(m
) <- (pdimno, x, y, pdim
);
1241 if pageno
= state
.pagecount
1242 then fixrow (((pageno
- 1) / columns
) * columns
)
1244 let pdimno, ((_
, w, h, xoff
) as pdim
), pdims
=
1246 | ((pageno'
, _
, _
, _
) as pdim
) :: rest
when pageno'
= pageno
->
1247 pdimno+1, pdim
, rest
1252 if pageno
= coverA
- 1 || pageno
= state
.pagecount
- coverB
1254 let x = (wadj + state
.winw
- w) / 2 in
1256 if conf
.presentation
then calcips
h else conf
.interpagespace
in
1257 x, y + ips + rowh
, h
1260 if (pageno
- coverA
) mod columns
= 0
1262 let x = max
0 (wadj + state
.winw
- state
.w) / 2 in
1264 if conf
.presentation
1266 let ips = calcips
h in
1267 y + (if pageno
= 0 then 0 else calcips rowh
+ ips)
1269 y + (if pageno
= 0 then 0 else conf
.interpagespace
)
1273 else x, y, max rowh
h
1277 if pageno
> 1 && (pageno
- coverA
) mod columns
= 0
1280 if pageno
= columns
&& conf
.presentation
1282 let ips = calcips rowh
in
1283 for i
= 0 to pred columns
1285 let (pdimno, x, y, pdim
) = a.(i
) in
1286 a.(i
) <- (pdimno, x, y+ips, pdim
)
1292 fixrow (pageno
- columns
);
1297 a.(pageno
) <- (pdimno, x, y, pdim
);
1298 let x = x + w + xoff
*2 + conf
.interpagespace
in
1299 loop (pageno
+1) pdimno pdim
x y rowh' pdims
1301 loop 0 ~
-1 (-1,-1,-1,-1) 0 0 0 state
.pdims
;
1302 conf
.columns
<- Cmulti
((columns
, coverA
, coverB
), a);
1305 let a = Array.make
(state
.pagecount
*c) (-1, -1, -1, (-1, -1, -1, -1)) in
1306 let rec loop pageno
pdimno pdim
y pdims
=
1307 if pageno
= state
.pagecount
1310 let pdimno, ((_
, w, h, _
) as pdim
), pdims
=
1312 | ((pageno'
, _
, _
, _
) as pdim
) :: rest
when pageno'
= pageno
->
1313 pdimno+1, pdim
, rest
1318 let rec loop1 n x y =
1319 if n = c then y else (
1320 a.(pageno
*c + n) <- (pdimno, x, y, pdim
);
1321 loop1 (n+1) (x+cw) (y + h + conf
.interpagespace
)
1324 let y = loop1 0 0 y in
1325 loop (pageno
+1) pdimno pdim
y pdims
1327 loop 0 ~
-1 (-1,-1,-1,-1) 0 state
.pdims
;
1328 conf
.columns
<- Csplit
(c, a);
1332 docolumns conf
.columns
;
1333 state
.maxy
<- calcheight
();
1334 if state
.reprf
== noreprf
1336 match state
.mode
with
1337 | Birdseye
(_
, _
, pageno
, _
, _
) ->
1338 let y, h = getpageyh pageno
in
1339 let top = (state
.winh
- h) / 2 in
1340 gotoy (max
0 (y - top))
1344 let y = getanchory state
.anchor in
1345 let y = min
y (state
.maxy
- state
.winw
- hscrollh ()) in
1350 state
.reprf
<- noreprf
;
1354 let reshape ?
(firsttime
=false) w h =
1355 GlDraw.viewport ~
x:0 ~
y:0 ~
w:w ~
h:h;
1356 if not firsttime
&& nogeomcmds state
.geomcmds
1357 then state
.anchor <- getanchor
();
1360 let w = wadjsb () + (truncate
(float w *. conf
.zoom
)) in
1363 setfontsize fstate
.fontsize
;
1364 GlMat.mode `modelview
;
1365 GlMat.load_identity
();
1367 GlMat.mode `projection
;
1368 GlMat.load_identity
();
1369 GlMat.rotate ~
x:1.0 ~angle
:180.0 ();
1370 GlMat.translate ~
x:~
-.1.0 ~
y:~
-.1.0 ();
1371 GlMat.scale3
(2.0 /. float state
.winw
, 2.0 /. float state
.winh
, 1.0);
1376 else float state
.x /. float state
.w
1378 invalidate "geometry"
1382 then state
.x <- truncate
(relx *. float w);
1384 match conf
.columns
with
1386 | Cmulti
((c, _
, _
), _
) -> (w - (c-1)*conf
.interpagespace
) / c
1387 | Csplit
(c, _
) -> w * c
1389 wcmd "geometry %d %d %d"
1390 w (stateh h) (FMTE.to_int conf
.fitmodel
)
1395 let len = String.length state
.text in
1396 let x0 = xadjsb () in
1399 match state
.mode
with
1400 | Textentry _
| View
| LinkNav _
->
1401 let h, _
, _
= state
.uioh#scrollpw
in
1406 filledrect x (float (state
.winh
- (fstate
.fontsize
+ 4) - hscrollh))
1407 (x+.w) (float (state
.winh
- hscrollh))
1410 let w = float (wadjsb () + state
.winw
- 1) in
1411 if state
.progress
>= 0.0 && state
.progress
< 1.0
1413 GlDraw.color (0.3, 0.3, 0.3);
1414 let w1 = w *. state
.progress
in
1416 GlDraw.color (0.0, 0.0, 0.0);
1417 rect (float x0+.w1) (float x0+.w-.w1)
1420 GlDraw.color (0.0, 0.0, 0.0);
1424 GlDraw.color (1.0, 1.0, 1.0);
1425 drawstring fstate
.fontsize
1426 (if conf
.leftscroll
then x0 + 2 else x0 + if len > 0 then 8 else 2)
1427 (state
.winh
- hscrollh - 5) s;
1430 match state
.mode
with
1431 | Textentry
((prefix
, text, _
, _
, _
, _
), _
) ->
1435 Printf.sprintf
"%s%s_ [%s]" prefix
text state
.text
1437 Printf.sprintf
"%s%s_" prefix
text
1443 | LinkNav _
-> state
.text
1448 if not
(istextentry state
.mode
) && state
.uioh#eformsgs
1450 let s1 = "(press 'e' to review error messasges)" in
1451 if nonemptystr
s then s ^
" " ^
s1 else s1
1461 let len = Queue.length state
.tilelru
in
1463 match state
.throttle
with
1466 then preloadlayout state
.x state
.y state
.winw state
.winh
1468 | Some
(layout, _
, _
) ->
1472 if state
.memused
<= conf
.memlimit
1477 let (k
, p
, s) as lruitem
= Queue.pop state
.tilelru
in
1478 let n, gen
, colorspace
, angle
, pagew
, pageh
, col, row = k
in
1479 let (_
, pw, ph
, _
) = getpagedim
n in
1482 && colorspace
= conf
.colorspace
1483 && angle
= conf
.angle
1487 let x = col*conf
.tilew
1488 and y = row*conf
.tileh
in
1489 tilevisible (Lazy.force_val
layout) n x y
1491 then Queue.push lruitem state
.tilelru
1494 wcmd "freetile %s" (~
> p
);
1495 state
.memused
<- state
.memused
- s;
1496 state
.uioh#infochanged Memused
;
1497 Hashtbl.remove state
.tilemap k
;
1505 let onpagerect pageno
f =
1507 match conf
.columns
with
1508 | Cmulti
(_
, b) -> b
1510 | Csplit
(_
, b) -> b
1512 if pageno
>= 0 && pageno
< Array.length
b
1514 let (_
, _
, _
, (_
, w, h, _
)) = b.(pageno
) in
1518 let gotopagexy1 wtmode pageno
x y =
1519 let _,w1,h1
,leftx
= getpagedim pageno
in
1520 let top = y /. (float h1
) in
1521 let left = x /. (float w1) in
1522 let py, w, h = getpageywh pageno
in
1523 let wh = state
.winh
- hscrollh () in
1524 let x = left *. (float w) in
1525 let x = leftx
+ state
.x + truncate
x in
1526 let wadj = wadjsb () in
1528 if x < 0 || x >= wadj + state
.winw
1532 let pdy = truncate
(top *. float h) in
1533 let y'
= py + pdy in
1534 let dy = y'
- state
.y in
1536 if x != state
.x || not
(dy > 0 && dy < wh)
1538 if conf
.presentation
1540 if abs
(py - y'
) > wh
1547 if state
.x != sx || state
.y != sy
1552 let ww = wadj + state
.winw
in
1554 and qy
= pdy / wh in
1556 and y = py + qy
* wh in
1557 let x = if -x + ww > w1 then -(w1-ww) else x
1558 and y'
= if y + wh > state
.maxy
then state
.maxy
- wh else y in
1560 if conf
.presentation
1562 if abs
(py - y'
) > wh
1572 gotoy_and_clear_text y;
1574 else gotoy_and_clear_text state
.y;
1577 let gotopagexy wtmode pageno
x y =
1578 match state
.mode
with
1579 | Birdseye
_ -> gotopage pageno
0.0
1582 | LinkNav
_ -> gotopagexy1 wtmode pageno
x y
1585 let getpassword () =
1586 let passcmd = getenvwithdef
"LLPP_ASKPASS" conf
.passcmd in
1591 impmsg "error getting password: %s" s;
1592 dolog
"%s" s) passcmd;
1595 let pgoto opaque pageno
x y =
1596 let pdimno = getpdimno pageno
in
1597 let x, y = project opaque pageno
pdimno x y in
1598 gotopagexy false pageno
x y;
1602 (* dolog "%S" cmds; *)
1603 let cl = splitatspace cmds
in
1605 try Scanf.sscanf
s fmt
f
1607 dolog
"error processing '%S': %s" cmds
@@ exntos exn
;
1610 let addoutline outline
=
1611 match state
.currently
with
1612 | Outlining outlines
->
1613 state
.currently
<- Outlining
(outline
:: outlines
)
1614 | Idle
-> state
.currently
<- Outlining
[outline
]
1617 dolog
"invalid outlining state";
1618 logcurrently state
.currently
1622 state
.uioh#infochanged Pdim
;
1625 | "clearrects" :: [] ->
1626 state
.rects
<- state
.rects1
;
1627 G.postRedisplay "clearrects";
1629 | "continue" :: args
:: [] ->
1630 let n = scan args
"%u" (fun n -> n) in
1631 state
.pagecount
<- n;
1632 begin match state
.currently
with
1634 state
.currently
<- Idle
;
1635 state
.outlines
<- Array.of_list
(List.rev
l)
1641 let cur, cmds
= state
.geomcmds
in
1643 then failwith
"umpossible";
1645 begin match List.rev cmds
with
1647 state
.geomcmds
<- E.s, [];
1648 state
.throttle
<- None
;
1652 state
.geomcmds
<- s, List.rev rest
;
1654 if conf
.maxwait
= None
&& not
!wtmode
1655 then G.postRedisplay "continue";
1657 | "msg" :: args
:: [] ->
1660 | "vmsg" :: args
:: [] ->
1662 then showtext ' ' args
1664 | "emsg" :: args
:: [] ->
1665 Buffer.add_string state
.errmsgs args
;
1666 state
.newerrmsgs
<- true;
1667 G.postRedisplay "error message"
1669 | "progress" :: args
:: [] ->
1670 let progress, text =
1673 f, String.sub args pos
(String.length args
- pos
))
1676 state
.progress <- progress;
1677 G.postRedisplay "progress"
1679 | "firstmatch" :: 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 y = (getpagey
pageno) + truncate
y0 in
1692 then state
.x <- truncate
(xoff -. x0) + state
.winw
/2;
1695 let color = (0.0, 0.0, 1.0 /. float c, 0.5) in
1696 state
.rects1
<- [pageno, color, (x0, y0, x1, y1, x2
, y2
, x3
, y3
)]
1698 | "match" :: args
:: [] ->
1699 let pageno, c, x0, y0, x1, y1, x2
, y2
, x3
, y3
=
1700 scan args
"%u %d %f %f %f %f %f %f %f %f"
1701 (fun p
c x0 y0 x1 y1 x2 y2 x3 y3
->
1702 (p
, c, x0, y0, x1, y1, x2
, y2
, x3
, y3
))
1704 let xoff = float (xadjsb ()) in
1708 and x3
= x3
+. xoff in
1709 let color = (0.0, 0.0, 1.0 /. float c, 0.5) in
1711 (pageno, color, (x0, y0, x1, y1, x2
, y2
, x3
, y3
)) :: state
.rects1
1713 | "page" :: args
:: [] ->
1714 let pageopaques, t
= scan args
"%s %f" (fun p t
-> p
, t
) in
1715 let pageopaque = ~
< pageopaques in
1716 begin match state
.currently
with
1717 | Loading
(l, gen
) ->
1718 vlog "page %d took %f sec" l.pageno t
;
1719 Hashtbl.replace state
.pagemap
(l.pageno, gen
) pageopaque;
1720 begin match state
.throttle
with
1722 let preloadedpages =
1724 then preloadlayout state
.x state
.y state
.winw state
.winh
1729 List.fold_left
(fun s l -> IntSet.add
l.pageno s)
1730 IntSet.empty
preloadedpages
1733 Hashtbl.fold (fun ((pageno, _) as key) opaque
accu ->
1734 if not
(IntSet.mem
pageno set)
1736 wcmd "freepage %s" (~
> opaque
);
1742 List.iter
(Hashtbl.remove state
.pagemap
) evictedpages;
1745 state
.currently
<- Idle
;
1748 tilepage l.pageno pageopaque state
.layout;
1750 load preloadedpages;
1751 let visible = pagevisible state
.layout l.pageno in
1754 match state
.mode
with
1755 | LinkNav
(Ltnotready
(pageno, dir
)) ->
1756 if pageno = l.pageno
1761 then LDfirstvisible
(l.pagex
, l.pagey, dir
)
1763 if dir
> 0 then LDfirst
else LDlast
1766 findlink
pageopaque ld
1771 showlinktype (getlink
pageopaque n);
1772 state
.mode
<- LinkNav
(Ltexact
(l.pageno, n))
1774 | LinkNav
(Ltgendir
_)
1775 | LinkNav
(Ltexact
_)
1781 if visible && layoutready state
.layout
1783 G.postRedisplay "page";
1787 | Some
(layout, _, _) ->
1788 state
.currently
<- Idle
;
1789 tilepage l.pageno pageopaque layout;
1796 dolog
"Inconsistent loading state";
1797 logcurrently state
.currently
;
1801 | "tile" :: args
:: [] ->
1802 let (x, y, opaques
, size
, t
) =
1803 scan args
"%u %u %s %u %f"
1804 (fun x y p size t
-> (x, y, p
, size
, t
))
1806 let opaque = ~
< opaques
in
1807 begin match state
.currently
with
1808 | Tiling
(l, pageopaque, cs
, angle
, gen
, col, row, tilew
, tileh
) ->
1809 vlog "tile %d [%d,%d] took %f sec" l.pageno col row t
;
1812 if tilew
!= conf
.tilew
|| tileh
!= conf
.tileh
1814 wcmd "freetile %s" (~
> opaque);
1815 state
.currently
<- Idle
;
1819 puttileopaque l col row gen cs angle
opaque size t
;
1820 state
.memused
<- state
.memused
+ size
;
1821 state
.uioh#infochanged Memused
;
1823 Queue.push
((l.pageno, gen
, cs
, angle
, l.pagew
, l.pageh
, col, row),
1824 opaque, size
) state
.tilelru
;
1827 match state
.throttle
with
1828 | None
-> state
.layout
1829 | Some
(layout, _, _) -> layout
1832 state
.currently
<- Idle
;
1834 && conf
.colorspace
= cs
1835 && conf
.angle
= angle
1836 && tilevisible layout l.pageno x y
1837 then conttiling l.pageno pageopaque;
1839 begin match state
.throttle
with
1841 preload state
.layout;
1843 && conf
.colorspace
= cs
1844 && conf
.angle
= angle
1845 && tilevisible state
.layout l.pageno x y
1846 && (not
!wtmode || layoutready state
.layout)
1847 then G.postRedisplay "tile nothrottle";
1849 | Some
(layout, y, _) ->
1850 let ready = layoutready layout in
1854 state
.layout <- layout;
1855 state
.throttle
<- None
;
1856 G.postRedisplay "throttle";
1865 dolog
"Inconsistent tiling state";
1866 logcurrently state
.currently
;
1870 | "pdim" :: args
:: [] ->
1871 let (n, w, h, _) as pdim
=
1872 scan args
"%u %u %u %u" (fun n w h x -> n, w, h, x)
1875 match conf
.fitmodel
with
1877 | FitPage
| FitProportional
->
1878 match conf
.columns
with
1879 | Csplit
_ -> (n, w, h, 0)
1880 | Csingle
_ | Cmulti
_ -> pdim
1882 state
.uioh#infochanged Pdim
;
1883 state
.pdims
<- pdim :: state
.pdims
1885 | "o" :: args
:: [] ->
1886 let (l, n, t
, h, pos
) =
1887 scan args
"%u %u %d %u %n"
1888 (fun l n t
h pos
-> l, n, t
, h, pos
)
1890 let s = String.sub args pos
(String.length args
- pos
) in
1891 addoutline (s, l, Oanchor
(n, float t
/. float h, 0.0))
1893 | "ou" :: args
:: [] ->
1894 let (l, len, pos
) = scan args
"%u %u %n" (fun l len pos
-> l, len, pos
) in
1895 let s = String.sub args pos
len in
1896 let pos2 = pos
+ len + 1 in
1897 let uri = String.sub args
pos2 (String.length args
- pos2) in
1898 addoutline (s, l, Ouri
uri)
1900 | "on" :: args
:: [] ->
1901 let (l, pos
) = scan args
"%u %n" (fun l pos
-> l, pos
) in
1902 let s = String.sub args pos
(String.length args
- pos
) in
1903 addoutline (s, l, Onone
)
1905 | "a" :: args
:: [] ->
1907 scan args
"%u %d %d" (fun n l t
-> n, l, t
)
1909 state
.reprf
<- (fun () -> gotopagexy !wtmode n (float l) (float t
))
1911 | "info" :: args
:: [] ->
1912 let pos = nindex args '
\t'
in
1913 if pos >= 0 && String.sub args
0 pos = "Title"
1915 let s = String.sub args
(pos+1) @@ String.length args
- pos - 1 in
1919 state
.docinfo
<- (1, args
) :: state
.docinfo
1921 | "infoend" :: [] ->
1922 state
.uioh#infochanged Docinfo
;
1923 state
.docinfo
<- List.rev state
.docinfo
1927 then Wsi.settitle
"Wrong password";
1928 let password = getpassword () in
1929 if emptystr
password
1930 then error
"document is password protected"
1931 else opendoc state
.path
password
1933 error
"unknown cmd `%S'" cmds
1938 let action = function
1939 | HCprev
-> cbget cb ~
-1
1940 | HCnext
-> cbget cb
1
1941 | HCfirst
-> cbget cb ~
-(cb
.rc)
1942 | HClast
-> cbget cb
(cb
.len - 1 - cb
.rc)
1943 and cancel
() = cb
.rc <- rc
1947 let search pattern forward
=
1948 match conf
.columns
with
1949 | Csplit
_ -> impmsg "searching does not work properly in split columns mode"
1952 if nonemptystr pattern
1955 match state
.layout with
1958 l.pageno, (l.pagey + if forward
then 0 else 0*l.pagevh)
1960 wcmd "search %d %d %d %d,%s\000"
1961 (btod conf
.icase
) pn py (btod forward
) pattern
;
1964 let intentry text key =
1966 if key >= 32 && key < 127
1972 let text = addchar
text c in
1976 state
.text <- Printf.sprintf
"invalid char (%d, `%c')" key c;
1984 let l = String.length
s in
1985 let rec loop pos n = if pos = l then n else
1986 let m = Char.code
s.[pos] - (if pos = 0 && l > 1 then 96 else 97) in
1987 loop (pos+1) (n*26 + m)
1990 let rec loop n = function
1993 match getopaque l.pageno with
1994 | None
-> loop n rest
1996 let m = getlinkcount
opaque in
1999 let under = getlink
opaque n in
2002 else loop (n-m) rest
2004 loop n state
.layout;
2008 let linknentry text key =
2010 if key >= 32 && key < 127
2016 let text = addchar
text c in
2017 linknact (fun under -> state
.text <- undertext ~nopath
:true under) text;
2021 state
.text <- Printf.sprintf
"invalid char (%d, `%c')" key c;
2025 let textentry text key =
2026 if key land 0xff00 = 0xff00
2028 else TEcont
(text ^ toutf8
key)
2031 let reqlayout angle fitmodel
=
2032 match state
.throttle
with
2034 if nogeomcmds state
.geomcmds
2035 then state
.anchor <- getanchor
();
2036 conf
.angle
<- angle
mod 360;
2039 match state
.mode
with
2040 | LinkNav
_ -> state
.mode
<- View
2045 conf
.fitmodel
<- fitmodel
;
2046 invalidate "reqlayout"
2048 wcmd "reqlayout %d %d %d"
2049 conf
.angle
(FMTE.to_int conf
.fitmodel
) (stateh state
.winh
)
2054 let settrim trimmargins trimfuzz
=
2055 if nogeomcmds state
.geomcmds
2056 then state
.anchor <- getanchor
();
2057 conf
.trimmargins
<- trimmargins
;
2058 conf
.trimfuzz
<- trimfuzz
;
2059 let x0, y0, x1, y1 = trimfuzz
in
2060 invalidate "settrim"
2062 wcmd "settrim %d %d %d %d %d" (btod conf
.trimmargins
) x0 y0 x1 y1);
2067 match state
.throttle
with
2069 let zoom = max
0.0001 zoom in
2070 if zoom <> conf
.zoom
2072 state
.prevzoom
<- (conf
.zoom, state
.x);
2074 reshape state
.winw state
.winh
;
2075 state
.text <- Printf.sprintf
"zoom is now %-5.2f" (zoom *. 100.0);
2078 | Some
(layout, y, started
) ->
2080 match conf
.maxwait
with
2084 let dt = now
() -. started
in
2092 let setcolumns mode columns coverA coverB
=
2093 state
.prevcolumns
<- Some
(conf
.columns
, conf
.zoom);
2097 then impmsg "split mode doesn't work in bird's eye"
2099 conf
.columns
<- Csplit
(-columns
, E.a);
2107 conf
.columns
<- Csingle
E.a;
2112 conf
.columns
<- Cmulti
((columns
, coverA
, coverB
), E.a);
2116 reshape state
.winw state
.winh
;
2119 let resetmstate () =
2120 state
.mstate
<- Mnone
;
2121 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
2124 let enterbirdseye () =
2125 let zoom = float conf
.thumbw
/. float state
.winw
in
2126 let birdseyepageno =
2127 let cy = state
.winh
/ 2 in
2131 let rec fold best
= function
2134 let d = cy - (l.pagedispy + l.pagevh/2)
2135 and dbest
= cy - (best
.pagedispy + best
.pagevh/2) in
2136 if abs
d < abs dbest
2143 state
.mode
<- Birdseye
(
2144 { conf
with zoom = conf
.zoom }, state
.x, birdseyepageno, -1, getanchor
()
2148 conf
.presentation
<- false;
2149 conf
.interpagespace
<- 10;
2150 conf
.hlinks
<- false;
2151 conf
.fitmodel
<- FitPage
;
2153 conf
.maxwait
<- None
;
2155 match conf
.beyecolumns
with
2158 Cmulti
((c, 0, 0), E.a)
2159 | None
-> Csingle
E.a
2163 state
.text <- Printf.sprintf
"birds eye mode on (zoom %3.1f%%)"
2168 reshape state
.winw state
.winh
;
2171 let leavebirdseye (c, leftx
, pageno, _, anchor) goback
=
2173 conf
.zoom <- c.zoom;
2174 conf
.presentation
<- c.presentation
;
2175 conf
.interpagespace
<- c.interpagespace
;
2176 conf
.maxwait
<- c.maxwait
;
2177 conf
.hlinks
<- c.hlinks
;
2178 conf
.fitmodel
<- c.fitmodel
;
2179 conf
.beyecolumns
<- (
2180 match conf
.columns
with
2181 | Cmulti
((c, _, _), _) -> Some
c
2183 | Csplit
_ -> failwith
"leaving bird's eye split mode"
2186 match c.columns
with
2187 | Cmulti
(c, _) -> Cmulti
(c, E.a)
2188 | Csingle
_ -> Csingle
E.a
2189 | Csplit
(c, _) -> Csplit
(c, E.a)
2193 state
.text <- Printf.sprintf
"birds eye mode off (zoom %3.1f%%)"
2196 reshape state
.winw state
.winh
;
2197 state
.anchor <- if goback
then anchor else (pageno, 0.0, 1.0);
2201 let togglebirdseye () =
2202 match state
.mode
with
2203 | Birdseye vals
-> leavebirdseye vals
true
2204 | View
-> enterbirdseye ()
2209 let upbirdseye incr
(conf
, leftx
, pageno, hooverpageno
, anchor) =
2210 let pageno = max
0 (pageno - incr
) in
2211 let rec loop = function
2212 | [] -> gotopage1 pageno 0
2213 | l :: _ when l.pageno = pageno ->
2214 if l.pagedispy >= 0 && l.pagey = 0
2215 then G.postRedisplay "upbirdseye"
2216 else gotopage1 pageno 0
2217 | _ :: rest
-> loop rest
2221 state
.mode
<- Birdseye
(conf
, leftx
, pageno, hooverpageno
, anchor)
2224 let downbirdseye incr
(conf
, leftx
, pageno, hooverpageno
, anchor) =
2225 let pageno = min
(state
.pagecount
- 1) (pageno + incr
) in
2226 state
.mode
<- Birdseye
(conf
, leftx
, pageno, hooverpageno
, anchor);
2227 let rec loop = function
2229 let y, h = getpageyh
pageno in
2230 let dy = (y - state
.y) - (state
.winh
- h - conf
.interpagespace
) in
2232 | l :: _ when l.pageno = pageno ->
2233 if l.pagevh != l.pageh
2234 then gotoy (clamp (l.pageh
- l.pagevh + conf
.interpagespace
))
2235 else G.postRedisplay "downbirdseye"
2236 | _ :: rest
-> loop rest
2242 let optentry mode
_ key =
2243 let btos b = if b then "on" else "off" in
2244 if key >= 32 && key < 127
2246 let c = Char.chr
key in
2250 try conf
.scrollstep
<- int_of_string
s with exc
->
2251 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exc
2253 TEswitch
("scroll step: ", E.s, None
, intentry, ondone, true)
2258 conf
.autoscrollstep
<- boundastep state
.winh
(int_of_string
s);
2259 if state
.autoscroll
<> None
2260 then state
.autoscroll
<- Some conf
.autoscrollstep
2262 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exc
2264 TEswitch
("auto scroll step: ", E.s, None
, intentry, ondone, true)
2269 let n, a, b = multicolumns_of_string
s in
2270 setcolumns mode
n a b;
2272 state
.text <- Printf.sprintf
"bad columns `%s': %s" s @@ exntos exc
2274 TEswitch
("columns: ", E.s, None
, textentry, ondone, true)
2279 let zoom = float (int_of_string
s) /. 100.0 in
2282 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exc
2284 TEswitch
("zoom: ", E.s, None
, intentry, ondone, true)
2289 conf
.thumbw
<- bound
(int_of_string
s) 2 4096;
2291 Printf.sprintf
"thumbnail width is set to %d" conf
.thumbw
;
2292 begin match mode
with
2294 leavebirdseye beye
false;
2301 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exc
2303 TEswitch
("thumbnail width: ", E.s, None
, intentry, ondone, true)
2308 Some
(int_of_string
s)
2311 Printf.sprintf
"bad integer `%s': %s" s @@ exntos exc
;
2314 | Some angle
-> reqlayout angle conf
.fitmodel
2317 TEswitch
("rotation: ", E.s, None
, intentry, ondone, true)
2320 conf
.icase
<- not conf
.icase
;
2321 TEdone
("case insensitive search " ^
(btos conf
.icase
))
2324 conf
.preload <- not conf
.preload;
2326 TEdone
("preload " ^
(btos conf
.preload))
2329 conf
.verbose
<- not conf
.verbose
;
2330 TEdone
("verbose " ^
(btos conf
.verbose
))
2333 conf
.debug
<- not conf
.debug
;
2334 TEdone
("debug " ^
(btos conf
.debug
))
2337 conf
.maxhfit
<- not conf
.maxhfit
;
2338 state
.maxy
<- calcheight
();
2339 TEdone
("maxhfit " ^
(btos conf
.maxhfit
))
2342 conf
.crophack
<- not conf
.crophack
;
2343 TEdone
("crophack " ^
btos conf
.crophack
)
2347 match conf
.maxwait
with
2349 conf
.maxwait
<- Some infinity
;
2350 "always wait for page to complete"
2352 conf
.maxwait
<- None
;
2353 "show placeholder if page is not ready"
2358 conf
.underinfo
<- not conf
.underinfo
;
2359 TEdone
("underinfo " ^
btos conf
.underinfo
)
2362 conf
.savebmarks
<- not conf
.savebmarks
;
2363 TEdone
("persistent bookmarks " ^
btos conf
.savebmarks
)
2369 match state
.layout with
2374 conf
.interpagespace
<- int_of_string
s;
2375 docolumns conf
.columns
;
2376 state
.maxy
<- calcheight
();
2377 let y = getpagey
pageno in
2380 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exc
2382 TEswitch
("vertical margin: ", E.s, None
, intentry, ondone, true)
2386 match conf
.fitmodel
with
2387 | FitProportional
-> FitWidth
2388 | FitWidth
| FitPage
-> FitProportional
2390 reqlayout conf
.angle
fm;
2391 TEdone
("proportional display " ^
btos (fm == FitProportional
))
2394 settrim (not conf
.trimmargins
) conf
.trimfuzz
;
2395 TEdone
("trim margins " ^
btos conf
.trimmargins
)
2398 conf
.invert
<- not conf
.invert
;
2399 TEdone
("invert colors " ^
btos conf
.invert
)
2403 cbput state
.hists
.sel
s;
2406 TEswitch
("selection command: ", E.s, Some
(onhist state
.hists
.sel
),
2407 textentry, ondone, true)
2411 then conf
.pax
<- Some
(ref (0.0, 0, 0))
2412 else conf
.pax
<- None
;
2413 TEdone
("PAX " ^
btos (conf
.pax
!= None
))
2416 state
.text <- Printf.sprintf
"bad option %d `%c'" key c;
2422 class type lvsource
= object
2423 method getitemcount
: int
2424 method getitem
: int -> (string * int)
2425 method hasaction
: int -> bool
2433 method getactive
: int
2434 method getfirst
: int
2436 method getminfo
: (int * int) array
2439 class virtual lvsourcebase
= object
2440 val mutable m_active
= 0
2441 val mutable m_first
= 0
2442 val mutable m_pan
= 0
2443 method getactive
= m_active
2444 method getfirst
= m_first
2445 method getpan
= m_pan
2446 method getminfo
: (int * int) array
= E.a
2449 let textentrykeyboard
2450 key _mask
((c, text, opthist
, onkey
, ondone, cancelonempty
), onleave
) =
2453 if key >= 0xffb0 && key <= 0xffb9
2454 then key - 0xffb0 + 48 else key
2457 state
.mode
<- Textentry
(te
, onleave
);
2459 G.postRedisplay "textentrykeyboard enttext";
2461 let histaction cmd
=
2464 | Some
(action, _) ->
2465 state
.mode
<- Textentry
(
2466 (c, action cmd
, opthist
, onkey
, ondone, cancelonempty
), onleave
2468 G.postRedisplay "textentry histaction"
2472 if emptystr
text && cancelonempty
2475 G.postRedisplay "textentrykeyboard after cancel";
2478 let s = withoutlastutf8
text in
2479 enttext (c, s, opthist
, onkey
, ondone, cancelonempty
)
2481 | @enter
| @kpenter
->
2484 G.postRedisplay "textentrykeyboard after confirm"
2486 | @up
| @kpup
-> histaction HCprev
2487 | @down
| @kpdown
-> histaction HCnext
2488 | @home
| @kphome
-> histaction HCfirst
2489 | @jend
| @kpend
-> histaction HClast
2494 begin match opthist
with
2496 | Some
(_, onhistcancel
) -> onhistcancel
()
2500 G.postRedisplay "textentrykeyboard after cancel2"
2503 enttext (c, E.s, opthist
, onkey
, ondone, cancelonempty
)
2506 | @delete
| @kpdelete
-> ()
2509 && key land 0xff00 != 0xff00 (* keyboard *)
2510 && key land 0xfe00 != 0xfe00 (* xkb *)
2511 && key land 0xfd00 != 0xfd00 (* 3270 *)
2513 begin match onkey
text key with
2517 G.postRedisplay "textentrykeyboard after confirm2";
2520 enttext (c, text, opthist
, onkey
, ondone, cancelonempty
);
2524 G.postRedisplay "textentrykeyboard after cancel3"
2527 state
.mode
<- Textentry
(te
, onleave
);
2528 G.postRedisplay "textentrykeyboard switch";
2532 vlog "unhandled key %s" (Wsi.keyname
key)
2535 let firstof first active
=
2536 if first
> active
|| abs
(first
- active
) > fstate
.maxrows
- 1
2537 then max
0 (active
- (fstate
.maxrows
/2))
2541 let calcfirst first active
=
2544 let rows = active
- first
in
2545 if rows > fstate
.maxrows
then active
- fstate
.maxrows
else first
2549 let scrollph y maxy
=
2550 let sh = float (maxy
+ state
.winh
) /. float state
.winh
in
2551 let sh = float state
.winh
/. sh in
2552 let sh = max
sh (float conf
.scrollh
) in
2554 let percent = float y /. float maxy
in
2555 let position = (float state
.winh
-. sh) *. percent in
2558 if position +. sh > float state
.winh
2559 then float state
.winh
-. sh
2565 let coe s = (s :> uioh
);;
2567 class listview ~zebra ~helpmode ~
(source
:lvsource
) ~trusted ~modehash
=
2569 val m_pan
= source#getpan
2570 val m_first
= source#getfirst
2571 val m_active
= source#getactive
2573 val m_prev_uioh
= state
.uioh
2575 method private elemunder
y =
2579 let n = y / (fstate
.fontsize
+1) in
2580 if m_first
+ n < source#getitemcount
2582 if source#hasaction
(m_first
+ n)
2583 then Some
(m_first
+ n)
2590 GlFunc.blend_func ~src
:`src_alpha ~dst
:`one_minus_src_alpha
;
2591 GlDraw.color (0., 0., 0.) ~alpha
:0.85;
2592 filledrect 0. 0. (float state
.winw
) (float state
.winh
);
2593 GlDraw.color (1., 1., 1.);
2594 Gl.enable `texture_2d
;
2595 let fs = fstate
.fontsize
in
2597 let hw = (wadjsb () + xadjsb () + state
.winw
)/3 in
2598 let ww = fstate
.wwidth
in
2599 let tabw = 17.0*.ww in
2600 let itemcount = source#getitemcount
in
2601 let minfo = source#getminfo
in
2604 then float (xadjsb ()), float (state
.winw
- 1)
2605 else 0.0, float (state
.winw
- conf
.scrollbw
- 1)
2607 let xadj = xadjsb () in
2609 if (row - m_first
) > fstate
.maxrows
2612 if row >= 0 && row < itemcount
2614 let (s, level
) = source#getitem
row in
2615 let y = (row - m_first
) * nfs in
2617 (if conf
.leftscroll
then float xadj else 5.0)
2618 +. (float (level
+ m_pan
)) *. ww in
2621 (let c = if row land 1 = 0 then 1.0 else 0.92 in (c,c,c));
2625 Gl.disable `texture_2d
;
2626 let alpha = if source#hasaction
row then 0.9 else 0.3 in
2627 GlDraw.color (1., 1., 1.) ~
alpha;
2628 linerect (x0 +. 1.) (float (y + 1)) (x1) (float (y + fs + 3));
2629 Gl.enable `texture_2d
;
2632 if zebra
&& row land 1 = 1
2636 GlDraw.color (c,c,c);
2637 let drawtabularstring s =
2639 let x'
= truncate
(x0 +. x) in
2640 let pos = nindex
s '
\000'
in
2642 then drawstring1 fs x'
(y+nfs) s
2644 let s1 = String.sub
s 0 pos
2645 and s2
= String.sub
s (pos+1) (String.length
s - pos - 1) in
2650 let s'
= withoutlastutf8
s in
2651 let s = s' ^
"@Uellipsis" in
2652 let w = measurestr
fs s in
2653 if float x'
+. w +. ww < float (hw + x'
)
2658 if float x'
+. ww +. measurestr
fs s1 > float (hw + x'
)
2662 ignore
(drawstring1 fs x'
(y+nfs) s1);
2663 drawstring1 fs (hw + x'
) (y+nfs) s2
2667 let x = if helpmode
&& row > 0 then x +. ww else x in
2668 let tabpos = nindex
s '
\t'
in
2671 let len = String.length
s - tabpos - 1 in
2672 let s1 = String.sub
s 0 tabpos
2673 and s2
= String.sub
s (tabpos + 1) len in
2674 let nx = drawstr x s1 in
2676 let x = x +. (max
tabw sw) in
2679 let len = String.length
s - 2 in
2680 if len > 0 && s.[0] = '
\xc2'
&& s.[1] = '
\xb7'
2682 let s = String.sub
s 2 len in
2683 let x = if not helpmode
then x +. ww else x in
2684 GlDraw.color (1.2, 1.2, 1.2);
2685 let vinc = drawstring1 (fs+fs/4)
2686 (truncate
(x -. ww)) (y+nfs) s in
2687 GlDraw.color (1., 1., 1.);
2688 vinc +. (float fs *. 0.8)
2694 ignore
(drawtabularstring s);
2700 GlDraw.color (1.0, 1.0, 1.0) ~
alpha:0.5;
2701 let xadj = float (xadjsb () + 5) in
2703 if (row - m_first
) > fstate
.maxrows
2706 if row >= 0 && row < itemcount
2708 let (s, level
) = source#getitem
row in
2709 let pos0 = nindex
s '
\000'
in
2710 let y = (row - m_first
) * nfs in
2711 let x = float (level
+ m_pan
) *. ww in
2712 let (first
, last
) = minfo.(row) in
2714 if pos0 > 0 && first
> pos0
2715 then String.sub
s (pos0+1) (first
-pos0-1)
2716 else String.sub
s 0 first
2718 let suffix = String.sub
s first
(last
- first
) in
2719 let w1 = measurestr fstate
.fontsize
prefix in
2720 let w2 = measurestr fstate
.fontsize
suffix in
2721 let x = x +. if conf
.leftscroll
then xadj else 5.0 in
2722 let x = if pos0 > 0 && first
> pos0 then x +. float hw else x in
2724 and y0 = float (y+2) in
2726 and y1 = float (y+fs+3) in
2727 filledrect x0 y0 x1 y1;
2732 Gl.disable `texture_2d
;
2733 if Array.length
minfo > 0 then loop m_first
;
2736 method updownlevel incr
=
2737 let len = source#getitemcount
in
2739 if m_active
>= 0 && m_active
< len
2740 then snd
(source#getitem m_active
)
2744 if i
= len then i
-1 else if i
= -1 then 0 else
2745 let _, l = source#getitem i
in
2746 if l != curlevel then i
else flow (i
+incr
)
2748 let active = flow m_active
in
2749 let first = calcfirst m_first
active in
2750 G.postRedisplay "outline updownlevel";
2751 {< m_active
= active; m_first
= first >}
2753 method private key1
key mask
=
2754 let set1 active first qsearch
=
2755 coe {< m_active
= active; m_first
= first; m_qsearch
= qsearch
>}
2757 let search active pattern incr
=
2758 let active = if active = -1 then m_first
else active in
2761 if n >= 0 && n < source#getitemcount
2763 let s, _ = source#getitem
n in
2764 match Str.search_forward re
s 0 with
2765 | (exception Not_found
) -> loop (n + incr
)
2772 Str.regexp_case_fold pattern
|> dosearch
2774 let itemcount = source#getitemcount
in
2775 let find start incr
=
2777 if i
= -1 || i
= itemcount
2780 if source#hasaction i
2782 else find (i
+ incr
)
2787 let set active first =
2788 let first = bound
first 0 (itemcount - fstate
.maxrows
) in
2790 coe {< m_active
= active; m_first
= first; m_qsearch
= E.s >}
2793 let isvisible first n = n >= first && n - first <= fstate
.maxrows
in
2795 let incr1 = if incr
> 0 then 1 else -1 in
2796 if isvisible m_first m_active
2799 let next = m_active
+ incr
in
2801 if next < 0 || next >= itemcount
2803 else find next incr1
2805 if abs
(m_active
- next) > fstate
.maxrows
2811 let first = m_first
+ incr
in
2812 let first = bound
first 0 (itemcount - fstate
.maxrows
) in
2814 let next = m_active
+ incr
in
2815 let next = bound
next 0 (itemcount - 1) in
2822 if isvisible first next
2829 let first = min
next m_first
in
2831 if abs
(next - first) > fstate
.maxrows
2837 let first = m_first
+ incr
in
2838 let first = bound
first 0 (itemcount - 1) in
2840 let next = m_active
+ incr
in
2841 let next = bound
next 0 (itemcount - 1) in
2842 let next = find next incr1 in
2844 if next = -1 || abs
(m_active
- first) > fstate
.maxrows
2846 let active = if m_active
= -1 then next else m_active
in
2851 if isvisible first active
2857 G.postRedisplay "listview navigate";
2861 | (@r
|@s) when Wsi.withctrl mask
->
2862 let incr = if key = @r
then -1 else 1 in
2864 match search (m_active
+ incr) m_qsearch
incr with
2866 state
.text <- m_qsearch ^
" [not found]";
2869 state
.text <- m_qsearch
;
2870 active, firstof m_first
active
2872 G.postRedisplay "listview ctrl-r/s";
2873 set1 active first m_qsearch
;
2875 | @insert
when Wsi.withctrl mask
->
2876 if m_active
>= 0 && m_active
< source#getitemcount
2878 let s, _ = source#getitem m_active
in
2884 if emptystr m_qsearch
2887 let qsearch = withoutlastutf8 m_qsearch
in
2891 G.postRedisplay "listview empty qsearch";
2892 set1 m_active m_first
E.s;
2896 match search m_active
qsearch ~
-1 with
2898 state
.text <- qsearch ^
" [not found]";
2901 state
.text <- qsearch;
2902 active, firstof m_first
active
2904 G.postRedisplay "listview backspace qsearch";
2905 set1 active first qsearch
2908 | key when (key != 0 && key land 0xff00 != 0xff00) ->
2909 let pattern = m_qsearch ^ toutf8
key in
2911 match search m_active
pattern 1 with
2913 state
.text <- pattern ^
" [not found]";
2916 state
.text <- pattern;
2917 active, firstof m_first
active
2919 G.postRedisplay "listview qsearch add";
2920 set1 active first pattern;
2924 if emptystr m_qsearch
2926 G.postRedisplay "list view escape";
2927 let mx, my
= state
.mpos
in
2931 source#exit ~uioh
:(coe self
)
2932 ~cancel
:true ~
active:m_active ~
first:m_first ~pan
:m_pan
2934 | None
-> m_prev_uioh
2939 G.postRedisplay "list view kill qsearch";
2940 coe {< m_qsearch
= E.s >}
2943 | @enter
| @kpenter
->
2945 let self = {< m_qsearch
= E.s >} in
2947 G.postRedisplay "listview enter";
2948 if m_active
>= 0 && m_active
< source#getitemcount
2950 source#exit ~uioh
:(coe self) ~cancel
:false
2951 ~
active:m_active ~
first:m_first ~pan
:m_pan
;
2954 source#exit ~uioh
:(coe self) ~cancel
:true
2955 ~
active:m_active ~
first:m_first ~pan
:m_pan
;
2958 begin match opt with
2959 | None
-> m_prev_uioh
2963 | @delete
| @kpdelete
->
2966 | @up
| @kpup
-> navigate ~
-1
2967 | @down
| @kpdown
-> navigate 1
2968 | @prior
| @kpprior
-> navigate ~
-(fstate
.maxrows
)
2969 | @next | @kpnext
-> navigate fstate
.maxrows
2971 | @right
| @kpright
->
2973 G.postRedisplay "listview right";
2974 coe {< m_pan
= m_pan
- 1 >}
2976 | @left | @kpleft
->
2978 G.postRedisplay "listview left";
2979 coe {< m_pan
= m_pan
+ 1 >}
2981 | @home
| @kphome
->
2982 let active = find 0 1 in
2983 G.postRedisplay "listview home";
2987 let first = max
0 (itemcount - fstate
.maxrows
) in
2988 let active = find (itemcount - 1) ~
-1 in
2989 G.postRedisplay "listview end";
2992 | key when (key = 0 || key land 0xff00 = 0xff00) ->
2996 dolog
"listview unknown key %#x" key; coe self
2998 method key key mask
=
2999 match state
.mode
with
3000 | Textentry te
-> textentrykeyboard key mask te
; coe self
3003 | LinkNav
_ -> self#key1
key mask
3005 method button button down
x y _ =
3008 | 1 when vscrollhit x ->
3009 G.postRedisplay "listview scroll";
3012 let _, position, sh = self#
scrollph in
3013 if y > truncate
position && y < truncate
(position +. sh)
3015 state
.mstate
<- Mscrolly
;
3019 let s = float (max
0 (y - conf
.scrollh
)) /. float state
.winh
in
3020 let first = truncate
(s *. float source#getitemcount
) in
3021 let first = min source#getitemcount
first in
3022 Some
(coe {< m_first
= first; m_active
= first >})
3024 state
.mstate
<- Mnone
;
3028 begin match self#elemunder
y with
3030 G.postRedisplay "listview click";
3031 source#exit ~uioh
:(coe {< m_active
= n >})
3032 ~cancel
:false ~
active:n ~
first:m_first ~pan
:m_pan
3036 | n when (n == 4 || n == 5) && not down
->
3037 let len = source#getitemcount
in
3039 if n = 5 && m_first
+ fstate
.maxrows
>= len
3043 let first = m_first
+ (if n == 4 then -1 else 1) in
3044 bound
first 0 (len - 1)
3046 G.postRedisplay "listview wheel";
3047 Some
(coe {< m_first
= first >})
3048 | n when (n = 6 || n = 7) && not down
->
3049 let inc = if n = 7 then -1 else 1 in
3050 G.postRedisplay "listview hwheel";
3051 Some
(coe {< m_pan
= m_pan
+ inc >})
3056 | None
-> m_prev_uioh
3059 method multiclick
_ x y = self#button
1 true x y
3062 match state
.mstate
with
3064 let s = float (max
0 (y - conf
.scrollh
)) /. float state
.winh
in
3065 let first = truncate
(s *. float source#getitemcount
) in
3066 let first = min source#getitemcount
first in
3067 G.postRedisplay "listview motion";
3068 coe {< m_first
= first; m_active
= first >}
3076 method pmotion
x y =
3077 if x < state
.winw
- conf
.scrollbw
3080 match self#elemunder
y with
3081 | None
-> Wsi.setcursor
Wsi.CURSOR_INHERIT
; m_active
3082 | Some
n -> Wsi.setcursor
Wsi.CURSOR_INFO
; n
3086 then (G.postRedisplay "listview pmotion"; {< m_active
= n >})
3091 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
3095 method infochanged
_ = ()
3097 method scrollpw
= (0, 0.0, 0.0)
3099 let nfs = fstate
.fontsize
+ 1 in
3100 let y = m_first
* nfs in
3101 let itemcount = source#getitemcount
in
3102 let maxi = max
0 (itemcount - fstate
.maxrows
) in
3103 let maxy = maxi * nfs in
3104 let p, h = scrollph y maxy in
3107 method modehash
= modehash
3108 method eformsgs
= false
3109 method alwaysscrolly
= true
3112 class outlinelistview ~zebra ~source
=
3113 let settext autonarrow
s =
3116 let ss = source#statestr
in
3120 else "{" ^
ss ^
"} [" ^
s ^
"]"
3121 else state
.text <- s
3127 ~source
:(source
:> lvsource
)
3129 ~modehash
:(findkeyhash conf
"outline")
3132 val m_autonarrow
= false
3134 method! key key mask
=
3136 if emptystr state
.text
3138 else fstate
.maxrows - 2
3140 let calcfirst first active =
3143 let rows = active - first in
3144 if rows > maxrows then active - maxrows else first
3148 let active = m_active
+ incr in
3149 let active = bound
active 0 (source#getitemcount
- 1) in
3150 let first = calcfirst m_first
active in
3151 G.postRedisplay "outline navigate";
3152 coe {< m_active
= active; m_first
= first >}
3154 let navscroll first =
3156 let dist = m_active
- first in
3162 else first + maxrows
3165 G.postRedisplay "outline navscroll";
3166 coe {< m_first
= first; m_active
= active >}
3168 let ctrl = Wsi.withctrl mask
in
3173 then (source#denarrow
; E.s)
3175 let pattern = source#renarrow
in
3176 if nonemptystr m_qsearch
3177 then (source#narrow m_qsearch
; m_qsearch
)
3181 settext (not m_autonarrow
) text;
3182 G.postRedisplay "toggle auto narrowing";
3183 coe {< m_first
= 0; m_active
= 0; m_autonarrow
= not m_autonarrow
>}
3185 | @slash
when emptystr m_qsearch
&& not m_autonarrow
->
3187 G.postRedisplay "toggle auto narrowing";
3188 coe {< m_first
= 0; m_active
= 0; m_autonarrow
= true >}
3191 source#narrow m_qsearch
;
3193 then source#add_narrow_pattern m_qsearch
;
3194 G.postRedisplay "outline ctrl-n";
3195 coe {< m_first
= 0; m_active
= 0 >}
3198 let active = source#calcactive
(getanchor
()) in
3199 let first = firstof m_first
active in
3200 G.postRedisplay "outline ctrl-s";
3201 coe {< m_first
= first; m_active
= active >}
3204 G.postRedisplay "outline ctrl-u";
3205 if m_autonarrow
&& nonemptystr m_qsearch
3207 ignore
(source#renarrow
);
3208 settext m_autonarrow
E.s;
3209 coe {< m_first
= 0; m_active
= 0; m_qsearch
= E.s >}
3212 source#del_narrow_pattern
;
3213 let pattern = source#renarrow
in
3215 if emptystr
pattern then E.s else "Narrowed to " ^
pattern
3217 settext m_autonarrow
text;
3218 coe {< m_first
= 0; m_active
= 0; m_qsearch
= E.s >}
3222 let first = max
0 (m_active
- (fstate
.maxrows / 2)) in
3223 G.postRedisplay "outline ctrl-l";
3224 coe {< m_first
= first >}
3226 | @tab
when m_autonarrow
->
3227 if nonemptystr m_qsearch
3229 G.postRedisplay "outline list view tab";
3230 source#add_narrow_pattern m_qsearch
;
3232 coe {< m_qsearch
= E.s >}
3236 | @escape
when m_autonarrow
->
3237 if nonemptystr m_qsearch
3238 then source#add_narrow_pattern m_qsearch
;
3241 | @enter
| @kpenter
when m_autonarrow
->
3242 if nonemptystr m_qsearch
3243 then source#add_narrow_pattern m_qsearch
;
3246 | key when m_autonarrow
&& (key != 0 && key land 0xff00 != 0xff00) ->
3247 let pattern = m_qsearch ^ toutf8
key in
3248 G.postRedisplay "outlinelistview autonarrow add";
3249 source#narrow
pattern;
3250 settext true pattern;
3251 coe {< m_first
= 0; m_active
= 0; m_qsearch
= pattern >}
3253 | key when m_autonarrow
&& key = @backspace
->
3254 if emptystr m_qsearch
3257 let pattern = withoutlastutf8 m_qsearch
in
3258 G.postRedisplay "outlinelistview autonarrow backspace";
3259 ignore
(source#renarrow
);
3260 source#narrow
pattern;
3261 settext true pattern;
3262 coe {< m_first
= 0; m_active
= 0; m_qsearch
= pattern >}
3264 | @up
| @kpup
when ctrl ->
3265 navscroll (max
0 (m_first
- 1))
3267 | @down
| @kpdown
when ctrl ->
3268 navscroll (min
(source#getitemcount
- 1) (m_first
+ 1))
3270 | @up
| @kpup
-> navigate ~
-1
3271 | @down
| @kpdown
-> navigate 1
3272 | @prior
| @kpprior
-> navigate ~
-(fstate
.maxrows)
3273 | @next | @kpnext
-> navigate fstate
.maxrows
3275 | @right
| @kpright
->
3279 G.postRedisplay "outline ctrl right";
3280 {< m_pan
= m_pan
+ 1 >}
3282 else self#updownlevel
1
3286 | @left | @kpleft
->
3290 G.postRedisplay "outline ctrl left";
3291 {< m_pan
= m_pan
- 1 >}
3293 else self#updownlevel ~
-1
3297 | @home
| @kphome
->
3298 G.postRedisplay "outline home";
3299 coe {< m_first
= 0; m_active
= 0 >}
3302 let active = source#getitemcount
- 1 in
3303 let first = max
0 (active - fstate
.maxrows) in
3304 G.postRedisplay "outline end";
3305 coe {< m_active
= active; m_first
= first >}
3307 | _ -> super#
key key mask
3310 let genhistoutlines () =
3312 |> List.sort
(fun (_, c1
, _, _, _, _) (_, c2
, _, _, _, _) ->
3313 compare c2
.lastvisit c1
.lastvisit
)
3315 (fun ((path
, c, _, _, _, origin
) as hist
) ->
3316 let path = if nonemptystr origin
then origin
else path in
3317 let base = mbtoutf8
@@ Filename.basename
path in
3318 (base ^
"\000" ^
c.title
, 1, Ohistory hist
)
3323 let gotohist (path, c, bookmarks
, x, anchor, origin
) =
3324 Config.save
leavebirdseye;
3325 state
.anchor <- anchor;
3326 state
.bookmarks
<- bookmarks
;
3327 state
.origin
<- origin
;
3330 let x0, y0, x1, y1 = conf
.trimfuzz
in
3331 wcmd "trimset %d %d %d %d %d" (btod conf
.trimmargins
) x0 y0 x1 y1;
3332 reshape ~firsttime
:true state
.winw state
.winh
;
3333 opendoc path origin
;
3337 let makecheckers () =
3338 (* Based on lablGL-1.04/LablGlut/examples/lablGL/checker.ml which had
3340 converted by Issac Trotts. July 25, 2002 *)
3341 let image = GlPix.create `ubyte ~format
:`luminance ~width
:2 ~height
:2 in
3342 Raw.sets_string
(GlPix.to_raw
image) ~
pos:0 "\255\200\200\255";
3343 let id = GlTex.gen_texture
() in
3344 GlTex.bind_texture ~target
:`texture_2d
id;
3345 GlPix.store
(`unpack_alignment
1);
3346 GlTex.image2d
image;
3347 List.iter
(GlTex.parameter ~target
:`texture_2d
)
3348 [ `mag_filter `nearest
; `min_filter `nearest
];
3352 let setcheckers enabled
=
3353 match state
.checkerstexid
with
3355 if enabled
then state
.checkerstexid
<- Some
(makecheckers ())
3357 | Some checkerstexid
->
3360 GlTex.delete_texture checkerstexid
;
3361 state
.checkerstexid
<- None
;
3365 let describe_location () =
3366 let fn = page_of_y state
.y in
3367 let ln = page_of_y
(state
.y + state
.winh
- hscrollh () - 1) in
3368 let maxy = state
.maxy - (if conf
.maxhfit
then state
.winh
else 0) in
3372 else (100. *. (float state
.y /. float maxy))
3376 Printf.sprintf
"page %d of %d [%.2f%%]"
3377 (fn+1) state
.pagecount
percent
3380 "pages %d-%d of %d [%.2f%%]"
3381 (fn+1) (ln+1) state
.pagecount
percent
3384 let setpresentationmode v
=
3385 let n = page_of_y state
.y in
3386 state
.anchor <- (n, 0.0, 1.0);
3387 conf
.presentation
<- v
;
3388 if conf
.fitmodel
= FitPage
3389 then reqlayout conf
.angle conf
.fitmodel
;
3393 let setbgcol (r
, g, b) =
3395 let r = r *. 255.0 |> truncate
3396 and g = g *. 255.0 |> truncate
3397 and b = b *. 255.0 |> truncate
in
3398 r lsl 16 |> (lor) (g lsl 8) |> (lor) b
3400 Wsi.setwinbgcol
col;
3404 let btos b = if b then "@Uradical" else E.s in
3405 let showextended = ref false in
3406 let leave mode
_ = state
.mode
<- mode
in
3409 val mutable m_l
= []
3410 val mutable m_a
= E.a
3411 val mutable m_prev_uioh
= nouioh
3412 val mutable m_prev_mode
= View
3414 inherit lvsourcebase
3416 method reset prev_mode prev_uioh
=
3417 m_a
<- Array.of_list
(List.rev m_l
);
3419 m_prev_mode
<- prev_mode
;
3420 m_prev_uioh
<- prev_uioh
;
3422 method int name get
set =
3424 (name
, `
int get
, 1, Action
(
3427 try set (int_of_string
s)
3429 state
.text <- Printf.sprintf
"bad integer `%s': %s"
3433 let te = name ^
": ", E.s, None
, intentry, ondone, true in
3434 state
.mode
<- Textentry
(te, leave m_prev_mode
);
3438 method int_with_suffix name get
set =
3440 (name
, `intws get
, 1, Action
(
3443 try set (int_of_string_with_suffix
s)
3445 state
.text <- Printf.sprintf
"bad integer `%s': %s"
3450 name ^
": ", E.s, None
, intentry_with_suffix, ondone, true
3452 state
.mode
<- Textentry
(te, leave m_prev_mode
);
3456 method bool ?
(offset
=1) ?
(btos=btos) name get
set =
3458 (name
, `
bool (btos, get
), offset
, Action
(
3465 method color name get
set =
3467 (name
, `
color get
, 1, Action
(
3469 let invalid = (nan
, nan
, nan
) in
3472 try color_of_string
s
3474 state
.text <- Printf.sprintf
"bad color `%s': %s"
3481 let te = name ^
": ", E.s, None
, textentry, ondone, true in
3482 state
.text <- color_to_string
(get
());
3483 state
.mode
<- Textentry
(te, leave m_prev_mode
);
3487 method string name get
set =
3489 (name
, `
string get
, 1, Action
(
3491 let ondone s = set s in
3492 let te = name ^
": ", E.s, None
, textentry, ondone, true in
3493 state
.mode
<- Textentry
(te, leave m_prev_mode
);
3497 method colorspace name get
set =
3499 (name
, `
string get
, 1, Action
(
3503 inherit lvsourcebase
3506 m_active
<- CSTE.to_int conf
.colorspace
;
3509 method getitemcount
=
3510 Array.length
CSTE.names
3513 method exit ~uioh ~cancel ~
active ~
first ~pan
=
3514 ignore
(uioh
, first, pan
);
3515 if not cancel
then set active;
3517 method hasaction
_ = true
3521 let modehash = findkeyhash conf
"info" in
3522 coe (new listview ~zebra
:false ~helpmode
:false
3523 ~
source ~trusted
:true ~
modehash)
3526 method paxmark name get
set =
3528 (name
, `
string get
, 1, Action
(
3532 inherit lvsourcebase
3535 m_active
<- MTE.to_int conf
.paxmark
;
3538 method getitemcount
= Array.length
MTE.names
3539 method getitem
n = (MTE.names
.(n), 0)
3540 method exit ~uioh ~cancel ~
active ~
first ~pan
=
3541 ignore
(uioh
, first, pan
);
3542 if not cancel
then set active;
3544 method hasaction
_ = true
3548 let modehash = findkeyhash conf
"info" in
3549 coe (new listview ~zebra
:false ~helpmode
:false
3550 ~
source ~trusted
:true ~
modehash)
3553 method fitmodel name get
set =
3555 (name
, `
string get
, 1, Action
(
3559 inherit lvsourcebase
3562 m_active
<- FMTE.to_int conf
.fitmodel
;
3565 method getitemcount
= Array.length
FMTE.names
3566 method getitem
n = (FMTE.names
.(n), 0)
3567 method exit ~uioh ~cancel ~
active ~
first ~pan
=
3568 ignore
(uioh
, first, pan
);
3569 if not cancel
then set active;
3571 method hasaction
_ = true
3575 let modehash = findkeyhash conf
"info" in
3576 coe (new listview ~zebra
:false ~helpmode
:false
3577 ~
source ~trusted
:true ~
modehash)
3580 method caption
s offset
=
3581 m_l
<- (s, `empty
, offset
, Noaction
) :: m_l
3583 method caption2
s f offset
=
3584 m_l
<- (s, `
string f, offset
, Noaction
) :: m_l
3586 method getitemcount
= Array.length m_a
3589 let tostr = function
3590 | `
int f -> string_of_int
(f ())
3591 | `intws
f -> string_with_suffix_of_int
(f ())
3593 | `
color f -> color_to_string
(f ())
3594 | `
bool (btos, f) -> btos (f ())
3597 let name, t
, offset
, _ = m_a
.(n) in
3598 ((let s = tostr t
in
3600 then Printf.sprintf
"%s\t%s" name s
3604 method exit ~uioh ~cancel ~
active ~
first ~pan
=
3609 match m_a
.(active) with
3610 | _, _, _, Action
f -> f uioh
3611 | _, _, _, Noaction
-> uioh
3622 method hasaction
n =
3624 | _, _, _, Action
_ -> true
3625 | _, _, _, Noaction
-> false
3627 initializer m_active
<- 1
3630 let rec fillsrc prevmode prevuioh
=
3631 let sep () = src#caption
E.s 0 in
3632 let colorp name get
set =
3634 (fun () -> color_to_string
(get
()))
3637 let c = color_of_string
v in
3640 state
.text <- Printf.sprintf
"bad color `%s': %s" v @@ exntos exn
3643 let oldmode = state
.mode
in
3644 let birdseye = isbirdseye state
.mode
in
3646 src#caption
(if birdseye then "Setup (Bird's eye)" else "Setup") 0;
3648 src#
bool "presentation mode"
3649 (fun () -> conf
.presentation
)
3650 (fun v -> setpresentationmode v);
3652 src#
bool "ignore case in searches"
3653 (fun () -> conf
.icase
)
3654 (fun v -> conf
.icase
<- v);
3657 (fun () -> conf
.preload)
3658 (fun v -> conf
.preload <- v);
3660 src#
bool "highlight links"
3661 (fun () -> conf
.hlinks
)
3662 (fun v -> conf
.hlinks
<- v);
3664 src#
bool "under info"
3665 (fun () -> conf
.underinfo
)
3666 (fun v -> conf
.underinfo
<- v);
3668 src#
bool "persistent bookmarks"
3669 (fun () -> conf
.savebmarks
)
3670 (fun v -> conf
.savebmarks
<- v);
3672 src#fitmodel
"fit model"
3673 (fun () -> FMTE.to_string conf
.fitmodel
)
3674 (fun v -> reqlayout conf
.angle
(FMTE.of_int
v));
3676 src#
bool "trim margins"
3677 (fun () -> conf
.trimmargins
)
3678 (fun v -> settrim v conf
.trimfuzz
; fillsrc prevmode prevuioh
);
3680 src#
bool "persistent location"
3681 (fun () -> conf
.jumpback
)
3682 (fun v -> conf
.jumpback
<- v);
3685 src#
int "inter-page space"
3686 (fun () -> conf
.interpagespace
)
3688 conf
.interpagespace
<- n;
3689 docolumns conf
.columns
;
3691 match state
.layout with
3696 state
.maxy <- calcheight
();
3697 let y = getpagey
pageno in
3702 (fun () -> conf
.pagebias
)
3703 (fun v -> conf
.pagebias
<- v);
3705 src#
int "scroll step"
3706 (fun () -> conf
.scrollstep
)
3707 (fun n -> conf
.scrollstep
<- n);
3709 src#
int "horizontal scroll step"
3710 (fun () -> conf
.hscrollstep
)
3711 (fun v -> conf
.hscrollstep
<- v);
3713 src#
int "auto scroll step"
3715 match state
.autoscroll
with
3717 | _ -> conf
.autoscrollstep
)
3719 let n = boundastep state
.winh
n in
3720 if state
.autoscroll
<> None
3721 then state
.autoscroll
<- Some
n;
3722 conf
.autoscrollstep
<- n);
3725 (fun () -> truncate
(conf
.zoom *. 100.))
3726 (fun v -> setzoom ((float v) /. 100.));
3729 (fun () -> conf
.angle
)
3730 (fun v -> reqlayout v conf
.fitmodel
);
3732 src#
int "scroll bar width"
3733 (fun () -> conf
.scrollbw
)
3736 reshape state
.winw state
.winh
;
3739 src#
int "scroll handle height"
3740 (fun () -> conf
.scrollh
)
3741 (fun v -> conf
.scrollh
<- v;);
3743 src#
int "thumbnail width"
3744 (fun () -> conf
.thumbw
)
3746 conf
.thumbw
<- min
4096 v;
3749 leavebirdseye beye
false;
3756 let mode = state
.mode in
3757 src#
string "columns"
3759 match conf
.columns
with
3761 | Cmulti
(multi
, _) -> multicolumns_to_string multi
3762 | Csplit
(count
, _) -> "-" ^ string_of_int count
3765 let n, a, b = multicolumns_of_string
v in
3766 setcolumns mode n a b);
3769 src#caption
"Pixmap cache" 0;
3770 src#int_with_suffix
"size (advisory)"
3771 (fun () -> conf
.memlimit
)
3772 (fun v -> conf
.memlimit
<- v);
3775 (fun () -> Printf.sprintf
"%s bytes, %d tiles"
3776 (string_with_suffix_of_int state
.memused
)
3777 (Hashtbl.length state
.tilemap
)) 1;
3780 src#caption
"Layout" 0;
3781 src#caption2
"Dimension"
3783 Printf.sprintf
"%dx%d (virtual %dx%d)"
3784 state
.winw state
.winh
3789 src#caption2
"Position" (fun () ->
3790 Printf.sprintf
"%dx%d" state
.x state
.y
3793 src#caption2
"Position" (fun () -> describe_location ()) 1
3797 src#
bool ~offset
:0 ~
btos:(fun v -> if v then "(on)" else "(off)")
3798 "Save these parameters as global defaults at exit"
3799 (fun () -> conf
.bedefault
)
3800 (fun v -> conf
.bedefault
<- v)
3804 let btos b = if b then "@Ulguillemet" else "@Urguillemet" in
3805 src#
bool ~offset
:0 ~
btos "Extended parameters"
3806 (fun () -> !showextended)
3807 (fun v -> showextended := v; fillsrc prevmode prevuioh
);
3811 (fun () -> conf
.checkers
)
3812 (fun v -> conf
.checkers
<- v; setcheckers v);
3813 src#
bool "update cursor"
3814 (fun () -> conf
.updatecurs
)
3815 (fun v -> conf
.updatecurs
<- v);
3816 src#
bool "scroll-bar on the left"
3817 (fun () -> conf
.leftscroll
)
3818 (fun v -> conf
.leftscroll
<- v);
3820 (fun () -> conf
.verbose
)
3821 (fun v -> conf
.verbose
<- v);
3822 src#
bool "invert colors"
3823 (fun () -> conf
.invert
)
3824 (fun v -> conf
.invert
<- v);
3826 (fun () -> conf
.maxhfit
)
3827 (fun v -> conf
.maxhfit
<- v);
3829 (fun () -> conf
.pax
!= None
)
3832 then conf
.pax
<- Some
(ref (now
(), 0, 0))
3833 else conf
.pax
<- None
);
3834 src#
string "uri launcher"
3835 (fun () -> conf
.urilauncher
)
3836 (fun v -> conf
.urilauncher
<- v);
3837 src#
string "path launcher"
3838 (fun () -> conf
.pathlauncher
)
3839 (fun v -> conf
.pathlauncher
<- v);
3840 src#
string "tile size"
3841 (fun () -> Printf.sprintf
"%dx%d" conf
.tilew conf
.tileh
)
3844 let w, h = Scanf.sscanf
v "%dx%d" (fun w h -> w, h) in
3845 conf
.tilew
<- max
64 w;
3846 conf
.tileh
<- max
64 h;
3849 state
.text <- Printf.sprintf
"bad tile size `%s': %s"
3852 src#
int "texture count"
3853 (fun () -> conf
.texcount
)
3856 then conf
.texcount
<- v
3857 else impmsg "failed to set texture count please retry later"
3859 src#
int "slice height"
3860 (fun () -> conf
.sliceheight
)
3862 conf
.sliceheight
<- v;
3863 wcmd "sliceh %d" conf
.sliceheight
;
3865 src#
int "anti-aliasing level"
3866 (fun () -> conf
.aalevel
)
3868 conf
.aalevel
<- bound
v 0 8;
3869 state
.anchor <- getanchor
();
3870 opendoc state
.path state
.password;
3872 src#
string "page scroll scaling factor"
3873 (fun () -> string_of_float conf
.pgscale)
3876 let s = float_of_string
v in
3879 state
.text <- Printf.sprintf
3880 "bad page scroll scaling factor `%s': %s" v @@ exntos exn
3883 src#
int "ui font size"
3884 (fun () -> fstate
.fontsize
)
3885 (fun v -> setfontsize (bound
v 5 100));
3886 src#
int "hint font size"
3887 (fun () -> conf
.hfsize
)
3888 (fun v -> conf
.hfsize
<- bound
v 5 100);
3889 colorp "background color"
3890 (fun () -> conf
.bgcolor
)
3891 (fun v -> conf
.bgcolor
<- v; setbgcol v);
3892 src#
bool "crop hack"
3893 (fun () -> conf
.crophack
)
3894 (fun v -> conf
.crophack
<- v);
3895 src#
string "trim fuzz"
3896 (fun () -> irect_to_string conf
.trimfuzz
)
3899 conf
.trimfuzz
<- irect_of_string
v;
3901 then settrim true conf
.trimfuzz
;
3903 state
.text <- Printf.sprintf
"bad irect `%s': %s" v @@ exntos exn
3905 src#
string "throttle"
3907 match conf
.maxwait
with
3908 | None
-> "show place holder if page is not ready"
3911 then "wait for page to fully render"
3913 "wait " ^ string_of_float
time
3914 ^
" seconds before showing placeholder"
3918 let f = float_of_string
v in
3920 then conf
.maxwait
<- None
3921 else conf
.maxwait
<- Some
f
3923 state
.text <- Printf.sprintf
"bad time `%s': %s" v @@ exntos exn
3925 src#
string "ghyll scroll"
3927 match conf
.ghyllscroll
with
3929 | Some nab
-> ghyllscroll_to_string nab
3932 try conf
.ghyllscroll
<- ghyllscroll_of_string
v
3935 state
.text <- Printf.sprintf
"bad ghyll `%s': %s" v msg
3937 state
.text <- Printf.sprintf
"bad ghyll `%s': %s" v @@ exntos exn
3939 src#
string "selection command"
3940 (fun () -> conf
.selcmd
)
3941 (fun v -> conf
.selcmd
<- v);
3942 src#
string "synctex command"
3943 (fun () -> conf
.stcmd
)
3944 (fun v -> conf
.stcmd
<- v);
3945 src#
string "pax command"
3946 (fun () -> conf
.paxcmd
)
3947 (fun v -> conf
.paxcmd
<- v);
3948 src#
string "ask password command"
3949 (fun () -> conf
.passcmd)
3950 (fun v -> conf
.passcmd <- v);
3951 src#
string "save path command"
3952 (fun () -> conf
.savecmd
)
3953 (fun v -> conf
.savecmd
<- v);
3954 src#colorspace
"color space"
3955 (fun () -> CSTE.to_string conf
.colorspace
)
3957 conf
.colorspace
<- CSTE.of_int
v;
3961 src#paxmark
"pax mark method"
3962 (fun () -> MTE.to_string conf
.paxmark
)
3963 (fun v -> conf
.paxmark
<- MTE.of_int
v);
3964 if bousable
() && !opengl_has_pbo
3967 (fun () -> conf
.usepbo
)
3968 (fun v -> conf
.usepbo
<- v);
3969 src#
bool "mouse wheel scrolls pages"
3970 (fun () -> conf
.wheelbypage
)
3971 (fun v -> conf
.wheelbypage
<- v);
3972 src#
bool "open remote links in a new instance"
3973 (fun () -> conf
.riani
)
3974 (fun v -> conf
.riani
<- v);
3975 src#
bool "edit annotations inline"
3976 (fun () -> conf
.annotinline
)
3977 (fun v -> conf
.annotinline
<- 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) ->
4304 gotopage1 pageno top;
4307 | Ulinkuri
s -> gotouri
s
4309 | Uremote
(filename
, pageno) ->
4310 let path = getpath filename
in
4315 let command = Printf.sprintf
"%s -page %d %S" !selfexec pageno path in
4316 match spawn
command [] with
4318 | (exception exn
) ->
4319 dolog
"failed to execute `%s': %s" command @@ exntos exn
4321 let anchor = getanchor
() in
4322 let ranchor = state
.path, state
.password, anchor, state
.origin
in
4323 state
.origin
<- E.s;
4324 state
.anchor <- (pageno, 0.0, 0.0);
4325 state
.ranchors
<- ranchor :: state
.ranchors
;
4328 else impmsg "cannot find %s" filename
4330 | Uremotedest
(filename
, destname
) ->
4331 let path = getpath filename
in
4336 let command = !selfexec ^
" " ^
path ^
" -dest " ^ destname
in
4337 match spawn
command [] with
4338 | (exception exn
) ->
4339 dolog
"failed to execute `%s': %s" command @@ exntos exn
4342 let anchor = getanchor
() in
4343 let ranchor = state
.path, state
.password, anchor, state
.origin
in
4344 state
.origin
<- E.s;
4345 state
.nameddest
<- destname
;
4346 state
.ranchors
<- ranchor :: state
.ranchors
;
4349 else impmsg "cannot find %s" filename
4351 | Uunexpected
_ | Ulaunch
_ | Unamed
_ | Utext
_ | Unone
-> ()
4352 | Uannotation
(opaque, slinkindex
) -> enterannotmode opaque slinkindex
4355 let gotooutline (_, _, kind
) =
4359 let (pageno, y, _) = anchor in
4361 (if conf
.presentation
then (pageno, y, 1.0) else anchor)
4365 | Ouri
uri -> gotounder (Ulinkuri
uri)
4366 | Olaunch cmd
-> gotounder (Ulaunch cmd
)
4367 | Oremote remote
-> gotounder (Uremote remote
)
4368 | Ohistory hist
-> gotohist hist
4369 | Oremotedest remotedest
-> gotounder (Uremotedest remotedest
)
4372 class outlinesoucebase fetchoutlines
= object (self)
4373 inherit lvsourcebase
4374 val mutable m_items
= E.a
4375 val mutable m_minfo
= E.a
4376 val mutable m_orig_items
= E.a
4377 val mutable m_orig_minfo
= E.a
4378 val mutable m_narrow_patterns
= []
4379 val mutable m_gen
= -1
4381 method getitemcount
= Array.length m_items
4384 let s, n, _ = m_items
.(n) in
4387 method exit ~
(uioh:uioh) ~cancel ~
active ~
(first:int) ~pan
:
4389 ignore
(uioh, first);
4391 if m_narrow_patterns
= []
4392 then m_orig_items
, m_orig_minfo
4393 else m_items
, m_minfo
4400 gotooutline m_items
.(active);
4408 method hasaction
(_:int) = true
4411 if Array.length m_items
!= Array.length m_orig_items
4414 match m_narrow_patterns
with
4416 | many
-> String.concat
"@Uellipsis" (List.rev many
)
4418 "Narrowed to " ^
s ^
" (ctrl-u to restore)"
4422 match m_narrow_patterns
with
4425 | head
:: _ -> "@Uellipsis" ^ head
4427 method narrow
pattern =
4428 match Str.regexp_case_fold
pattern with
4429 | (exception _) -> ()
4431 let rec loop accu minfo n =
4434 m_items
<- Array.of_list
accu;
4435 m_minfo
<- Array.of_list
minfo;
4438 let (s, _, _) as o = m_items
.(n) in
4440 match Str.search_forward re
s 0 with
4441 | (exception Not_found
) -> accu, minfo
4442 | first -> o :: accu, (first, Str.match_end
()) :: minfo
4444 loop accu minfo (n-1)
4446 loop [] [] (Array.length m_items
- 1)
4448 method! getminfo
= m_minfo
4451 m_orig_items
<- fetchoutlines
();
4452 m_minfo
<- m_orig_minfo
;
4453 m_items
<- m_orig_items
4455 method add_narrow_pattern
pattern =
4456 m_narrow_patterns
<- pattern :: m_narrow_patterns
4458 method del_narrow_pattern
=
4459 match m_narrow_patterns
with
4460 | _ :: rest
-> m_narrow_patterns
<- rest
4465 match m_narrow_patterns
with
4466 | pattern :: [] -> self#narrow
pattern; pattern
4468 List.fold_left
(fun accu pattern ->
4469 self#narrow
pattern;
4470 pattern ^
"@Uellipsis" ^
accu) E.s list
4472 method calcactive
(_:anchor) = 0
4474 method reset
anchor items =
4475 if state
.gen
!= m_gen
4477 m_orig_items
<- items;
4479 m_narrow_patterns
<- [];
4481 m_orig_minfo
<- E.a;
4485 if items != m_orig_items
4487 m_orig_items
<- items;
4488 if m_narrow_patterns
== []
4489 then m_items
<- items;
4492 let active = self#calcactive
anchor in
4494 m_first
<- firstof m_first
active
4498 let outlinesource fetchoutlines
=
4500 inherit outlinesoucebase fetchoutlines
4501 method! calcactive
anchor =
4502 let rely = getanchory anchor in
4503 let rec loop n best bestd
=
4504 if n = Array.length m_items
4507 let _, _, kind
= m_items
.(n) in
4510 let orely = getanchory anchor in
4511 let d = abs
(orely - rely) in
4514 else loop (n+1) best bestd
4515 | Onone
| Oremote
_ | Olaunch
_
4516 | Oremotedest
_ | Ouri
_ | Ohistory
_ ->
4517 loop (n+1) best bestd
4523 let enteroutlinemode, enterbookmarkmode
, enterhistmode
=
4524 let mkselector sourcetype
=
4525 let fetchoutlines () =
4526 match sourcetype
with
4527 | `bookmarks
-> Array.of_list state
.bookmarks
4528 | `outlines
-> state
.outlines
4529 | `history
-> genhistoutlines ()
4532 if sourcetype
= `history
4533 then new outlinesoucebase
fetchoutlines
4534 else outlinesource fetchoutlines
4537 let outlines = fetchoutlines () in
4538 if Array.length
outlines = 0
4540 showtext ' ' errmsg
;
4544 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
4545 let anchor = getanchor
() in
4546 source#reset
anchor outlines;
4547 state
.text <- source#greetmsg
;
4549 coe (new outlinelistview ~zebra
:(sourcetype
=`history
) ~
source);
4550 G.postRedisplay "enter selector";
4553 let mkenter sourcetype errmsg
=
4554 let enter = mkselector sourcetype
in
4555 fun () -> enter errmsg
4557 (**)mkenter `
outlines "document has no outline"
4558 , mkenter `bookmarks
"document has no bookmarks (yet)"
4559 , mkenter `history
"history is empty"
4562 let quickbookmark ?title
() =
4563 match state
.layout with
4569 let tm = Unix.localtime
(now
()) in
4571 "Quick (page %d) (bookmarked at %02d/%02d/%d %02d:%02d)"
4575 (tm.Unix.tm_year
+ 1900)
4578 | Some
title -> title
4580 state
.bookmarks
<- (title, 0, Oanchor
(getanchor1
l)) :: state
.bookmarks
4583 let setautoscrollspeed step goingdown
=
4584 let incr = max
1 ((abs step
) / 2) in
4585 let incr = if goingdown
then incr else -incr in
4586 let astep = boundastep state
.winh
(step
+ incr) in
4587 state
.autoscroll
<- Some
astep;
4591 match conf
.columns
with
4593 | Csingle
_ | Cmulti
_ -> state
.x != 0 || conf
.zoom > 1.0
4596 let panbound x = bound
x (-state
.w) (wadjsb () + state
.winw
);;
4598 let existsinrow pageno (columns
, coverA
, coverB
) p =
4599 let last = ((pageno - coverA
) mod columns
) + columns
in
4600 let rec any = function
4603 if l.pageno = coverA
- 1 || l.pageno = state
.pagecount
- coverB
4607 then (if l.pageno = last then false else any rest
)
4615 match state
.layout with
4617 let pageno = page_of_y state
.y in
4618 gotoghyll (getpagey
(pageno+1))
4620 match conf
.columns
with
4622 if conf
.presentation
&& rest
== [] && l.pageh
> l.pagey + l.pagevh
4624 let y = clamp (pgscale state
.winh
) in
4627 let pageno = min
(l.pageno+1) (state
.pagecount
-1) in
4628 gotoghyll (getpagey
pageno)
4629 | Cmulti
((c, _, _) as cl, _) ->
4630 if conf
.presentation
4631 && (existsinrow l.pageno cl
4632 (fun l -> l.pageh
> l.pagey + l.pagevh))
4634 let y = clamp (pgscale state
.winh
) in
4637 let pageno = min
(l.pageno+c) (state
.pagecount
-1) in
4638 gotoghyll (getpagey
pageno)
4640 if l.pageno < state
.pagecount
- 1 || l.pagecol
< n - 1
4642 let pagey, pageh
= getpageyh
l.pageno in
4643 let pagey = pagey + pageh
* l.pagecol
in
4644 let ips = if l.pagecol
= 0 then 0 else conf
.interpagespace
in
4645 gotoghyll (pagey + pageh
+ ips)
4649 match state
.layout with
4651 let pageno = page_of_y state
.y in
4652 gotoghyll (getpagey
(pageno-1))
4654 match conf
.columns
with
4656 if conf
.presentation
&& l.pagey != 0
4658 gotoghyll (clamp (pgscale ~
-(state
.winh
)))
4660 let pageno = max
0 (l.pageno-1) in
4661 gotoghyll (getpagey
pageno)
4662 | Cmulti
((c, _, coverB
) as cl, _) ->
4663 if conf
.presentation
&&
4664 (existsinrow l.pageno cl (fun l -> l.pagey != 0))
4666 gotoghyll (clamp (pgscale ~
-(state
.winh
)))
4669 if l.pageno = state
.pagecount
- coverB
4673 let pageno = max
0 (l.pageno-decr) in
4674 gotoghyll (getpagey
pageno)
4682 let pageno = max
0 (l.pageno-1) in
4683 let pagey, pageh
= getpageyh
pageno in
4686 let pagey, pageh
= getpageyh
l.pageno in
4687 pagey + pageh
* (l.pagecol
-1) - conf
.interpagespace
4693 if emptystr conf
.savecmd
4694 then error
"don't know where to save modified document"
4696 let savecmd = Str.global_replace percentsre state
.path conf
.savecmd in
4699 (fun s -> error
"failed to obtain path to the saved copy: %s" s)
4704 let tmp = path ^
".tmp" in
4706 Unix.rename
tmp path;
4709 let viewkeyboard key mask
=
4711 let mode = state
.mode in
4712 state
.mode <- Textentry
(te, fun _ -> state
.mode <- mode);
4715 G.postRedisplay "view:enttext"
4717 let ctrl = Wsi.withctrl mask
in
4719 if key >= 0xffb0 && key < 0xffb9 then key - 0xffb0 + 48 else key
4725 if hasunsavedchanges
()
4729 if conf
.angle
mod 360 = 0 && not
(isbirdseye state
.mode)
4731 state
.mode <- LinkNav
(Ltgendir
0);
4734 else impmsg "keyboard link navigation does not work under rotation"
4737 begin match state
.mstate
with
4740 G.postRedisplay "kill rect";
4743 | Mscrolly
| Mscrollx
4746 begin match state
.mode with
4749 G.postRedisplay "esc leave linknav"
4753 match state
.ranchors
with
4755 | (path, password, anchor, origin
) :: rest
->
4756 state
.ranchors
<- rest
;
4757 state
.anchor <- anchor;
4758 state
.origin
<- origin
;
4759 state
.nameddest
<- E.s;
4760 opendoc path password
4765 gotoghyll (getnav ~
-1)
4776 Hashtbl.iter
(fun _ opaque ->
4778 Hashtbl.clear state
.prects
) state
.pagemap
;
4779 G.postRedisplay "dehighlight";
4781 | @slash
| @question
->
4782 let ondone isforw
s =
4783 cbput state
.hists
.pat
s;
4784 state
.searchpattern
<- s;
4787 let s = String.make
1 (Char.chr
key) in
4788 enttext (s, E.s, Some
(onhist state
.hists
.pat
),
4789 textentry, ondone (key = @slash
), true)
4791 | @plus
| @kpplus
| @equals
when ctrl ->
4792 let incr = if conf
.zoom +. 0.01 > 0.1 then 0.1 else 0.01 in
4793 setzoom (conf
.zoom +. incr)
4795 | @plus
| @kpplus
->
4798 try int_of_string
s with exc
->
4799 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exc
;
4805 state
.text <- "page bias is now " ^ string_of_int
n;
4808 enttext ("page bias: ", E.s, None
, intentry, ondone, true)
4810 | @minus
| @kpminus
when ctrl ->
4811 let decr = if conf
.zoom -. 0.1 < 0.1 then 0.01 else 0.1 in
4812 setzoom (max
0.01 (conf
.zoom -. decr))
4814 | @minus
| @kpminus
->
4815 let ondone msg
= state
.text <- msg
in
4817 "option [acfhilpstvxACFPRSZTISM]: ", E.s, None
,
4818 optentry state
.mode, ondone, true
4829 | (@1 | @2) when ctrl && conf
.fitmodel
!= FitPage
-> (* ctrl-1/2 *)
4831 match conf
.columns
with
4832 | Csingle
_ | Cmulti
_ -> 1
4833 | Csplit
(n, _) -> n
4835 let h = state
.winh
-
4836 conf
.interpagespace
lsl (if conf
.presentation
then 1 else 0)
4838 let zoom = zoomforh state
.winw
h (vscrollw ()) cols in
4839 if zoom > 0.0 && (key = @2 || zoom < 1.0)
4844 match conf
.fitmodel
with
4845 | FitWidth
-> FitProportional
4846 | FitProportional
-> FitPage
4847 | FitPage
-> FitWidth
4849 state
.text <- "fit model: " ^
FMTE.to_string
fm;
4850 reqlayout conf
.angle
fm
4852 | @4 when ctrl -> (* ctrl-4 *)
4853 let zoom = getmaxw
() /. float state
.winw
in
4854 if zoom > 0.0 then setzoom zoom
4862 | (48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57)
4863 when not
ctrl -> (* 0..9 *)
4866 try int_of_string
s with exc
->
4867 state
.text <- Printf.sprintf
"bad integer `%s': %s" s @@ exntos exc
;
4873 cbput state
.hists
.pag
(string_of_int
n);
4874 gotopage1 (n + conf
.pagebias
- 1) 0;
4877 let pageentry text key =
4878 match Char.unsafe_chr
key with
4879 | '
g'
-> TEdone
text
4880 | _ -> intentry text key
4882 let text = String.make
1 (Char.chr
key) in
4883 enttext (":", text, Some
(onhist state
.hists
.pag
),
4884 pageentry, ondone, true)
4887 conf
.scrollb
<- if conf
.scrollb
= 0 then (scrollbvv
lor scrollbhv
) else 0;
4888 reshape state
.winw state
.winh
;
4891 state
.bzoom
<- not state
.bzoom
;
4893 showtext ' '
("block zoom " ^
if state
.bzoom
then "on" else "off")
4896 conf
.hlinks
<- not conf
.hlinks
;
4897 state
.text <- "highlightlinks " ^
if conf
.hlinks
then "on" else "off";
4898 G.postRedisplay "toggle highlightlinks";
4901 if conf
.angle
mod 360 = 0
4903 state
.glinks
<- true;
4904 let mode = state
.mode in
4907 (":", E.s, None
, linknentry, linknact gotounder, false),
4909 state
.glinks
<- false;
4913 G.postRedisplay "view:linkent(F)"
4915 else impmsg "hint mode does not work under rotation"
4918 state
.glinks
<- true;
4919 let mode = state
.mode in
4920 state
.mode <- Textentry
(
4922 ":", E.s, None
, linknentry, linknact (fun under ->
4923 selstring (undertext under);
4927 state
.glinks
<- false;
4931 G.postRedisplay "view:linkent"
4934 begin match state
.autoscroll
with
4936 conf
.autoscrollstep
<- step
;
4937 state
.autoscroll
<- None
4939 if conf
.autoscrollstep
= 0
4940 then state
.autoscroll
<- Some
1
4941 else state
.autoscroll
<- Some conf
.autoscrollstep
4945 launchpath () (* XXX where do error messages go? *)
4948 setpresentationmode (not conf
.presentation
);
4949 showtext ' '
("presentation mode " ^
4950 if conf
.presentation
then "on" else "off");
4953 if List.mem
Wsi.Fullscreen state
.winstate
4954 then Wsi.reshape conf
.cwinw conf
.cwinh
4955 else Wsi.fullscreen
()
4958 search state
.searchpattern
false
4961 search state
.searchpattern
true
4964 begin match state
.layout with
4967 gotoghyll (getpagey
l.pageno)
4973 | @delete
| @kpdelete
-> (* delete *)
4977 showtext ' '
(describe_location ());
4980 begin match state
.layout with
4983 Wsi.reshape (l.pagew
+ vscrollw ()) l.pageh
;
4988 enterbookmarkmode
()
4996 | @e when Buffer.length state
.errmsgs
> 0 ->
5001 match state
.layout with
5006 (s, 0, Oanchor
(getanchor1
l)) :: state
.bookmarks
5009 enttext ("bookmark: ", E.s, None
, textentry, ondone, true)
5013 showtext ' '
"Quick bookmark added";
5016 begin match state
.layout with
5018 let rect = getpdimrect
l.pagedimno
in
5022 (truncate
(1.8 *. (rect.(1) -. rect.(0))),
5023 truncate
(1.2 *. (rect.(3) -. rect.(0))))
5025 (truncate
(rect.(1) -. rect.(0)),
5026 truncate
(rect.(3) -. rect.(0)))
5028 let w = truncate
((float w)*.conf
.zoom)
5029 and h = truncate
((float h)*.conf
.zoom) in
5032 state
.anchor <- getanchor
();
5033 Wsi.reshape (w + vscrollw ()) (h + conf
.interpagespace
)
5035 G.postRedisplay "z";
5040 | @x -> state
.roam
()
5043 reqlayout (conf
.angle
+
5044 (if key = @Gt
then 30 else -30)) conf
.fitmodel
5048 bound
(conf
.colorscale
+. (if key = 93 then 0.1 else -0.1)) 0.0 1.0
5050 G.postRedisplay "brightness";
5052 | @c when state
.mode = View
->
5057 let m = (wadjsb () + state
.winw
- state
.w) / 2 in
5059 gotoy_and_clear_text state
.y
5063 match state
.prevcolumns
with
5064 | None
-> (1, 0, 0), 1.0
5065 | Some
(columns
, z
) ->
5068 | Csplit
(c, _) -> -c, 0, 0
5069 | Cmulti
((c, a, b), _) -> c, a, b
5070 | Csingle
_ -> 1, 0, 0
5074 setcolumns View
c a b;
5077 | @down
| @up
when ctrl && Wsi.withshift mask
->
5078 let zoom, x = state
.prevzoom
in
5082 | @k
| @up
| @kpup
->
5083 begin match state
.autoscroll
with
5085 begin match state
.mode with
5086 | Birdseye beye
-> upbirdseye 1 beye
5091 then gotoy_and_clear_text (clamp ~
-(state
.winh
/2))
5093 if not
(Wsi.withshift mask
) && conf
.presentation
5095 else gotoghyll1 true (clamp (-conf
.scrollstep
))
5099 setautoscrollspeed n false
5102 | @j
| @down
| @kpdown
->
5103 begin match state
.autoscroll
with
5105 begin match state
.mode with
5106 | Birdseye beye
-> downbirdseye 1 beye
5111 then gotoy_and_clear_text (clamp (state
.winh
/2))
5113 if not
(Wsi.withshift mask
) && conf
.presentation
5115 else gotoghyll1 true (clamp (conf
.scrollstep
))
5119 setautoscrollspeed n true
5122 | @left | @right
| @kpleft
| @kpright
when not
(Wsi.withalt mask
) ->
5128 else conf
.hscrollstep
5130 let dx = if key = @left || key = @kpleft
then dx else -dx in
5131 state
.x <- panbound (state
.x + dx);
5132 gotoy_and_clear_text state
.y
5135 G.postRedisplay "left/right"
5138 | @prior
| @kpprior
->
5142 match state
.layout with
5144 | l :: _ -> state
.y - l.pagey
5146 clamp (pgscale (-state
.winh
))
5150 | @next | @kpnext
->
5154 match List.rev state
.layout with
5156 | l :: _ -> getpagey
l.pageno
5158 clamp (pgscale state
.winh
)
5162 | @g | @home
| @kphome
->
5165 | @G
| @jend
| @kpend
->
5167 gotoghyll (clamp state
.maxy)
5169 | @right
| @kpright
when Wsi.withalt mask
->
5170 gotoghyll (getnav 1)
5171 | @left | @kpleft
when Wsi.withalt mask
->
5172 gotoghyll (getnav ~
-1)
5177 | @v when conf
.debug
->
5180 match getopaque l.pageno with
5183 let x0, y0, x1, y1 = pagebbox
opaque in
5184 let a,b = float x0, float y0 in
5185 let c,d = float x1, float y0 in
5186 let e,f = float x1, float y1 in
5187 let h,j
= float x0, float y1 in
5188 let rect = (a,b,c,d,e,f,h,j
) in
5190 let color = (0.0, 0.0, 1.0 /. (l.pageno mod 3 |> float), 0.5) in
5191 state
.rects
<- (l.pageno, color, rect) :: state
.rects
;
5193 G.postRedisplay "v";
5196 let mode = state
.mode in
5197 let cmd = ref E.s in
5198 let onleave = function
5199 | Cancel
-> state
.mode <- mode
5202 match getopaque l.pageno with
5203 | Some
opaque -> pipesel opaque !cmd
5204 | None
-> ()) state
.layout;
5208 cbput state
.hists
.sel
s;
5212 "| ", !cmd, Some
(onhist state
.hists
.sel
), textentry, ondone, true
5214 G.postRedisplay "|";
5215 state
.mode <- Textentry
(te, onleave);
5218 vlog "huh? %s" (Wsi.keyname
key)
5221 let linknavkeyboard key mask
linknav =
5222 let getpage pageno =
5223 let rec loop = function
5225 | l :: _ when l.pageno = pageno -> Some
l
5226 | _ :: rest
-> loop rest
5227 in loop state
.layout
5229 let doexact (pageno, n) =
5230 match getopaque pageno, getpage pageno with
5231 | Some
opaque, Some
l ->
5232 if key = @enter || key = @kpenter
5234 let under = getlink
opaque n in
5235 G.postRedisplay "link gotounder";
5242 Some
(findlink
opaque LDfirst
), -1
5245 Some
(findlink
opaque LDlast
), 1
5248 Some
(findlink
opaque (LDleft
n)), -1
5251 Some
(findlink
opaque (LDright
n)), 1
5254 Some
(findlink
opaque (LDup
n)), -1
5257 Some
(findlink
opaque (LDdown
n)), 1
5262 begin match findpwl
l.pageno dir with
5266 state
.mode <- LinkNav
(Ltgendir
dir);
5267 let y, h = getpageyh
pageno in
5270 then y + h - state
.winh
5275 begin match getopaque pageno, getpage pageno with
5276 | Some
opaque, Some
_ ->
5278 let ld = if dir > 0 then LDfirst
else LDlast
in
5281 begin match link with
5283 showlinktype (getlink
opaque m);
5284 state
.mode <- LinkNav
(Ltexact
(pageno, m));
5285 G.postRedisplay "linknav jpage";
5286 | Lnotfound
-> notfound dir
5292 begin match opt with
5293 | Some Lnotfound
-> pwl l dir;
5294 | Some
(Lfound
m) ->
5298 let _, y0, _, y1 = getlinkrect
opaque m in
5300 then gotopage1 l.pageno y0
5302 let d = fstate
.fontsize
+ 1 in
5303 if y1 - l.pagey > l.pagevh - d
5304 then gotopage1 l.pageno (y1 - state
.winh
- hscrollh () + d)
5305 else G.postRedisplay "linknav";
5307 showlinktype (getlink
opaque m);
5308 state
.mode <- LinkNav
(Ltexact
(l.pageno, m));
5311 | None
-> viewkeyboard key mask
5313 | _ -> viewkeyboard key mask
5318 G.postRedisplay "leave linknav"
5322 | Ltgendir
_ | Ltnotready
_ -> viewkeyboard key mask
5323 | Ltexact exact
-> doexact exact
5326 let keyboard key mask
=
5327 if (key = @g && Wsi.withctrl mask
) && not
(istextentry state
.mode)
5328 then wcmd "interrupt"
5329 else state
.uioh <- state
.uioh#
key key mask
5332 let birdseyekeyboard key mask
5333 ((oconf
, leftx
, pageno, hooverpageno
, anchor) as beye
) =
5335 match conf
.columns
with
5337 | Cmulti
((c, _, _), _) -> c
5338 | Csplit
_ -> failwith
"bird's eye split mode"
5340 let pgh layout = List.fold_left
5341 (fun m l -> max
l.pageh
m) state
.winh
layout in
5343 | @l when Wsi.withctrl mask
->
5344 let y, h = getpageyh
pageno in
5345 let top = (state
.winh
- h) / 2 in
5346 gotoy (max
0 (y - top))
5347 | @enter | @kpenter
-> leavebirdseye beye
false
5348 | @escape
-> leavebirdseye beye
true
5349 | @up
-> upbirdseye incr beye
5350 | @down
-> downbirdseye incr beye
5351 | @left -> upbirdseye 1 beye
5352 | @right
-> downbirdseye 1 beye
5355 begin match state
.layout with
5359 state
.mode <- Birdseye
(
5360 oconf
, leftx
, l.pageno, hooverpageno
, anchor
5362 gotopage1 l.pageno 0;
5365 let layout = layout state
.x (state
.y-state
.winh
)
5367 (pgh state
.layout) in
5369 | [] -> gotoy (clamp (-state
.winh
))
5371 state
.mode <- Birdseye
(
5372 oconf
, leftx
, l.pageno, hooverpageno
, anchor
5374 gotopage1 l.pageno 0
5377 | [] -> gotoy (clamp (-state
.winh
))
5381 begin match List.rev state
.layout with
5383 let layout = layout state
.x
5384 (state
.y + (pgh state
.layout))
5385 state
.winw state
.winh
in
5386 begin match layout with
5388 let incr = l.pageh
- l.pagevh in
5393 oconf
, leftx
, state
.pagecount
- 1, hooverpageno
, anchor
5395 G.postRedisplay "birdseye pagedown";
5397 else gotoy (clamp (incr + conf
.interpagespace
*2));
5401 Birdseye
(oconf
, leftx
, l.pageno, hooverpageno
, anchor);
5402 gotopage1 l.pageno 0;
5405 | [] -> gotoy (clamp state
.winh
)
5409 state
.mode <- Birdseye
(oconf
, leftx
, 0, hooverpageno
, anchor);
5413 let pageno = state
.pagecount
- 1 in
5414 state
.mode <- Birdseye
(oconf
, leftx
, pageno, hooverpageno
, anchor);
5415 if not
(pagevisible state
.layout pageno)
5418 match List.rev state
.pdims
with
5420 | (_, _, h, _) :: _ -> h
5422 gotoy (max
0 (getpagey
pageno - (state
.winh
- h - conf
.interpagespace
)))
5423 else G.postRedisplay "birdseye end";
5425 | _ -> viewkeyboard key mask
5430 match state
.mode with
5431 | Textentry
_ -> scalecolor 0.4
5433 | View
-> scalecolor 1.0
5434 | Birdseye
(_, _, pageno, hooverpageno
, _) ->
5435 if l.pageno = hooverpageno
5438 if l.pageno = pageno
5440 let c = scalecolor 1.0 in
5442 GlDraw.line_width
3.0;
5443 let dispx = xadjsb () + l.pagedispx in
5445 (float (dispx-1)) (float (l.pagedispy-1))
5446 (float (dispx+l.pagevw+1))
5447 (float (l.pagedispy+l.pagevh+1))
5449 GlDraw.line_width
1.0;
5458 let postdrawpage l linkindexbase
=
5459 match getopaque l.pageno with
5461 if tileready l l.pagex
l.pagey
5463 let x = l.pagedispx - l.pagex
+ xadjsb ()
5464 and y = l.pagedispy - l.pagey in
5466 match conf
.columns
with
5467 | Csingle
_ | Cmulti
_ ->
5468 (if conf
.hlinks
then 1 else 0)
5470 && not
(isbirdseye state
.mode) then 2 else 0)
5474 match state
.mode with
5475 | Textentry
((_, s, _, _, _, _), _) when state
.glinks
-> s
5481 Hashtbl.find_all state
.prects
l.pageno |>
5482 List.iter
(fun vals
-> drawprect
opaque x y vals
);
5483 postprocess
opaque hlmask x y (linkindexbase
, s, conf
.hfsize
);
5488 let scrollindicator () =
5489 let sbw, ph
, sh = state
.uioh#
scrollph in
5490 let sbh, pw, sw = state
.uioh#scrollpw
in
5495 else ((state
.winw
- sbw), state
.winw
, 0)
5498 GlDraw.color (0.64, 0.64, 0.64);
5499 filledrect (float x0) 0. (float x1) (float state
.winh
);
5501 (float hx0
) (float (state
.winh
- sbh))
5502 (float (hx0
+ wadjsb () + state
.winw
)) (float state
.winh
)
5504 GlDraw.color (0.0, 0.0, 0.0);
5506 filledrect (float x0) ph
(float x1) (ph
+. sh);
5507 let pw = pw +. float hx0
in
5508 filledrect pw (float (state
.winh
- sbh)) (pw +. sw) (float state
.winh
);
5512 match state
.mstate
with
5513 | Mnone
| Mscrolly
| Mscrollx
| Mpan
_ | Mzoom
_ | Mzoomrect
_ ->
5516 | Msel
((x0, y0), (x1, y1)) ->
5517 let identify opaque l px py = Some
(opaque, l.pageno, px, py) in
5518 let o0,n0
,px0
,py0
= onppundermouse identify x0 y0 (~
< E.s, -1, 0, 0) in
5519 let _o1,n1
,px1
,py1
= onppundermouse identify x1 y1 (~
< E.s, -1, 0, 0) in
5520 if n0
!= -1 && n0
= n1
then seltext
o0 (px0
, py0
, px1
, py1
);
5523 let showrects = function [] -> () | rects
->
5525 GlDraw.color (0.0, 0.0, 1.0) ~
alpha:0.5;
5526 GlFunc.blend_func ~
src:`src_alpha ~dst
:`one_minus_src_alpha
;
5528 (fun (pageno, c, (x0, y0, x1, y1, x2
, y2
, x3
, y3
)) ->
5530 if l.pageno = pageno
5532 let dx = float (l.pagedispx - l.pagex
) in
5533 let dy = float (l.pagedispy - l.pagey) in
5534 let r, g, b, alpha = c in
5535 GlDraw.color (r, g, b) ~
alpha;
5536 Raw.sets_float state
.vraw ~
pos:0
5541 GlArray.vertex `two state
.vraw
;
5542 GlArray.draw_arrays `triangle_strip ~
first:0 ~count
:4;
5551 begin match conf
.columns
, state
.layout with
5552 | Csingle
_, _ :: _ ->
5553 GlDraw.color (scalecolor2 conf
.bgcolor
);
5555 List.fold_left
(fun y l ->
5558 let x1 = l.pagedispx + xadjsb () in
5559 let y1 = (l.pagedispy + l.pagevh) in
5560 filledrect (float x0) (float y0) (float x1) (float y1);
5561 let x0 = x1 + l.pagevw in
5562 let x1 = state
.winw
in
5563 filledrect1 (float x0) (float y0) (float x1) (float y1);
5567 and x1 = state
.winw
in
5569 and y1 = l.pagedispy in
5570 filledrect1 (float x0) (float y0) (float x1) (float y1);
5572 l.pagedispy + l.pagevh) 0 state
.layout
5575 and x1 = state
.winw
in
5577 and y1 = state
.winh
in
5578 filledrect1 (float x0) (float y0) (float x1) (float y1)
5579 | (Cmulti
_ | Csplit
_), _ | Csingle
_, [] ->
5580 GlClear.color (scalecolor2 conf
.bgcolor
);
5581 GlClear.clear
[`
color];
5583 List.iter
drawpage state
.layout;
5585 match state
.mode with
5586 | LinkNav
(Ltexact
(pageno, linkno
)) ->
5587 begin match getopaque pageno with
5589 let dx = xadjsb () in
5590 let x0, y0, x1, y1 = getlinkrect
opaque linkno
in
5591 let x0 = x0 + dx and x1 = x1 + dx in
5592 let color = (0.0, 0.0, 0.5, 0.5) in
5599 | None
-> state
.rects
5601 | LinkNav
(Ltgendir
_) | LinkNav
(Ltnotready
_)
5604 | View
-> state
.rects
5607 let rec postloop linkindexbase
= function
5609 let linkindexbase = linkindexbase + postdrawpage l linkindexbase in
5610 postloop linkindexbase rest
5614 postloop 0 state
.layout;
5616 begin match state
.mstate
with
5617 | Mzoomrect
((x0, y0), (x1, y1)) ->
5619 GlDraw.color (0.3, 0.3, 0.3) ~
alpha:0.5;
5620 GlFunc.blend_func ~
src:`src_alpha ~dst
:`one_minus_src_alpha
;
5621 filledrect (float x0) (float y0) (float x1) (float y1);
5625 | Mscrolly
| Mscrollx
5634 let zoomrect x y x1 y1 =
5637 and y0 = min
y y1 in
5638 gotoy (state
.y + y0);
5639 state
.anchor <- getanchor
();
5640 let zoom = (float state
.w) /. float (x1 - x0) in
5643 let adjw = wadjsb () + state
.winw
in
5645 then (adjw - state
.w) / 2
5648 match conf
.fitmodel
with
5649 | FitWidth
| FitProportional
-> simple ()
5651 match conf
.columns
with
5653 onppundermouse (fun _ l _ _ -> Some
l.pagedispx) x0 y0 x0
5654 | Cmulti
_ | Csingle
_ -> simple ()
5656 state
.x <- (state
.x + margin) - x0;
5661 let annot inline
x y =
5662 match unproject x y with
5663 | Some
(opaque, n, ux
, uy
) ->
5665 addannot
opaque ux uy
text;
5666 wcmd "freepage %s" (~
> opaque);
5667 Hashtbl.remove state
.pagemap
(n, state
.gen
);
5673 let ondone s = add s in
5674 let mode = state
.mode in
5675 state
.mode <- Textentry
(
5676 ("annotation: ", E.s, None
, textentry, ondone, true),
5677 fun _ -> state
.mode <- mode);
5680 G.postRedisplay "annot"
5682 add @@ getusertext E.s
5687 let g opaque l px py =
5688 match rectofblock
opaque px py with
5690 let x0 = a.(0) -. 20. in
5691 let x1 = a.(1) +. 20. in
5692 let y0 = a.(2) -. 20. in
5693 let zoom = (float state
.w) /. (x1 -. x0) in
5694 let pagey = getpagey
l.pageno in
5695 gotoy_and_clear_text (pagey + truncate
y0);
5696 state
.anchor <- getanchor
();
5697 let margin = (state
.w - l.pagew
)/2 in
5698 state
.x <- -truncate
x0 - margin;
5703 match conf
.columns
with
5705 impmsg "block zooming does not work properly in split columns mode"
5706 | Cmulti
_ | Csingle
_ -> onppundermouse g x y ()
5710 let winw = wadjsb () + state
.winw - 1 in
5711 let s = float x /. float winw in
5712 let destx = truncate
(float (state
.w + winw) *. s) in
5713 state
.x <- winw - destx;
5714 gotoy_and_clear_text state
.y;
5715 state
.mstate
<- Mscrollx
;
5719 let s = float y /. float state
.winh
in
5720 let desty = truncate
(float (state
.maxy - state
.winh
) *. s) in
5721 gotoy_and_clear_text desty;
5722 state
.mstate
<- Mscrolly
;
5725 let viewmulticlick clicks
x y mask
=
5726 let g opaque l px py =
5734 if markunder
opaque px py mark
5738 match getopaque l.pageno with
5740 | Some
opaque -> pipesel opaque cmd
5742 state
.roam
<- (fun () -> dopipe conf
.paxcmd
);
5743 if not
(Wsi.withctrl mask
) then dopipe conf
.selcmd
;
5748 G.postRedisplay "viewmulticlick";
5749 onppundermouse g x y (fun () -> impmsg "nothing to select") ();
5753 match conf
.columns
with
5755 | Csingle
_ | Cmulti
_ -> conf
.angle
mod 360 = 0
5758 let viewmouse button down
x y mask
=
5760 | n when (n == 4 || n == 5) && not down
->
5761 if Wsi.withctrl mask
5763 match state
.mstate
with
5764 | Mzoom
(oldn
, i
) ->
5772 if conf
.zoom +. 0.01 > 0.1 then 0.1 else 0.01
5774 if conf
.zoom -. 0.1 < 0.1 then -0.01 else -0.1
5776 let zoom = conf
.zoom -. incr in
5778 state
.mstate
<- Mzoom
(n, 0);
5780 state
.mstate
<- Mzoom
(n, i
+1);
5782 else state
.mstate
<- Mzoom
(n, 0)
5786 | Mscrolly
| Mscrollx
5788 | Mnone
-> state
.mstate
<- Mzoom
(n, 0)
5791 match state
.autoscroll
with
5792 | Some step
-> setautoscrollspeed step
(n=4)
5794 if conf
.wheelbypage
|| conf
.presentation
5803 then -conf
.scrollstep
5804 else conf
.scrollstep
5806 let incr = incr * 2 in
5807 let y = clamp incr in
5808 gotoy_and_clear_text y
5811 | n when (n = 6 || n = 7) && not down
&& canpan () ->
5813 panbound (state
.x + (if n = 7 then -2 else 2) * conf
.hscrollstep
);
5814 gotoy_and_clear_text state
.y
5816 | 1 when Wsi.withshift mask
->
5817 state
.mstate
<- Mnone
;
5820 match unproject x y with
5822 | Some
(_, pageno, ux
, uy
) ->
5823 let cmd = Printf.sprintf
5825 conf
.stcmd state
.path pageno ux uy
5827 match spawn
cmd [] with
5828 | (exception exn
) ->
5829 impmsg "execution of synctex command(%S) failed: %S"
5830 conf
.stcmd
@@ exntos exn
5834 | 1 when Wsi.withctrl mask
->
5837 Wsi.setcursor
Wsi.CURSOR_FLEUR
;
5838 state
.mstate
<- Mpan
(x, y)
5841 state
.mstate
<- Mnone
5846 if Wsi.withshift mask
5848 annot conf
.annotinline
x y;
5849 G.postRedisplay "addannot"
5853 Wsi.setcursor
Wsi.CURSOR_CYCLE
;
5854 state
.mstate
<- Mzoomrect
(p, p)
5857 match state
.mstate
with
5858 | Mzoomrect
((x0, y0), _) ->
5859 if abs
(x-x0) > 10 && abs
(y - y0) > 10
5860 then zoomrect x0 y0 x y
5863 G.postRedisplay "kill accidental zoom rect";
5867 | Mscrolly
| Mscrollx
5873 | 1 when vscrollhit x ->
5876 let _, position, sh = state
.uioh#
scrollph in
5877 if y > truncate
position && y < truncate
(position +. sh)
5878 then state
.mstate
<- Mscrolly
5881 state
.mstate
<- Mnone
5883 | 1 when y > state
.winh
- hscrollh () ->
5886 let _, position, sw = state
.uioh#scrollpw
in
5887 if x > truncate
position && x < truncate
(position +. sw)
5888 then state
.mstate
<- Mscrollx
5891 state
.mstate
<- Mnone
5893 | 1 when state
.bzoom
-> if not down
then zoomblock x y
5896 let dest = if down
then getunder x y else Unone
in
5897 begin match dest with
5900 | Uremote
_ | Uremotedest
_
5901 | Uunexpected
_ | Ulaunch
_ | Unamed
_ ->
5904 | Unone
when down
->
5905 Wsi.setcursor
Wsi.CURSOR_FLEUR
;
5906 state
.mstate
<- Mpan
(x, y);
5908 | Uannotation
(opaque, slinkindex
) -> enterannotmode opaque slinkindex
5910 | Unone
| Utext
_ ->
5915 state
.mstate
<- Msel
((x, y), (x, y));
5916 G.postRedisplay "mouse select";
5920 match state
.mstate
with
5923 | Mzoom
_ | Mscrollx
| Mscrolly
->
5924 state
.mstate
<- Mnone
5926 | Mzoomrect
((x0, y0), _) ->
5930 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
5931 state
.mstate
<- Mnone
5933 | Msel
((x0, y0), (x1, y1)) ->
5934 let rec loop = function
5938 let a0 = l.pagedispy in
5939 let a1 = a0 + l.pagevh in
5940 let b0 = l.pagedispx in
5941 let b1 = b0 + l.pagevw in
5942 ((y0 >= a0 && y0 <= a1) || (y1 >= a0 && y1 <= a1))
5943 && ((x0 >= b0 && x0 <= b1) || (x1 >= b0 && x1 <= b1))
5947 match getopaque l.pageno with
5950 match Unix.pipe
() with
5951 | (exception exn
) ->
5952 impmsg "cannot create sel pipe: %s" @@
5956 Ne.clo fd
(fun msg
->
5957 dolog
"%s close failed: %s" what msg
)
5960 try spawn
cmd [r, 0; w, -1]
5962 dolog
"cannot execute %S: %s"
5969 G.postRedisplay "copysel";
5971 else clo "Msel pipe/w" w;
5972 clo "Msel pipe/r" r;
5974 dosel conf
.selcmd
();
5975 state
.roam
<- dosel conf
.paxcmd
;
5987 let birdseyemouse button down
x y mask
5988 (conf
, leftx
, _, hooverpageno
, anchor) =
5991 let rec loop = function
5994 if y > l.pagedispy && y < l.pagedispy + l.pagevh
5995 && x > l.pagedispx && x < l.pagedispx + l.pagevw
5997 leavebirdseye (conf
, leftx
, l.pageno, hooverpageno
, anchor) false;
6003 | _ -> viewmouse button down
x y mask
6009 method key key mask
=
6010 begin match state
.mode with
6011 | Textentry
textentry -> textentrykeyboard key mask
textentry
6012 | Birdseye
birdseye -> birdseyekeyboard key mask
birdseye
6013 | View
-> viewkeyboard key mask
6014 | LinkNav
linknav -> linknavkeyboard key mask
linknav
6018 method button button bstate
x y mask
=
6019 begin match state
.mode with
6021 | View
-> viewmouse button bstate
x y mask
6022 | Birdseye beye
-> birdseyemouse button bstate
x y mask beye
6027 method multiclick clicks
x y mask
=
6028 begin match state
.mode with
6030 | View
-> viewmulticlick clicks
x y mask
6037 begin match state
.mode with
6039 | View
| Birdseye
_ | LinkNav
_ ->
6040 match state
.mstate
with
6041 | Mzoom
_ | Mnone
-> ()
6046 state
.mstate
<- Mpan
(x, y);
6048 then state
.x <- panbound (state
.x + dx);
6050 gotoy_and_clear_text y
6053 state
.mstate
<- Msel
(a, (x, y));
6054 G.postRedisplay "motion select";
6057 let y = min state
.winh
(max
0 y) in
6061 let x = min state
.winw (max
0 x) in
6064 | Mzoomrect
(p0
, _) ->
6065 state
.mstate
<- Mzoomrect
(p0
, (x, y));
6066 G.postRedisplay "motion zoomrect";
6070 method pmotion
x y =
6071 begin match state
.mode with
6072 | Birdseye
(conf
, leftx
, pageno, hooverpageno
, anchor) ->
6073 let rec loop = function
6075 if hooverpageno
!= -1
6077 state
.mode <- Birdseye
(conf
, leftx
, pageno, -1, anchor);
6078 G.postRedisplay "pmotion birdseye no hoover";
6081 if y > l.pagedispy && y < l.pagedispy + l.pagevh
6082 && x > l.pagedispx && x < l.pagedispx + l.pagevw
6084 state
.mode <- Birdseye
(conf
, leftx
, pageno, l.pageno, anchor);
6085 G.postRedisplay "pmotion birdseye hoover";
6095 match state
.mstate
with
6096 | Mpan
_ | Msel
_ | Mzoom
_ | Mscrolly
| Mscrollx
| Mzoomrect
_ -> ()
6104 let past, _, _ = !r in
6106 let delta = now -. past in
6109 else r := (now, x, y)
6113 method infochanged
_ = ()
6116 let maxy = state
.maxy - (if conf
.maxhfit
then state
.winh
else 0) in
6119 then 0.0, float state
.winh
6120 else scrollph state
.y maxy
6125 let winw = wadjsb () + state
.winw in
6126 let fwinw = float winw in
6128 let sw = fwinw /. float state
.w in
6129 let sw = fwinw *. sw in
6130 max
sw (float conf
.scrollh
)
6133 let maxx = state
.w + winw in
6134 let x = winw - state
.x in
6135 let percent = float x /. float maxx in
6136 (fwinw -. sw) *. percent
6138 hscrollh (), position, sw
6142 match state
.mode with
6143 | LinkNav
_ -> "links"
6144 | Textentry
_ -> "textentry"
6145 | Birdseye
_ -> "birdseye"
6148 findkeyhash conf
modename
6150 method eformsgs
= true
6151 method alwaysscrolly
= false
6154 let adderrmsg src msg
=
6155 Buffer.add_string state
.errmsgs msg
;
6156 state
.newerrmsgs
<- true;
6160 let adderrfmt src fmt
=
6161 Format.ksprintf
(fun s -> adderrmsg src s) fmt
;
6164 let addrect pageno r g b a x0 y0 x1 y1 =
6165 Hashtbl.add state
.prects
pageno [|r; g; b; a; x0; y0; x1; y1|];
6169 let cl = splitatspace cmds
in
6171 try Scanf.sscanf
s fmt
f
6173 adderrfmt "remote exec"
6174 "error processing '%S': %s\n" cmds
@@ exntos exn
6176 let rectx s pageno (r, g, b, a) x0 y0 x1 y1 =
6177 vlog "%s page %d color (%f %f %f %f) x0,y0,x1,y1 = %f %f %f %f"
6178 s pageno r g b a x0 y0 x1 y1;
6182 let _,w1,h1
,_ = getpagedim
pageno in
6183 let sw = float w1 /. float w
6184 and sh = float h1
/. float h in
6188 and y1s
= y1 *. sh in
6189 let rect = (x0s,y0s
,x1s
,y0s
,x1s
,y1s
,x0s,y1s
) in
6190 let color = (r, g, b, a) in
6191 if conf
.verbose
then debugrect rect;
6192 state
.rects <- (pageno, color, rect) :: state
.rects;
6197 | "reload" :: [] -> reload ()
6198 | "goto" :: args
:: [] ->
6199 scan args
"%u %f %f"
6201 let cmd, _ = state
.geomcmds
in
6203 then gotopagexy !wtmode pageno x y
6206 gotopagexy !wtmode pageno x y;
6209 state
.reprf
<- f state
.reprf
6211 | "goto1" :: args
:: [] -> scan args
"%u %f" gotopage
6212 | "gotor" :: args
:: [] ->
6214 (fun filename
pageno -> gotounder (Uremote
(filename
, pageno)))
6215 | "gotord" :: args
:: [] ->
6217 (fun filename
dest -> gotounder (Uremotedest
(filename
, dest)))
6218 | "rect" :: args
:: [] ->
6219 scan args
"%u %u %f %f %f %f"
6220 (fun pageno c x0 y0 x1 y1 ->
6221 let color = (0.0, 0.0, 1.0 /. float c, 0.5) in
6222 rectx "rect" pageno color x0 y0 x1 y1;
6224 | "prect" :: args
:: [] ->
6225 scan args
"%u %f %f %f %f %f %f %f %f"
6226 (fun pageno r g b alpha x0 y0 x1 y1 ->
6227 addrect pageno r g b alpha x0 y0 x1 y1;
6228 G.postRedisplay "prect"
6230 | "pgoto" :: args
:: [] ->
6231 scan args
"%u %f %f"
6234 match getopaque pageno with
6235 | Some
opaque -> opaque
6238 pgoto optopaque pageno x y;
6239 let rec fixx = function
6242 if l.pageno = pageno
6244 state
.x <- state
.x - l.pagedispx;
6251 match conf
.columns
with
6252 | Csingle
_ | Csplit
_ -> 1
6253 | Cmulti
((n, _, _), _) -> n
6255 layout 0 state
.y (state
.winw * mult) state
.winh
6259 | "activatewin" :: [] -> Wsi.activatewin
()
6260 | "quit" :: [] -> raise Quit
6261 | "clearrects" :: [] ->
6262 Hashtbl.clear state
.prects
;
6263 G.postRedisplay "clearrects"
6265 adderrfmt "remote command"
6266 "error processing remote command: %S\n" cmds
;
6270 let scratch = Bytes.create
80 in
6271 let buf = Buffer.create
80 in
6273 match tempfailureretry
(Unix.read fd
scratch 0) 80 with
6274 | (exception Unix.Unix_error
(Unix.EAGAIN
, _, _)) -> None
6277 if Buffer.length
buf > 0
6279 let s = Buffer.contents
buf in
6287 match Bytes.index_from
scratch ppos '
\n'
with
6288 | pos -> if pos >= n then -1 else pos
6289 | (exception Not_found
) -> -1
6293 Buffer.add_subbytes
buf scratch ppos
(nlpos-ppos
);
6294 let s = Buffer.contents
buf in
6300 Buffer.add_subbytes
buf scratch ppos
(n-ppos
);
6306 let remoteopen path =
6307 try Some
(Unix.openfile
path [Unix.O_NONBLOCK
; Unix.O_RDONLY
] 0o0)
6309 adderrfmt "remoteopen" "error opening %S: %s" path @@ exntos exn
;
6314 let gcconfig = ref E.s in
6315 let trimcachepath = ref E.s in
6316 let rcmdpath = ref E.s in
6317 let pageno = ref None
in
6318 let rootwid = ref 0 in
6319 let openlast = ref false in
6320 let nofc = ref false in
6321 let doreap = ref false in
6322 selfexec := Sys.executable_name
;
6325 [("-p", Arg.String
(fun s -> state
.password <- s),
6326 "<password> Set password");
6330 Config.fontpath
:= s;
6331 selfexec := !selfexec ^
" -f " ^
Filename.quote
s;
6333 "<path> Set path to the user interface font");
6337 selfexec := !selfexec ^
" -c " ^
Filename.quote
s;
6338 Config.confpath
:= s),
6339 "<path> Set path to the configuration file");
6341 ("-last", Arg.Set
openlast, " Open last document");
6343 ("-page", Arg.Int
(fun pageno1
-> pageno := Some
(pageno1
-1)),
6344 "<page-number> Jump to page");
6346 ("-tcf", Arg.String
(fun s -> trimcachepath := s),
6347 "<path> Set path to the trim cache file");
6349 ("-dest", Arg.String
(fun s -> state
.nameddest
<- s),
6350 "<named-destination> Set named destination");
6352 ("-wtmode", Arg.Set
wtmode, " Operate in wt mode");
6353 ("-cxack", Arg.Set
cxack, " Cut corners");
6355 ("-remote", Arg.String
(fun s -> rcmdpath := s),
6356 "<path> Set path to the remote commands source");
6358 ("-origin", Arg.String
(fun s -> state
.origin
<- s),
6359 "<original-path> Set original path");
6361 ("-gc", Arg.Set_string
gcconfig,
6362 "<script-path> Collect garbage with the help of a script");
6364 ("-nofc", Arg.Set
nofc, " Do not use fontconfig");
6366 ("-v", Arg.Unit
(fun () ->
6368 "%s\nconfiguration path: %s\n"
6372 exit
0), " Print version and exit");
6374 ("-embed", Arg.Set_int
rootwid,
6375 "<window-id> Embed into window")
6378 (fun s -> state
.path <- s)
6379 ("Usage: " ^
Sys.argv
.(0) ^
" [options] some.pdf\nOptions:")
6382 then selfexec := !selfexec ^
" -wtmode";
6384 let histmode = emptystr state
.path && not
!openlast in
6386 if not
(Config.load !openlast)
6387 then dolog
"failed to load configuration";
6388 begin match !pageno with
6389 | Some
pageno -> state
.anchor <- (pageno, 0.0, 0.0)
6393 if nonemptystr
!gcconfig
6396 match Unix.socketpair
Unix.PF_UNIX
Unix.SOCK_STREAM
0 with
6397 | (exception exn
) -> error
"socketpair for gc failed: %s" @@ exntos exn
6400 match spawn
!gcconfig [(c, 0); (c, 1); (s, -1)] with
6401 | (exception exn
) -> error
"failed to execute gc script: %s" @@ exntos exn
6403 Ne.clo c @@ (fun s -> error
"failed to close gc fd %s" s);
6408 let wsfd, winw, winh
= Wsi.init
(object (self)
6409 val mutable m_clicks
= 0
6410 val mutable m_click_x
= 0
6411 val mutable m_click_y
= 0
6412 val mutable m_lastclicktime
= infinity
6414 method private cleanup =
6415 state
.roam
<- noroam
;
6416 Hashtbl.iter
(fun _ opaque -> clearmark
opaque) state
.pagemap
6417 method expose
= G.postRedisplay "expose"
6421 | Wsi.Unobscured
-> "unobscured"
6422 | Wsi.PartiallyObscured
-> "partiallyobscured"
6423 | Wsi.FullyObscured
-> "fullyobscured"
6425 vlog "visibility change %s" name
6426 method display = display ()
6427 method map mapped
= vlog "mapped %b" mapped
6428 method reshape w h =
6431 method mouse
b d x y m =
6432 if d && canselect ()
6434 (* http://blogs.msdn.com/b/oldnewthing/archive/2004/10/18/243925.aspx *)
6440 if abs
x - m_click_x
> 10
6441 || abs
y - m_click_y
> 10
6442 || abs_float
(t -. m_lastclicktime
) > 0.3
6444 m_clicks
<- m_clicks
+ 1;
6445 m_lastclicktime
<- t;
6449 G.postRedisplay "cleanup";
6450 state
.uioh <- state
.uioh#button
b d x y m;
6452 else state
.uioh <- state
.uioh#multiclick m_clicks
x y m
6457 m_lastclicktime
<- infinity
;
6458 state
.uioh <- state
.uioh#button
b d x y m
6462 state
.uioh <- state
.uioh#button
b d x y m
6465 state
.mpos
<- (x, y);
6466 state
.uioh <- state
.uioh#motion
x y
6467 method pmotion
x y =
6468 state
.mpos
<- (x, y);
6469 state
.uioh <- state
.uioh#pmotion
x y
6471 let mascm = m land (
6472 Wsi.altmask
+ Wsi.shiftmask
+ Wsi.ctrlmask
+ Wsi.metamask
6475 let x = state
.x and y = state
.y in
6477 if x != state
.x || y != state
.y then self#
cleanup
6479 match state
.keystate
with
6481 let km = k
, mascm in
6484 let modehash = state
.uioh#
modehash in
6485 try Hashtbl.find modehash km
6487 try Hashtbl.find (findkeyhash conf
"global") km
6488 with Not_found
-> KMinsrt
(k
, m)
6490 | KMinsrt
(k
, m) -> keyboard k
m
6491 | KMinsrl
l -> List.iter
(fun (k
, m) -> keyboard k
m) l
6492 | KMmulti
(l, r) -> state
.keystate
<- KSinto
(l, r)
6494 | KSinto
((k'
, m'
) :: [], insrt
) when k'
=k
&& m'
land mascm = m'
->
6495 List.iter
(fun (k
, m) -> keyboard k
m) insrt
;
6496 state
.keystate
<- KSnone
6497 | KSinto
((k'
, m'
) :: keys, insrt
) when k'
=k
&& m'
land mascm = m'
->
6498 state
.keystate
<- KSinto
(keys, insrt
)
6499 | KSinto
_ -> state
.keystate
<- KSnone
6502 state
.mpos
<- (x, y);
6503 state
.uioh <- state
.uioh#pmotion
x y
6504 method leave = state
.mpos
<- (-1, -1)
6505 method winstate wsl
= state
.winstate
<- wsl
6506 method quit
= raise Quit
6507 end) !rootwid conf
.cwinw conf
.cwinh platform
in
6509 setbgcol conf
.bgcolor
;
6513 List.exists
GlMisc.check_extension
6514 [ "GL_ARB_texture_rectangle"
6515 ; "GL_EXT_texture_recangle"
6516 ; "GL_NV_texture_rectangle" ]
6518 then (dolog
"OpenGL does not suppport rectangular textures"; exit
1);
6521 let r = GlMisc.get_string `renderer
in
6522 let p = "Mesa DRI Intel(" in
6523 let l = String.length
p in
6524 String.length
r > l && String.sub
r 0 l = p
6527 defconf
.sliceheight
<- 1024;
6528 defconf
.texcount
<- 32;
6529 defconf
.usepbo
<- true;
6533 match Unix.socketpair
Unix.PF_UNIX
Unix.SOCK_STREAM
0 with
6534 | (exception exn
) ->
6535 dolog
"socketpair failed: %s" @@ exntos exn
;
6543 setcheckers conf
.checkers
;
6545 opengl_has_pbo := GlMisc.check_extension
"GL_ARB_pixel_buffer_object";
6548 conf
.angle
, conf
.fitmodel
, (conf
.trimmargins
, conf
.trimfuzz
),
6549 conf
.texcount
, conf
.sliceheight
, conf
.mustoresize
, conf
.colorspace
,
6550 !Config.fontpath
, !trimcachepath,
6554 List.iter
GlArray.enable
[`texture_coord
; `vertex
];
6556 reshape ~firsttime
:true winw winh
;
6560 Wsi.settitle
"llpp (history)";
6564 state
.text <- "Opening " ^
(mbtoutf8 state
.path);
6565 opendoc state
.path state
.password;
6569 Wsi.setcursor
Wsi.CURSOR_INHERIT
;
6570 Sys.set_signal
Sys.sighup
(Sys.Signal_handle
(fun _ -> reload ()));
6573 match Unix.waitpid
[Unix.WNOHANG
] ~
-1 with
6574 | (exception (Unix.Unix_error
(Unix.ECHILD
, _, _))) -> ()
6575 | (exception exn
) -> dolog
"Unix.waitpid: %s" @@ exntos exn
6577 | _pid
, _status
-> reap ()
6579 Sys.set_signal
Sys.sigchld
(Sys.Signal_handle
(fun _ -> doreap := true));
6583 if nonemptystr
!rcmdpath
6584 then remoteopen !rcmdpath
6589 let rec loop deadline
=
6595 let r = [state
.ss; state
.wsfd] in
6599 | Some fd
-> fd
:: r
6603 state
.redisplay
<- false;
6610 if deadline
= infinity
6612 else max
0.0 (deadline
-. now)
6617 try Unix.select
r [] [] timeout
6618 with Unix.Unix_error
(Unix.EINTR
, _, _) -> [], [], []
6624 if state
.ghyll
== noghyll
6626 match state
.autoscroll
with
6627 | Some step
when step
!= 0 ->
6628 let y = state
.y + step
in
6632 else if y >= state
.maxy then 0 else y
6634 if state
.mode = View
6635 then gotoy_and_clear_text y
6639 else deadline
+. 0.01
6644 let rec checkfds = function
6646 | fd
:: rest
when fd
= state
.ss ->
6647 let cmd = readcmd state
.ss in
6651 | fd
:: rest
when fd
= state
.wsfd ->
6655 | fd
:: rest
when Some fd
= !optrfd ->
6656 begin match remote fd
with
6657 | None
-> optrfd := remoteopen !rcmdpath;
6658 | opt -> optrfd := opt
6663 dolog
"select returned unknown descriptor";
6669 if deadline
= infinity
6673 match state
.autoscroll
with
6674 | Some step
when step
!= 0 -> deadline1
6675 | _ -> if state
.ghyll
== noghyll
then infinity
else deadline1
6683 Config.save leavebirdseye;
6684 if hasunsavedchanges
()