Remove bogus =end from end of manpage.
[virt-top.git] / virt-ctrl / vc_mainwindow.ml
1 (* virt-ctrl: A graphical management tool.
2    (C) Copyright 2007 Richard W.M. Jones, Red Hat Inc.
3    http://libvirt.org/
4
5    This program 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.
9
10    This program 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.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *)
19
20 open Printf
21
22 let title = "Virtual Control"
23
24 let utf8_copyright = "\194\169"
25
26 let help_about () =
27   let gtk_version =
28     let gtk_major, gtk_minor, gtk_micro = GMain.Main.version in
29     sprintf "%d.%d.%d" gtk_major gtk_minor gtk_micro in
30   let virt_version = string_of_int (fst (Libvirt.get_version ())) in
31   let title = "About " ^ title in
32   let icon = GMisc.image () in
33   icon#set_stock `DIALOG_INFO;
34   icon#set_icon_size `DIALOG;
35   GToolbox.message_box
36     ~title
37     ~icon
38     ("Virtualization control tool (virt-ctrl) by\n" ^
39      "Richard W.M. Jones (rjones@redhat.com).\n\n" ^
40      "Copyright " ^ utf8_copyright ^ " 2007-2008 Red Hat Inc.\n\n" ^
41      "Libvirt version: " ^ virt_version ^ "\n" ^
42      "Gtk toolkit version: " ^ gtk_version)
43
44 (* Catch any exception and throw up a dialog. *)
45 let () =
46   (* A nicer exception printing function. *)
47   let string_of_exn = function
48     | Libvirt.Virterror err ->
49         "Virtualisation error: " ^ (Libvirt.Virterror.to_string err)
50     | Failure msg -> msg
51     | exn -> Printexc.to_string exn
52   in
53   GtkSignal.user_handler :=
54     fun exn ->
55       let label = string_of_exn exn in
56       prerr_endline label;
57       let title = "Error" in
58       let icon = GMisc.image () in
59       icon#set_stock `DIALOG_ERROR;
60       icon#set_icon_size `DIALOG;
61       GToolbox.message_box ~title ~icon label
62
63 let make
64     ~start_domain ~pause_domain ~resume_domain ~shutdown_domain
65     ~open_domain_details =
66   (* Create the main window. *)
67   let window = GWindow.window ~width:800 ~height:600 ~title () in
68   let vbox = GPack.vbox ~packing:window#add () in
69
70   (* Menu bar. *)
71   let quit_item =
72     let menubar = GMenu.menu_bar ~packing:vbox#pack () in
73     let factory = new GMenu.factory menubar in
74     let accel_group = factory#accel_group in
75     let file_menu = factory#add_submenu "File" in
76     let help_menu = factory#add_submenu "Help" in
77
78     window#add_accel_group accel_group;
79
80     (* File menu. *)
81     let factory = new GMenu.factory file_menu ~accel_group in
82     let open_item = factory#add_item "Open connection ..."
83       ~key:GdkKeysyms._O in
84     ignore (factory#add_separator ());
85     let quit_item = factory#add_item "Quit" ~key:GdkKeysyms._Q in
86
87     ignore (open_item#connect#activate
88               ~callback:(Vc_connection_dlg.open_connection window));
89
90     (* Help menu. *)
91     let factory = new GMenu.factory help_menu ~accel_group in
92     let help_item = factory#add_item "Help" in
93     let help_about_item = factory#add_item "About ..." in
94
95     ignore (help_about_item#connect#activate ~callback:help_about);
96
97     quit_item in
98
99   (* The toolbar. *)
100   let toolbar = GButton.toolbar ~packing:vbox#pack () in
101
102   (* The treeview. *)
103   let (tree, model, columns, initial_state) =
104     Vc_connections.make_treeview
105       ~packing:(vbox#pack ~expand:true ~fill:true) () in
106
107   (* Add buttons to the toolbar (requires the treeview to
108    * have been made above).
109    *)
110   let () =
111     let connect_button_menu = GMenu.menu () in
112     let connect_button =
113       GButton.menu_tool_button
114         ~label:"Connect ..." ~stock:`CONNECT
115         ~menu:connect_button_menu
116         ~packing:toolbar#insert () in
117     ignore (GButton.separator_tool_item ~packing:toolbar#insert ());
118     let open_button =
119       GButton.tool_button ~label:"Details" ~stock:`OPEN
120         ~packing:toolbar#insert () in
121     ignore (GButton.separator_tool_item ~packing:toolbar#insert ());
122     let start_button =
123       GButton.tool_button ~label:"Start" ~stock:`ADD
124         ~packing:toolbar#insert () in
125     let pause_button =
126       GButton.tool_button ~label:"Pause" ~stock:`MEDIA_PAUSE
127         ~packing:toolbar#insert () in
128     let resume_button =
129       GButton.tool_button ~label:"Resume" ~stock:`MEDIA_PLAY
130         ~packing:toolbar#insert () in
131     ignore (GButton.separator_tool_item ~packing:toolbar#insert ());
132     let shutdown_button =
133       GButton.tool_button ~label:"Shutdown" ~stock:`STOP
134         ~packing:toolbar#insert () in
135
136     (* Set callbacks for the toolbar buttons. *)
137     ignore (connect_button#connect#clicked
138               ~callback:(Vc_connection_dlg.open_connection window));
139     ignore (open_button#connect#clicked
140               ~callback:(open_domain_details tree model columns));
141     ignore (start_button#connect#clicked
142               ~callback:(start_domain tree model columns));
143     ignore (pause_button#connect#clicked
144               ~callback:(pause_domain tree model columns));
145     ignore (resume_button#connect#clicked
146               ~callback:(resume_domain tree model columns));
147     ignore (shutdown_button#connect#clicked
148               ~callback:(shutdown_domain tree model columns));
149
150     (* Set a menu on the connect menu-button. *)
151     let () =
152       let factory = new GMenu.factory connect_button_menu (*~accel_group*) in
153       let local_xen = factory#add_item "Local Xen" in
154       let local_qemu = factory#add_item "Local QEMU/KVM" in
155       ignore (factory#add_separator ());
156       let open_dialog = factory#add_item "Connect to ..." in
157       ignore (local_xen#connect#activate
158                 ~callback:Vc_connection_dlg.open_local_xen);
159       ignore (local_qemu#connect#activate
160                 ~callback:Vc_connection_dlg.open_local_qemu);
161       ignore (open_dialog#connect#activate
162                 ~callback:(Vc_connection_dlg.open_connection window)) in
163     () in
164
165   (* Make a timeout function which is called once per second. *)
166   let state = ref initial_state in
167   let callback () =
168     (* Gc.compact is generally not safe in lablgtk programs, but
169      * is explicitly allowed in timeouts (see lablgtk README).
170      * This ensures memory is compacted regularly, but is also an
171      * excellent way to catch memory bugs in the ocaml libvirt bindings.
172      *)
173     Gc.compact ();
174
175     (* Ugh: Bug in lablgtk causes a segfault if a timeout raises an
176      * exception.  Catch and print exceptions instead.
177      *)
178     (try state := Vc_connections.repopulate tree model columns !state
179      with exn -> prerr_endline (Printexc.to_string exn));
180
181     true
182   in
183   let timeout_id = GMain.Timeout.add ~ms:1000 ~callback in
184
185   (* Quit. *)
186   let quit _ =
187     GMain.Timeout.remove timeout_id;
188     GMain.quit ();
189     false
190   in
191
192   ignore (window#connect#destroy ~callback:GMain.quit);
193   ignore (window#event#connect#delete ~callback:quit);
194   ignore (quit_item#connect#activate
195             ~callback:(fun () -> ignore (quit ()); ()));
196
197   (* Display the window. *)
198   window#show ()