1 (***********************************************************************)
3 (* MLTk, Tcl/Tk interface of Objective Caml *)
5 (* Francois Rouaix, Francois Pessaux, Jun Furuse and Pierre Weis *)
6 (* projet Cristal, INRIA Rocquencourt *)
7 (* Jacques Garrigue, Kyoto University RIMS *)
9 (* Copyright 2002 Institut National de Recherche en Informatique et *)
10 (* en Automatique and Kyoto University. All rights reserved. *)
11 (* This file is distributed under the terms of the GNU Library *)
12 (* General Public License, with the special exception on linking *)
13 (* described in file LICENSE found in the Objective Caml source tree. *)
15 (***********************************************************************)
22 external init : unit -> unit = "tkanim_init"
25 imagephoto : imagePhoto;
34 frames : gifFrame list;
42 | Animated of animatedGif
46 let cTKtoCAMLgifFrame s =
47 match splitlist s with
48 | [photo; width; height; left; top; delay] ->
49 {imagephoto = cTKtoCAMLimagePhoto photo;
50 frameWidth = int_of_string width;
51 frameHeight = int_of_string height;
52 left = int_of_string left;
53 top = int_of_string top;
54 delay = int_of_string delay}
55 | _ -> raise (Invalid_argument ("cTKtoCAMLgifFrame: " ^ s))
57 let cTKtoCAMLanimatedGif s =
58 match splitlist s with
59 | [width; height; frames; loop] ->
60 {frames = List.map cTKtoCAMLgifFrame (splitlist frames);
61 animWidth = int_of_string width;
62 animHeight = int_of_string height;
63 loop = int_of_string loop}
64 | _ -> raise (Invalid_argument ("cTKtoCAMLgifFrame: " ^ s))
66 (* check Tkanim package is in the interpreter *)
69 splitlist (Protocol.tkEval [| TkToken "package";
72 List.mem "Tkanim" packages
76 Protocol.tkEval [| TkToken "animation";
80 let anmgif = cTKtoCAMLanimatedGif s in
81 match anmgif.frames with
82 | [] -> raise (TkError "Null frame in a gif ?")
83 | [x] -> Still (ImagePhoto x.imagephoto)
84 | _ -> Animated anmgif
87 List.iter (fun {imagephoto = i} -> Imagephoto.delete i) anim.frames
89 let width anm = anm.animWidth
90 let height anm = anm.animHeight
91 let images anm = List.map (fun x -> x.imagephoto) anm.frames
93 let image_existence_check img =
94 (* I found there is a bug in Tk (even v8.0a2). *)
95 (* We can copy from deleted images, Tk never says "it doesn't exist", *)
96 (* But just do some operation. And sometimes it causes Seg-fault. *)
97 (* So, before using Imagephoto.copy, I should check the source image *)
99 try ignore (Imagephoto.height img) with
100 TkError s -> prerr_endline ("tkanim: " ^ s); raise (TkError s)
102 let imagephoto_copy dst src opts =
103 image_existence_check src;
104 Imagephoto.copy dst src opts
106 let animate_gen w i anim =
107 let length = List.length anim.frames in
108 let frames = Array.of_list anim.frames in
109 let current = ref 0 in
110 let loop = ref anim.loop in
111 let f = frames.(!current) in
112 imagephoto_copy i f.imagephoto
113 [ImgTo (f.left, f.top, f.left + f.frameWidth,
114 f.top + f.frameHeight)];
115 let visible = ref true in
116 let animated = ref false in
117 let timer = ref None in
119 let display_current () =
120 let f = frames.(!current) in
121 imagephoto_copy i f.imagephoto
122 [ImgTo (f.left, f.top,
123 f.left + f.frameWidth, f.top + f.frameHeight)]
126 if not (Winfo.exists w && Winfo.viewable w) then begin
127 (* the widget is invisible. stop animation for efficiency *)
128 if !debug then prerr_endline "Stopped (Visibility)";
134 Timer.add (if f.delay = 0 then 100 else f.delay * 10)
137 if !current = length then begin
140 if !loop > 1 then begin
142 if !loop = 0 then begin
143 if !debug then prerr_endline "Loop end";
168 if !timer = None then begin
170 if !current = length then current := 0;
174 (* We shouldn't delete the animation here. *)
177 (BindSet ([], (fun _ -> Imagephoto.delete i)));
179 bind w [[], Visibility]
180 (BindSet ([], (fun _ ->
181 if not !visible then begin
183 if !animated then start ()
187 if !animated then stop () else start ()
190 let animate label anim =
191 (* prerr_endline "animate"; *)
192 let i = Imagephoto.create [Width (Pixels anim.animWidth);
193 Height (Pixels anim.animHeight)]
195 bind label [[], Destroy] (BindExtend ([], (fun _ ->
196 Imagephoto.delete i)));
197 Label.configure label [ImagePhoto i];
198 animate_gen label i anim
200 let animate_canvas_item canvas tag anim =
201 (* prerr_endline "animate"; *)
202 let i = Imagephoto.create [Width (Pixels anim.animWidth);
203 Height (Pixels anim.animHeight)]
205 bind canvas [[], Destroy] (BindExtend ([], (fun _ ->
206 Imagephoto.delete i)));
207 Canvas.configure_image canvas tag [ImagePhoto i];
208 animate_gen canvas i anim
211 let tmp_dir = ref Filename.temp_dir_name in
214 and pid = Unix.getpid() in
217 (Filename.concat !tmp_dir
218 (prefx ^ string_of_int pid ^ "." ^ string_of_int !cnter)))
220 let fname = mktemp "gifdata" in
221 let oc = open_out_bin fname in
225 let anim = create fname in
229 e -> begin Unix.unlink fname; raise e end