1 (* Copyright 2001, 2002 b8_bavard, b8_fee_carabine, INRIA *)
3 This file is part of mldonkey.
5 mldonkey is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 mldonkey is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with mldonkey; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 module O
= Gui_options
25 module M
= Gui_messages
30 (*module Gui_rooms = Gui_rooms2*)
33 (try Options.load
O.mldonkey_gui_ini
with
35 (try Options.save
O.mldonkey_gui_ini
with _ -> ())
37 lprintf
"Exception %s in load options %s\n"
38 (Printexc2.to_string e
)
39 (Options.options_file_name
O.mldonkey_gui_ini
);
43 ("-dump_msg", Arg.Unit
(fun _ ->
44 Options.save
Gui_messages.message_file
45 ), ": update internationalisation message file")::
46 Options.simple_args
"" O.mldonkey_gui_ini
in
47 Arg.parse
args (Arg.usage
args) "mlgui: the GUI to use with mldonkey"
51 if !!O.keymap_global
= [] then
53 let a = O.add_binding
O.keymap_global
in
54 a "A-s" M.a_page_servers
;
55 a "A-d" M.a_page_downloads
;
56 a "A-f" M.a_page_friends
;
57 a "A-q" M.a_page_queries
;
58 a "A-r" M.a_page_results
;
59 a "A-m" M.a_page_rooms
;
60 a "A-u" M.a_page_uploads
;
61 a "A-o" M.a_page_options
;
62 a "A-c" M.a_page_console
;
63 a "A-h" M.a_page_help
;
64 a "A-Left" M.a_previous_page
;
65 a "A-Right" M.a_next_page
;
66 a "C-r" M.a_reconnect
;
69 if !!O.keymap_servers
= [] then
71 let a = O.add_binding
O.keymap_servers
in
73 a "C-m" M.a_connect_more
;
74 a "C-a" M.a_select_all
;
76 if !!O.keymap_downloads
= [] then
78 let a = O.add_binding
O.keymap_downloads
in
79 a "C-c" M.a_cancel_download
;
80 a "CS-s" M.a_save_all_files
;
81 a "C-s" M.a_menu_save_file
;
82 a "C-a" M.a_select_all
;
84 if !!O.keymap_friends
= [] then
86 let a = O.add_binding
O.keymap_friends
in
87 a "C-d" M.a_download_selection
;
88 a "C-x" M.a_remove_friend
;
89 a "C-a" M.a_select_all
;
91 if !!O.keymap_queries
= [] then
93 let a = O.add_binding
O.keymap_queries
in
96 if !!O.keymap_results
= [] then
98 let a = O.add_binding
O.keymap_results
in
101 if !!O.keymap_console
= [] then
103 let a = O.add_binding
O.keymap_console
in
107 (** {2 Handling core messages} *)
113 let canon_client gui c
=
114 let box_file_locs = gui#tab_downloads#box_locations
in
115 let box_friends = gui#tab_friends#
box_friends in
116 let box_downloads = gui#tab_downloads
in
119 let cc = Hashtbl.find
G.locations
c.client_num
in
121 let is_in_locations =
123 ignore
(box_file_locs#find_client
c.client_num
);
127 if is_in_locations then
128 gui#tab_downloads#h_update_location
c;
130 cc.client_state
<- c.client_state
;
132 if c.client_state
= RemovedHost
then begin
133 (* lprintf "Removing client %d" c.client_num; lprint_newline ();
135 Hashtbl.remove
G.locations
c.client_num
;
136 (* gui#tab_downloads#box_downloads#remove_client cc.client_num *)
140 if c.client_type
<> cc.client_type
then begin
141 if c.client_type
= 0 then
142 box_friends#h_remove_friend
c.client_num
144 box_friends#h_update_friend
cc
148 cc.client_type
<- c.client_type
;
149 cc.client_rating
<- c.client_rating
;
150 cc.client_name
<- c.client_name
;
152 cc.client_kind
<- c.client_kind
;
153 cc.client_tags
<- c.client_tags
;
155 if c.client_type
<> 0 then
156 box_friends#h_update_friend
cc;
161 (* lprintf "Adding client %d" c.client_num; lprint_newline (); *)
162 Hashtbl.add
G.locations
c.client_num
c;
164 if c.client_type
<> 0 then
165 box_friends#h_update_friend
c;
171 let verbose_gui_messages = ref false
173 let value_reader gui t
=
176 if !verbose_gui_messages then begin
177 lprintf
"MESSAGE RECEIVED: %s"
178 (string_of_to_gui t
);
186 gui#tab_console#insert text
191 let nn = Hashtbl.find
Gui_global.networks n
.network_netnum
193 nn.net_enabled
<- n
.network_enabled
;
194 nn.net_menu_item#set_active n
.network_enabled
196 let display_menu_item =
197 GMenu.check_menu_item ~label
: n
.network_netname ~active
:true
198 ~packing
:gui#menu_display#add
()
200 let network_menu_item =
201 GMenu.check_menu_item ~label
: n
.network_netname
202 ~active
:n
.network_enabled
203 ~packing
:gui#menu_networks#add
()
206 net_num
= n
.network_netnum
;
207 net_name
= n
.network_netname
;
208 net_enabled
= n
.network_enabled
;
209 net_menu_item
= network_menu_item;
210 net_displayed
= true;
212 ignore
(network_menu_item#connect#toggled ~callback
:(fun _ ->
213 nn.net_enabled
<- not
nn.net_enabled
;
214 Com.send
(EnableNetwork
(n
.network_netnum
,
215 network_menu_item#active
)
217 ignore
(display_menu_item#connect#toggled ~callback
:(fun _ ->
218 nn.net_displayed
<- not
nn.net_displayed
;
219 networks_filtered
:= (if nn.net_displayed
then
220 List2.removeq
nn.net_num
!networks_filtered
221 else nn.net_num
:: !networks_filtered
);
222 gui#tab_servers#h_server_filter_networks
;
223 gui#tab_queries#h_search_filter_networks
;
225 Hashtbl.add
Gui_global.networks n
.network_netnum
nn;
230 gui#tab_uploads#wl_status#set_text
231 (Printf.sprintf
"Shared: %5d/%-12s U/D bytes/s: %7d[%5d]/%-7d[%5d]"
233 (Gui_misc.size_of_int64 s
.upload_counter
)
234 (s
.tcp_upload_rate
+ s
.udp_upload_rate
) s
.udp_upload_rate
235 (s
.tcp_download_rate
+ s
.udp_download_rate
) s
.udp_download_rate
238 | CoreProtocol
(v
, _, _) ->
240 let version = min v
GuiProto.best_gui_version
in
241 for i
= 0 to to_gui_last_opcode
do
242 Gui_com.to_gui_protocol_used
.(i
) <- version;
244 for i
= 0 to from_gui_last_opcode
do
245 Gui_com.from_gui_protocol_used
.(i
) <- version;
247 lprintf
"Using protocol %d for communications\n" version;
248 gui#label_connect_status#set_text
(gettext
M.connected
);
249 Com.send
(Password
(!!O.login
, !!O.password
))
251 | Search_result
(num
,r
,_) ->
253 let r = Hashtbl.find
G.results
r in
254 gui#tab_queries#h_search_result num
r
256 lprintf
"Exception in Search_result %d %d\n" num
r;
259 | Search_waiting
(num
,waiting
) ->
260 gui#tab_queries#h_search_waiting num waiting
262 | File_add_source
(num
, src
) ->
263 gui#tab_downloads#h_file_location num src
;
265 | File_remove_source
(num
, src
) ->
266 gui#tab_downloads#h_file_remove_location num src
;
268 | File_downloaded
(num
, downloaded
, rate
, last_seen
) ->
269 gui#tab_downloads#h_file_downloaded num downloaded rate
;
270 gui#tab_downloads#h_file_last_seen num last_seen
272 | File_update_availability
(file_num
, client_num
, avail
) ->
273 gui#tab_downloads#h_file_availability file_num client_num avail
;
276 (* lprintf "FILE INFO"; lprint_newline (); *)
277 gui#tab_downloads#h_file_info f
;
280 (* lprintf "server info"; lprint_newline (); *)
281 gui#tab_servers#h_server_info s
283 | Server_state
(key
,state
) ->
284 gui#tab_servers#h_server_state key state
286 | Server_busy
(key
,nusers
, nfiles
) ->
287 gui#tab_servers#h_server_busy key nusers nfiles
289 | Server_user
(key
, user
) ->
290 (* lprintf "server user %d %d" key user; lprint_newline (); *)
291 if not
(Hashtbl.mem
G.users user
) then begin
292 (* lprintf "Unknown user %d" user; lprint_newline ();*)
293 Gui_com.send
(GetUser_info user
);
296 gui#tab_servers#h_server_user key user
300 (* lprintf "Room info %d" room.room_num; lprint_newline (); *)
301 gui#tab_rooms#room_info room
305 let u = Hashtbl.find
G.users
user.user_num
in
306 u.user_tags
<- user.user_tags
;
309 Hashtbl.add
G.users
user.user_num
user;
312 (* lprintf "user_info %s/%d" user.user_name user.user_server; lprint_newline (); *)
313 gui#tab_servers#h_server_user
user.user_server
user.user_num
;
314 Gui_rooms.user_info
user
316 | Room_add_user
(num
, user_num
) ->
319 gui#tab_rooms#add_room_user num user_num
321 lprintf
"Exception in Room_user %d %d" num user_num
;
325 | Room_remove_user
(num
, user_num
) ->
328 gui#tab_rooms#remove_room_user num user_num
330 lprintf
"Exception in Room_user %d %d" num user_num
;
334 | Options_info list
->
335 (* lprintf "Options_info"; lprint_newline ();*)
336 let module M
= Options
in
344 List.assoc o
.M.option_name
Gui_options.client_options_assocs
346 reference := o
.M.option_value
;
347 Gui_config.add_option_value o
.M.option_name
reference
349 Gui_config.add_option_value o
.M.option_name
(ref o
.M.option_value
)
355 | Add_section_option
(section
, o
) ->
356 let optype = match o
.option_type
with
358 | "Filename" -> FileEntry
359 | _ -> StringEntry
in
360 let line = o
.option_desc
, optype, o
.option_name
in
362 let options = List.assoc section
!client_sections
in
363 if not
(List.mem
line !options) then
364 options := !options @ [line]
366 client_sections
:= !client_sections
@[section
, ref [line]]
369 | Add_plugin_option
(section
, o
) ->
370 let optype = match o
.option_type
with
372 | "Filename" -> FileEntry
373 | _ -> StringEntry
in
374 let line = o
.option_desc
, optype, o
.option_name
in
376 let options = List.assoc section
!plugins_sections
in
377 if not
(List.mem
line !options) then
378 options := !options @ [line]
380 plugins_sections
:= !plugins_sections
@[section
, ref [line]]
383 | DefineSearches l
->
384 gui#tab_queries#h_define_searches l
386 | Client_state
(num
, state
) ->
388 lprintf "Client_state" ; lprint_newline ();
392 let c = Hashtbl.find
G.locations num
in
393 ignore
(canon_client gui
{ c with client_state
= state
})
395 Com.send
(GetClient_info num
)
398 | Client_friend
(num
, friend_kind
) ->
401 let c = Hashtbl.find
G.locations num
in
402 ignore
(canon_client gui
{ c with client_type
= friend_kind
});
404 Com.send
(GetClient_info num
)
409 if not
(Hashtbl.mem
G.results
r.result_num
) then
410 Hashtbl.add
G.results
r.result_num
r
412 | Client_file
(num
, dirname
, file_num
) ->
413 (* Here, the dirname is forgotten: it should be used to build a tree
418 let file = Hashtbl.find
G.results file_num
in
420 let c = Hashtbl.find
G.locations num
in
422 let tree = { file_tree_list
= []; file_tree_name
= "" } in
423 add_file
tree dirname
file;
425 ignore (canon_client gui { c with client_files = Some tree })
429 (* lprintf "File already there"; lprint_newline (); *)
432 (* lprintf "Unknown client %d" num; lprint_newline (); *)
433 Com.send
(GetClient_info num
);
435 (* lprintf "Unknown file %d" file_num;
436 lprint_newline (); *)
441 (* lprintf "Client_info"; lprint_newline (); *)
444 ignore
(canon_client gui
c) ;
447 (* A VOIR : Ca sert à quoi le bouzin ci-dessous ?
448 ben, ca sert a mettre a jour la liste des locations affichees pour un
449 fichier selectionne. Si ca marche toujours dans ton interface, pas de
452 match !current_file with
455 let num = c.client_num in
456 match file.file_more_info with
459 if array_memq num fmi.file_known_locations ||
460 array_memq num fmi.file_indirect_locations then
461 let c = Hashtbl.find locations c.client_num in
462 if is_connected c.client_state then incr nclocations;
463 MyCList.update clist_file_locations c.client_num c
468 | Room_message
(_, PrivateMessage
(num, mes
) )
469 | Room_message
(0, PublicMessage
(num, mes
) )
470 | MessageFromClient
(num, mes
) ->
473 let c = Hashtbl.find
G.locations
num in
474 let d = gui#tab_friends#get_dialog
c in
480 Room_message
(num, msg
) ->
481 gui#tab_rooms#add_room_message
num msg
482 | _ -> raise Not_found
484 lprintf
"Client %d not found in reader.MessageFromClient" num;
488 | Room_message
(num, msg
) ->
490 gui#tab_rooms#add_room_message
num msg
492 lprintf
"Exception in Room_message %d" num;
496 | (DownloadedFiles
_|DownloadFiles
_|ConnectedServers
_) -> assert false
498 | Shared_file_info si
->
499 gui#tab_uploads#h_shared_file_info si
501 | CleanTables
(clients
, servers
) ->
502 gui#tab_servers#clean_table servers
;
503 gui#tab_downloads#clean_table clients
505 | Shared_file_upload
(num,size
,requests
) ->
506 gui#tab_uploads#h_shared_file_upload
num size requests
507 | Shared_file_unshared
_ -> ()
509 GToolbox.message_box ~title
: "Bad Password"
510 "Authorization Failed\nPlease, open the File->Settings menu and
511 enter a valid password"
513 | GiftServerStats
_ -> assert false
522 lprintf
"Exception %s in reader\n" (Printexc2.to_string e
)
525 let generate_connect_menu gui
=
526 let add_item hostname port
=
528 let label = Printf.sprintf
"%s:%d" hostname port
in
529 GMenu.menu_item ~
label: label
530 ~packing
:gui#cores_menu#add
()
532 ignore
(menu_item#connect#activate ~callback
:(fun _ ->
533 O.hostname
=:= hostname
;
535 Com.reconnect gui
value_reader BasicSocket.Closed_by_user
538 List.iter (fun child
-> child#destroy
()) gui#cores_menu#children
;
539 List.iter (fun (h
,port
) -> add_item h port
) !!O.history
;
540 let _ = GMenu.menu_item ~packing
:(gui#cores_menu#add
) () in
541 List.iter (fun (h
,port
) -> add_item h port
) !G.scanned_ports
544 let gui = new Gui_window.window
() in
545 let w = gui#window
in
547 CommonGlobals.exit_properly
0
549 Gui_config.update_toolbars_style
gui;
550 List.iter (fun (menu
, init
) ->
551 let _Menu = GMenu.menu_item ~
label:menu ~packing
:(gui#menubar#add
) ()
553 let _menu = GMenu.menu ~packing
:(_Menu#set_submenu
) () in
555 ) !Gui_global.top_menus
;
556 ignore
(w#connect#destroy
quit);
558 console_message
:= (fun s
->
561 lprintf "to primary"; lprint_newline ();
562 let e = gui#tab_console#text in
564 ignore (GtkBase.Selection.owner_set e#as_widget `PRIMARY 0);
565 (* ignore(e#misc#grab_selection `PRIMARY); *)
566 (* e#misc#add_selection_target ~target:"string" `PRIMARY;
567 ignore (e#misc#connect#selection_get (fun sel ~info ~time ->
568 lprintf "request selection"; lprint_newline ();
571 ignore
(e#event#connect#selection_clear
(fun sel
->
572 lprintf
"selection cleared"; lprint_newline
();
575 ignore
(e#event#connect#selection_request
(fun sel
->
576 lprintf
"Selection request"; lprint_newline
();
579 ignore
(e#event#connect#selection_notify
(fun sel
->
580 lprintf
"Selection notify"; lprint_newline
();
584 gui#tab_console#insert s
);
586 CommonGlobals.do_at_exit
(fun _ ->
587 Gui_misc.save_gui_options
gui;
588 Gui_com.disconnect
gui BasicSocket.Closed_by_user
);
590 ignore
(gui#itemQuit#connect#activate
(fun () ->
591 CommonGlobals.exit_properly
0)) ;
592 ignore
(gui#itemKill#connect#activate
(fun () -> Com.send KillServer
));
593 ignore
(gui#itemReconnect#connect#activate
594 (fun () ->Com.reconnect
gui value_reader BasicSocket.Closed_by_user
));
595 ignore
(gui#itemDisconnect#connect#activate
596 (fun () -> Com.disconnect
gui BasicSocket.Closed_by_user
));
597 ignore
(gui#itemServers#connect#activate
(fun () -> gui#notebook#goto_page
0));
598 ignore
(gui#itemDownloads#connect#activate
(fun () -> gui#notebook#goto_page
1));
599 ignore
(gui#itemFriends#connect#activate
(fun () -> gui#notebook#goto_page
2));
600 ignore
(gui#itemResults#connect#activate
(fun () -> gui#notebook#goto_page
3));
601 ignore
(gui#itemRooms#connect#activate
(fun () -> gui#notebook#goto_page
4));
602 ignore
(gui#itemUploads#connect#activate
(fun () -> gui#notebook#goto_page
5));
603 ignore
(gui#itemConsole#connect#activate
(fun () -> gui#notebook#goto_page
6));
604 ignore
(gui#itemHelp#connect#activate
(fun () -> gui#notebook#goto_page
7));
606 ignore
(gui#itemOptions#connect#activate
(fun () -> Gui_config.edit_options
gui));
608 ignore
(gui#itemScanPorts#connect#activate
(fun _ ->
612 (************ Some hooks ***************)
613 option_hook
Gui_options.notebook_tab
(fun _ ->
614 gui#notebook#set_tab_pos
!!Gui_options.notebook_tab
617 (** connection with core *)
618 Com.reconnect
gui value_reader BasicSocket.Closed_by_user
;
619 (* BasicSocket.add_timer 2.0 update_sizes;*)
620 let never_connected = ref true in
621 BasicSocket.add_timer
1.0 (fun timer
->
622 if !G.new_scanned_port
then begin
623 generate_connect_menu gui
626 if !never_connected && not
(Com.connected
()) then begin
627 BasicSocket.reactivate_timer timer
;
628 Com.reconnect
gui value_reader BasicSocket.Closed_by_user
630 never_connected := false
634 CommonGlobals.gui_included
:= true;