1
(* $Id: uq_gtk.ml 924 2006-06-19 16:57:05Z gerd $ *)
7
type event_id = GMain.Io.event_source
9
type event_id = GMain.Io.id
12
type gtk_file_handler_rec =
13
{ gtk_fd : Unix.file_descr;
14
mutable gtk_event_source_in : (event_id * bool ref) option;
15
mutable gtk_event_source_out : (event_id * bool ref) option;
16
mutable gtk_event_source_pri : (event_id * bool ref) option;
17
mutable gtk_event_source_err : (event_id * bool ref) option;
18
mutable gtk_event_source_hup : (event_id * bool ref) option;
23
event_system -> (unit -> unit) -> unit
26
class gtk_event_system ?(run : runner option) () =
28
inherit unix_event_system() as super
30
val mutable gtk_attaching = false
31
val mutable gtk_run_soon = false
32
val mutable gtk_is_running = false
34
val mutable gtk_last_timer = (None : GMain.Timeout.id option)
36
val mutable gtk_last_file_handlers =
38
(Unix.file_descr, gtk_file_handler_rec) Hashtbl.t)
40
val mutable gtk_watch_tuple = ([], [], [], -1.0)
42
method private gtk_attach ?(run_soon=false) () =
43
(* Creates an idle callback to reschedule events the next time the
44
* event loop is entered. This step can be omitted when this method
45
* is called from a Unixqueue callback (it is ensured gtk_setup
46
* will be invoked soon).
48
* run_soon: if true, the Unixqueue is run once from the idle
49
* callback. This can be used to process additional, non-file events.
51
if not gtk_is_running then (
52
(* prerr_endline "ATTACH!"; *)
53
if not gtk_attaching then (
54
gtk_attaching <- true;
55
( match gtk_last_timer with
56
Some th -> GMain.Timeout.remove th; gtk_last_timer <- None
59
gtk_last_timer <- Some (GMain.Timeout.add
65
gtk_run_soon <- false;
66
self#gtk_safe_handler false ([],[],[]) ()
70
gtk_run_soon <- gtk_run_soon || run_soon;
72
(* else prerr_endline "(no attach)"; *)
75
method private gtk_setup() =
76
let (infiles, outfiles, oobfiles, time) as watch_tuple = super#setup() in
78
gtk_watch_tuple <- watch_tuple;
80
let ht = Hashtbl.create 50 (* n *) in (* 50 should be enough *)
82
(* Fill ht, the new hash table of file handlers: *)
85
Hashtbl.replace ht fd (true,false,false))
91
try Hashtbl.find ht fd
92
with Not_found -> (false,true,false)
94
Hashtbl.replace ht fd (i,true,false))
100
try Hashtbl.find ht fd
101
with Not_found -> (false,false,true)
103
Hashtbl.replace ht fd (i,o,true))
106
let dest_handler (gh, is_active) =
109
ignore(GMain.Io.remove_source gh);
112
ignore(GMain.Io.remove gh);
116
(* Update GTK file handlers: *)
119
let mk_handler cond il ol xl =
120
let is_active = ref true in
121
(* Note: prio=150 has slightly lower priority than resize/redraw
122
* operations, but higher priority than idle callbacks
128
IFDEF GTK2_IO_ADD_WATCH_SUPPORTS_LISTS THEN
136
self#gtk_safe_handler true (il,ol,xl) ())
137
(GMain.Io.channel_of_descr fd) in
140
try Hashtbl.find gtk_last_file_handlers fd
143
gtk_event_source_in = None;
144
gtk_event_source_out = None;
145
gtk_event_source_pri = None;
146
gtk_event_source_err = None;
147
gtk_event_source_hup = None; } in
148
( match g.gtk_event_source_in with
150
g.gtk_event_source_in <- Some(mk_handler `IN [fd] [] []);
151
| Some s when not i ->
153
g.gtk_event_source_in <- None
157
( match g.gtk_event_source_out with
159
g.gtk_event_source_out <- Some(mk_handler `OUT [] [fd] []);
160
| Some s when not o ->
162
g.gtk_event_source_out <- None
166
( match g.gtk_event_source_pri with
168
g.gtk_event_source_pri <- Some(mk_handler `PRI [] [] [fd]);
169
| Some s when not x ->
171
g.gtk_event_source_pri <- None
175
( match g.gtk_event_source_err with
176
None when i || o || x ->
177
let il = if i then [fd] else [] in
178
let ol = if o then [fd] else [] in
179
let xl = if x then [fd] else [] in
180
g.gtk_event_source_err <- Some(mk_handler `ERR il ol xl);
181
| Some s when not (i || o || x) ->
183
g.gtk_event_source_err <- None
187
( match g.gtk_event_source_hup with
188
None when i || o || x ->
189
let il = if i then [fd] else [] in
190
let ol = if o then [fd] else [] in
191
let xl = if x then [fd] else [] in
192
g.gtk_event_source_hup <- Some(mk_handler `HUP il ol xl);
193
| Some s when not (i || o || x) ->
195
g.gtk_event_source_hup <- None
199
Hashtbl.replace gtk_last_file_handlers fd g
205
if not (Hashtbl.mem ht fd) then (
206
( match g.gtk_event_source_in with
209
g.gtk_event_source_in <- None
212
( match g.gtk_event_source_out with
215
g.gtk_event_source_out <- None
218
( match g.gtk_event_source_pri with
221
g.gtk_event_source_pri <- None
224
( match g.gtk_event_source_err with
227
g.gtk_event_source_err <- None
230
( match g.gtk_event_source_hup with
233
g.gtk_event_source_hup <- None
238
gtk_last_file_handlers;
240
let watching_files = infiles <> [] ||
245
(* Remove the old timer, if any. *)
246
begin match gtk_last_timer with
249
GMain.Timeout.remove th;
250
gtk_last_timer <- None;
252
gtk_attaching <- false;
254
(* Set the new timer, if necessary *)
255
if time >= 0.0 then begin
256
(* prerr_endline ("Timeout: " ^ string_of_float time); *)
257
gtk_last_timer <- Some (GMain.Timeout.add
258
~ms:(int_of_float (time *. 1E3 +. 0.5))
259
~callback:(self#gtk_safe_handler false ([],[],[])));
262
(* If no handler is active, detach. *)
264
if gtk_last_timer = None && not watching_files then begin
265
gtk_attached <- false;
266
(* prerr_endline "Detached!"; *)
270
method private gtk_safe_handler keep watch_tuple () =
272
self#gtk_handler watch_tuple ();
276
prerr_endline("Uq_gtk: Internal uncaught exception: " ^
277
Printexc.to_string any);
281
method private gtk_handler watch_tuple () =
284
* It is possible that this is a "ghost event". We need to test whether
285
* there is a resource for the event or not.
288
(* Do now a 'select' with zero timeout to test the file descriptors. *)
290
let (infiles,outfiles,oobfiles) = watch_tuple in
292
let (infiles', outfiles', oobfiles') as actual_tuple =
293
(* (infiles', outfiles', oobfiles'): Lists of file descriptors that
296
Unix.select infiles outfiles oobfiles 0.0
297
(* Because of the timeout value 0.0, this "select" call cannot block,
298
* and it cannot raise EINTR.
302
(* Now we have in infiles', outfiles', oobfiles' the actually happened
303
* file descriptor events.
304
* Furthermore, pure timeout events may have happened, but this is not
305
* indicated specially.
307
ignore(self#queue_events actual_tuple);
309
(* Now run the queue (without source). *)
311
gtk_is_running <- true;
314
| Some r -> r (self : #event_system :> event_system) super#run;
317
prerr_endline ("Uq_gtk: Uncaught exception: " ^
318
Printexc.to_string any
321
gtk_is_running <- false;
323
(* Set up for the next round. *)
326
(**********************************************************************)
327
(* Overriden methods *)
328
(**********************************************************************)
330
method private source _ =
331
(* Override this method: All events are coming from the glib loop,
332
* so disable this source of events
336
(* After certain method invocations, we must ensure we are attached: *)
338
method add_resource g (op,t) =
339
super # add_resource g (op,t);
342
method remove_resource g op =
343
super # remove_resource g op;
348
self # gtk_attach ~run_soon:true ()
352
(* Calling this method is an error! *)
353
failwith "gtk_event_system#run: This method is disabled. Run the Glib event loop instead!"